754 lines
33 KiB
JavaScript
754 lines
33 KiB
JavaScript
/**
|
|
* Galaxy Strike Online - Game Engine
|
|
* Core game loop and state management
|
|
*/
|
|
|
|
class GameEngine extends EventTarget {
|
|
constructor() {
|
|
// Must call super() first since we extend EventTarget
|
|
super();
|
|
|
|
// Basic game state
|
|
this.isRunning = false;
|
|
this.isPaused = false;
|
|
this.gameTime = 0;
|
|
this.lastSaveTime = 0;
|
|
this.autoSaveInterval = 5000; // 5 seconds
|
|
this.gameLogicInterval = 1000; // 1 second for game updates
|
|
|
|
// Game systems
|
|
this.systems = {};
|
|
|
|
// Save slot configuration
|
|
this.saveSlotInfo = {
|
|
slot: 1,
|
|
useFileSystem: true
|
|
};
|
|
|
|
// Game state
|
|
this.state = {
|
|
paused: false,
|
|
currentTab: 'dashboard',
|
|
notifications: []
|
|
};
|
|
|
|
// Event listeners
|
|
this.eventListeners = new Map();
|
|
|
|
// Initialize immediately
|
|
this.init();
|
|
}
|
|
|
|
setMultiplayerMode(isMultiplayer, socket = null, serverData = null, currentUser = null) {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
console.log('[GAME ENGINE] Setting multiplayer mode:', isMultiplayer);
|
|
console.log('[GAME ENGINE] Previous mode was:', this.isMultiplayer);
|
|
if (debugLogger) debugLogger.logStep('setMultiplayerMode', { isMultiplayer, previousMode: this.isMultiplayer });
|
|
|
|
// CRITICAL: Once set to multiplayer, never allow fallback to singleplayer
|
|
if (this.isMultiplayer && !isMultiplayer) {
|
|
console.warn('[GAME ENGINE] ATTEMPTED FALLBACK TO SINGLEPLAYER - BLOCKING!');
|
|
console.log('[GAME ENGINE] Preserving multiplayer mode');
|
|
return; // Don't allow fallback to singleplayer
|
|
}
|
|
|
|
this.isMultiplayer = isMultiplayer;
|
|
this.socket = socket;
|
|
this.serverData = serverData;
|
|
this.currentUser = currentUser;
|
|
|
|
// Store multiplayer settings for systems that need them
|
|
this.multiplayerConfig = {
|
|
isMultiplayer,
|
|
socket,
|
|
serverData,
|
|
currentUser
|
|
};
|
|
|
|
console.log('[GAME ENGINE] Multiplayer mode configured:', {
|
|
isMultiplayer,
|
|
hasSocket: !!socket,
|
|
hasServerData: !!serverData,
|
|
hasCurrentUser: !!currentUser
|
|
});
|
|
}
|
|
|
|
// Get random integer between min and max (inclusive)
|
|
getRandomInt(min, max) {
|
|
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
}
|
|
|
|
// Get random float between min and max
|
|
getRandomFloat(min, max) {
|
|
return Math.random() * (max - min) + min;
|
|
}
|
|
|
|
async init() {
|
|
console.log('[GAME ENGINE] Initializing game engine');
|
|
const logger = window.logger;
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (logger) await logger.info('Initializing game engine');
|
|
if (debugLogger) await debugLogger.startStep('gameEngineInit');
|
|
|
|
try {
|
|
// In multiplayer mode, use simplified initialization to avoid hanging
|
|
if (this.isMultiplayer) {
|
|
console.log('[GAME ENGINE] Using simplified multiplayer initialization');
|
|
try {
|
|
await this.initializeMultiplayerSystems();
|
|
console.log('[GAME ENGINE] Multiplayer initialization complete - skipping event listeners');
|
|
} catch (multiplayerError) {
|
|
console.error('[GAME ENGINE] Multiplayer systems initialization failed:', multiplayerError);
|
|
// Don't fall back to singleplayer - keep multiplayer mode but with minimal systems
|
|
console.log('[GAME ENGINE] Continuing with minimal multiplayer systems');
|
|
// Create essential systems only
|
|
this.systems.player = new Player(this);
|
|
this.systems.inventory = new Inventory(this);
|
|
this.systems.economy = new Economy(this);
|
|
this.systems.itemSystem = new ItemSystem(this);
|
|
this.systems.idleSystem = new IdleSystem(this);
|
|
}
|
|
} else {
|
|
// Full initialization for singleplayer
|
|
await this.initializeSystemsForLoad();
|
|
|
|
if (debugLogger) await debugLogger.logStep('Systems initialized, setting up event listeners');
|
|
|
|
// Set up event listeners (only in singleplayer to avoid conflicts)
|
|
await this.setupEventListeners();
|
|
}
|
|
|
|
if (debugLogger) await debugLogger.endStep('gameEngineInit', {
|
|
systemsInitialized: Object.keys(this.systems).length,
|
|
eventListeners: this.eventListeners.size
|
|
});
|
|
|
|
} catch (error) {
|
|
console.error('Failed to initialize game:', error);
|
|
if (logger) await logger.errorEvent(error, 'Game Engine Initialization');
|
|
if (debugLogger) await debugLogger.errorEvent(error, 'Game Engine Initialization');
|
|
}
|
|
}
|
|
|
|
// Simplified multiplayer-only system initialization to avoid hanging
|
|
async initializeMultiplayerSystems() {
|
|
console.log('[GAME ENGINE] Initializing multiplayer systems');
|
|
|
|
try {
|
|
// Initialize texture manager first
|
|
this.systems.textureManager = new TextureManager(this);
|
|
|
|
// Create essential systems immediately
|
|
console.log('[GAME ENGINE] Creating essential systems');
|
|
this.systems.player = new Player(this);
|
|
this.systems.inventory = new Inventory(this);
|
|
this.systems.economy = new Economy(this);
|
|
this.systems.ui = new UIManager(this);
|
|
this.systems.idleSystem = new IdleSystem(this);
|
|
this.systems.itemSystem = new ItemSystem(this);
|
|
|
|
console.log('[GAME ENGINE] Essential systems created successfully');
|
|
|
|
// Initialize ItemSystem ONCE and emit event when ready
|
|
console.log('[GAME ENGINE] Initializing ItemSystem (single initialization)');
|
|
this.systems.itemSystem.initialize().then(() => {
|
|
console.log('[GAME ENGINE] ItemSystem fully initialized, emitting ready event');
|
|
this.emit('itemSystemReady');
|
|
}).catch(error => {
|
|
console.error('[GAME ENGINE] ItemSystem initialization failed:', error);
|
|
// Still emit event so Economy can fallback gracefully
|
|
this.emit('itemSystemReady');
|
|
});
|
|
|
|
// Initialize Economy (without ItemSystem - it will wait for the event)
|
|
console.log('[GAME ENGINE] Initializing Economy system');
|
|
this.systems.economy.initialize().catch(error => {
|
|
console.error('[GAME ENGINE] Economy initialization failed:', error);
|
|
});
|
|
|
|
// Create additional systems asynchronously to avoid blocking
|
|
setTimeout(() => {
|
|
console.log('[GAME ENGINE] Creating additional multiplayer systems asynchronously');
|
|
|
|
if (typeof SkillSystem !== 'undefined') {
|
|
this.systems.skillSystem = new SkillSystem(this);
|
|
}
|
|
if (typeof DungeonSystem !== 'undefined') {
|
|
this.systems.dungeonSystem = new DungeonSystem(this);
|
|
// Initialize server-driven dungeon system
|
|
this.systems.dungeonSystem.initialize().then(() => {
|
|
console.log('[GAME ENGINE] DungeonSystem initialized with server data');
|
|
}).catch(error => {
|
|
console.error('[GAME ENGINE] Failed to initialize DungeonSystem:', error);
|
|
});
|
|
}
|
|
if (typeof QuestSystem !== 'undefined') {
|
|
this.systems.questSystem = new QuestSystem(this);
|
|
console.log('[GAME ENGINE] QuestSystem created');
|
|
}
|
|
if (typeof CraftingSystem !== 'undefined') {
|
|
this.systems.crafting = new CraftingSystem(this);
|
|
}
|
|
if (typeof BaseSystem !== 'undefined') {
|
|
this.systems.base = new BaseSystem(this);
|
|
}
|
|
console.log('[GAME ENGINE] All multiplayer systems created asynchronously');
|
|
}, 100); // Create after 100ms delay
|
|
|
|
} catch (error) {
|
|
console.error('[GAME ENGINE] Error in multiplayer systems initialization:', error);
|
|
// Don't re-throw - allow game to continue with basic systems
|
|
console.log('[GAME ENGINE] Continuing with available systems');
|
|
}
|
|
}
|
|
|
|
async initializeSystemsForLoad() {
|
|
const logger = window.logger;
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) await debugLogger.startStep('initializeSystemsForLoad');
|
|
|
|
if (logger) {
|
|
await logger.timeAsync('Game Systems Initialization for Load', async () => {
|
|
await logger.info('Initializing game systems for loading');
|
|
|
|
if (debugLogger) await debugLogger.logStep('Initializing TextureManager');
|
|
// Initialize texture manager first
|
|
this.systems.textureManager = new TextureManager(this);
|
|
if (logger) await logger.systemEvent('TextureManager', 'Initialized');
|
|
if (debugLogger) await debugLogger.logStep('TextureManager initialized');
|
|
|
|
if (debugLogger) await debugLogger.logStep('Creating Player system (without initialization)');
|
|
// Create systems but don't initialize with default data
|
|
this.systems.player = new Player(this);
|
|
if (logger) await logger.systemEvent('Player', 'Created');
|
|
if (debugLogger) await debugLogger.logStep('Player system created');
|
|
|
|
if (debugLogger) await debugLogger.logStep('Creating Inventory system (without initialization)');
|
|
this.systems.inventory = new Inventory(this);
|
|
if (logger) await logger.systemEvent('Inventory', 'Created');
|
|
if (debugLogger) await debugLogger.logStep('Inventory system created');
|
|
|
|
if (debugLogger) await debugLogger.logStep('Creating Economy system (without initialization)');
|
|
this.systems.economy = new Economy(this);
|
|
if (logger) await logger.systemEvent('Economy', 'Created');
|
|
if (debugLogger) await debugLogger.logStep('Economy system created');
|
|
|
|
// In multiplayer mode, skip singleplayer systems
|
|
if (!this.isMultiplayer) {
|
|
if (debugLogger) await debugLogger.logStep('Creating IdleSystem');
|
|
this.systems.idleSystem = new IdleSystem(this);
|
|
if (logger) await logger.systemEvent('IdleSystem', 'Created');
|
|
if (debugLogger) await debugLogger.logStep('IdleSystem created');
|
|
|
|
if (debugLogger) await debugLogger.logStep('Creating ItemSystem');
|
|
this.systems.itemSystem = new ItemSystem(this);
|
|
if (logger) await logger.systemEvent('ItemSystem', 'Created');
|
|
if (debugLogger) await debugLogger.logStep('ItemSystem created');
|
|
} else {
|
|
console.log('[GAME ENGINE] Multiplayer mode - skipping singleplayer systems (IdleSystem, ItemSystem)');
|
|
}
|
|
|
|
if (debugLogger) await debugLogger.logStep('Creating UIManager');
|
|
if (typeof UIManager !== 'undefined') {
|
|
console.log('[GAME ENGINE] UIManager class found, creating real UIManager');
|
|
this.systems.ui = new UIManager(this);
|
|
// Expose UIManager globally for button onclick handlers
|
|
window.uiManager = this.systems.ui;
|
|
window.game.systems.ui = this.systems.ui;
|
|
if (logger) await logger.systemEvent('UIManager', 'Created');
|
|
if (debugLogger) await debugLogger.logStep('UIManager created and exposed');
|
|
} else {
|
|
console.error('[GAME ENGINE] UIManager class not found - this should not happen!');
|
|
if (debugLogger) await debugLogger.error('UIManager class not found - this should not happen!');
|
|
}
|
|
|
|
if (debugLogger) await debugLogger.endStep('initializeSystemsForLoad', {
|
|
systemsCreated: Object.keys(this.systems).length
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
async startGame(continueGame = false) {
|
|
const logger = window.logger;
|
|
const debugLogger = window.debugLogger;
|
|
|
|
console.log('[GAME ENGINE] startGame called with continueGame =', continueGame);
|
|
if (logger) await logger.info('Starting game', { continueGame });
|
|
if (debugLogger) await debugLogger.startStep('startGame', { continueGame });
|
|
|
|
try {
|
|
if (continueGame) {
|
|
console.log('[GAME ENGINE] Loading existing save data...');
|
|
if (debugLogger) await debugLogger.logStep('Loading existing save data');
|
|
await this.loadGame();
|
|
console.log('[GAME ENGINE] Save data loaded');
|
|
} else {
|
|
console.log('[GAME ENGINE] Creating new game...');
|
|
if (debugLogger) await debugLogger.logStep('Creating new game');
|
|
await this.newGame();
|
|
console.log('[GAME ENGINE] New game created');
|
|
}
|
|
|
|
// Start game loop
|
|
this.start();
|
|
console.log('[GAME ENGINE] Game loop started');
|
|
if (debugLogger) await debugLogger.logStep('Game loop started');
|
|
|
|
const loadingStatus = document.getElementById('loadingStatus');
|
|
if (loadingStatus) {
|
|
console.log('[GAME ENGINE] Hiding loading status text');
|
|
if (debugLogger) await debugLogger.logStep('Hiding loading status text');
|
|
loadingStatus.classList.add('hidden');
|
|
}
|
|
|
|
const gameInterface = document.getElementById('gameInterface');
|
|
if (gameInterface) {
|
|
console.log('[GAME ENGINE] Showing game interface');
|
|
if (debugLogger) await debugLogger.logStep('Showing game interface');
|
|
gameInterface.classList.remove('hidden');
|
|
} else {
|
|
console.warn('[GAME ENGINE] gameInterface element not found');
|
|
if (debugLogger) await debugLogger.warn('gameInterface element not found');
|
|
}
|
|
|
|
if (logger) await logger.info('Game started successfully');
|
|
if (debugLogger) await debugLogger.endStep('startGame', {
|
|
continueGame,
|
|
isRunning: this.isRunning,
|
|
gameTime: this.gameTime
|
|
});
|
|
|
|
} catch (error) {
|
|
console.error('[GAME ENGINE] Failed to start game:', error);
|
|
if (logger) await logger.errorEvent(error, 'Game Start');
|
|
if (debugLogger) await debugLogger.errorEvent(error, 'Game Start');
|
|
}
|
|
}
|
|
|
|
start() {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (this.isRunning) {
|
|
if (debugLogger) debugLogger.log('GameEngine.start() called but game is already running', {
|
|
isRunning: this.isRunning,
|
|
gameTime: this.gameTime
|
|
});
|
|
return;
|
|
}
|
|
|
|
if (debugLogger) debugLogger.logStep('Starting game engine', {
|
|
gameLogicInterval: this.gameLogicInterval
|
|
});
|
|
|
|
this.isRunning = true;
|
|
this.lastUpdate = Date.now();
|
|
|
|
// Start game logic timer (completely independent of frame rate)
|
|
console.log('[GAME ENGINE] Starting game logic timer with interval:', this.gameLogicInterval);
|
|
this.gameLogicTimer = setInterval(() => {
|
|
this.updateGameLogic();
|
|
}, this.gameLogicInterval);
|
|
|
|
// Start auto-save
|
|
this.startAutoSave();
|
|
|
|
console.log('[GAME ENGINE] Game engine started');
|
|
if (debugLogger) debugLogger.logStep('Game engine started successfully', {
|
|
gameLogicInterval: this.gameLogicInterval,
|
|
autoSaveInterval: this.autoSaveInterval
|
|
});
|
|
}
|
|
|
|
updateGameLogic() {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
// Use fixed 1-second interval for all updates
|
|
const fixedDelta = 1000; // 1 second in milliseconds
|
|
|
|
if (this.state.paused) {
|
|
if (debugLogger) debugLogger.logStep('Game logic update called but game is paused', {
|
|
gameTime: this.gameTime,
|
|
fixedDelta: fixedDelta
|
|
});
|
|
return;
|
|
}
|
|
|
|
this.gameTime += fixedDelta;
|
|
|
|
// Update player play time with fixed delta
|
|
if (this.systems.player && this.systems.player.updatePlayTime) {
|
|
this.systems.player.updatePlayTime(fixedDelta);
|
|
}
|
|
|
|
// Update all systems with fixed delta
|
|
for (const [name, system] of Object.entries(this.systems)) {
|
|
if (system && typeof system.update === 'function') {
|
|
try {
|
|
system.update(fixedDelta);
|
|
} catch (error) {
|
|
console.error(`[GAME ENGINE] Error updating ${name} system:`, error);
|
|
if (debugLogger) debugLogger.errorEvent(error, `Update ${name} system`);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update UI displays (money, gems, energy) after system updates
|
|
if (this.systems && this.systems.ui) {
|
|
try {
|
|
this.systems.ui.updateUI();
|
|
} catch (error) {
|
|
console.error('[GAME ENGINE] Error updating UI:', error);
|
|
}
|
|
}
|
|
|
|
// Emit game updated event
|
|
this.emit('gameUpdated', { gameTime: this.gameTime });
|
|
}
|
|
|
|
startAutoSave() {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
// Load saved interval or use default
|
|
const savedInterval = localStorage.getItem('autoSaveInterval');
|
|
this.autoSaveInterval = savedInterval ? parseInt(savedInterval) : 5;
|
|
|
|
console.log(`[GAME ENGINE] Starting auto-save with ${this.autoSaveInterval} minute interval`);
|
|
|
|
// Clear any existing timer
|
|
this.stopAutoSave();
|
|
|
|
// Set up new timer
|
|
this.autoSaveTimer = setInterval(async () => {
|
|
console.log('[GAME ENGINE] Auto-save timer triggered - isRunning:', this.isRunning, 'paused:', this.state.paused);
|
|
|
|
if (this.isRunning && !this.state.paused) {
|
|
console.log('[GAME ENGINE] Auto-saving game...');
|
|
|
|
try {
|
|
// In multiplayer mode, save to server
|
|
if (window.smartSaveManager?.isMultiplayer) {
|
|
console.log('[GAME ENGINE] Auto-saving to server...');
|
|
if (this.socket) {
|
|
this.socket.emit('saveGameData', {
|
|
timestamp: Date.now(),
|
|
gameTime: this.gameTime
|
|
});
|
|
} else {
|
|
console.warn('[GAME ENGINE] No socket available for server save');
|
|
}
|
|
} else {
|
|
// Singleplayer mode - local save (not implemented yet)
|
|
console.log('[GAME ENGINE] Local auto-save not implemented');
|
|
}
|
|
|
|
this.showNotification('Game auto-saved', 'info', 2000);
|
|
console.log('[GAME ENGINE] Auto-save completed successfully');
|
|
|
|
} catch (error) {
|
|
console.error('[GAME ENGINE] Auto-save failed:', error);
|
|
if (debugLogger) await debugLogger.errorEvent(error, 'Auto-save');
|
|
}
|
|
} else {
|
|
console.log('[GAME ENGINE] Auto-save skipped - game not running or paused');
|
|
}
|
|
}, this.autoSaveInterval * 60 * 1000); // Convert minutes to milliseconds
|
|
}
|
|
|
|
stopAutoSave() {
|
|
if (this.autoSaveTimer) {
|
|
console.log('[GAME ENGINE] Stopping auto-save timer');
|
|
clearInterval(this.autoSaveTimer);
|
|
this.autoSaveTimer = null;
|
|
}
|
|
}
|
|
|
|
// Notification system
|
|
async showNotification(message, type = 'info', duration = 3000) {
|
|
const logger = window.logger;
|
|
if (logger) await logger.playerAction('Notification', { message, type, duration });
|
|
|
|
const notification = {
|
|
id: Date.now(),
|
|
message,
|
|
type,
|
|
duration,
|
|
timestamp: Date.now()
|
|
};
|
|
|
|
this.state.notifications.push(notification);
|
|
|
|
// Auto-remove notification after duration
|
|
setTimeout(() => {
|
|
this.removeNotification(notification.id);
|
|
}, duration);
|
|
|
|
// Update UI
|
|
if (this.systems.ui) {
|
|
// UI updates handled by individual systems
|
|
}
|
|
}
|
|
|
|
removeNotification(id) {
|
|
this.state.notifications = this.state.notifications.filter(notification => notification.id !== id);
|
|
}
|
|
|
|
// Event system
|
|
on(event, callback) {
|
|
if (!this.eventListeners.has(event)) {
|
|
this.eventListeners.set(event, []);
|
|
}
|
|
this.eventListeners.get(event).push(callback);
|
|
}
|
|
|
|
emit(event, data) {
|
|
if (this.eventListeners.has(event)) {
|
|
this.eventListeners.get(event).forEach(callback => {
|
|
try {
|
|
callback(data);
|
|
} catch (error) {
|
|
console.error(`[GAME ENGINE] Error in event listener for ${event}:`, error);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Also dispatch as DOM event for UIManager
|
|
this.dispatchEvent(new CustomEvent(event, { detail: data }));
|
|
}
|
|
|
|
// Utility methods
|
|
formatNumber(num) {
|
|
if (num >= 1e9) return (num / 1e9).toFixed(2) + 'B';
|
|
if (num >= 1e6) return (num / 1e6).toFixed(2) + 'M';
|
|
if (num >= 1e3) return (num / 1e3).toFixed(2) + 'K';
|
|
return num.toString();
|
|
}
|
|
|
|
formatTime(seconds) {
|
|
const hours = Math.floor(seconds / 3600);
|
|
const minutes = Math.floor((seconds % 3600) / 60);
|
|
const secs = Math.floor(seconds % 60);
|
|
|
|
if (hours > 0) {
|
|
return `${hours}h ${minutes}m ${secs}s`;
|
|
} else if (minutes > 0) {
|
|
return `${minutes}m ${secs}s`;
|
|
} else {
|
|
return `${secs}s`;
|
|
}
|
|
}
|
|
|
|
getPerformanceStats() {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
const stats = {
|
|
gameTime: this.gameTime,
|
|
isRunning: this.isRunning,
|
|
lastUpdate: this.lastUpdate,
|
|
memory: null
|
|
};
|
|
|
|
// Add memory info if available
|
|
if (window.performance && window.performance.memory) {
|
|
stats.memory = {
|
|
used: window.performance.memory.usedJSHeapSize,
|
|
total: window.performance.memory.totalJSHeapSize,
|
|
limit: window.performance.memory.jsHeapSizeLimit
|
|
};
|
|
}
|
|
|
|
return stats;
|
|
}
|
|
|
|
// Load server player data (transforms server format to client format)
|
|
async loadServerPlayerData(playerData) {
|
|
console.log('[GAME ENGINE] Loading server player data with format transformation');
|
|
console.log('[GAME ENGINE] Original server data structure:', playerData);
|
|
|
|
// Transform server data format to client format
|
|
const transformedData = {
|
|
...playerData,
|
|
|
|
// Transform quests from server format to client format
|
|
quests: playerData.quests ? {
|
|
mainQuests: playerData.quests.main || [],
|
|
dailyQuests: playerData.quests.daily || [],
|
|
weeklyQuests: playerData.quests.weekly || [],
|
|
tutorialQuests: playerData.quests.tutorial || [],
|
|
activeQuests: playerData.quests.active || [],
|
|
completedQuests: playerData.quests.completed || []
|
|
} : {
|
|
mainQuests: [],
|
|
dailyQuests: [],
|
|
weeklyQuests: [],
|
|
tutorialQuests: [],
|
|
activeQuests: [],
|
|
completedQuests: []
|
|
}
|
|
};
|
|
|
|
// DEBUG: Log quest data transformation
|
|
console.log('[GAME ENGINE] Quest data transformation:', {
|
|
serverQuests: playerData.quests,
|
|
transformedQuests: transformedData.quests,
|
|
mainQuestsCount: transformedData.quests.mainQuests.length,
|
|
dailyQuestsCount: transformedData.quests.dailyQuests.length,
|
|
weeklyQuestsCount: transformedData.quests.weeklyQuests.length,
|
|
tutorialQuestsCount: transformedData.quests.tutorialQuests.length
|
|
});
|
|
|
|
// Use crafting data from server or initialize empty
|
|
transformedData.crafting = playerData.crafting || {
|
|
skill: 1,
|
|
experience: 0,
|
|
knownRecipes: [],
|
|
completedDungeons: [],
|
|
currentInstance: null,
|
|
dungeonProgress: {}
|
|
};
|
|
|
|
return transformedData;
|
|
}
|
|
|
|
async loadPlayerData(playerData) {
|
|
console.log('[GAME ENGINE] Loading server player data');
|
|
console.log('[GAME ENGINE] Full playerData structure:', playerData);
|
|
console.log('[GAME ENGINE] PlayerData keys:', Object.keys(playerData));
|
|
|
|
try {
|
|
// Apply basic player stats
|
|
if (playerData.stats && this.systems && this.systems.player) {
|
|
console.log('[GAME ENGINE] Found player stats and player system, applying...');
|
|
console.log('[GAME ENGINE] Server playerData.stats:', playerData.stats);
|
|
console.log('[GAME ENGINE] Server playerData keys:', Object.keys(playerData));
|
|
|
|
// Check for playTime in different possible locations
|
|
const possiblePlayTimeFields = [
|
|
playerData.stats?.playTime,
|
|
playerData.playTime,
|
|
playerData.totalPlayTime,
|
|
playerData.stats?.totalPlayTime
|
|
];
|
|
|
|
console.log('[GAME ENGINE] Possible playTime fields found:', possiblePlayTimeFields);
|
|
|
|
// Preserve existing playTime if server doesn't provide it
|
|
const existingPlayTime = this.systems.player.stats.playTime || 0;
|
|
console.log('[GAME ENGINE] Preserving existing playTime:', existingPlayTime);
|
|
|
|
this.systems.player.load(playerData.stats);
|
|
console.log('[GAME ENGINE] Applied player stats:', playerData.stats);
|
|
|
|
// Restore playTime if it was lost
|
|
if (!this.systems.player.stats.playTime || this.systems.player.stats.playTime === 0) {
|
|
this.systems.player.stats.playTime = existingPlayTime;
|
|
console.log('[GAME ENGINE] Restored playTime to:', existingPlayTime);
|
|
}
|
|
|
|
console.log('[GAME ENGINE] Final playTime after load:', this.systems.player.stats.playTime);
|
|
|
|
// Apply credits from server data to economy system
|
|
if (playerData.stats.credits !== undefined && this.systems.economy) {
|
|
this.systems.economy.credits = playerData.stats.credits;
|
|
console.log('[GAME ENGINE] Applied credits from server:', playerData.stats.credits);
|
|
}
|
|
|
|
// Apply gems from server data to economy system
|
|
if (playerData.stats.gems !== undefined && this.systems.economy) {
|
|
this.systems.economy.gems = playerData.stats.gems;
|
|
console.log('[GAME ENGINE] Applied gems from server:', playerData.stats.gems);
|
|
}
|
|
|
|
// Force manual sync to ensure economy is updated
|
|
if (this.systems.economy && this.systems.economy.syncWithServerData) {
|
|
console.log('[GAME ENGINE] Forcing manual economy sync');
|
|
this.systems.economy.syncWithServerData(playerData);
|
|
}
|
|
|
|
// Request fresh economy data from server to ensure sync
|
|
if (this.systems.economy && this.systems.economy.requestEconomyData) {
|
|
setTimeout(() => {
|
|
this.systems.economy.requestEconomyData();
|
|
}, 1000); // Delay to ensure socket is ready
|
|
}
|
|
|
|
// Apply energy from server data to player attributes
|
|
if (playerData.stats.currentEnergy !== undefined && this.systems.player.attributes) {
|
|
this.systems.player.attributes.currentEnergy = playerData.stats.currentEnergy;
|
|
console.log('[GAME ENGINE] Applied current energy from server:', playerData.stats.currentEnergy);
|
|
}
|
|
|
|
if (playerData.stats.maxEnergy !== undefined && this.systems.player.attributes) {
|
|
this.systems.player.attributes.maxEnergy = playerData.stats.maxEnergy;
|
|
console.log('[GAME ENGINE] Applied max energy from server:', playerData.stats.maxEnergy);
|
|
}
|
|
|
|
// Ensure player has minimum energy for dungeon access
|
|
if (this.systems.player.attributes) {
|
|
// Check if energy is missing or too low
|
|
if (!this.systems.player.attributes.energy || this.systems.player.attributes.energy < 10) {
|
|
const oldEnergy = this.systems.player.attributes.energy;
|
|
this.systems.player.attributes.energy = 100;
|
|
this.systems.player.attributes.maxEnergy = Math.max(this.systems.player.attributes.maxEnergy || 0, 100);
|
|
console.log('[GAME ENGINE] Set minimum energy for dungeon access:', oldEnergy, '->', this.systems.player.attributes.energy);
|
|
}
|
|
|
|
// Also ensure currentEnergy is set if it exists
|
|
if (this.systems.player.attributes.currentEnergy !== undefined) {
|
|
if (this.systems.player.attributes.currentEnergy < 10) {
|
|
this.systems.player.attributes.currentEnergy = 100;
|
|
console.log('[GAME ENGINE] Set minimum currentEnergy for dungeon access');
|
|
}
|
|
}
|
|
}
|
|
|
|
console.log('[GAME ENGINE] Final player stats after application:', this.systems.player.stats);
|
|
} else {
|
|
console.log('[GAME ENGINE] Missing player stats or player system');
|
|
console.log('[GAME ENGINE] - playerData.stats:', !!playerData.stats);
|
|
console.log('[GAME ENGINE] - this.systems:', !!this.systems);
|
|
console.log('[GAME ENGINE] - this.systems.player:', !!this.systems?.player);
|
|
}
|
|
|
|
// Apply inventory
|
|
if (playerData.inventory && this.systems && this.systems.inventory) {
|
|
this.systems.inventory.load(playerData.inventory);
|
|
console.log('[GAME ENGINE] Applied inventory');
|
|
}
|
|
|
|
// REMOVED: QuestSystem should be server-driven only
|
|
// Quest data will be handled by server-side systems only
|
|
|
|
// Show notification
|
|
if (this.showNotification) {
|
|
this.showNotification(`Welcome back! Level ${playerData.stats?.level || 1}`, 'success', 3000);
|
|
}
|
|
|
|
console.log('[GAME ENGINE] Server player data loaded successfully');
|
|
|
|
// Trigger UI update to refresh all tabs with new data
|
|
if (this.systems && this.systems.ui) {
|
|
this.systems.ui.updateUI();
|
|
console.log('[GAME ENGINE] Triggered UI update after server data load');
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('[GAME ENGINE] Error loading server player data:', error);
|
|
if (this.showNotification) {
|
|
this.showNotification('Failed to load server data!', 'error', 3000);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Global game instance
|
|
let game = null;
|
|
|
|
// Export GameEngine to global scope
|
|
if (typeof window !== 'undefined') {
|
|
window.GameEngine = GameEngine;
|
|
}
|