105 lines
4.1 KiB
JavaScript
105 lines
4.1 KiB
JavaScript
import { NetworkService } from "./NetworkService.js";
|
|
import { Player } from "./Player.js";
|
|
import { BaseService } from "./BaseService.js";
|
|
import { Auth } from "../core/Auth.js";
|
|
/**
|
|
* Players manager
|
|
* - Tracks connected players after successful auth (0x01 0x03)
|
|
*/
|
|
export class Players extends BaseService {
|
|
constructor(networkService,isClient) {
|
|
super("Players");
|
|
this.InstanceId = "Players"; // For replication system
|
|
if (isClient) {
|
|
this.networkService = networkService;
|
|
this.networkService.registerHandler(0x00, 0x04, (payload) => {
|
|
// Auth response from server, parse it
|
|
const decoder = new TextDecoder();
|
|
const msg = decoder.decode(payload);
|
|
console.debug("[Players] Received auth response from server:", msg);
|
|
if (msg.startsWith("AUTH_SUCCESS|")) {
|
|
const playerName = msg.split("|")[1];
|
|
const id = msg.split("|")[2];
|
|
console.debug(`[Players] You have logged in as ${playerName}`);
|
|
// Create a local Player instance
|
|
const player = new Player( id, playerName, null );
|
|
this.players = new Map();
|
|
this.players.set(null, player); // single local player
|
|
this.LocalPlayer = player;
|
|
player.SetParent(this);
|
|
} else {
|
|
console.warn("[Players] Auth failed or unknown response:", msg);
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
this.networkService = networkService;
|
|
this.players = new Map(); // id -> Player
|
|
this.authenticator = new Auth();
|
|
|
|
// Listen for auth packets
|
|
this.networkService.registerHandler(0x01, 0x03, async (payload, ws) => {
|
|
if (ws.isAuthed) return; // Already authed, ignore additional auth attempts
|
|
console.debug("[Players] Received auth packet:", "CENSORED");
|
|
// Assume payload is a string (player name)
|
|
let token;
|
|
try {
|
|
// Decode bytes
|
|
const decoder = new TextDecoder();
|
|
token = decoder.decode(payload);
|
|
} catch (e) {
|
|
console.warn("[Players] Invalid auth payload:", payload);
|
|
networkService.KickClientLater(ws, 4000, "Invalid auth payload, please try again.");
|
|
|
|
return;
|
|
}
|
|
// Verify token (dummy implementation)
|
|
const id = await this.authenticator.verifySessionToken(token);
|
|
if (id === null) {
|
|
// Kick off the client
|
|
networkService.KickClientLater(ws, 4001, "Authentication failed; are you logged in?");
|
|
// Reason must be understandable as its shown to the user
|
|
return;
|
|
}
|
|
console.debug(`[Players] Client authenticated as ${id}`);
|
|
ws.isAuthed = true; // Mark ws as authed
|
|
// Create Player instance
|
|
const name = await this.authenticator.getUserNameById(id);
|
|
const player = new Player(id, name, ws );
|
|
this.players.set(ws, player);
|
|
player.SetParent(this);
|
|
// Listen for disconnection
|
|
ws.on("close", () => {
|
|
this.players.delete(ws);
|
|
player.Destroy();
|
|
console.debug(`[Players] Player ${name} (${id}) disconnected.`);
|
|
});
|
|
console.debug(`[Players] Player ${name} (${id}) connected.`);
|
|
// Send auth success packet
|
|
const encoder = new TextEncoder();
|
|
const successPayload = encoder.encode("AUTH_SUCCESS|" + name + "|" + id);
|
|
this.networkService.sendToClient(ws, 0x00, 0x04, successPayload);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get all connected players
|
|
*/
|
|
getAll() {
|
|
return Array.from(this.players.values());
|
|
}
|
|
|
|
/**
|
|
* Remove player by ws
|
|
*/
|
|
removeByWs(ws) {
|
|
this.players.delete(ws);
|
|
}
|
|
|
|
/**
|
|
* Get player by ws
|
|
*/
|
|
getByWs(ws) {
|
|
return this.players.get(ws);
|
|
}
|
|
} |