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(); // global-ish state for modules const state = { me: null, world: null, inventory: [], players: [], nodes: [] }; // expose to UIs if they need it 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)`); // inventory not re-fetched here for brevity } else if (res?.error) { window.addChatLine?.(`Gather failed: ${res.error}`); } }); }); // socket updates hooked to MapView socket.on('nodes:init', list => { state.nodes = list; this.mapView.replaceNodes(list); }); socket.on('node:update', u => { this.mapView.updateNode(u); }); socket.on('state', snap => { state.players = snap.players; this.mapView.updateOtherPlayers(snap.players); }); // zoom from HUD window.setGameZoom = z => this.mapView.setZoom(z); } update(time, delta) { this.mapView.update(delta); } } async function boot() { // mount UIs 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')); // attempt auto-login const meData = await fetchMe(); if (!meData) { // show auth document.getElementById('ui-auth').firstElementChild?.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 socket world await new Promise(resolve => { socket.emit('auth:join', ack => { resolve(ack); }); }); document.getElementById('ui-auth').innerHTML = ''; // hide auth document.getElementById('ui-hud').firstElementChild?.classList.remove('hidden'); document.getElementById('ui-chat').firstElementChild?.classList.remove('hidden'); // start Phaser game const config = { type: Phaser.AUTO, parent: 'game', width: window.innerWidth, height: window.innerHeight, backgroundColor: '#020617', scene: [GameScene] }; new Phaser.Game(config); } boot();