1203 lines
47 KiB
JavaScript
1203 lines
47 KiB
JavaScript
/**
|
|
* Live Main Menu System
|
|
* Handles server authentication, server browser, and multiplayer game initialization
|
|
*/
|
|
|
|
console.log('[LIVE MAIN MENU] LiveMainMenu.js script loaded');
|
|
|
|
class LiveMainMenu {
|
|
constructor() {
|
|
console.log('[LIVE MAIN MENU] Constructor called');
|
|
|
|
// Check if DOM is ready
|
|
if (document.readyState === 'loading') {
|
|
console.warn('[LIVE MAIN MENU] DOM not ready yet, elements may not be found');
|
|
} else {
|
|
console.log('[LIVE MAIN MENU] DOM is ready');
|
|
}
|
|
|
|
this.mainMenu = document.getElementById('mainMenu');
|
|
console.log('[LIVE MAIN MENU] Main menu element found:', !!this.mainMenu);
|
|
|
|
this.selectedServer = null;
|
|
this.authToken = null;
|
|
this.currentUser = null;
|
|
this.servers = []; // Renamed from serverList to avoid conflict with DOM element
|
|
this.apiBaseUrl = 'https://api.korvarix.com/api'; // API Server URL
|
|
this.gameServerUrl = 'https://dev.gameserver.galaxystrike.online'; // Game Server URL for Socket.IO
|
|
this.localGameServerUrl = 'http://localhost:3002'; // Local Game Server URL
|
|
this.isLocalMode = false; // Track if we're in local mode
|
|
|
|
console.log('[LIVE MAIN MENU] Initializing elements');
|
|
this.initializeElements();
|
|
|
|
console.log('[LIVE MAIN MENU] Initializing event listeners');
|
|
this.bindEvents();
|
|
|
|
// Check for existing auth token
|
|
this.checkExistingAuth();
|
|
|
|
// 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');
|
|
}
|
|
|
|
initializeElements() {
|
|
// Menu sections
|
|
this.loginSection = document.getElementById('loginSection');
|
|
this.serverSection = document.getElementById('serverSection');
|
|
this.serverConfirmSection = document.getElementById('serverConfirmSection');
|
|
this.optionsSection = document.getElementById('optionsSection');
|
|
|
|
// Login form elements
|
|
this.emailInput = document.getElementById('emailInput');
|
|
this.passwordInput = document.getElementById('passwordInput');
|
|
this.loginBtn = document.getElementById('loginBtn');
|
|
this.registerBtn = document.getElementById('registerBtn');
|
|
this.loginNotice = document.getElementById('loginNotice');
|
|
|
|
// Server browser elements
|
|
this.createServerBtn = document.getElementById('createServerBtn');
|
|
this.refreshServersBtn = document.getElementById('refreshServersBtn');
|
|
this.regionFilter = document.getElementById('regionFilter');
|
|
this.typeFilter = document.getElementById('typeFilter');
|
|
this.serverList = document.getElementById('serverList');
|
|
this.serverLoading = document.getElementById('serverLoading');
|
|
this.serverEmpty = document.getElementById('serverEmpty');
|
|
|
|
// Server confirmation elements
|
|
this.joinServerBtn = document.getElementById('joinServerBtn');
|
|
this.serverInfoBtn = document.getElementById('serverInfoBtn');
|
|
this.leaveServerBtn = document.getElementById('leaveServerBtn');
|
|
|
|
// Server detail elements
|
|
this.selectedServerName = document.getElementById('selectedServerName');
|
|
this.selectedServerType = document.getElementById('selectedServerType');
|
|
this.selectedServerRegion = document.getElementById('selectedServerRegion');
|
|
this.selectedServerPlayers = document.getElementById('selectedServerPlayers');
|
|
this.selectedServerOwner = document.getElementById('selectedServerOwner');
|
|
|
|
// Navigation buttons
|
|
this.backToLoginBtn = document.getElementById('backToLoginBtn');
|
|
this.backToServersBtn = document.getElementById('backToServersBtn');
|
|
|
|
console.log('[LIVE MAIN MENU] All elements initialized');
|
|
}
|
|
|
|
bindEvents() {
|
|
console.log('[LIVE MAIN MENU] Binding events...');
|
|
|
|
// Login events
|
|
if (this.loginBtn) {
|
|
this.loginBtn.addEventListener('click', () => this.handleLogin());
|
|
console.log('[LIVE MAIN MENU] Login button event bound');
|
|
} else {
|
|
console.warn('[LIVE MAIN MENU] Login button not found');
|
|
}
|
|
|
|
if (this.registerBtn) {
|
|
this.registerBtn.addEventListener('click', () => this.handleRegister());
|
|
console.log('[LIVE MAIN MENU] Register button event bound');
|
|
} else {
|
|
console.warn('[LIVE MAIN MENU] Register button not found');
|
|
}
|
|
|
|
// Enter key login
|
|
if (this.passwordInput) {
|
|
this.passwordInput.addEventListener('keypress', (e) => {
|
|
if (e.key === 'Enter') this.handleLogin();
|
|
});
|
|
console.log('[LIVE MAIN MENU] Password input event bound');
|
|
} else {
|
|
console.warn('[LIVE MAIN MENU] Password input not found');
|
|
}
|
|
|
|
// Server browser events
|
|
if (this.createServerBtn) {
|
|
this.createServerBtn.addEventListener('click', () => this.startLocalServer());
|
|
console.log('[LIVE MAIN MENU] Create server button event bound (now starts local server)');
|
|
} else {
|
|
console.warn('[LIVE MAIN MENU] Create server button not found');
|
|
}
|
|
|
|
if (this.refreshServersBtn) {
|
|
this.refreshServersBtn.addEventListener('click', () => this.refreshServerListWithoutAnimation());
|
|
console.log('[LIVE MAIN MENU] Refresh servers button event bound');
|
|
} else {
|
|
console.warn('[LIVE MAIN MENU] Refresh servers button not found');
|
|
}
|
|
|
|
if (this.regionFilter) {
|
|
this.regionFilter.addEventListener('change', () => this.filterServers());
|
|
console.log('[LIVE MAIN MENU] Region filter event bound');
|
|
} else {
|
|
console.warn('[LIVE MAIN MENU] Region filter not found');
|
|
}
|
|
|
|
if (this.typeFilter) {
|
|
this.typeFilter.addEventListener('change', () => this.filterServers());
|
|
console.log('[LIVE MAIN MENU] Type filter event bound');
|
|
} else {
|
|
console.warn('[LIVE MAIN MENU] Type filter not found');
|
|
}
|
|
|
|
// Server confirmation events
|
|
if (this.joinServerBtn) {
|
|
this.joinServerBtn.addEventListener('click', () => this.joinServer());
|
|
console.log('[LIVE MAIN MENU] Join server button event bound');
|
|
} else {
|
|
console.warn('[LIVE MAIN MENU] Join server not found');
|
|
}
|
|
|
|
// Navigation events
|
|
if (this.backToLoginBtn) {
|
|
this.backToLoginBtn.addEventListener('click', () => this.showLoginSection());
|
|
console.log('[LIVE MAIN MENU] Back to login button event bound');
|
|
} else {
|
|
console.warn('[LIVE MAIN MENU] Back to login button not found');
|
|
}
|
|
|
|
if (this.backToServersBtn) {
|
|
this.backToServersBtn.addEventListener('click', () => this.showServerSection());
|
|
console.log('[LIVE MAIN MENU] Back to servers button event bound');
|
|
} else {
|
|
console.warn('[LIVE MAIN MENU] Back to servers button not found');
|
|
}
|
|
|
|
console.log('[LIVE MAIN MENU] All events bound (with warnings for missing elements)');
|
|
}
|
|
|
|
checkExistingAuth() {
|
|
const token = localStorage.getItem('authToken');
|
|
const user = localStorage.getItem('currentUser');
|
|
|
|
if (token && user) {
|
|
this.authToken = token;
|
|
this.currentUser = JSON.parse(user);
|
|
console.log('[LIVE MAIN MENU] Found existing auth token, validating...');
|
|
this.validateToken();
|
|
} else {
|
|
console.log('[LIVE MAIN MENU] No existing auth found');
|
|
this.showLoginSection();
|
|
}
|
|
}
|
|
|
|
async validateToken() {
|
|
try {
|
|
const response = await fetch(`${this.apiBaseUrl}/auth/verify`, {
|
|
method: 'GET',
|
|
headers: {
|
|
'Authorization': `Bearer ${this.authToken}`,
|
|
'Content-Type': 'application/json'
|
|
}
|
|
});
|
|
|
|
if (response.ok) {
|
|
const data = await response.json();
|
|
this.currentUser = data.user;
|
|
localStorage.setItem('currentUser', JSON.stringify(this.currentUser));
|
|
console.log('[LIVE MAIN MENU] Token validated successfully');
|
|
this.showServerSection();
|
|
} else {
|
|
console.log('[LIVE MAIN MENU] Token invalid, clearing auth');
|
|
this.clearAuth();
|
|
this.showLoginSection();
|
|
}
|
|
} catch (error) {
|
|
console.error('[LIVE MAIN MENU] Token validation failed:', error);
|
|
this.clearAuth();
|
|
this.showLoginSection();
|
|
}
|
|
}
|
|
|
|
clearAuth() {
|
|
this.authToken = null;
|
|
this.currentUser = null;
|
|
localStorage.removeItem('authToken');
|
|
localStorage.removeItem('currentUser');
|
|
}
|
|
|
|
showSection(sectionName, animate = true) {
|
|
// Don't re-animate if we're showing the same section
|
|
if (this.currentSection === sectionName) {
|
|
animate = false;
|
|
}
|
|
|
|
// Hide all sections
|
|
this.loginSection?.classList.add('hidden');
|
|
this.serverSection?.classList.add('hidden');
|
|
this.serverConfirmSection?.classList.add('hidden');
|
|
this.optionsSection?.classList.add('hidden');
|
|
|
|
// Show selected section
|
|
const section = document.getElementById(`${sectionName}Section`);
|
|
if (section) {
|
|
section.classList.remove('hidden');
|
|
|
|
// Control animation
|
|
if (animate) {
|
|
section.style.animation = 'fadeInUp 0.5s ease-out';
|
|
} else {
|
|
section.style.animation = 'none';
|
|
}
|
|
|
|
this.currentSection = sectionName;
|
|
}
|
|
}
|
|
|
|
showLoginSection() {
|
|
this.showSection('login');
|
|
this.clearLoginForm();
|
|
}
|
|
|
|
showServerSection(refreshServers = true, animate = true) {
|
|
this.showSection('server', animate);
|
|
if (refreshServers) {
|
|
this.refreshServerList();
|
|
}
|
|
}
|
|
|
|
showServerConfirmSection() {
|
|
this.showSection('serverConfirm');
|
|
this.updateServerConfirmSection();
|
|
}
|
|
|
|
clearLoginForm() {
|
|
if (this.emailInput) this.emailInput.value = '';
|
|
if (this.passwordInput) this.passwordInput.value = '';
|
|
this.clearLoginNotice();
|
|
}
|
|
|
|
clearLoginNotice() {
|
|
if (this.loginNotice) {
|
|
this.loginNotice.innerHTML = `
|
|
<p><i class="fas fa-info-circle"></i> Connect to the live server to play</p>
|
|
<p style="font-size: 0.9em; margin-top: 10px; opacity: 0.8;">
|
|
<strong>Note:</strong> You need an internet connection to play Galaxy Strike Online.
|
|
</p>
|
|
`;
|
|
}
|
|
}
|
|
|
|
showLoginNotice(message, type = 'info') {
|
|
if (this.loginNotice) {
|
|
const iconClass = type === 'error' ? 'fa-exclamation-triangle' :
|
|
type === 'success' ? 'fa-check-circle' : 'fa-info-circle';
|
|
this.loginNotice.innerHTML = `<p><i class="fas ${iconClass}"></i> ${message}</p>`;
|
|
this.loginNotice.className = `login-notice ${type}`;
|
|
this.loginNotice.style.display = 'block';
|
|
}
|
|
}
|
|
|
|
hideLoginNotice() {
|
|
if (this.loginNotice) {
|
|
this.loginNotice.style.display = 'none';
|
|
}
|
|
}
|
|
|
|
async handleLogin() {
|
|
const email = this.emailInput?.value?.trim();
|
|
const password = this.passwordInput?.value?.trim();
|
|
|
|
if (!email || !password) {
|
|
this.showLoginNotice('Please enter email and password', 'error');
|
|
return;
|
|
}
|
|
|
|
// Disable login button
|
|
if (this.loginBtn) {
|
|
this.loginBtn.disabled = true;
|
|
this.loginBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Logging in...';
|
|
}
|
|
|
|
try {
|
|
const response = await fetch(`${this.apiBaseUrl}/auth/login`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({ email, password })
|
|
});
|
|
|
|
// Check if response is HTML (error page) instead of JSON
|
|
const contentType = response.headers.get('content-type');
|
|
if (!contentType || !contentType.includes('application/json')) {
|
|
throw new Error('API server is not available. Please check your connection.');
|
|
}
|
|
|
|
const data = await response.json();
|
|
|
|
if (response.ok) {
|
|
this.authToken = data.token;
|
|
this.currentUser = data.user;
|
|
|
|
// Save to localStorage
|
|
localStorage.setItem('authToken', this.authToken);
|
|
localStorage.setItem('currentUser', JSON.stringify(this.currentUser));
|
|
|
|
this.showLoginNotice('Login successful!', 'success');
|
|
console.log('[LIVE MAIN MENU] Login successful');
|
|
|
|
// Show server browser after a short delay
|
|
setTimeout(() => this.showServerSection(), 1000);
|
|
} else {
|
|
this.showLoginNotice(data.error || 'Login failed', 'error');
|
|
}
|
|
} catch (error) {
|
|
console.error('[LIVE MAIN MENU] Login error:', error);
|
|
this.showLoginNotice('Connection error. Please try again.', 'error');
|
|
} finally {
|
|
// Re-enable login button
|
|
if (this.loginBtn) {
|
|
this.loginBtn.disabled = false;
|
|
this.loginBtn.innerHTML = '<i class="fas fa-sign-in-alt"></i> Login';
|
|
}
|
|
}
|
|
}
|
|
|
|
async handleRegister() {
|
|
const email = this.emailInput?.value?.trim();
|
|
const password = this.passwordInput?.value?.trim();
|
|
|
|
if (!email || !password) {
|
|
this.showLoginNotice('Please enter email and password', 'error');
|
|
return;
|
|
}
|
|
|
|
if (password.length < 6) {
|
|
this.showLoginNotice('Password must be at least 6 characters', 'error');
|
|
return;
|
|
}
|
|
|
|
// Disable register button
|
|
if (this.registerBtn) {
|
|
this.registerBtn.disabled = true;
|
|
this.registerBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Registering...';
|
|
}
|
|
|
|
try {
|
|
// Generate a username from email
|
|
const username = email.split('@')[0];
|
|
|
|
const response = await fetch(`${this.apiBaseUrl}/auth/register`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({ username, email, password })
|
|
});
|
|
|
|
// Check if response is HTML (error page) instead of JSON
|
|
const contentType = response.headers.get('content-type');
|
|
if (!contentType || !contentType.includes('application/json')) {
|
|
throw new Error('API server is not available. Please check your connection.');
|
|
}
|
|
|
|
const data = await response.json();
|
|
|
|
if (response.ok) {
|
|
this.authToken = data.token;
|
|
this.currentUser = data.user;
|
|
|
|
// Save to localStorage
|
|
localStorage.setItem('authToken', this.authToken);
|
|
localStorage.setItem('currentUser', JSON.stringify(this.currentUser));
|
|
|
|
this.showLoginNotice('Registration successful!', 'success');
|
|
console.log('[LIVE MAIN MENU] Registration successful');
|
|
|
|
// Show server browser after a short delay
|
|
setTimeout(() => this.showServerSection(), 1000);
|
|
} else {
|
|
this.showLoginNotice(data.error || 'Registration failed', 'error');
|
|
}
|
|
} catch (error) {
|
|
console.error('[LIVE MAIN MENU] Registration error:', error);
|
|
this.showLoginNotice('Connection error. Please try again.', 'error');
|
|
} finally {
|
|
// Re-enable register button
|
|
if (this.registerBtn) {
|
|
this.registerBtn.disabled = false;
|
|
this.registerBtn.innerHTML = '<i class="fas fa-user-plus"></i> Register';
|
|
}
|
|
}
|
|
}
|
|
|
|
async refreshServerListWithoutAnimation() {
|
|
// Ensure we're in server section without animation
|
|
if (this.currentSection !== 'server') {
|
|
this.showServerSection(true, false); // Refresh but don't animate
|
|
} else {
|
|
// Already in server section, just refresh
|
|
await this.refreshServerList();
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
// Show loading state
|
|
if (this.serverLoading) this.serverLoading.classList.remove('hidden');
|
|
if (this.serverEmpty) this.serverEmpty.classList.add('hidden');
|
|
|
|
try {
|
|
let response;
|
|
|
|
// 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');
|
|
const localResponse = await window.localServerManager.localServer.mockRequest('GET', '/api/servers');
|
|
if (localResponse.success && localResponse.servers) {
|
|
servers.push(...localResponse.servers);
|
|
}
|
|
}
|
|
|
|
// 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`);
|
|
const apiResponse = await fetch(`${this.apiBaseUrl}/servers`, {
|
|
method: 'GET',
|
|
headers: {
|
|
'Authorization': `Bearer ${this.authToken}`,
|
|
'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]);
|
|
}
|
|
}
|
|
}
|
|
} catch (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() {
|
|
const filteredServers = this.getFilteredServers();
|
|
|
|
// Handle empty state
|
|
if (filteredServers.length === 0) {
|
|
if (this.serverEmpty) this.serverEmpty.classList.remove('hidden');
|
|
// Remove existing server items smoothly
|
|
this.removeServerItemsSmoothly();
|
|
return;
|
|
} else {
|
|
if (this.serverEmpty) this.serverEmpty.classList.add('hidden');
|
|
}
|
|
|
|
// Get current server items
|
|
const currentItems = this.serverList?.querySelectorAll('.server-item') || [];
|
|
|
|
// Create new server items HTML
|
|
const serverListHtml = filteredServers.map(server => this.createServerItem(server)).join('');
|
|
|
|
// Create a temporary container to hold new items
|
|
const tempDiv = document.createElement('div');
|
|
tempDiv.innerHTML = serverListHtml;
|
|
const newItems = Array.from(tempDiv.querySelectorAll('.server-item'));
|
|
|
|
// Smooth update: fade out current items, then replace with new ones
|
|
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') || [];
|
|
|
|
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);
|
|
}
|
|
|
|
updateServerItemsSmoothly(currentItems, newItems) {
|
|
// Fade out current items
|
|
if (currentItems.length > 0) {
|
|
currentItems.forEach(item => {
|
|
item.style.transition = 'opacity 0.2s ease-out';
|
|
item.style.opacity = '0';
|
|
});
|
|
|
|
// Replace with new items after fade out
|
|
setTimeout(() => {
|
|
currentItems.forEach(item => item.remove());
|
|
this.addNewServerItems(newItems);
|
|
}, 200);
|
|
} else {
|
|
// No current items, add new ones immediately
|
|
this.addNewServerItems(newItems);
|
|
}
|
|
}
|
|
|
|
addNewServerItems(newItems) {
|
|
if (!this.serverList) return;
|
|
|
|
// Add fade-in transition to new items
|
|
newItems.forEach(item => {
|
|
item.style.transition = 'opacity 0.3s ease-in';
|
|
item.style.opacity = '0';
|
|
});
|
|
|
|
// Add new items to DOM
|
|
newItems.forEach(item => {
|
|
this.serverList.appendChild(item);
|
|
});
|
|
|
|
// Add click handlers
|
|
newItems.forEach(item => {
|
|
item.addEventListener('click', () => {
|
|
const serverId = item.dataset.serverId;
|
|
this.selectServer(serverId);
|
|
});
|
|
});
|
|
|
|
// Fade in new items
|
|
setTimeout(() => {
|
|
newItems.forEach(item => {
|
|
item.style.opacity = '1';
|
|
});
|
|
}, 50);
|
|
}
|
|
|
|
createServerItem(server) {
|
|
const playerCount = `${server.currentPlayers}/${server.maxPlayers}`;
|
|
const createdDate = new Date(server.createdAt).toLocaleDateString();
|
|
|
|
return `
|
|
<div class="server-item" data-server-id="${server.id}">
|
|
<div class="server-info">
|
|
<div class="server-name">${server.name}</div>
|
|
<div class="server-details">
|
|
<span class="server-detail">
|
|
<i class="fas fa-globe"></i>
|
|
<span class="server-region">${server.region || 'Unknown'}</span>
|
|
</span>
|
|
<span class="server-detail">
|
|
<i class="fas fa-calendar"></i>
|
|
<span>${createdDate}</span>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<div class="server-actions-right">
|
|
<span class="server-type ${server.type}">${server.type}</span>
|
|
<span class="server-player-count">${playerCount}</span>
|
|
<i class="fas fa-chevron-right"></i>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
getFilteredServers() {
|
|
let filtered = [...this.servers];
|
|
|
|
const regionFilter = this.regionFilter?.value;
|
|
const typeFilter = this.typeFilter?.value;
|
|
|
|
if (regionFilter) {
|
|
filtered = filtered.filter(server => server.region === regionFilter);
|
|
}
|
|
|
|
if (typeFilter) {
|
|
filtered = filtered.filter(server => server.type === typeFilter);
|
|
}
|
|
|
|
return filtered;
|
|
}
|
|
|
|
filterServers() {
|
|
this.renderServerList();
|
|
}
|
|
|
|
selectServer(serverId) {
|
|
this.selectedServer = this.servers.find(server => server.id === serverId);
|
|
if (this.selectedServer) {
|
|
console.log('[LIVE MAIN MENU] Server selected:', this.selectedServer);
|
|
this.showServerConfirmSection();
|
|
}
|
|
}
|
|
|
|
updateServerConfirmSection() {
|
|
if (!this.selectedServer) return;
|
|
|
|
// Update server details
|
|
if (this.selectedServerName) this.selectedServerName.textContent = this.selectedServer.name;
|
|
if (this.selectedServerType) this.selectedServerType.textContent = this.selectedServer.type;
|
|
if (this.selectedServerRegion) this.selectedServerRegion.textContent = this.selectedServer.region || 'Unknown';
|
|
if (this.selectedServerPlayers) this.selectedServerPlayers.textContent =
|
|
`${this.selectedServer.currentPlayers}/${this.selectedServer.maxPlayers}`;
|
|
if (this.selectedServerOwner) this.selectedServerOwner.textContent = this.selectedServer.ownerName || 'Unknown';
|
|
}
|
|
|
|
async joinServer() {
|
|
if (!this.selectedServer || !this.authToken) {
|
|
console.error('[LIVE MAIN MENU] No server selected or not authenticated');
|
|
return;
|
|
}
|
|
|
|
// Disable join button
|
|
if (this.joinServerBtn) {
|
|
this.joinServerBtn.disabled = true;
|
|
this.joinServerBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Joining...';
|
|
}
|
|
|
|
try {
|
|
let response;
|
|
|
|
// Use SimpleLocalServer mock API if in local mode
|
|
if (this.isLocalMode && window.localServerManager && window.localServerManager.localServer && window.localServerManager.localServer.mockRequest) {
|
|
console.log('[LIVE MAIN MENU] Using SimpleLocalServer mock API for join server');
|
|
response = await window.localServerManager.localServer.mockRequest('POST', `/servers/${this.selectedServer.id}/join`, {
|
|
userId: this.currentUser.id,
|
|
token: this.authToken
|
|
});
|
|
} else {
|
|
console.log('[LIVE MAIN MENU] Using real fetch for join server');
|
|
response = await fetch(`${this.apiBaseUrl}/servers/${this.selectedServer.id}/join`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Authorization': `Bearer ${this.authToken}`,
|
|
'Content-Type': 'application/json'
|
|
}
|
|
});
|
|
}
|
|
|
|
// Check if response is HTML (error page) instead of JSON
|
|
const contentType = response.headers ? response.headers.get('content-type') : 'application/json';
|
|
if (!contentType || !contentType.includes('application/json')) {
|
|
throw new Error('API server is not available. Please check your connection.');
|
|
}
|
|
|
|
const data = await response.json();
|
|
|
|
if (response.ok) {
|
|
console.log('[LIVE MAIN MENU] Joined server successfully');
|
|
|
|
// Apply existing save data if in local mode
|
|
if (this.isLocalMode && window.localServerManager && window.localServerManager.localServer) {
|
|
console.log('[LIVE MAIN MENU] Applying existing save data for local mode...');
|
|
|
|
// Store save data for later application (after GameEngine is created)
|
|
this.pendingSaveData = window.localServerManager.localServer.existingSaveData;
|
|
|
|
if (this.pendingSaveData) {
|
|
console.log('[LIVE MAIN MENU] Save data stored for later application');
|
|
} else {
|
|
console.log('[LIVE MAIN MENU] No save data to store');
|
|
}
|
|
}
|
|
|
|
this.launchMultiplayerGame(this.selectedServer, data.server);
|
|
} else {
|
|
console.error('[LIVE MAIN MENU] Failed to join server:', data.error);
|
|
alert(data.error || 'Failed to join server');
|
|
}
|
|
} catch (error) {
|
|
console.error('[LIVE MAIN MENU] Join server error:', error);
|
|
alert('Connection error. Please try again.');
|
|
} finally {
|
|
// Re-enable join button
|
|
if (this.joinServerBtn) {
|
|
this.joinServerBtn.disabled = false;
|
|
this.joinServerBtn.innerHTML = '<i class="fas fa-sign-in-alt"></i> Join Server';
|
|
}
|
|
}
|
|
}
|
|
|
|
showServerInfo() {
|
|
if (!this.selectedServer) return;
|
|
|
|
const info = `
|
|
Server Information:
|
|
Name: ${this.selectedServer.name}
|
|
Type: ${this.selectedServer.type}
|
|
Region: ${this.selectedServer.region}
|
|
Players: ${this.selectedServer.currentPlayers}/${this.selectedServer.maxPlayers}
|
|
Owner: ${this.selectedServer.ownerName}
|
|
Created: ${new Date(this.selectedServer.createdAt).toLocaleString()}
|
|
Status: ${this.selectedServer.status}
|
|
`.trim();
|
|
|
|
alert(info);
|
|
}
|
|
|
|
leaveServer() {
|
|
this.selectedServer = null;
|
|
this.showServerSection();
|
|
}
|
|
|
|
showCreateServerDialog() {
|
|
return new Promise((resolve) => {
|
|
// Create modal dialog
|
|
const modal = document.createElement('div');
|
|
modal.className = 'modal-overlay';
|
|
modal.innerHTML = `
|
|
<div class="modal-dialog">
|
|
<div class="modal-header">
|
|
<h3>Create New Server</h3>
|
|
<button class="modal-close">×</button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="form-group">
|
|
<label for="serverName">Server Name:</label>
|
|
<input type="text" id="serverName" placeholder="Enter server name..." maxlength="50" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="serverType">Server Type:</label>
|
|
<select id="serverType">
|
|
<option value="public">Public</option>
|
|
<option value="private">Private</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="serverRegion">Region:</label>
|
|
<select id="serverRegion">
|
|
<option value="us-east">US East</option>
|
|
<option value="us-west">US West</option>
|
|
<option value="europe">Europe</option>
|
|
<option value="asia">Asia</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="maxPlayers">Max Players:</label>
|
|
<input type="number" id="maxPlayers" min="1" max="20" value="10">
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button class="btn btn-secondary" id="cancelBtn">Cancel</button>
|
|
<button class="btn btn-primary" id="createBtn">Create Server</button>
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
// Add styles for modal
|
|
const style = document.createElement('style');
|
|
style.textContent = `
|
|
.modal-overlay {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: rgba(0, 0, 0, 0.8);
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
z-index: 10000;
|
|
}
|
|
.modal-dialog {
|
|
background: var(--bg-primary);
|
|
border: 1px solid var(--border-color);
|
|
border-radius: 8px;
|
|
padding: 20px;
|
|
min-width: 400px;
|
|
max-width: 500px;
|
|
}
|
|
.modal-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 20px;
|
|
}
|
|
.modal-header h3 {
|
|
margin: 0;
|
|
color: var(--text-primary);
|
|
}
|
|
.modal-close {
|
|
background: none;
|
|
border: none;
|
|
color: var(--text-secondary);
|
|
font-size: 24px;
|
|
cursor: pointer;
|
|
}
|
|
.form-group {
|
|
margin-bottom: 15px;
|
|
}
|
|
.form-group label {
|
|
display: block;
|
|
margin-bottom: 5px;
|
|
color: var(--text-primary);
|
|
}
|
|
.form-group input,
|
|
.form-group select {
|
|
width: 100%;
|
|
padding: 8px;
|
|
background: var(--bg-secondary);
|
|
border: 1px solid var(--border-color);
|
|
border-radius: 4px;
|
|
color: var(--text-primary);
|
|
}
|
|
.modal-footer {
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
gap: 10px;
|
|
margin-top: 20px;
|
|
}
|
|
.btn {
|
|
padding: 8px 16px;
|
|
border: none;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
}
|
|
.btn-primary {
|
|
background: var(--primary-color);
|
|
color: white;
|
|
}
|
|
.btn-secondary {
|
|
background: var(--bg-secondary);
|
|
color: var(--text-primary);
|
|
border: 1px solid var(--border-color);
|
|
}
|
|
`;
|
|
document.head.appendChild(style);
|
|
|
|
// Add modal to page
|
|
document.body.appendChild(modal);
|
|
|
|
// Get elements
|
|
const closeBtn = modal.querySelector('.modal-close');
|
|
const cancelBtn = modal.querySelector('#cancelBtn');
|
|
const createBtn = modal.querySelector('#createBtn');
|
|
const nameInput = modal.querySelector('#serverName');
|
|
|
|
// Event handlers
|
|
const closeModal = () => {
|
|
document.body.removeChild(modal);
|
|
document.head.removeChild(style);
|
|
resolve(null);
|
|
};
|
|
|
|
const handleCreate = () => {
|
|
const name = nameInput.value.trim();
|
|
const type = modal.querySelector('#serverType').value;
|
|
const region = modal.querySelector('#serverRegion').value;
|
|
const maxPlayers = parseInt(modal.querySelector('#maxPlayers').value);
|
|
|
|
if (!name) {
|
|
nameInput.focus();
|
|
return;
|
|
}
|
|
|
|
if (maxPlayers < 1 || maxPlayers > 20) {
|
|
modal.querySelector('#maxPlayers').focus();
|
|
return;
|
|
}
|
|
|
|
document.body.removeChild(modal);
|
|
document.head.removeChild(style);
|
|
resolve({ name, type, region, maxPlayers });
|
|
};
|
|
|
|
closeBtn.addEventListener('click', closeModal);
|
|
cancelBtn.addEventListener('click', closeModal);
|
|
createBtn.addEventListener('click', handleCreate);
|
|
|
|
// Handle Enter key in name input
|
|
nameInput.addEventListener('keypress', (e) => {
|
|
if (e.key === 'Enter') {
|
|
handleCreate();
|
|
}
|
|
});
|
|
|
|
// Focus on name input
|
|
nameInput.focus();
|
|
});
|
|
}
|
|
|
|
async handleCreateServer() {
|
|
try {
|
|
// Get server details from user using custom dialog
|
|
const serverDetails = await this.showCreateServerDialog();
|
|
|
|
if (!serverDetails) {
|
|
return; // User cancelled
|
|
}
|
|
|
|
const { name, type, maxPlayers, region } = serverDetails;
|
|
|
|
// Show loading state
|
|
if (this.serverLoading) this.serverLoading.classList.remove('hidden');
|
|
|
|
const response = await fetch(`${this.apiBaseUrl}/servers/create`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Authorization': `Bearer ${this.authToken}`,
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
name,
|
|
type,
|
|
maxPlayers,
|
|
region,
|
|
username: this.currentUser.username
|
|
})
|
|
});
|
|
|
|
// Check if response is HTML (error page) instead of JSON
|
|
const contentType = response.headers.get('content-type');
|
|
if (!contentType || !contentType.includes('application/json')) {
|
|
throw new Error('API server is not available. Please check your connection.');
|
|
}
|
|
|
|
if (response.ok) {
|
|
const data = await response.json();
|
|
console.log('[LIVE MAIN MENU] Server created:', data.server);
|
|
|
|
// Refresh server list
|
|
await this.refreshServerList();
|
|
|
|
// Show success message
|
|
this.showLoginNotice('Server created successfully!', 'success');
|
|
|
|
// Auto-join the created server
|
|
this.joinServer(data.server.id);
|
|
} else {
|
|
const errorData = await response.json();
|
|
console.error('[LIVE MAIN MENU] Failed to create server:', errorData);
|
|
this.showLoginNotice(`Failed to create server: ${errorData.error}`, 'error');
|
|
}
|
|
} catch (error) {
|
|
console.error('[LIVE MAIN MENU] Create server error:', error);
|
|
this.showLoginNotice('Failed to create server', 'error');
|
|
} finally {
|
|
// Hide loading state
|
|
if (this.serverLoading) this.serverLoading.classList.add('hidden');
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
hideLoadingScreenAndShowGame() {
|
|
console.log('[LIVE MAIN MENU] Hiding main menu and showing game interface');
|
|
|
|
// Hide main menu
|
|
if (this.mainMenu) {
|
|
this.mainMenu.classList.add('hidden');
|
|
}
|
|
|
|
// Show game interface
|
|
const gameInterface = document.getElementById('gameInterface');
|
|
if (gameInterface) {
|
|
gameInterface.classList.remove('hidden');
|
|
}
|
|
|
|
// Note: gameContainer element doesn't exist in HTML, so we skip it
|
|
}
|
|
|
|
initializeMultiplayerGame(server, serverData) {
|
|
console.log('[LIVE MAIN MENU] Initializing multiplayer game');
|
|
|
|
// 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();
|
|
}
|
|
|
|
// 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();
|
|
}
|
|
};
|
|
}
|
|
|
|
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}`);
|
|
|
|
// 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');
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
// Start the local server
|
|
const result = await window.localServerManager.startServer();
|
|
|
|
if (result.success) {
|
|
console.log('[LIVE MAIN MENU] Local server started successfully:', result);
|
|
|
|
// Update to local mode
|
|
this.isLocalMode = true;
|
|
this.apiBaseUrl = `http://localhost:${result.port}/api`;
|
|
this.gameServerUrl = `http://localhost:${result.port}`;
|
|
|
|
console.log(`[LIVE MAIN MENU] Updated to local mode - API: ${this.apiBaseUrl}`);
|
|
|
|
// Update button to show running state
|
|
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');
|
|
}
|
|
|
|
// Auto-login for local mode
|
|
await this.autoLoginLocalMode();
|
|
|
|
// Show success message
|
|
this.showLoginNotice('Local server started successfully!', 'success');
|
|
|
|
} else {
|
|
console.error('[LIVE MAIN MENU] Failed to start local server:', result.error);
|
|
this.showLoginNotice(`Failed to start local server: ${result.error}`, 'error');
|
|
|
|
// Reset button to original state
|
|
if (this.createServerBtn) {
|
|
this.createServerBtn.innerHTML = '<i class="fas fa-server"></i> Start Local Server';
|
|
this.createServerBtn.disabled = false;
|
|
}
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('[LIVE MAIN MENU] Error starting local server:', error);
|
|
this.showLoginNotice('Error starting local server', 'error');
|
|
|
|
// Reset button to original state
|
|
if (this.createServerBtn) {
|
|
this.createServerBtn.innerHTML = '<i class="fas fa-server"></i> Start Local Server';
|
|
this.createServerBtn.disabled = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// End of LiveMainMenu class
|
|
|
|
// Initialize LiveMainMenu when DOM is ready
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
if (typeof window !== 'undefined') {
|
|
window.liveMainMenu = new LiveMainMenu();
|
|
}
|
|
});
|
|
|
|
// Export for use in other scripts
|
|
if (typeof module !== 'undefined' && module.exports) {
|
|
module.exports = LiveMainMenu;
|
|
}
|