feat: track followed NPCs via socket for LLM narration priority

Adds follow-npc client event so the server knows which NPCs are being
watched, enabling priority LLM narration for followed entity interactions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
root
2026-03-08 18:25:16 +00:00
parent e8723f0a06
commit 6514dde42e
4 changed files with 31 additions and 1 deletions
+17 -1
View File
@@ -1,6 +1,6 @@
import { Server } from 'socket.io';
import type http from 'http';
import type { ClientEvents, ServerEvents, PlayerInput, Position, Movement, PlayerControlled, Appearance } from '@dflike/shared';
import type { ClientEvents, ServerEvents, PlayerInput, Position, Movement, PlayerControlled, Appearance, EntityId } from '@dflike/shared';
import { Direction, MAX_NPC_COUNT } from '@dflike/shared';
import { generateRandomAppearance } from '../spawner/appearanceGenerator.js';
import type { GameLoop } from '../game/GameLoop.js';
@@ -10,6 +10,7 @@ import { serializeWorldState, serializeStateUpdate } from './stateSerializer.js'
export class SocketServer {
private io: Server<ClientEvents, ServerEvents>;
private gameLoop: GameLoop;
private followedEntities: Map<string, EntityId | null> = new Map();
constructor(httpServer: http.Server, gameLoop: GameLoop) {
this.io = new Server(httpServer, {
@@ -82,15 +83,30 @@ export class SocketServer {
spawnNPC(world, map, target);
});
// Handle follow-npc
socket.on('follow-npc', (data: { entityId: EntityId | null }) => {
this.followedEntities.set(socket.id, data.entityId);
this.rebuildFollowedEntityIds();
});
// Handle disconnect
socket.on('disconnect', () => {
console.log(`Player disconnected: ${playerId}`);
this.followedEntities.delete(socket.id);
this.rebuildFollowedEntityIds();
world.removeEntity(entity);
this.io.emit('player-left', { playerId });
});
});
}
private rebuildFollowedEntityIds(): void {
this.gameLoop.followedEntityIds.clear();
for (const [, entityId] of this.followedEntities) {
if (entityId !== null) this.gameLoop.followedEntityIds.add(entityId);
}
}
private handleInput(playerId: string, entityId: number, input: PlayerInput): void {
const world = this.gameLoop.world;
const pc = world.getComponent<PlayerControlled>(entityId, 'playerControlled');