almost a full rework of the client with server data-driven calls
This commit is contained in:
parent
4aeb217e51
commit
b793b85e25
@ -10,8 +10,6 @@
|
||||
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&family=Space+Mono:wght@400;700&display=swap" rel="stylesheet">
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
|
||||
<script src="https://cdn.socket.io/4.7.4/socket.io.min.js"></script>
|
||||
<script src="js/SimpleLocalServer.js"></script>
|
||||
<script src="js/LocalServerManager.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Custom Title Bar -->
|
||||
@ -220,8 +218,14 @@
|
||||
<div class="header-left">
|
||||
<h1 class="logo">GSO</h1>
|
||||
<div class="player-info">
|
||||
<span class="player-name" id="playerName">Commander</span>
|
||||
<span class="player-level" id="playerLevel">Lv. 1</span>
|
||||
<div>
|
||||
<span class="player-name" id="playerName">Commander</span>
|
||||
<span class="player-title" id="playerTitle">- Rookie Pilot</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="player-username" id="playerUsername"></span>
|
||||
<span class="player-level" id="playerLevel">Lv. 1</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
@ -261,35 +265,35 @@
|
||||
|
||||
<!-- Navigation -->
|
||||
<nav class="main-nav">
|
||||
<button class="nav-btn active" data-tab="dashboard">
|
||||
<button class="nav-btn active" data-tab="dashboard" onclick="switchToTab('dashboard')">
|
||||
<i class="fas fa-tachometer-alt"></i>
|
||||
<span>Dashboard</span>
|
||||
</button>
|
||||
<button class="nav-btn" data-tab="dungeons">
|
||||
<button class="nav-btn" data-tab="dungeons" onclick="switchToTab('dungeons')">
|
||||
<i class="fas fa-dungeon"></i>
|
||||
<span>Dungeons</span>
|
||||
</button>
|
||||
<button class="nav-btn" data-tab="skills">
|
||||
<button class="nav-btn" data-tab="skills" onclick="switchToTab('skills')">
|
||||
<i class="fas fa-graduation-cap"></i>
|
||||
<span>Skills</span>
|
||||
</button>
|
||||
<button class="nav-btn" data-tab="base">
|
||||
<button class="nav-btn" data-tab="base" onclick="switchToTab('base')">
|
||||
<i class="fas fa-home"></i>
|
||||
<span>Base</span>
|
||||
</button>
|
||||
<button class="nav-btn" data-tab="quests">
|
||||
<button class="nav-btn" data-tab="quests" onclick="switchToTab('quests')">
|
||||
<i class="fas fa-scroll"></i>
|
||||
<span>Quests</span>
|
||||
</button>
|
||||
<button class="nav-btn" data-tab="inventory">
|
||||
<button class="nav-btn" data-tab="inventory" onclick="switchToTab('inventory')">
|
||||
<i class="fas fa-backpack"></i>
|
||||
<span>Inventory</span>
|
||||
</button>
|
||||
<button class="nav-btn" data-tab="crafting">
|
||||
<button class="nav-btn" data-tab="crafting" onclick="switchToTab('crafting')">
|
||||
<i class="fas fa-hammer"></i>
|
||||
<span>Crafting</span>
|
||||
</button>
|
||||
<button class="nav-btn" data-tab="shop">
|
||||
<button class="nav-btn" data-tab="shop" onclick="switchToTab('shop')">
|
||||
<i class="fas fa-store"></i>
|
||||
<span>Shop</span>
|
||||
</button>
|
||||
@ -320,7 +324,35 @@
|
||||
<p>Resources Gained: <span id="offlineResources">0</span></p>
|
||||
<button class="btn btn-primary" id="claimOfflineBtn">Claim Rewards</button>
|
||||
</div>
|
||||
<div class="stats-grid">
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>Player Stats</h3>
|
||||
<div class="player-stats-grid">
|
||||
<div class="stat">
|
||||
<span class="stat-label">Level</span>
|
||||
<span class="stat-value" id="playerLevelDisplay">1</span>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<span class="stat-label">Experience</span>
|
||||
<span class="stat-value" id="playerXP">0 / 100</span>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<span class="stat-label">Skill Points</span>
|
||||
<span class="stat-value" id="skillPoints">0</span>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<span class="stat-label">Total XP Earned</span>
|
||||
<span class="stat-value" id="totalXP">0</span>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<span class="stat-label">Quests Completed</span>
|
||||
<span class="stat-value" id="questsCompleted">0</span>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<span class="stat-label">Last Login</span>
|
||||
<span class="stat-value" id="lastLogin">Never</span>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<span class="stat-label">Total Kills</span>
|
||||
<span class="stat-value" id="totalKills">0</span>
|
||||
@ -331,7 +363,7 @@
|
||||
</div>
|
||||
<div class="stat">
|
||||
<span class="stat-label">Play Time</span>
|
||||
<span class="stat-value" id="playTime">0h 0m</span>
|
||||
<span class="stat-value" id="playTime">0m 0s</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -366,9 +398,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="skill-categories">
|
||||
<button class="skill-cat-btn active" data-category="combat">Combat</button>
|
||||
<button class="skill-cat-btn" data-category="science">Science</button>
|
||||
<button class="skill-cat-btn" data-category="crafting">Crafting</button>
|
||||
<button class="skill-cat-btn active" data-category="combat" onclick="switchSkillCategory('combat')">Combat</button>
|
||||
<button class="skill-cat-btn" data-category="science" onclick="switchSkillCategory('science')">Science</button>
|
||||
<button class="skill-cat-btn" data-category="crafting" onclick="switchSkillCategory('crafting')">Crafting</button>
|
||||
</div>
|
||||
<div class="skills-grid" id="skillsGrid">
|
||||
<!-- Skills will be generated here -->
|
||||
@ -379,10 +411,10 @@
|
||||
<!-- Base Tab -->
|
||||
<div class="tab-content" id="base-tab">
|
||||
<div class="base-navigation">
|
||||
<button class="base-nav-btn active" data-view="overview">Base Overview</button>
|
||||
<button class="base-nav-btn" data-view="visualization">Base Visualization</button>
|
||||
<button class="base-nav-btn" data-view="ships">Ship Gallery</button>
|
||||
<button class="base-nav-btn" data-view="starbases">Starbases</button>
|
||||
<button class="base-nav-btn active" data-view="overview" onclick="switchBaseView('overview')">Base Overview</button>
|
||||
<button class="base-nav-btn" data-view="visualization" onclick="switchBaseView('visualization')">Base Visualization</button>
|
||||
<button class="base-nav-btn" data-view="ships" onclick="switchBaseView('ships')">Ship Gallery</button>
|
||||
<button class="base-nav-btn" data-view="starbases" onclick="switchBaseView('starbases')">Starbases</button>
|
||||
</div>
|
||||
|
||||
<!-- Base Overview -->
|
||||
@ -515,11 +547,11 @@
|
||||
<div class="tab-content" id="quests-tab">
|
||||
<div class="quests-container">
|
||||
<div class="quest-tabs">
|
||||
<button class="quest-tab-btn active" data-type="main">Main Story</button>
|
||||
<button class="quest-tab-btn" data-type="daily">Daily</button>
|
||||
<button class="quest-tab-btn" data-type="weekly">Weekly</button>
|
||||
<button class="quest-tab-btn" data-type="completed">Completed</button>
|
||||
<button class="quest-tab-btn" data-type="failed">Failed Quests</button>
|
||||
<button class="quest-tab-btn active" data-type="main" onclick="switchQuestCategory('main')">Main Story</button>
|
||||
<button class="quest-tab-btn" data-type="daily" onclick="switchQuestCategory('daily')">Daily</button>
|
||||
<button class="quest-tab-btn" data-type="weekly" onclick="switchQuestCategory('weekly')">Weekly</button>
|
||||
<button class="quest-tab-btn" data-type="completed" onclick="switchQuestCategory('completed')">Completed</button>
|
||||
<button class="quest-tab-btn" data-type="failed" onclick="switchQuestCategory('failed')">Failed Quests</button>
|
||||
</div>
|
||||
<div class="daily-countdown" id="dailyCountdown">Daily quests reset in: 00:00:00</div>
|
||||
<div class="weekly-countdown" id="weeklyCountdown">Weekly quests reset in: 0d 00:00</div>
|
||||
@ -600,10 +632,10 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="crafting-categories">
|
||||
<button class="crafting-cat-btn active" data-category="weapons">Weapons</button>
|
||||
<button class="crafting-cat-btn" data-category="armor">Armor</button>
|
||||
<button class="crafting-cat-btn" data-category="items">Items</button>
|
||||
<button class="crafting-cat-btn" data-category="ships">Ships</button>
|
||||
<button class="crafting-cat-btn active" data-category="weapons" onclick="switchCraftingCategory('weapons')">Weapons</button>
|
||||
<button class="crafting-cat-btn" data-category="armor" onclick="switchCraftingCategory('armor')">Armor</button>
|
||||
<button class="crafting-cat-btn" data-category="items" onclick="switchCraftingCategory('items')">Items</button>
|
||||
<button class="crafting-cat-btn" data-category="ships" onclick="switchCraftingCategory('ships')">Ships</button>
|
||||
</div>
|
||||
<div class="crafting-grid" id="recipeList">
|
||||
<!-- Recipes will be generated here -->
|
||||
@ -616,13 +648,13 @@
|
||||
<div class="shop-container">
|
||||
<div class="shop-header">
|
||||
<div class="shop-categories">
|
||||
<button class="shop-cat-btn active" data-category="ships">Ships</button>
|
||||
<button class="shop-cat-btn" data-category="weapons">Weapons</button>
|
||||
<button class="shop-cat-btn" data-category="armors">Armors</button>
|
||||
<button class="shop-cat-btn active" data-category="ships" onclick="switchShopCategory('ships')">Ships</button>
|
||||
<button class="shop-cat-btn" data-category="weapons" onclick="switchShopCategory('weapons')">Weapons</button>
|
||||
<button class="shop-cat-btn" data-category="armors" onclick="switchShopCategory('armors')">Armors</button>
|
||||
<!-- <button class="shop-cat-btn" data-category="upgrades">Upgrades</button> -->
|
||||
<button class="shop-cat-btn" data-category="cosmetics">Cosmetics</button>
|
||||
<button class="shop-cat-btn" data-category="consumables">Consumables</button>
|
||||
<button class="shop-cat-btn" data-category="materials">Materials</button>
|
||||
<button class="shop-cat-btn" data-category="cosmetics" onclick="switchShopCategory('cosmetics')">Cosmetics</button>
|
||||
<button class="shop-cat-btn" data-category="consumables" onclick="switchShopCategory('consumables')">Consumables</button>
|
||||
<button class="shop-cat-btn" data-category="materials" onclick="switchShopCategory('materials')">Materials</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="shop-content">
|
||||
@ -672,12 +704,558 @@
|
||||
<script src="js/systems/QuestSystem.js"></script>
|
||||
<script src="js/systems/ShipSystem.js"></script>
|
||||
<script src="js/systems/IdleSystem.js"></script>
|
||||
<script src="js/systems/ItemSystem.js"></script>
|
||||
<script src="js/systems/CraftingSystem.js"></script>
|
||||
<script src="js/data/GameData.js"></script>
|
||||
<script src="js/ui/UIManager.js"></script>
|
||||
<script src="js/SmartSaveManager.js"></script>
|
||||
<script src="js/SaveSystemIntegration.js"></script>
|
||||
<script src="https://cdn.socket.io/4.7.4/socket.io.min.js"></script>
|
||||
<script src="js/GameInitializer.js"></script>
|
||||
<script src="js/ui/LiveMainMenu.js"></script>
|
||||
<script src="js/main.js"></script>
|
||||
|
||||
<!-- Global Navigation Function -->
|
||||
<script>
|
||||
function switchToTab(tabName) {
|
||||
console.log('[GLOBAL] switchToTab called with:', tabName);
|
||||
|
||||
// Try to use UIManager first
|
||||
if (window.game && window.game.systems && window.game.systems.ui) {
|
||||
console.log('[GLOBAL] Using UIManager to switch tab');
|
||||
window.game.systems.ui.switchTab(tabName);
|
||||
|
||||
// Force update the specific tab content
|
||||
console.log('[GLOBAL] Forcing update for tab:', tabName);
|
||||
switch(tabName) {
|
||||
case 'shop':
|
||||
if (window.game.systems.economy) {
|
||||
console.log('[GLOBAL] Forcing shop UI update');
|
||||
window.game.systems.economy.updateShopUI();
|
||||
}
|
||||
break;
|
||||
case 'quests':
|
||||
console.log('[GLOBAL] Quest system check:', {
|
||||
hasGame: !!window.game,
|
||||
hasSystems: !!(window.game?.systems),
|
||||
hasQuestSystem: !!(window.game?.systems?.questSystem),
|
||||
questSystemType: typeof window.game?.systems?.questSystem
|
||||
});
|
||||
|
||||
// REMOVED: QuestSystem should be server-driven only
|
||||
console.log('[GLOBAL] Quests are server-driven - displaying server quest data');
|
||||
|
||||
// Display server quest data
|
||||
const questListElement = document.getElementById('questList');
|
||||
if (questListElement) {
|
||||
// Get quest data from server playerData
|
||||
const serverPlayerData = window.gameInitializer?.serverPlayerData;
|
||||
if (serverPlayerData && serverPlayerData.quests) {
|
||||
const quests = serverPlayerData.quests;
|
||||
console.log('[GLOBAL] Displaying server quest data:', quests);
|
||||
|
||||
// Categorize quests on client since server sends old format
|
||||
const activeQuests = quests.active || [];
|
||||
const mainQuests = activeQuests.filter(quest => quest.type === 'main');
|
||||
const dailyQuests = activeQuests.filter(quest => quest.type === 'daily');
|
||||
const weeklyQuests = activeQuests.filter(quest => quest.type === 'weekly');
|
||||
const tutorialQuests = activeQuests.filter(quest => quest.type === 'tutorial');
|
||||
|
||||
console.log('[GLOBAL] Client-side categorization:', {
|
||||
mainQuests: mainQuests.length,
|
||||
dailyQuests: dailyQuests.length,
|
||||
weeklyQuests: weeklyQuests.length,
|
||||
tutorialQuests: tutorialQuests.length
|
||||
});
|
||||
|
||||
// Get the currently selected quest tab type
|
||||
const activeQuestTab = document.querySelector('.quest-tab-btn.active')?.dataset.type || 'main';
|
||||
console.log('[GLOBAL] Active quest tab:', activeQuestTab);
|
||||
console.log('[GLOBAL] All quest tab buttons:', document.querySelectorAll('.quest-tab-btn'));
|
||||
console.log('[GLOBAL] Active button found:', document.querySelector('.quest-tab-btn.active'));
|
||||
|
||||
// Force check for debugging
|
||||
document.querySelectorAll('.quest-tab-btn').forEach(btn => {
|
||||
console.log('[GLOBAL] Quest tab button:', btn.dataset.type, 'active:', btn.classList.contains('active'));
|
||||
});
|
||||
|
||||
// Create quest HTML
|
||||
let questHTML = '<div class="quest-list-container">';
|
||||
|
||||
// Show quests based on selected tab
|
||||
if (activeQuestTab === 'main' && mainQuests.length > 0) {
|
||||
questHTML += '<h3>Main Story Quests</h3>';
|
||||
mainQuests.forEach(quest => {
|
||||
const progress = quest.progress || 0;
|
||||
const requirement = quest.requirements?.battlesWon || 1;
|
||||
const progressPercent = (progress / requirement) * 100;
|
||||
questHTML += '<div class="quest-item">';
|
||||
questHTML += '<div class="quest-header">';
|
||||
questHTML += '<h4>' + quest.name + '</h4>';
|
||||
questHTML += '<span class="quest-status ' + (quest.status || 'active') + '">' + (quest.status || 'active') + '</span>';
|
||||
questHTML += '</div>';
|
||||
questHTML += '<div class="quest-description">' + quest.description + '</div>';
|
||||
questHTML += '<div class="quest-progress">';
|
||||
questHTML += '<div class="progress-bar">';
|
||||
questHTML += '<div class="progress-fill" style="width: ' + progressPercent + '%"></div>';
|
||||
questHTML += '</div>';
|
||||
questHTML += '<span>' + progress + '/' + requirement + '</span>';
|
||||
questHTML += '</div>';
|
||||
questHTML += '<div class="quest-rewards">';
|
||||
questHTML += '<span>Rewards: ' + (quest.rewards?.experience || 0) + ' XP, ' + (quest.rewards?.credits || 0) + ' credits</span>';
|
||||
questHTML += '</div>';
|
||||
questHTML += '</div>';
|
||||
});
|
||||
}
|
||||
|
||||
if (activeQuestTab === 'daily' && dailyQuests.length > 0) {
|
||||
questHTML += '<h3>Daily Quests</h3>';
|
||||
dailyQuests.forEach(quest => {
|
||||
const progress = quest.progress || 0;
|
||||
const requirement = quest.requirements?.battlesWon || 1;
|
||||
const progressPercent = (progress / requirement) * 100;
|
||||
questHTML += '<div class="quest-item daily">';
|
||||
questHTML += '<div class="quest-header">';
|
||||
questHTML += '<h4>' + quest.name + '</h4>';
|
||||
questHTML += '<span class="quest-status ' + (quest.status || 'active') + '">' + (quest.status || 'active') + '</span>';
|
||||
questHTML += '</div>';
|
||||
questHTML += '<div class="quest-description">' + quest.description + '</div>';
|
||||
questHTML += '<div class="quest-progress">';
|
||||
questHTML += '<div class="progress-bar">';
|
||||
questHTML += '<div class="progress-fill" style="width: ' + progressPercent + '%"></div>';
|
||||
questHTML += '</div>';
|
||||
questHTML += '<span>' + progress + '/' + requirement + '</span>';
|
||||
questHTML += '</div>';
|
||||
questHTML += '<div class="quest-rewards">';
|
||||
questHTML += '<span>Rewards: ' + (quest.rewards?.experience || 0) + ' XP, ' + (quest.rewards?.credits || 0) + ' credits, ' + (quest.rewards?.gems || 0) + ' gems</span>';
|
||||
questHTML += '</div>';
|
||||
questHTML += '</div>';
|
||||
});
|
||||
}
|
||||
|
||||
if (activeQuestTab === 'weekly' && weeklyQuests.length > 0) {
|
||||
questHTML += '<h3>Weekly Quests</h3>';
|
||||
weeklyQuests.forEach(quest => {
|
||||
const progress = quest.progress || 0;
|
||||
const requirement = quest.requirements?.battlesWon || 1;
|
||||
const progressPercent = (progress / requirement) * 100;
|
||||
questHTML += '<div class="quest-item weekly">';
|
||||
questHTML += '<div class="quest-header">';
|
||||
questHTML += '<h4>' + quest.name + '</h4>';
|
||||
questHTML += '<span class="quest-status ' + (quest.status || 'active') + '">' + (quest.status || 'active') + '</span>';
|
||||
questHTML += '</div>';
|
||||
questHTML += '<div class="quest-description">' + quest.description + '</div>';
|
||||
questHTML += '<div class="quest-progress">';
|
||||
questHTML += '<div class="progress-bar">';
|
||||
questHTML += '<div class="progress-fill" style="width: ' + progressPercent + '%"></div>';
|
||||
questHTML += '</div>';
|
||||
questHTML += '<span>' + progress + '/' + requirement + '</span>';
|
||||
questHTML += '</div>';
|
||||
questHTML += '<div class="quest-rewards">';
|
||||
questHTML += '<span>Rewards: ' + (quest.rewards?.experience || 0) + ' XP, ' + (quest.rewards?.credits || 0) + ' credits, ' + (quest.rewards?.gems || 0) + ' gems</span>';
|
||||
questHTML += '</div>';
|
||||
questHTML += '</div>';
|
||||
});
|
||||
}
|
||||
|
||||
if (activeQuestTab === 'completed') {
|
||||
questHTML += '<h3>Completed Quests</h3>';
|
||||
questHTML += '<p>No completed quests yet.</p>';
|
||||
}
|
||||
|
||||
if (activeQuestTab === 'failed') {
|
||||
questHTML += '<h3>Failed Quests</h3>';
|
||||
questHTML += '<p>No failed quests yet.</p>';
|
||||
}
|
||||
|
||||
// Show no quests message if category is empty
|
||||
if ((activeQuestTab === 'main' && mainQuests.length === 0) ||
|
||||
(activeQuestTab === 'daily' && dailyQuests.length === 0) ||
|
||||
(activeQuestTab === 'weekly' && weeklyQuests.length === 0)) {
|
||||
questHTML += '<p>No quests available in this category.</p>';
|
||||
}
|
||||
|
||||
questHTML += '</div>';
|
||||
questListElement.innerHTML = questHTML;
|
||||
} else {
|
||||
questListElement.innerHTML = '<div style="text-align: center; padding: 2rem; color: var(--text-secondary);"><h3>No Quest Data Available</h3><p>Server quest data not found.</p></div>';
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'skills':
|
||||
if (window.game.systems.skillSystem) {
|
||||
console.log('[GLOBAL] Forcing skills UI update');
|
||||
window.game.systems.skillSystem.updateUI();
|
||||
}
|
||||
break;
|
||||
case 'crafting':
|
||||
if (window.game.systems.crafting) {
|
||||
console.log('[GLOBAL] Forcing crafting UI update');
|
||||
window.game.systems.crafting.updateUI();
|
||||
}
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback: Manual tab switching
|
||||
console.log('[GLOBAL] Using manual tab switching fallback');
|
||||
|
||||
// Hide all tabs
|
||||
document.querySelectorAll('.tab-content').forEach(tab => {
|
||||
tab.classList.remove('active');
|
||||
});
|
||||
|
||||
// Remove active class from all nav buttons
|
||||
document.querySelectorAll('.nav-btn').forEach(btn => {
|
||||
btn.classList.remove('active');
|
||||
});
|
||||
|
||||
// Show selected tab
|
||||
const targetTab = document.getElementById(tabName + '-tab');
|
||||
if (targetTab) {
|
||||
targetTab.classList.add('active');
|
||||
}
|
||||
|
||||
// Add active class to clicked button
|
||||
const targetButton = document.querySelector(`[data-tab="${tabName}"]`);
|
||||
if (targetButton) {
|
||||
targetButton.classList.add('active');
|
||||
}
|
||||
}
|
||||
|
||||
function switchShopCategory(category) {
|
||||
console.log('[GLOBAL] switchShopCategory called with:', category);
|
||||
console.log('[GLOBAL] switchShopCategory function starting');
|
||||
|
||||
try {
|
||||
// Try to use UIManager first
|
||||
if (window.game && window.game.systems && window.game.systems.ui) {
|
||||
console.log('[GLOBAL] Using UIManager path for shop');
|
||||
window.game.systems.ui.switchShopCategory(category);
|
||||
console.log('[GLOBAL] switchShopCategory function completed (UIManager path)');
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback: Manual category switching
|
||||
console.log('[GLOBAL] Using manual shop category switching');
|
||||
document.querySelectorAll('.shop-cat-btn').forEach(btn => {
|
||||
btn.classList.remove('active');
|
||||
});
|
||||
|
||||
const targetButton = document.querySelector(`[data-category="${category}"]`);
|
||||
if (targetButton) {
|
||||
targetButton.classList.add('active');
|
||||
console.log('[GLOBAL] Set active shop button:', category);
|
||||
}
|
||||
|
||||
// Force shop display update immediately
|
||||
console.log('[GLOBAL] About to call updateShopDisplay');
|
||||
updateShopDisplay();
|
||||
console.log('[GLOBAL] Called updateShopDisplay');
|
||||
console.log('[GLOBAL] switchShopCategory function completed (manual path)');
|
||||
} catch (error) {
|
||||
console.error('[GLOBAL] Error in switchShopCategory:', error);
|
||||
}
|
||||
}
|
||||
|
||||
function updateShopDisplay() {
|
||||
try {
|
||||
console.log('[GLOBAL] updateShopDisplay called');
|
||||
console.log('[GLOBAL] window.game:', !!window.game);
|
||||
console.log('[GLOBAL] game.systems.economy:', !!(window.game?.systems?.economy));
|
||||
console.log('[GLOBAL] game.systems.itemSystem:', !!(window.game?.systems?.itemSystem));
|
||||
|
||||
if (window.game && window.game.systems && window.game.systems.economy) {
|
||||
console.log('[GLOBAL] Calling economy.updateShopUI');
|
||||
window.game.systems.economy.updateShopUI();
|
||||
console.log('[GLOBAL] updateShopDisplay completed');
|
||||
} else {
|
||||
console.log('[GLOBAL] Economy system not available');
|
||||
const shopItemsElement = document.getElementById('shopItems');
|
||||
if (shopItemsElement) {
|
||||
shopItemsElement.innerHTML = '<div style="text-align: center; padding: 2rem; color: var(--text-secondary);"><h3>Shop Not Available</h3><p>Economy system not found.</p></div>';
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[GLOBAL] Error in updateShopDisplay:', error);
|
||||
}
|
||||
}
|
||||
|
||||
function switchSkillCategory(category) {
|
||||
console.log('[GLOBAL] switchSkillCategory called with:', category);
|
||||
|
||||
// Try to use UIManager first
|
||||
if (window.game && window.game.systems && window.game.systems.ui) {
|
||||
window.game.systems.ui.switchSkillCategory(category);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback: Manual category switching
|
||||
document.querySelectorAll('.skill-cat-btn').forEach(btn => {
|
||||
btn.classList.remove('active');
|
||||
});
|
||||
|
||||
const targetButton = document.querySelector(`[data-category="${category}"]`);
|
||||
if (targetButton) {
|
||||
targetButton.classList.add('active');
|
||||
}
|
||||
}
|
||||
|
||||
function switchQuestCategory(category) {
|
||||
console.log('[GLOBAL] switchQuestCategory called with:', category);
|
||||
console.log('[GLOBAL] switchQuestCategory function starting');
|
||||
|
||||
try {
|
||||
// Try to use UIManager first
|
||||
if (window.game && window.game.systems && window.game.systems.ui) {
|
||||
console.log('[GLOBAL] Using UIManager path');
|
||||
// Try to call updateQuestTabs if it exists, otherwise use fallback
|
||||
if (typeof window.game.systems.ui.updateQuestTabs === 'function') {
|
||||
console.log('[GLOBAL] Calling UIManager updateQuestTabs');
|
||||
window.game.systems.ui.updateQuestTabs(category);
|
||||
} else {
|
||||
console.log('[GLOBAL] updateQuestTabs not found, using fallback');
|
||||
// Fallback: Manual category switching
|
||||
document.querySelectorAll('.quest-tab-btn').forEach(btn => {
|
||||
btn.classList.remove('active');
|
||||
});
|
||||
|
||||
const targetButton = document.querySelector(`[data-type="${category}"]`);
|
||||
if (targetButton) {
|
||||
targetButton.classList.add('active');
|
||||
}
|
||||
|
||||
// Force quest display update immediately
|
||||
console.log('[GLOBAL] About to call updateQuestDisplay');
|
||||
updateQuestDisplay();
|
||||
console.log('[GLOBAL] Called updateQuestDisplay');
|
||||
}
|
||||
console.log('[GLOBAL] switchQuestCategory function completed (UIManager path)');
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback: Manual category switching
|
||||
console.log('[GLOBAL] Using manual quest category switching');
|
||||
document.querySelectorAll('.quest-tab-btn').forEach(btn => {
|
||||
btn.classList.remove('active');
|
||||
});
|
||||
|
||||
const targetButton = document.querySelector(`[data-type="${category}"]`);
|
||||
if (targetButton) {
|
||||
targetButton.classList.add('active');
|
||||
console.log('[GLOBAL] Set active button:', category);
|
||||
}
|
||||
|
||||
// Force quest display update immediately
|
||||
console.log('[GLOBAL] About to call updateQuestDisplay');
|
||||
updateQuestDisplay();
|
||||
console.log('[GLOBAL] Called updateQuestDisplay');
|
||||
console.log('[GLOBAL] switchQuestCategory function completed (manual path)');
|
||||
} catch (error) {
|
||||
console.error('[GLOBAL] Error in switchQuestCategory:', error);
|
||||
}
|
||||
}
|
||||
|
||||
function updateQuestDisplay() {
|
||||
try {
|
||||
console.log('[GLOBAL] updateQuestDisplay called');
|
||||
console.log('[GLOBAL] window.gameInitializer:', !!window.gameInitializer);
|
||||
console.log('[GLOBAL] serverPlayerData:', window.gameInitializer?.serverPlayerData);
|
||||
|
||||
// Get quest data from server playerData
|
||||
const serverPlayerData = window.gameInitializer?.serverPlayerData;
|
||||
if (serverPlayerData && serverPlayerData.quests) {
|
||||
const quests = serverPlayerData.quests;
|
||||
console.log('[GLOBAL] Updating quest display with data:', quests);
|
||||
|
||||
// Categorize quests on client since server sends old format
|
||||
const activeQuests = quests.active || [];
|
||||
const mainQuests = activeQuests.filter(quest => quest.type === 'main');
|
||||
const dailyQuests = activeQuests.filter(quest => quest.type === 'daily');
|
||||
const weeklyQuests = activeQuests.filter(quest => quest.type === 'weekly');
|
||||
const tutorialQuests = activeQuests.filter(quest => quest.type === 'tutorial');
|
||||
|
||||
console.log('[GLOBAL] Quest categorization:', {
|
||||
total: activeQuests.length,
|
||||
main: mainQuests.length,
|
||||
daily: dailyQuests.length,
|
||||
weekly: weeklyQuests.length,
|
||||
tutorial: tutorialQuests.length
|
||||
});
|
||||
|
||||
// Get the currently selected quest tab type
|
||||
const activeQuestTab = document.querySelector('.quest-tab-btn.active')?.dataset.type || 'main';
|
||||
console.log('[GLOBAL] Active quest tab for update:', activeQuestTab);
|
||||
|
||||
const questListElement = document.getElementById('questList');
|
||||
if (questListElement) {
|
||||
// Create quest HTML
|
||||
let questHTML = '<div class="quest-list-container">';
|
||||
|
||||
// Show quests based on selected tab
|
||||
if (activeQuestTab === 'daily' && dailyQuests.length > 0) {
|
||||
console.log('[GLOBAL] Showing daily quests:', dailyQuests.length);
|
||||
questHTML += '<h3>Daily Quests</h3>';
|
||||
dailyQuests.forEach(quest => {
|
||||
const progress = quest.progress || 0;
|
||||
const requirement = quest.requirements?.battlesWon || 1;
|
||||
const progressPercent = (progress / requirement) * 100;
|
||||
questHTML += '<div class="quest-item daily">';
|
||||
questHTML += '<div class="quest-header">';
|
||||
questHTML += '<h4>' + quest.name + '</h4>';
|
||||
questHTML += '<span class="quest-status ' + (quest.status || 'active') + '">' + (quest.status || 'active') + '</span>';
|
||||
questHTML += '</div>';
|
||||
questHTML += '<div class="quest-description">' + quest.description + '</div>';
|
||||
questHTML += '<div class="quest-progress">';
|
||||
questHTML += '<div class="progress-bar">';
|
||||
questHTML += '<div class="progress-fill" style="width: ' + progressPercent + '%"></div>';
|
||||
questHTML += '</div>';
|
||||
questHTML += '<span>' + progress + '/' + requirement + '</span>';
|
||||
questHTML += '</div>';
|
||||
questHTML += '<div class="quest-rewards">';
|
||||
questHTML += '<span>Rewards: ' + (quest.rewards?.experience || 0) + ' XP, ' + (quest.rewards?.credits || 0) + ' credits, ' + (quest.rewards?.gems || 0) + ' gems</span>';
|
||||
questHTML += '</div>';
|
||||
questHTML += '</div>';
|
||||
});
|
||||
}
|
||||
|
||||
if (activeQuestTab === 'weekly' && weeklyQuests.length > 0) {
|
||||
console.log('[GLOBAL] Showing weekly quests:', weeklyQuests.length);
|
||||
questHTML += '<h3>Weekly Quests</h3>';
|
||||
weeklyQuests.forEach(quest => {
|
||||
const progress = quest.progress || 0;
|
||||
const requirement = quest.requirements?.battlesWon || 1;
|
||||
const progressPercent = (progress / requirement) * 100;
|
||||
questHTML += '<div class="quest-item weekly">';
|
||||
questHTML += '<div class="quest-header">';
|
||||
questHTML += '<h4>' + quest.name + '</h4>';
|
||||
questHTML += '<span class="quest-status ' + (quest.status || 'active') + '">' + (quest.status || 'active') + '</span>';
|
||||
questHTML += '</div>';
|
||||
questHTML += '<div class="quest-description">' + quest.description + '</div>';
|
||||
questHTML += '<div class="quest-progress">';
|
||||
questHTML += '<div class="progress-bar">';
|
||||
questHTML += '<div class="progress-fill" style="width: ' + progressPercent + '%"></div>';
|
||||
questHTML += '</div>';
|
||||
questHTML += '<span>' + progress + '/' + requirement + '</span>';
|
||||
questHTML += '</div>';
|
||||
questHTML += '<div class="quest-rewards">';
|
||||
questHTML += '<span>Rewards: ' + (quest.rewards?.experience || 0) + ' XP, ' + (quest.rewards?.credits || 0) + ' credits, ' + (quest.rewards?.gems || 0) + ' gems</span>';
|
||||
questHTML += '</div>';
|
||||
questHTML += '</div>';
|
||||
});
|
||||
}
|
||||
|
||||
if (activeQuestTab === 'main' && mainQuests.length > 0) {
|
||||
console.log('[GLOBAL] Showing main quests:', mainQuests.length);
|
||||
questHTML += '<h3>Main Story Quests</h3>';
|
||||
mainQuests.forEach(quest => {
|
||||
const progress = quest.progress || 0;
|
||||
const requirement = quest.requirements?.battlesWon || 1;
|
||||
const progressPercent = (progress / requirement) * 100;
|
||||
questHTML += '<div class="quest-item">';
|
||||
questHTML += '<div class="quest-header">';
|
||||
questHTML += '<h4>' + quest.name + '</h4>';
|
||||
questHTML += '<span class="quest-status ' + (quest.status || 'active') + '">' + (quest.status || 'active') + '</span>';
|
||||
questHTML += '</div>';
|
||||
questHTML += '<div class="quest-description">' + quest.description + '</div>';
|
||||
questHTML += '<div class="quest-progress">';
|
||||
questHTML += '<div class="progress-bar">';
|
||||
questHTML += '<div class="progress-fill" style="width: ' + progressPercent + '%"></div>';
|
||||
questHTML += '</div>';
|
||||
questHTML += '<span>' + progress + '/' + requirement + '</span>';
|
||||
questHTML += '</div>';
|
||||
questHTML += '<div class="quest-rewards">';
|
||||
questHTML += '<span>Rewards: ' + (quest.rewards?.experience || 0) + ' XP, ' + (quest.rewards?.credits || 0) + ' credits</span>';
|
||||
questHTML += '</div>';
|
||||
questHTML += '</div>';
|
||||
});
|
||||
}
|
||||
|
||||
if (activeQuestTab === 'completed') {
|
||||
questHTML += '<h3>Completed Quests</h3>';
|
||||
questHTML += '<p>No completed quests yet.</p>';
|
||||
}
|
||||
|
||||
if (activeQuestTab === 'failed') {
|
||||
questHTML += '<h3>Failed Quests</h3>';
|
||||
questHTML += '<p>No failed quests yet.</p>';
|
||||
}
|
||||
|
||||
// Show no quests message if category is empty
|
||||
if ((activeQuestTab === 'main' && mainQuests.length === 0) ||
|
||||
(activeQuestTab === 'daily' && dailyQuests.length === 0) ||
|
||||
(activeQuestTab === 'weekly' && weeklyQuests.length === 0)) {
|
||||
questHTML += '<p>No quests available in this category.</p>';
|
||||
}
|
||||
|
||||
questHTML += '</div>';
|
||||
questListElement.innerHTML = questHTML;
|
||||
console.log('[GLOBAL] Quest display updated for tab:', activeQuestTab);
|
||||
}
|
||||
} else {
|
||||
console.log('[GLOBAL] No quest data available');
|
||||
const questListElement = document.getElementById('questList');
|
||||
if (questListElement) {
|
||||
questListElement.innerHTML = '<div style="text-align: center; padding: 2rem; color: var(--text-secondary);"><h3>No Quest Data Available</h3><p>Server quest data not found.</p></div>';
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[GLOBAL] Error in updateQuestDisplay:', error);
|
||||
}
|
||||
}
|
||||
|
||||
function switchCraftingCategory(category) {
|
||||
console.log('[GLOBAL] switchCraftingCategory called with:', category);
|
||||
|
||||
// Try to use UIManager first
|
||||
if (window.game && window.game.systems && window.game.systems.ui) {
|
||||
window.game.systems.ui.switchCraftingCategory(category);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback: Manual category switching
|
||||
document.querySelectorAll('.crafting-cat-btn').forEach(btn => {
|
||||
btn.classList.remove('active');
|
||||
});
|
||||
|
||||
const targetButton = document.querySelector(`[data-category="${category}"]`);
|
||||
if (targetButton) {
|
||||
targetButton.classList.add('active');
|
||||
}
|
||||
}
|
||||
|
||||
function switchBaseView(view) {
|
||||
console.log('[GLOBAL] switchBaseView called with:', view);
|
||||
|
||||
// Try to use BaseSystem first
|
||||
if (window.game && window.game.systems && window.game.systems.base) {
|
||||
window.game.systems.base.switchBaseView(view);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback: Manual view switching
|
||||
document.querySelectorAll('.base-nav-btn').forEach(btn => {
|
||||
btn.classList.remove('active');
|
||||
});
|
||||
|
||||
const targetButton = document.querySelector(`[data-view="${view}"]`);
|
||||
if (targetButton) {
|
||||
targetButton.classList.add('active');
|
||||
}
|
||||
|
||||
// Hide all base view contents
|
||||
document.querySelectorAll('.base-view-content').forEach(content => {
|
||||
content.style.display = 'none';
|
||||
});
|
||||
|
||||
// Show selected view content
|
||||
const targetContent = document.getElementById(`base-${view}`);
|
||||
if (targetContent) {
|
||||
targetContent.style.display = 'block';
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Hidden Console Window -->
|
||||
<div id="consoleWindow" class="console-window">
|
||||
|
||||
@ -15,12 +15,16 @@ class GameInitializer {
|
||||
this.socket = null;
|
||||
this.apiBaseUrl = 'https://api.korvarix.com/api'; // API Server
|
||||
this.gameServerUrl = 'https://dev.gameserver.galaxystrike.online'; // Game Server for Socket.IO (local dev server)
|
||||
|
||||
console.log('[GAME INITIALIZER] Constructor - gameServerUrl set to:', this.gameServerUrl);
|
||||
}
|
||||
|
||||
updateServerUrls(apiUrl, gameUrl) {
|
||||
console.log('[GAME INITIALIZER] Updating server URLs:', { 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) {
|
||||
@ -33,8 +37,10 @@ class GameInitializer {
|
||||
// Initialize Socket.IO connection
|
||||
this.initializeSocketConnection();
|
||||
|
||||
// Initialize game systems with multiplayer support
|
||||
this.initializeGameSystems();
|
||||
// Set SmartSaveManager to multiplayer mode
|
||||
if (window.smartSaveManager) {
|
||||
window.smartSaveManager.setMultiplayerMode(true, this);
|
||||
}
|
||||
|
||||
// Update UI for multiplayer mode
|
||||
this.updateUIForMultiplayerMode();
|
||||
@ -49,6 +55,7 @@ class GameInitializer {
|
||||
}
|
||||
|
||||
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) {
|
||||
@ -63,14 +70,21 @@ class GameInitializer {
|
||||
return;
|
||||
}
|
||||
|
||||
// Connect to the game server (different from API server)
|
||||
this.socket = io(this.gameServerUrl, {
|
||||
// FORCE THE URL - Override any undefined issues
|
||||
const FORCED_URL = 'https://dev.gameserver.galaxystrike.online';
|
||||
console.log('[GAME INITIALIZER] FORCING URL to:', FORCED_URL);
|
||||
console.log('[GAME INITIALIZER] Original this.gameServerUrl:', this.gameServerUrl);
|
||||
|
||||
// Connect to the game server with FORCED URL
|
||||
this.socket = io(FORCED_URL, {
|
||||
auth: {
|
||||
token: this.authToken,
|
||||
serverId: this.serverData.id
|
||||
}
|
||||
});
|
||||
|
||||
console.log('[GAME INITIALIZER] Socket.IO connection initiated to FORCED URL:', FORCED_URL);
|
||||
|
||||
// Socket event handlers
|
||||
this.socket.on('connect', () => {
|
||||
console.log('[GAME INITIALIZER] Connected to server');
|
||||
@ -111,9 +125,69 @@ class GameInitializer {
|
||||
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) => {
|
||||
console.log('[GAME INITIALIZER] Online idle rewards received:', data);
|
||||
this.onOnlineIdleRewards(data);
|
||||
});
|
||||
|
||||
// PlayTime events
|
||||
this.socket.on('playTimeUpdated', (data) => {
|
||||
console.log('[GAME INITIALIZER] PlayTime updated from server:', data);
|
||||
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('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,
|
||||
@ -121,13 +195,48 @@ class GameInitializer {
|
||||
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) {
|
||||
@ -156,6 +265,147 @@ class GameInitializer {
|
||||
}
|
||||
}
|
||||
|
||||
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');
|
||||
|
||||
// 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);
|
||||
@ -211,7 +461,56 @@ class GameInitializer {
|
||||
|
||||
// Configure game for multiplayer mode
|
||||
console.log('[GAME INITIALIZER] Configuring for multiplayer mode');
|
||||
window.game.setMultiplayerMode(true, this.socket, this.serverData, this.currentUser);
|
||||
// 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) {
|
||||
@ -230,8 +529,24 @@ class GameInitializer {
|
||||
updateUIForMultiplayerMode() {
|
||||
// Update UI elements to show multiplayer mode
|
||||
const playerName = document.getElementById('playerName');
|
||||
if (playerName && this.currentUser) {
|
||||
playerName.textContent = this.currentUser.username;
|
||||
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
|
||||
@ -340,10 +655,211 @@ class GameInitializer {
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
console.warn('[GAME INITIALIZER] Cannot authenticate - missing socket or user data');
|
||||
if (!this.socket) {
|
||||
console.warn('[GAME INITIALIZER] Socket is null/undefined');
|
||||
}
|
||||
if (!this.currentUser) {
|
||||
console.warn('[GAME INITIALIZER] Current user is null/undefined');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onOfflineRewardsClaimed(data) {
|
||||
if (data.success) {
|
||||
if (data.rewards.credits > 0 || data.rewards.experience > 0) {
|
||||
// Apply rewards to player
|
||||
if (window.game && window.game.systems) {
|
||||
if (data.rewards.credits > 0) {
|
||||
window.game.systems.economy.addCredits(data.rewards.credits, 'offline');
|
||||
}
|
||||
if (data.rewards.experience > 0) {
|
||||
window.game.systems.player.addExperience(data.rewards.experience);
|
||||
}
|
||||
|
||||
// Show success message
|
||||
let message = 'Offline rewards claimed!\n';
|
||||
if (data.rewards.credits > 0) message += `+${data.rewards.credits} credits\n`;
|
||||
if (data.rewards.experience > 0) message += `+${data.rewards.experience} experience\n`;
|
||||
|
||||
window.game.showNotification(message, 'success', 5000);
|
||||
}
|
||||
} else {
|
||||
window.game.showNotification('No offline rewards available', 'info', 3000);
|
||||
}
|
||||
} else {
|
||||
window.game.showNotification(`Failed to claim offline rewards: ${data.error}`, 'error', 5000);
|
||||
}
|
||||
}
|
||||
|
||||
onOnlineIdleRewards(data) {
|
||||
if (window.game && window.game.systems) {
|
||||
// Update player balance with online idle rewards
|
||||
if (data.credits > 0) {
|
||||
// The server already updated the balance, just show notification
|
||||
window.game.showNotification(`+${data.credits} credits (online idle)`, 'success', 2000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onPlayTimeUpdated(data) {
|
||||
console.log('[GAME INITIALIZER] PlayTime updated from server:', data);
|
||||
|
||||
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;
|
||||
|
||||
console.log('[GAME INITIALIZER] Updated local playTime to:', data.playTime, 'ms');
|
||||
console.log('[GAME INITIALIZER] PlayTime in hours:', data.playTime / (1000 * 60 * 60), 'hours');
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Request fresh economy data from server to ensure sync
|
||||
if (economy.requestEconomyData) {
|
||||
setTimeout(() => {
|
||||
economy.requestEconomyData();
|
||||
}, 500);
|
||||
}
|
||||
|
||||
// Update UI
|
||||
economy.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) {
|
||||
// Update ItemSystem with server data
|
||||
window.game.systems.itemSystem.processServerItems(data.items);
|
||||
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;
|
||||
@ -353,12 +869,26 @@ class GameInitializer {
|
||||
this.serverData = null;
|
||||
this.authToken = null;
|
||||
this.currentUser = null;
|
||||
this.serverPlayerData = null;
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
325
Client/js/SaveSystemIntegration.js
Normal file
325
Client/js/SaveSystemIntegration.js
Normal file
@ -0,0 +1,325 @@
|
||||
/**
|
||||
* Save System Integration
|
||||
* Integrates SmartSaveManager with existing game systems
|
||||
*/
|
||||
|
||||
console.log('[SAVE INTEGRATION] Save system integration loading');
|
||||
|
||||
// Override the game's save method to use SmartSaveManager
|
||||
function integrateWithGameEngine() {
|
||||
if (window.game && window.game.save) {
|
||||
// Store original save method
|
||||
const originalSave = window.game.save;
|
||||
|
||||
// Override game save method
|
||||
window.game.save = async function() {
|
||||
// console.log('[SAVE INTEGRATION] Game save called');
|
||||
|
||||
if (window.smartSaveManager) {
|
||||
await window.smartSaveManager.save();
|
||||
} else {
|
||||
// Fallback to original save if SmartSaveManager not available
|
||||
return await originalSave.call(this);
|
||||
}
|
||||
};
|
||||
|
||||
console.log('[SAVE INTEGRATION] Game save method overridden');
|
||||
}
|
||||
}
|
||||
|
||||
// Override the game's load method to use SmartSaveManager
|
||||
function integrateLoadSystem() {
|
||||
if (window.game && window.game.load) {
|
||||
// Store original load method
|
||||
const originalLoad = window.game.load;
|
||||
|
||||
// Override load method
|
||||
window.game.load = async function(saveData = null) {
|
||||
console.log('[SAVE INTEGRATION] Game load called, using SmartSaveManager');
|
||||
|
||||
try {
|
||||
let dataToLoad = saveData;
|
||||
|
||||
// If no data provided, use SmartSaveManager
|
||||
if (!dataToLoad && window.smartSaveManager) {
|
||||
dataToLoad = await window.smartSaveManager.loadPlayerData();
|
||||
}
|
||||
|
||||
// Load the data
|
||||
if (dataToLoad) {
|
||||
if (this.loadPlayerData) {
|
||||
this.loadPlayerData(dataToLoad);
|
||||
} else {
|
||||
// Fallback to original load
|
||||
return await originalLoad.call(this, dataToLoad);
|
||||
}
|
||||
|
||||
console.log('[SAVE INTEGRATION] Game data loaded successfully');
|
||||
return true;
|
||||
} else {
|
||||
console.log('[SAVE INTEGRATION] No save data found, starting fresh');
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[SAVE INTEGRATION] Load error:', error);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
console.log('[SAVE INTEGRATION] Game load method overridden');
|
||||
}
|
||||
}
|
||||
|
||||
// Add server data loading method to game
|
||||
function addServerDataSupport() {
|
||||
if (window.game) {
|
||||
// Store pending server data for later application
|
||||
window.game.pendingServerData = null;
|
||||
|
||||
window.game.loadServerPlayerData = function(serverData) {
|
||||
console.log('[SAVE INTEGRATION] Loading server player data into game');
|
||||
console.log('[SAVE INTEGRATION] Server data received:', serverData);
|
||||
console.log('[SAVE INTEGRATION] Server data type:', typeof serverData);
|
||||
console.log('[SAVE INTEGRATION] Server data keys:', serverData ? Object.keys(serverData) : 'No data');
|
||||
console.log('[SAVE INTEGRATION] Game systems available:', this.systems ? Object.keys(this.systems) : 'No systems');
|
||||
|
||||
// Store server data for later if systems aren't ready
|
||||
if (!this.systems || Object.keys(this.systems).length === 0) {
|
||||
console.log('[SAVE INTEGRATION] Game systems not ready, storing data for later');
|
||||
this.pendingServerData = serverData;
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('[SAVE INTEGRATION] Game systems ready, applying server data now');
|
||||
|
||||
try {
|
||||
// Apply player stats
|
||||
if (serverData.stats && this.systems && this.systems.player) {
|
||||
console.log('[SAVE INTEGRATION] Applying player stats:', serverData.stats);
|
||||
console.log('[SAVE INTEGRATION] Player system methods:', Object.getOwnPropertyNames(Object.getPrototypeOf(this.systems.player)));
|
||||
|
||||
// Check if load method exists
|
||||
if (typeof this.systems.player.load === 'function') {
|
||||
this.systems.player.load(serverData.stats);
|
||||
console.log('[SAVE INTEGRATION] Player stats applied successfully');
|
||||
console.log('[SAVE INTEGRATION] Updated player stats:', this.systems.player.stats);
|
||||
} else {
|
||||
console.warn('[SAVE INTEGRATION] Player system has no load method, trying direct assignment');
|
||||
// Direct assignment as fallback
|
||||
if (this.systems.player.stats) {
|
||||
Object.assign(this.systems.player.stats, serverData.stats);
|
||||
console.log('[SAVE INTEGRATION] Player stats assigned directly:', this.systems.player.stats);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.warn('[SAVE INTEGRATION] No player system or stats in server data');
|
||||
console.log('[SAVE INTEGRATION] Has serverData.stats:', !!serverData?.stats);
|
||||
console.log('[SAVE INTEGRATION] Has systems.player:', !!(this.systems?.player));
|
||||
}
|
||||
|
||||
// Apply inventory
|
||||
if (serverData.inventory && this.systems && this.systems.inventory) {
|
||||
console.log('[SAVE INTEGRATION] Applying player inventory:', serverData.inventory);
|
||||
if (typeof this.systems.inventory.load === 'function') {
|
||||
this.systems.inventory.load(serverData.inventory);
|
||||
} else {
|
||||
console.warn('[SAVE INTEGRATION] Inventory system has no load method');
|
||||
}
|
||||
}
|
||||
|
||||
// Apply ship data
|
||||
if (serverData.ship && this.systems && this.systems.ship) {
|
||||
console.log('[SAVE INTEGRATION] Applying player ship:', serverData.ship);
|
||||
if (typeof this.systems.ship.load === 'function') {
|
||||
this.systems.ship.load(serverData.ship);
|
||||
} else {
|
||||
console.warn('[SAVE INTEGRATION] Ship system has no load method');
|
||||
}
|
||||
}
|
||||
|
||||
// Apply base data
|
||||
if (serverData.base && this.systems && this.systems.base) {
|
||||
console.log('[SAVE INTEGRATION] Applying player base:', serverData.base);
|
||||
if (typeof this.systems.base.load === 'function') {
|
||||
this.systems.base.load(serverData.base);
|
||||
} else {
|
||||
console.warn('[SAVE INTEGRATION] Base system has no load method');
|
||||
}
|
||||
}
|
||||
|
||||
// Show notification
|
||||
if (this.showNotification) {
|
||||
this.showNotification(`Welcome back! Level ${serverData.stats?.level || 1}`, 'success', 3000);
|
||||
}
|
||||
|
||||
console.log('[SAVE INTEGRATION] Server player data application completed');
|
||||
|
||||
// Force UI update
|
||||
if (this.systems && this.systems.ui && this.systems.ui.updateUI) {
|
||||
this.systems.ui.updateUI();
|
||||
console.log('[SAVE INTEGRATION] Server player data application completed');
|
||||
}
|
||||
|
||||
// Apply pending server data if any exists
|
||||
if (this.pendingServerData) {
|
||||
console.log('[SAVE INTEGRATION] Applying pending server data');
|
||||
this.loadServerPlayerData(this.pendingServerData);
|
||||
this.pendingServerData = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[SAVE INTEGRATION] Error applying server player data:', error);
|
||||
if (this.showNotification) {
|
||||
this.showNotification('Failed to load server data!', 'error', 3000);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Method to check and apply pending server data
|
||||
window.game.checkAndApplyPendingServerData = function() {
|
||||
if (this.pendingServerData && this.systems && Object.keys(this.systems).length > 0) {
|
||||
console.log('[SAVE INTEGRATION] Systems ready, applying pending server data');
|
||||
this.loadServerPlayerData(this.pendingServerData);
|
||||
this.pendingServerData = null;
|
||||
}
|
||||
};
|
||||
|
||||
// Fallback loadPlayerData method if GameEngine doesn't have it
|
||||
if (!window.game.loadPlayerData) {
|
||||
window.game.loadPlayerData = window.game.loadServerPlayerData;
|
||||
}
|
||||
|
||||
console.log('[SAVE INTEGRATION] Server data support added to game');
|
||||
}
|
||||
}
|
||||
|
||||
// Add save mode switching to UI
|
||||
function addSaveModeUI() {
|
||||
// Add save mode indicator to UI
|
||||
const createSaveModeIndicator = () => {
|
||||
const indicator = document.createElement('div');
|
||||
indicator.id = 'save-mode-indicator';
|
||||
indicator.style.cssText = `
|
||||
position: fixed;
|
||||
bottom: 10px;
|
||||
right: 10px;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
color: white;
|
||||
padding: 8px 12px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
z-index: 10000;
|
||||
display: none;
|
||||
`;
|
||||
document.body.appendChild(indicator);
|
||||
return indicator;
|
||||
};
|
||||
|
||||
const updateSaveModeIndicator = () => {
|
||||
const indicator = document.getElementById('save-mode-indicator') || createSaveModeIndicator();
|
||||
|
||||
if (window.smartSaveManager) {
|
||||
const info = window.smartSaveManager.getSaveInfo();
|
||||
indicator.textContent = `Save: ${info.saveLocation}`;
|
||||
indicator.style.display = 'block';
|
||||
|
||||
// Color code based on mode
|
||||
indicator.style.background = info.isMultiplayer ? 'rgba(0, 100, 200, 0.8)' : 'rgba(0, 150, 0, 0.8)';
|
||||
}
|
||||
};
|
||||
|
||||
// Update indicator when mode changes
|
||||
if (window.smartSaveManager) {
|
||||
const originalSetMultiplayerMode = window.smartSaveManager.setMultiplayerMode;
|
||||
window.smartSaveManager.setMultiplayerMode = function(...args) {
|
||||
originalSetMultiplayerMode.apply(this, args);
|
||||
updateSaveModeIndicator();
|
||||
};
|
||||
}
|
||||
|
||||
// Initial update
|
||||
setTimeout(updateSaveModeIndicator, 1000);
|
||||
}
|
||||
|
||||
// Debug function to check data flow
|
||||
function debugDataFlow() {
|
||||
console.log('[DEBUG] === DATA FLOW DEBUG ===');
|
||||
|
||||
// Check GameInitializer
|
||||
if (window.gameInitializer) {
|
||||
console.log('[DEBUG] GameInitializer exists:', !!window.gameInitializer);
|
||||
console.log('[DEBUG] GameInitializer serverPlayerData:', window.gameInitializer.serverPlayerData);
|
||||
console.log('[DEBUG] GameInitializer gameMode:', window.gameInitializer.gameMode);
|
||||
} else {
|
||||
console.log('[DEBUG] GameInitializer NOT found');
|
||||
}
|
||||
|
||||
// Check game systems
|
||||
if (window.game) {
|
||||
console.log('[DEBUG] Game exists:', !!window.game);
|
||||
console.log('[DEBUG] Game systems:', window.game.systems ? Object.keys(window.game.systems) : 'No systems');
|
||||
|
||||
if (window.game.systems && window.game.systems.player) {
|
||||
console.log('[DEBUG] Player system exists:', !!window.game.systems.player);
|
||||
console.log('[DEBUG] Player stats:', window.game.systems.player.stats);
|
||||
console.log('[DEBUG] Player credits:', window.game.systems.player.stats?.credits);
|
||||
}
|
||||
} else {
|
||||
console.log('[DEBUG] Game NOT found');
|
||||
}
|
||||
|
||||
// Check SmartSaveManager
|
||||
if (window.smartSaveManager) {
|
||||
console.log('[DEBUG] SmartSaveManager exists:', !!window.smartSaveManager);
|
||||
console.log('[DEBUG] SmartSaveManager mode:', window.smartSaveManager.isMultiplayer ? 'multiplayer' : 'singleplayer');
|
||||
} else {
|
||||
console.log('[DEBUG] SmartSaveManager NOT found');
|
||||
}
|
||||
|
||||
console.log('[DEBUG] === END DEBUG ===');
|
||||
}
|
||||
|
||||
// Debug function available for manual testing
|
||||
window.debugDataFlow = debugDataFlow;
|
||||
|
||||
// Enhanced debug function for connection testing
|
||||
window.debugConnectionState = function() {
|
||||
console.log('=== CONNECTION STATE DEBUG ===');
|
||||
console.log('GameInitializer exists:', !!window.gameInitializer);
|
||||
console.log('GameInitializer socket connected:', !!window.gameInitializer?.socket?.connected);
|
||||
console.log('GameInitializer gameMode:', window.gameInitializer?.gameMode);
|
||||
console.log('GameInitializer serverPlayerData:', !!window.gameInitializer?.serverPlayerData);
|
||||
console.log('SmartSaveManager exists:', !!window.smartSaveManager);
|
||||
console.log('SmartSaveManager mode:', window.smartSaveManager?.isMultiplayer ? 'multiplayer' : 'singleplayer');
|
||||
console.log('Game exists:', !!window.game);
|
||||
console.log('Game isRunning:', window.game?.isRunning);
|
||||
console.log('=== END CONNECTION DEBUG ===');
|
||||
};
|
||||
|
||||
// Initialize integration when DOM is ready
|
||||
function initializeIntegration() {
|
||||
console.log('[SAVE INTEGRATION] Initializing save system integration');
|
||||
|
||||
// Wait for game to be ready
|
||||
const checkGameReady = () => {
|
||||
if (window.game) {
|
||||
integrateWithGameEngine();
|
||||
integrateLoadSystem();
|
||||
addServerDataSupport();
|
||||
addSaveModeUI();
|
||||
console.log('[SAVE INTEGRATION] Integration complete');
|
||||
} else {
|
||||
setTimeout(checkGameReady, 500);
|
||||
}
|
||||
};
|
||||
|
||||
checkGameReady();
|
||||
}
|
||||
|
||||
// Auto-initialize
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', initializeIntegration);
|
||||
} else {
|
||||
initializeIntegration();
|
||||
}
|
||||
|
||||
console.log('[SAVE INTEGRATION] Save system integration loaded');
|
||||
228
Client/js/SmartSaveManager.js
Normal file
228
Client/js/SmartSaveManager.js
Normal file
@ -0,0 +1,228 @@
|
||||
/**
|
||||
* Smart Save Manager
|
||||
* Intelligently handles save data for both singleplayer and multiplayer modes
|
||||
*/
|
||||
|
||||
class SmartSaveManager {
|
||||
constructor() {
|
||||
this.isMultiplayer = false;
|
||||
this.serverPlayerData = null;
|
||||
this.localSaveData = null;
|
||||
this.gameInitializer = null;
|
||||
|
||||
console.log('[SMART SAVE] SmartSaveManager initialized');
|
||||
}
|
||||
|
||||
setMultiplayerMode(isMultiplayer, gameInitializer = null) {
|
||||
const oldMode = this.isMultiplayer;
|
||||
this.isMultiplayer = isMultiplayer;
|
||||
this.gameInitializer = gameInitializer;
|
||||
|
||||
console.log(`[SMART SAVE] Mode change: ${oldMode ? 'multiplayer' : 'singleplayer'} -> ${isMultiplayer ? 'multiplayer' : 'singleplayer'}`);
|
||||
console.log(`[SMART SAVE] Set to ${isMultiplayer ? 'multiplayer' : 'singleplayer'} mode`);
|
||||
|
||||
if (isMultiplayer && gameInitializer) {
|
||||
// Load server data when switching to multiplayer
|
||||
this.loadServerData();
|
||||
}
|
||||
}
|
||||
|
||||
// Load player data (intelligently chooses source)
|
||||
async loadPlayerData() {
|
||||
if (this.isMultiplayer) {
|
||||
return await this.loadServerData();
|
||||
} else {
|
||||
return await this.loadLocalData();
|
||||
}
|
||||
}
|
||||
|
||||
// Save player data (intelligently chooses destination)
|
||||
async savePlayerData(gameData) {
|
||||
if (this.isMultiplayer) {
|
||||
return await this.saveServerData(gameData);
|
||||
} else {
|
||||
return await this.saveLocalData(gameData);
|
||||
}
|
||||
}
|
||||
|
||||
// Load server data
|
||||
async loadServerData() {
|
||||
try {
|
||||
if (!this.gameInitializer || !this.gameInitializer.socket) {
|
||||
// Don't warn during initialization - this is expected before socket is ready
|
||||
// console.warn('[SMART SAVE] No multiplayer connection available');
|
||||
return null;
|
||||
}
|
||||
|
||||
console.log('[SMART SAVE] Loading server player data');
|
||||
|
||||
// Request data from server
|
||||
this.gameInitializer.loadGameDataFromServer();
|
||||
|
||||
// Return cached server data if available
|
||||
return this.serverPlayerData;
|
||||
} catch (error) {
|
||||
console.error('[SMART SAVE] Error loading server data:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Save server data (DISABLED - client should not send data to server)
|
||||
async saveServerData(gameData) {
|
||||
console.warn('[SMART SAVE] Client save disabled - server is authoritative');
|
||||
return true; // Pretend it worked to avoid client errors
|
||||
}
|
||||
|
||||
// Load local data
|
||||
async loadLocalData() {
|
||||
try {
|
||||
console.log('[SMART SAVE] Loading local save data');
|
||||
|
||||
// Use existing local save system
|
||||
if (window.mainMenu && window.mainMenu.loadGame) {
|
||||
const saveData = await window.mainMenu.loadGame(1); // Load slot 1
|
||||
this.localSaveData = saveData;
|
||||
return saveData;
|
||||
}
|
||||
|
||||
// Fallback to localStorage
|
||||
const saveKey = 'gso_save_slot_1';
|
||||
const saveData = localStorage.getItem(saveKey);
|
||||
|
||||
if (saveData) {
|
||||
const parsed = JSON.parse(saveData);
|
||||
this.localSaveData = parsed;
|
||||
return parsed;
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (error) {
|
||||
console.error('[SMART SAVE] Error loading local data:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Save local data
|
||||
async saveLocalData(gameData) {
|
||||
try {
|
||||
// Don't save locally when in multiplayer mode
|
||||
if (this.isMultiplayer) {
|
||||
console.log('[SMART SAVE] Skipping local save - in multiplayer mode');
|
||||
return true;
|
||||
}
|
||||
|
||||
console.log('[SMART SAVE] Saving locally');
|
||||
|
||||
// Use existing local save system
|
||||
if (window.mainMenu && window.mainMenu.saveGame) {
|
||||
await window.mainMenu.saveGame(1, gameData); // Save to slot 1
|
||||
this.localSaveData = gameData;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Fallback to localStorage
|
||||
const saveKey = 'gso_save_slot_1';
|
||||
localStorage.setItem(saveKey, JSON.stringify(gameData));
|
||||
this.localSaveData = gameData;
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('[SMART SAVE] Error saving local data:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply server data to game
|
||||
applyServerDataToGame(serverData) {
|
||||
console.log('[SMART SAVE] Applying server data to game');
|
||||
|
||||
this.serverPlayerData = serverData;
|
||||
|
||||
// Apply to game if game is running (try both methods)
|
||||
if (window.game) {
|
||||
console.log('[SMART SAVE] Game is available, checking for data loading methods');
|
||||
console.log('[SMART SAVE] - loadPlayerData:', !!window.game.loadPlayerData);
|
||||
console.log('[SMART SAVE] - loadServerPlayerData:', !!window.game.loadServerPlayerData);
|
||||
|
||||
if (window.game.loadServerPlayerData) {
|
||||
console.log('[SMART SAVE] Using loadServerPlayerData method');
|
||||
window.game.loadServerPlayerData(serverData);
|
||||
console.log('[SMART SAVE] Server data applied to game, forcing UI refresh');
|
||||
|
||||
// Force UI refresh after applying server data
|
||||
if (window.game.systems && window.game.systems.ui && window.game.systems.ui.forceRefreshAllUI) {
|
||||
console.log('[SMART SAVE] Forcing UI refresh after server data application');
|
||||
window.game.systems.ui.forceRefreshAllUI();
|
||||
} else {
|
||||
console.warn('[SMART SAVE] UI refresh not available after server data application - systems:', !!window.game.systems, 'ui:', !!window.game.systems?.ui, 'forceRefreshAllUI:', !!window.game.systems?.ui?.forceRefreshAllUI);
|
||||
}
|
||||
} else if (window.game.loadPlayerData) {
|
||||
console.log('[SMART SAVE] Using loadPlayerData method');
|
||||
window.game.loadPlayerData(serverData);
|
||||
console.log('[SMART SAVE] Server data applied to game, forcing UI refresh');
|
||||
|
||||
// Force UI refresh after applying server data
|
||||
if (window.game.systems && window.game.systems.ui && window.game.systems.ui.forceRefreshAllUI) {
|
||||
console.log('[SMART SAVE] Forcing UI refresh after server data application');
|
||||
window.game.systems.ui.forceRefreshAllUI();
|
||||
} else {
|
||||
console.warn('[SMART SAVE] UI refresh not available after server data application - systems:', !!window.game.systems, 'ui:', !!window.game.systems?.ui, 'forceRefreshAllUI:', !!window.game.systems?.ui?.forceRefreshAllUI);
|
||||
|
||||
// Try delayed UI refresh since UIManager might not be ready yet
|
||||
console.log('[SMART SAVE] Attempting delayed UI refresh...');
|
||||
setTimeout(() => {
|
||||
if (window.game.systems && window.game.systems.ui && window.game.systems.ui.forceRefreshAllUI) {
|
||||
console.log('[SMART SAVE] Delayed UI refresh successful');
|
||||
window.game.systems.ui.forceRefreshAllUI();
|
||||
} else {
|
||||
console.warn('[SMART SAVE] Delayed UI refresh also failed - systems:', !!window.game.systems, 'ui:', !!window.game.systems?.ui, 'forceRefreshAllUI:', !!window.game.systems?.ui?.forceRefreshAllUI);
|
||||
}
|
||||
}, 2000); // Wait 2 seconds for systems to initialize
|
||||
}
|
||||
} else {
|
||||
console.warn('[SMART SAVE] No data loading method available on game object');
|
||||
}
|
||||
} else {
|
||||
console.warn('[SMART SAVE] Game not available for data application');
|
||||
}
|
||||
|
||||
// Store for game engine
|
||||
if (window.gameInitializer) {
|
||||
window.gameInitializer.serverPlayerData = serverData;
|
||||
}
|
||||
}
|
||||
|
||||
// Get current save source info
|
||||
getSaveInfo() {
|
||||
return {
|
||||
isMultiplayer: this.isMultiplayer,
|
||||
hasServerData: !!this.serverPlayerData,
|
||||
hasLocalData: !!this.localSaveData,
|
||||
saveLocation: this.isMultiplayer ? 'Server Database' : 'Local Storage'
|
||||
};
|
||||
}
|
||||
|
||||
// Sync data between local and server (for migration)
|
||||
async syncData(direction = 'toServer') {
|
||||
if (direction === 'toServer') {
|
||||
// Upload local data to server
|
||||
const localData = await this.loadLocalData();
|
||||
if (localData) {
|
||||
await this.saveServerData(localData);
|
||||
console.log('[SMART SAVE] Synced local data to server');
|
||||
}
|
||||
} else {
|
||||
// Download server data to local
|
||||
const serverData = await this.loadServerData();
|
||||
if (serverData) {
|
||||
await this.saveLocalData(serverData);
|
||||
console.log('[SMART SAVE] Synced server data to local');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create global instance
|
||||
window.smartSaveManager = new SmartSaveManager();
|
||||
|
||||
console.log('[SMART SAVE] SmartSaveManager loaded and available globally');
|
||||
@ -5,7 +5,9 @@
|
||||
|
||||
class DebugLogger {
|
||||
constructor() {
|
||||
this.debugEnabled = true; // Always enabled
|
||||
// Completely disable debug logging to prevent console flooding
|
||||
this.debugEnabled = false;
|
||||
|
||||
this.startTime = performance.now();
|
||||
this.stepTimers = new Map();
|
||||
this.debugLogs = []; // Store logs in memory
|
||||
@ -15,10 +17,15 @@ class DebugLogger {
|
||||
this.logger = window.logger || null;
|
||||
|
||||
// Log initialization
|
||||
this.log('=== DEBUG SESSION STARTED ===');
|
||||
if (this.debugEnabled) {
|
||||
this.log('=== DEBUG SESSION STARTED ===');
|
||||
}
|
||||
}
|
||||
|
||||
async log(message, data = null) {
|
||||
// Skip logging if debug is disabled
|
||||
if (!this.debugEnabled) return;
|
||||
|
||||
const timestamp = new Date().toISOString();
|
||||
const stackTrace = new Error().stack;
|
||||
|
||||
@ -55,13 +62,13 @@ class DebugLogger {
|
||||
this.debugLogs.shift();
|
||||
}
|
||||
|
||||
// Always log to console
|
||||
console.log(`[DEBUG] ${message}`, data || '');
|
||||
// Skip console logging to prevent flooding
|
||||
// console.log(`[DEBUG] ${message}`, data || '');
|
||||
|
||||
// Log performance data to console
|
||||
if (performanceData.memory) {
|
||||
console.log(`[PERF] ${performanceData.elapsed} | Memory: ${performanceData.memory.used}/${performanceData.memory.total}`);
|
||||
}
|
||||
// Skip performance logging to prevent flooding
|
||||
// if (performanceData.memory) {
|
||||
// console.log(`[PERF] ${performanceData.elapsed} | Memory: ${performanceData.memory.used}/${performanceData.memory.total}`);
|
||||
// }
|
||||
|
||||
// Use existing logger if available
|
||||
if (this.logger) {
|
||||
@ -79,6 +86,9 @@ class DebugLogger {
|
||||
}
|
||||
|
||||
async startStep(stepName) {
|
||||
// Skip logging if debug is disabled
|
||||
if (!this.debugEnabled) return;
|
||||
|
||||
this.stepTimers.set(stepName, performance.now());
|
||||
await this.log(`STEP START: ${stepName}`, {
|
||||
type: 'step_start',
|
||||
@ -88,6 +98,9 @@ class DebugLogger {
|
||||
}
|
||||
|
||||
async endStep(stepName, data = null) {
|
||||
// Skip logging if debug is disabled
|
||||
if (!this.debugEnabled) return;
|
||||
|
||||
const startTime = this.stepTimers.get(stepName);
|
||||
const duration = startTime ? (performance.now() - startTime).toFixed(2) : 'N/A';
|
||||
|
||||
@ -101,6 +114,9 @@ class DebugLogger {
|
||||
}
|
||||
|
||||
async logStep(stepName, data = null) {
|
||||
// Skip logging if debug is disabled
|
||||
if (!this.debugEnabled) return;
|
||||
|
||||
await this.log(`STEP: ${stepName}`, {
|
||||
type: 'step',
|
||||
step: stepName,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -95,72 +95,24 @@ class Inventory {
|
||||
maxSlots: this.maxSlots
|
||||
});
|
||||
|
||||
const startingItems = [
|
||||
{
|
||||
id: 'starter_blaster_common',
|
||||
name: 'Common Blaster',
|
||||
type: 'weapon',
|
||||
rarity: 'common',
|
||||
quantity: 1,
|
||||
stats: { attack: 5, criticalChance: 0.02 },
|
||||
description: 'A reliable basic blaster for new pilots',
|
||||
equipable: true,
|
||||
slot: 'weapon'
|
||||
},
|
||||
{
|
||||
id: 'basic_armor_common',
|
||||
name: 'Basic Armor',
|
||||
type: 'armor',
|
||||
rarity: 'common',
|
||||
quantity: 1,
|
||||
stats: { defense: 3 },
|
||||
description: 'Light armor providing basic protection',
|
||||
equipable: true,
|
||||
slot: 'armor'
|
||||
}
|
||||
];
|
||||
|
||||
if (debugLogger) debugLogger.logStep('Adding starting items', {
|
||||
startingItemCount: startingItems.length,
|
||||
startingItems: startingItems.map(item => ({
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
type: item.type,
|
||||
quantity: item.quantity
|
||||
}))
|
||||
});
|
||||
|
||||
startingItems.forEach(item => {
|
||||
console.log(`[DEBUG] Adding starting item: ${item.name}`);
|
||||
const result = this.addItem(item);
|
||||
console.log(`[DEBUG] Starting item add result: ${result}, inventory size: ${this.items.length}`);
|
||||
});
|
||||
|
||||
// Equip starter items
|
||||
console.log('[INVENTORY] Equipping starter items');
|
||||
if (debugLogger) debugLogger.logStep('Equipping starter items');
|
||||
|
||||
// Equip starter blaster
|
||||
const blasterItem = this.items.find(item => item.id === 'starter_blaster');
|
||||
if (blasterItem) {
|
||||
console.log('[INVENTORY] Equipping starter blaster');
|
||||
this.equipItem(blasterItem.id);
|
||||
// In multiplayer mode, starting items should come from server
|
||||
if (window.smartSaveManager?.isMultiplayer) {
|
||||
console.log('[INVENTORY] Multiplayer mode - starting items will be provided by server');
|
||||
if (debugLogger) debugLogger.logStep('Skipping starting items in multiplayer mode');
|
||||
if (debugLogger) debugLogger.endStep('Inventory.addStartingItems', {
|
||||
finalItemCount: this.items.length,
|
||||
itemsAdded: 0
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Equip basic armor
|
||||
const armorItem = this.items.find(item => item.id === 'basic_armor');
|
||||
if (armorItem) {
|
||||
console.log('[INVENTORY] Equipping basic armor');
|
||||
this.equipItem(armorItem.id);
|
||||
}
|
||||
|
||||
// Auto-stack starting items
|
||||
if (debugLogger) debugLogger.logStep('Auto-stacking starting items');
|
||||
this.autoStackItems();
|
||||
// Singleplayer mode - no hardcoded starting items available
|
||||
console.log('[INVENTORY] Singleplayer mode - no hardcoded starting items available');
|
||||
if (debugLogger) debugLogger.logStep('No starting items available in singleplayer mode');
|
||||
|
||||
if (debugLogger) debugLogger.endStep('Inventory.addStartingItems', {
|
||||
finalItemCount: this.items.length,
|
||||
itemsAdded: startingItems.length
|
||||
itemsAdded: 0
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -213,12 +213,10 @@ class Logger {
|
||||
|
||||
async info(message, data = null) {
|
||||
await this.log('info', message, data);
|
||||
console.info(`[INFO] ${message}`, data || '');
|
||||
}
|
||||
|
||||
async debug(message, data = null) {
|
||||
await this.log('debug', message, data);
|
||||
console.debug(`[DEBUG] ${message}`, data || '');
|
||||
}
|
||||
|
||||
async gameEvent(eventType, details) {
|
||||
|
||||
@ -537,9 +537,9 @@ class Player {
|
||||
upgrades: []
|
||||
};
|
||||
|
||||
console.log('=== DEBUG: Character Reset ===');
|
||||
console.log('Player health reset to:', this.attributes.health, '/', this.attributes.maxHealth);
|
||||
console.log('Ship health reset to:', this.ship.health, '/', this.ship.maxHealth);
|
||||
// console.log('=== DEBUG: Character Reset ===');
|
||||
// console.log('Player health reset to:', this.attributes.health, '/', this.attributes.maxHealth);
|
||||
// console.log('Ship health reset to:', this.ship.health, '/', this.ship.maxHealth);
|
||||
|
||||
// Reset skills
|
||||
this.skills = {};
|
||||
@ -692,16 +692,43 @@ class Player {
|
||||
}
|
||||
|
||||
updatePlayTime(deltaTime) {
|
||||
// DISABLED: Reduce console spam for quest debugging
|
||||
/*
|
||||
console.log('[PLAYER] updatePlayTime called with deltaTime:', deltaTime, 'ms');
|
||||
console.log('[PLAYER] Game state check:', {
|
||||
hasGame: !!this.game,
|
||||
isRunning: this.game?.isRunning,
|
||||
isPaused: this.game?.state?.paused,
|
||||
isHidden: document.hidden
|
||||
});
|
||||
*/
|
||||
|
||||
// Only update playtime when game is actively running and not paused
|
||||
if (!this.game || !this.game.isRunning || this.game.state.paused) {
|
||||
// console.log('[PLAYER] Skipping playtime update - game not running or paused');
|
||||
return;
|
||||
}
|
||||
|
||||
// Also check if tab is visible (don't count time when tab is in background)
|
||||
if (document.hidden) {
|
||||
// console.log('[PLAYER] Skipping playtime update - tab hidden');
|
||||
return;
|
||||
}
|
||||
|
||||
// DISABLED: Reduce console spam for quest debugging
|
||||
/*
|
||||
console.log('[PLAYER] Before update - playTime:', this.stats.playTime, 'ms');
|
||||
*/
|
||||
|
||||
// Use real computer time delta
|
||||
this.stats.playTime += deltaTime;
|
||||
|
||||
// DISABLED: Reduce console spam for quest debugging
|
||||
/*
|
||||
console.log('[PLAYER] After update - playTime:', this.stats.playTime, 'ms');
|
||||
console.log('[PLAYER] PlayTime in seconds:', this.stats.playTime / 1000, 'seconds');
|
||||
console.log('[PLAYER] PlayTime in minutes:', this.stats.playTime / 60000, 'minutes');
|
||||
console.log('[PLAYER] PlayTime in hours:', this.stats.playTime / 3600000, 'hours');
|
||||
*/
|
||||
}
|
||||
|
||||
// UI updates
|
||||
@ -717,18 +744,25 @@ class Player {
|
||||
|
||||
// Update player info
|
||||
const playerNameElement = document.getElementById('playerName');
|
||||
const playerTitleElement = document.getElementById('playerTitle');
|
||||
const playerLevelElement = document.getElementById('playerLevel');
|
||||
|
||||
if (playerNameElement) {
|
||||
playerNameElement.textContent = `${this.info.name} - ${this.info.title}`;
|
||||
playerNameElement.textContent = this.info.name;
|
||||
}
|
||||
|
||||
if (playerTitleElement) {
|
||||
playerTitleElement.textContent = ` - ${this.info.title}`;
|
||||
}
|
||||
|
||||
if (playerLevelElement) {
|
||||
playerLevelElement.textContent = `Lv. ${this.stats.level}`;
|
||||
}
|
||||
|
||||
// Update health and energy
|
||||
if (this.game && this.game.systems && this.game.systems.ui) {
|
||||
// Update health and energy only if in multiplayer mode or game is actively running
|
||||
const shouldUpdateUI = window.smartSaveManager?.isMultiplayer || this.game?.isRunning;
|
||||
|
||||
if (shouldUpdateUI && this.game && this.game.systems && this.game.systems.ui) {
|
||||
this.game.systems.ui.updateResourceDisplay();
|
||||
}
|
||||
|
||||
@ -765,6 +799,7 @@ class Player {
|
||||
if (debugLogger) debugLogger.logStep('Player UI update completed', {
|
||||
elementsUpdated: {
|
||||
playerName: !!playerNameElement,
|
||||
playerTitle: !!playerTitleElement,
|
||||
playerLevel: !!playerLevelElement,
|
||||
totalKills: !!totalKillsElement,
|
||||
dungeonsCleared: !!dungeonsClearedElement,
|
||||
@ -817,9 +852,29 @@ class Player {
|
||||
try {
|
||||
if (data.stats) {
|
||||
console.log('[PLAYER] Loading stats:', data.stats);
|
||||
console.log('[PLAYER] Current playTime before load:', this.stats.playTime);
|
||||
console.log('[PLAYER] Server playTime:', data.stats.playTime);
|
||||
|
||||
const oldStats = { ...this.stats };
|
||||
this.stats = { ...this.stats, ...data.stats };
|
||||
|
||||
// Preserve playTime if server doesn't provide it or provides 0
|
||||
const existingPlayTime = this.stats.playTime || 0;
|
||||
const serverPlayTime = data.stats.playTime || 0;
|
||||
|
||||
// Use server playTime if it's greater than existing, otherwise preserve existing
|
||||
const preservedPlayTime = serverPlayTime > existingPlayTime ? serverPlayTime : existingPlayTime;
|
||||
|
||||
console.log('[PLAYER] Preserving playTime:', preservedPlayTime, '(existing:', existingPlayTime, ', server:', serverPlayTime, ')');
|
||||
|
||||
// Merge stats but preserve playTime
|
||||
this.stats = {
|
||||
...this.stats,
|
||||
...data.stats,
|
||||
playTime: preservedPlayTime // Force preserve playTime
|
||||
};
|
||||
|
||||
console.log('[PLAYER] Level after stats load:', this.stats.level);
|
||||
console.log('[PLAYER] PlayTime after stats load:', this.stats.playTime);
|
||||
|
||||
if (debugLogger) debugLogger.logStep('Player stats loaded', {
|
||||
oldLevel: oldStats.level,
|
||||
|
||||
@ -54,8 +54,9 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
window.debugLogger.startStep('domLoad');
|
||||
window.debugLogger.logStep('DOM loaded, starting initialization');
|
||||
|
||||
// Auto-start local server for singleplayer mode
|
||||
console.log('[MAIN] Checking local server status...');
|
||||
// Auto-start local server for singleplayer mode (DISABLED to prevent auto-start after multiplayer disconnect)
|
||||
console.log('[MAIN] Skipping local server auto-start to prevent conflicts with multiplayer mode');
|
||||
/*
|
||||
if (window.localServerManager) {
|
||||
try {
|
||||
const serverResult = await window.localServerManager.autoStartIfSingleplayer();
|
||||
@ -78,6 +79,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
} else {
|
||||
console.warn('[MAIN] LocalServerManager not available');
|
||||
}
|
||||
*/
|
||||
|
||||
// Title bar is already initialized, just log it
|
||||
console.log('[MAIN] DOM loaded - title bar should already be working');
|
||||
@ -368,7 +370,7 @@ if (window.performance && window.performance.memory) {
|
||||
setInterval(() => {
|
||||
if (window.game && window.game.isRunning) {
|
||||
const stats = window.game.getPerformanceStats();
|
||||
if (stats.memory && stats.memory.used / stats.memory.total > 0.9) {
|
||||
if (stats.memory && stats.memory.used / stats.memory.limit > 0.8) {
|
||||
console.warn('High memory usage detected:', stats.memory);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1309,7 +1309,11 @@ class BaseSystem {
|
||||
});
|
||||
}
|
||||
|
||||
player.updateUI();
|
||||
// Only update player UI if in multiplayer mode or game is actively running
|
||||
if (this.game.shouldUpdateGUI()) {
|
||||
player.updateUI();
|
||||
}
|
||||
|
||||
this.updateShipGallery();
|
||||
|
||||
// Also update ShipSystem display
|
||||
@ -1592,10 +1596,12 @@ class BaseSystem {
|
||||
// Apply benefits
|
||||
this.applyStarbaseBenefits(newStarbase);
|
||||
|
||||
// Update UI
|
||||
economy.updateUI();
|
||||
this.updateStarbaseList();
|
||||
this.updateStarbasePurchaseList();
|
||||
// Only update UI if in multiplayer mode or game is actively running
|
||||
if (this.game.shouldUpdateGUI()) {
|
||||
economy.updateUI();
|
||||
this.updateStarbaseList();
|
||||
this.updateStarbasePurchaseList();
|
||||
}
|
||||
|
||||
this.game.showNotification(`Purchased ${starbaseTemplate.name}!`, 'success', 4000);
|
||||
}
|
||||
@ -1650,11 +1656,18 @@ class BaseSystem {
|
||||
}
|
||||
|
||||
startMiningProduction(starbase) {
|
||||
// Set up passive credit generation
|
||||
if (!this.miningInterval) {
|
||||
// Only start mining if in multiplayer mode or game is actively running
|
||||
const shouldStartMining = window.smartSaveManager?.isMultiplayer || this.game?.isRunning;
|
||||
|
||||
if (shouldStartMining && !this.miningInterval) {
|
||||
// Set up passive credit generation
|
||||
this.miningInterval = setInterval(() => {
|
||||
this.game.systems.economy.addCredits(500, 'mining_outpost');
|
||||
}, 3600000); // 1 hour
|
||||
|
||||
console.log('[BASE SYSTEM] Mining production started');
|
||||
} else if (!shouldStartMining) {
|
||||
console.log('[BASE SYSTEM] Skipping mining production - not in multiplayer mode');
|
||||
}
|
||||
}
|
||||
|
||||
@ -2057,10 +2070,12 @@ showRoomBuildMenu(x, y) {
|
||||
console.log('[DEBUG] Player ship updated:', player.ship);
|
||||
console.log('[DEBUG] Player attributes updated:', player.attributes);
|
||||
|
||||
// Update UI displays
|
||||
player.updateUI();
|
||||
if (this.game.systems.ship && this.game.systems.ship.updateCurrentShipDisplay) {
|
||||
this.game.systems.ship.updateCurrentShipDisplay();
|
||||
// Only update UI displays if in multiplayer mode or game is actively running
|
||||
if (this.game.shouldUpdateGUI()) {
|
||||
player.updateUI();
|
||||
if (this.game.systems.ship && this.game.systems.ship.updateCurrentShipDisplay) {
|
||||
this.game.systems.ship.updateCurrentShipDisplay();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -641,7 +641,13 @@ class CraftingSystem extends BaseSystem {
|
||||
switchCategory(category) {
|
||||
this.currentCategory = category;
|
||||
this.selectedRecipe = null;
|
||||
this.updateUI();
|
||||
|
||||
// Update UI only if in multiplayer mode or game is actively running
|
||||
const shouldUpdateUI = window.smartSaveManager?.isMultiplayer || this.game?.isRunning;
|
||||
|
||||
if (shouldUpdateUI) {
|
||||
this.updateUI();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -12,11 +12,18 @@ class IdleSystem {
|
||||
this.lastActiveTime = Date.now();
|
||||
this.accumulatedTime = 0; // Track time for resource generation
|
||||
|
||||
// Idle production rates
|
||||
// Idle production rates (online rates)
|
||||
this.productionRates = {
|
||||
credits: 10, // credits per second (increased for better gameplay)
|
||||
experience: 1, // experience per second (increased for better progression)
|
||||
energy: 0.5 // energy regeneration per second
|
||||
credits: 0.1, // 1 credit every 10 seconds (0.1 per second)
|
||||
experience: 0, // no auto experience - only from dungeons
|
||||
energy: 1/300 // 1 energy every 5 minutes (1/300 per second)
|
||||
};
|
||||
|
||||
// Offline rates (different from online rates)
|
||||
this.offlineProductionRates = {
|
||||
credits: 1/60, // 1 credit every 1 minute (1/60 per second)
|
||||
experience: 0, // no experience offline - only from dungeons
|
||||
energy: 1/300 // 1 energy every 5 minutes (same as online)
|
||||
};
|
||||
|
||||
// Offline rewards
|
||||
@ -144,6 +151,20 @@ class IdleSystem {
|
||||
}
|
||||
|
||||
claimOfflineRewards() {
|
||||
// In multiplayer mode, use server communication
|
||||
if (window.smartSaveManager?.isMultiplayer) {
|
||||
this.game.showNotification('Claiming offline rewards from server...', 'info', 2000);
|
||||
|
||||
// Send request to server
|
||||
if (window.game && window.game.socket) {
|
||||
window.game.socket.emit('claimOfflineRewards', {});
|
||||
} else {
|
||||
this.game.showNotification('Not connected to server', 'error', 3000);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Singleplayer mode - use local logic
|
||||
if (this.offlineRewards.credits === 0 &&
|
||||
this.offlineRewards.experience === 0 &&
|
||||
this.offlineRewards.items.length === 0) {
|
||||
|
||||
383
Client/js/systems/ItemSystem.js
Normal file
383
Client/js/systems/ItemSystem.js
Normal file
@ -0,0 +1,383 @@
|
||||
/**
|
||||
* Galaxy Strike Online - Client Item System
|
||||
* Dynamically loads and manages items from the GameServer
|
||||
*/
|
||||
|
||||
class ItemSystem {
|
||||
constructor(gameEngine) {
|
||||
this.game = gameEngine;
|
||||
|
||||
// Item storage
|
||||
this.itemCatalog = new Map(); // itemId -> item data
|
||||
this.shopItems = []; // Array of shop items
|
||||
this.lastUpdated = null;
|
||||
|
||||
// Loading state
|
||||
this.isLoading = false;
|
||||
this.loadPromise = null;
|
||||
|
||||
// Event listeners
|
||||
this.eventListeners = new Map();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the item system and load data from server
|
||||
*/
|
||||
async initialize() {
|
||||
console.log('[ITEM SYSTEM] Initializing client item system');
|
||||
|
||||
if (this.loadPromise) {
|
||||
return this.loadPromise;
|
||||
}
|
||||
|
||||
this.loadPromise = this.loadFromServer();
|
||||
return this.loadPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all items from the GameServer
|
||||
*/
|
||||
async loadFromServer() {
|
||||
if (this.isLoading) {
|
||||
console.log('[ITEM SYSTEM] Already loading items from server');
|
||||
return this.loadPromise;
|
||||
}
|
||||
|
||||
this.isLoading = true;
|
||||
|
||||
try {
|
||||
console.log('[ITEM SYSTEM] Loading items from GameServer - Multiplayer Mode');
|
||||
console.log('[ITEM SYSTEM] Socket connection status:', !!window.game?.socket);
|
||||
|
||||
if (!window.game || !window.game.socket) {
|
||||
throw new Error('Not connected to server - multiplayer mode requires server connection');
|
||||
}
|
||||
|
||||
// Load shop items from server
|
||||
const shopItems = await this.fetchShopItems();
|
||||
|
||||
console.log('[ITEM SYSTEM] Received', shopItems.length, 'items from server');
|
||||
|
||||
// Process and store items
|
||||
this.processServerItems(shopItems);
|
||||
|
||||
this.lastUpdated = Date.now();
|
||||
console.log(`[ITEM SYSTEM] Successfully loaded ${this.itemCatalog.size} items from server`);
|
||||
console.log('[ITEM SYSTEM] Item categories loaded:', Object.keys(this.itemCatalog).length);
|
||||
|
||||
// Emit loaded event
|
||||
this.emit('itemsLoaded', {
|
||||
itemCount: this.itemCatalog.size,
|
||||
shopItemCount: this.shopItems.length,
|
||||
timestamp: this.lastUpdated
|
||||
});
|
||||
|
||||
return true;
|
||||
|
||||
} catch (error) {
|
||||
console.error('[ITEM SYSTEM] Failed to load items from server:', error);
|
||||
console.error('[ITEM SYSTEM] Error details:', {
|
||||
message: error.message,
|
||||
stack: error.stack,
|
||||
socketConnected: !!window.game?.socket,
|
||||
socketId: window.game?.socket?.id
|
||||
});
|
||||
|
||||
// No fallback - emit error event
|
||||
this.emit('itemsLoadError', error);
|
||||
return false;
|
||||
|
||||
} finally {
|
||||
this.isLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch shop items from the GameServer
|
||||
*/
|
||||
async fetchShopItems() {
|
||||
console.log('[ITEM SYSTEM] Starting fetchShopItems');
|
||||
|
||||
if (!window.game || !window.game.socket) {
|
||||
console.error('[ITEM SYSTEM] No socket connection available');
|
||||
throw new Error('Not connected to server');
|
||||
}
|
||||
|
||||
console.log('[ITEM SYSTEM] Socket ID:', window.game.socket.id);
|
||||
console.log('[ITEM SYSTEM] Socket connected:', window.game.socket.connected);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const timeout = setTimeout(() => {
|
||||
console.error('[ITEM SYSTEM] Server request timeout after 10 seconds');
|
||||
window.game.socket.off('shopItemsReceived', handleResponse);
|
||||
reject(new Error('Server request timeout'));
|
||||
}, 10000);
|
||||
|
||||
// Request shop items from server
|
||||
console.log('[ITEM SYSTEM] Emitting getShopItems request');
|
||||
window.game.socket.emit('getShopItems', {});
|
||||
|
||||
// Listen for response
|
||||
const handleResponse = (data) => {
|
||||
console.log('[ITEM SYSTEM] Received shopItemsReceived response:', data);
|
||||
clearTimeout(timeout);
|
||||
window.game.socket.off('shopItemsReceived', handleResponse);
|
||||
|
||||
if (data.success) {
|
||||
console.log('[ITEM SYSTEM] Successfully received', data.items?.length || 0, 'items');
|
||||
console.log('[ITEM SYSTEM] Response timestamp:', data.timestamp);
|
||||
resolve(data.items || []);
|
||||
} else {
|
||||
console.error('[ITEM SYSTEM] Server returned error:', data.error);
|
||||
reject(new Error(data.error || 'Failed to load shop items'));
|
||||
}
|
||||
};
|
||||
|
||||
console.log('[ITEM SYSTEM] Setting up shopItemsReceived listener');
|
||||
window.game.socket.on('shopItemsReceived', handleResponse);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch specific item details from server
|
||||
*/
|
||||
async fetchItemDetails(itemId) {
|
||||
if (!window.game || !window.game.socket) {
|
||||
throw new Error('Not connected to server');
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const timeout = setTimeout(() => {
|
||||
reject(new Error('Server request timeout'));
|
||||
}, 5000);
|
||||
|
||||
// Request item details from server
|
||||
window.game.socket.emit('getItemDetails', { itemId });
|
||||
|
||||
// Listen for response
|
||||
const handleResponse = (data) => {
|
||||
clearTimeout(timeout);
|
||||
window.game.socket.off('itemDetailsReceived', handleResponse);
|
||||
|
||||
if (data.success) {
|
||||
// Cache the item
|
||||
this.itemCatalog.set(itemId, data.item);
|
||||
resolve(data.item);
|
||||
} else {
|
||||
reject(new Error(data.error || 'Item not found'));
|
||||
}
|
||||
};
|
||||
|
||||
window.game.socket.on('itemDetailsReceived', handleResponse);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Process items received from server
|
||||
*/
|
||||
processServerItems(items) {
|
||||
console.log('[ITEM SYSTEM] Processing', items.length, 'items from server');
|
||||
console.log('[ITEM SYSTEM] Sample items:', items.slice(0, 3));
|
||||
|
||||
this.itemCatalog.clear();
|
||||
this.shopItems = [];
|
||||
|
||||
for (const item of items) {
|
||||
// Store in catalog
|
||||
this.itemCatalog.set(item.id, item);
|
||||
|
||||
// Add to shop items if available for shop
|
||||
if (item.categories && item.categories.includes('shop')) {
|
||||
this.shopItems.push(item);
|
||||
}
|
||||
|
||||
console.log('[ITEM SYSTEM] Added item:', {
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
type: item.type,
|
||||
rarity: item.rarity,
|
||||
price: item.price,
|
||||
categories: item.categories
|
||||
});
|
||||
}
|
||||
|
||||
console.log('[ITEM SYSTEM] Processing complete - Catalog:', this.itemCatalog.size, 'Shop items:', this.shopItems.length);
|
||||
console.log('[ITEM SYSTEM] Shop items by type:', this.shopItems.reduce((acc, item) => {
|
||||
acc[item.type] = (acc[item.type] || 0) + 1;
|
||||
return acc;
|
||||
}, {}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get item by ID
|
||||
*/
|
||||
getItem(itemId) {
|
||||
// Return from cache if available
|
||||
if (this.itemCatalog.has(itemId)) {
|
||||
return this.itemCatalog.get(itemId);
|
||||
}
|
||||
|
||||
// Try to fetch from server if not cached
|
||||
if (window.game && window.game.socket) {
|
||||
this.fetchItemDetails(itemId).catch(error => {
|
||||
console.warn(`[ITEM SYSTEM] Failed to fetch item ${itemId}:`, error);
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all shop items
|
||||
*/
|
||||
getShopItems() {
|
||||
return [...this.shopItems];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get items by category
|
||||
*/
|
||||
getItemsByCategory(category) {
|
||||
return Array.from(this.itemCatalog.values()).filter(item =>
|
||||
item.type === category || (item.categories && item.categories.includes(category))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get items by type
|
||||
*/
|
||||
getItemsByType(type) {
|
||||
return Array.from(this.itemCatalog.values()).filter(item => item.type === type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get items by rarity
|
||||
*/
|
||||
getItemsByRarity(rarity) {
|
||||
return Array.from(this.itemCatalog.values()).filter(item => item.rarity === rarity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if player can use item based on requirements
|
||||
*/
|
||||
canPlayerUseItem(item, playerLevel = null) {
|
||||
if (!item.requirements) return true;
|
||||
|
||||
// Get player level if not provided
|
||||
if (playerLevel === null && window.game && window.game.systems && window.game.systems.player) {
|
||||
playerLevel = window.game.systems.player.level;
|
||||
}
|
||||
|
||||
// Check level requirement
|
||||
if (item.requirements.level && playerLevel < item.requirements.level) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add other requirement checks here
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filtered shop items for current player
|
||||
*/
|
||||
getAvailableShopItems() {
|
||||
return this.shopItems.filter(item => this.canPlayerUseItem(item));
|
||||
}
|
||||
|
||||
/**
|
||||
* Format item price for display
|
||||
*/
|
||||
formatPrice(item) {
|
||||
if (!item.price) return 'Free';
|
||||
|
||||
const currency = item.currency || 'credits';
|
||||
const price = this.game.formatNumber(item.price);
|
||||
|
||||
return `${price} ${currency}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get item rarity color
|
||||
*/
|
||||
getRarityColor(rarity) {
|
||||
const colors = {
|
||||
common: '#888888',
|
||||
uncommon: '#00ff00',
|
||||
rare: '#0088ff',
|
||||
legendary: '#ff8800',
|
||||
epic: '#ff00ff'
|
||||
};
|
||||
|
||||
return colors[rarity] || '#ffffff';
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh items from server
|
||||
*/
|
||||
async refresh() {
|
||||
console.log('[ITEM SYSTEM] Refreshing items from server');
|
||||
return this.loadFromServer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Event system
|
||||
*/
|
||||
on(event, callback) {
|
||||
if (!this.eventListeners.has(event)) {
|
||||
this.eventListeners.set(event, []);
|
||||
}
|
||||
this.eventListeners.get(event).push(callback);
|
||||
}
|
||||
|
||||
off(event, callback) {
|
||||
if (this.eventListeners.has(event)) {
|
||||
const listeners = this.eventListeners.get(event);
|
||||
const index = listeners.indexOf(callback);
|
||||
if (index > -1) {
|
||||
listeners.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
emit(event, data) {
|
||||
if (this.eventListeners.has(event)) {
|
||||
for (const callback of this.eventListeners.get(event)) {
|
||||
try {
|
||||
callback(data);
|
||||
} catch (error) {
|
||||
console.error(`[ITEM SYSTEM] Error in event listener for ${event}:`, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get system statistics
|
||||
*/
|
||||
getStats() {
|
||||
const stats = {
|
||||
totalItems: this.itemCatalog.size,
|
||||
shopItems: this.shopItems.length,
|
||||
lastUpdated: this.lastUpdated,
|
||||
isLoading: this.isLoading,
|
||||
socketConnected: !!(window.game?.socket),
|
||||
socketId: window.game?.socket?.id
|
||||
};
|
||||
|
||||
// Add category breakdown
|
||||
stats.categories = {};
|
||||
for (const item of this.itemCatalog.values()) {
|
||||
stats.categories[item.type] = (stats.categories[item.type] || 0) + 1;
|
||||
}
|
||||
|
||||
return stats;
|
||||
}
|
||||
}
|
||||
|
||||
// Export for use in other modules
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = ItemSystem;
|
||||
} else {
|
||||
window.ItemSystem = ItemSystem;
|
||||
}
|
||||
@ -13,6 +13,10 @@ class QuestSystem {
|
||||
|
||||
this.game = gameEngine;
|
||||
|
||||
// Server time synchronization
|
||||
this.serverTimeOffset = 0; // Difference between server and client time
|
||||
this.lastServerTimeSync = 0;
|
||||
|
||||
// Quest types
|
||||
this.questTypes = {
|
||||
main: 'Main Story',
|
||||
@ -788,14 +792,15 @@ class QuestSystem {
|
||||
this.maxProceduralQuests = 3;
|
||||
this.proceduralQuestRefresh = 30 * 60 * 1000; // 30 minutes
|
||||
|
||||
// Statistics
|
||||
// Initialize stats
|
||||
this.stats = {
|
||||
questsCompleted: 0,
|
||||
questsFailed: 0,
|
||||
dailyQuestsCompleted: 0,
|
||||
weeklyQuestsCompleted: 0,
|
||||
totalRewardsEarned: { credits: 0, experience: 0, gems: 0 },
|
||||
lastDailyReset: Date.now(),
|
||||
lastWeeklyReset: Date.now()
|
||||
lastDailyReset: this.getServerTime(),
|
||||
lastWeeklyReset: this.getServerTime()
|
||||
};
|
||||
|
||||
// Initialize daily quests
|
||||
@ -816,6 +821,43 @@ class QuestSystem {
|
||||
});
|
||||
}
|
||||
|
||||
// Server time synchronization methods
|
||||
getServerTime() {
|
||||
// In multiplayer mode, use UTC time as server time
|
||||
if (window.smartSaveManager?.isMultiplayer) {
|
||||
// Get current UTC timestamp
|
||||
const utcTime = Date.now();
|
||||
|
||||
console.log('[QUEST SYSTEM] Using UTC time as server time:', utcTime);
|
||||
console.log('[QUEST SYSTEM] Local time:', Date.now());
|
||||
|
||||
return utcTime;
|
||||
}
|
||||
|
||||
// Fallback to client time in singleplayer
|
||||
return Date.now();
|
||||
}
|
||||
|
||||
getServerDate() {
|
||||
// Create a date that displays in UTC
|
||||
const timestamp = this.getServerTime();
|
||||
const utcDate = new Date(timestamp);
|
||||
|
||||
// Force UTC display by using UTC methods
|
||||
return {
|
||||
getTime: () => timestamp,
|
||||
getDay: () => utcDate.getUTCDay(),
|
||||
getHours: () => utcDate.getUTCHours(),
|
||||
getMinutes: () => utcDate.getUTCMinutes(),
|
||||
getSeconds: () => utcDate.getUTCSeconds(),
|
||||
getDate: () => utcDate.getUTCDate(),
|
||||
getFullYear: () => utcDate.getUTCFullYear(),
|
||||
getMonth: () => utcDate.getUTCMonth(),
|
||||
toString: () => utcDate.toUTCString(),
|
||||
valueOf: () => timestamp
|
||||
};
|
||||
}
|
||||
|
||||
async initialize() {
|
||||
const debugLogger = window.debugLogger;
|
||||
|
||||
@ -1119,7 +1161,7 @@ class QuestSystem {
|
||||
|
||||
// Complete quest
|
||||
quest.status = 'completed';
|
||||
quest.completedAt = Date.now();
|
||||
quest.completedAt = this.getServerTime();
|
||||
this.completedQuests.push(quest);
|
||||
|
||||
if (debugLogger) debugLogger.logStep('Quest marked as completed', {
|
||||
@ -1131,7 +1173,7 @@ class QuestSystem {
|
||||
|
||||
// Save completed daily quests to history
|
||||
if (quest.type === 'daily') {
|
||||
const questCopy = { ...quest, completedAt: Date.now() };
|
||||
const questCopy = { ...quest, completedAt: this.getServerTime() };
|
||||
this.completedDailyQuests.push(questCopy);
|
||||
|
||||
if (debugLogger) debugLogger.logStep('Daily quest added to history', {
|
||||
@ -1143,7 +1185,7 @@ class QuestSystem {
|
||||
|
||||
// Save completed weekly quests to history
|
||||
if (quest.type === 'weekly') {
|
||||
const questCopy = { ...quest, completedAt: Date.now() };
|
||||
const questCopy = { ...quest, completedAt: this.getServerTime() };
|
||||
this.completedWeeklyQuests.push(questCopy);
|
||||
|
||||
if (debugLogger) debugLogger.logStep('Weekly quest added to history', {
|
||||
@ -1218,22 +1260,6 @@ class QuestSystem {
|
||||
giveQuestRewards(quest) {
|
||||
const debugLogger = window.debugLogger;
|
||||
|
||||
if (debugLogger) debugLogger.startStep('QuestSystem.giveQuestRewards', {
|
||||
questId: quest.id,
|
||||
questName: quest.name,
|
||||
questType: quest.type,
|
||||
rewards: quest.rewards
|
||||
});
|
||||
|
||||
const oldPlayerStats = {
|
||||
credits: this.game.systems.economy.credits,
|
||||
gems: this.game.systems.economy.gems,
|
||||
experience: this.game.systems.player.stats.experience,
|
||||
level: this.game.systems.player.stats.level
|
||||
};
|
||||
|
||||
const rewardsGiven = {};
|
||||
|
||||
if (quest.rewards.credits) {
|
||||
this.game.systems.economy.addCredits(quest.rewards.credits, 'quest');
|
||||
this.stats.totalRewardsEarned.credits += quest.rewards.credits;
|
||||
@ -1558,7 +1584,7 @@ class QuestSystem {
|
||||
this.completedQuests = [];
|
||||
this.dailyQuests = [];
|
||||
this.selectedDailyQuests = [];
|
||||
this.lastDailyReset = Date.now();
|
||||
this.lastDailyReset = this.getServerTime();
|
||||
|
||||
// Reset main quest statuses
|
||||
this.mainQuests.forEach(quest => {
|
||||
@ -1591,7 +1617,7 @@ class QuestSystem {
|
||||
|
||||
checkDailyReset() {
|
||||
const debugLogger = window.debugLogger;
|
||||
const now = Date.now();
|
||||
const now = this.getServerTime();
|
||||
const lastReset = this.lastDailyReset;
|
||||
const daysSinceReset = Math.floor((now - lastReset) / (24 * 60 * 60 * 1000));
|
||||
|
||||
@ -1645,20 +1671,27 @@ class QuestSystem {
|
||||
// Update countdown immediately
|
||||
this.updateDailyCountdown();
|
||||
|
||||
// Update every second
|
||||
this.dailyCountdownInterval = setInterval(() => {
|
||||
this.updateDailyCountdown();
|
||||
}, 1000);
|
||||
// Only start timer if in multiplayer mode or game is actively running
|
||||
const shouldStartTimer = window.smartSaveManager?.isMultiplayer || this.game?.isRunning;
|
||||
|
||||
console.log('[QUEST SYSTEM] Daily countdown timer started with interval:', this.dailyCountdownInterval);
|
||||
if (shouldStartTimer) {
|
||||
// Update every second
|
||||
this.dailyCountdownInterval = setInterval(() => {
|
||||
this.updateDailyCountdown();
|
||||
}, 1000);
|
||||
|
||||
console.log('[QUEST SYSTEM] Daily countdown timer started with interval:', this.dailyCountdownInterval);
|
||||
} else {
|
||||
console.log('[QUEST SYSTEM] Skipping daily countdown timer - not in multiplayer mode');
|
||||
}
|
||||
}
|
||||
|
||||
updateDailyCountdown() {
|
||||
// Always update countdown so it's ready when user switches to daily tab
|
||||
const now = new Date();
|
||||
const tomorrow = new Date(now);
|
||||
tomorrow.setDate(tomorrow.getDate() + 1);
|
||||
tomorrow.setHours(0, 0, 0, 0); // Set to midnight
|
||||
const now = this.getServerDate();
|
||||
const tomorrow = new Date();
|
||||
tomorrow.setUTCDate(now.getDate() + 1);
|
||||
tomorrow.setUTCHours(0, 0, 0, 0); // Set to midnight UTC
|
||||
|
||||
const timeUntilReset = tomorrow - now;
|
||||
const hours = Math.floor(timeUntilReset / (1000 * 60 * 60));
|
||||
@ -1723,11 +1756,11 @@ class QuestSystem {
|
||||
|
||||
checkWeeklyReset() {
|
||||
const debugLogger = window.debugLogger;
|
||||
const now = Date.now();
|
||||
const now = this.getServerTime();
|
||||
const lastReset = this.lastWeeklyReset || 0;
|
||||
|
||||
// Calculate if we need to reset based on Saturday midnight
|
||||
const currentDateTime = new Date();
|
||||
// Calculate if we need to reset based on Saturday midnight (server time)
|
||||
const currentDateTime = this.getServerDate();
|
||||
const dayOfWeek = currentDateTime.getDay(); // 0 = Sunday, 1 = Monday, ..., 6 = Saturday
|
||||
const currentHour = currentDateTime.getHours();
|
||||
const currentMinute = currentDateTime.getMinutes();
|
||||
@ -1805,18 +1838,25 @@ class QuestSystem {
|
||||
// Update countdown immediately
|
||||
this.updateWeeklyCountdown();
|
||||
|
||||
// Update every minute (weekly changes less frequently)
|
||||
this.weeklyCountdownInterval = setInterval(() => {
|
||||
this.updateWeeklyCountdown();
|
||||
// Check for weekly reset every minute
|
||||
this.checkWeeklyReset();
|
||||
}, 60000); // Update every minute
|
||||
// Only start timer if in multiplayer mode or game is actively running
|
||||
const shouldStartTimer = window.smartSaveManager?.isMultiplayer || this.game?.isRunning;
|
||||
|
||||
console.log('[QUEST SYSTEM] Weekly countdown timer started with interval:', this.weeklyCountdownInterval);
|
||||
if (shouldStartTimer) {
|
||||
// Update every minute (weekly changes less frequently)
|
||||
this.weeklyCountdownInterval = setInterval(() => {
|
||||
this.updateWeeklyCountdown();
|
||||
// Check for weekly reset every minute
|
||||
this.checkWeeklyReset();
|
||||
}, 60000); // 1 minute
|
||||
|
||||
console.log('[QUEST SYSTEM] Weekly countdown timer started with interval:', this.weeklyCountdownInterval);
|
||||
} else {
|
||||
console.log('[QUEST SYSTEM] Skipping weekly countdown timer - not in multiplayer mode');
|
||||
}
|
||||
}
|
||||
|
||||
updateWeeklyCountdown() {
|
||||
const now = new Date();
|
||||
const now = this.getServerDate();
|
||||
const dayOfWeek = now.getDay(); // 0 = Sunday, 1 = Monday, ..., 6 = Saturday
|
||||
const currentHour = now.getHours();
|
||||
const currentMinute = now.getMinutes();
|
||||
@ -1850,19 +1890,19 @@ class QuestSystem {
|
||||
|
||||
console.log('[QUEST SYSTEM] Days until Saturday:', daysUntilSaturday);
|
||||
|
||||
// Create the target reset time (Saturday midnight)
|
||||
const nextSaturday = new Date(now);
|
||||
nextSaturday.setDate(now.getDate() + daysUntilSaturday);
|
||||
nextSaturday.setHours(0, 0, 0, 0); // Set to midnight
|
||||
// Create the target reset time (Saturday midnight UTC)
|
||||
const nextSaturday = new Date();
|
||||
nextSaturday.setUTCDate(now.getDate() + daysUntilSaturday);
|
||||
nextSaturday.setUTCHours(0, 0, 0, 0); // Set to midnight UTC
|
||||
|
||||
console.log('[QUEST SYSTEM] Next Saturday reset time:', nextSaturday.toString());
|
||||
console.log('[QUEST SYSTEM] Next Saturday reset time:', nextSaturday.toUTCString());
|
||||
|
||||
let timeUntilReset = nextSaturday.getTime() - now.getTime();
|
||||
|
||||
// Ensure timeUntilReset is positive (handle edge cases)
|
||||
if (timeUntilReset <= 0) {
|
||||
console.log('[QUEST SYSTEM] Time until reset is negative or zero, adding 7 days');
|
||||
nextSaturday.setDate(nextSaturday.getDate() + 7);
|
||||
nextSaturday.setUTCDate(nextSaturday.getDate() + 7);
|
||||
timeUntilReset = nextSaturday.getTime() - now.getTime();
|
||||
}
|
||||
|
||||
@ -2067,8 +2107,58 @@ class QuestSystem {
|
||||
return completed.sort((a, b) => (b.completedAt || 0) - (a.completedAt || 0));
|
||||
}
|
||||
|
||||
// Load quests from server data
|
||||
loadServerQuests(serverQuestData) {
|
||||
console.log('[QUEST SYSTEM] Loading server quest data:', serverQuestData);
|
||||
|
||||
if (!serverQuestData) {
|
||||
console.log('[QUEST SYSTEM] No server quest data provided');
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear existing quests
|
||||
this.mainQuests = [];
|
||||
this.dailyQuests = [];
|
||||
this.weeklyQuests = [];
|
||||
this.activeQuests = [];
|
||||
this.completedQuests = [];
|
||||
|
||||
// Load quests from server data
|
||||
if (serverQuestData.mainQuests && Array.isArray(serverQuestData.mainQuests)) {
|
||||
this.mainQuests = serverQuestData.mainQuests;
|
||||
console.log('[QUEST SYSTEM] Loaded', this.mainQuests.length, 'main quests');
|
||||
}
|
||||
|
||||
if (serverQuestData.dailyQuests && Array.isArray(serverQuestData.dailyQuests)) {
|
||||
this.dailyQuests = serverQuestData.dailyQuests;
|
||||
console.log('[QUEST SYSTEM] Loaded', this.dailyQuests.length, 'daily quests');
|
||||
}
|
||||
|
||||
if (serverQuestData.activeQuests && Array.isArray(serverQuestData.activeQuests)) {
|
||||
this.activeQuests = serverQuestData.activeQuests;
|
||||
console.log('[QUEST SYSTEM] Loaded', this.activeQuests.length, 'active quests');
|
||||
}
|
||||
|
||||
if (serverQuestData.completedQuests && Array.isArray(serverQuestData.completedQuests)) {
|
||||
this.completedQuests = serverQuestData.completedQuests;
|
||||
console.log('[QUEST SYSTEM] Loaded', this.completedQuests.length, 'completed quests');
|
||||
}
|
||||
|
||||
console.log('[QUEST SYSTEM] Server quest data loaded successfully');
|
||||
console.log('[QUEST SYSTEM] Total quests loaded:', {
|
||||
main: this.mainQuests.length,
|
||||
daily: this.dailyQuests.length,
|
||||
active: this.activeQuests.length,
|
||||
completed: this.completedQuests.length
|
||||
});
|
||||
}
|
||||
|
||||
// UI updates
|
||||
updateUI() {
|
||||
console.log('[QUEST SYSTEM] updateUI called');
|
||||
console.log('[QUEST SYSTEM] Game available:', !!this.game);
|
||||
console.log('[QUEST SYSTEM] Multiplayer mode:', window.smartSaveManager?.isMultiplayer);
|
||||
|
||||
this.updateQuestList();
|
||||
this.updateQuestStats();
|
||||
}
|
||||
@ -2086,6 +2176,7 @@ class QuestSystem {
|
||||
|
||||
const quests = this.getQuestsByType(activeType);
|
||||
console.log(`[QUEST SYSTEM] Getting quests for type: ${activeType}, found: ${quests.length} quests`);
|
||||
console.log('[QUEST SYSTEM] First few quests:', quests.slice(0, 3));
|
||||
|
||||
questListElement.innerHTML = '';
|
||||
|
||||
@ -2273,7 +2364,10 @@ class QuestSystem {
|
||||
break;
|
||||
}
|
||||
|
||||
player.updateUI();
|
||||
// Only update player UI if in multiplayer mode or game is actively running
|
||||
if (this.game.shouldUpdateGUI()) {
|
||||
player.updateUI();
|
||||
}
|
||||
}
|
||||
|
||||
// Retry failed quest
|
||||
|
||||
@ -304,8 +304,12 @@ return true;
|
||||
player.stats.skillPoints--;
|
||||
this.levelUpSkill(category, skillId);
|
||||
|
||||
// Update UI to refresh skill points display
|
||||
this.updateUI();
|
||||
// Update UI to refresh skill points display only if in multiplayer mode or game is actively running
|
||||
const shouldUpdateUI = window.smartSaveManager?.isMultiplayer || this.game?.isRunning;
|
||||
|
||||
if (shouldUpdateUI) {
|
||||
this.updateUI();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -341,8 +345,12 @@ return true;
|
||||
|
||||
this.applySkillEffects();
|
||||
|
||||
// Update UI to refresh skill points display
|
||||
this.updateUI();
|
||||
// Update UI to refresh skill points display only if in multiplayer mode or game is actively running
|
||||
const shouldUpdateUI = window.smartSaveManager?.isMultiplayer || this.game?.isRunning;
|
||||
|
||||
if (shouldUpdateUI) {
|
||||
this.updateUI();
|
||||
}
|
||||
|
||||
this.game.showNotification(`${skill.name} unlocked!`, 'success', 4000);
|
||||
return true;
|
||||
|
||||
@ -37,8 +37,16 @@ class LiveMainMenu {
|
||||
// Check for existing auth token
|
||||
this.checkExistingAuth();
|
||||
|
||||
// Check for local server and update URLs if needed
|
||||
this.checkForLocalServer();
|
||||
// DISABLE local server check - always use remote multiplayer server
|
||||
// this.checkForLocalServer();
|
||||
console.log('[LIVE MAIN MENU] Local server check disabled - using remote multiplayer server only');
|
||||
console.log('[LIVE MAIN MENU] Using remote API:', this.apiBaseUrl);
|
||||
console.log('[LIVE MAIN MENU] Using remote game server:', this.gameServerUrl);
|
||||
|
||||
// Initialize SmartSaveManager to singleplayer mode by default
|
||||
if (window.smartSaveManager) {
|
||||
window.smartSaveManager.setMultiplayerMode(false);
|
||||
}
|
||||
|
||||
console.log('[LIVE MAIN MENU] Constructor completed');
|
||||
}
|
||||
@ -435,6 +443,9 @@ class LiveMainMenu {
|
||||
}
|
||||
|
||||
async refreshServerList() {
|
||||
// Build server list with local server, dev server, and API servers
|
||||
const servers = [];
|
||||
|
||||
if (!this.authToken) {
|
||||
console.error('[LIVE MAIN MENU] No auth token for server list');
|
||||
return;
|
||||
@ -447,9 +458,6 @@ class LiveMainMenu {
|
||||
try {
|
||||
let response;
|
||||
|
||||
// Build server list with local server, dev server, and API servers
|
||||
const servers = [];
|
||||
|
||||
// Add local server if available
|
||||
if (this.isLocalMode && window.localServerManager && window.localServerManager.localServer && window.localServerManager.localServer.mockRequest) {
|
||||
console.log('[LIVE MAIN MENU] Using SimpleLocalServer mock API for local server');
|
||||
@ -459,32 +467,8 @@ class LiveMainMenu {
|
||||
}
|
||||
}
|
||||
|
||||
// Add dev game server
|
||||
try {
|
||||
const devServerResponse = await fetch('http://localhost:3002/health');
|
||||
if (devServerResponse.ok) {
|
||||
const devServerInfo = await devServerResponse.json();
|
||||
servers.push({
|
||||
id: 'dev-game-server',
|
||||
name: 'Dev Game Server',
|
||||
description: 'Development game server for testing',
|
||||
type: 'development',
|
||||
region: 'local',
|
||||
maxPlayers: 8,
|
||||
currentPlayers: 0,
|
||||
owner: 'Developer',
|
||||
address: 'localhost',
|
||||
port: 3002,
|
||||
status: 'online',
|
||||
createdAt: new Date().toISOString(),
|
||||
ping: 0,
|
||||
isLocal: true,
|
||||
isDev: true
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('[LIVE MAIN MENU] Dev game server not available:', error.message);
|
||||
}
|
||||
// Skip local dev server check to avoid blocking
|
||||
console.log('[LIVE MAIN MENU] Skipping local dev server check to avoid blocking');
|
||||
|
||||
// Add API servers
|
||||
console.log('[LIVE MAIN MENU] Fetching server list from:', `${this.apiBaseUrl}/servers`);
|
||||
@ -495,37 +479,35 @@ class LiveMainMenu {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
if (apiResponse.ok) {
|
||||
const apiData = await apiResponse.json();
|
||||
if (apiData.success && apiData.servers) {
|
||||
servers.push(...apiData.servers);
|
||||
console.log(`[LIVE MAIN MENU] Server list loaded: ${servers.length} servers found`);
|
||||
|
||||
// Debug: Log server list data
|
||||
console.log('[LIVE MAIN MENU] Server list loaded:', servers);
|
||||
if (servers.length > 0) {
|
||||
console.log('[LIVE MAIN MENU] First server details:', servers[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.servers = servers;
|
||||
|
||||
console.log('[LIVE MAIN MENU] Server list loaded:', servers.length, 'servers found');
|
||||
|
||||
// Display servers
|
||||
this.renderServerList();
|
||||
|
||||
} catch (error) {
|
||||
console.error('[LIVE MAIN MENU] Server list error:', error);
|
||||
this.servers = [];
|
||||
this.renderServerList();
|
||||
|
||||
// Show error message to user
|
||||
this.showLoginNotice(`Network error: ${error.message}`, 'error');
|
||||
console.error('[LIVE MAIN MENU] Error fetching server list:', error);
|
||||
this.showLoginNotice('Connection error. Please try again.', 'error');
|
||||
} finally {
|
||||
// Hide loading state
|
||||
if (this.serverLoading) this.serverLoading.classList.add('hidden');
|
||||
}
|
||||
|
||||
// Store servers
|
||||
this.servers = servers;
|
||||
|
||||
// Render server list
|
||||
this.renderServerList();
|
||||
}
|
||||
|
||||
renderServerList() {
|
||||
if (!this.servers) return;
|
||||
|
||||
const filteredServers = this.getFilteredServers();
|
||||
|
||||
// Handle empty state
|
||||
@ -553,6 +535,22 @@ class LiveMainMenu {
|
||||
this.updateServerItemsSmoothly(currentItems, newItems);
|
||||
}
|
||||
|
||||
removeServerItemsSmoothly() {
|
||||
const existingItems = this.serverList?.querySelectorAll('.server-item') || [];
|
||||
|
||||
if (existingItems.length === 0) return;
|
||||
|
||||
// Add fade-out transition
|
||||
existingItems.forEach(item => {
|
||||
item.style.transition = 'opacity 0.2s ease-out';
|
||||
item.style.opacity = '0';
|
||||
});
|
||||
|
||||
// Remove items after fade out
|
||||
setTimeout(() => {
|
||||
existingItems.forEach(item => item.remove());
|
||||
}, 200);
|
||||
}
|
||||
removeServerItemsSmoothly() {
|
||||
const existingItems = this.serverList?.querySelectorAll('.server-item') || [];
|
||||
|
||||
@ -1026,6 +1024,13 @@ Status: ${this.selectedServer.status}
|
||||
|
||||
launchMultiplayerGame(server, serverData) {
|
||||
console.log('[LIVE MAIN MENU] Launching multiplayer game on server:', server.name);
|
||||
|
||||
// Set SmartSaveManager to multiplayer mode
|
||||
if (window.smartSaveManager && window.gameInitializer) {
|
||||
window.smartSaveManager.setMultiplayerMode(true, window.gameInitializer);
|
||||
console.log('[LIVE MAIN MENU] SmartSaveManager set to multiplayer mode');
|
||||
}
|
||||
|
||||
// Hide main menu and start game in multiplayer mode
|
||||
this.hideLoadingScreenAndShowGame();
|
||||
this.initializeMultiplayerGame(server, serverData);
|
||||
@ -1051,278 +1056,88 @@ Status: ${this.selectedServer.status}
|
||||
initializeMultiplayerGame(server, serverData) {
|
||||
console.log('[LIVE MAIN MENU] Initializing multiplayer game');
|
||||
|
||||
// Check if GameEngine is available, if not create a basic fallback
|
||||
if (typeof GameEngine === 'undefined') {
|
||||
console.warn('[LIVE MAIN MENU] GameEngine class not available, creating fallback');
|
||||
|
||||
// Create a basic fallback GameEngine class
|
||||
window.GameEngine = class GameEngine extends EventTarget {
|
||||
constructor() {
|
||||
super();
|
||||
this.systems = {};
|
||||
this.gameTime = 0;
|
||||
this.isRunning = false;
|
||||
this.isFallback = true; // Mark as fallback for UIManager
|
||||
console.log('[LIVE MAIN MENU] Fallback GameEngine created');
|
||||
}
|
||||
|
||||
async init() {
|
||||
console.log('[LIVE MAIN MENU] Fallback GameEngine init() called');
|
||||
return true;
|
||||
}
|
||||
|
||||
setMultiplayerMode(isMultiplayer, socket, serverData, currentUser) {
|
||||
console.log('[LIVE MAIN MENU] Fallback GameEngine setMultiplayerMode called');
|
||||
this.isMultiplayer = isMultiplayer;
|
||||
this.socket = socket;
|
||||
this.serverData = serverData;
|
||||
this.currentUser = currentUser;
|
||||
}
|
||||
|
||||
startGame(continueGame) {
|
||||
console.log('[LIVE MAIN MENU] Fallback GameEngine startGame called, continueGame:', continueGame);
|
||||
this.isRunning = true;
|
||||
|
||||
// Add simple return to menu functionality
|
||||
window.returnToMainMenu = () => {
|
||||
console.log('[LIVE MAIN MENU] Return to main menu requested');
|
||||
if (window.liveMainMenu) {
|
||||
window.liveMainMenu.showLoginSection();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
getPerformanceStats() {
|
||||
console.log('[LIVE MAIN MENU] Fallback GameEngine getPerformanceStats called');
|
||||
return {
|
||||
gameTime: this.gameTime,
|
||||
isRunning: this.isRunning,
|
||||
fps: 60,
|
||||
memory: 'N/A (fallback mode)'
|
||||
};
|
||||
}
|
||||
|
||||
showNotification(message, type = 'info', duration = 3000) {
|
||||
console.log(`[LIVE MAIN MENU] Fallback notification: ${message} (${type})`);
|
||||
// Simple console notification for fallback mode
|
||||
if (typeof console !== 'undefined') {
|
||||
console.log(`📢 ${type.toUpperCase()}: ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
save() {
|
||||
console.log('[LIVE MAIN MENU] Fallback GameEngine save called');
|
||||
// Save will be handled by the main save logic when it detects local mode
|
||||
return Promise.resolve({ success: true });
|
||||
}
|
||||
};
|
||||
// DELAY GameEngine creation until after multiplayer connection is ready
|
||||
// First, set up GameInitializer and socket connection
|
||||
if (!window.gameInitializer) {
|
||||
console.log('[LIVE MAIN MENU] Creating new GameInitializer for multiplayer');
|
||||
window.gameInitializer = new GameInitializer();
|
||||
}
|
||||
|
||||
// Create GameEngine if it doesn't exist
|
||||
if (!window.game) {
|
||||
console.log('[LIVE MAIN MENU] Creating new GameEngine instance for multiplayer');
|
||||
try {
|
||||
window.game = new GameEngine();
|
||||
|
||||
// Initialize the game engine
|
||||
window.game.init().then(() => {
|
||||
console.log('[LIVE MAIN MENU] GameEngine initialized successfully for multiplayer');
|
||||
|
||||
// Apply pending save data if available (after GameEngine is ready)
|
||||
if (window.liveMainMenu && window.liveMainMenu.pendingSaveData) {
|
||||
console.log('[LIVE MAIN MENU] Applying pending save data after GameEngine init...');
|
||||
|
||||
try {
|
||||
const saveData = window.liveMainMenu.pendingSaveData;
|
||||
console.log('[LIVE MAIN MENU] Save data structure:', {
|
||||
hasPlayer: !!saveData.player,
|
||||
hasInventory: !!saveData.inventory,
|
||||
hasEconomy: !!saveData.economy,
|
||||
hasIdleSystem: !!saveData.idleSystem,
|
||||
hasDungeonSystem: !!saveData.dungeonSystem,
|
||||
hasSkillSystem: !!saveData.skillSystem,
|
||||
hasBaseSystem: !!saveData.baseSystem,
|
||||
hasQuestSystem: !!saveData.questSystem,
|
||||
gameTime: saveData.gameTime,
|
||||
playerLevel: saveData.player?.stats?.level
|
||||
});
|
||||
|
||||
console.log('[LIVE MAIN MENU] Game systems available:', {
|
||||
hasGame: !!window.game,
|
||||
hasSystems: !!window.game?.systems,
|
||||
hasPlayer: !!window.game?.systems?.player,
|
||||
hasInventory: !!window.game?.systems?.inventory,
|
||||
hasEconomy: !!window.game?.systems?.economy,
|
||||
hasIdleSystem: !!window.game?.systems?.idleSystem,
|
||||
hasDungeonSystem: !!window.game?.systems?.dungeonSystem,
|
||||
hasSkillSystem: !!window.game?.systems?.skillSystem,
|
||||
hasBaseSystem: !!window.game?.systems?.baseSystem,
|
||||
hasQuestSystem: !!window.game?.systems?.questSystem
|
||||
});
|
||||
|
||||
let appliedCount = 0;
|
||||
|
||||
// Apply save data to game systems
|
||||
if (saveData.player && window.game.systems.player) {
|
||||
window.game.systems.player.load(saveData.player);
|
||||
console.log('[LIVE MAIN MENU] ✅ Player data loaded from pending save');
|
||||
appliedCount++;
|
||||
} else {
|
||||
console.log('[LIVE MAIN MENU] ❌ Player data NOT loaded - saveData.player:', !!saveData.player, 'window.game.systems.player:', !!window.game?.systems?.player);
|
||||
}
|
||||
|
||||
if (saveData.inventory && window.game.systems.inventory) {
|
||||
window.game.systems.inventory.load(saveData.inventory);
|
||||
console.log('[LIVE MAIN MENU] ✅ Inventory data loaded from pending save');
|
||||
appliedCount++;
|
||||
} else {
|
||||
console.log('[LIVE MAIN MENU] ❌ Inventory data NOT loaded - saveData.inventory:', !!saveData.inventory, 'window.game.systems.inventory:', !!window.game?.systems?.inventory);
|
||||
}
|
||||
|
||||
if (saveData.economy && window.game.systems.economy) {
|
||||
window.game.systems.economy.load(saveData.economy);
|
||||
console.log('[LIVE MAIN MENU] ✅ Economy data loaded from pending save');
|
||||
appliedCount++;
|
||||
} else {
|
||||
console.log('[LIVE MAIN MENU] ❌ Economy data NOT loaded - saveData.economy:', !!saveData.economy, 'window.game.systems.economy:', !!window.game?.systems?.economy);
|
||||
}
|
||||
|
||||
if (saveData.idleSystem && window.game.systems.idleSystem) {
|
||||
window.game.systems.idleSystem.load(saveData.idleSystem);
|
||||
console.log('[LIVE MAIN MENU] ✅ Idle system data loaded from pending save');
|
||||
appliedCount++;
|
||||
} else {
|
||||
console.log('[LIVE MAIN MENU] ❌ Idle system data NOT loaded - saveData.idleSystem:', !!saveData.idleSystem, 'window.game.systems.idleSystem:', !!window.game?.systems?.idleSystem);
|
||||
}
|
||||
|
||||
if (saveData.dungeonSystem && window.game.systems.dungeonSystem) {
|
||||
window.game.systems.dungeonSystem.load(saveData.dungeonSystem);
|
||||
console.log('[LIVE MAIN MENU] ✅ Dungeon system data loaded from pending save');
|
||||
appliedCount++;
|
||||
} else {
|
||||
console.log('[LIVE MAIN MENU] ❌ Dungeon system data NOT loaded - saveData.dungeonSystem:', !!saveData.dungeonSystem, 'window.game.systems.dungeonSystem:', !!window.game?.systems?.dungeonSystem);
|
||||
}
|
||||
|
||||
if (saveData.skillSystem && window.game.systems.skillSystem) {
|
||||
window.game.systems.skillSystem.load(saveData.skillSystem);
|
||||
console.log('[LIVE MAIN MENU] ✅ Skill system data loaded from pending save');
|
||||
appliedCount++;
|
||||
} else {
|
||||
console.log('[LIVE MAIN MENU] ❌ Skill system data NOT loaded - saveData.skillSystem:', !!saveData.skillSystem, 'window.game.systems.skillSystem:', !!window.game?.systems?.skillSystem);
|
||||
}
|
||||
|
||||
if (saveData.baseSystem && window.game.systems.baseSystem) {
|
||||
window.game.systems.baseSystem.load(saveData.baseSystem);
|
||||
console.log('[LIVE MAIN MENU] ✅ Base system data loaded from pending save');
|
||||
appliedCount++;
|
||||
} else {
|
||||
console.log('[LIVE MAIN MENU] ❌ Base system data NOT loaded - saveData.baseSystem:', !!saveData.baseSystem, 'window.game.systems.baseSystem:', !!window.game?.systems?.baseSystem);
|
||||
}
|
||||
|
||||
if (saveData.questSystem && window.game.systems.questSystem) {
|
||||
window.game.systems.questSystem.load(saveData.questSystem);
|
||||
console.log('[LIVE MAIN MENU] ✅ Quest system data loaded from pending save');
|
||||
appliedCount++;
|
||||
} else {
|
||||
console.log('[LIVE MAIN MENU] ❌ Quest system data NOT loaded - saveData.questSystem:', !!saveData.questSystem, 'window.game.systems.questSystem:', !!window.game?.systems?.questSystem);
|
||||
}
|
||||
|
||||
if (saveData.gameTime && window.game) {
|
||||
window.game.gameTime = saveData.gameTime;
|
||||
console.log('[LIVE MAIN MENU] ✅ Game time loaded from pending save:', saveData.gameTime);
|
||||
appliedCount++;
|
||||
} else {
|
||||
console.log('[LIVE MAIN MENU] ❌ Game time NOT loaded - saveData.gameTime:', !!saveData.gameTime, 'window.game:', !!window.game);
|
||||
}
|
||||
|
||||
console.log(`[LIVE MAIN MENU] Save data application complete: ${appliedCount}/9 systems loaded`);
|
||||
|
||||
if (appliedCount === 0) {
|
||||
console.warn('[LIVE MAIN MENU] ⚠️ NO save data was applied! This is why the UI shows fresh game state.');
|
||||
console.warn('[LIVE MAIN MENU] ⚠️ The fallback GameEngine does not have the required game systems.');
|
||||
}
|
||||
|
||||
console.log('[LIVE MAIN MENU] Pending save data applied successfully');
|
||||
|
||||
// Clear pending save data
|
||||
window.liveMainMenu.pendingSaveData = null;
|
||||
|
||||
} catch (error) {
|
||||
console.error('[LIVE MAIN MENU] Error applying pending save data:', error);
|
||||
}
|
||||
} else {
|
||||
console.log('[LIVE MAIN MENU] No pending save data to apply');
|
||||
}
|
||||
|
||||
// Now initialize multiplayer mode through GameInitializer
|
||||
if (window.gameInitializer) {
|
||||
// Determine the correct game server URL based on server type
|
||||
let gameServerUrl = this.gameServerUrl; // Default to dev server
|
||||
|
||||
if (server.isLocal) {
|
||||
gameServerUrl = this.localGameServerUrl;
|
||||
} else if (server.isDev) {
|
||||
gameServerUrl = this.gameServerUrl;
|
||||
} else {
|
||||
// Use server address and port for remote servers
|
||||
gameServerUrl = `http://${server.address}:${server.port}`;
|
||||
}
|
||||
|
||||
console.log('[LIVE MAIN MENU] Using game server URL:', gameServerUrl);
|
||||
window.gameInitializer.updateServerUrls(this.apiBaseUrl, gameServerUrl);
|
||||
window.gameInitializer.initializeMultiplayer(server, serverData, this.authToken, this.currentUser);
|
||||
}
|
||||
}).catch(error => {
|
||||
console.error('[LIVE MAIN MENU] Failed to initialize GameEngine for multiplayer:', error);
|
||||
this.showLoginNotice('Failed to initialize game: ' + error.message, 'error');
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('[LIVE MAIN MENU] Error creating GameEngine:', error);
|
||||
this.showLoginNotice('Failed to create game engine: ' + error.message, 'error');
|
||||
// Set up server URLs and connection first
|
||||
window.gameInitializer.updateServerUrls(
|
||||
'https://api.korvarix.com/api',
|
||||
server.url || 'https://dev.gameserver.galaxystrike.online'
|
||||
);
|
||||
|
||||
// Initialize multiplayer mode (this will handle GameEngine creation after authentication)
|
||||
window.gameInitializer.initializeMultiplayer(server, serverData, this.authToken, this.currentUser);
|
||||
|
||||
// Add simple return to menu functionality
|
||||
window.returnToMainMenu = () => {
|
||||
console.log('[LIVE MAIN MENU] Return to main menu requested');
|
||||
if (window.liveMainMenu) {
|
||||
window.liveMainMenu.showLoginSection();
|
||||
}
|
||||
} else {
|
||||
console.log('[LIVE MAIN MENU] GameEngine already exists, initializing multiplayer mode');
|
||||
};
|
||||
}
|
||||
|
||||
checkForLocalServer() {
|
||||
console.log('[LIVE MAIN MENU] Checking for local server...');
|
||||
|
||||
// Check if local server manager is available and running
|
||||
if (window.localServerManager) {
|
||||
const serverStatus = window.localServerManager.getStatus();
|
||||
|
||||
// Initialize multiplayer mode through GameInitializer
|
||||
if (window.gameInitializer) {
|
||||
// Determine the correct game server URL based on server type
|
||||
let gameServerUrl = this.gameServerUrl; // Default to dev server
|
||||
if (serverStatus.isRunning) {
|
||||
console.log('[LIVE MAIN MENU] Local server detected, switching to local mode');
|
||||
this.isLocalMode = true;
|
||||
this.apiBaseUrl = `http://localhost:${serverStatus.port}/api`;
|
||||
this.gameServerUrl = `http://localhost:${serverStatus.port}`;
|
||||
|
||||
if (server.isLocal) {
|
||||
gameServerUrl = this.localGameServerUrl;
|
||||
} else if (server.isDev) {
|
||||
gameServerUrl = this.gameServerUrl;
|
||||
} else {
|
||||
// Use server address and port for remote servers
|
||||
gameServerUrl = `http://${server.address}:${server.port}`;
|
||||
console.log(`[LIVE MAIN MENU] Updated API URL to: ${this.apiBaseUrl}`);
|
||||
|
||||
// Update button to show local mode
|
||||
if (this.createServerBtn) {
|
||||
this.createServerBtn.innerHTML = '<i class="fas fa-check"></i> Local Server Running';
|
||||
this.createServerBtn.classList.remove('btn-primary');
|
||||
this.createServerBtn.classList.add('btn-success');
|
||||
}
|
||||
|
||||
console.log('[LIVE MAIN MENU] Using game server URL:', gameServerUrl);
|
||||
window.gameInitializer.updateServerUrls(this.apiBaseUrl, gameServerUrl);
|
||||
window.gameInitializer.initializeMultiplayer(server, serverData, this.authToken, this.currentUser);
|
||||
// Auto-login for local mode
|
||||
this.autoLoginLocalMode();
|
||||
|
||||
} else {
|
||||
console.log('[LIVE MAIN MENU] No local server running');
|
||||
}
|
||||
} else {
|
||||
console.log('[LIVE MAIN MENU] Local server manager not available');
|
||||
}
|
||||
}
|
||||
|
||||
async startLocalServer() {
|
||||
console.log('[LIVE MAIN MENU] Starting local server...');
|
||||
|
||||
// Disable button to prevent multiple clicks
|
||||
if (this.createServerBtn) {
|
||||
this.createServerBtn.disabled = true;
|
||||
this.createServerBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Starting...';
|
||||
}
|
||||
|
||||
try {
|
||||
// Check if LocalServerManager is available
|
||||
if (!window.localServerManager) {
|
||||
console.error('[LIVE MAIN MENU] LocalServerManager not available');
|
||||
this.showLoginNotice('Local server manager not available', 'error');
|
||||
|
||||
// Reset button
|
||||
if (this.createServerBtn) {
|
||||
this.createServerBtn.disabled = false;
|
||||
this.createServerBtn.innerHTML = '<i class="fas fa-server"></i> Start Local Server';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Update button to show loading state
|
||||
if (this.createServerBtn) {
|
||||
this.createServerBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Starting...';
|
||||
this.createServerBtn.disabled = true;
|
||||
}
|
||||
|
||||
// Show loading message
|
||||
this.showLoginNotice('Starting local server...', 'info');
|
||||
|
||||
// Start the local server
|
||||
const result = await window.localServerManager.startServer();
|
||||
|
||||
if (result.success) {
|
||||
@ -1370,117 +1185,16 @@ Status: ${this.selectedServer.status}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkForLocalServer() {
|
||||
console.log('[LIVE MAIN MENU] Checking for local server...');
|
||||
|
||||
// Check if local server manager is available and running
|
||||
if (window.localServerManager) {
|
||||
const serverStatus = window.localServerManager.getStatus();
|
||||
|
||||
if (serverStatus.isRunning) {
|
||||
console.log('[LIVE MAIN MENU] Local server detected, switching to local mode');
|
||||
this.isLocalMode = true;
|
||||
this.apiBaseUrl = `http://localhost:${serverStatus.port}/api`;
|
||||
this.gameServerUrl = `http://localhost:${serverStatus.port}`;
|
||||
|
||||
console.log(`[LIVE MAIN MENU] Updated API URL to: ${this.apiBaseUrl}`);
|
||||
console.log(`[LIVE MAIN MENU] Updated Game Server URL to: ${this.gameServerUrl}`);
|
||||
|
||||
// Update login notice to show local mode
|
||||
this.showLoginNotice('Local server active - Singleplayer mode available', 'info');
|
||||
|
||||
// Auto-login for local mode
|
||||
this.autoLoginLocalMode();
|
||||
} else {
|
||||
console.log('[LIVE MAIN MENU] Local server not running, using remote servers');
|
||||
}
|
||||
} else {
|
||||
console.log('[LIVE MAIN MENU] LocalServerManager not available');
|
||||
}
|
||||
}
|
||||
|
||||
async autoLoginLocalMode() {
|
||||
console.log('[LIVE MAIN MENU] Auto-logging in to local mode...');
|
||||
|
||||
try {
|
||||
let response;
|
||||
|
||||
// Use SimpleLocalServer mock API if available
|
||||
if (window.localServerManager && window.localServerManager.localServer && window.localServerManager.localServer.mockRequest) {
|
||||
console.log('[LIVE MAIN MENU] Using SimpleLocalServer mock API');
|
||||
response = await window.localServerManager.localServer.mockRequest('POST', '/api/auth/login', {
|
||||
email: 'local@player.com',
|
||||
password: 'local'
|
||||
});
|
||||
} else {
|
||||
// Fallback to real fetch
|
||||
console.log('[LIVE MAIN MENU] Using real fetch for local login');
|
||||
response = await fetch(`${this.apiBaseUrl}/auth/login`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
email: 'local@player.com',
|
||||
password: 'local'
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
console.log('[LIVE MAIN MENU] Local mode login successful');
|
||||
this.authToken = data.token;
|
||||
this.currentUser = data.user;
|
||||
|
||||
// Update UI
|
||||
this.hideLoginNotice();
|
||||
this.showServerSection(false, false); // Show section without refreshing or animating
|
||||
|
||||
// Load servers (will show local server)
|
||||
this.refreshServerList();
|
||||
} else {
|
||||
console.error('[LIVE MAIN MENU] Local mode login failed:', data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[LIVE MAIN MENU] Error in local mode auto-login:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the live main menu when DOM is ready
|
||||
function initializeLiveMainMenu() {
|
||||
console.log('[LIVE MAIN MENU] Initializing LiveMainMenu...');
|
||||
|
||||
// Wait a bit for DOM to be fully ready
|
||||
setTimeout(() => {
|
||||
if (!window.liveMainMenu) {
|
||||
console.log('[LIVE MAIN MENU] Creating new LiveMainMenu instance');
|
||||
window.liveMainMenu = new LiveMainMenu();
|
||||
} else {
|
||||
console.log('[LIVE MAIN MENU] LiveMainMenu already exists');
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
// End of LiveMainMenu class
|
||||
|
||||
// Try multiple initialization methods
|
||||
if (document.readyState === 'loading') {
|
||||
// DOM is still loading, wait for DOMContentLoaded
|
||||
document.addEventListener('DOMContentLoaded', initializeLiveMainMenu);
|
||||
} else {
|
||||
// DOM is already ready, initialize immediately
|
||||
initializeLiveMainMenu();
|
||||
}
|
||||
|
||||
// Also try initialization as a fallback
|
||||
setTimeout(() => {
|
||||
if (!window.liveMainMenu) {
|
||||
console.warn('[LIVE MAIN MENU] Fallback initialization triggered');
|
||||
// Initialize LiveMainMenu when DOM is ready
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
if (typeof window !== 'undefined') {
|
||||
window.liveMainMenu = new LiveMainMenu();
|
||||
}
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
// Export for use in other scripts
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
|
||||
@ -43,16 +43,19 @@ class UIManager {
|
||||
const gameInterface = document.getElementById('gameInterface');
|
||||
const navButtons = document.querySelectorAll('.nav-btn');
|
||||
|
||||
if (debugLogger) debugLogger.logStep('DOM Check', {
|
||||
console.log('[UI MANAGER] DOM Check:', {
|
||||
gameInterfaceExists: !!gameInterface,
|
||||
gameInterfaceHidden: gameInterface?.classList.contains('hidden'),
|
||||
navButtonsFound: navButtons.length,
|
||||
documentReady: document.readyState
|
||||
});
|
||||
|
||||
if (gameInterface && !gameInterface.classList.contains('hidden') && navButtons.length > 0) {
|
||||
// Less strict condition - proceed if we have nav buttons, even if interface is still hidden
|
||||
if (navButtons.length > 0) {
|
||||
console.log('[UI MANAGER] Navigation buttons found, proceeding with initialization');
|
||||
this.proceedWithInitialization();
|
||||
} else {
|
||||
console.log('[UI MANAGER] Waiting for navigation buttons...');
|
||||
setTimeout(waitForDOM, 100);
|
||||
}
|
||||
};
|
||||
@ -117,10 +120,6 @@ class UIManager {
|
||||
});
|
||||
|
||||
if (debugLogger) debugLogger.endStep('UIManager.setupNavigation', {
|
||||
navButtonsSetup: navButtons.length,
|
||||
skillCatButtonsSetup: skillCatButtons.length,
|
||||
shopCatButtonsSetup: shopCatButtons.length,
|
||||
questTabButtonsSetup: questTabButtons.length,
|
||||
craftingCatButtonsSetup: craftingCatButtons.length
|
||||
});
|
||||
}
|
||||
@ -140,10 +139,11 @@ class UIManager {
|
||||
if (navButtons.length === 0) {
|
||||
console.warn('[UIManager] No navigation buttons found!');
|
||||
if (debugLogger) debugLogger.logStep('No navigation buttons found');
|
||||
return;
|
||||
}
|
||||
|
||||
navButtons.forEach((btn, index) => {
|
||||
console.log(`[UIManager] Setting up button ${index}:`, btn.dataset.tab);
|
||||
console.log(`[UIManager] Setting up button ${index}:`, btn.dataset.tab, btn);
|
||||
// Check if button already has a listener to prevent duplicates
|
||||
if (btn.getAttribute('data-has-listener') === 'true') {
|
||||
console.log(`[UIManager] Button ${btn.dataset.tab} already has listener, skipping`);
|
||||
@ -151,16 +151,30 @@ class UIManager {
|
||||
}
|
||||
|
||||
btn.addEventListener('click', (e) => {
|
||||
console.log(`[UIManager] Navigation button clicked: ${btn.dataset.tab}`);
|
||||
console.log(`[UIManager] Navigation button clicked: ${btn.dataset.tab}`, e);
|
||||
const tab = btn.dataset.tab;
|
||||
if (tab) {
|
||||
this.switchTab(tab);
|
||||
} else {
|
||||
console.warn('[UIManager] Button clicked but no tab data found');
|
||||
}
|
||||
});
|
||||
|
||||
// Mark button as having a listener
|
||||
// Mark as having listener
|
||||
btn.setAttribute('data-has-listener', 'true');
|
||||
console.log(`[UIManager] Button ${btn.dataset.tab} setup complete`);
|
||||
console.log(`[UIManager] Event listener added to button: ${btn.dataset.tab}`);
|
||||
});
|
||||
|
||||
// Add a global fallback click handler for navigation buttons
|
||||
document.addEventListener('click', (e) => {
|
||||
if (e.target.classList.contains('nav-btn') || e.target.closest('.nav-btn')) {
|
||||
const button = e.target.classList.contains('nav-btn') ? e.target : e.target.closest('.nav-btn');
|
||||
const tab = button.dataset.tab;
|
||||
if (tab && window.game && window.game.systems && window.game.systems.ui) {
|
||||
console.log('[UI MANAGER] Global fallback: Navigation button clicked:', tab);
|
||||
window.game.systems.ui.switchTab(tab);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Set up UI update event listener from GameEngine
|
||||
@ -284,7 +298,7 @@ class UIManager {
|
||||
// if (debugLogger) debugLogger.logStep('Setting up return to menu button');
|
||||
returnToMenuBtn.addEventListener('click', () => {
|
||||
if (debugLogger) debugLogger.log('Return to menu button clicked');
|
||||
this.returnToMainMenu();
|
||||
this.showReturnToMainMenuModal();
|
||||
});
|
||||
|
||||
// Mark as having listener
|
||||
@ -697,43 +711,92 @@ class UIManager {
|
||||
}
|
||||
|
||||
showReturnToMainMenuModal() {
|
||||
const debugLogger = window.debugLogger;
|
||||
const debugLogger = window.debugLogger;
|
||||
|
||||
// Show confirmation modal instead of browser confirm dialog
|
||||
let content = '<div class="confirmation-content">';
|
||||
content += '<p>Are you sure you want to return to the main menu?</p>';
|
||||
content += '<p><strong>Warning:</strong> Any unsaved progress will be lost.</p>';
|
||||
content += '<div class="confirmation-actions">';
|
||||
// Show confirmation modal instead of browser confirm dialog
|
||||
let content = '<div class="confirmation-content">';
|
||||
content += '<p>Are you sure you want to return to the main menu?</p>';
|
||||
content += '<p><strong>Warning:</strong> Any unsaved progress will be lost.</p>';
|
||||
content += '<div class="confirmation-actions">';
|
||||
|
||||
// Check if using fallback GameEngine
|
||||
if (window.game && window.game.isFallback) {
|
||||
content += '<button class="btn btn-primary" onclick="if(window.uiManager) { window.uiManager.confirmReturnToMainMenu(); }">Return to Menu</button>';
|
||||
content += '<button class="btn btn-secondary" onclick="if(window.uiManager) { window.uiManager.closeModal(); }">Cancel</button>';
|
||||
} else {
|
||||
content += '<button class="btn btn-primary" onclick="if(window.game && window.game.systems && window.game.systems.ui) { window.game.systems.ui.confirmReturnToMainMenu(); }">Return to Menu</button>';
|
||||
content += '<button class="btn btn-secondary" onclick="if(window.game && window.game.systems && window.game.systems.ui) { window.game.systems.ui.closeModal(); }">Cancel</button>';
|
||||
// Check if using fallback GameEngine
|
||||
if (window.game && window.game.isFallback) {
|
||||
content += '<button class="btn btn-primary" onclick="if(window.uiManager) { window.uiManager.confirmReturnToMainMenu(); }">Return to Menu</button>';
|
||||
content += '<button class="btn btn-secondary" onclick="if(window.uiManager) { window.uiManager.closeModal(); }">Cancel</button>';
|
||||
} else {
|
||||
content += '<button class="btn btn-primary" onclick="if(window.game && window.game.systems && window.game.systems.ui) { window.game.systems.ui.confirmReturnToMainMenu(); }">Return to Menu</button>';
|
||||
content += '<button class="btn btn-secondary" onclick="if(window.game && window.game.systems && window.game.systems.ui) { window.game.systems.ui.closeModal(); }">Cancel</button>';
|
||||
}
|
||||
|
||||
content += '</div>';
|
||||
content += '</div>';
|
||||
|
||||
this.showModal('Return to Main Menu', content);
|
||||
|
||||
if (debugLogger) debugLogger.endStep('UIManager.returnToMainMenu', {
|
||||
success: true,
|
||||
confirmationShown: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
confirmReturnToMainMenu() {
|
||||
async confirmReturnToMainMenu() {
|
||||
try {
|
||||
const debugLogger = window.debugLogger;
|
||||
|
||||
if (debugLogger) debugLogger.startStep('UIManager.confirmReturnToMainMenu', {
|
||||
gameRunning: this.game ? this.game.isRunning : false
|
||||
});
|
||||
// Reset multiplayer mode when returning to main menu
|
||||
if (window.smartSaveManager) {
|
||||
window.smartSaveManager.setMultiplayerMode(false);
|
||||
}
|
||||
|
||||
// Check if we're in multiplayer mode - if so, don't save locally
|
||||
const isMultiplayer = window.smartSaveManager?.isMultiplayer;
|
||||
|
||||
// Stop the game engine and save
|
||||
if (this.game && typeof this.game.isRunning === 'boolean') {
|
||||
// Always stop the game and clear timers regardless of mode
|
||||
this.game.isRunning = false;
|
||||
|
||||
// Force save before stopping in multiplayer mode
|
||||
if (isMultiplayer && this.game && this.game.save) {
|
||||
console.log('[UI MANAGER] Force saving game before leaving multiplayer mode');
|
||||
try {
|
||||
await this.game.save();
|
||||
console.log('[UI MANAGER] Game saved successfully before leaving server');
|
||||
} catch (error) {
|
||||
console.error('[UI MANAGER] Error saving game before leaving server:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear game logic timer
|
||||
if (this.game.gameLogicTimer) {
|
||||
clearInterval(this.game.gameLogicTimer);
|
||||
this.game.gameLogicTimer = null;
|
||||
}
|
||||
|
||||
// Clear auto-save timer
|
||||
if (this.game.autoSaveTimer) {
|
||||
clearInterval(this.game.autoSaveTimer);
|
||||
this.game.autoSaveTimer = null;
|
||||
}
|
||||
|
||||
// Stop economy system timers
|
||||
if (this.game.systems.economy) {
|
||||
this.game.systems.economy.stopShopRefreshTimer();
|
||||
}
|
||||
|
||||
if (isMultiplayer) {
|
||||
console.log('[UI MANAGER] Skipping local save - returning from multiplayer mode');
|
||||
|
||||
// if (debugLogger) debugLogger.logStep('Stopping game engine and saving');
|
||||
// Show main menu immediately
|
||||
this.showMainMenu();
|
||||
this.closeModal();
|
||||
|
||||
// Handle async stop properly
|
||||
if (debugLogger) debugLogger.endStep('UIManager.confirmReturnToMainMenu', {
|
||||
success: true,
|
||||
multiplayerMode: true,
|
||||
localSaveSkipped: true,
|
||||
mainMenuShown: true
|
||||
});
|
||||
} else {
|
||||
// Handle async stop properly for singleplayer mode
|
||||
this.game.stop().then(() => {
|
||||
try {
|
||||
|
||||
@ -747,6 +810,25 @@ class UIManager {
|
||||
mainMenuShown: true
|
||||
});
|
||||
} catch (error) {
|
||||
try {
|
||||
|
||||
if (debugLogger) debugLogger.errorEvent('UIManager.confirmReturnToMainMenu', error, {
|
||||
phase: 'game_stop_and_save'
|
||||
});
|
||||
|
||||
// Still return to menu even if save fails
|
||||
this.showMainMenu();
|
||||
this.closeModal();
|
||||
|
||||
if (debugLogger) debugLogger.endStep('UIManager.confirmReturnToMainMenu', {
|
||||
success: true,
|
||||
gameStopped: true,
|
||||
saveError: true,
|
||||
mainMenuShown: true
|
||||
});
|
||||
} catch (loggerError) {
|
||||
console.error('[UI MANAGER] Debug logger error:', loggerError);
|
||||
}
|
||||
}
|
||||
}).catch(error => {
|
||||
try {
|
||||
@ -765,26 +847,36 @@ class UIManager {
|
||||
saveError: true,
|
||||
mainMenuShown: true
|
||||
});
|
||||
} catch (fallbackError) {
|
||||
} catch (loggerError) {
|
||||
console.error('[UI MANAGER] Debug logger error:', loggerError);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Always show main menu regardless of game state
|
||||
} catch (error) {
|
||||
console.error('[UI MANAGER] Error in confirmReturnToMainMenu:', error);
|
||||
if (debugLogger) debugLogger.errorEvent('UIManager.confirmReturnToMainMenu', error, {
|
||||
phase: 'main_logic'
|
||||
});
|
||||
}
|
||||
|
||||
// Always show main menu regardless of game state
|
||||
try {
|
||||
setTimeout(() => {
|
||||
this.showMainMenu();
|
||||
this.closeModal();
|
||||
}, 5000); // 5 second delay to ensure full cleanup and menu readiness
|
||||
|
||||
if (debugLogger) debugLogger.endStep('UIManager.confirmReturnToMainMenu', {
|
||||
success: true,
|
||||
gameStopped: this.game ? !this.game.isRunning : false,
|
||||
mainMenuShown: true
|
||||
});
|
||||
gameStopped: this.game ? !this.game.isRunning : false,
|
||||
mainMenuShown: true
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('[UI MANAGER] Error during return to main menu:', error);
|
||||
if (debugLogger) debugLogger.errorEvent('UIManager.confirmReturnToMainMenu', error, {
|
||||
phase: 'return_to_main_menu'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
showMainMenu() {
|
||||
const debugLogger = window.debugLogger;
|
||||
|
||||
@ -1005,8 +1097,10 @@ class UIManager {
|
||||
gameStateUpdated: true
|
||||
});
|
||||
|
||||
// Update specific tab content
|
||||
this.updateTabContent(tabName);
|
||||
// Update specific tab content only if in multiplayer mode or game is actively running
|
||||
if (this.shouldUpdateUI()) {
|
||||
this.updateTabContent(tabName);
|
||||
}
|
||||
|
||||
if (debugLogger) debugLogger.endStep('UIManager.switchTab', {
|
||||
success: true,
|
||||
@ -1019,6 +1113,10 @@ class UIManager {
|
||||
}
|
||||
|
||||
updateTabContent(tabName) {
|
||||
if (!this.shouldUpdateUI()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (debugLogger) debugLogger.startStep('UIManager.updateTabContent', {
|
||||
tabName: tabName,
|
||||
currentTab: this.currentTab
|
||||
@ -1208,8 +1306,14 @@ class UIManager {
|
||||
});
|
||||
|
||||
try {
|
||||
// Call economy system update
|
||||
this.game.systems.economy.updateUI();
|
||||
|
||||
// Also call global shop display function for additional debugging
|
||||
if (typeof updateShopDisplay === 'function') {
|
||||
updateShopDisplay();
|
||||
}
|
||||
|
||||
if (debugLogger) debugLogger.endStep('UIManager.switchShopCategory', {
|
||||
success: true,
|
||||
category: category,
|
||||
@ -1229,13 +1333,7 @@ class UIManager {
|
||||
}
|
||||
}
|
||||
|
||||
switchQuestType(type) {
|
||||
const debugLogger = window.debugLogger;
|
||||
|
||||
if (debugLogger) debugLogger.startStep('UIManager.switchQuestType', {
|
||||
type: type
|
||||
});
|
||||
|
||||
updateQuestTabs(type) {
|
||||
const questTabButtons = document.querySelectorAll('.quest-tab-btn');
|
||||
let buttonsUpdated = 0;
|
||||
|
||||
@ -1255,7 +1353,13 @@ class UIManager {
|
||||
});
|
||||
|
||||
try {
|
||||
this.game.systems.questSystem.updateUI();
|
||||
// REMOVED: Client-side QuestSystem is now server-driven
|
||||
// this.game.systems.questSystem.updateUI();
|
||||
|
||||
// Call the global quest display update function instead
|
||||
if (typeof updateQuestDisplay === 'function') {
|
||||
updateQuestDisplay();
|
||||
}
|
||||
|
||||
if (debugLogger) debugLogger.endStep('UIManager.switchQuestType', {
|
||||
success: true,
|
||||
@ -1403,7 +1507,29 @@ class UIManager {
|
||||
});
|
||||
}
|
||||
|
||||
// Handle UI update events from GameEngine
|
||||
// Force refresh all UI elements (called when server data is updated)
|
||||
forceRefreshAllUI() {
|
||||
if (window.smartSaveManager?.isMultiplayer) {
|
||||
console.log('[UI MANAGER] Force refreshing all UI elements with server data');
|
||||
|
||||
// Update all resource displays
|
||||
this.updateResourceDisplay();
|
||||
|
||||
// Update current tab content
|
||||
if (this.currentTab) {
|
||||
this.updateTabContent(this.currentTab);
|
||||
}
|
||||
|
||||
// Update quest system
|
||||
if (this.game && this.game.systems && this.game.systems.questSystem) {
|
||||
this.game.systems.questSystem.updateUI();
|
||||
}
|
||||
|
||||
console.log('[UI MANAGER] UI refresh completed');
|
||||
}
|
||||
}
|
||||
|
||||
// Handle UI update events from game engine
|
||||
handleUIUpdate(data) {
|
||||
const debugLogger = window.debugLogger;
|
||||
|
||||
@ -1447,6 +1573,10 @@ class UIManager {
|
||||
}
|
||||
|
||||
updateAllUI() {
|
||||
if (!this.shouldUpdateUI()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if (debugLogger) debugLogger.log('Updating all UI elements');
|
||||
|
||||
this.updateResourceDisplay();
|
||||
@ -1481,18 +1611,40 @@ class UIManager {
|
||||
});
|
||||
}
|
||||
|
||||
// Centralized UI update control - blocks all UI updates when not in multiplayer mode
|
||||
shouldUpdateUI() {
|
||||
const shouldUpdate = window.smartSaveManager?.isMultiplayer || this.game?.isRunning;
|
||||
|
||||
if (!shouldUpdate) {
|
||||
console.log('[UI MANAGER] Blocking UI update - not in multiplayer mode');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Centralized update resource display - all calls should go through this
|
||||
updateResourceDisplay() {
|
||||
const debugLogger = window.debugLogger;
|
||||
if (!this.shouldUpdateUI()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// In multiplayer mode, ensure we're using server data
|
||||
if (window.smartSaveManager?.isMultiplayer) {
|
||||
// console.log('[UI MANAGER] Updating resource display in multiplayer mode - using server data');
|
||||
}
|
||||
|
||||
// const debugLogger = window.debugLogger;
|
||||
|
||||
try {
|
||||
// Safety checks - return early if systems aren't available
|
||||
if (!this.game || !this.game.systems) {
|
||||
if (debugLogger) debugLogger.log('Game systems not available, skipping resource display update');
|
||||
// if (debugLogger) debugLogger.log('Game systems not available, skipping resource display update');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.game.systems.player || !this.game.systems.economy) {
|
||||
if (debugLogger) debugLogger.log('Player or economy system not available, skipping resource display update');
|
||||
// if (debugLogger) debugLogger.log('Player or economy system not available, skipping resource display update');
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1501,18 +1653,18 @@ class UIManager {
|
||||
|
||||
// Additional safety checks for player properties
|
||||
if (!player.stats || !player.attributes || !player.ship) {
|
||||
if (debugLogger) debugLogger.log('Player properties not fully initialized, skipping resource display update');
|
||||
// if (debugLogger) debugLogger.log('Player properties not fully initialized, skipping resource display update');
|
||||
return;
|
||||
}
|
||||
|
||||
if (debugLogger) debugLogger.startStep('UIManager.updateResourceDisplay', {
|
||||
gameSystemsAvailable: !!(this.game && this.game.systems),
|
||||
playerSystemAvailable: !!(this.game && this.game.systems && this.game.systems.player),
|
||||
economySystemAvailable: !!(this.game && this.game.systems && this.game.systems.economy),
|
||||
playerStatsAvailable: !!player.stats,
|
||||
playerAttributesAvailable: !!player.attributes,
|
||||
playerShipAvailable: !!player.ship
|
||||
});
|
||||
// if (debugLogger) debugLogger.startStep('UIManager.updateResourceDisplay', {
|
||||
// gameSystemsAvailable: !!(this.game && this.game.systems),
|
||||
// playerSystemAvailable: !!(this.game && this.game.systems && this.game.systems.player),
|
||||
// economySystemAvailable: !!(this.game && this.game.systems && this.game.systems.economy),
|
||||
// playerStatsAvailable: !!player.stats,
|
||||
// playerAttributesAvailable: !!player.attributes,
|
||||
// playerShipAvailable: !!player.ship
|
||||
// });
|
||||
|
||||
let elementsUpdated = 0;
|
||||
let elementsNotFound = 0;
|
||||
@ -1522,6 +1674,7 @@ class UIManager {
|
||||
if (playerLevelElement) {
|
||||
const oldLevel = playerLevelElement.textContent;
|
||||
const playerLevel = player.stats.level || 1;
|
||||
// console.log('[UI MANAGER] Updating player level:', { oldLevel, newLevel: playerLevel, playerStats: player.stats });
|
||||
playerLevelElement.textContent = `Lv. ${playerLevel}`;
|
||||
elementsUpdated++;
|
||||
|
||||
@ -1532,7 +1685,7 @@ class UIManager {
|
||||
});
|
||||
} else {
|
||||
elementsNotFound++;
|
||||
if (debugLogger) debugLogger.log('Player level element not found');
|
||||
// if (debugLogger) debugLogger.log('Player level element not found');
|
||||
}
|
||||
|
||||
// Update ship level with safety checks
|
||||
@ -1559,6 +1712,7 @@ class UIManager {
|
||||
if (creditsElement) {
|
||||
const oldCredits = creditsElement.textContent;
|
||||
const creditsAmount = economy.credits || 0;
|
||||
// console.log('[UI MANAGER] Credits debug - economy.credits:', economy.credits, 'creditsAmount:', creditsAmount);
|
||||
creditsElement.textContent = this.game.formatNumber(creditsAmount);
|
||||
elementsUpdated++;
|
||||
|
||||
@ -1578,6 +1732,7 @@ class UIManager {
|
||||
if (gemsElement) {
|
||||
const oldGems = gemsElement.textContent;
|
||||
const gemsAmount = economy.gems || 0;
|
||||
// console.log('[UI MANAGER] Gems debug - economy.gems:', economy.gems, 'gemsAmount:', gemsAmount);
|
||||
gemsElement.textContent = this.game.formatNumber(gemsAmount);
|
||||
elementsUpdated++;
|
||||
|
||||
@ -1596,9 +1751,9 @@ class UIManager {
|
||||
const energyElement = document.getElementById('energy');
|
||||
if (energyElement) {
|
||||
const oldEnergy = energyElement.textContent;
|
||||
// Ensure we're using the correct energy values, not credits
|
||||
const currentEnergy = Math.floor(player.attributes.energy || 0);
|
||||
const maxEnergy = Math.floor(player.attributes.maxEnergy || 100);
|
||||
const currentEnergy = player.attributes.currentEnergy || player.attributes.energy || 0;
|
||||
const maxEnergy = player.attributes.maxEnergy || 100;
|
||||
// console.log('[UI MANAGER] Energy debug - player.attributes.currentEnergy:', player.attributes.currentEnergy, 'player.attributes.maxEnergy:', player.attributes.maxEnergy);
|
||||
energyElement.textContent = `${currentEnergy}/${maxEnergy}`;
|
||||
elementsUpdated++;
|
||||
|
||||
@ -1615,6 +1770,65 @@ class UIManager {
|
||||
if (debugLogger) debugLogger.log('Energy element not found');
|
||||
}
|
||||
|
||||
// Update play time (keep this here as it's part of the core resource display)
|
||||
const playTimeElement = document.getElementById('playTime');
|
||||
if (playTimeElement) {
|
||||
const playTimeMs = player.stats.playTime || 0;
|
||||
playTimeElement.textContent = this.formatPlayTime(playTimeMs);
|
||||
elementsUpdated++;
|
||||
}
|
||||
|
||||
// Update player stats panel
|
||||
const playerLevelDisplayElement = document.getElementById('playerLevelDisplay');
|
||||
if (playerLevelDisplayElement) {
|
||||
playerLevelDisplayElement.textContent = player.stats.level || 1;
|
||||
elementsUpdated++;
|
||||
}
|
||||
|
||||
const playerXPElement = document.getElementById('playerXP');
|
||||
if (playerXPElement) {
|
||||
const currentXP = player.stats.experience || 0;
|
||||
const xpToNext = player.stats.experienceToNext || 100;
|
||||
playerXPElement.textContent = `${currentXP} / ${xpToNext}`;
|
||||
elementsUpdated++;
|
||||
}
|
||||
|
||||
const skillPointsElement = document.getElementById('skillPoints');
|
||||
if (skillPointsElement) {
|
||||
skillPointsElement.textContent = player.stats.skillPoints || 0;
|
||||
elementsUpdated++;
|
||||
}
|
||||
|
||||
const totalXPElement = document.getElementById('totalXP');
|
||||
if (totalXPElement) {
|
||||
totalXPElement.textContent = this.game.formatNumber(player.stats.totalXP || 0);
|
||||
elementsUpdated++;
|
||||
}
|
||||
|
||||
const questsCompletedElement = document.getElementById('questsCompleted');
|
||||
if (questsCompletedElement) {
|
||||
// Use player stats from server first, then quest system stats as fallback
|
||||
const questsCompleted = player.stats.questsCompleted ||
|
||||
(this.game.systems.questSystem?.stats?.questsCompleted) || 0;
|
||||
questsCompletedElement.textContent = questsCompleted;
|
||||
elementsUpdated++;
|
||||
}
|
||||
|
||||
const lastLoginElement = document.getElementById('lastLogin');
|
||||
if (lastLoginElement) {
|
||||
const lastLogin = player.stats.lastLogin;
|
||||
if (lastLogin) {
|
||||
const loginDate = new Date(lastLogin);
|
||||
lastLoginElement.textContent = loginDate.toLocaleDateString() + ' ' + loginDate.toLocaleTimeString();
|
||||
} else {
|
||||
lastLoginElement.textContent = 'Never';
|
||||
}
|
||||
elementsUpdated++;
|
||||
}
|
||||
|
||||
// Update all player stats
|
||||
this.updatePlayerStats();
|
||||
|
||||
if (debugLogger) debugLogger.endStep('UIManager.updateResourceDisplay', {
|
||||
elementsUpdated: elementsUpdated,
|
||||
elementsNotFound: elementsNotFound,
|
||||
@ -1633,29 +1847,132 @@ class UIManager {
|
||||
}
|
||||
}
|
||||
|
||||
formatPlayTime(milliseconds) {
|
||||
// Format play time showing only the two most relevant units
|
||||
const totalSeconds = Math.floor(milliseconds / 1000);
|
||||
|
||||
if (totalSeconds < 60) {
|
||||
// Less than 1 minute: show seconds only
|
||||
return `${totalSeconds}s`;
|
||||
} else if (totalSeconds < 3600) {
|
||||
// Less than 1 hour: show minutes and seconds
|
||||
const minutes = Math.floor(totalSeconds / 60);
|
||||
const seconds = totalSeconds % 60;
|
||||
return `${minutes}m ${seconds}s`;
|
||||
} else if (totalSeconds < 86400) {
|
||||
// Less than 1 day: show hours and minutes
|
||||
const hours = Math.floor(totalSeconds / 3600);
|
||||
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
||||
return `${hours}h ${minutes}m`;
|
||||
} else {
|
||||
// 1 day or more: show days and hours
|
||||
const days = Math.floor(totalSeconds / 86400);
|
||||
const hours = Math.floor((totalSeconds % 86400) / 3600);
|
||||
return `${days}d ${hours}h`;
|
||||
}
|
||||
}
|
||||
|
||||
updatePlayerStats() {
|
||||
// Update just the player stats panel (excluding those handled in updateResourceDisplay)
|
||||
if (!this.game || !this.game.systems || !this.game.systems.player) {
|
||||
return;
|
||||
}
|
||||
|
||||
const player = this.game.systems.player;
|
||||
let elementsUpdated = 0;
|
||||
|
||||
// Update player stats panel
|
||||
const playerLevelDisplayElement = document.getElementById('playerLevelDisplay');
|
||||
if (playerLevelDisplayElement) {
|
||||
playerLevelDisplayElement.textContent = player.stats.level || 1;
|
||||
elementsUpdated++;
|
||||
}
|
||||
|
||||
const playerXPElement = document.getElementById('playerXP');
|
||||
if (playerXPElement) {
|
||||
const currentXP = player.stats.experience || 0;
|
||||
const xpToNext = player.stats.experienceToNext || 100;
|
||||
playerXPElement.textContent = `${currentXP} / ${xpToNext}`;
|
||||
elementsUpdated++;
|
||||
}
|
||||
|
||||
const skillPointsElement = document.getElementById('skillPoints');
|
||||
if (skillPointsElement) {
|
||||
skillPointsElement.textContent = player.stats.skillPoints || 0;
|
||||
elementsUpdated++;
|
||||
}
|
||||
|
||||
const totalXPElement = document.getElementById('totalXP');
|
||||
if (totalXPElement) {
|
||||
totalXPElement.textContent = this.game.formatNumber(player.stats.totalXP || 0);
|
||||
elementsUpdated++;
|
||||
}
|
||||
|
||||
const questsCompletedElement = document.getElementById('questsCompleted');
|
||||
if (questsCompletedElement) {
|
||||
// Use player stats from server first, then quest system stats as fallback
|
||||
const questsCompleted = player.stats.questsCompleted ||
|
||||
(this.game.systems.questSystem?.stats?.questsCompleted) || 0;
|
||||
questsCompletedElement.textContent = questsCompleted;
|
||||
elementsUpdated++;
|
||||
}
|
||||
|
||||
const lastLoginElement = document.getElementById('lastLogin');
|
||||
if (lastLoginElement) {
|
||||
const lastLogin = player.stats.lastLogin;
|
||||
if (lastLogin) {
|
||||
const loginDate = new Date(lastLogin);
|
||||
lastLoginElement.textContent = loginDate.toLocaleDateString() + ' ' + loginDate.toLocaleTimeString();
|
||||
} else {
|
||||
lastLoginElement.textContent = 'Never';
|
||||
}
|
||||
elementsUpdated++;
|
||||
}
|
||||
|
||||
// Update stats moved from Idle Progress card
|
||||
const totalKillsElement = document.getElementById('totalKills');
|
||||
if (totalKillsElement) {
|
||||
totalKillsElement.textContent = this.game.formatNumber(player.stats.totalKills || 0);
|
||||
elementsUpdated++;
|
||||
}
|
||||
|
||||
const dungeonsClearedElement = document.getElementById('dungeonsCleared');
|
||||
if (dungeonsClearedElement) {
|
||||
dungeonsClearedElement.textContent = player.stats.dungeonsCleared || 0;
|
||||
elementsUpdated++;
|
||||
}
|
||||
|
||||
// DISABLED: Reduce console spam for quest debugging
|
||||
// console.log(`[UI MANAGER] Player stats updated: ${elementsUpdated} elements`);
|
||||
}
|
||||
|
||||
updateUI() {
|
||||
const debugLogger = window.debugLogger;
|
||||
// const debugLogger = window.debugLogger;
|
||||
|
||||
if (debugLogger) debugLogger.startStep('UIManager.updateUI', {
|
||||
currentTab: this.currentTab,
|
||||
modalOpen: this.modalOpen
|
||||
});
|
||||
// if (debugLogger) debugLogger.startStep('UIManager.updateUI', {
|
||||
// currentTab: this.currentTab,
|
||||
// modalOpen: this.modalOpen
|
||||
// });
|
||||
|
||||
// Update resource display
|
||||
if (debugLogger) debugLogger.logStep('Updating resource display');
|
||||
this.updateResourceDisplay();
|
||||
// Update resource display only if in multiplayer mode or game is actively running
|
||||
if (this.shouldUpdateUI()) {
|
||||
// if (debugLogger) debugLogger.logStep('Updating resource display');
|
||||
this.updateResourceDisplay();
|
||||
}
|
||||
|
||||
// Update tab content
|
||||
if (debugLogger) debugLogger.logStep('Updating tab content', {
|
||||
currentTab: this.currentTab
|
||||
});
|
||||
this.updateTabContent(this.currentTab);
|
||||
// Update tab content only if in multiplayer mode or game is actively running
|
||||
if (this.shouldUpdateUI()) {
|
||||
// if (debugLogger) debugLogger.logStep('Updating tab content', {
|
||||
// currentTab: this.currentTab
|
||||
// });
|
||||
this.updateTabContent(this.currentTab);
|
||||
}
|
||||
|
||||
if (debugLogger) debugLogger.endStep('UIManager.updateUI', {
|
||||
resourceDisplayUpdated: true,
|
||||
tabContentUpdated: true,
|
||||
currentTab: this.currentTab
|
||||
});
|
||||
// if (debugLogger) debugLogger.endStep('UIManager.updateUI', {
|
||||
// resourceDisplayUpdated: true,
|
||||
// tabContentUpdated: true,
|
||||
// currentTab: this.currentTab
|
||||
// });
|
||||
}
|
||||
|
||||
// Menus
|
||||
@ -1807,8 +2124,8 @@ class UIManager {
|
||||
} else {
|
||||
}
|
||||
|
||||
// Reset economy
|
||||
if (this.game.systems.economy) {
|
||||
// Reset economy - only reset if not in multiplayer mode
|
||||
if (this.game.systems.economy && !window.smartSaveManager?.isMultiplayer) {
|
||||
this.game.systems.economy.credits = 1000;
|
||||
this.game.systems.economy.gems = 10;
|
||||
}
|
||||
@ -1927,8 +2244,8 @@ class UIManager {
|
||||
};
|
||||
}
|
||||
|
||||
// Clear economy data
|
||||
if (this.game.systems.economy) {
|
||||
// Clear economy data - only reset if not in multiplayer mode
|
||||
if (this.game.systems.economy && !window.smartSaveManager?.isMultiplayer) {
|
||||
this.game.systems.economy.credits = 1000;
|
||||
this.game.systems.economy.gems = 10;
|
||||
}
|
||||
|
||||
@ -1196,6 +1196,13 @@ body {
|
||||
.player-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.2rem;
|
||||
}
|
||||
|
||||
.player-info > div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
}
|
||||
|
||||
.player-name {
|
||||
@ -1203,6 +1210,18 @@ body {
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.player-title {
|
||||
font-weight: 500;
|
||||
color: var(--text-secondary);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.player-username {
|
||||
font-weight: 600;
|
||||
color: var(--accent-color);
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.player-level {
|
||||
font-size: 0.8rem;
|
||||
color: var(--primary-color);
|
||||
@ -1381,6 +1400,20 @@ body {
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.player-stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 0.5rem;
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.player-stats-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.stat {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user