1559 lines
72 KiB
JavaScript
1559 lines
72 KiB
JavaScript
/**
|
|
* Galaxy Strike Online - Game Engine
|
|
* Core game loop and state management
|
|
*/
|
|
|
|
class GameEngine extends EventTarget {
|
|
constructor() {
|
|
super(); // Call EventTarget constructor first
|
|
|
|
console.log('🛑 DEBUG STOP 1: GameEngine constructor starting');
|
|
const debugLogger = window.debugLogger;
|
|
if (debugLogger) debugLogger.log('GameEngine constructor called', {
|
|
autoSaveInterval: 5,
|
|
timestamp: new Date().toISOString()
|
|
});
|
|
|
|
this.isRunning = false;
|
|
this.lastUpdate = 0;
|
|
this.gameTime = 0;
|
|
|
|
// Auto-save settings
|
|
this.autoSaveInterval = 1; // Default 1 minute
|
|
this.autoSaveTimer = null;
|
|
this.lastAutoSave = 0;
|
|
|
|
// Save slot information
|
|
this.saveSlotInfo = {
|
|
slot: 1, // Default save slot
|
|
useFileSystem: !!window.electronAPI // Use file system if Electron API is available
|
|
};
|
|
|
|
console.log('🛑 DEBUG STOP 2: Save slot info initialized:', this.saveSlotInfo);
|
|
|
|
// GUI update settings
|
|
this.guiUpdateInterval = 1000; // Update GUI once per second (1000ms)
|
|
this.lastGUIUpdate = 0;
|
|
|
|
// Game logic settings (independent of frame rate)
|
|
this.gameLogicInterval = 1000; // Update game logic every 1 second
|
|
this.gameLogicTimer = null;
|
|
|
|
// Game state
|
|
this.state = {
|
|
paused: false,
|
|
currentTab: 'dashboard',
|
|
notifications: [],
|
|
loading: true
|
|
};
|
|
|
|
console.log('🛑 DEBUG STOP 3: Game state initialized:', this.state);
|
|
|
|
// Systems
|
|
this.systems = {};
|
|
|
|
// Event listeners
|
|
this.eventListeners = new Map();
|
|
|
|
console.log('🛑 DEBUG STOP 4: About to call this.init()');
|
|
this.init();
|
|
console.log('🛑 DEBUG STOP 5: GameEngine constructor completed');
|
|
}
|
|
|
|
setMultiplayerMode(isMultiplayer, socket = null, serverData = null, currentUser = null) {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
console.log('[GAME ENGINE] Setting multiplayer mode:', isMultiplayer);
|
|
if (debugLogger) debugLogger.logStep('setMultiplayerMode', { isMultiplayer });
|
|
|
|
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 {
|
|
// Initialize core systems but don't setup new game data
|
|
await this.initializeSystemsForLoad();
|
|
|
|
if (debugLogger) await debugLogger.logStep('Systems initialized, setting up event listeners');
|
|
|
|
// Set up event listeners
|
|
await this.setupEventListeners();
|
|
|
|
if (debugLogger) await debugLogger.logStep('Event listeners setup complete');
|
|
|
|
if (logger) await logger.info('Game engine initialization completed');
|
|
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');
|
|
}
|
|
}
|
|
|
|
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
|
|
// CRITICAL: Ensure UIManager is initialized before starting game
|
|
if (this.systems.ui) {
|
|
console.log('[GAME ENGINE] Final UIManager initialization check...');
|
|
try {
|
|
await this.systems.ui.initialize();
|
|
console.log('[GAME ENGINE] UIManager initialized successfully');
|
|
} catch (error) {
|
|
console.error('[GAME ENGINE] UIManager initialization failed:', error);
|
|
}
|
|
}
|
|
|
|
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');
|
|
|
|
// CRITICAL: Initialize UIManager after showing interface
|
|
console.log('[GAME ENGINE] Initializing UIManager after showing interface...');
|
|
if (this.systems.ui) {
|
|
try {
|
|
await this.systems.ui.initialize();
|
|
console.log('[GAME ENGINE] UIManager initialized successfully (post-interface)');
|
|
} catch (error) {
|
|
console.error('[GAME ENGINE] UIManager initialization failed:', error);
|
|
}
|
|
} else {
|
|
console.log('[GAME ENGINE] UIManager not found when trying to initialize after interface');
|
|
}
|
|
} 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');
|
|
}
|
|
}
|
|
|
|
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');
|
|
|
|
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 DungeonSystem');
|
|
this.systems.dungeonSystem = new DungeonSystem(this);
|
|
if (logger) await logger.systemEvent('DungeonSystem', 'Created');
|
|
if (debugLogger) await debugLogger.logStep('DungeonSystem created');
|
|
|
|
if (debugLogger) await debugLogger.logStep('Creating SkillSystem');
|
|
this.systems.skillSystem = new SkillSystem(this);
|
|
if (logger) await logger.systemEvent('SkillSystem', 'Created');
|
|
if (debugLogger) await debugLogger.logStep('SkillSystem created');
|
|
|
|
if (debugLogger) await debugLogger.logStep('Creating BaseSystem');
|
|
this.systems.baseSystem = new BaseSystem(this);
|
|
if (logger) await logger.systemEvent('BaseSystem', 'Created');
|
|
if (debugLogger) await debugLogger.logStep('BaseSystem created');
|
|
|
|
if (debugLogger) await debugLogger.logStep('Creating QuestSystem');
|
|
this.systems.questSystem = new QuestSystem(this);
|
|
if (logger) await logger.systemEvent('QuestSystem', 'Created');
|
|
if (debugLogger) await debugLogger.logStep('QuestSystem created');
|
|
|
|
if (debugLogger) await debugLogger.logStep('Creating ShipSystem');
|
|
this.systems.shipSystem = new ShipSystem(this);
|
|
if (logger) await logger.systemEvent('ShipSystem', 'Created');
|
|
if (debugLogger) await debugLogger.logStep('ShipSystem created');
|
|
|
|
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!');
|
|
// Create minimal UI system to prevent crashes (should never be needed based on logs)
|
|
this.systems.ui = {
|
|
showNotification: (message, type, duration) => {
|
|
console.log(`[UI MINIMAL] ${type}: ${message}`);
|
|
},
|
|
updateUI: () => {
|
|
console.log('[UI MINIMAL] updateUI called');
|
|
},
|
|
switchTab: (tabName) => {
|
|
console.log('[UI MINIMAL] switchTab called');
|
|
}
|
|
};
|
|
}
|
|
if (debugLogger) await debugLogger.logStep('Creating CraftingSystem');
|
|
this.systems.crafting = new CraftingSystem(this);
|
|
if (logger) await logger.systemEvent('CraftingSystem', 'Created');
|
|
if (debugLogger) await debugLogger.logStep('CraftingSystem created');
|
|
|
|
if (debugLogger) await debugLogger.endStep('initializeSystemsForLoad', {
|
|
systemsCreated: Object.keys(this.systems).length
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
async initializeSystems() {
|
|
const logger = window.logger;
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) await debugLogger.startStep('initializeSystems');
|
|
|
|
if (logger) {
|
|
await logger.timeAsync('Game Systems Initialization', async () => {
|
|
await logger.info('Initializing game systems');
|
|
|
|
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('Initializing Player system');
|
|
// Initialize in dependency order
|
|
this.systems.player = new Player(this);
|
|
if (logger) await logger.systemEvent('Player', 'Initialized');
|
|
if (debugLogger) await debugLogger.logStep('Player system initialized', {
|
|
playerLevel: this.systems.player.stats.level,
|
|
playerExperience: this.systems.player.stats.experience
|
|
});
|
|
|
|
if (debugLogger) await debugLogger.logStep('Initializing Inventory system');
|
|
this.systems.inventory = new Inventory(this);
|
|
if (logger) await logger.systemEvent('Inventory', 'Initialized');
|
|
if (debugLogger) await debugLogger.logStep('Inventory system initialized', {
|
|
inventorySize: this.systems.inventory.items.length
|
|
});
|
|
|
|
if (debugLogger) await debugLogger.logStep('Initializing Economy system');
|
|
this.systems.economy = new Economy(this);
|
|
if (logger) await logger.systemEvent('Economy', 'Initialized');
|
|
if (debugLogger) await debugLogger.logStep('Economy system initialized', {
|
|
credits: this.systems.economy.credits,
|
|
gems: this.systems.economy.gems
|
|
});
|
|
|
|
if (debugLogger) await debugLogger.logStep('Initializing IdleSystem');
|
|
this.systems.idleSystem = new IdleSystem(this);
|
|
if (logger) await logger.systemEvent('IdleSystem', 'Initialized');
|
|
if (debugLogger) await debugLogger.logStep('IdleSystem initialized');
|
|
|
|
if (debugLogger) await debugLogger.logStep('Initializing DungeonSystem');
|
|
this.systems.dungeonSystem = new DungeonSystem(this);
|
|
if (logger) await logger.systemEvent('DungeonSystem', 'Initialized');
|
|
if (debugLogger) await debugLogger.logStep('DungeonSystem initialized');
|
|
|
|
if (debugLogger) await debugLogger.logStep('Initializing SkillSystem');
|
|
this.systems.skillSystem = new SkillSystem(this);
|
|
if (logger) await logger.systemEvent('SkillSystem', 'Initialized');
|
|
if (debugLogger) await debugLogger.logStep('SkillSystem initialized');
|
|
|
|
if (debugLogger) await debugLogger.logStep('Initializing BaseSystem');
|
|
this.systems.baseSystem = new BaseSystem(this);
|
|
if (logger) await logger.systemEvent('BaseSystem', 'Initialized');
|
|
if (debugLogger) await debugLogger.logStep('BaseSystem initialized');
|
|
|
|
if (debugLogger) await debugLogger.logStep('Initializing QuestSystem');
|
|
this.systems.questSystem = new QuestSystem(this);
|
|
await this.systems.questSystem.initialize();
|
|
if (logger) await logger.systemEvent('QuestSystem', 'Initialized');
|
|
if (debugLogger) await debugLogger.logStep('QuestSystem initialized');
|
|
|
|
if (debugLogger) await debugLogger.logStep('Initializing ShipSystem');
|
|
this.systems.ship = new ShipSystem(this);
|
|
if (logger) await logger.systemEvent('ShipSystem', 'Initialized');
|
|
if (debugLogger) await debugLogger.logStep('ShipSystem initialized');
|
|
|
|
if (debugLogger) await debugLogger.logStep('UIManager already initialized in initializeSystemsForLoad');
|
|
|
|
if (debugLogger) await debugLogger.logStep('Initializing CraftingSystem');
|
|
this.systems.crafting = new CraftingSystem(this);
|
|
if (logger) await logger.systemEvent('CraftingSystem', 'Initialized');
|
|
if (debugLogger) await debugLogger.logStep('CraftingSystem initialized');
|
|
|
|
if (logger) await logger.info('All game systems initialized');
|
|
if (debugLogger) await debugLogger.logStep('All systems created, running individual initializations');
|
|
|
|
if (debugLogger) await debugLogger.logStep('Running individual system initializations');
|
|
for (const [name, system] of Object.entries(this.systems)) {
|
|
if (system.initialize) {
|
|
if (debugLogger) await debugLogger.logStep(`Initializing ${name} system`);
|
|
await system.initialize();
|
|
if (debugLogger) await debugLogger.logStep(`${name} system initialization complete`);
|
|
} else {
|
|
if (debugLogger) await debugLogger.logStep(`${name} system has no initialize method`);
|
|
}
|
|
}
|
|
|
|
if (debugLogger) await debugLogger.endStep('initializeSystems', {
|
|
totalSystems: Object.keys(this.systems).length,
|
|
systemsList: Object.keys(this.systems)
|
|
});
|
|
});
|
|
} else {
|
|
// Fallback without timing
|
|
if (debugLogger) await debugLogger.logStep('Logger not available, using fallback initialization');
|
|
|
|
// Initialize texture manager first
|
|
this.systems.textureManager = new TextureManager(this);
|
|
|
|
// Initialize in dependency order
|
|
this.systems.player = new Player(this);
|
|
this.systems.inventory = new Inventory(this);
|
|
this.systems.economy = new Economy(this);
|
|
this.systems.idleSystem = new IdleSystem(this);
|
|
this.systems.dungeonSystem = new DungeonSystem(this);
|
|
this.systems.skillSystem = new SkillSystem(this);
|
|
this.systems.baseSystem = new BaseSystem(this);
|
|
this.systems.questSystem = new QuestSystem(this);
|
|
// UIManager already initialized in initializeSystemsForLoad
|
|
this.systems.crafting = new CraftingSystem(this);
|
|
|
|
for (const [name, system] of Object.entries(this.systems)) {
|
|
if (system.initialize) {
|
|
await system.initialize();
|
|
}
|
|
}
|
|
|
|
if (debugLogger) await debugLogger.endStep('initializeSystems', {
|
|
fallbackMode: true,
|
|
totalSystems: Object.keys(this.systems).length
|
|
});
|
|
}
|
|
}
|
|
|
|
async setupEventListeners() {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) await debugLogger.startStep('setupEventListeners');
|
|
|
|
// Window events
|
|
if (debugLogger) await debugLogger.logStep('Setting up window event listeners');
|
|
window.addEventListener('beforeunload', () => {
|
|
if (debugLogger) debugLogger.logStep('beforeunload event triggered - saving game');
|
|
this.save();
|
|
});
|
|
|
|
window.addEventListener('visibilitychange', () => {
|
|
// if (debugLogger) debugLogger.logStep('visibilitychange event triggered', {
|
|
// hidden: document.hidden,
|
|
// visibilityState: document.visibilityState
|
|
// });
|
|
if (document.hidden) {
|
|
// if (debugLogger) debugLogger.logStep('Document hidden - saving game');
|
|
this.save();
|
|
}
|
|
});
|
|
|
|
// Keyboard shortcuts
|
|
if (debugLogger) await debugLogger.logStep('Setting up keyboard shortcuts');
|
|
document.addEventListener('keydown', (event) => {
|
|
if (debugLogger) debugLogger.logStep('Key pressed', {
|
|
key: event.key,
|
|
code: event.code,
|
|
ctrlKey: event.ctrlKey,
|
|
altKey: event.altKey,
|
|
shiftKey: event.shiftKey
|
|
});
|
|
|
|
// Ctrl+S for manual save
|
|
if (event.ctrlKey && event.key === 's') {
|
|
event.preventDefault();
|
|
if (debugLogger) debugLogger.logStep('Manual save shortcut triggered (Ctrl+S)');
|
|
this.save();
|
|
}
|
|
});
|
|
|
|
// Game loop events
|
|
if (debugLogger) await debugLogger.logStep('Setting up game loop events');
|
|
this.addEventListener('gameStarted', () => {
|
|
if (debugLogger) debugLogger.logStep('Game started event received');
|
|
});
|
|
|
|
this.addEventListener('gameStopped', () => {
|
|
if (debugLogger) debugLogger.logStep('Game stopped event received');
|
|
});
|
|
|
|
this.addEventListener('gameSaved', () => {
|
|
// if (debugLogger) debugLogger.logStep('Game saved event received');
|
|
});
|
|
|
|
this.addEventListener('gameLoaded', () => {
|
|
if (debugLogger) debugLogger.logStep('Game loaded event received');
|
|
});
|
|
|
|
// Setup UI event listeners
|
|
if (debugLogger) await debugLogger.logStep('Setting up UI event listeners');
|
|
if (this.systems.ui && typeof this.systems.ui.setupEventListeners === 'function' && !this.uiEventListenersSetup) {
|
|
this.systems.ui.setupEventListeners();
|
|
this.uiEventListenersSetup = true; // Prevent duplicate setup
|
|
if (debugLogger) await debugLogger.logStep('UI event listeners setup complete');
|
|
} else if (this.uiEventListenersSetup) {
|
|
if (debugLogger) await debugLogger.logStep('UI event listeners already setup, skipping');
|
|
}
|
|
|
|
if (debugLogger) await debugLogger.endStep('setupEventListeners', {
|
|
windowEvents: 2,
|
|
keyboardShortcuts: 2,
|
|
gameLoopEvents: 4
|
|
});
|
|
}
|
|
|
|
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 = performance.now();
|
|
|
|
if (debugLogger) debugLogger.logStep('Game engine started, beginning game loop');
|
|
|
|
this.gameLoop();
|
|
|
|
// Loading screen is now handled by startGame() method
|
|
// Don't duplicate the hiding logic here
|
|
|
|
if (debugLogger) debugLogger.logStep('Game loop initiated');
|
|
}
|
|
|
|
async stop() {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) await debugLogger.startStep('stopGame');
|
|
|
|
console.log('[GAME ENGINE] Stopping game and saving...');
|
|
if (debugLogger) await debugLogger.logStep('Stopping game engine');
|
|
|
|
if (!this.isRunning) {
|
|
if (debugLogger) debugLogger.logStep('Game already stopped, ignoring stop request');
|
|
return;
|
|
}
|
|
|
|
this.isRunning = false;
|
|
|
|
// Clear game logic timer
|
|
if (this.gameLogicTimer) {
|
|
clearInterval(this.gameLogicTimer);
|
|
this.gameLogicTimer = null;
|
|
}
|
|
|
|
// Clear auto-save timer
|
|
if (this.autoSaveTimer) {
|
|
clearInterval(this.autoSaveTimer);
|
|
this.autoSaveTimer = null;
|
|
}
|
|
|
|
console.log('[GAME ENGINE] Game stopped and saved successfully');
|
|
|
|
if (debugLogger) await debugLogger.endStep('stopGame', {
|
|
gameTime: this.gameTime,
|
|
isRunning: this.isRunning
|
|
});
|
|
}
|
|
|
|
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`);
|
|
if (debugLogger) debugLogger.logStep('Starting auto-save system', {
|
|
interval: this.autoSaveInterval,
|
|
intervalMs: this.autoSaveInterval * 60 * 1000,
|
|
savedInterval: savedInterval,
|
|
isRunning: this.isRunning
|
|
});
|
|
|
|
// Clear any existing timer
|
|
this.stopAutoSave();
|
|
|
|
// Set up new timer
|
|
this.autoSaveTimer = setInterval(async () => {
|
|
if (debugLogger) debugLogger.logStep('Auto-save timer triggered', {
|
|
isRunning: this.isRunning,
|
|
paused: this.state.paused,
|
|
gameTime: this.gameTime,
|
|
lastAutoSave: this.lastAutoSave
|
|
});
|
|
|
|
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...');
|
|
if (debugLogger) debugLogger.logStep('Auto-saving game');
|
|
|
|
try {
|
|
await this.save();
|
|
this.showNotification('Game auto-saved', 'info', 2000);
|
|
console.log('[GAME ENGINE] Auto-save completed successfully');
|
|
|
|
this.lastAutoSave = Date.now();
|
|
if (debugLogger) debugLogger.logStep('Auto-save completed successfully', {
|
|
lastAutoSave: this.lastAutoSave
|
|
});
|
|
|
|
} 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');
|
|
if (debugLogger) debugLogger.logStep('Auto-save skipped', {
|
|
reason: this.isRunning ? 'paused' : 'not running',
|
|
isRunning: this.isRunning,
|
|
paused: this.state.paused
|
|
});
|
|
}
|
|
}, this.autoSaveInterval * 60 * 1000); // Convert minutes to milliseconds
|
|
|
|
this.lastAutoSave = Date.now();
|
|
if (debugLogger) debugLogger.logStep('Auto-save timer started', {
|
|
timerId: this.autoSaveTimer,
|
|
lastAutoSave: this.lastAutoSave
|
|
});
|
|
}
|
|
|
|
stopAutoSave() {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (this.autoSaveTimer) {
|
|
console.log('[GAME ENGINE] Stopping auto-save timer');
|
|
if (debugLogger) debugLogger.logStep('Stopping auto-save timer', {
|
|
timerId: this.autoSaveTimer,
|
|
wasRunning: true
|
|
});
|
|
|
|
clearInterval(this.autoSaveTimer);
|
|
this.autoSaveTimer = null;
|
|
|
|
if (debugLogger) debugLogger.logStep('Auto-save timer stopped');
|
|
} else {
|
|
if (debugLogger) debugLogger.logStep('stopAutoSave called but no timer was active', {
|
|
timerId: this.autoSaveTimer,
|
|
wasRunning: false
|
|
});
|
|
}
|
|
}
|
|
|
|
updateAutoSaveInterval(newInterval) {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
console.log(`[GAME ENGINE] Updating auto-save interval to ${newInterval} minutes`);
|
|
if (debugLogger) debugLogger.logStep('Updating auto-save interval', {
|
|
oldInterval: this.autoSaveInterval,
|
|
newInterval: newInterval,
|
|
isRunning: this.isRunning
|
|
});
|
|
|
|
this.autoSaveInterval = newInterval;
|
|
|
|
// Save to localStorage
|
|
localStorage.setItem('autoSaveInterval', newInterval.toString());
|
|
|
|
// Restart auto-save with new interval if game is running
|
|
if (this.isRunning) {
|
|
if (debugLogger) debugLogger.logStep('Restarting auto-save with new interval');
|
|
this.startAutoSave();
|
|
}
|
|
|
|
if (debugLogger) debugLogger.logStep('Auto-save interval updated successfully', {
|
|
currentInterval: this.autoSaveInterval,
|
|
savedToStorage: true
|
|
});
|
|
}
|
|
|
|
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
|
|
|
|
console.log('[GAME ENGINE] Game logic update called - adding', fixedDelta, 'ms to playtime');
|
|
|
|
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;
|
|
|
|
console.log('[GAME ENGINE] Total game time now:', this.gameTime, 'ms');
|
|
|
|
// Emit UI update event instead of direct call
|
|
this.emitUIUpdateEvent('full');
|
|
|
|
// Log update performance every 300 frames (approximately 5 seconds)
|
|
if (debugLogger && this.gameTime % 15000 === 0) { // Every 15 seconds of game time
|
|
debugLogger.logStep('Game logic update cycle', {
|
|
gameTime: this.gameTime,
|
|
fixedDelta: fixedDelta,
|
|
isRunning: this.isRunning,
|
|
paused: this.state.paused,
|
|
currentTab: this.state.currentTab
|
|
});
|
|
}
|
|
|
|
// Update player play time with fixed delta
|
|
if (this.systems.player && this.systems.player.updatePlayTime) {
|
|
console.log('[GAME ENGINE] Before update - player playTime:', this.systems.player.stats.playTime);
|
|
this.systems.player.updatePlayTime(fixedDelta);
|
|
console.log('[GAME ENGINE] After update - player playTime:', this.systems.player.stats.playTime);
|
|
}
|
|
|
|
// 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) {
|
|
console.log('[GAME ENGINE] Updating UI displays');
|
|
try {
|
|
this.systems.ui.updateUI();
|
|
console.log('[GAME ENGINE] UI update completed');
|
|
} catch (error) {
|
|
console.error('[GAME ENGINE] Error updating UI:', error);
|
|
}
|
|
}
|
|
}
|
|
|
|
update(deltaTime) {
|
|
// Legacy method - game logic now handled by updateGameLogic()
|
|
// This method kept for compatibility but doesn't process game systems
|
|
}
|
|
|
|
shouldUpdateGUI() {
|
|
const currentTime = Date.now();
|
|
if (currentTime - this.lastGUIUpdate >= this.guiUpdateInterval) {
|
|
this.lastGUIUpdate = currentTime;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
updateGUI() {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
console.log('[GAME ENGINE] Updating GUI');
|
|
|
|
// Update UI displays (money, gems, energy) after system updates
|
|
if (this.systems && this.systems.ui) {
|
|
console.log('[GAME ENGINE] Updating UI displays');
|
|
try {
|
|
this.systems.ui.updateUI();
|
|
console.log('[GAME ENGINE] UI update completed');
|
|
} catch (error) {
|
|
console.error('[GAME ENGINE] Error updating UI:', error);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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 }));
|
|
}
|
|
|
|
emitUIUpdateEvent(type, data = {}) {
|
|
const eventData = {
|
|
type: type,
|
|
timestamp: Date.now(),
|
|
...data
|
|
};
|
|
|
|
console.log('[GAME ENGINE] Emitting UI update event:', eventData);
|
|
this.emit('uiUpdate', eventData);
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
|
|
processNotifications() {
|
|
const now = Date.now();
|
|
this.state.notifications = this.state.notifications.filter(
|
|
notification => now - notification.timestamp < notification.duration
|
|
);
|
|
}
|
|
|
|
// Save/Load system
|
|
async save() {
|
|
const logger = window.logger;
|
|
const debugLogger = window.debugLogger;
|
|
|
|
console.log('[GAME ENGINE] Save method called');
|
|
if (logger) await logger.info('Saving game');
|
|
// if (debugLogger) await debugLogger.startStep('saveGame');
|
|
|
|
try {
|
|
// if (debugLogger) await debugLogger.logStep('Collecting save data from systems');
|
|
console.log('[GAME ENGINE] Collecting save data from systems...');
|
|
|
|
const saveData = {
|
|
player: this.systems.player.save(),
|
|
inventory: this.systems.inventory.save(),
|
|
economy: this.systems.economy.save(),
|
|
idleSystem: this.systems.idleSystem.save(),
|
|
dungeonSystem: this.systems.dungeonSystem.save(),
|
|
skillSystem: this.systems.skillSystem.save(),
|
|
baseSystem: this.systems.baseSystem.save(),
|
|
questSystem: this.systems.questSystem.save(),
|
|
gameTime: this.gameTime,
|
|
lastSave: Date.now()
|
|
};
|
|
|
|
// if (debugLogger) await debugLogger.logStep('Save data collected', {
|
|
// playerLevel: saveData.player?.stats?.level,
|
|
// gameTime: this.gameTime,
|
|
// saveDataSize: JSON.stringify(saveData).length,
|
|
// });
|
|
|
|
// console.log('[GAME ENGINE] Save data collected, player level:', saveData.player?.stats?.level);
|
|
// console.log('[GAME ENGINE] Save slot info:', this.saveSlotInfo);
|
|
|
|
// Check if we're in local mode and should use localStorage
|
|
const isLocalMode = window.liveMainMenu && window.liveMainMenu.isLocalMode;
|
|
|
|
if (isLocalMode) {
|
|
console.log('[GAME ENGINE] Using localStorage for local mode save');
|
|
if (debugLogger) await debugLogger.logStep('Saving via localStorage for local mode');
|
|
|
|
try {
|
|
const saveKey = `gso_save_slot_${this.saveSlotInfo.slot}`;
|
|
const saveString = JSON.stringify(saveData);
|
|
|
|
// Save to localStorage
|
|
localStorage.setItem(saveKey, saveString);
|
|
|
|
console.log('[GAME ENGINE] Game saved successfully to localStorage');
|
|
console.log('[GAME ENGINE] Save key:', saveKey);
|
|
console.log('[GAME ENGINE] Save data size:', saveString.length, 'characters');
|
|
console.log('[GAME ENGINE] Current localStorage keys:', Object.keys(localStorage));
|
|
|
|
// Verify save exists
|
|
const verifySave = localStorage.getItem(saveKey);
|
|
console.log('[GAME ENGINE] Save verification:', !!verifySave ? 'SUCCESS' : 'FAILED');
|
|
|
|
if (debugLogger) await debugLogger.logStep('Game saved successfully to localStorage', {
|
|
saveKey,
|
|
saveDataSize: saveString.length
|
|
});
|
|
|
|
// Emit save event
|
|
this.emit('gameSaved', { slot: this.saveSlotInfo.slot, saveData });
|
|
// if (debugLogger) debugLogger.logStep('Game saved event emitted');
|
|
|
|
} catch (error) {
|
|
console.error('[GAME ENGINE] Failed to save to localStorage:', error);
|
|
if (debugLogger) await debugLogger.errorEvent(error, 'LocalStorage Save');
|
|
throw error;
|
|
}
|
|
} else {
|
|
// Use file system if available, otherwise localStorage (original logic)
|
|
if (this.saveSlotInfo && this.saveSlotInfo.useFileSystem) {
|
|
if (window.electronAPI) {
|
|
// console.log('[GAME ENGINE] Using Electron API to save game');
|
|
// if (debugLogger) await debugLogger.logStep('Saving via Electron API', {
|
|
// slot: this.saveSlotInfo.slot,
|
|
// useFileSystem: true
|
|
// });
|
|
|
|
try {
|
|
// Save through Electron API
|
|
const result = await window.electronAPI.saveGame(this.saveSlotInfo.slot, saveData);
|
|
if (result.success) {
|
|
// console.log('[GAME ENGINE] Game saved successfully via Electron API');
|
|
if (debugLogger) await debugLogger.logStep('Game saved successfully via Electron API', {
|
|
slot: this.saveSlotInfo.slot,
|
|
result: result
|
|
});
|
|
|
|
// Emit save event
|
|
this.emit('gameSaved', { slot: this.saveSlotInfo.slot, saveData });
|
|
// if (debugLogger) debugLogger.logStep('Game saved event emitted');
|
|
|
|
} else {
|
|
console.error('[GAME ENGINE] Failed to save via Electron API:', result.error);
|
|
if (debugLogger) await debugLogger.errorEvent(new Error(result.error), 'Electron API Save');
|
|
|
|
// Fallback to localStorage
|
|
if (debugLogger) await debugLogger.logStep('Falling back to localStorage');
|
|
const saveKey = `gso_save_slot_${this.saveSlotInfo.slot}`;
|
|
localStorage.setItem(saveKey, JSON.stringify(saveData));
|
|
console.log('[GAME ENGINE] Fallback: Game saved to localStorage with key:', saveKey);
|
|
if (debugLogger) await debugLogger.logStep('Game saved to localStorage fallback', {
|
|
saveKey,
|
|
dataSize: JSON.stringify(saveData).length
|
|
});
|
|
}
|
|
} catch (error) {
|
|
console.error('[GAME ENGINE] Electron API save error:', error);
|
|
if (debugLogger) await debugLogger.errorEvent(error, 'Electron API Save');
|
|
|
|
// Fallback to localStorage
|
|
if (debugLogger) await debugLogger.logStep('Falling back to localStorage due to error');
|
|
const saveKey = `gso_save_slot_${this.saveSlotInfo.slot}`;
|
|
localStorage.setItem(saveKey, JSON.stringify(saveData));
|
|
console.log('[GAME ENGINE] Error fallback: Game saved to localStorage with key:', saveKey);
|
|
}
|
|
} else {
|
|
console.warn('[GAME ENGINE] Electron API not available, using localStorage');
|
|
if (debugLogger) await debugLogger.warn('Electron API not available, using localStorage');
|
|
|
|
const saveKey = `gso_save_slot_${this.saveSlotInfo.slot}`;
|
|
localStorage.setItem(saveKey, JSON.stringify(saveData));
|
|
console.log('[GAME ENGINE] Game saved to localStorage with key:', saveKey);
|
|
if (debugLogger) await debugLogger.logStep('Game saved to localStorage', {
|
|
saveKey,
|
|
dataSize: JSON.stringify(saveData).length
|
|
});
|
|
}
|
|
} else {
|
|
// LocalStorage fallback
|
|
if (debugLogger) await debugLogger.logStep('Using localStorage save');
|
|
const saveKey = `gso_save_slot_${this.saveSlotInfo.slot}`;
|
|
localStorage.setItem(saveKey, JSON.stringify(saveData));
|
|
console.log('[GAME ENGINE] Game saved to localStorage with key:', saveKey);
|
|
if (debugLogger) await debugLogger.logStep('Game saved to localStorage', {
|
|
saveKey,
|
|
dataSize: JSON.stringify(saveData).length
|
|
});
|
|
}
|
|
}
|
|
|
|
if (logger) await logger.info('Game saved successfully');
|
|
// if (debugLogger) await debugLogger.endStep('saveGame', {
|
|
// gameTime: this.gameTime,
|
|
// saveSlot: this.saveSlotInfo?.slot,
|
|
// success: true
|
|
// });
|
|
|
|
} catch (error) {
|
|
console.error('[GAME ENGINE] Save failed:', error);
|
|
if (logger) await logger.errorEvent(error, 'Game Save');
|
|
if (debugLogger) await debugLogger.errorEvent(error, 'Game Save');
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async loadGame() {
|
|
const logger = window.logger;
|
|
const debugLogger = window.debugLogger;
|
|
|
|
console.log('[GAME ENGINE] Load method called');
|
|
if (logger) await logger.info('Loading game');
|
|
if (debugLogger) await debugLogger.startStep('loadGame');
|
|
|
|
try {
|
|
if (debugLogger) await debugLogger.logStep('Loading save data', {
|
|
saveSlot: this.saveSlotInfo?.slot,
|
|
useFileSystem: this.saveSlotInfo?.useFileSystem
|
|
});
|
|
|
|
let saveData;
|
|
|
|
// Use file system if available, otherwise localStorage
|
|
if (this.saveSlotInfo && this.saveSlotInfo.useFileSystem && window.electronAPI) {
|
|
console.log('[GAME ENGINE] Loading via Electron API');
|
|
if (debugLogger) await debugLogger.logStep('Loading via Electron API');
|
|
|
|
const result = await window.electronAPI.loadGame(this.saveSlotInfo.slot);
|
|
if (result.success) {
|
|
saveData = result.data;
|
|
console.log('[GAME ENGINE] Game loaded successfully via Electron API');
|
|
if (debugLogger) await debugLogger.logStep('Game loaded via Electron API', {
|
|
slot: this.saveSlotInfo.slot,
|
|
dataSize: JSON.stringify(saveData).length
|
|
});
|
|
} else {
|
|
console.error('[GAME ENGINE] Failed to load via Electron API:', result.error);
|
|
if (debugLogger) await debugLogger.errorEvent(new Error(result.error), 'Electron API Load');
|
|
throw new Error(result.error);
|
|
}
|
|
} else {
|
|
// LocalStorage fallback
|
|
console.log('[GAME ENGINE] Loading from localStorage');
|
|
if (debugLogger) await debugLogger.logStep('Loading from localStorage');
|
|
|
|
const saveKey = `gso_save_slot_${this.saveSlotInfo.slot}`;
|
|
const saveString = localStorage.getItem(saveKey);
|
|
|
|
if (saveString) {
|
|
try {
|
|
saveData = JSON.parse(saveString);
|
|
console.log('[GAME ENGINE] Game loaded from localStorage');
|
|
if (debugLogger) await debugLogger.logStep('Game loaded from localStorage', {
|
|
saveKey,
|
|
dataSize: saveString.length
|
|
});
|
|
} catch (parseError) {
|
|
console.error('[GAME ENGINE] Failed to parse save data:', parseError);
|
|
if (debugLogger) await debugLogger.errorEvent(parseError, 'Parse Save Data');
|
|
throw new Error('Corrupted save data');
|
|
}
|
|
} else {
|
|
console.warn('[GAME ENGINE] No save data found in localStorage');
|
|
if (debugLogger) await debugLogger.warn('No save data found in localStorage', { saveKey });
|
|
throw new Error('No save data found');
|
|
}
|
|
}
|
|
|
|
if (debugLogger) await debugLogger.logStep('Applying save data to systems');
|
|
|
|
// Apply save data to systems
|
|
if (saveData.player && this.systems.player) {
|
|
console.log('[GAME ENGINE] Loading player data...');
|
|
this.systems.player.load(saveData.player);
|
|
if (debugLogger) await debugLogger.logStep('Player data loaded', {
|
|
level: saveData.player?.stats?.level,
|
|
experience: saveData.player?.stats?.experience
|
|
});
|
|
}
|
|
|
|
if (saveData.inventory && this.systems.inventory) {
|
|
console.log('[GAME ENGINE] Loading inventory data...');
|
|
this.systems.inventory.load(saveData.inventory);
|
|
if (debugLogger) await debugLogger.logStep('Inventory data loaded', {
|
|
itemCount: saveData.inventory.items?.length || 0
|
|
});
|
|
}
|
|
|
|
if (saveData.economy && this.systems.economy) {
|
|
console.log('[GAME ENGINE] Loading economy data...');
|
|
this.systems.economy.load(saveData.economy);
|
|
if (debugLogger) await debugLogger.logStep('Economy data loaded', {
|
|
credits: saveData.economy.credits,
|
|
gems: saveData.economy.gems
|
|
});
|
|
}
|
|
|
|
if (saveData.questSystem && this.systems.questSystem) {
|
|
console.log('[GAME ENGINE] Loading quest data...');
|
|
try {
|
|
this.systems.questSystem.load(saveData.questSystem);
|
|
if (debugLogger) await debugLogger.logStep('Quest data loaded', {
|
|
mainQuestsCount: saveData.questSystem.mainQuests?.length || 0,
|
|
dailyQuestsCount: saveData.questSystem.dailyQuests?.length || 0
|
|
});
|
|
console.log('[GAME ENGINE] Quest data loaded successfully');
|
|
} catch (questError) {
|
|
console.error('[GAME ENGINE] Failed to load quest data:', questError);
|
|
if (debugLogger) await debugLogger.errorEvent(questError, 'Quest data load failed');
|
|
// Continue with other systems instead of throwing
|
|
}
|
|
}
|
|
|
|
if (saveData.baseSystem && this.systems.baseSystem) {
|
|
console.log('[GAME ENGINE] Loading base data...');
|
|
try {
|
|
this.systems.baseSystem.load(saveData.baseSystem);
|
|
if (debugLogger) await debugLogger.logStep('Base data loaded', {
|
|
baseLevel: saveData.baseSystem.base?.level || 1,
|
|
roomsCount: saveData.baseSystem.base?.rooms?.length || 0
|
|
});
|
|
console.log('[GAME ENGINE] Base data loaded successfully');
|
|
} catch (baseError) {
|
|
console.error('[GAME ENGINE] Failed to load base data:', baseError);
|
|
if (debugLogger) await debugLogger.errorEvent(baseError, 'Base data load failed');
|
|
}
|
|
}
|
|
|
|
if (saveData.skillSystem && this.systems.skillSystem) {
|
|
console.log('[GAME ENGINE] Loading skill data...');
|
|
try {
|
|
this.systems.skillSystem.load(saveData.skillSystem);
|
|
if (debugLogger) await debugLogger.logStep('Skill data loaded');
|
|
console.log('[GAME ENGINE] Skill data loaded successfully');
|
|
} catch (skillError) {
|
|
console.error('[GAME ENGINE] Failed to load skill data:', skillError);
|
|
if (debugLogger) await debugLogger.errorEvent(skillError, 'Skill data load failed');
|
|
}
|
|
}
|
|
|
|
// CRITICAL: Initialize UIManager after loading save data
|
|
console.log('[GAME ENGINE] About to initialize UIManager - checking systems...');
|
|
console.log('[GAME ENGINE] Available systems:', Object.keys(this.systems));
|
|
console.log('[GAME ENGINE] UIManager exists:', !!this.systems.ui);
|
|
|
|
if (this.systems.ui) {
|
|
console.log('[GAME ENGINE] Initializing UIManager after save load...');
|
|
if (debugLogger) await debugLogger.logStep('Initializing UIManager after save load');
|
|
try {
|
|
await this.systems.ui.initialize();
|
|
console.log('[GAME ENGINE] UIManager initialized successfully');
|
|
if (debugLogger) await debugLogger.logStep('UIManager initialized successfully');
|
|
} catch (uiError) {
|
|
console.error('[GAME ENGINE] UIManager initialization failed:', uiError);
|
|
if (debugLogger) await debugLogger.errorEvent(uiError, 'UIManager initialization failed');
|
|
}
|
|
} else {
|
|
console.log('[GAME ENGINE] UIManager not found in systems!');
|
|
}
|
|
|
|
console.log('[GAME ENGINE] UIManager initialization section completed');
|
|
|
|
// Initialize DungeonSystem after UIManager is ready
|
|
if (this.systems.dungeonSystem) {
|
|
console.log('[GAME ENGINE] Initializing DungeonSystem...');
|
|
if (debugLogger) await debugLogger.logStep('Initializing DungeonSystem after save load');
|
|
try {
|
|
await this.systems.dungeonSystem.initialize();
|
|
console.log('[GAME ENGINE] DungeonSystem initialized successfully');
|
|
if (debugLogger) await debugLogger.logStep('DungeonSystem initialized successfully');
|
|
} catch (dungeonError) {
|
|
console.error('[GAME ENGINE] DungeonSystem initialization failed:', dungeonError);
|
|
if (debugLogger) await debugLogger.errorEvent(dungeonError, 'DungeonSystem initialization failed');
|
|
}
|
|
} else {
|
|
console.log('[GAME ENGINE] DungeonSystem not found in systems!');
|
|
}
|
|
|
|
// Restore game time
|
|
if (saveData.gameTime !== undefined) {
|
|
this.gameTime = saveData.gameTime;
|
|
console.log('[GAME ENGINE] Game time restored:', this.gameTime);
|
|
}
|
|
|
|
console.log('[GAME ENGINE] loadGame method completed successfully');
|
|
|
|
} catch (error) {
|
|
console.error('[GAME ENGINE] Failed to load game:', error);
|
|
if (logger) await logger.errorEvent(error, 'Game Load');
|
|
if (debugLogger) await debugLogger.errorEvent(error, 'loadGame');
|
|
|
|
if (debugLogger) await debugLogger.endStep('loadGame', {
|
|
success: false,
|
|
error: error.message
|
|
});
|
|
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async load() {
|
|
const logger = window.logger;
|
|
const debugLogger = window.debugLogger;
|
|
|
|
console.log('[GAME ENGINE] Load method called');
|
|
if (logger) await logger.info('Loading game');
|
|
if (debugLogger) await debugLogger.startStep('loadGame');
|
|
|
|
try {
|
|
if (debugLogger) await debugLogger.logStep('Loading save data', {
|
|
saveSlot: this.saveSlotInfo?.slot,
|
|
useFileSystem: this.saveSlotInfo?.useFileSystem
|
|
});
|
|
|
|
let saveData;
|
|
|
|
// Use file system if available, otherwise localStorage
|
|
if (this.saveSlotInfo && this.saveSlotInfo.useFileSystem && window.electronAPI) {
|
|
console.log('[GAME ENGINE] Loading via Electron API');
|
|
if (debugLogger) await debugLogger.logStep('Loading via Electron API');
|
|
|
|
const result = await window.electronAPI.loadGame(this.saveSlotInfo.slot);
|
|
if (result.success) {
|
|
saveData = result.data;
|
|
console.log('[GAME ENGINE] Game loaded successfully via Electron API');
|
|
if (debugLogger) await debugLogger.logStep('Game loaded via Electron API', {
|
|
slot: this.saveSlotInfo.slot,
|
|
dataSize: JSON.stringify(saveData).length
|
|
});
|
|
} else {
|
|
console.error('[GAME ENGINE] Failed to load via Electron API:', result.error);
|
|
if (debugLogger) await debugLogger.errorEvent(new Error(result.error), 'Electron API Load');
|
|
throw new Error(result.error);
|
|
}
|
|
} else {
|
|
// LocalStorage fallback
|
|
console.log('[GAME ENGINE] Loading from localStorage');
|
|
if (debugLogger) await debugLogger.logStep('Loading from localStorage');
|
|
|
|
const saveKey = `gso_save_slot_${this.saveSlotInfo.slot}`;
|
|
const saveString = localStorage.getItem(saveKey);
|
|
|
|
if (saveString) {
|
|
try {
|
|
saveData = JSON.parse(saveString);
|
|
console.log('[GAME ENGINE] Game loaded from localStorage');
|
|
if (debugLogger) await debugLogger.logStep('Game loaded from localStorage', {
|
|
saveKey,
|
|
dataSize: saveString.length
|
|
});
|
|
} catch (parseError) {
|
|
console.error('[GAME ENGINE] Failed to parse save data:', parseError);
|
|
if (debugLogger) await debugLogger.errorEvent(parseError, 'Parse Save Data');
|
|
throw new Error('Corrupted save data');
|
|
}
|
|
} else {
|
|
console.warn('[GAME ENGINE] No save data found in localStorage');
|
|
if (debugLogger) await debugLogger.warn('No save data found in localStorage', { saveKey });
|
|
throw new Error('No save data found');
|
|
}
|
|
}
|
|
|
|
// if (debugLogger) await debugLogger.logStep('Applying save data to systems');
|
|
|
|
// Apply save data to systems
|
|
if (saveData.player && this.systems.player) {
|
|
console.log('[GAME ENGINE] Loading player data...');
|
|
this.systems.player.load(saveData.player);
|
|
if (debugLogger) await debugLogger.logStep('Player data loaded', {
|
|
level: saveData.player?.stats?.level,
|
|
experience: saveData.player?.stats?.experience
|
|
});
|
|
}
|
|
|
|
if (saveData.inventory && this.systems.inventory) {
|
|
console.log('[GAME ENGINE] Loading inventory data...');
|
|
this.systems.inventory.load(saveData.inventory);
|
|
if (debugLogger) await debugLogger.logStep('Inventory data loaded', {
|
|
itemCount: saveData.inventory.items?.length || 0
|
|
});
|
|
}
|
|
|
|
if (saveData.economy && this.systems.economy) {
|
|
console.log('[GAME ENGINE] Loading economy data...');
|
|
this.systems.economy.load(saveData.economy);
|
|
if (debugLogger) await debugLogger.logStep('Economy data loaded', {
|
|
credits: saveData.economy.credits,
|
|
gems: saveData.economy.gems
|
|
});
|
|
}
|
|
|
|
if (saveData.gameTime) {
|
|
this.gameTime = saveData.gameTime;
|
|
if (debugLogger) await debugLogger.logStep('Game time restored', {
|
|
gameTime: this.gameTime
|
|
});
|
|
}
|
|
|
|
// Emit load event
|
|
this.emit('gameLoaded', { saveData });
|
|
if (debugLogger) debugLogger.logStep('Game loaded event emitted');
|
|
|
|
if (logger) await logger.info('Game loaded successfully');
|
|
if (debugLogger) await debugLogger.endStep('loadGame', {
|
|
gameTime: this.gameTime,
|
|
saveSlot: this.saveSlotInfo?.slot,
|
|
success: true
|
|
});
|
|
|
|
} catch (error) {
|
|
console.error('[GAME ENGINE] Load failed:', error);
|
|
if (logger) await logger.errorEvent(error, 'Game Load');
|
|
if (debugLogger) await debugLogger.errorEvent(error, 'Game Load');
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async newGame() {
|
|
const logger = window.logger;
|
|
const debugLogger = window.debugLogger;
|
|
|
|
console.log('[GAME ENGINE] Starting new game initialization');
|
|
if (logger) await logger.info('Starting new game');
|
|
if (debugLogger) await debugLogger.startStep('newGame');
|
|
|
|
try {
|
|
// For new games, we need to properly initialize systems with default data
|
|
if (debugLogger) await debugLogger.logStep('Initializing systems for new game');
|
|
|
|
// Initialize inventory with starting items
|
|
if (this.systems.inventory) {
|
|
console.log('[GAME ENGINE] Initializing inventory with starting items');
|
|
if (debugLogger) await debugLogger.logStep('Initializing inventory with starting items');
|
|
await this.systems.inventory.initialize();
|
|
}
|
|
|
|
// Initialize DungeonSystem for new game
|
|
if (this.systems.dungeonSystem) {
|
|
console.log('[GAME ENGINE] Initializing DungeonSystem for new game...');
|
|
if (debugLogger) await debugLogger.logStep('Initializing DungeonSystem for new game');
|
|
try {
|
|
await this.systems.dungeonSystem.initialize();
|
|
console.log('[GAME ENGINE] DungeonSystem initialized successfully for new game');
|
|
if (debugLogger) await debugLogger.logStep('DungeonSystem initialized successfully for new game');
|
|
} catch (dungeonError) {
|
|
console.error('[GAME ENGINE] DungeonSystem initialization failed for new game:', dungeonError);
|
|
if (debugLogger) await debugLogger.errorEvent(dungeonError, 'DungeonSystem initialization failed for new game');
|
|
}
|
|
} else {
|
|
console.log('[GAME ENGINE] DungeonSystem not found in systems!');
|
|
}
|
|
|
|
if (this.systems.player) {
|
|
console.log('[GAME ENGINE] Resetting player to initial state');
|
|
if (debugLogger) await debugLogger.logStep('Resetting player to initial state');
|
|
this.systems.player.resetToLevel1();
|
|
console.log('[GAME ENGINE] Player reset completed');
|
|
if (debugLogger) await debugLogger.logStep('Player reset completed', {
|
|
level: this.systems.player.stats.level,
|
|
experience: this.systems.player.stats.experience,
|
|
playTime: this.systems.player.stats.playTime
|
|
});
|
|
|
|
console.log('[GAME ENGINE] Setting up new player');
|
|
if (debugLogger) await debugLogger.logStep('Setting up new player');
|
|
this.systems.player.setupNewPlayer();
|
|
console.log('[GAME ENGINE] Player setup completed');
|
|
if (debugLogger) await debugLogger.logStep('Player setup completed', {
|
|
level: this.systems.player.stats.level,
|
|
experience: this.systems.player.stats.experience
|
|
});
|
|
} else {
|
|
console.error('[GAME ENGINE] Player system not available');
|
|
if (debugLogger) await debugLogger.error('Player system not available');
|
|
}
|
|
|
|
if (debugLogger) await debugLogger.logStep('Resetting economy system');
|
|
console.log('[GAME ENGINE] Step 2: Resetting economy system');
|
|
|
|
if (this.systems.economy) {
|
|
console.log('[GAME ENGINE] Calling economy.reset()');
|
|
if (debugLogger) await debugLogger.logStep('Calling economy.reset()');
|
|
this.systems.economy.reset();
|
|
console.log('[GAME ENGINE] Economy reset completed');
|
|
if (debugLogger) await debugLogger.logStep('Economy reset completed', {
|
|
credits: this.systems.economy.credits,
|
|
gems: this.systems.economy.gems
|
|
});
|
|
} else {
|
|
console.error('[GAME ENGINE] Economy system not available');
|
|
if (debugLogger) await debugLogger.error('Economy system not available');
|
|
}
|
|
|
|
// Skip inventory reset - initialize() already handles proper setup
|
|
if (debugLogger) await debugLogger.logStep('Skipping inventory reset - already initialized');
|
|
console.log('[GAME ENGINE] Skipping inventory reset - already initialized with starting items');
|
|
|
|
if (this.systems.inventory) {
|
|
if (debugLogger) await debugLogger.logStep('Inventory already initialized', {
|
|
itemCount: this.systems.inventory.items.length
|
|
});
|
|
} else {
|
|
console.error('[GAME ENGINE] Inventory system not available');
|
|
if (debugLogger) await debugLogger.error('Inventory system not available');
|
|
}
|
|
|
|
if (debugLogger) await debugLogger.logStep('Resetting quest system');
|
|
console.log('[GAME ENGINE] Step 4: Resetting quest system');
|
|
|
|
if (this.systems.questSystem) {
|
|
console.log('[GAME ENGINE] Calling questSystem.reset()');
|
|
if (debugLogger) await debugLogger.logStep('Calling questSystem.reset()');
|
|
this.systems.questSystem.reset();
|
|
console.log('[GAME ENGINE] Quest system reset completed');
|
|
if (debugLogger) await debugLogger.logStep('Quest system reset completed');
|
|
|
|
// Activate the tutorial quest for new games
|
|
console.log('[GAME ENGINE] Activating tutorial quest for new game');
|
|
if (debugLogger) await debugLogger.logStep('Activating tutorial quest');
|
|
this.systems.questSystem.startQuest('tutorial_complete');
|
|
console.log('[GAME ENGINE] Tutorial quest activated');
|
|
if (debugLogger) await debugLogger.logStep('Tutorial quest activated');
|
|
} else {
|
|
console.error('[GAME ENGINE] Quest system not available');
|
|
if (debugLogger) await debugLogger.error('Quest system not available');
|
|
}
|
|
|
|
if (debugLogger) await debugLogger.logStep('Resetting game time');
|
|
console.log('[GAME ENGINE] Step 5: Resetting game time');
|
|
this.gameTime = 0;
|
|
console.log('[GAME ENGINE] Game time reset to 0');
|
|
if (debugLogger) await debugLogger.logStep('Game time reset', { gameTime: this.gameTime });
|
|
|
|
if (logger) await logger.info('New game initialized successfully');
|
|
if (debugLogger) await debugLogger.endStep('newGame', {
|
|
gameTime: this.gameTime,
|
|
playerLevel: this.systems.player?.stats.level,
|
|
success: true
|
|
});
|
|
|
|
} catch (error) {
|
|
console.error('[GAME ENGINE] Failed to initialize new game:', error);
|
|
if (logger) await logger.errorEvent(error, 'New Game Initialization');
|
|
if (debugLogger) await debugLogger.errorEvent(error, 'New Game Initialization');
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// 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`;
|
|
}
|
|
}
|
|
|
|
toggleDebugConsole() {
|
|
const debugLogger = window.debugLogger;
|
|
// if (debugLogger) debugLogger.logStep('Toggle debug console requested');
|
|
|
|
// Implementation would go here
|
|
// console.log('[GAME ENGINE] Debug console toggle requested');
|
|
}
|
|
|
|
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
|
|
};
|
|
}
|
|
|
|
// if (debugLogger) debugLogger.logStep('Performance stats requested', stats);
|
|
|
|
return stats;
|
|
}
|
|
}
|
|
|
|
// Global game instance
|
|
let game = null;
|
|
|
|
// Export GameEngine to global scope
|
|
if (typeof window !== 'undefined') {
|
|
window.GameEngine = GameEngine;
|
|
}
|