Files
novafarma/EMERGENCY_SYSTEMS_RECOVERY/MultiplayerSystem.js
2026-01-16 02:43:46 +01:00

130 lines
4.3 KiB
JavaScript

class MultiplayerSystem {
constructor(scene) {
this.scene = scene;
this.socket = null;
this.otherPlayers = {}; // Map socketId -> Sprite
this.isConnected = false;
// Try to connect
this.connect();
}
connect() {
if (typeof io === 'undefined') {
console.warn('⚠️ Socket.IO not found. Multiplayer disabled.');
console.warn('Please run: npm install socket.io-client OR include CDN.');
return;
}
console.log('🌐 Connecting to Multiplayer Server...');
// Connect to localhost:3000
this.socket = io('http://localhost:3000');
this.socket.on('connect', () => {
console.log('✅ Connected to Server! ID:', this.socket.id);
this.isConnected = true;
// Send initial pos
if (this.scene.player) {
const pos = this.scene.player.getPosition();
this.socket.emit('playerMovement', {
x: pos.x,
y: pos.y,
anim: 'idle',
flipX: false
});
}
});
this.socket.on('currentPlayers', (players) => {
Object.keys(players).forEach((id) => {
if (id === this.socket.id) return;
this.addOtherPlayer(players[id]);
});
});
this.socket.on('newPlayer', (playerInfo) => {
this.addOtherPlayer(playerInfo);
});
this.socket.on('playerDisconnected', (playerId) => {
this.removeOtherPlayer(playerId);
});
this.socket.on('playerMoved', (playerInfo) => {
if (this.otherPlayers[playerInfo.id]) {
const sprite = this.otherPlayers[playerInfo.id];
// Update target pos for interpolation (TODO: logic)
// For now direct teleport
// Convert grid to screen
const iso = new IsometricUtils(48, 24);
const screen = iso.toScreen(playerInfo.x, playerInfo.y);
sprite.setPosition(screen.x + this.scene.terrainOffsetX, screen.y + this.scene.terrainOffsetY);
sprite.setDepth(sprite.y);
// Anim/Flip logic could go here
if (playerInfo.flipX !== undefined) sprite.setFlipX(playerInfo.flipX);
}
});
this.socket.on('worldAction', (action) => {
// Handle world syncing
if (action.type === 'build' && this.scene.buildingSystem) {
// Hacky: place building remotely
// this.scene.terrainSystem.placeStructure(...)
}
});
}
addOtherPlayer(playerInfo) {
if (this.otherPlayers[playerInfo.id]) return;
console.log('👤 New Player Joined:', playerInfo.id);
// Use player sprite
const iso = new IsometricUtils(48, 24);
const screen = iso.toScreen(playerInfo.x, playerInfo.y);
const sprite = this.scene.add.sprite(
screen.x + this.scene.terrainOffsetX,
screen.y + this.scene.terrainOffsetY,
'player' // or player_idle
);
sprite.setOrigin(0.5, 1);
sprite.setScale(0.3); // Same as local player
// Add name tag
const text = this.scene.add.text(0, -50, 'Player', { fontSize: '12px', fill: '#ffffff' });
text.setOrigin(0.5);
// Container? For now just sprite, text handling is complex
this.otherPlayers[playerInfo.id] = sprite;
}
removeOtherPlayer(playerId) {
if (this.otherPlayers[playerId]) {
console.log('👋 Player Left:', playerId);
this.otherPlayers[playerId].destroy();
delete this.otherPlayers[playerId];
}
}
update(delta) {
if (!this.isConnected || !this.socket || !this.scene.player) return;
// Rate limit: send 10 times second? Or every frame?
// Let's send only if moved
const player = this.scene.player;
if (player.isMoving) {
this.socket.emit('playerMovement', {
x: player.gridX,
y: player.gridY,
anim: 'walk',
flipX: player.sprite.flipX // Accessing internal sprite
});
}
}
}