narejeno
This commit is contained in:
427
src/systems/SaveSystemExpansion.js
Normal file
427
src/systems/SaveSystemExpansion.js
Normal file
@@ -0,0 +1,427 @@
|
||||
/**
|
||||
* SAVE SYSTEM EXPANSION
|
||||
* Advanced save/load with cloud sync, multiple slots, and auto-save
|
||||
*/
|
||||
class SaveSystemExpansion {
|
||||
constructor(scene) {
|
||||
this.scene = scene;
|
||||
this.enabled = true;
|
||||
|
||||
// Save slots
|
||||
this.maxSlots = 5;
|
||||
this.currentSlot = 1;
|
||||
this.saveSlots = new Map();
|
||||
|
||||
// Cloud sync
|
||||
this.cloudSyncEnabled = false;
|
||||
this.lastCloudSync = 0;
|
||||
this.syncInterval = 300000; // 5 minutes
|
||||
|
||||
// Auto-save
|
||||
this.autoSaveEnabled = true;
|
||||
this.autoSaveInterval = 300000; // 5 minutes
|
||||
this.lastAutoSave = 0;
|
||||
this.preventSaveDuringCombat = true;
|
||||
|
||||
// Backup
|
||||
this.backupEnabled = true;
|
||||
this.maxBackups = 3;
|
||||
|
||||
this.loadSaveSlots();
|
||||
this.init();
|
||||
|
||||
console.log('✅ Save System Expansion initialized');
|
||||
}
|
||||
|
||||
init() {
|
||||
this.setupAutoSave();
|
||||
console.log('💾 Save system ready');
|
||||
}
|
||||
|
||||
// ========== SAVE SLOTS ==========
|
||||
|
||||
createSaveSlot(slotNumber, saveName) {
|
||||
if (slotNumber < 1 || slotNumber > this.maxSlots) {
|
||||
console.log('❌ Invalid slot number');
|
||||
return false;
|
||||
}
|
||||
|
||||
const saveData = this.gatherSaveData();
|
||||
|
||||
const slot = {
|
||||
slotNumber,
|
||||
name: saveName || `Save ${slotNumber}`,
|
||||
timestamp: Date.now(),
|
||||
playTime: this.calculatePlayTime(),
|
||||
thumbnail: this.generateThumbnail(),
|
||||
data: saveData
|
||||
};
|
||||
|
||||
this.saveSlots.set(slotNumber, slot);
|
||||
this.saveToDisk(slotNumber);
|
||||
|
||||
console.log(`💾 Save created: Slot ${slotNumber} - ${slot.name}`);
|
||||
return true;
|
||||
}
|
||||
|
||||
loadSaveSlot(slotNumber) {
|
||||
const slot = this.saveSlots.get(slotNumber);
|
||||
if (!slot) {
|
||||
console.log('❌ Save slot not found');
|
||||
return false;
|
||||
}
|
||||
|
||||
this.applySaveData(slot.data);
|
||||
this.currentSlot = slotNumber;
|
||||
|
||||
console.log(`📂 Save loaded: Slot ${slotNumber} - ${slot.name}`);
|
||||
return true;
|
||||
}
|
||||
|
||||
deleteSaveSlot(slotNumber) {
|
||||
if (!this.saveSlots.has(slotNumber)) {
|
||||
console.log('❌ Save slot not found');
|
||||
return false;
|
||||
}
|
||||
|
||||
this.saveSlots.delete(slotNumber);
|
||||
localStorage.removeItem(`novafarma_save_${slotNumber}`);
|
||||
|
||||
console.log(`🗑️ Save deleted: Slot ${slotNumber}`);
|
||||
return true;
|
||||
}
|
||||
|
||||
renameSaveSlot(slotNumber, newName) {
|
||||
const slot = this.saveSlots.get(slotNumber);
|
||||
if (!slot) return false;
|
||||
|
||||
slot.name = newName;
|
||||
this.saveToDisk(slotNumber);
|
||||
|
||||
console.log(`✏️ Save renamed: Slot ${slotNumber} → ${newName}`);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ========== SAVE DATA ==========
|
||||
|
||||
gatherSaveData() {
|
||||
const data = {
|
||||
version: '3.0.0',
|
||||
timestamp: Date.now(),
|
||||
|
||||
// Player data
|
||||
player: this.getPlayerData(),
|
||||
|
||||
// World data
|
||||
world: this.getWorldData(),
|
||||
|
||||
// Systems data
|
||||
systems: this.getSystemsData(),
|
||||
|
||||
// Progress
|
||||
progress: this.getProgressData()
|
||||
};
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
getPlayerData() {
|
||||
if (!this.scene.player) return null;
|
||||
|
||||
return {
|
||||
position: this.scene.player.getPosition(),
|
||||
health: this.scene.statsSystem?.health || 100,
|
||||
hunger: this.scene.statsSystem?.hunger || 100,
|
||||
level: this.scene.skillTree?.level || 1,
|
||||
xp: this.scene.skillTree?.xp || 0
|
||||
};
|
||||
}
|
||||
|
||||
getWorldData() {
|
||||
return {
|
||||
time: this.scene.weatherSystem?.currentTime || 0,
|
||||
day: this.scene.weatherSystem?.currentDay || 1,
|
||||
weather: this.scene.weatherSystem?.currentWeather || 'clear',
|
||||
season: this.scene.weatherSystem?.currentSeason || 'spring'
|
||||
};
|
||||
}
|
||||
|
||||
getSystemsData() {
|
||||
return {
|
||||
inventory: this.scene.inventorySystem?.items || {},
|
||||
skills: this.scene.skillTree?.skills || {},
|
||||
quests: {
|
||||
active: Array.from(this.scene.storyQuest?.activeQuests || []),
|
||||
completed: Array.from(this.scene.storyQuest?.completedQuests || [])
|
||||
},
|
||||
automation: {
|
||||
workers: this.scene.farmAutomation?.zombieWorkers.length || 0,
|
||||
buildings: this.scene.farmAutomation?.automationBuildings.size || 0
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
getProgressData() {
|
||||
return {
|
||||
achievements: this.scene.uiGraphics?.unlockedAchievements || [],
|
||||
bossesDefeated: Array.from(this.scene.bossBattles?.defeatedBosses || []),
|
||||
recipesDiscovered: Array.from(this.scene.cooking?.knownRecipes || [])
|
||||
};
|
||||
}
|
||||
|
||||
applySaveData(data) {
|
||||
// Restore player
|
||||
if (data.player && this.scene.player) {
|
||||
this.scene.player.setPosition(data.player.position.x, data.player.position.y);
|
||||
if (this.scene.statsSystem) {
|
||||
this.scene.statsSystem.health = data.player.health;
|
||||
this.scene.statsSystem.hunger = data.player.hunger;
|
||||
}
|
||||
}
|
||||
|
||||
// Restore world
|
||||
if (data.world && this.scene.weatherSystem) {
|
||||
this.scene.weatherSystem.currentTime = data.world.time;
|
||||
this.scene.weatherSystem.currentDay = data.world.day;
|
||||
this.scene.weatherSystem.setWeather(data.world.weather);
|
||||
}
|
||||
|
||||
// Restore systems
|
||||
if (data.systems) {
|
||||
if (this.scene.inventorySystem && data.systems.inventory) {
|
||||
this.scene.inventorySystem.items = data.systems.inventory;
|
||||
}
|
||||
}
|
||||
|
||||
console.log('✅ Save data applied');
|
||||
}
|
||||
|
||||
// ========== AUTO-SAVE ==========
|
||||
|
||||
setupAutoSave() {
|
||||
if (!this.autoSaveEnabled) return;
|
||||
|
||||
setInterval(() => {
|
||||
this.performAutoSave();
|
||||
}, this.autoSaveInterval);
|
||||
|
||||
console.log(`⏰ Auto-save enabled (every ${this.autoSaveInterval / 1000}s)`);
|
||||
}
|
||||
|
||||
performAutoSave() {
|
||||
if (!this.canAutoSave()) return;
|
||||
|
||||
this.quickSave();
|
||||
this.lastAutoSave = Date.now();
|
||||
|
||||
console.log('💾 Auto-save performed');
|
||||
}
|
||||
|
||||
canAutoSave() {
|
||||
// Don't save during combat
|
||||
if (this.preventSaveDuringCombat && this.isInCombat()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
isInCombat() {
|
||||
// Check if player is in combat
|
||||
return false; // Placeholder
|
||||
}
|
||||
|
||||
// ========== QUICK SAVE/LOAD ==========
|
||||
|
||||
quickSave() {
|
||||
return this.createSaveSlot(this.currentSlot, `Quick Save`);
|
||||
}
|
||||
|
||||
quickLoad() {
|
||||
return this.loadSaveSlot(this.currentSlot);
|
||||
}
|
||||
|
||||
// ========== CLOUD SYNC ==========
|
||||
|
||||
enableCloudSync() {
|
||||
this.cloudSyncEnabled = true;
|
||||
console.log('☁️ Cloud sync enabled');
|
||||
}
|
||||
|
||||
disableCloudSync() {
|
||||
this.cloudSyncEnabled = false;
|
||||
console.log('☁️ Cloud sync disabled');
|
||||
}
|
||||
|
||||
syncToCloud(slotNumber) {
|
||||
if (!this.cloudSyncEnabled) {
|
||||
console.log('❌ Cloud sync is disabled');
|
||||
return false;
|
||||
}
|
||||
|
||||
const slot = this.saveSlots.get(slotNumber);
|
||||
if (!slot) return false;
|
||||
|
||||
// Upload to Steam Cloud
|
||||
console.log(`☁️ Uploading save to cloud: Slot ${slotNumber}`);
|
||||
|
||||
// Simulate cloud upload
|
||||
this.lastCloudSync = Date.now();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
syncFromCloud(slotNumber) {
|
||||
if (!this.cloudSyncEnabled) {
|
||||
console.log('❌ Cloud sync is disabled');
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log(`☁️ Downloading save from cloud: Slot ${slotNumber}`);
|
||||
|
||||
// Simulate cloud download
|
||||
return true;
|
||||
}
|
||||
|
||||
resolveConflict(localSlot, cloudSlot) {
|
||||
// Show UI to let player choose which save to keep
|
||||
console.log('⚠️ Save conflict detected');
|
||||
|
||||
if (localSlot.timestamp > cloudSlot.timestamp) {
|
||||
console.log('📤 Local save is newer - uploading');
|
||||
return 'upload';
|
||||
} else {
|
||||
console.log('📥 Cloud save is newer - downloading');
|
||||
return 'download';
|
||||
}
|
||||
}
|
||||
|
||||
// ========== BACKUP SYSTEM ==========
|
||||
|
||||
createBackup(slotNumber) {
|
||||
if (!this.backupEnabled) return false;
|
||||
|
||||
const slot = this.saveSlots.get(slotNumber);
|
||||
if (!slot) return false;
|
||||
|
||||
const backupKey = `novafarma_backup_${slotNumber}_${Date.now()}`;
|
||||
localStorage.setItem(backupKey, JSON.stringify(slot));
|
||||
|
||||
// Clean old backups
|
||||
this.cleanOldBackups(slotNumber);
|
||||
|
||||
console.log(`💾 Backup created: ${backupKey}`);
|
||||
return true;
|
||||
}
|
||||
|
||||
cleanOldBackups(slotNumber) {
|
||||
const backups = this.getBackups(slotNumber);
|
||||
|
||||
if (backups.length > this.maxBackups) {
|
||||
// Remove oldest backups
|
||||
const toRemove = backups.slice(0, backups.length - this.maxBackups);
|
||||
toRemove.forEach(backup => {
|
||||
localStorage.removeItem(backup.key);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
getBackups(slotNumber) {
|
||||
const backups = [];
|
||||
const prefix = `novafarma_backup_${slotNumber}_`;
|
||||
|
||||
for (let i = 0; i < localStorage.length; i++) {
|
||||
const key = localStorage.key(i);
|
||||
if (key && key.startsWith(prefix)) {
|
||||
const timestamp = parseInt(key.split('_').pop());
|
||||
backups.push({ key, timestamp });
|
||||
}
|
||||
}
|
||||
|
||||
return backups.sort((a, b) => a.timestamp - b.timestamp);
|
||||
}
|
||||
|
||||
restoreBackup(backupKey) {
|
||||
const backup = localStorage.getItem(backupKey);
|
||||
if (!backup) {
|
||||
console.log('❌ Backup not found');
|
||||
return false;
|
||||
}
|
||||
|
||||
const slot = JSON.parse(backup);
|
||||
this.saveSlots.set(slot.slotNumber, slot);
|
||||
|
||||
console.log(`📂 Backup restored: ${backupKey}`);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ========== THUMBNAILS ==========
|
||||
|
||||
generateThumbnail() {
|
||||
// Generate screenshot thumbnail
|
||||
return {
|
||||
width: 160,
|
||||
height: 90,
|
||||
data: null // Base64 image data
|
||||
};
|
||||
}
|
||||
|
||||
// ========== PLAY TIME ==========
|
||||
|
||||
calculatePlayTime() {
|
||||
// Calculate total play time in seconds
|
||||
return 0; // Placeholder
|
||||
}
|
||||
|
||||
formatPlayTime(seconds) {
|
||||
const hours = Math.floor(seconds / 3600);
|
||||
const minutes = Math.floor((seconds % 3600) / 60);
|
||||
return `${hours}h ${minutes}m`;
|
||||
}
|
||||
|
||||
// ========== PERSISTENCE ==========
|
||||
|
||||
saveToDisk(slotNumber) {
|
||||
const slot = this.saveSlots.get(slotNumber);
|
||||
if (!slot) return;
|
||||
|
||||
localStorage.setItem(`novafarma_save_${slotNumber}`, JSON.stringify(slot));
|
||||
|
||||
// Create backup
|
||||
if (this.backupEnabled) {
|
||||
this.createBackup(slotNumber);
|
||||
}
|
||||
}
|
||||
|
||||
loadSaveSlots() {
|
||||
for (let i = 1; i <= this.maxSlots; i++) {
|
||||
const saved = localStorage.getItem(`novafarma_save_${i}`);
|
||||
if (saved) {
|
||||
try {
|
||||
const slot = JSON.parse(saved);
|
||||
this.saveSlots.set(i, slot);
|
||||
} catch (error) {
|
||||
console.error(`Failed to load save slot ${i}:`, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`✅ Loaded ${this.saveSlots.size} save slots`);
|
||||
}
|
||||
|
||||
// ========== UPDATE ==========
|
||||
|
||||
update(delta) {
|
||||
// Auto cloud sync
|
||||
if (this.cloudSyncEnabled) {
|
||||
const now = Date.now();
|
||||
if (now - this.lastCloudSync > this.syncInterval) {
|
||||
this.syncToCloud(this.currentSlot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
destroy() {
|
||||
console.log('💾 Save System Expansion destroyed');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user