import { setupAuthPanel } from './ui_auth.js'; import { setupHUD } from './ui_hud.js'; import { setupChat } from './ui_chat.js'; import { setupInventory } from './ui_inventory.js'; import { setupCrafting } from './ui_crafting.js'; import { MapView } from './map.js'; const socket = io(); // shared state const state = { me: null, world: null, inventory: [], players: [], nodes: [] }; window.GameState = state; window.GameSocket = socket; async function fetchMe() { const res = await fetch('/api/me', { credentials: 'include' }); if (res.status !== 200) return null; return res.json(); } // Phaser scene class GameScene extends Phaser.Scene { constructor() { super('Game'); } preload() { this.textures.generate('player', { data: ['333', '383', '333'], pixelWidth: 8 }); this.textures.generate('other', { data: ['939', '999', '939'], pixelWidth: 8 }); this.textures.generate('wood', { data: ['060', '660', '060'], pixelWidth: 8 }); this.textures.generate('stone', { data: ['888', 'aaa', '888'], pixelWidth: 8 }); this.textures.generate('ore', { data: ['a73', 'c95', 'a73'], pixelWidth: 8 }); this.textures.generate('fiber', { data: ['6a6', '8c8', '6a6'], pixelWidth: 8 }); } create() { this.mapView = new MapView(this); this.mapView.create(state.me, state.world, state.nodes); // click to move this.input.on('pointerdown', p => { this.mapView.setTarget(p.worldX, p.worldY); socket.emit('move:click', { x: p.worldX, y: p.worldY }); }); // gather on E this.input.keyboard.on('keydown-E', () => { const nodeId = this.mapView.getClosestNodeIdInRange(40); if (nodeId == null) return; socket.emit('gather', { nodeId }, res => { if (res?.ok) { window.updateXP?.(res.level); window.addChatLine?.(`You gather 1 ${res.item} (+${res.xp} xp)`); } else if (res?.error) { window.addChatLine?.(`Gather failed: ${res.error}`); } }); }); // resource nodes from server socket.on('nodes:init', list => { state.nodes = list; this.mapView.replaceNodes(list); }); socket.on('node:update', u => { this.mapView.updateNode(u); }); // player positions socket.on('state', snap => { state.players = snap.players; this.mapView.updateOtherPlayers(snap.players); }); // HUD zoom hook window.setGameZoom = z => this.mapView.setZoom(z); } update(time, delta) { this.mapView.update(delta); } } async function boot() { // Mount UI modules setupAuthPanel(document.getElementById('ui-auth'), socket, bootAfterLogin); setupHUD(document.getElementById('ui-hud')); setupChat(document.getElementById('ui-chat'), socket); setupInventory(document.getElementById('ui-inventory')); setupCrafting(document.getElementById('ui-crafting')); // auto-login attempt const meData = await fetchMe(); if (!meData) { const authPanel = document.getElementById('ui-auth').firstElementChild; if (authPanel) authPanel.classList.remove('hidden'); return; } await bootAfterLogin(); } async function bootAfterLogin() { const data = await fetchMe(); if (!data) return; state.me = data.character; state.inventory = data.inventory; state.world = data.world; // join world socket await new Promise(resolve => { socket.emit('auth:join', ack => resolve(ack)); }); // show HUD + chat; hide auth document.getElementById('ui-auth').innerHTML = ''; const hudPanel = document.getElementById('ui-hud').firstElementChild; if (hudPanel) hudPanel.classList.remove('hidden'); const chatPanel = document.getElementById('ui-chat').firstElementChild; if (chatPanel) chatPanel.classList.remove('hidden'); // start Phaser const config = { type: Phaser.AUTO, parent: 'game', width: window.innerWidth, height: window.innerHeight, backgroundColor: '#020617', scene: [GameScene] }; new Phaser.Game(config); } boot();