1165 lines
50 KiB
JavaScript
1165 lines
50 KiB
JavaScript
/**
|
|
* Game Initializer
|
|
* Handles initialization of multiplayer game modes
|
|
*/
|
|
|
|
console.log('[GAME INITIALIZER] GameInitializer.js script loaded');
|
|
|
|
class GameInitializer {
|
|
constructor() {
|
|
console.log('[GAME INITIALIZER] Constructor called');
|
|
this.gameMode = 'multiplayer';
|
|
this.serverData = null;
|
|
this.authToken = null;
|
|
this.currentUser = null;
|
|
this.socket = null;
|
|
this.apiBaseUrl = 'https://api.korvarix.com/api'; // API Server
|
|
this.gameServerUrl = 'https://dev.gameserver.galaxystrike.online'; // Game Server for Socket.IO
|
|
|
|
console.log('[GAME INITIALIZER] Constructor - gameServerUrl set to:', this.gameServerUrl);
|
|
}
|
|
|
|
updateServerUrls(apiUrl, gameUrl) {
|
|
console.log('[GAME INITIALIZER] Updating server URLs:', { apiUrl: apiUrl, gameUrl: gameUrl });
|
|
console.log('[GAME INITIALIZER] Previous gameServerUrl:', this.gameServerUrl);
|
|
this.apiBaseUrl = apiUrl;
|
|
this.gameServerUrl = gameUrl;
|
|
console.log('[GAME INITIALIZER] New gameServerUrl:', this.gameServerUrl);
|
|
}
|
|
|
|
initializeMultiplayer(server, serverData, authToken, currentUser) {
|
|
console.log('[GAME INITIALIZER] Initializing multiplayer game mode');
|
|
this.gameMode = 'multiplayer';
|
|
this.serverData = { ...server, ...serverData };
|
|
this.authToken = authToken;
|
|
this.currentUser = currentUser;
|
|
|
|
// Initialize Socket.IO connection
|
|
this.initializeSocketConnection();
|
|
|
|
// Set SmartSaveManager to multiplayer mode
|
|
if (window.smartSaveManager) {
|
|
window.smartSaveManager.setMultiplayerMode(true, this);
|
|
}
|
|
|
|
// Update UI for multiplayer mode
|
|
this.updateUIForMultiplayerMode();
|
|
|
|
console.log('[GAME INITIALIZER] Multiplayer game initialized');
|
|
}
|
|
|
|
initializeSocketConnection() {
|
|
if (!this.serverData) {
|
|
console.error('[GAME INITIALIZER] No server data for socket connection');
|
|
return;
|
|
}
|
|
|
|
console.log('[GAME INITIALIZER] Initializing Socket.IO connection');
|
|
console.log('[GAME INITIALIZER] Using gameServerUrl:', this.gameServerUrl);
|
|
|
|
// Check if we're in local mode and should use mock socket
|
|
if (this.gameServerUrl.includes('localhost') && window.localServerManager && window.localServerManager.localServer) {
|
|
console.log('[GAME INITIALIZER] Using mock socket for local mode');
|
|
this.socket = window.localServerManager.localServer.createMockSocket();
|
|
|
|
// Trigger connected event immediately since mock socket auto-connects
|
|
setTimeout(() => {
|
|
this.onSocketConnected();
|
|
}, 200);
|
|
|
|
return;
|
|
}
|
|
|
|
// Resolve server URL: use serverData.url if set, otherwise gameServerUrl, then dev default
|
|
const FORCED_URL = (this.serverData && this.serverData.url)
|
|
? this.serverData.url
|
|
: (this.gameServerUrl || 'https://dev.gameserver.galaxystrike.online');
|
|
console.log('[GAME INITIALIZER] Connecting to:', FORCED_URL);
|
|
|
|
// Connect to the game server
|
|
this.socket = io(FORCED_URL, {
|
|
auth: {
|
|
token: this.authToken,
|
|
serverId: this.serverData.id
|
|
}
|
|
});
|
|
|
|
console.log('[GAME INITIALIZER] Socket.IO connection initiated to:', FORCED_URL);
|
|
|
|
// Socket event handlers
|
|
this.socket.on('connect', () => {
|
|
console.log('[GAME INITIALIZER] Connected to server');
|
|
this.onSocketConnected();
|
|
});
|
|
|
|
this.socket.on('disconnect', () => {
|
|
console.log('[GAME INITIALIZER] Disconnected from server');
|
|
this.onSocketDisconnected();
|
|
});
|
|
|
|
this.socket.on('error', (error) => {
|
|
console.error('[GAME INITIALIZER] Socket error:', error);
|
|
});
|
|
|
|
this.socket.on('force_disconnect', (data) => {
|
|
console.warn('[GAME INITIALIZER] Force disconnected:', data);
|
|
this.onForceDisconnect(data);
|
|
});
|
|
|
|
// Game-specific events
|
|
this.socket.on('playerJoined', (data) => {
|
|
console.log('[GAME INITIALIZER] Player joined:', data);
|
|
this.onPlayerJoined(data);
|
|
});
|
|
|
|
this.socket.on('playerLeft', (data) => {
|
|
console.log('[GAME INITIALIZER] Player left:', data);
|
|
this.onPlayerLeft(data);
|
|
});
|
|
|
|
this.socket.on('gameUpdate', (data) => {
|
|
console.log('[GAME INITIALIZER] Game update:', data);
|
|
this.onGameUpdate(data);
|
|
});
|
|
|
|
this.socket.on('chatMessage', (data) => {
|
|
console.log('[GAME INITIALIZER] Chat message:', data);
|
|
this.onChatMessage(data);
|
|
});
|
|
|
|
// Server data events
|
|
this.socket.on('authenticated', (data) => {
|
|
console.log('[GAME INITIALIZER] Authentication response:', data);
|
|
this.onAuthenticated(data);
|
|
});
|
|
|
|
this.socket.on('gameDataLoaded', (data) => {
|
|
console.log('[GAME INITIALIZER] Game data loaded:', data);
|
|
this.onGameDataLoaded(data);
|
|
});
|
|
|
|
this.socket.on('updatePlayerStats', (data) => {
|
|
console.log('[GAME INITIALIZER] Player stats updated on server:', data);
|
|
this.onGameDataSaved(data);
|
|
});
|
|
|
|
this.socket.on('gameDataSaved', (data) => {
|
|
console.log('[GAME INITIALIZER] Game data saved:', data);
|
|
this.onGameDataSaved(data);
|
|
});
|
|
|
|
// Idle rewards events
|
|
this.socket.on('offlineRewardsClaimed', (data) => {
|
|
console.log('[GAME INITIALIZER] Offline rewards claimed:', data);
|
|
this.onOfflineRewardsClaimed(data);
|
|
});
|
|
|
|
this.socket.on('onlineIdleRewards', (data) => {
|
|
if (data.credits > 0 || data.experience > 0) {
|
|
console.log('[GAME INITIALIZER] Online idle rewards received:', data);
|
|
}
|
|
this.onOnlineIdleRewards(data);
|
|
});
|
|
|
|
// Quest completion events
|
|
this.socket.on('quest_completed', (data) => {
|
|
console.log('[GAME INITIALIZER] Quest completed:', data);
|
|
this.onQuestCompleted(data);
|
|
});
|
|
|
|
// Player stat update events
|
|
this.socket.on('player_stat_update', (data) => {
|
|
// Check for level-up
|
|
const oldLevel = this.serverPlayerData?.stats?.level || 0;
|
|
const newLevel = data.stats?.level || data.level || 0;
|
|
if (newLevel > oldLevel && oldLevel > 0) {
|
|
this.showNotification(`🎉 Level Up! Commander Level ${newLevel}`, 'success');
|
|
if (window.GSO_Dashboard) GSO_Dashboard.refresh(this.serverPlayerData);
|
|
}
|
|
console.log('[GAME INITIALIZER] Player stat update:', data);
|
|
this.onPlayerStatUpdate(data);
|
|
});
|
|
|
|
// Quest data events
|
|
this.socket.on('quests_data', (data) => {
|
|
console.log('[GAME INITIALIZER] Quest data received:', data);
|
|
this.onQuestsData(data);
|
|
});
|
|
|
|
// PlayTime events
|
|
this.socket.on('playTimeUpdated', (data) => {
|
|
// Only log playtime updates every minute (600,000 ms) to reduce spam
|
|
if (!this.lastPlayTimeLog || Date.now() - this.lastPlayTimeLog > 60000) {
|
|
console.log('[GAME INITIALIZER] PlayTime updated:', `${Math.floor(data.playTime / 3600000)}h ${Math.floor((data.playTime % 3600000) / 60000)}m`);
|
|
this.lastPlayTimeLog = Date.now();
|
|
}
|
|
this.onPlayTimeUpdated(data);
|
|
});
|
|
|
|
// Shop purchase events
|
|
this.socket.on('purchaseCompleted', (data) => {
|
|
console.log('[GAME INITIALIZER] Purchase completed:', data);
|
|
this.onPurchaseCompleted(data);
|
|
});
|
|
|
|
// Item system events
|
|
this.socket.on('shopItemsReceived', (data) => {
|
|
console.log('[GAME INITIALIZER] Shop items received:', data);
|
|
this.onShopItemsReceived(data);
|
|
});
|
|
|
|
this.socket.on('season_data', (data) => {
|
|
if (!data?.active) return;
|
|
const s = data.season;
|
|
const banner = document.getElementById('season-banner');
|
|
if (banner) {
|
|
banner.style.display = 'flex';
|
|
const set = (id,v) => { const el=document.getElementById(id); if(el) el.textContent=v; };
|
|
set('season-icon', s.icon||'🌑');
|
|
set('season-name', `Season ${s.id}: ${s.name}`);
|
|
set('season-desc', s.description||'');
|
|
set('season-eta', `${s.daysLeft} days remaining (${s.progress}%)`);
|
|
set('season-score', data.myScore ? `Your score: ${data.myScore.toLocaleString()}` : '');
|
|
}
|
|
});
|
|
|
|
this.socket.on('galaxy_event_data', (data) => {
|
|
if (!data?.active) return;
|
|
const ev = data.event;
|
|
const banner = document.getElementById('galaxy-event-banner');
|
|
if (banner) {
|
|
banner.style.display = 'flex';
|
|
const set = (id,v) => { const el=document.getElementById(id); if(el) el.textContent=v; };
|
|
set('gev-icon', ev.icon||'👾');
|
|
set('gev-name', ev.name||'Galaxy Event');
|
|
set('gev-desc', ev.desc||'');
|
|
set('gev-eta', ev.etaLabel||'');
|
|
set('gev-participants', `${ev.participantCount||0} commanders participating`);
|
|
}
|
|
});
|
|
|
|
this.socket.on('resource_update', (data) => {
|
|
// Keep serverPlayerData.resources in sync
|
|
if (this.serverPlayerData && data.resources) {
|
|
this.serverPlayerData.resources = data.resources;
|
|
}
|
|
if (window.GSO_Resources) GSO_Resources.update(data);
|
|
});
|
|
|
|
this.socket.on('itemDetailsReceived', (data) => {
|
|
console.log('[GAME INITIALIZER] Item details received:', data);
|
|
this.onItemDetailsReceived(data);
|
|
});
|
|
}
|
|
|
|
onSocketConnected() {
|
|
// Expose socket globally for systems that need it
|
|
if (window.game) {
|
|
window.game.socket = this.socket;
|
|
}
|
|
|
|
// Join the server room
|
|
this.socket.emit('joinServer', {
|
|
serverId: this.serverData.id,
|
|
userId: this.currentUser.userId,
|
|
username: this.currentUser.username
|
|
});
|
|
|
|
// Authenticate with server to get player data
|
|
this.authenticateWithServer();
|
|
|
|
// Show connected status
|
|
this.showConnectionStatus('Connected', 'success');
|
|
}
|
|
|
|
onSocketDisconnected() {
|
|
console.log('[GAME INITIALIZER] Socket disconnected - switching to singleplayer mode');
|
|
|
|
// Show disconnected status
|
|
this.showConnectionStatus('Disconnected', 'error');
|
|
|
|
// Switch SmartSaveManager back to singleplayer mode
|
|
if (window.smartSaveManager) {
|
|
window.smartSaveManager.setMultiplayerMode(false);
|
|
console.log('[GAME INITIALIZER] SmartSaveManager set to singleplayer mode');
|
|
}
|
|
|
|
// Clear socket reference
|
|
this.socket = null;
|
|
console.log('[GAME INITIALIZER] Socket reference cleared');
|
|
}
|
|
|
|
// Force disconnect from multiplayer server
|
|
forceDisconnect() {
|
|
console.log('[GAME INITIALIZER] Force disconnect called');
|
|
|
|
if (this.socket) {
|
|
console.log('[GAME INITIALIZER] Disconnecting socket...');
|
|
this.socket.disconnect();
|
|
this.socket = null;
|
|
}
|
|
|
|
// Switch to singleplayer mode
|
|
if (window.smartSaveManager) {
|
|
window.smartSaveManager.setMultiplayerMode(false);
|
|
console.log('[GAME INITIALIZER] Force switched to singleplayer mode');
|
|
}
|
|
|
|
this.showConnectionStatus('Disconnected', 'error');
|
|
console.log('[GAME INITIALIZER] Force disconnect completed');
|
|
}
|
|
|
|
onPlayerJoined(data) {
|
|
// Handle player joining
|
|
this.updatePlayerList();
|
|
this.showNotification(`${data.username} joined the server`, 'info');
|
|
}
|
|
|
|
onPlayerLeft(data) {
|
|
// Handle player leaving
|
|
this.updatePlayerList();
|
|
this.showNotification(`${data.username} left the server`, 'info');
|
|
}
|
|
|
|
onGameUpdate(data) {
|
|
// Handle game state updates
|
|
if (window.game && window.game.handleServerUpdate) {
|
|
window.game.handleServerUpdate(data);
|
|
}
|
|
}
|
|
|
|
onChatMessage(data) {
|
|
// Handle chat messages
|
|
if (window.game && window.game.handleChatMessage) {
|
|
window.game.handleChatMessage(data);
|
|
}
|
|
}
|
|
|
|
onAuthenticated(data) {
|
|
console.log('[GAME INITIALIZER] Authentication successful:', data);
|
|
|
|
if (data.success && data.playerData) {
|
|
// Store server player data from authentication (this is our primary source)
|
|
this.serverPlayerData = data.playerData;
|
|
this.currentUser = data.user;
|
|
|
|
// CRITICAL: Force multiplayer mode and prevent fallback
|
|
if (window.smartSaveManager) {
|
|
console.log('[GAME INITIALIZER] FORCING multiplayer mode after authentication');
|
|
window.smartSaveManager.setMultiplayerMode(true, this);
|
|
}
|
|
|
|
// ItemSystem is now initialized by GameEngine - no need to initialize here
|
|
console.log('[GAME INITIALIZER] ItemSystem initialization handled by GameEngine');
|
|
|
|
console.log('[GAME INITIALIZER] Using authentication data as primary source:', this.serverPlayerData);
|
|
|
|
// NOW create GameEngine AFTER authentication is successful
|
|
if (!window.game) {
|
|
console.log('[GAME INITIALIZER] Creating GameEngine after successful authentication');
|
|
this.createGameEngineForMultiplayer();
|
|
}
|
|
|
|
// Set SmartSaveManager to multiplayer mode
|
|
if (window.smartSaveManager) {
|
|
window.smartSaveManager.setMultiplayerMode(true, this);
|
|
console.log('[GAME INITIALIZER] SmartSaveManager set to multiplayer mode');
|
|
|
|
// Apply authentication data immediately (this will be stored for later)
|
|
window.smartSaveManager.applyServerDataToGame(data.playerData);
|
|
}
|
|
|
|
// NOTE: Don't apply to GameEngine here - it doesn't exist yet!
|
|
// The data will be applied in createGameEngineForMultiplayer() after the game is created.
|
|
|
|
this.showNotification(`Welcome back! Level ${data.playerData.stats?.level || 1}`, 'success');
|
|
} else {
|
|
this.showNotification(data.error || 'Authentication failed', 'error');
|
|
}
|
|
}
|
|
|
|
createGameEngineForMultiplayer() {
|
|
console.log('[GAME INITIALIZER] Creating GameEngine for multiplayer mode');
|
|
console.log('[GAME INITIALIZER] Server player data available:', !!this.serverPlayerData);
|
|
|
|
try {
|
|
// Create GameEngine instance
|
|
window.game = new GameEngine();
|
|
|
|
// CRITICAL: Set multiplayer mode BEFORE initializing systems
|
|
console.log('[GAME INITIALIZER] Setting multiplayer mode BEFORE initialization');
|
|
window.game.setMultiplayerMode(true, this.socket, this.serverData, this.currentUser);
|
|
|
|
// NOTE: Don't apply server data immediately - wait for full initialization
|
|
console.log('[GAME INITIALIZER] Server data ready, will apply after GameEngine initialization');
|
|
console.log('[GAME INITIALIZER] - this.serverPlayerData:', !!this.serverPlayerData);
|
|
console.log('[GAME INITIALIZER] - window.game:', !!window.game);
|
|
console.log('[GAME INITIALIZER] - window.game.loadServerPlayerData:', !!window.game?.loadServerPlayerData);
|
|
|
|
// Initialize the game engine
|
|
console.log('[GAME INITIALIZER] About to call window.game.init()');
|
|
const initPromise = window.game.init();
|
|
console.log('[GAME INITIALIZER] GameEngine.init() returned:', typeof initPromise, initPromise);
|
|
|
|
// Apply server data and refresh UI after initialization is complete
|
|
initPromise.then(() => {
|
|
console.log('[GAME INITIALIZER] GameEngine initialized successfully for multiplayer');
|
|
|
|
// Apply server data immediately after initialization
|
|
if (this.serverPlayerData && window.game.loadServerPlayerData) {
|
|
console.log('[GAME INITIALIZER] Applying server player data to GameEngine:', this.serverPlayerData);
|
|
window.game.loadServerPlayerData(this.serverPlayerData);
|
|
console.log('[GAME INITIALIZER] Server player data applied to GameEngine');
|
|
|
|
// CRITICAL: Force immediate economy sync
|
|
if (window.game.systems && window.game.systems.economy && window.game.systems.economy.syncWithServerData) {
|
|
console.log('[GAME INITIALIZER] Forcing immediate economy sync with server data');
|
|
window.game.systems.economy.syncWithServerData(this.serverPlayerData);
|
|
}
|
|
|
|
// Force UI refresh
|
|
if (window.game.systems && window.game.systems.ui && window.game.systems.ui.forceRefreshAllUI) {
|
|
console.log('[GAME INITIALIZER] Forcing UI refresh after data application');
|
|
window.game.systems.ui.forceRefreshAllUI();
|
|
} else {
|
|
console.warn('[GAME INITIALIZER] UI refresh not available - systems:', !!window.game.systems, 'ui:', !!window.game.systems?.ui, 'forceRefreshAllUI:', !!window.game.systems?.ui?.forceRefreshAllUI);
|
|
}
|
|
} else {
|
|
console.warn('[GAME INITIALIZER] No server player data or loadServerPlayerData method available');
|
|
console.log('[GAME INITIALIZER] - this.serverPlayerData:', !!this.serverPlayerData);
|
|
console.log('[GAME INITIALIZER] - window.game.loadServerPlayerData:', !!window.game?.loadServerPlayerData);
|
|
}
|
|
|
|
// Start the game
|
|
if (window.game.start) {
|
|
window.game.start();
|
|
}
|
|
|
|
}).catch((error) => {
|
|
console.error('[GAME INITIALIZER] GameEngine init failed:', error);
|
|
console.error('[GAME INITIALIZER] Error details:', error.stack);
|
|
this.showNotification('Failed to initialize game engine', 'error');
|
|
});
|
|
|
|
} catch (error) {
|
|
console.error('[GAME INITIALIZER] Error creating GameEngine:', error);
|
|
this.showNotification('Error creating game engine', 'error');
|
|
}
|
|
}
|
|
|
|
onGameDataLoaded(data) {
|
|
console.log('[GAME INITIALIZER] Server game data loaded:', data);
|
|
console.log('[GAME INITIALIZER] Data success:', data.success);
|
|
console.log('[GAME INITIALIZER] Data content:', data.data);
|
|
console.log('[GAME INITIALIZER] Data keys:', data.data ? Object.keys(data.data) : 'No data object');
|
|
|
|
// Only process if we don't already have good data from authentication
|
|
if (data.success && data.data && Object.keys(data.data).length > 0 && !this.serverPlayerData) {
|
|
console.log('[GAME INITIALIZER] Using gameDataLoaded as primary source (no auth data available)');
|
|
this.serverPlayerData = data.data;
|
|
|
|
// Apply server data to game if game is running
|
|
if (window.game && window.game.loadServerPlayerData) {
|
|
window.game.loadServerPlayerData(data.data);
|
|
|
|
// Force UI refresh when server data is applied
|
|
if (window.game.systems && window.game.systems.ui && window.game.systems.ui.forceRefreshAllUI) {
|
|
window.game.systems.ui.forceRefreshAllUI();
|
|
}
|
|
}
|
|
} else {
|
|
console.log('[GAME INITIALIZER] Ignoring gameDataLoaded - already have data from authentication or data is empty');
|
|
}
|
|
}
|
|
|
|
onGameDataSaved(data) {
|
|
console.log('[GAME INITIALIZER] Server game data saved:', data);
|
|
|
|
if (data.success) {
|
|
this.showNotification('Game saved to server!', 'success');
|
|
} else {
|
|
this.showNotification(data.error || 'Failed to save to server', 'error');
|
|
}
|
|
}
|
|
|
|
onForceDisconnect(data) {
|
|
// Handle forced disconnection from server
|
|
console.warn('[GAME INITIALIZER] Force disconnected by server:', data);
|
|
|
|
// Show notification to user
|
|
if (window.game && window.game.showNotification) {
|
|
window.game.showNotification(
|
|
`Disconnected: ${data.reason}`,
|
|
'warning',
|
|
10000
|
|
);
|
|
}
|
|
|
|
// Disconnect the socket
|
|
if (this.socket) {
|
|
this.socket.disconnect();
|
|
}
|
|
|
|
// Clean up multiplayer mode
|
|
if (window.game) {
|
|
window.game.setMultiplayerMode(false);
|
|
}
|
|
|
|
// Return to main menu after a delay
|
|
setTimeout(() => {
|
|
if (window.liveMainMenu) {
|
|
window.liveMainMenu.showLoginSection();
|
|
}
|
|
}, 2000);
|
|
}
|
|
|
|
initializeGameSystems() {
|
|
console.log('[GAME INITIALIZER] Initializing game systems');
|
|
|
|
// Wait for the main game script to be ready
|
|
if (typeof window.game !== 'undefined') {
|
|
console.log('[GAME INITIALIZER] window.game is available, calling setupGameSystems');
|
|
this.setupGameSystems();
|
|
} else {
|
|
console.log('[GAME INITIALIZER] window.game not available, waiting 100ms');
|
|
// Wait for the game to be initialized
|
|
setTimeout(() => this.initializeGameSystems(), 100);
|
|
}
|
|
}
|
|
|
|
setupGameSystems() {
|
|
if (!window.game) {
|
|
console.error('[GAME INITIALIZER] Game not available');
|
|
return;
|
|
}
|
|
|
|
console.log('[GAME INITIALIZER] Setting up game systems for multiplayer mode');
|
|
|
|
// Configure game for multiplayer mode
|
|
console.log('[GAME INITIALIZER] Configuring for multiplayer mode');
|
|
// Note: setMultiplayerMode already called in createGameEngineForMultiplayer() before initialization
|
|
window.game.gameInitializer = this; // Store reference for server polling
|
|
|
|
// DISABLE game logic in multiplayer - server is authoritative
|
|
if (window.game) {
|
|
console.log('[GAME INITIALIZER] Disabling client game logic - server is authoritative');
|
|
|
|
// Override game logic methods to do nothing in multiplayer
|
|
const originalUpdateGameLogic = window.game.updateGameLogic;
|
|
window.game.updateGameLogic = function() {
|
|
// In multiplayer mode, client does NO game logic
|
|
// Server is authoritative for ALL game data including credits
|
|
// Client is display-only
|
|
};
|
|
|
|
const originalStart = window.game.start;
|
|
window.game.start = function() {
|
|
console.log('[GAME ENGINE] Multiplayer mode - client does not run game logic, server is authoritative');
|
|
console.log('[GAME ENGINE] GameInitializer reference:', !!this.gameInitializer);
|
|
console.log('[GAME ENGINE] Socket reference:', !!(this.gameInitializer && this.gameInitializer.socket));
|
|
console.log('[GAME ENGINE] Game mode:', this.gameInitializer ? this.gameInitializer.gameMode : 'no gameInitializer');
|
|
|
|
this.isRunning = true;
|
|
|
|
// NO game logic timer - client is display-only
|
|
// Server handles all game logic including credit generation
|
|
|
|
// Start server data polling for UI updates
|
|
if (this.gameInitializer && this.gameInitializer.socket) {
|
|
console.log('[GAME ENGINE] Starting server data polling for UI updates');
|
|
this.serverPollTimer = setInterval(() => {
|
|
console.log('[GAME ENGINE] Polling server for data...');
|
|
this.gameInitializer.loadGameDataFromServer();
|
|
}, 5000); // Request updates every 5 seconds
|
|
} else {
|
|
console.warn('[GAME ENGINE] Cannot start server polling - no gameInitializer or socket');
|
|
}
|
|
|
|
// Only start UI updates that use server data (every second)
|
|
if (this.systems.ui) {
|
|
console.log('[GAME ENGINE] Starting multiplayer UI updates');
|
|
this.uiUpdateTimer = setInterval(() => {
|
|
if (this.systems && this.systems.ui && this.systems.ui.updateUI) {
|
|
console.log('[GAME ENGINE] Updating multiplayer UI with server data');
|
|
this.systems.ui.updateUI();
|
|
}
|
|
}, 1000);
|
|
}
|
|
};
|
|
}
|
|
|
|
// Game is already set up with save data, just start the game loop
|
|
if (window.game.start) {
|
|
// console.log('[GAME INITIALIZER] Calling start() to begin game loop');
|
|
window.game.start();
|
|
} else if (window.game.startGame) {
|
|
// console.log('[GAME INITIALIZER] Calling startGame(false) - save data already applied');
|
|
window.game.startGame(false); // false = don't load again (save data already applied)
|
|
} else {
|
|
console.error('[GAME INITIALIZER] No start method available on window.game');
|
|
}
|
|
|
|
console.log('[GAME INITIALIZER] Game systems configured');
|
|
}
|
|
|
|
updateUIForMultiplayerMode() {
|
|
// Update UI elements to show multiplayer mode
|
|
const playerName = document.getElementById('playerName');
|
|
const playerTitle = document.getElementById('playerTitle');
|
|
const playerUsername = document.getElementById('playerUsername');
|
|
|
|
if (this.currentUser) {
|
|
// Set the player name (rank/title)
|
|
if (playerName) {
|
|
playerName.textContent = 'Commander';
|
|
}
|
|
|
|
// Set the player title
|
|
if (playerTitle) {
|
|
playerTitle.textContent = '- Rookie Pilot';
|
|
}
|
|
|
|
// Set the username next to the level
|
|
if (playerUsername) {
|
|
playerUsername.textContent = this.currentUser.username + ' ';
|
|
}
|
|
}
|
|
|
|
// Show multiplayer-specific UI elements
|
|
this.showMultiplayerUI();
|
|
|
|
// Show server info
|
|
this.showServerInfo();
|
|
}
|
|
|
|
hideMultiplayerUI() {
|
|
// Hide elements that are only relevant in multiplayer
|
|
const chatContainer = document.getElementById('chatContainer');
|
|
if (chatContainer) {
|
|
chatContainer.classList.add('hidden');
|
|
}
|
|
|
|
const playerList = document.getElementById('playerList');
|
|
if (playerList) {
|
|
playerList.classList.add('hidden');
|
|
}
|
|
}
|
|
|
|
showMultiplayerUI() {
|
|
// Show multiplayer-specific elements
|
|
const chatContainer = document.getElementById('chatContainer');
|
|
if (chatContainer) {
|
|
chatContainer.classList.remove('hidden');
|
|
}
|
|
|
|
const playerList = document.getElementById('playerList');
|
|
if (playerList) {
|
|
playerList.classList.remove('hidden');
|
|
}
|
|
}
|
|
|
|
showServerInfo() {
|
|
// Add server information to the UI
|
|
const header = document.querySelector('.game-header');
|
|
if (header && !header.querySelector('.server-info')) {
|
|
const serverInfo = document.createElement('div');
|
|
serverInfo.className = 'server-info';
|
|
serverInfo.innerHTML = `
|
|
<i class="fas fa-server"></i>
|
|
<span>${this.serverData.name} (${this.serverData.currentPlayers}/${this.serverData.maxPlayers})</span>
|
|
`;
|
|
serverInfo.style.cssText = `
|
|
background: rgba(0, 212, 255, 0.2);
|
|
color: #00d4ff;
|
|
padding: 4px 8px;
|
|
border-radius: 4px;
|
|
font-size: 0.8rem;
|
|
margin-left: 10px;
|
|
`;
|
|
header.appendChild(serverInfo);
|
|
}
|
|
}
|
|
|
|
showConnectionStatus(status, type) {
|
|
// Show connection status in the UI
|
|
const statusElement = document.getElementById('connectionStatus');
|
|
if (statusElement) {
|
|
statusElement.textContent = status;
|
|
statusElement.className = `connection-status ${type}`;
|
|
}
|
|
}
|
|
|
|
updatePlayerList() {
|
|
// Update the player list UI
|
|
if (this.socket && this.serverData) {
|
|
// Request updated player list from server
|
|
this.socket.emit('getPlayerList', { serverId: this.serverData.id });
|
|
}
|
|
}
|
|
|
|
showNotification(message, type = 'info') {
|
|
// Show a notification to the user
|
|
if (window.game && window.game.showNotification) {
|
|
window.game.showNotification(message, type, 3000);
|
|
} else {
|
|
// Fallback to alert
|
|
console.log(`[GAME INITIALIZER] Notification: ${message}`);
|
|
}
|
|
}
|
|
|
|
// Method to send actions to the server
|
|
sendGameAction(actionType, actionData) {
|
|
if (this.socket && this.gameMode === 'multiplayer') {
|
|
this.socket.emit('gameAction', {
|
|
type: actionType,
|
|
data: actionData,
|
|
userId: this.currentUser.userId,
|
|
serverId: this.serverData.id
|
|
});
|
|
}
|
|
}
|
|
|
|
// Method to send chat messages
|
|
sendChatMessage(message) {
|
|
if (this.socket && this.gameMode === 'multiplayer') {
|
|
this.socket.emit('chatMessage', {
|
|
message: message,
|
|
userId: this.currentUser.userId,
|
|
username: this.currentUser.username,
|
|
serverId: this.serverData.id
|
|
});
|
|
}
|
|
}
|
|
|
|
// Method to save game data to server (SECURE: only send specific updates)
|
|
saveGameDataToServer(gameData) {
|
|
if (this.socket && this.gameMode === 'multiplayer') {
|
|
console.log('[GAME INITIALIZER] Sending secure game updates to server');
|
|
|
|
// Only send specific, validated updates - not entire game state
|
|
const secureUpdates = {
|
|
playerStats: {
|
|
credits: gameData.player?.credits || 0,
|
|
level: gameData.player?.level || 1,
|
|
experience: gameData.player?.experience || 0,
|
|
playTime: gameData.player?.playTime || 0
|
|
},
|
|
timestamp: Date.now()
|
|
};
|
|
|
|
// Send only the specific updates for server validation
|
|
this.socket.emit('updatePlayerStats', secureUpdates);
|
|
}
|
|
}
|
|
|
|
// Method to load game data from server
|
|
loadGameDataFromServer() {
|
|
if (this.socket && this.gameMode === 'multiplayer') {
|
|
console.log('[GAME INITIALIZER] Loading game data from server');
|
|
console.log('[GAME INITIALIZER] Socket available:', !!this.socket);
|
|
console.log('[GAME INITIALIZER] Game mode:', this.gameMode);
|
|
console.log('[GAME INITIALIZER] Current user:', this.currentUser);
|
|
console.log('[GAME INITIALIZER] Emitting loadGameData event with username');
|
|
|
|
// Get username from current user or fallback to stored user
|
|
let username = 'anonymous'; // default fallback
|
|
if (this.currentUser?.username) {
|
|
username = this.currentUser.username;
|
|
} else {
|
|
// Try to get from localStorage as fallback
|
|
const storedUser = localStorage.getItem('currentUser');
|
|
if (storedUser) {
|
|
try {
|
|
const user = JSON.parse(storedUser);
|
|
username = user.username || 'anonymous';
|
|
} catch (e) {
|
|
console.warn('[GAME INITIALIZER] Failed to parse stored user, using default');
|
|
}
|
|
}
|
|
}
|
|
|
|
console.log('[GAME INITIALIZER] Using username for data load:', username);
|
|
|
|
// Send the username to load the correct player data
|
|
this.socket.emit('loadGameData', {
|
|
username: username
|
|
});
|
|
} else {
|
|
console.log('[GAME INITIALIZER] Cannot load game data - socket or multiplayer mode not available');
|
|
console.log('[GAME INITIALIZER] Socket available:', !!this.socket);
|
|
console.log('[GAME INITIALIZER] Game mode:', this.gameMode);
|
|
}
|
|
}
|
|
|
|
// Method to authenticate with server
|
|
authenticateWithServer() {
|
|
console.log('[GAME INITIALIZER] authenticateWithServer called');
|
|
console.log('[GAME INITIALIZER] Socket available:', !!this.socket);
|
|
console.log('[GAME INITIALIZER] Game mode:', this.gameMode);
|
|
console.log('[GAME INITIALIZER] Current user:', this.currentUser);
|
|
|
|
if (this.socket && this.currentUser) {
|
|
console.log('[GAME INITIALIZER] Sending authentication to server');
|
|
this.socket.emit('authenticate', {
|
|
userId: this.currentUser.userId,
|
|
username: this.currentUser.username
|
|
});
|
|
} else {
|
|
// Try to get from localStorage as fallback
|
|
const storedUser = localStorage.getItem('currentUser');
|
|
if (storedUser) {
|
|
try {
|
|
const user = JSON.parse(storedUser);
|
|
const username = user.username || 'anonymous';
|
|
} catch (e) {
|
|
console.warn('[GAME INITIALIZER] Failed to parse stored user, using default');
|
|
}
|
|
} else {
|
|
window.game.showNotification('No offline rewards available', 'info', 3000);
|
|
}
|
|
}
|
|
}
|
|
|
|
onOnlineIdleRewards(data) {
|
|
if (window.game && window.game.systems) {
|
|
// Only log if there are actual rewards to process
|
|
if (data.credits > 0 || data.experience > 0 || data.energy > 0) {
|
|
console.log('[GAME INITIALIZER] Processing online idle rewards:', data);
|
|
}
|
|
|
|
// Update player balance with online idle rewards
|
|
if (data.credits > 0) {
|
|
// Update the Economy system's local credits
|
|
if (window.game.systems.economy) {
|
|
window.game.systems.economy.credits += data.credits;
|
|
|
|
// Update UI immediately
|
|
if (window.game.ui) {
|
|
window.game.ui.updatePlayerStats();
|
|
console.log('[GAME INITIALIZER] UI updated with new credits');
|
|
}
|
|
} else {
|
|
console.warn('[GAME INITIALIZER] Economy system not available for credit update');
|
|
}
|
|
|
|
// Show notification
|
|
window.game.showNotification(`+${data.credits} credits (online idle)`, 'success', 2000);
|
|
}
|
|
|
|
// Update experience if provided
|
|
if (data.experience > 0 && window.game.systems.player) {
|
|
window.game.systems.player.addExperience(data.experience);
|
|
console.log('[GAME INITIALIZER] Added idle experience:', data.experience);
|
|
}
|
|
} else {
|
|
console.warn('[GAME INITIALIZER] Game systems not available for idle rewards');
|
|
}
|
|
}
|
|
|
|
onPlayTimeUpdated(data) {
|
|
// PlayTime updates are handled in the socket listener with throttled logging
|
|
if (window.game && window.game.systems && window.game.systems.player) {
|
|
const player = window.game.systems.player;
|
|
|
|
// Update playTime from server
|
|
player.stats.playTime = data.playTime;
|
|
|
|
// Update UI
|
|
player.updateUI();
|
|
}
|
|
}
|
|
|
|
onPurchaseCompleted(data) {
|
|
if (data.success) {
|
|
// Update local player data with server response
|
|
if (window.game && window.game.systems && window.game.systems.economy) {
|
|
const economy = window.game.systems.economy;
|
|
|
|
// Update currency balance
|
|
if (data.currency === 'credits') {
|
|
economy.credits = data.newBalance;
|
|
} else if (data.currency === 'gems') {
|
|
economy.gems = data.newBalance;
|
|
}
|
|
|
|
// Add item to inventory if it's a consumable or material
|
|
if (data.item && (data.item.type === 'consumable' || data.item.type === 'material')) {
|
|
if (window.game.systems.inventory) {
|
|
console.log('[GAME INITIALIZER] Adding item to inventory:', data.item);
|
|
window.game.systems.inventory.addItem(data.item, data.quantity || 1);
|
|
window.game.showNotification(`${data.item.name} added to inventory!`, 'success', 3000);
|
|
}
|
|
}
|
|
|
|
// Update owned ships if it's a ship
|
|
if (data.item && data.item.type === 'ship') {
|
|
if (!economy.ownedShips) economy.ownedShips = [];
|
|
if (!economy.ownedShips.includes(data.item.id)) {
|
|
economy.ownedShips.push(data.item.id);
|
|
console.log('[GAME INITIALIZER] Ship added to owned ships:', data.item.id);
|
|
|
|
// Add ship to BaseSystem ship gallery
|
|
if (window.game.systems.baseSystem) {
|
|
console.log('[GAME INITIALIZER] BaseSystem available, adding ship to gallery');
|
|
const shipData = {
|
|
id: data.item.id,
|
|
name: data.item.name,
|
|
class: data.item.name.replace(/\s+/g, '_').toLowerCase(), // Generate class from name
|
|
level: 1,
|
|
stats: data.item.stats || {},
|
|
texture: data.item.texturePath || `assets/textures/ships/${data.item.id}.png`,
|
|
isCurrent: false,
|
|
rarity: data.item.rarity || 'common'
|
|
};
|
|
|
|
console.log('[GAME INITIALIZER] Ship data prepared:', shipData);
|
|
|
|
// Initialize ship gallery if needed
|
|
if (!window.game.systems.baseSystem.purchasedShips) {
|
|
console.log('[GAME INITIALIZER] Initializing ship gallery');
|
|
window.game.systems.baseSystem.initializeShipGallery();
|
|
}
|
|
|
|
// Check if ship already exists
|
|
const existingShip = window.game.systems.baseSystem.purchasedShips.find(s => s.id === shipData.id);
|
|
if (!existingShip) {
|
|
// Add ship to gallery
|
|
window.game.systems.baseSystem.purchasedShips.push(shipData);
|
|
console.log('[GAME INITIALIZER] Ship added to gallery. Total ships:', window.game.systems.baseSystem.purchasedShips.length);
|
|
|
|
// Update the ship gallery UI
|
|
window.game.systems.baseSystem.updateShipGallery();
|
|
console.log('[GAME INITIALIZER] Ship gallery UI updated');
|
|
} else {
|
|
console.log('[GAME INITIALIZER] Ship already exists in gallery:', shipData.id);
|
|
}
|
|
} else {
|
|
console.error('[GAME INITIALIZER] BaseSystem not available for ship gallery');
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update owned cosmetics if it's a cosmetic
|
|
if (data.item && data.item.type === 'cosmetic') {
|
|
if (!economy.ownedCosmetics) economy.ownedCosmetics = [];
|
|
if (!economy.ownedCosmetics.includes(data.item.id)) {
|
|
economy.ownedCosmetics.push(data.item.id);
|
|
console.log('[GAME INITIALIZER] Cosmetic added to owned cosmetics:', data.item.id);
|
|
}
|
|
}
|
|
|
|
// Request fresh economy data from server to ensure sync
|
|
if (economy.requestEconomyData) {
|
|
setTimeout(() => {
|
|
economy.requestEconomyData();
|
|
}, 500);
|
|
}
|
|
|
|
// Also request economy data immediately to prevent reset
|
|
if (economy.requestEconomyData) {
|
|
economy.requestEconomyData();
|
|
}
|
|
|
|
// Update UI
|
|
economy.updateUI();
|
|
|
|
// Update inventory UI if item was added
|
|
if (data.item && (data.item.type === 'consumable' || data.item.type === 'material')) {
|
|
if (window.game.systems.inventory) {
|
|
window.game.systems.inventory.updateUI();
|
|
}
|
|
}
|
|
|
|
// Show success message
|
|
window.game.showNotification(`Purchased ${data.item.name}!`, 'success', 3000);
|
|
}
|
|
} else {
|
|
// Show error message
|
|
window.game.showNotification(`Purchase failed: ${data.error}`, 'error', 5000);
|
|
}
|
|
}
|
|
|
|
onShopItemsReceived(data) {
|
|
if (data.success && window.game && window.game.systems && window.game.systems.itemSystem) {
|
|
console.log('[GAME INITIALIZER] Processing shop items data structure:', Object.keys(data));
|
|
|
|
// Handle both old (data.items) and new (data.shopItems) structures
|
|
let itemsToProcess = null;
|
|
|
|
if (data.shopItems && typeof data.shopItems === 'object') {
|
|
// New structure: categorized items
|
|
console.log('[GAME INITIALIZER] Using new shop structure');
|
|
itemsToProcess = Object.values(data.shopItems).flat();
|
|
console.log('[GAME INITIALIZER] Flattened', itemsToProcess.length, 'items from categories');
|
|
} else if (data.items && Array.isArray(data.items)) {
|
|
// Old structure: flat array
|
|
console.log('[GAME INITIALIZER] Using old shop structure');
|
|
itemsToProcess = data.items;
|
|
console.log('[GAME INITIALIZER] Processing', itemsToProcess.length, 'items from flat array');
|
|
} else {
|
|
console.warn('[GAME INITIALIZER] Invalid shop items structure:', data);
|
|
return;
|
|
}
|
|
|
|
// Update ItemSystem with server data
|
|
window.game.systems.itemSystem.processServerItems(itemsToProcess);
|
|
console.log('[GAME INITIALIZER] ItemSystem updated with server shop items');
|
|
|
|
// Update Economy shop UI
|
|
if (window.game.systems.economy) {
|
|
window.game.systems.economy.updateShopUI();
|
|
console.log('[GAME INITIALIZER] Economy shop UI updated');
|
|
}
|
|
} else {
|
|
console.warn('[GAME INITIALIZER] Failed to receive shop items:', data);
|
|
}
|
|
}
|
|
|
|
onItemDetailsReceived(data) {
|
|
// This is handled by the ItemSystem directly
|
|
// Just log for debugging
|
|
if (data.success) {
|
|
console.log('[GAME INITIALIZER] Item details received for:', data.item.name);
|
|
} else {
|
|
console.warn('[GAME INITIALIZER] Failed to receive item details:', data);
|
|
}
|
|
}
|
|
|
|
// Cleanup method
|
|
cleanup() {
|
|
console.log('[GAME INITIALIZER] Cleaning up');
|
|
|
|
// Reset SmartSaveManager to singleplayer mode
|
|
if (window.smartSaveManager) {
|
|
window.smartSaveManager.setMultiplayerMode(false);
|
|
}
|
|
|
|
if (this.socket) {
|
|
this.socket.disconnect();
|
|
this.socket = null;
|
|
}
|
|
|
|
this.gameMode = null;
|
|
this.serverData = null;
|
|
this.authToken = null;
|
|
this.currentUser = null;
|
|
this.serverPlayerData = null;
|
|
}
|
|
|
|
onQuestCompleted(data) {
|
|
console.log('[GAME INITIALIZER] Processing quest completion:', data);
|
|
|
|
// Show quest completion notification
|
|
if (window.game && window.game.showNotification) {
|
|
const questName = data.questId.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase());
|
|
window.game.showNotification(`Quest Completed: ${questName}! 🎯`, 'success', 5000);
|
|
}
|
|
|
|
// Award quest rewards
|
|
if (data.rewards) {
|
|
if (data.rewards.experience > 0 && window.game.systems.player) {
|
|
window.game.systems.player.addExperience(data.rewards.experience);
|
|
console.log('[GAME INITIALIZER] Awarded quest experience:', data.rewards.experience);
|
|
}
|
|
|
|
if (data.rewards.credits > 0 && window.game.systems.economy) {
|
|
window.game.systems.economy.credits += data.rewards.credits;
|
|
console.log('[GAME INITIALIZER] Awarded quest credits:', data.rewards.credits);
|
|
}
|
|
}
|
|
|
|
// Update quest UI if quest system exists
|
|
if (window.game && window.game.systems && window.game.systems.questSystem) {
|
|
window.game.systems.questSystem.completeQuest(data.questId, data.rewards);
|
|
|
|
// Force fetch fresh quest data from server (Fix #1 - Corrected)
|
|
console.log('[GAME INITIALIZER] Requesting fresh quest data from server after completion');
|
|
|
|
// Request fresh quest data from server
|
|
if (window.gameInitializer && window.gameInitializer.socket) {
|
|
window.gameInitializer.socket.emit('get_quests');
|
|
}
|
|
}
|
|
|
|
// Force quest UI refresh for server-driven quests
|
|
if (typeof updateQuestDisplay === 'function') {
|
|
updateQuestDisplay();
|
|
}
|
|
|
|
// Update UI
|
|
if (window.game && window.game.ui) {
|
|
window.game.ui.updatePlayerStats();
|
|
}
|
|
}
|
|
|
|
onPlayerStatUpdate(data) {
|
|
console.log('[GAME INITIALIZER] Processing player stat update:', data);
|
|
|
|
if (window.game && window.game.systems && window.game.systems.player && window.game.systems.player.stats) {
|
|
// Update the player stat
|
|
window.game.systems.player.stats[data.stat] = data.value;
|
|
console.log('[GAME INITIALIZER] Updated player stat:', data.stat, '=', data.value);
|
|
|
|
// Update UI to reflect the change
|
|
if (window.game.ui) {
|
|
window.game.ui.updatePlayerStats();
|
|
}
|
|
|
|
// Update quest system to check for quest progress
|
|
if (window.game.systems.questSystem) {
|
|
window.game.systems.questSystem.checkQuestAvailability();
|
|
}
|
|
}
|
|
}
|
|
|
|
onQuestsData(data) {
|
|
console.log('[GAME INITIALIZER] Processing quest data from server:', data);
|
|
console.log('[GAME INITIALIZER] Quest data keys:', Object.keys(data || {}));
|
|
console.log('[GAME INITIALIZER] Main quests count:', (data?.mainQuests || []).length);
|
|
console.log('[GAME INITIALIZER] Daily quests count:', (data?.dailyQuests || []).length);
|
|
console.log('[GAME INITIALIZER] Weekly quests count:', (data?.weeklyQuests || []).length);
|
|
|
|
if (window.game && window.game.systems && window.game.systems.questSystem) {
|
|
// Load quest data into the quest system
|
|
if (window.game.systems.questSystem.loadServerQuests) {
|
|
console.log('[GAME INITIALIZER] Calling loadServerQuests with data');
|
|
window.game.systems.questSystem.loadServerQuests(data);
|
|
console.log('[GAME INITIALIZER] Loaded quest data into quest system');
|
|
} else {
|
|
console.log('[GAME INITIALIZER] loadServerQuests method not found');
|
|
}
|
|
|
|
// Update quest UI
|
|
if (typeof updateQuestDisplay === 'function') {
|
|
console.log('[GAME INITIALIZER] Calling updateQuestDisplay');
|
|
updateQuestDisplay();
|
|
} else {
|
|
console.log('[GAME INITIALIZER] updateQuestDisplay function not found');
|
|
}
|
|
} else {
|
|
console.log('[GAME INITIALIZER] Quest system not available');
|
|
}
|
|
}
|
|
}
|
|
|
|
// Create global instance
|
|
window.gameInitializer = new GameInitializer();
|
|
|
|
// Make force disconnect available globally for testing
|
|
window.forceDisconnectMultiplayer = function() {
|
|
if (window.gameInitializer && window.gameInitializer.forceDisconnect) {
|
|
window.gameInitializer.forceDisconnect();
|
|
} else {
|
|
console.log('[GAME INITIALIZER] GameInitializer not available for force disconnect');
|
|
}
|
|
};
|
|
|
|
// Debug: Log the global instance immediately
|
|
console.log('[GAME INITIALIZER] Global instance created:', window.gameInitializer);
|
|
console.log('[GAME INITIALIZER] Global instance gameServerUrl:', window.gameInitializer.gameServerUrl);
|
|
|
|
// Export for use in other scripts
|
|
if (typeof module !== 'undefined' && module.exports) {
|
|
module.exports = GameInitializer;
|
|
}
|