From c08acb424158644a9c5c5b05ec142d71820cc126 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Mart=C3=ADnez=20Sebasti=C3=A1n?= Date: Wed, 10 Jun 2026 00:26:03 +0200 Subject: [PATCH 01/10] =?UTF-8?q?feat(multiplayer):=20implement=20Phase=20?= =?UTF-8?q?14=20MVP=20=E2=80=94=20agnostic=20core=20+=20/multiplayer=20rou?= =?UTF-8?q?te?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit engine-core (agnostic, no network/window): - MultiplayerPort + NetEnvelope + HeadlessMultiplayerAdapter/InMemoryHub - event classification (world/presence/private, exhaustive satisfies) - PlayerDescriptor + remotePlayersStore; net:* events/commands - MultiplayerSession (bus<->port bridge, origin-tagging anti-loop, presence throttle) - HLC clock + LWW worldState + claim resolution + optimistic reconciler engine-renderer-r3f: - RemotePlayers (reuses DavidSprite, per-player lerp interpolation) apps/web-demo: - PartyKit server (party/multiplayer.ts, cap 4) + client adapter (partysocket) - roomSession (code + localStorage persist + solo/reset + N/4) - createMultiplayerRuntime + RoomLobby + /multiplayer route - GameTouchCanvas extraCanvasChildren slot Tests: +29 core (273 total) + 6 roomSession, all green. Core agnosticism test added. Pre-existing publicApi.test.ts failures unaffected. E2E two-tab pending manual run. Co-Authored-By: Claude Opus 4.8 --- .../app/components/GameTouchCanvas.tsx | 4 + .../web-demo/app/components/net/RoomLobby.tsx | 69 ++++++++ .../app/lib/net/__tests__/roomSession.test.ts | 47 ++++++ .../app/lib/net/createMultiplayerRuntime.ts | 67 ++++++++ apps/web-demo/app/lib/net/partyKitAdapter.ts | 56 +++++++ apps/web-demo/app/lib/net/roomCode.ts | 20 +++ apps/web-demo/app/lib/net/roomCodeStorage.ts | 12 ++ apps/web-demo/app/lib/net/roomSession.ts | 58 +++++++ apps/web-demo/app/multiplayer/page.tsx | 79 +++++++++ apps/web-demo/package.json | 4 +- apps/web-demo/party/multiplayer.ts | 82 +++++++++ apps/web-demo/partykit.json | 7 + .../tasks/01-define-multiplayer-port.md | 20 ++- docs/phases/phase-14-multiplayer/tracking.md | 30 ++-- .../phase-14-multiplayer/validation-report.md | 53 ++++++ .../engine-core/dist/game/commands/types.d.ts | 9 + .../dist/game/commands/types.d.ts.map | 2 +- .../engine-core/dist/game/events/types.d.ts | 11 ++ .../dist/game/events/types.d.ts.map | 2 +- .../game/logic/pathfinding/findPath.d.ts.map | 2 +- .../dist/game/logic/pathfinding/findPath.js | 31 +++- .../game/logic/pathfinding/findPath.js.map | 2 +- .../dist/game/net/MultiplayerSession.d.ts | 36 ++++ .../dist/game/net/MultiplayerSession.d.ts.map | 1 + .../dist/game/net/MultiplayerSession.js | 118 +++++++++++++ .../dist/game/net/MultiplayerSession.js.map | 1 + .../engine-core/dist/game/net/claims.d.ts | 17 ++ .../engine-core/dist/game/net/claims.d.ts.map | 1 + packages/engine-core/dist/game/net/claims.js | 15 ++ .../engine-core/dist/game/net/claims.js.map | 1 + packages/engine-core/dist/game/net/clock.d.ts | 9 + .../engine-core/dist/game/net/clock.d.ts.map | 1 + packages/engine-core/dist/game/net/clock.js | 28 ++++ .../engine-core/dist/game/net/clock.js.map | 1 + .../dist/game/net/eventClassification.d.ts | 43 +++++ .../game/net/eventClassification.d.ts.map | 1 + .../dist/game/net/eventClassification.js | 51 ++++++ .../dist/game/net/eventClassification.js.map | 1 + packages/engine-core/dist/game/net/index.d.ts | 10 ++ .../engine-core/dist/game/net/index.d.ts.map | 1 + packages/engine-core/dist/game/net/index.js | 10 ++ .../engine-core/dist/game/net/index.js.map | 1 + .../engine-core/dist/game/net/optimistic.d.ts | 21 +++ .../dist/game/net/optimistic.d.ts.map | 1 + .../engine-core/dist/game/net/optimistic.js | 34 ++++ .../dist/game/net/optimistic.js.map | 1 + .../dist/game/net/playerIdentity.d.ts | 29 ++++ .../dist/game/net/playerIdentity.d.ts.map | 1 + .../dist/game/net/playerIdentity.js | 31 ++++ .../dist/game/net/playerIdentity.js.map | 1 + .../dist/game/net/remotePlayersStore.d.ts | 19 +++ .../dist/game/net/remotePlayersStore.d.ts.map | 1 + .../dist/game/net/remotePlayersStore.js | 47 ++++++ .../dist/game/net/remotePlayersStore.js.map | 1 + .../engine-core/dist/game/net/throttle.d.ts | 11 ++ .../dist/game/net/throttle.d.ts.map | 1 + .../engine-core/dist/game/net/throttle.js | 26 +++ .../engine-core/dist/game/net/throttle.js.map | 1 + .../engine-core/dist/game/net/worldState.d.ts | 17 ++ .../dist/game/net/worldState.d.ts.map | 1 + .../engine-core/dist/game/net/worldState.js | 28 ++++ .../dist/game/net/worldState.js.map | 1 + packages/engine-core/dist/index.d.ts | 1 + packages/engine-core/dist/index.d.ts.map | 2 +- packages/engine-core/dist/index.js | 1 + packages/engine-core/dist/index.js.map | 2 +- .../dist/ports/headlessMultiplayer.d.ts | 25 +++ .../dist/ports/headlessMultiplayer.d.ts.map | 1 + .../dist/ports/headlessMultiplayer.js | 67 ++++++++ .../dist/ports/headlessMultiplayer.js.map | 1 + packages/engine-core/dist/ports/index.d.ts | 3 + .../engine-core/dist/ports/index.d.ts.map | 2 +- packages/engine-core/dist/ports/index.js | 2 + packages/engine-core/dist/ports/index.js.map | 2 +- .../engine-core/dist/ports/multiplayer.d.ts | 62 +++++++ .../dist/ports/multiplayer.d.ts.map | 1 + .../engine-core/dist/ports/multiplayer.js | 11 ++ .../engine-core/dist/ports/multiplayer.js.map | 1 + .../src/__tests__/eventClassification.test.ts | 29 ++++ .../src/__tests__/itemClaim.test.ts | 23 +++ .../src/__tests__/multiplayerPort.test.ts | 67 ++++++++ .../src/__tests__/multiplayerSession.test.ts | 101 ++++++++++++ .../src/__tests__/netAgnosticism.test.ts | 43 +++++ .../src/__tests__/optimisticReconcile.test.ts | 32 ++++ .../src/__tests__/presence.test.ts | 24 +++ .../src/__tests__/remotePlayersStore.test.ts | 33 ++++ .../src/__tests__/worldStateLww.test.ts | 27 +++ .../engine-core/src/game/commands/types.ts | 6 +- packages/engine-core/src/game/events/types.ts | 8 +- .../src/game/net/MultiplayerSession.ts | 155 ++++++++++++++++++ packages/engine-core/src/game/net/claims.ts | 26 +++ packages/engine-core/src/game/net/clock.ts | 27 +++ .../src/game/net/eventClassification.ts | 58 +++++++ packages/engine-core/src/game/net/index.ts | 9 + .../engine-core/src/game/net/optimistic.ts | 40 +++++ .../src/game/net/playerIdentity.ts | 59 +++++++ .../src/game/net/remotePlayersStore.ts | 63 +++++++ packages/engine-core/src/game/net/throttle.ts | 35 ++++ .../engine-core/src/game/net/worldState.ts | 36 ++++ packages/engine-core/src/index.ts | 1 + .../src/ports/headlessMultiplayer.ts | 96 +++++++++++ packages/engine-core/src/ports/index.ts | 12 ++ packages/engine-core/src/ports/multiplayer.ts | 69 ++++++++ .../dist/GameTouchSpriteRuntime.d.ts.map | 2 +- .../dist/GameTouchSpriteRuntime.js | 46 +++++- .../dist/GameTouchSpriteRuntime.js.map | 2 +- .../hooks/useClickToMoveController.d.ts.map | 2 +- .../dist/hooks/useClickToMoveController.js | 28 +++- .../hooks/useClickToMoveController.js.map | 2 +- packages/engine-renderer-r3f/dist/index.d.ts | 1 + .../engine-renderer-r3f/dist/index.d.ts.map | 2 +- packages/engine-renderer-r3f/dist/index.js | 2 + .../engine-renderer-r3f/dist/index.js.map | 2 +- .../dist/net/RemotePlayers.d.ts | 8 + .../dist/net/RemotePlayers.d.ts.map | 1 + .../dist/net/RemotePlayers.js | 41 +++++ .../dist/net/RemotePlayers.js.map | 1 + packages/engine-renderer-r3f/src/index.ts | 3 + .../src/net/RemotePlayers.tsx | 69 ++++++++ 119 files changed, 2718 insertions(+), 44 deletions(-) create mode 100644 apps/web-demo/app/components/net/RoomLobby.tsx create mode 100644 apps/web-demo/app/lib/net/__tests__/roomSession.test.ts create mode 100644 apps/web-demo/app/lib/net/createMultiplayerRuntime.ts create mode 100644 apps/web-demo/app/lib/net/partyKitAdapter.ts create mode 100644 apps/web-demo/app/lib/net/roomCode.ts create mode 100644 apps/web-demo/app/lib/net/roomCodeStorage.ts create mode 100644 apps/web-demo/app/lib/net/roomSession.ts create mode 100644 apps/web-demo/app/multiplayer/page.tsx create mode 100644 apps/web-demo/party/multiplayer.ts create mode 100644 apps/web-demo/partykit.json create mode 100644 docs/phases/phase-14-multiplayer/validation-report.md create mode 100644 packages/engine-core/dist/game/net/MultiplayerSession.d.ts create mode 100644 packages/engine-core/dist/game/net/MultiplayerSession.d.ts.map create mode 100644 packages/engine-core/dist/game/net/MultiplayerSession.js create mode 100644 packages/engine-core/dist/game/net/MultiplayerSession.js.map create mode 100644 packages/engine-core/dist/game/net/claims.d.ts create mode 100644 packages/engine-core/dist/game/net/claims.d.ts.map create mode 100644 packages/engine-core/dist/game/net/claims.js create mode 100644 packages/engine-core/dist/game/net/claims.js.map create mode 100644 packages/engine-core/dist/game/net/clock.d.ts create mode 100644 packages/engine-core/dist/game/net/clock.d.ts.map create mode 100644 packages/engine-core/dist/game/net/clock.js create mode 100644 packages/engine-core/dist/game/net/clock.js.map create mode 100644 packages/engine-core/dist/game/net/eventClassification.d.ts create mode 100644 packages/engine-core/dist/game/net/eventClassification.d.ts.map create mode 100644 packages/engine-core/dist/game/net/eventClassification.js create mode 100644 packages/engine-core/dist/game/net/eventClassification.js.map create mode 100644 packages/engine-core/dist/game/net/index.d.ts create mode 100644 packages/engine-core/dist/game/net/index.d.ts.map create mode 100644 packages/engine-core/dist/game/net/index.js create mode 100644 packages/engine-core/dist/game/net/index.js.map create mode 100644 packages/engine-core/dist/game/net/optimistic.d.ts create mode 100644 packages/engine-core/dist/game/net/optimistic.d.ts.map create mode 100644 packages/engine-core/dist/game/net/optimistic.js create mode 100644 packages/engine-core/dist/game/net/optimistic.js.map create mode 100644 packages/engine-core/dist/game/net/playerIdentity.d.ts create mode 100644 packages/engine-core/dist/game/net/playerIdentity.d.ts.map create mode 100644 packages/engine-core/dist/game/net/playerIdentity.js create mode 100644 packages/engine-core/dist/game/net/playerIdentity.js.map create mode 100644 packages/engine-core/dist/game/net/remotePlayersStore.d.ts create mode 100644 packages/engine-core/dist/game/net/remotePlayersStore.d.ts.map create mode 100644 packages/engine-core/dist/game/net/remotePlayersStore.js create mode 100644 packages/engine-core/dist/game/net/remotePlayersStore.js.map create mode 100644 packages/engine-core/dist/game/net/throttle.d.ts create mode 100644 packages/engine-core/dist/game/net/throttle.d.ts.map create mode 100644 packages/engine-core/dist/game/net/throttle.js create mode 100644 packages/engine-core/dist/game/net/throttle.js.map create mode 100644 packages/engine-core/dist/game/net/worldState.d.ts create mode 100644 packages/engine-core/dist/game/net/worldState.d.ts.map create mode 100644 packages/engine-core/dist/game/net/worldState.js create mode 100644 packages/engine-core/dist/game/net/worldState.js.map create mode 100644 packages/engine-core/dist/ports/headlessMultiplayer.d.ts create mode 100644 packages/engine-core/dist/ports/headlessMultiplayer.d.ts.map create mode 100644 packages/engine-core/dist/ports/headlessMultiplayer.js create mode 100644 packages/engine-core/dist/ports/headlessMultiplayer.js.map create mode 100644 packages/engine-core/dist/ports/multiplayer.d.ts create mode 100644 packages/engine-core/dist/ports/multiplayer.d.ts.map create mode 100644 packages/engine-core/dist/ports/multiplayer.js create mode 100644 packages/engine-core/dist/ports/multiplayer.js.map create mode 100644 packages/engine-core/src/__tests__/eventClassification.test.ts create mode 100644 packages/engine-core/src/__tests__/itemClaim.test.ts create mode 100644 packages/engine-core/src/__tests__/multiplayerPort.test.ts create mode 100644 packages/engine-core/src/__tests__/multiplayerSession.test.ts create mode 100644 packages/engine-core/src/__tests__/netAgnosticism.test.ts create mode 100644 packages/engine-core/src/__tests__/optimisticReconcile.test.ts create mode 100644 packages/engine-core/src/__tests__/presence.test.ts create mode 100644 packages/engine-core/src/__tests__/remotePlayersStore.test.ts create mode 100644 packages/engine-core/src/__tests__/worldStateLww.test.ts create mode 100644 packages/engine-core/src/game/net/MultiplayerSession.ts create mode 100644 packages/engine-core/src/game/net/claims.ts create mode 100644 packages/engine-core/src/game/net/clock.ts create mode 100644 packages/engine-core/src/game/net/eventClassification.ts create mode 100644 packages/engine-core/src/game/net/index.ts create mode 100644 packages/engine-core/src/game/net/optimistic.ts create mode 100644 packages/engine-core/src/game/net/playerIdentity.ts create mode 100644 packages/engine-core/src/game/net/remotePlayersStore.ts create mode 100644 packages/engine-core/src/game/net/throttle.ts create mode 100644 packages/engine-core/src/game/net/worldState.ts create mode 100644 packages/engine-core/src/ports/headlessMultiplayer.ts create mode 100644 packages/engine-core/src/ports/multiplayer.ts create mode 100644 packages/engine-renderer-r3f/dist/net/RemotePlayers.d.ts create mode 100644 packages/engine-renderer-r3f/dist/net/RemotePlayers.d.ts.map create mode 100644 packages/engine-renderer-r3f/dist/net/RemotePlayers.js create mode 100644 packages/engine-renderer-r3f/dist/net/RemotePlayers.js.map create mode 100644 packages/engine-renderer-r3f/src/net/RemotePlayers.tsx diff --git a/apps/web-demo/app/components/GameTouchCanvas.tsx b/apps/web-demo/app/components/GameTouchCanvas.tsx index 2a1b3e5..b918880 100644 --- a/apps/web-demo/app/components/GameTouchCanvas.tsx +++ b/apps/web-demo/app/components/GameTouchCanvas.tsx @@ -53,6 +53,8 @@ const EMPTY_TRANSITIONS: GameSceneTransition[] = []; type GameTouchCanvasProps = { debug?: boolean; onRuntimeEvent?: (event: RuntimeEvent) => void; + /** Contenido extra dentro del mundo físico (p.ej. en /multiplayer). */ + extraCanvasChildren?: React.ReactNode; }; /** @@ -69,6 +71,7 @@ function SceneReadyReporter({ onReady }: { onReady: () => void }) { export default function GameTouchCanvas({ debug: debugOverride, onRuntimeEvent, + extraCanvasChildren, }: GameTouchCanvasProps = {}) { const selectedCharacter: GameCharacterName = "Dave"; const [sceneReady, setSceneReady] = useState(false); @@ -451,6 +454,7 @@ export default function GameTouchCanvas({ debug={runtimeDebug} onTransitionTriggered={handleTransitionTriggered} /> + {extraCanvasChildren} diff --git a/apps/web-demo/app/components/net/RoomLobby.tsx b/apps/web-demo/app/components/net/RoomLobby.tsx new file mode 100644 index 0000000..01c1926 --- /dev/null +++ b/apps/web-demo/app/components/net/RoomLobby.tsx @@ -0,0 +1,69 @@ +"use client"; +import { useState } from "react"; + +export interface RoomLobbyProps { + code: string | null; + remoteCount: number; // otros jugadores en mi escena + capacity: number; // 4 + displayName: string; + onCreate: () => void; + onJoin: (code: string) => void; + onReset: () => void; + onRename: (name: string) => void; +} + +export function RoomLobby(p: RoomLobbyProps) { + const [joinCode, setJoinCode] = useState(""); + const total = p.remoteCount + 1; + const missing = p.capacity - total; + return ( +
+ {!p.code ? ( +
+ + setJoinCode(e.target.value)} + /> + +
+ ) : ( +
+
+ Room: {p.code}{" "} + +
+
+ Jugadores:{" "} + + {total}/{p.capacity} + +
+ {missing > 0 && ( +
Faltan {missing} jugador(es)…
+ )} + p.onRename(e.target.value)} /> + +
+ )} +
+ ); +} diff --git a/apps/web-demo/app/lib/net/__tests__/roomSession.test.ts b/apps/web-demo/app/lib/net/__tests__/roomSession.test.ts new file mode 100644 index 0000000..9439b10 --- /dev/null +++ b/apps/web-demo/app/lib/net/__tests__/roomSession.test.ts @@ -0,0 +1,47 @@ +import { describe, it, expect } from "vitest"; +import { createRoomSession, MAX_PLAYERS } from "../roomSession"; +import { generateRoomCode, isValidRoomCode } from "../roomCode"; +import { NoopStorageAdapter } from "../../platform-web"; + +describe("roomSession", () => { + it("generates valid codes without ambiguous chars", () => { + const c = generateRoomCode(() => 0); + expect(isValidRoomCode(c)).toBe(true); + expect(c).not.toMatch(/[0O1I]/); + }); + it("create persists and restore returns it", () => { + const s1 = new NoopStorageAdapter(); + const a = createRoomSession(s1); + const code = a.create(); + const b = createRoomSession(s1); + expect(b.restore()).toBe(code); + }); + it("reset produces a fresh code", () => { + let calls = 0; + // rng determinista que cambia entre llamadas para garantizar códigos distintos + const rng = () => { + calls += 1; + return (calls % 31) / 31; + }; + const s = createRoomSession(new NoopStorageAdapter(), rng); + const first = s.create(); + const second = s.reset(); + expect(second).not.toBe(first); + }); + it("capacity helpers reflect N/4", () => { + const s = createRoomSession(new NoopStorageAdapter()); + expect(s.freeSlots(0)).toBe(MAX_PLAYERS - 1); // solo yo → 3 libres + expect(s.isFull(3)).toBe(true); // 3 remotos + yo = 4 + }); + it("join rejects invalid codes", () => { + const s = createRoomSession(new NoopStorageAdapter()); + expect(() => s.join("xx")).toThrow(); + }); + it("forget clears persisted code", () => { + const storage = new NoopStorageAdapter(); + const s = createRoomSession(storage); + s.create(); + s.forget(); + expect(createRoomSession(storage).restore()).toBeNull(); + }); +}); diff --git a/apps/web-demo/app/lib/net/createMultiplayerRuntime.ts b/apps/web-demo/app/lib/net/createMultiplayerRuntime.ts new file mode 100644 index 0000000..e04d464 --- /dev/null +++ b/apps/web-demo/app/lib/net/createMultiplayerRuntime.ts @@ -0,0 +1,67 @@ +import { createGameRuntime, type GameSceneConfig } from "../engine/publicApi"; +import { + createMultiplayerSession, + createRemotePlayersStore, + createSelfDescriptor, + getSceneState, + type GameEvent, + type RemotePlayersStore, +} from "@pointclick-engine/engine-core"; +import { createPartyKitAdapter } from "./partyKitAdapter"; + +export interface MultiplayerRuntime { + remotePlayers: RemotePlayersStore; + setName: (name: string) => void; + dispose: () => void; +} + +type RuntimeConfig = NonNullable[0]>; + +export function createMultiplayerRuntime(opts: { + room: string; + host: string; + scenes: GameSceneConfig[]; + displayName: string; + inventoryAdapter?: RuntimeConfig["inventoryAdapter"]; + dialogAdapter?: RuntimeConfig["dialogAdapter"]; +}): MultiplayerRuntime { + const runtime = createGameRuntime({ + scenes: opts.scenes, + inventoryAdapter: opts.inventoryAdapter, + dialogAdapter: opts.dialogAdapter, + }); + const remotePlayers = createRemotePlayersStore(); + const port = createPartyKitAdapter(opts.host); + const scene = getSceneState(); + + const session = createMultiplayerSession({ + port, + bus: runtime, // el handle cumple SessionBus (on/emit) + room: opts.room, + self: createSelfDescriptor({ + playerId: globalThis.crypto?.randomUUID?.() ?? `p-${Date.now()}`, + sceneId: scene.sceneId, + position: scene.playerPosition, + displayName: opts.displayName, + }), + remotePlayers, + // Re-emite el evento world remoto al bus local. La sesión activa `applyingRemote` + // mientras corre esto, así que NO se vuelve a difundir (anti-bucle). Los suscriptores + // del demo (audio, door… vía runtime.on) reaccionan al evento compartido. + applyRemoteEvent: (event: GameEvent) => runtime.emit(event), + presenceThrottleMs: 80, + }); + + // Limpia jugadores desconectados cada 5s. + const prune = setInterval(() => remotePlayers.pruneStale(8000), 5000); + + return { + remotePlayers, + setName: (name) => session.updateSelf({ displayName: name }), + dispose: () => { + clearInterval(prune); + session.dispose(); + runtime.dispose(); + }, + }; +} diff --git a/apps/web-demo/app/lib/net/partyKitAdapter.ts b/apps/web-demo/app/lib/net/partyKitAdapter.ts new file mode 100644 index 0000000..0ac3f8d --- /dev/null +++ b/apps/web-demo/app/lib/net/partyKitAdapter.ts @@ -0,0 +1,56 @@ +import { PartySocket } from "partysocket"; +import type { + MultiplayerPort, + NetEnvelope, + ConnectOptions, + ConnectionStatus, +} from "@pointclick-engine/engine-core"; + +/** Adapter PartyKit. `host` = NEXT_PUBLIC_PARTYKIT_HOST (p.ej. "127.0.0.1:1999" en dev). */ +export function createPartyKitAdapter(host: string): MultiplayerPort { + let socket: PartySocket | null = null; + let msgHandlers: Array<(m: NetEnvelope) => void> = []; + let statusHandlers: Array<(s: ConnectionStatus) => void> = []; + + return { + connect(opts: ConnectOptions) { + statusHandlers.forEach((h) => h({ state: "connecting" })); + socket = new PartySocket({ host, party: "multiplayer", room: opts.room }); + socket.addEventListener("message", (e: MessageEvent) => { + let env: { kind?: string; payload?: unknown }; + try { + env = JSON.parse(e.data as string); + } catch { + return; + } + if (env.kind === "status") { + statusHandlers.forEach((h) => h(env.payload as ConnectionStatus)); + return; + } + msgHandlers.forEach((h) => h(env as NetEnvelope)); + }); + socket.addEventListener("close", () => + statusHandlers.forEach((h) => h({ state: "disconnected" })), + ); + }, + disconnect() { + socket?.close(); + socket = null; + }, + send(m: NetEnvelope) { + socket?.send(JSON.stringify(m)); + }, + onMessage(h) { + msgHandlers.push(h); + return () => { + msgHandlers = msgHandlers.filter((x) => x !== h); + }; + }, + onStatus(h) { + statusHandlers.push(h); + return () => { + statusHandlers = statusHandlers.filter((x) => x !== h); + }; + }, + }; +} diff --git a/apps/web-demo/app/lib/net/roomCode.ts b/apps/web-demo/app/lib/net/roomCode.ts new file mode 100644 index 0000000..98524e6 --- /dev/null +++ b/apps/web-demo/app/lib/net/roomCode.ts @@ -0,0 +1,20 @@ +const ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"; // sin 0/O/1/I ambiguos +export const ROOM_CODE_LENGTH = 6; + +export function generateRoomCode(rng: () => number = Math.random): string { + let out = ""; + for (let i = 0; i < ROOM_CODE_LENGTH; i++) { + out += ALPHABET[Math.floor(rng() * ALPHABET.length)]; + } + return out; +} + +export function isValidRoomCode(code: string): boolean { + return new RegExp(`^[${ALPHABET}]{${ROOM_CODE_LENGTH}}$`).test( + code.toUpperCase(), + ); +} + +export function normalizeRoomCode(code: string): string { + return code.trim().toUpperCase(); +} diff --git a/apps/web-demo/app/lib/net/roomCodeStorage.ts b/apps/web-demo/app/lib/net/roomCodeStorage.ts new file mode 100644 index 0000000..c0b305d --- /dev/null +++ b/apps/web-demo/app/lib/net/roomCodeStorage.ts @@ -0,0 +1,12 @@ +import type { StoragePort } from "../platform-web"; + +export const ROOM_CODE_STORAGE_KEY = "pce:multiplayer:roomCode"; + +/** Persiste el último código de room (reutilizable al volver). */ +export function createRoomCodeStorage(storage: StoragePort) { + return { + load: (): string | null => storage.getItem(ROOM_CODE_STORAGE_KEY), + save: (code: string): void => storage.setItem(ROOM_CODE_STORAGE_KEY, code), + clear: (): void => storage.removeItem(ROOM_CODE_STORAGE_KEY), + }; +} diff --git a/apps/web-demo/app/lib/net/roomSession.ts b/apps/web-demo/app/lib/net/roomSession.ts new file mode 100644 index 0000000..f37d3e1 --- /dev/null +++ b/apps/web-demo/app/lib/net/roomSession.ts @@ -0,0 +1,58 @@ +import { generateRoomCode, normalizeRoomCode, isValidRoomCode } from "./roomCode"; +import { createRoomCodeStorage } from "./roomCodeStorage"; +import type { StoragePort } from "../platform-web"; + +export const MAX_PLAYERS = 4; + +export interface RoomSession { + /** Código activo (null si aún no se ha creado/unido). */ + getCode: () => string | null; + /** Crea una room nueva (genera código), la persiste y la devuelve. */ + create: () => string; + /** Une a un código existente (valida + persiste). Lanza si inválido. */ + join: (code: string) => string; + /** Reset: nueva room vacía (solo-play hasta que entre alguien). */ + reset: () => string; + /** Olvida el código persistido (empezar limpio). */ + forget: () => void; + /** Restaura el último código guardado, si existe. */ + restore: () => string | null; + capacity: number; + isFull: (remoteCount: number) => boolean; + freeSlots: (remoteCount: number) => number; +} + +export function createRoomSession( + storage: StoragePort, + rng: () => number = Math.random, +): RoomSession { + const persist = createRoomCodeStorage(storage); + let code: string | null = null; + const setCode = (c: string) => { + code = c; + persist.save(c); + return c; + }; + return { + getCode: () => code, + create: () => setCode(generateRoomCode(rng)), + join: (raw) => { + const c = normalizeRoomCode(raw); + if (!isValidRoomCode(c)) throw new Error(`código inválido: ${raw}`); + return setCode(c); + }, + reset: () => setCode(generateRoomCode(rng)), + forget: () => { + code = null; + persist.clear(); + }, + restore: () => { + code = persist.load(); + return code; + }, + capacity: MAX_PLAYERS, + // remoteCount = otros jugadores; +1 = yo + isFull: (remoteCount) => remoteCount + 1 >= MAX_PLAYERS, + freeSlots: (remoteCount) => Math.max(0, MAX_PLAYERS - (remoteCount + 1)), + }; +} diff --git a/apps/web-demo/app/multiplayer/page.tsx b/apps/web-demo/app/multiplayer/page.tsx new file mode 100644 index 0000000..9f3b162 --- /dev/null +++ b/apps/web-demo/app/multiplayer/page.tsx @@ -0,0 +1,79 @@ +"use client"; +import { useEffect, useMemo, useReducer, useRef, useState } from "react"; +import GameTouchCanvas from "../components/GameTouchCanvas"; +import { RemotePlayers } from "@pointclick-engine/engine-renderer-r3f"; +import { useSceneStore, generateRandomName } from "@pointclick-engine/engine-core"; +import { SCENES } from "../../demo-content/scenes/scenes"; +import type { GameSceneConfig } from "../lib/engine/publicApi"; +import { + createMultiplayerRuntime, + type MultiplayerRuntime, +} from "../lib/net/createMultiplayerRuntime"; +import { createRoomSession } from "../lib/net/roomSession"; +import { localStorageAdapter } from "../lib/platform-web"; +import { RoomLobby } from "../components/net/RoomLobby"; + +const HOST = process.env.NEXT_PUBLIC_PARTYKIT_HOST ?? "127.0.0.1:1999"; + +export default function MultiplayerPage() { + const room = useMemo(() => createRoomSession(localStorageAdapter), []); + const [code, setCode] = useState(null); + const [name, setName] = useState(() => generateRandomName()); + const mpRef = useRef(null); + const [, force] = useReducer((x: number) => x + 1, 0); + const sceneId = useSceneStore((s) => s.sceneId); + + useEffect(() => { + if (!code) return; + const mp = createMultiplayerRuntime({ + room: code, + host: HOST, + displayName: name, + scenes: Object.values(SCENES) as GameSceneConfig[], + }); + mpRef.current = mp; + const unsub = mp.remotePlayers.subscribe(() => force()); // refresca el contador N/4 + return () => { + unsub(); + mp.dispose(); + mpRef.current = null; + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [code]); + + const remoteCount = mpRef.current?.remotePlayers.getInScene(sceneId).length ?? 0; + + return ( + <> + + ) : null + } + /> + setCode(room.create())} + onJoin={(c) => { + try { + setCode(room.join(c)); + } catch { + alert("código inválido"); + } + }} + onReset={() => setCode(room.reset())} + onRename={(n) => { + setName(n); + mpRef.current?.setName(n); + }} + /> + + ); +} diff --git a/apps/web-demo/package.json b/apps/web-demo/package.json index c951a4c..bdfc7df 100644 --- a/apps/web-demo/package.json +++ b/apps/web-demo/package.json @@ -8,7 +8,9 @@ "build": "next build", "start": "next start", "lint": "eslint", - "test": "vitest run" + "test": "vitest run", + "party:dev": "partykit dev", + "party:deploy": "partykit deploy" }, "dependencies": { "@pointclick-engine/engine-core": "file:../../packages/engine-core", diff --git a/apps/web-demo/party/multiplayer.ts b/apps/web-demo/party/multiplayer.ts new file mode 100644 index 0000000..492ebc4 --- /dev/null +++ b/apps/web-demo/party/multiplayer.ts @@ -0,0 +1,82 @@ +import type * as Party from "partykit/server"; + +const MAX_PLAYERS = 4; + +/** + * Servidor PartyKit de la partida. Es la autoridad: mantiene el snapshot del + * world, hace fan-out de los sobres y aplica el límite de capacidad (4). + * + * room.id = código de partida (ver app/lib/net/roomSession.ts). + */ +export default class MultiplayerServer implements Party.Server { + /** Snapshot LWW del world (registros `${entityId}:${field}` → {value,ts,by}). */ + private world: Record = {}; + + constructor(readonly room: Party.Room) {} + + onConnect(conn: Party.Connection) { + const count = [...this.room.getConnections()].length; // incluye a `conn` + if (count > MAX_PLAYERS) { + conn.send( + JSON.stringify({ + kind: "status", + payload: { state: "disconnected", reason: "room-full" }, + }), + ); + conn.close(); + return; + } + // 1) snapshot del world 2) status connected con el id asignado + conn.send( + JSON.stringify({ + v: 1, + room: this.room.id, + from: "server", + ts: Date.now(), + kind: "snapshot", + payload: this.world, + }), + ); + conn.send( + JSON.stringify({ + kind: "status", + payload: { state: "connected", selfId: conn.id }, + }), + ); + } + + onMessage(message: string, sender: Party.Connection) { + let env: { kind?: string; payload?: unknown }; + try { + env = JSON.parse(message); + } catch { + return; + } + if (env.kind === "event") this.applyWorldEvent(env.payload); + // fan-out a todos menos el emisor + this.room.broadcast(message, [sender.id]); + } + + onClose(conn: Party.Connection) { + this.room.broadcast( + JSON.stringify({ + v: 1, + room: this.room.id, + from: conn.id, + ts: Date.now(), + kind: "presence", + payload: { playerId: conn.id, __left: true }, + }), + ); + } + + /** Aplica un evento world al snapshot (item placed/removed). Simplificado. */ + private applyWorldEvent(payload: unknown) { + const e = payload as { type?: string; itemId?: string; outcome?: string }; + if (e?.type === "item:dropped" && e.itemId) { + const key = `item:${e.itemId}:placed`; + this.world[key] = { value: e.outcome === "place", ts: Date.now(), by: "server" }; + } + // Extiende para puertas/interaction-state según las escenas de la demo. + } +} diff --git a/apps/web-demo/partykit.json b/apps/web-demo/partykit.json new file mode 100644 index 0000000..02bf6af --- /dev/null +++ b/apps/web-demo/partykit.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://www.partykit.io/schema.json", + "name": "pointclick-multiplayer", + "main": "party/multiplayer.ts", + "parties": { "multiplayer": "party/multiplayer.ts" }, + "compatibilityDate": "2024-01-01" +} diff --git a/docs/phases/phase-14-multiplayer/tasks/01-define-multiplayer-port.md b/docs/phases/phase-14-multiplayer/tasks/01-define-multiplayer-port.md index 651cd32..aa7e675 100644 --- a/docs/phases/phase-14-multiplayer/tasks/01-define-multiplayer-port.md +++ b/docs/phases/phase-14-multiplayer/tasks/01-define-multiplayer-port.md @@ -110,20 +110,22 @@ import type { * Bus en memoria que conecta varios HeadlessMultiplayerAdapter (simula la red * en tests). Reenvía cada `send` a los demás adapters de la MISMA room. */ +interface HubPeer { room: string; inbound: (m: NetEnvelope) => void; } + export class InMemoryHub { - private peers = new Map void>(); + private peers = new Map(); - register(id: PlayerId, inbound: (m: NetEnvelope) => void): () => void { - this.peers.set(id, inbound); + register(id: PlayerId, room: string, inbound: (m: NetEnvelope) => void): () => void { + this.peers.set(id, { room, inbound }); return () => this.peers.delete(id); } - /** Fan-out a todos menos al emisor (sin self-echo). */ - broadcast(from: PlayerId, room: string, message: NetEnvelope): void { - for (const [id, inbound] of this.peers) { + /** Fan-out a los peers de la MISMA room que el mensaje, menos al emisor. */ + broadcast(from: PlayerId, _room: string, message: NetEnvelope): void { + for (const [id, peer] of this.peers) { if (id === from) continue; - if (message.room !== room) continue; - inbound(message); + if (peer.room !== message.room) continue; // aísla por room del receptor + peer.inbound(message); } } } @@ -146,7 +148,7 @@ export class HeadlessMultiplayerAdapter implements MultiplayerPort { connect(opts: ConnectOptions): void { this.room = opts.room; this.connected = true; - this.unregister = this.hub.register(this.selfId, (m) => { + this.unregister = this.hub.register(this.selfId, this.room, (m) => { this.msgHandlers.forEach((h) => h(m)); }); this.emitStatus({ state: "connected", selfId: this.selfId }); diff --git a/docs/phases/phase-14-multiplayer/tracking.md b/docs/phases/phase-14-multiplayer/tracking.md index 54ae080..222d50d 100644 --- a/docs/phases/phase-14-multiplayer/tracking.md +++ b/docs/phases/phase-14-multiplayer/tracking.md @@ -3,30 +3,32 @@ > Marca `[x]` al completar. Detalle en cada task file. Ver `docs/workflow/how-to-track-tasks.md`. ## Week 1 — Fundamentos agnósticos (core) -- [ ] [01-define-multiplayer-port](tasks/01-define-multiplayer-port.md) -- [ ] [02-state-partition-classification](tasks/02-state-partition-classification.md) -- [ ] [03-player-identity-model](tasks/03-player-identity-model.md) +- [x] [01-define-multiplayer-port](tasks/01-define-multiplayer-port.md) +- [x] [02-state-partition-classification](tasks/02-state-partition-classification.md) +- [x] [03-player-identity-model](tasks/03-player-identity-model.md) ## Week 2 — Replicación -- [ ] [04-replication-engine](tasks/04-replication-engine.md) -- [ ] [06-presence-and-interest-management](tasks/06-presence-and-interest-management.md) +- [x] [04-replication-engine](tasks/04-replication-engine.md) +- [x] [06-presence-and-interest-management](tasks/06-presence-and-interest-management.md) ## Week 3 — Render + adapter PartyKit + rooms -- [ ] [07-renderer-remote-avatars](tasks/07-renderer-remote-avatars.md) -- [ ] [08-transport-adapters-and-vercel](tasks/08-transport-adapters-and-vercel.md) (PartyKit) +- [x] [07-renderer-remote-avatars](tasks/07-renderer-remote-avatars.md) +- [x] [08-transport-adapters-and-vercel](tasks/08-transport-adapters-and-vercel.md) (PartyKit) - [ ] [10-room-session-lifecycle](tasks/10-room-session-lifecycle.md) (código, join, solo, reset, cap 4) ## Week 4 — Autoridad y robustez (segunda iteración) -- [ ] [05-authority-and-conflict-resolution](tasks/05-authority-and-conflict-resolution.md) -- [ ] [09-optimistic-prediction-reconciliation](tasks/09-optimistic-prediction-reconciliation.md) +- [x] [05-authority-and-conflict-resolution](tasks/05-authority-and-conflict-resolution.md) +- [x] [09-optimistic-prediction-reconciliation](tasks/09-optimistic-prediction-reconciliation.md) ## Week 5 — Demo /multiplayer + validación -- [ ] [11-demo-multiplayer-route](tasks/11-demo-multiplayer-route.md) (ruta `/multiplayer`, lobby, RemotePlayers) -- [ ] [12-validation-gate](tasks/12-validation-gate.md) (tests + build + agnosticismo + escenarios A–E) +- [x] [11-demo-multiplayer-route](tasks/11-demo-multiplayer-route.md) (ruta `/multiplayer`, lobby, RemotePlayers) +- [~] [12-validation-gate](tasks/12-validation-gate.md) — gate automático ✅; escenarios two-tab E2E pendientes de run manual --- ## Gates -- [ ] Test de agnosticismo del core verde (sin imports de red/`window`/localStorage) -- [ ] No regresión single-player (suite actual pasa sin `MultiplayerPort`) -- [ ] Demo two-tab manual: presence + world + claim + room (código/solo/reset/cap 4) verificados +- [x] Test de agnosticismo del core verde (sin imports de red/`window`/localStorage) +- [x] No regresión single-player (suite actual pasa sin `MultiplayerPort`; fallos web-demo son pre-existentes) +- [ ] Demo two-tab manual: presence + room (código/solo/reset/cap 4) — pendiente de run con `party:dev` + +> Estado: **MVP implementado** (tasks 01–11). Ver `validation-report.md`. 273 tests core + 6 roomSession verdes. diff --git a/docs/phases/phase-14-multiplayer/validation-report.md b/docs/phases/phase-14-multiplayer/validation-report.md new file mode 100644 index 0000000..8ed8623 --- /dev/null +++ b/docs/phases/phase-14-multiplayer/validation-report.md @@ -0,0 +1,53 @@ +# Phase 14 — Validation Report (MVP implementation) + +**Fecha**: 2026-06-10 | **Rama**: `claude/phase-14-multiplayer-impl` + +## Alcance implementado + +MVP de presencia en tiempo real + rooms por código, end-to-end. Tasks 01–11 implementadas; +task 12 (gate) parcialmente: gate automático ✅, escenarios E2E de dos pestañas pendientes de run +manual (requieren `partykit dev` + navegador, no verificable headless). + +## Gate automático + +| Check | Resultado | +|-------|-----------| +| `npm test -w packages/engine-core` | ✅ **273 passed** (37 files) — +29 tests nuevos sobre baseline 244 | +| `npm test -w apps/web-demo` (roomSession) | ✅ **6/6** roomSession | +| Test de agnosticismo del core (`netAgnosticism.test.ts`) | ✅ verde (game/net + ports/multiplayer sin red/`window`/`localStorage`) | +| `npm run build -w packages/engine-core` (tsc) | ✅ | +| `npm run build -w packages/engine-renderer-r3f` (tsc) | ✅ | +| `tsc --noEmit` app — **archivos nuevos** | ✅ **0 errores** en `lib/net/`, `multiplayer/`, `party/`, `components/net/`, `RemotePlayers` | +| No regresión single-player | ✅ los únicos fallos (4 en `publicApi.test.ts`, 10 errores tsc en 2 test files) **pre-existen en main** (verificado por stash) | + +### Tests nuevos del core (29) +`multiplayerPort` (4), `eventClassification` (5), `remotePlayersStore` (4), `worldStateLww` (3), +`itemClaim` (3), `presence`/throttle (1), `optimisticReconcile` (3), `multiplayerSession` (5 — +replica world, bloquea private, anti-eco, presence join, propaga posición), `netAgnosticism` (1). + +## Escenarios manuales (pendientes de run con servidor) + +Requieren `npm run party:dev` + `npm run dev` y dos pestañas en `/multiplayer`: + +| # | Escenario | Estado | +|---|-----------|--------| +| A | Presence por escena (avatares en misma escena) | ⏳ manual — lógica cubierta por `multiplayerSession.test.ts` | +| E | Room lifecycle (código/join/solo/`N/4`/reset/cap 4) | ⏳ manual — lógica cubierta por `roomSession.test.ts` (cap 4 server-side en `party/multiplayer.ts`) | +| B/C/D | Puerta/llave/claim world compartido | ⏳ 2ª iteración (item-sync completo) | + +## Notas de implementación (desviaciones del plan) + +- `InMemoryHub.register(id, room, inbound)` lleva la room del peer y `broadcast` filtra por + `message.room` (aísla rooms correctamente). El doc de task 01 se actualizó para reflejarlo. +- Deps añadidas a `apps/web-demo`: `partysocket` (cliente) y `partykit` (servidor/CLI). +- E2E real (dos navegadores) no es verificable en entorno headless; queda documentado el comando. + +## Cómo probar en local + +```bash +# Terminal 1: servidor PartyKit +npm run party:dev -w apps/web-demo +# Terminal 2: Next +npm run dev -w apps/web-demo +# Abre http://localhost:3000/multiplayer en dos pestañas → Crear / Unirse con el código +``` diff --git a/packages/engine-core/dist/game/commands/types.d.ts b/packages/engine-core/dist/game/commands/types.d.ts index b411cc8..e1f402d 100644 --- a/packages/engine-core/dist/game/commands/types.d.ts +++ b/packages/engine-core/dist/game/commands/types.d.ts @@ -57,6 +57,15 @@ export type GameCommand = { type: "i18n:registerDictionary"; locale: Locale; dict: DialogDictionary; +} | { + type: "net:join"; + room: string; + displayName?: string; +} | { + type: "net:leave"; +} | { + type: "net:setName"; + displayName: string; }; export type GameCommandType = GameCommand["type"]; export {}; diff --git a/packages/engine-core/dist/game/commands/types.d.ts.map b/packages/engine-core/dist/game/commands/types.d.ts.map index ad62c13..960689c 100644 --- a/packages/engine-core/dist/game/commands/types.d.ts.map +++ b/packages/engine-core/dist/game/commands/types.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/game/commands/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAGlF,KAAK,eAAe,GAAG,QAAQ,GAAG,aAAa,CAAC;AAEhD;;;GAGG;AACH,MAAM,MAAM,WAAW,GAEnB;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,GAEzB;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GAE7C;IAAE,IAAI,EAAE,kBAAkB,CAAA;CAAE,GAC5B;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAE7D;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAE1B;IAAE,IAAI,EAAE,qBAAqB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAEnD;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,aAAa,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GACtF;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,MAAM,EAAE,eAAe,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GACnE;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,MAAM,EAAE,eAAe,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAEpE;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,yBAAyB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,gBAAgB,CAAA;CAAE,CAAC;AAEhF,MAAM,MAAM,eAAe,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC"} \ No newline at end of file +{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/game/commands/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAGlF,KAAK,eAAe,GAAG,QAAQ,GAAG,aAAa,CAAC;AAEhD;;;GAGG;AACH,MAAM,MAAM,WAAW,GAEnB;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,GAEzB;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GAE7C;IAAE,IAAI,EAAE,kBAAkB,CAAA;CAAE,GAC5B;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAE7D;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAE1B;IAAE,IAAI,EAAE,qBAAqB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAEnD;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,aAAa,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GACtF;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,MAAM,EAAE,eAAe,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GACnE;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,MAAM,EAAE,eAAe,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAEpE;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,yBAAyB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAE3E;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GACxD;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjD,MAAM,MAAM,eAAe,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC"} \ No newline at end of file diff --git a/packages/engine-core/dist/game/events/types.d.ts b/packages/engine-core/dist/game/events/types.d.ts index e00bd18..9758c78 100644 --- a/packages/engine-core/dist/game/events/types.d.ts +++ b/packages/engine-core/dist/game/events/types.d.ts @@ -1,4 +1,6 @@ import type { AudioSettings, GameScene, GameVec3, Locale, SoundCategory } from "../types"; +import type { PlayerDescriptor } from "../net/playerIdentity"; +import type { ConnectionStatus, PlayerId } from "../../ports/multiplayer"; /** * Union exhaustiva de todos los eventos que el motor puede emitir. * Naming: : (ver ADR-0006). @@ -84,6 +86,15 @@ export type GameEvent = { type: "i18n:dictionaryUpdated"; locale: Locale; keysAdded: number; +} | { + type: "net:playerJoined"; + player: PlayerDescriptor; +} | { + type: "net:playerLeft"; + playerId: PlayerId; +} | { + type: "net:status"; + status: ConnectionStatus; }; export type GameEventType = GameEvent["type"]; export type GameEventHandler = (event: Extract= the physics collider halfX (0.55) minus the +// obstacle padding (0.6) so the net clearance from obstacle surface is > 0. +const PLAYER_PATH_HALF_WIDTH = 0.28; const NEIGHBOR_OFFSETS = [ [-1, -1], [-1, 0], @@ -26,7 +32,7 @@ export function findPath({ start, goal, bounds, walls, interactions, cellSize = .filter((interaction) => interaction.hasCollision) .map((interaction) => toObstacle(interaction.position[0], interaction.position[2], interaction.halfSize[0], interaction.halfSize[2], interaction.rotationY ?? 0, interactionPadding)), ]; - if (isSegmentClear(start, goal, bounds, obstacles, segmentSampleStep)) { + if (isThickSegmentClear(start, goal, bounds, obstacles, segmentSampleStep)) { return [goal]; } const width = Math.max(1, Math.floor((bounds.maxX - bounds.minX) / cellSize) + 1); @@ -260,7 +266,7 @@ function smoothPath(points, bounds, obstacles, segmentSampleStep) { while (anchorIndex < points.length - 1) { let nextIndex = points.length - 1; while (nextIndex > anchorIndex + 1) { - if (isSegmentClear(points[anchorIndex], points[nextIndex], bounds, obstacles, segmentSampleStep)) { + if (isThickSegmentClear(points[anchorIndex], points[nextIndex], bounds, obstacles, segmentSampleStep)) { break; } nextIndex -= 1; @@ -297,6 +303,27 @@ function findNearestOpenCell(cell, width, height, blocked) { } return null; } +/** + * Like isSegmentClear but also checks two paths offset perpendicular to the + * movement direction by PLAYER_PATH_HALF_WIDTH. This prevents path smoothing + * from creating shortcuts that clip obstacle corners: even if the centre line + * is clear, a shortcut is only allowed when the full swept width of the player + * would fit without touching a padded obstacle boundary. + */ +function isThickSegmentClear(start, goal, bounds, obstacles, segmentSampleStep) { + if (!isSegmentClear(start, goal, bounds, obstacles, segmentSampleStep)) { + return false; + } + const dx = goal.x - start.x; + const dz = goal.z - start.z; + const len = Math.hypot(dx, dz); + if (len < 0.001) + return true; + const perpX = (-dz / len) * PLAYER_PATH_HALF_WIDTH; + const perpZ = (dx / len) * PLAYER_PATH_HALF_WIDTH; + return (isSegmentClear({ x: start.x + perpX, z: start.z + perpZ }, { x: goal.x + perpX, z: goal.z + perpZ }, bounds, obstacles, segmentSampleStep) && + isSegmentClear({ x: start.x - perpX, z: start.z - perpZ }, { x: goal.x - perpX, z: goal.z - perpZ }, bounds, obstacles, segmentSampleStep)); +} function isSegmentClear(start, goal, bounds, obstacles, segmentSampleStep) { const distance = Math.hypot(goal.x - start.x, goal.z - start.z); const samples = Math.max(1, Math.ceil(distance / segmentSampleStep)); diff --git a/packages/engine-core/dist/game/logic/pathfinding/findPath.js.map b/packages/engine-core/dist/game/logic/pathfinding/findPath.js.map index 7a93b0f..5d37184 100644 --- a/packages/engine-core/dist/game/logic/pathfinding/findPath.js.map +++ b/packages/engine-core/dist/game/logic/pathfinding/findPath.js.map @@ -1 +1 @@ -{"version":3,"file":"findPath.js","sourceRoot":"","sources":["../../../../src/game/logic/pathfinding/findPath.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"findPath.js","sourceRoot":"","sources":["../../../../src/game/logic/pathfinding/findPath.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/MultiplayerSession.d.ts b/packages/engine-core/dist/game/net/MultiplayerSession.d.ts new file mode 100644 index 0000000..a3ac8f7 --- /dev/null +++ b/packages/engine-core/dist/game/net/MultiplayerSession.d.ts @@ -0,0 +1,36 @@ +import type { GameEvent, GameEventType } from "../events/types"; +import type { MultiplayerPort, RoomId } from "../../ports/multiplayer"; +import type { PlayerDescriptor } from "./playerIdentity"; +import type { RemotePlayersStore } from "./remotePlayersStore"; +import { type ThrottleClock } from "./throttle"; +import type { OptimisticReconciler } from "./optimistic"; +/** Bus mínimo que la sesión necesita (lo cumple el handle de createGameRuntime). */ +export interface SessionBus { + on: (type: GameEventType, handler: (e: GameEvent) => void) => () => void; + emit: (event: GameEvent) => void; +} +export interface MultiplayerSessionOptions { + port: MultiplayerPort; + bus: SessionBus; + room: RoomId; + self: PlayerDescriptor; + remotePlayers: RemotePlayersStore; + /** Aplica un evento world remoto al estado local (el host lo cablea a los stores). */ + applyRemoteEvent: (event: GameEvent) => void; + /** Reloj lógico para `ts`. Default Date.now (task 05 puede inyectar HLC). */ + now?: () => number; + /** ms entre envíos de presence. Default 80 (~12.5 Hz). 0 = sin throttle. */ + presenceThrottleMs?: number; + /** Reloj/scheduler para el throttle (inyectable en tests). */ + clock?: ThrottleClock; + /** Reconciliador optimista (task 09) para claim-result/snapshot. */ + reconciler?: OptimisticReconciler; +} +export interface MultiplayerSession { + dispose: () => void; + getSelf: () => PlayerDescriptor; + /** Actualiza el descriptor local y difunde presence (usado por setName/task 06). */ + updateSelf: (patch: Partial) => void; +} +export declare function createMultiplayerSession(opts: MultiplayerSessionOptions): MultiplayerSession; +//# sourceMappingURL=MultiplayerSession.d.ts.map \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/MultiplayerSession.d.ts.map b/packages/engine-core/dist/game/net/MultiplayerSession.d.ts.map new file mode 100644 index 0000000..476ebb0 --- /dev/null +++ b/packages/engine-core/dist/game/net/MultiplayerSession.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"MultiplayerSession.d.ts","sourceRoot":"","sources":["../../../src/game/net/MultiplayerSession.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAe,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEpF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE/D,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAClE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEzD,oFAAoF;AACpF,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,CAAC,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,SAAS,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;IACzE,IAAI,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;CAClC;AAED,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,eAAe,CAAC;IACtB,GAAG,EAAE,UAAU,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,gBAAgB,CAAC;IACvB,aAAa,EAAE,kBAAkB,CAAC;IAClC,sFAAsF;IACtF,gBAAgB,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;IAC7C,6EAA6E;IAC7E,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,4EAA4E;IAC5E,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,8DAA8D;IAC9D,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,oEAAoE;IACpE,UAAU,CAAC,EAAE,oBAAoB,CAAC;CACnC;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,gBAAgB,CAAC;IAChC,oFAAoF;IACpF,UAAU,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;CACxD;AAED,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,yBAAyB,GAC9B,kBAAkB,CAgHpB"} \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/MultiplayerSession.js b/packages/engine-core/dist/game/net/MultiplayerSession.js new file mode 100644 index 0000000..b5511e9 --- /dev/null +++ b/packages/engine-core/dist/game/net/MultiplayerSession.js @@ -0,0 +1,118 @@ +import { NET_PROTOCOL_VERSION } from "../../ports/multiplayer"; +import { EVENT_CLASSIFICATION, shouldReplicate, isWorld } from "./eventClassification"; +import { throttleTrailing } from "./throttle"; +export function createMultiplayerSession(opts) { + const { port, bus, room, remotePlayers, applyRemoteEvent } = opts; + const now = opts.now ?? (() => Date.now()); + let self = { ...opts.self }; + let applyingRemote = false; // ⟵ anti-bucle: true mientras aplicamos algo recibido + const wrap = (kind, payload) => ({ + v: NET_PROTOCOL_VERSION, + room, + from: self.playerId, + ts: now(), + kind, + payload, + }); + const rawSendPresence = () => { + self = { ...self, lastSeenTs: now() }; + port.send(wrap("presence", self)); + }; + const clock = opts.clock ?? { + now: () => Date.now(), + schedule: (cb, d) => { + setTimeout(cb, d); + }, + }; + const throttleMs = opts.presenceThrottleMs ?? 80; + const sendPresence = throttleMs > 0 ? throttleTrailing(rawSendPresence, throttleMs, clock) : rawSendPresence; + // ── Salida: suscribe a TODOS los tipos de evento ──────────────────────────── + const types = Object.keys(EVENT_CLASSIFICATION); + const unsubs = types.map((type) => bus.on(type, (event) => { + if (applyingRemote) + return; // no re-difundir lo aplicado desde la red + if (!shouldReplicate(type)) + return; // private → nunca sale + if (isWorld(type)) { + port.send(wrap("event", event)); + } + if (type === "player:moved") { + const e = event; + self = { ...self, position: e.position, action: e.action }; + sendPresence(); + } + else if (type === "scene:changed") { + self = { + ...self, + sceneId: event.sceneId, + }; + sendPresence(); + } + else if (type === "transition:completed") { + self = { + ...self, + sceneId: event + .toSceneId, + }; + sendPresence(); + } + })); + // ── Entrada: aplica envelopes remotos ─────────────────────────────────────── + const offMsg = port.onMessage((m) => { + if (m.from === self.playerId) + return; // defensivo (headless ya filtra self) + if (m.kind === "presence") { + const d = m.payload; + if (d.__left) { + remotePlayers.remove(d.playerId); + bus.emit({ type: "net:playerLeft", playerId: d.playerId }); + return; + } + const isNew = remotePlayers.getAll().every((p) => p.playerId !== d.playerId); + remotePlayers.upsert(d); + if (isNew) + bus.emit({ type: "net:playerJoined", player: d }); + } + else if (m.kind === "event") { + applyingRemote = true; + try { + applyRemoteEvent(m.payload); + } + finally { + applyingRemote = false; + } + } + else if (m.kind === "claim-result") { + const r = m.payload; + if (r.granted) + opts.reconciler?.confirm(r.entityId); + else + opts.reconciler?.reject(r.entityId); + } + else if (m.kind === "snapshot") { + opts.reconciler?.onSnapshot(); + } + }); + const offStatus = port.onStatus((status) => { + bus.emit({ type: "net:status", status }); + if (status.state === "connected" && status.selfId) { + self = { ...self, playerId: status.selfId }; + } + }); + port.connect({ room, selfId: self.playerId }); + rawSendPresence(); // anúnciate al entrar (inmediato, sin throttle) + return { + dispose: () => { + unsubs.forEach((u) => u()); + offMsg(); + offStatus(); + port.disconnect(); + }, + getSelf: () => self, + updateSelf: (patch) => { + self = { ...self, ...patch }; + sendPresence(); + }, + }; +} +//# sourceMappingURL=MultiplayerSession.js.map \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/MultiplayerSession.js.map b/packages/engine-core/dist/game/net/MultiplayerSession.js.map new file mode 100644 index 0000000..7f9959d --- /dev/null +++ b/packages/engine-core/dist/game/net/MultiplayerSession.js.map @@ -0,0 +1 @@ +{"version":3,"file":"MultiplayerSession.js","sourceRoot":"","sources":["../../../src/game/net/MultiplayerSession.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAG/D,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACvF,OAAO,EAAE,gBAAgB,EAAsB,MAAM,YAAY,CAAC;AAkClE,MAAM,UAAU,wBAAwB,CACtC,IAA+B;IAE/B,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,aAAa,EAAE,gBAAgB,EAAE,GAAG,IAAI,CAAC;IAClE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAC3C,IAAI,IAAI,GAAG,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,cAAc,GAAG,KAAK,CAAC,CAAC,sDAAsD;IAElF,MAAM,IAAI,GAAG,CAAC,IAAyB,EAAE,OAAgB,EAAe,EAAE,CAAC,CAAC;QAC1E,CAAC,EAAE,oBAAoB;QACvB,IAAI;QACJ,IAAI,EAAE,IAAI,CAAC,QAAQ;QACnB,EAAE,EAAE,GAAG,EAAE;QACT,IAAI;QACJ,OAAO;KACR,CAAC,CAAC;IAEH,MAAM,eAAe,GAAG,GAAG,EAAE;QAC3B,IAAI,GAAG,EAAE,GAAG,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,EAAE,CAAC;QACtC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC;IACpC,CAAC,CAAC;IAEF,MAAM,KAAK,GAAkB,IAAI,CAAC,KAAK,IAAI;QACzC,GAAG,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;QACrB,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE;YAClB,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QACpB,CAAC;KACF,CAAC;IACF,MAAM,UAAU,GAAG,IAAI,CAAC,kBAAkB,IAAI,EAAE,CAAC;IACjD,MAAM,YAAY,GAChB,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,eAAe,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC;IAE1F,+EAA+E;IAC/E,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAoB,CAAC;IACnE,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAChC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE;QACrB,IAAI,cAAc;YAAE,OAAO,CAAC,0CAA0C;QACtE,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC;YAAE,OAAO,CAAC,uBAAuB;QAC3D,IAAI,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YAClB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;QAClC,CAAC;QACD,IAAI,IAAI,KAAK,cAAc,EAAE,CAAC;YAC5B,MAAM,CAAC,GAAG,KAAqD,CAAC;YAChE,IAAI,GAAG,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;YAC3D,YAAY,EAAE,CAAC;QACjB,CAAC;aAAM,IAAI,IAAI,KAAK,eAAe,EAAE,CAAC;YACpC,IAAI,GAAG;gBACL,GAAG,IAAI;gBACP,OAAO,EAAG,KAAuD,CAAC,OAAO;aAC1E,CAAC;YACF,YAAY,EAAE,CAAC;QACjB,CAAC;aAAM,IAAI,IAAI,KAAK,sBAAsB,EAAE,CAAC;YAC3C,IAAI,GAAG;gBACL,GAAG,IAAI;gBACP,OAAO,EAAG,KAA8D;qBACrE,SAAS;aACb,CAAC;YACF,YAAY,EAAE,CAAC;QACjB,CAAC;IACH,CAAC,CAAC,CACH,CAAC;IAEF,+EAA+E;IAC/E,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE;QAClC,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,QAAQ;YAAE,OAAO,CAAC,sCAAsC;QAC5E,IAAI,CAAC,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC1B,MAAM,CAAC,GAAG,CAAC,CAAC,OAAkD,CAAC;YAC/D,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;gBACb,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;gBACjC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;gBAC3D,OAAO;YACT,CAAC;YACD,MAAM,KAAK,GAAG,aAAa,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC;YAC7E,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YACxB,IAAI,KAAK;gBAAE,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;QAC/D,CAAC;aAAM,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAC9B,cAAc,GAAG,IAAI,CAAC;YACtB,IAAI,CAAC;gBACH,gBAAgB,CAAC,CAAC,CAAC,OAAoB,CAAC,CAAC;YAC3C,CAAC;oBAAS,CAAC;gBACT,cAAc,GAAG,KAAK,CAAC;YACzB,CAAC;QACH,CAAC;aAAM,IAAI,CAAC,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;YACrC,MAAM,CAAC,GAAG,CAAC,CAAC,OAAiD,CAAC;YAC9D,IAAI,CAAC,CAAC,OAAO;gBAAE,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;;gBAC/C,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QAC3C,CAAC;aAAM,IAAI,CAAC,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YACjC,IAAI,CAAC,UAAU,EAAE,UAAU,EAAE,CAAC;QAChC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,EAAE;QACzC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,CAAC;QACzC,IAAI,MAAM,CAAC,KAAK,KAAK,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAClD,IAAI,GAAG,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;QAC9C,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC9C,eAAe,EAAE,CAAC,CAAC,gDAAgD;IAEnE,OAAO;QACL,OAAO,EAAE,GAAG,EAAE;YACZ,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;YAC3B,MAAM,EAAE,CAAC;YACT,SAAS,EAAE,CAAC;YACZ,IAAI,CAAC,UAAU,EAAE,CAAC;QACpB,CAAC;QACD,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI;QACnB,UAAU,EAAE,CAAC,KAAK,EAAE,EAAE;YACpB,IAAI,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,EAAE,CAAC;YAC7B,YAAY,EAAE,CAAC;QACjB,CAAC;KACF,CAAC;AACJ,CAAC"} \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/claims.d.ts b/packages/engine-core/dist/game/net/claims.d.ts new file mode 100644 index 0000000..3ca1023 --- /dev/null +++ b/packages/engine-core/dist/game/net/claims.d.ts @@ -0,0 +1,17 @@ +import type { PlayerId } from "../../ports/multiplayer"; +export interface ItemClaim { + entityId: string; + by: PlayerId; + ts: number; +} +export interface ClaimResult { + entityId: string; + by: PlayerId; + granted: boolean; +} +/** + * Resuelve un conjunto de claims sobre el MISMO entityId (orden de llegada irrelevante). + * Gana el de menor ts (first-writer-wins); empate → menor playerId. Determinista. + */ +export declare function resolveClaim(claims: ItemClaim[]): ClaimResult[]; +//# sourceMappingURL=claims.d.ts.map \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/claims.d.ts.map b/packages/engine-core/dist/game/net/claims.d.ts.map new file mode 100644 index 0000000..379cfb5 --- /dev/null +++ b/packages/engine-core/dist/game/net/claims.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"claims.d.ts","sourceRoot":"","sources":["../../../src/game/net/claims.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAExD,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,QAAQ,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;CACZ;AACD,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,QAAQ,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,WAAW,EAAE,CAQ/D"} \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/claims.js b/packages/engine-core/dist/game/net/claims.js new file mode 100644 index 0000000..3404c28 --- /dev/null +++ b/packages/engine-core/dist/game/net/claims.js @@ -0,0 +1,15 @@ +/** + * Resuelve un conjunto de claims sobre el MISMO entityId (orden de llegada irrelevante). + * Gana el de menor ts (first-writer-wins); empate → menor playerId. Determinista. + */ +export function resolveClaim(claims) { + if (claims.length === 0) + return []; + const winner = [...claims].sort((a, b) => a.ts - b.ts || (a.by < b.by ? -1 : 1))[0]; + return claims.map((c) => ({ + entityId: c.entityId, + by: c.by, + granted: c.by === winner.by, + })); +} +//# sourceMappingURL=claims.js.map \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/claims.js.map b/packages/engine-core/dist/game/net/claims.js.map new file mode 100644 index 0000000..e411b05 --- /dev/null +++ b/packages/engine-core/dist/game/net/claims.js.map @@ -0,0 +1 @@ +{"version":3,"file":"claims.js","sourceRoot":"","sources":["../../../src/game/net/claims.ts"],"names":[],"mappings":"AAaA;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,MAAmB;IAC9C,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACnC,MAAM,MAAM,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC;IACrF,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACxB,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,EAAE,EAAE,CAAC,CAAC,EAAE;QACR,OAAO,EAAE,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE;KAC5B,CAAC,CAAC,CAAC;AACN,CAAC"} \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/clock.d.ts b/packages/engine-core/dist/game/net/clock.d.ts new file mode 100644 index 0000000..e575199 --- /dev/null +++ b/packages/engine-core/dist/game/net/clock.d.ts @@ -0,0 +1,9 @@ +export declare class Hlc { + private lastPhysical; + private counter; + /** Devuelve un timestamp codificado (number) monótono creciente. */ + now(wall?: number): number; + /** Actualiza el reloj al recibir un ts remoto (mantiene la causalidad). */ + update(remoteTs: number, wall?: number): number; +} +//# sourceMappingURL=clock.d.ts.map \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/clock.d.ts.map b/packages/engine-core/dist/game/net/clock.d.ts.map new file mode 100644 index 0000000..02d8f61 --- /dev/null +++ b/packages/engine-core/dist/game/net/clock.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"clock.d.ts","sourceRoot":"","sources":["../../../src/game/net/clock.ts"],"names":[],"mappings":"AAIA,qBAAa,GAAG;IACd,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,OAAO,CAAK;IAEpB,oEAAoE;IACpE,GAAG,CAAC,IAAI,GAAE,MAAmB,GAAG,MAAM;IAUtC,2EAA2E;IAC3E,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,GAAE,MAAmB,GAAG,MAAM;CAM5D"} \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/clock.js b/packages/engine-core/dist/game/net/clock.js new file mode 100644 index 0000000..db5190e --- /dev/null +++ b/packages/engine-core/dist/game/net/clock.js @@ -0,0 +1,28 @@ +/** HLC: combina reloj físico y contador lógico → orden total sin sincronizar relojes. */ +const COUNTER_BITS = 12; // hasta 4096 eventos por ms +const COUNTER_MASK = (1 << COUNTER_BITS) - 1; +export class Hlc { + constructor() { + this.lastPhysical = 0; + this.counter = 0; + } + /** Devuelve un timestamp codificado (number) monótono creciente. */ + now(wall = Date.now()) { + if (wall > this.lastPhysical) { + this.lastPhysical = wall; + this.counter = 0; + } + else { + this.counter = (this.counter + 1) & COUNTER_MASK; + } + return this.lastPhysical * (COUNTER_MASK + 1) + this.counter; + } + /** Actualiza el reloj al recibir un ts remoto (mantiene la causalidad). */ + update(remoteTs, wall = Date.now()) { + const remotePhysical = Math.floor(remoteTs / (COUNTER_MASK + 1)); + this.lastPhysical = Math.max(this.lastPhysical, remotePhysical, wall); + this.counter = (this.counter + 1) & COUNTER_MASK; + return this.lastPhysical * (COUNTER_MASK + 1) + this.counter; + } +} +//# sourceMappingURL=clock.js.map \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/clock.js.map b/packages/engine-core/dist/game/net/clock.js.map new file mode 100644 index 0000000..b95a5f8 --- /dev/null +++ b/packages/engine-core/dist/game/net/clock.js.map @@ -0,0 +1 @@ +{"version":3,"file":"clock.js","sourceRoot":"","sources":["../../../src/game/net/clock.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,MAAM,YAAY,GAAG,EAAE,CAAC,CAAC,4BAA4B;AACrD,MAAM,YAAY,GAAG,CAAC,CAAC,IAAI,YAAY,CAAC,GAAG,CAAC,CAAC;AAE7C,MAAM,OAAO,GAAG;IAAhB;QACU,iBAAY,GAAG,CAAC,CAAC;QACjB,YAAO,GAAG,CAAC,CAAC;IAoBtB,CAAC;IAlBC,oEAAoE;IACpE,GAAG,CAAC,OAAe,IAAI,CAAC,GAAG,EAAE;QAC3B,IAAI,IAAI,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;YAC7B,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;YACzB,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;QACnB,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,GAAG,YAAY,CAAC;QACnD,CAAC;QACD,OAAO,IAAI,CAAC,YAAY,GAAG,CAAC,YAAY,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC;IAC/D,CAAC;IAED,2EAA2E;IAC3E,MAAM,CAAC,QAAgB,EAAE,OAAe,IAAI,CAAC,GAAG,EAAE;QAChD,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC;QACjE,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,cAAc,EAAE,IAAI,CAAC,CAAC;QACtE,IAAI,CAAC,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,GAAG,YAAY,CAAC;QACjD,OAAO,IAAI,CAAC,YAAY,GAAG,CAAC,YAAY,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC;IAC/D,CAAC;CACF"} \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/eventClassification.d.ts b/packages/engine-core/dist/game/net/eventClassification.d.ts new file mode 100644 index 0000000..54109dd --- /dev/null +++ b/packages/engine-core/dist/game/net/eventClassification.d.ts @@ -0,0 +1,43 @@ +import type { GameEventType } from "../events/types"; +/** Clase de sincronización de un evento. Un evento puede pertenecer a varias. */ +export type SyncClass = "world" | "presence" | "private"; +/** + * Clasificación exhaustiva. `satisfies` obliga a cubrir TODOS los GameEventType: + * si añades un evento nuevo y no lo clasificas, TypeScript falla aquí. + * + * - world → estado compartido, replicado a todos, persistente (puertas, ítems colocados). + * - presence → efímero por jugador, fan-out a misma escena (posición, escena). + * - private → local, NUNCA cruza la red (diálogos, audio, animación de walk). + */ +export declare const EVENT_CLASSIFICATION: { + "scene:changed": "presence"[]; + "scene:respawnRequested": "private"[]; + "player:moved": "presence"[]; + "player:collided": "private"[]; + "item:pickedUp": ("world" | "private")[]; + "item:dropped": "world"[]; + "dialog:triggered": "private"[]; + "dialog:dismissed": "private"[]; + "transition:triggered": "private"[]; + "transition:started": "private"[]; + "transition:completed": "presence"[]; + "transition:colliderClicked": "private"[]; + "player:walkStarted": "private"[]; + "player:walkCompleted": "private"[]; + "player:walkAborted": "private"[]; + "audio:sfxRequested": "private"[]; + "audio:musicRequested": "private"[]; + "audio:musicStopped": "private"[]; + "audio:settingsChanged": "private"[]; + "i18n:localeChanged": "private"[]; + "i18n:dictionaryUpdated": "private"[]; + "net:playerJoined": "private"[]; + "net:playerLeft": "private"[]; + "net:status": "private"[]; +}; +export declare function classifyEvent(type: GameEventType): SyncClass[]; +export declare const isWorld: (t: GameEventType) => boolean; +export declare const isPresence: (t: GameEventType) => boolean; +/** ¿Debe salir a la red? (world o presence). Los `private` jamás. */ +export declare const shouldReplicate: (t: GameEventType) => boolean; +//# sourceMappingURL=eventClassification.d.ts.map \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/eventClassification.d.ts.map b/packages/engine-core/dist/game/net/eventClassification.d.ts.map new file mode 100644 index 0000000..8812f1d --- /dev/null +++ b/packages/engine-core/dist/game/net/eventClassification.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"eventClassification.d.ts","sourceRoot":"","sources":["../../../src/game/net/eventClassification.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,iFAAiF;AACjF,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,CAAC;AAEzD;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;CAkCa,CAAC;AAE/C,wBAAgB,aAAa,CAAC,IAAI,EAAE,aAAa,GAAG,SAAS,EAAE,CAE9D;AACD,eAAO,MAAM,OAAO,GAAI,GAAG,aAAa,KAAG,OAA6C,CAAC;AACzF,eAAO,MAAM,UAAU,GAAI,GAAG,aAAa,KAAG,OACP,CAAC;AACxC,qEAAqE;AACrE,eAAO,MAAM,eAAe,GAAI,GAAG,aAAa,KAAG,OACtB,CAAC"} \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/eventClassification.js b/packages/engine-core/dist/game/net/eventClassification.js new file mode 100644 index 0000000..a2dcdc8 --- /dev/null +++ b/packages/engine-core/dist/game/net/eventClassification.js @@ -0,0 +1,51 @@ +/** + * Clasificación exhaustiva. `satisfies` obliga a cubrir TODOS los GameEventType: + * si añades un evento nuevo y no lo clasificas, TypeScript falla aquí. + * + * - world → estado compartido, replicado a todos, persistente (puertas, ítems colocados). + * - presence → efímero por jugador, fan-out a misma escena (posición, escena). + * - private → local, NUNCA cruza la red (diálogos, audio, animación de walk). + */ +export const EVENT_CLASSIFICATION = { + // Scene + "scene:changed": ["presence"], // cambia MI escena → actualiza mi presence + "scene:respawnRequested": ["private"], + // Player + "player:moved": ["presence"], // alta frecuencia; throttle en el borde + "player:collided": ["private"], + // Inventory (pickup quita del world y añade a mi inventario) + "item:pickedUp": ["world", "private"], + "item:dropped": ["world"], // place/consume mutan placedItems compartidos + // Dialog + "dialog:triggered": ["private"], + "dialog:dismissed": ["private"], + // Transitions + "transition:triggered": ["private"], + "transition:started": ["private"], + "transition:completed": ["presence"], // cambio de escena propio + "transition:colliderClicked": ["private"], + // Player walking (se deriva de presence en remotos) + "player:walkStarted": ["private"], + "player:walkCompleted": ["private"], + "player:walkAborted": ["private"], + // Audio (local) + "audio:sfxRequested": ["private"], + "audio:musicRequested": ["private"], + "audio:musicStopped": ["private"], + "audio:settingsChanged": ["private"], + // i18n (local) + "i18n:localeChanged": ["private"], + "i18n:dictionaryUpdated": ["private"], + // Net (locales para UI; nunca se replican) + "net:playerJoined": ["private"], + "net:playerLeft": ["private"], + "net:status": ["private"], +}; +export function classifyEvent(type) { + return EVENT_CLASSIFICATION[type] ?? ["private"]; +} +export const isWorld = (t) => classifyEvent(t).includes("world"); +export const isPresence = (t) => classifyEvent(t).includes("presence"); +/** ¿Debe salir a la red? (world o presence). Los `private` jamás. */ +export const shouldReplicate = (t) => isWorld(t) || isPresence(t); +//# sourceMappingURL=eventClassification.js.map \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/eventClassification.js.map b/packages/engine-core/dist/game/net/eventClassification.js.map new file mode 100644 index 0000000..9e1e373 --- /dev/null +++ b/packages/engine-core/dist/game/net/eventClassification.js.map @@ -0,0 +1 @@ +{"version":3,"file":"eventClassification.js","sourceRoot":"","sources":["../../../src/game/net/eventClassification.ts"],"names":[],"mappings":"AAKA;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,QAAQ;IACR,eAAe,EAAE,CAAC,UAAU,CAAC,EAAE,2CAA2C;IAC1E,wBAAwB,EAAE,CAAC,SAAS,CAAC;IACrC,SAAS;IACT,cAAc,EAAE,CAAC,UAAU,CAAC,EAAE,wCAAwC;IACtE,iBAAiB,EAAE,CAAC,SAAS,CAAC;IAC9B,6DAA6D;IAC7D,eAAe,EAAE,CAAC,OAAO,EAAE,SAAS,CAAC;IACrC,cAAc,EAAE,CAAC,OAAO,CAAC,EAAE,8CAA8C;IACzE,SAAS;IACT,kBAAkB,EAAE,CAAC,SAAS,CAAC;IAC/B,kBAAkB,EAAE,CAAC,SAAS,CAAC;IAC/B,cAAc;IACd,sBAAsB,EAAE,CAAC,SAAS,CAAC;IACnC,oBAAoB,EAAE,CAAC,SAAS,CAAC;IACjC,sBAAsB,EAAE,CAAC,UAAU,CAAC,EAAE,0BAA0B;IAChE,4BAA4B,EAAE,CAAC,SAAS,CAAC;IACzC,oDAAoD;IACpD,oBAAoB,EAAE,CAAC,SAAS,CAAC;IACjC,sBAAsB,EAAE,CAAC,SAAS,CAAC;IACnC,oBAAoB,EAAE,CAAC,SAAS,CAAC;IACjC,gBAAgB;IAChB,oBAAoB,EAAE,CAAC,SAAS,CAAC;IACjC,sBAAsB,EAAE,CAAC,SAAS,CAAC;IACnC,oBAAoB,EAAE,CAAC,SAAS,CAAC;IACjC,uBAAuB,EAAE,CAAC,SAAS,CAAC;IACpC,eAAe;IACf,oBAAoB,EAAE,CAAC,SAAS,CAAC;IACjC,wBAAwB,EAAE,CAAC,SAAS,CAAC;IACrC,2CAA2C;IAC3C,kBAAkB,EAAE,CAAC,SAAS,CAAC;IAC/B,gBAAgB,EAAE,CAAC,SAAS,CAAC;IAC7B,YAAY,EAAE,CAAC,SAAS,CAAC;CACmB,CAAC;AAE/C,MAAM,UAAU,aAAa,CAAC,IAAmB;IAC/C,OAAO,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;AACnD,CAAC;AACD,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,CAAgB,EAAW,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AACzF,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAgB,EAAW,EAAE,CACtD,aAAa,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;AACxC,qEAAqE;AACrE,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAgB,EAAW,EAAE,CAC3D,OAAO,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/index.d.ts b/packages/engine-core/dist/game/net/index.d.ts new file mode 100644 index 0000000..be45baf --- /dev/null +++ b/packages/engine-core/dist/game/net/index.d.ts @@ -0,0 +1,10 @@ +export * from "./eventClassification"; +export * from "./playerIdentity"; +export * from "./remotePlayersStore"; +export * from "./MultiplayerSession"; +export * from "./clock"; +export * from "./worldState"; +export * from "./claims"; +export * from "./throttle"; +export * from "./optimistic"; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/index.d.ts.map b/packages/engine-core/dist/game/net/index.d.ts.map new file mode 100644 index 0000000..80104ad --- /dev/null +++ b/packages/engine-core/dist/game/net/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/game/net/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC"} \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/index.js b/packages/engine-core/dist/game/net/index.js new file mode 100644 index 0000000..5b9dde6 --- /dev/null +++ b/packages/engine-core/dist/game/net/index.js @@ -0,0 +1,10 @@ +export * from "./eventClassification"; +export * from "./playerIdentity"; +export * from "./remotePlayersStore"; +export * from "./MultiplayerSession"; +export * from "./clock"; +export * from "./worldState"; +export * from "./claims"; +export * from "./throttle"; +export * from "./optimistic"; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/index.js.map b/packages/engine-core/dist/game/net/index.js.map new file mode 100644 index 0000000..c308715 --- /dev/null +++ b/packages/engine-core/dist/game/net/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/game/net/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC"} \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/optimistic.d.ts b/packages/engine-core/dist/game/net/optimistic.d.ts new file mode 100644 index 0000000..a44f579 --- /dev/null +++ b/packages/engine-core/dist/game/net/optimistic.d.ts @@ -0,0 +1,21 @@ +export interface PendingAction { + entityId: string; + rollback: () => void; +} +/** + * Buffer de acciones optimistas pendientes de confirmación. Cada acción aporta + * su propio `rollback` (cómo deshacerla). Reconciliación determinista. + */ +export declare function createOptimisticReconciler(): { + /** Registra una predicción local ya aplicada. */ + track(entityId: string, rollback: () => void): void; + /** El servidor confirmó: descarta la predicción (no revierte). */ + confirm(entityId: string): void; + /** El servidor rechazó: revierte y descarta. */ + reject(entityId: string): void; + /** Reconexión: revierte TODO lo no confirmado antes de aplicar el snapshot. */ + onSnapshot(): void; + size(): number; +}; +export type OptimisticReconciler = ReturnType; +//# sourceMappingURL=optimistic.d.ts.map \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/optimistic.d.ts.map b/packages/engine-core/dist/game/net/optimistic.d.ts.map new file mode 100644 index 0000000..b8a197c --- /dev/null +++ b/packages/engine-core/dist/game/net/optimistic.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"optimistic.d.ts","sourceRoot":"","sources":["../../../src/game/net/optimistic.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAgB,0BAA0B;IAGtC,iDAAiD;oBACjC,MAAM,YAAY,MAAM,IAAI,GAAG,IAAI;IAGnD,kEAAkE;sBAChD,MAAM,GAAG,IAAI;IAG/B,gDAAgD;qBAC/B,MAAM,GAAG,IAAI;IAO9B,+EAA+E;kBACjE,IAAI;YAIV,MAAM;EAIjB;AAED,MAAM,MAAM,oBAAoB,GAAG,UAAU,CAAC,OAAO,0BAA0B,CAAC,CAAC"} \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/optimistic.js b/packages/engine-core/dist/game/net/optimistic.js new file mode 100644 index 0000000..a28c26e --- /dev/null +++ b/packages/engine-core/dist/game/net/optimistic.js @@ -0,0 +1,34 @@ +/** + * Buffer de acciones optimistas pendientes de confirmación. Cada acción aporta + * su propio `rollback` (cómo deshacerla). Reconciliación determinista. + */ +export function createOptimisticReconciler() { + const pending = new Map(); + return { + /** Registra una predicción local ya aplicada. */ + track(entityId, rollback) { + pending.set(entityId, { entityId, rollback }); + }, + /** El servidor confirmó: descarta la predicción (no revierte). */ + confirm(entityId) { + pending.delete(entityId); + }, + /** El servidor rechazó: revierte y descarta. */ + reject(entityId) { + const p = pending.get(entityId); + if (p) { + p.rollback(); + pending.delete(entityId); + } + }, + /** Reconexión: revierte TODO lo no confirmado antes de aplicar el snapshot. */ + onSnapshot() { + pending.forEach((p) => p.rollback()); + pending.clear(); + }, + size() { + return pending.size; + }, + }; +} +//# sourceMappingURL=optimistic.js.map \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/optimistic.js.map b/packages/engine-core/dist/game/net/optimistic.js.map new file mode 100644 index 0000000..37b4541 --- /dev/null +++ b/packages/engine-core/dist/game/net/optimistic.js.map @@ -0,0 +1 @@ +{"version":3,"file":"optimistic.js","sourceRoot":"","sources":["../../../src/game/net/optimistic.ts"],"names":[],"mappings":"AAKA;;;GAGG;AACH,MAAM,UAAU,0BAA0B;IACxC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAyB,CAAC;IACjD,OAAO;QACL,iDAAiD;QACjD,KAAK,CAAC,QAAgB,EAAE,QAAoB;YAC1C,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;QAChD,CAAC;QACD,kEAAkE;QAClE,OAAO,CAAC,QAAgB;YACtB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC3B,CAAC;QACD,gDAAgD;QAChD,MAAM,CAAC,QAAgB;YACrB,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAChC,IAAI,CAAC,EAAE,CAAC;gBACN,CAAC,CAAC,QAAQ,EAAE,CAAC;gBACb,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC;QACD,+EAA+E;QAC/E,UAAU;YACR,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;YACrC,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,CAAC;QACD,IAAI;YACF,OAAO,OAAO,CAAC,IAAI,CAAC;QACtB,CAAC;KACF,CAAC;AACJ,CAAC"} \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/playerIdentity.d.ts b/packages/engine-core/dist/game/net/playerIdentity.d.ts new file mode 100644 index 0000000..e5abfa6 --- /dev/null +++ b/packages/engine-core/dist/game/net/playerIdentity.d.ts @@ -0,0 +1,29 @@ +import type { GameVec3 } from "../types"; +import type { PlayerId } from "../../ports/multiplayer"; +/** Personaje seleccionable. Hoy solo "Dave"; reservado para multi-character futuro. */ +export type CharacterId = "Dave"; +export declare const DEFAULT_CHARACTER_ID: CharacterId; +export type PlayerAction = "idle" | "north" | "south" | "west" | "east"; +/** Descriptor de un jugador. Serializable: viaja como presence en NetEnvelope.payload. */ +export interface PlayerDescriptor { + playerId: PlayerId; + displayName: string; + characterId: CharacterId; + sceneId: string; + position: GameVec3; + action: PlayerAction; + /** Último timestamp visto (para limpiar jugadores stale). */ + lastSeenTs: number; +} +/** Genera un nombre anónimo legible, p.ej. "Viajero-A3F". RNG inyectable para tests. */ +export declare function generateRandomName(rng?: () => number): string; +/** Crea el descriptor inicial del jugador local. */ +export declare function createSelfDescriptor(opts: { + playerId: PlayerId; + sceneId: string; + position: GameVec3; + displayName?: string; + characterId?: CharacterId; + now?: () => number; +}): PlayerDescriptor; +//# sourceMappingURL=playerIdentity.d.ts.map \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/playerIdentity.d.ts.map b/packages/engine-core/dist/game/net/playerIdentity.d.ts.map new file mode 100644 index 0000000..11f1398 --- /dev/null +++ b/packages/engine-core/dist/game/net/playerIdentity.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"playerIdentity.d.ts","sourceRoot":"","sources":["../../../src/game/net/playerIdentity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAExD,uFAAuF;AACvF,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC;AACjC,eAAO,MAAM,oBAAoB,EAAE,WAAoB,CAAC;AAExD,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;AAExE,0FAA0F;AAC1F,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,QAAQ,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,WAAW,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,YAAY,CAAC;IACrB,6DAA6D;IAC7D,UAAU,EAAE,MAAM,CAAC;CACpB;AAWD,wFAAwF;AACxF,wBAAgB,kBAAkB,CAAC,GAAG,GAAE,MAAM,MAAoB,GAAG,MAAM,CAO1E;AAED,oDAAoD;AACpD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IACzC,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,QAAQ,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB,GAAG,gBAAgB,CAUnB"} \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/playerIdentity.js b/packages/engine-core/dist/game/net/playerIdentity.js new file mode 100644 index 0000000..2c6f509 --- /dev/null +++ b/packages/engine-core/dist/game/net/playerIdentity.js @@ -0,0 +1,31 @@ +export const DEFAULT_CHARACTER_ID = "Dave"; +const NAME_PREFIXES = [ + "Viajero", + "Errante", + "Nómada", + "Curioso", + "Vecino", + "Explorador", +]; +/** Genera un nombre anónimo legible, p.ej. "Viajero-A3F". RNG inyectable para tests. */ +export function generateRandomName(rng = Math.random) { + const prefix = NAME_PREFIXES[Math.floor(rng() * NAME_PREFIXES.length)]; + const suffix = Math.floor(rng() * 0xfff) + .toString(16) + .toUpperCase() + .padStart(3, "0"); + return `${prefix}-${suffix}`; +} +/** Crea el descriptor inicial del jugador local. */ +export function createSelfDescriptor(opts) { + return { + playerId: opts.playerId, + displayName: opts.displayName ?? generateRandomName(), + characterId: opts.characterId ?? DEFAULT_CHARACTER_ID, + sceneId: opts.sceneId, + position: opts.position, + action: "idle", + lastSeenTs: (opts.now ?? Date.now)(), + }; +} +//# sourceMappingURL=playerIdentity.js.map \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/playerIdentity.js.map b/packages/engine-core/dist/game/net/playerIdentity.js.map new file mode 100644 index 0000000..8132a19 --- /dev/null +++ b/packages/engine-core/dist/game/net/playerIdentity.js.map @@ -0,0 +1 @@ +{"version":3,"file":"playerIdentity.js","sourceRoot":"","sources":["../../../src/game/net/playerIdentity.ts"],"names":[],"mappings":"AAKA,MAAM,CAAC,MAAM,oBAAoB,GAAgB,MAAM,CAAC;AAgBxD,MAAM,aAAa,GAAG;IACpB,SAAS;IACT,SAAS;IACT,QAAQ;IACR,SAAS;IACT,QAAQ;IACR,YAAY;CACJ,CAAC;AAEX,wFAAwF;AACxF,MAAM,UAAU,kBAAkB,CAAC,MAAoB,IAAI,CAAC,MAAM;IAChE,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,aAAa,CAAC,MAAM,CAAC,CAAE,CAAC;IACxE,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;SACrC,QAAQ,CAAC,EAAE,CAAC;SACZ,WAAW,EAAE;SACb,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACpB,OAAO,GAAG,MAAM,IAAI,MAAM,EAAE,CAAC;AAC/B,CAAC;AAED,oDAAoD;AACpD,MAAM,UAAU,oBAAoB,CAAC,IAOpC;IACC,OAAO;QACL,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,kBAAkB,EAAE;QACrD,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,oBAAoB;QACrD,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,MAAM,EAAE,MAAM;QACd,UAAU,EAAE,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE;KACrC,CAAC;AACJ,CAAC"} \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/remotePlayersStore.d.ts b/packages/engine-core/dist/game/net/remotePlayersStore.d.ts new file mode 100644 index 0000000..e9614b7 --- /dev/null +++ b/packages/engine-core/dist/game/net/remotePlayersStore.d.ts @@ -0,0 +1,19 @@ +import type { PlayerDescriptor } from "./playerIdentity"; +import type { PlayerId } from "../../ports/multiplayer"; +export interface RemotePlayersStore { + /** Inserta o actualiza un jugador remoto (merge parcial sobre el existente). */ + upsert: (descriptor: Partial & { + playerId: PlayerId; + }) => void; + remove: (playerId: PlayerId) => void; + /** Solo los jugadores presentes en la escena dada (interest management en el borde). */ + getInScene: (sceneId: string) => PlayerDescriptor[]; + getAll: () => PlayerDescriptor[]; + /** Elimina jugadores sin presence en > maxAgeMs. Devuelve los ids eliminados. */ + pruneStale: (maxAgeMs: number, now?: number) => PlayerId[]; + reset: () => void; + /** Notifica en cada cambio (para que el renderer re-renderice). */ + subscribe: (listener: () => void) => () => void; +} +export declare function createRemotePlayersStore(): RemotePlayersStore; +//# sourceMappingURL=remotePlayersStore.d.ts.map \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/remotePlayersStore.d.ts.map b/packages/engine-core/dist/game/net/remotePlayersStore.d.ts.map new file mode 100644 index 0000000..6e697b6 --- /dev/null +++ b/packages/engine-core/dist/game/net/remotePlayersStore.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"remotePlayersStore.d.ts","sourceRoot":"","sources":["../../../src/game/net/remotePlayersStore.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAExD,MAAM,WAAW,kBAAkB;IACjC,gFAAgF;IAChF,MAAM,EAAE,CAAC,UAAU,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG;QAAE,QAAQ,EAAE,QAAQ,CAAA;KAAE,KAAK,IAAI,CAAC;IACjF,MAAM,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAC;IACrC,wFAAwF;IACxF,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,gBAAgB,EAAE,CAAC;IACpD,MAAM,EAAE,MAAM,gBAAgB,EAAE,CAAC;IACjC,iFAAiF;IACjF,UAAU,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,KAAK,QAAQ,EAAE,CAAC;IAC3D,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,mEAAmE;IACnE,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,CAAC;CACjD;AAED,wBAAgB,wBAAwB,IAAI,kBAAkB,CA6C7D"} \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/remotePlayersStore.js b/packages/engine-core/dist/game/net/remotePlayersStore.js new file mode 100644 index 0000000..f61fcee --- /dev/null +++ b/packages/engine-core/dist/game/net/remotePlayersStore.js @@ -0,0 +1,47 @@ +export function createRemotePlayersStore() { + const players = new Map(); + const listeners = new Set(); + const notify = () => listeners.forEach((l) => l()); + return { + upsert: (d) => { + const prev = players.get(d.playerId); + players.set(d.playerId, { + playerId: d.playerId, + displayName: d.displayName ?? prev?.displayName ?? d.playerId, + characterId: d.characterId ?? prev?.characterId ?? "Dave", + sceneId: d.sceneId ?? prev?.sceneId ?? "", + position: d.position ?? prev?.position ?? [0, 0, 0], + action: d.action ?? prev?.action ?? "idle", + lastSeenTs: d.lastSeenTs ?? Date.now(), + }); + notify(); + }, + remove: (id) => { + if (players.delete(id)) + notify(); + }, + getInScene: (sceneId) => [...players.values()].filter((p) => p.sceneId === sceneId), + getAll: () => [...players.values()], + pruneStale: (maxAgeMs, now = Date.now()) => { + const removed = []; + for (const [id, p] of players) { + if (now - p.lastSeenTs > maxAgeMs) { + players.delete(id); + removed.push(id); + } + } + if (removed.length) + notify(); + return removed; + }, + reset: () => { + players.clear(); + notify(); + }, + subscribe: (l) => { + listeners.add(l); + return () => listeners.delete(l); + }, + }; +} +//# sourceMappingURL=remotePlayersStore.js.map \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/remotePlayersStore.js.map b/packages/engine-core/dist/game/net/remotePlayersStore.js.map new file mode 100644 index 0000000..3b14be1 --- /dev/null +++ b/packages/engine-core/dist/game/net/remotePlayersStore.js.map @@ -0,0 +1 @@ +{"version":3,"file":"remotePlayersStore.js","sourceRoot":"","sources":["../../../src/game/net/remotePlayersStore.ts"],"names":[],"mappings":"AAiBA,MAAM,UAAU,wBAAwB;IACtC,MAAM,OAAO,GAAG,IAAI,GAAG,EAA8B,CAAC;IACtD,MAAM,SAAS,GAAG,IAAI,GAAG,EAAc,CAAC;IACxC,MAAM,MAAM,GAAG,GAAG,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;IAEnD,OAAO;QACL,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE;YACZ,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;YACrC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE;gBACtB,QAAQ,EAAE,CAAC,CAAC,QAAQ;gBACpB,WAAW,EAAE,CAAC,CAAC,WAAW,IAAI,IAAI,EAAE,WAAW,IAAI,CAAC,CAAC,QAAQ;gBAC7D,WAAW,EAAE,CAAC,CAAC,WAAW,IAAI,IAAI,EAAE,WAAW,IAAI,MAAM;gBACzD,OAAO,EAAE,CAAC,CAAC,OAAO,IAAI,IAAI,EAAE,OAAO,IAAI,EAAE;gBACzC,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,IAAI,EAAE,QAAQ,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;gBACnD,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,IAAI,EAAE,MAAM,IAAI,MAAM;gBAC1C,UAAU,EAAE,CAAC,CAAC,UAAU,IAAI,IAAI,CAAC,GAAG,EAAE;aACvC,CAAC,CAAC;YACH,MAAM,EAAE,CAAC;QACX,CAAC;QACD,MAAM,EAAE,CAAC,EAAE,EAAE,EAAE;YACb,IAAI,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;gBAAE,MAAM,EAAE,CAAC;QACnC,CAAC;QACD,UAAU,EAAE,CAAC,OAAO,EAAE,EAAE,CACtB,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC;QAC5D,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;QACnC,UAAU,EAAE,CAAC,QAAQ,EAAE,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,EAAE,EAAE;YACzC,MAAM,OAAO,GAAe,EAAE,CAAC;YAC/B,KAAK,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,OAAO,EAAE,CAAC;gBAC9B,IAAI,GAAG,GAAG,CAAC,CAAC,UAAU,GAAG,QAAQ,EAAE,CAAC;oBAClC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;oBACnB,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBACnB,CAAC;YACH,CAAC;YACD,IAAI,OAAO,CAAC,MAAM;gBAAE,MAAM,EAAE,CAAC;YAC7B,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,KAAK,EAAE,GAAG,EAAE;YACV,OAAO,CAAC,KAAK,EAAE,CAAC;YAChB,MAAM,EAAE,CAAC;QACX,CAAC;QACD,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE;YACf,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YACjB,OAAO,GAAG,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACnC,CAAC;KACF,CAAC;AACJ,CAAC"} \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/throttle.d.ts b/packages/engine-core/dist/game/net/throttle.d.ts new file mode 100644 index 0000000..12c0964 --- /dev/null +++ b/packages/engine-core/dist/game/net/throttle.d.ts @@ -0,0 +1,11 @@ +/** Reloj/scheduler inyectable para el throttle (permite tests deterministas). */ +export interface ThrottleClock { + now: () => number; + schedule: (cb: () => void, delay: number) => void; +} +/** + * Throttle con trailing: ejecuta `fn` como mucho 1 vez por `ms`, pero garantiza + * que la ÚLTIMA llamada dentro de la ventana se ejecuta (con el estado final). + */ +export declare function throttleTrailing(fn: () => void, ms: number, clock: ThrottleClock): () => void; +//# sourceMappingURL=throttle.d.ts.map \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/throttle.d.ts.map b/packages/engine-core/dist/game/net/throttle.d.ts.map new file mode 100644 index 0000000..681773a --- /dev/null +++ b/packages/engine-core/dist/game/net/throttle.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"throttle.d.ts","sourceRoot":"","sources":["../../../src/game/net/throttle.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,MAAM,CAAC;IAClB,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,IAAI,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,EAAE,EAAE,MAAM,IAAI,EACd,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,aAAa,GACnB,MAAM,IAAI,CAoBZ"} \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/throttle.js b/packages/engine-core/dist/game/net/throttle.js new file mode 100644 index 0000000..90c94b8 --- /dev/null +++ b/packages/engine-core/dist/game/net/throttle.js @@ -0,0 +1,26 @@ +/** + * Throttle con trailing: ejecuta `fn` como mucho 1 vez por `ms`, pero garantiza + * que la ÚLTIMA llamada dentro de la ventana se ejecuta (con el estado final). + */ +export function throttleTrailing(fn, ms, clock) { + let lastRun = -Infinity; + let scheduled = false; + return () => { + const t = clock.now(); + const elapsed = t - lastRun; + if (elapsed >= ms) { + lastRun = t; + fn(); + return; + } + if (!scheduled) { + scheduled = true; + clock.schedule(() => { + scheduled = false; + lastRun = clock.now(); + fn(); + }, ms - elapsed); + } + }; +} +//# sourceMappingURL=throttle.js.map \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/throttle.js.map b/packages/engine-core/dist/game/net/throttle.js.map new file mode 100644 index 0000000..ee592f5 --- /dev/null +++ b/packages/engine-core/dist/game/net/throttle.js.map @@ -0,0 +1 @@ +{"version":3,"file":"throttle.js","sourceRoot":"","sources":["../../../src/game/net/throttle.ts"],"names":[],"mappings":"AAMA;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAC9B,EAAc,EACd,EAAU,EACV,KAAoB;IAEpB,IAAI,OAAO,GAAG,CAAC,QAAQ,CAAC;IACxB,IAAI,SAAS,GAAG,KAAK,CAAC;IACtB,OAAO,GAAG,EAAE;QACV,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC;QACtB,MAAM,OAAO,GAAG,CAAC,GAAG,OAAO,CAAC;QAC5B,IAAI,OAAO,IAAI,EAAE,EAAE,CAAC;YAClB,OAAO,GAAG,CAAC,CAAC;YACZ,EAAE,EAAE,CAAC;YACL,OAAO;QACT,CAAC;QACD,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,SAAS,GAAG,IAAI,CAAC;YACjB,KAAK,CAAC,QAAQ,CAAC,GAAG,EAAE;gBAClB,SAAS,GAAG,KAAK,CAAC;gBAClB,OAAO,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC;gBACtB,EAAE,EAAE,CAAC;YACP,CAAC,EAAE,EAAE,GAAG,OAAO,CAAC,CAAC;QACnB,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"} \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/worldState.d.ts b/packages/engine-core/dist/game/net/worldState.d.ts new file mode 100644 index 0000000..e417e2f --- /dev/null +++ b/packages/engine-core/dist/game/net/worldState.d.ts @@ -0,0 +1,17 @@ +import type { PlayerId } from "../../ports/multiplayer"; +export interface LwwRegister { + value: V; + ts: number; + by: PlayerId; +} +/** Mapa de registros LWW por `${entityId}:${field}`. Determinista entre clientes. */ +export declare class WorldStateLww { + private map; + private key; + get(entityId: string, field: string): V | undefined; + /** Aplica un registro remoto/local. Devuelve true si ganó (cambió el estado). */ + merge(entityId: string, field: string, reg: LwwRegister): boolean; + snapshot(): Record; + load(snap: Record): void; +} +//# sourceMappingURL=worldState.d.ts.map \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/worldState.d.ts.map b/packages/engine-core/dist/game/net/worldState.d.ts.map new file mode 100644 index 0000000..afecbcc --- /dev/null +++ b/packages/engine-core/dist/game/net/worldState.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"worldState.d.ts","sourceRoot":"","sources":["../../../src/game/net/worldState.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAExD,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,OAAO;IACtC,KAAK,EAAE,CAAC,CAAC;IACT,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,QAAQ,CAAC;CACd;AAED,qFAAqF;AACrF,qBAAa,aAAa;IACxB,OAAO,CAAC,GAAG,CAAkC;IAC7C,OAAO,CAAC,GAAG,CAA+D;IAE1E,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAItD,iFAAiF;IACjF,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO;IAWjE,QAAQ,IAAI,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC;IAGvC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,IAAI;CAG9C"} \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/worldState.js b/packages/engine-core/dist/game/net/worldState.js new file mode 100644 index 0000000..e42e552 --- /dev/null +++ b/packages/engine-core/dist/game/net/worldState.js @@ -0,0 +1,28 @@ +/** Mapa de registros LWW por `${entityId}:${field}`. Determinista entre clientes. */ +export class WorldStateLww { + constructor() { + this.map = new Map(); + this.key = (entityId, field) => `${entityId}:${field}`; + } + get(entityId, field) { + return this.map.get(this.key(entityId, field))?.value; + } + /** Aplica un registro remoto/local. Devuelve true si ganó (cambió el estado). */ + merge(entityId, field, reg) { + const k = this.key(entityId, field); + const cur = this.map.get(k); + // Gana mayor ts; empate → mayor playerId (criterio estable arbitrario). + if (!cur || reg.ts > cur.ts || (reg.ts === cur.ts && reg.by > cur.by)) { + this.map.set(k, reg); + return true; + } + return false; + } + snapshot() { + return Object.fromEntries(this.map); + } + load(snap) { + this.map = new Map(Object.entries(snap)); + } +} +//# sourceMappingURL=worldState.js.map \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/worldState.js.map b/packages/engine-core/dist/game/net/worldState.js.map new file mode 100644 index 0000000..342fdc1 --- /dev/null +++ b/packages/engine-core/dist/game/net/worldState.js.map @@ -0,0 +1 @@ +{"version":3,"file":"worldState.js","sourceRoot":"","sources":["../../../src/game/net/worldState.ts"],"names":[],"mappings":"AAQA,qFAAqF;AACrF,MAAM,OAAO,aAAa;IAA1B;QACU,QAAG,GAAG,IAAI,GAAG,EAAuB,CAAC;QACrC,QAAG,GAAG,CAAC,QAAgB,EAAE,KAAa,EAAE,EAAE,CAAC,GAAG,QAAQ,IAAI,KAAK,EAAE,CAAC;IAwB5E,CAAC;IAtBC,GAAG,CAAI,QAAgB,EAAE,KAAa;QACpC,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,EAAE,KAAsB,CAAC;IACzE,CAAC;IAED,iFAAiF;IACjF,KAAK,CAAC,QAAgB,EAAE,KAAa,EAAE,GAAgB;QACrD,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QACpC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC5B,wEAAwE;QACxE,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YACtE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;YACrB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,QAAQ;QACN,OAAO,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACtC,CAAC;IACD,IAAI,CAAC,IAAiC;QACpC,IAAI,CAAC,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IAC3C,CAAC;CACF"} \ No newline at end of file diff --git a/packages/engine-core/dist/index.d.ts b/packages/engine-core/dist/index.d.ts index 04c9a60..d4be133 100644 --- a/packages/engine-core/dist/index.d.ts +++ b/packages/engine-core/dist/index.d.ts @@ -4,6 +4,7 @@ export * from "./game/state"; export * from "./game/commands"; export * from "./game/events"; export * from "./game/i18n"; +export * from "./game/net"; export * from "./events"; export * from "./ports"; export declare const VERSION = "0.4.0"; diff --git a/packages/engine-core/dist/index.d.ts.map b/packages/engine-core/dist/index.d.ts.map index 2737960..c419988 100644 --- a/packages/engine-core/dist/index.d.ts.map +++ b/packages/engine-core/dist/index.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AAExB,eAAO,MAAM,OAAO,UAAU,CAAC"} \ No newline at end of file +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AAExB,eAAO,MAAM,OAAO,UAAU,CAAC"} \ No newline at end of file diff --git a/packages/engine-core/dist/index.js b/packages/engine-core/dist/index.js index a31b0fe..04947fe 100644 --- a/packages/engine-core/dist/index.js +++ b/packages/engine-core/dist/index.js @@ -4,6 +4,7 @@ export * from "./game/state"; export * from "./game/commands"; export * from "./game/events"; export * from "./game/i18n"; +export * from "./game/net"; export * from "./events"; export * from "./ports"; export const VERSION = "0.4.0"; diff --git a/packages/engine-core/dist/index.js.map b/packages/engine-core/dist/index.js.map index 183441b..e8505e0 100644 --- a/packages/engine-core/dist/index.js.map +++ b/packages/engine-core/dist/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AAExB,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AAExB,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC"} \ No newline at end of file diff --git a/packages/engine-core/dist/ports/headlessMultiplayer.d.ts b/packages/engine-core/dist/ports/headlessMultiplayer.d.ts new file mode 100644 index 0000000..5ebc28f --- /dev/null +++ b/packages/engine-core/dist/ports/headlessMultiplayer.d.ts @@ -0,0 +1,25 @@ +import type { ConnectOptions, ConnectionStatus, MultiplayerPort, NetEnvelope, PlayerId } from "./multiplayer"; +export declare class InMemoryHub { + private peers; + register(id: PlayerId, room: string, inbound: (m: NetEnvelope) => void): () => void; + /** Fan-out a los peers de la MISMA room que el mensaje, menos al emisor. */ + broadcast(from: PlayerId, _room: string, message: NetEnvelope): void; +} +/** Adapter de loopback para tests. Implementa MultiplayerPort contra un InMemoryHub. */ +export declare class HeadlessMultiplayerAdapter implements MultiplayerPort { + private hub; + readonly selfId: PlayerId; + private room; + private connected; + private unregister; + private msgHandlers; + private statusHandlers; + constructor(hub: InMemoryHub, selfId?: PlayerId); + connect(opts: ConnectOptions): void; + disconnect(): void; + send(message: NetEnvelope): void; + onMessage(handler: (m: NetEnvelope) => void): () => void; + onStatus(handler: (s: ConnectionStatus) => void): () => void; + private emitStatus; +} +//# sourceMappingURL=headlessMultiplayer.d.ts.map \ No newline at end of file diff --git a/packages/engine-core/dist/ports/headlessMultiplayer.d.ts.map b/packages/engine-core/dist/ports/headlessMultiplayer.d.ts.map new file mode 100644 index 0000000..7afcf02 --- /dev/null +++ b/packages/engine-core/dist/ports/headlessMultiplayer.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"headlessMultiplayer.d.ts","sourceRoot":"","sources":["../../src/ports/headlessMultiplayer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,WAAW,EACX,QAAQ,EACT,MAAM,eAAe,CAAC;AAWvB,qBAAa,WAAW;IACtB,OAAO,CAAC,KAAK,CAAgC;IAE7C,QAAQ,CACN,EAAE,EAAE,QAAQ,EACZ,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,CAAC,CAAC,EAAE,WAAW,KAAK,IAAI,GAChC,MAAM,IAAI;IAKb,4EAA4E;IAC5E,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,IAAI;CAOrE;AAID,wFAAwF;AACxF,qBAAa,0BAA2B,YAAW,eAAe;IAS9D,OAAO,CAAC,GAAG;IARb,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1B,OAAO,CAAC,IAAI,CAAM;IAClB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,UAAU,CAA6B;IAC/C,OAAO,CAAC,WAAW,CAAuC;IAC1D,OAAO,CAAC,cAAc,CAA4C;gBAGxD,GAAG,EAAE,WAAW,EACxB,MAAM,CAAC,EAAE,QAAQ;IAKnB,OAAO,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI;IASnC,UAAU,IAAI,IAAI;IAOlB,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;IAKhC,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,WAAW,KAAK,IAAI,GAAG,MAAM,IAAI;IAOxD,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,gBAAgB,KAAK,IAAI,GAAG,MAAM,IAAI;IAO5D,OAAO,CAAC,UAAU;CAGnB"} \ No newline at end of file diff --git a/packages/engine-core/dist/ports/headlessMultiplayer.js b/packages/engine-core/dist/ports/headlessMultiplayer.js new file mode 100644 index 0000000..08571f4 --- /dev/null +++ b/packages/engine-core/dist/ports/headlessMultiplayer.js @@ -0,0 +1,67 @@ +export class InMemoryHub { + constructor() { + this.peers = new Map(); + } + register(id, room, inbound) { + this.peers.set(id, { room, inbound }); + return () => this.peers.delete(id); + } + /** Fan-out a los peers de la MISMA room que el mensaje, menos al emisor. */ + broadcast(from, _room, message) { + for (const [id, peer] of this.peers) { + if (id === from) + continue; + if (peer.room !== message.room) + continue; // aísla por room del receptor + peer.inbound(message); + } + } +} +let _autoId = 0; +/** Adapter de loopback para tests. Implementa MultiplayerPort contra un InMemoryHub. */ +export class HeadlessMultiplayerAdapter { + constructor(hub, selfId) { + this.hub = hub; + this.room = ""; + this.connected = false; + this.unregister = null; + this.msgHandlers = []; + this.statusHandlers = []; + this.selfId = selfId ?? `headless-${++_autoId}`; + } + connect(opts) { + this.room = opts.room; + this.connected = true; + this.unregister = this.hub.register(this.selfId, this.room, (m) => { + this.msgHandlers.forEach((h) => h(m)); + }); + this.emitStatus({ state: "connected", selfId: this.selfId }); + } + disconnect() { + this.connected = false; + this.unregister?.(); + this.unregister = null; + this.emitStatus({ state: "disconnected" }); + } + send(message) { + if (!this.connected) + return; + this.hub.broadcast(this.selfId, this.room, message); + } + onMessage(handler) { + this.msgHandlers.push(handler); + return () => { + this.msgHandlers = this.msgHandlers.filter((h) => h !== handler); + }; + } + onStatus(handler) { + this.statusHandlers.push(handler); + return () => { + this.statusHandlers = this.statusHandlers.filter((h) => h !== handler); + }; + } + emitStatus(s) { + this.statusHandlers.forEach((h) => h(s)); + } +} +//# sourceMappingURL=headlessMultiplayer.js.map \ No newline at end of file diff --git a/packages/engine-core/dist/ports/headlessMultiplayer.js.map b/packages/engine-core/dist/ports/headlessMultiplayer.js.map new file mode 100644 index 0000000..a1c59d5 --- /dev/null +++ b/packages/engine-core/dist/ports/headlessMultiplayer.js.map @@ -0,0 +1 @@ +{"version":3,"file":"headlessMultiplayer.js","sourceRoot":"","sources":["../../src/ports/headlessMultiplayer.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/engine-core/dist/ports/index.d.ts b/packages/engine-core/dist/ports/index.d.ts index 775501a..287fa0b 100644 --- a/packages/engine-core/dist/ports/index.d.ts +++ b/packages/engine-core/dist/ports/index.d.ts @@ -7,4 +7,7 @@ export { HeadlessInput } from "./headlessInput"; export { HeadlessAudioAdapter, type HeadlessAudioCall } from "./headlessAudio"; export type { I18nPort } from "./i18n"; export { HeadlessI18nAdapter, type HeadlessI18nCall } from "./headlessI18n"; +export type { PlayerId, RoomId, NetEnvelope, NetEnvelopeKind, ConnectionStatus, ConnectOptions, MultiplayerPort, } from "./multiplayer"; +export { NET_PROTOCOL_VERSION } from "./multiplayer"; +export { HeadlessMultiplayerAdapter, InMemoryHub } from "./headlessMultiplayer"; //# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/packages/engine-core/dist/ports/index.d.ts.map b/packages/engine-core/dist/ports/index.d.ts.map index 20dc153..2f8bb60 100644 --- a/packages/engine-core/dist/ports/index.d.ts.map +++ b/packages/engine-core/dist/ports/index.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ports/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,gBAAgB,EAChB,YAAY,EACZ,WAAW,GACZ,MAAM,YAAY,CAAC;AAEpB,YAAY,EACV,cAAc,EACd,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,SAAS,GACV,MAAM,SAAS,CAAC;AAEjB,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,YAAY,EACV,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,SAAS,GACV,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,oBAAoB,EAAE,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAE/E,YAAY,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EAAE,mBAAmB,EAAE,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC"} \ No newline at end of file +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ports/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,gBAAgB,EAChB,YAAY,EACZ,WAAW,GACZ,MAAM,YAAY,CAAC;AAEpB,YAAY,EACV,cAAc,EACd,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,SAAS,GACV,MAAM,SAAS,CAAC;AAEjB,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,YAAY,EACV,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,SAAS,GACV,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,oBAAoB,EAAE,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAE/E,YAAY,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EAAE,mBAAmB,EAAE,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAE5E,YAAY,EACV,QAAQ,EACR,MAAM,EACN,WAAW,EACX,eAAe,EACf,gBAAgB,EAChB,cAAc,EACd,eAAe,GAChB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,0BAA0B,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC"} \ No newline at end of file diff --git a/packages/engine-core/dist/ports/index.js b/packages/engine-core/dist/ports/index.js index cca10ce..c6339e3 100644 --- a/packages/engine-core/dist/ports/index.js +++ b/packages/engine-core/dist/ports/index.js @@ -2,4 +2,6 @@ export { HeadlessGameLoop } from "./headlessGameLoop"; export { HeadlessInput } from "./headlessInput"; export { HeadlessAudioAdapter } from "./headlessAudio"; export { HeadlessI18nAdapter } from "./headlessI18n"; +export { NET_PROTOCOL_VERSION } from "./multiplayer"; +export { HeadlessMultiplayerAdapter, InMemoryHub } from "./headlessMultiplayer"; //# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/packages/engine-core/dist/ports/index.js.map b/packages/engine-core/dist/ports/index.js.map index 3262b86..50739f8 100644 --- a/packages/engine-core/dist/ports/index.js.map +++ b/packages/engine-core/dist/ports/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ports/index.ts"],"names":[],"mappings":"AAwBA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,oBAAoB,EAA0B,MAAM,iBAAiB,CAAC;AAG/E,OAAO,EAAE,mBAAmB,EAAyB,MAAM,gBAAgB,CAAC"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ports/index.ts"],"names":[],"mappings":"AAwBA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,oBAAoB,EAA0B,MAAM,iBAAiB,CAAC;AAG/E,OAAO,EAAE,mBAAmB,EAAyB,MAAM,gBAAgB,CAAC;AAW5E,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,0BAA0B,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC"} \ No newline at end of file diff --git a/packages/engine-core/dist/ports/multiplayer.d.ts b/packages/engine-core/dist/ports/multiplayer.d.ts new file mode 100644 index 0000000..c89b44d --- /dev/null +++ b/packages/engine-core/dist/ports/multiplayer.d.ts @@ -0,0 +1,62 @@ +/** + * MultiplayerPort – contrato agnóstico de transporte multijugador. + * + * El core SOLO habla con esta interfaz. Los adapters (PartyKit, headless, …) la + * implementan fuera del core. Ningún import de red/`window`/proveedor aquí. + * + * Ver docs/architecture/09-multiplayer.md §3 y ADR-0008. + */ +/** Identificadores. */ +export type PlayerId = string; +export type RoomId = string; +/** Versión del protocolo de red. Súbela ante cambios incompatibles del sobre. */ +export declare const NET_PROTOCOL_VERSION = 1; +/** Tipo de carga del sobre. `payload` se interpreta según este discriminador. */ +export type NetEnvelopeKind = "command" | "event" | "presence" | "snapshot" | "claim" | "claim-result"; +/** Sobre serializable que viaja por el cable. SIEMPRE JSON-serializable. */ +export interface NetEnvelope { + /** Versión de protocolo (NET_PROTOCOL_VERSION). */ + v: number; + /** Room/partida destino. */ + room: RoomId; + /** Emisor. */ + from: PlayerId; + /** Reloj lógico (HLC en task 05; Date.now() hasta entonces). Para ordenar/LWW. */ + ts: number; + /** Discriminador de payload. */ + kind: NetEnvelopeKind; + /** Carga; su forma depende de `kind`. */ + payload: T; +} +/** Estado de conexión reportado por el transporte. */ +export type ConnectionStatus = { + state: "connecting"; +} | { + state: "connected"; + selfId: PlayerId; +} | { + state: "disconnected"; + reason?: string; +}; +/** Opciones para conectar a una room. `selfId` puede asignarlo el servidor. */ +export interface ConnectOptions { + room: RoomId; + selfId?: PlayerId; +} +/** + * Puerto agnóstico de transporte multijugador. Implementado fuera del core por + * adapters (PartyKit, headless, …). El core SOLO habla con esta interfaz. + */ +export interface MultiplayerPort { + /** Abre la conexión a la room. Idempotente si ya conectado. */ + connect(opts: ConnectOptions): Promise | void; + /** Cierra la conexión y libera recursos. */ + disconnect(): void; + /** Envía un sobre a los peers (o al relay, que hace fan-out). Fire-and-forget. */ + send(message: NetEnvelope): void; + /** Suscribe a sobres entrantes. Devuelve unsubscribe. */ + onMessage(handler: (message: NetEnvelope) => void): () => void; + /** Suscribe a cambios de estado de conexión. Devuelve unsubscribe. */ + onStatus(handler: (status: ConnectionStatus) => void): () => void; +} +//# sourceMappingURL=multiplayer.d.ts.map \ No newline at end of file diff --git a/packages/engine-core/dist/ports/multiplayer.d.ts.map b/packages/engine-core/dist/ports/multiplayer.d.ts.map new file mode 100644 index 0000000..8c3bc08 --- /dev/null +++ b/packages/engine-core/dist/ports/multiplayer.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"multiplayer.d.ts","sourceRoot":"","sources":["../../src/ports/multiplayer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,uBAAuB;AACvB,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC;AAC9B,MAAM,MAAM,MAAM,GAAG,MAAM,CAAC;AAE5B,iFAAiF;AACjF,eAAO,MAAM,oBAAoB,IAAI,CAAC;AAEtC,iFAAiF;AACjF,MAAM,MAAM,eAAe,GACvB,SAAS,GACT,OAAO,GACP,UAAU,GACV,UAAU,GACV,OAAO,GACP,cAAc,CAAC;AAEnB,4EAA4E;AAC5E,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,OAAO;IACtC,mDAAmD;IACnD,CAAC,EAAE,MAAM,CAAC;IACV,4BAA4B;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,cAAc;IACd,IAAI,EAAE,QAAQ,CAAC;IACf,kFAAkF;IAClF,EAAE,EAAE,MAAM,CAAC;IACX,gCAAgC;IAChC,IAAI,EAAE,eAAe,CAAC;IACtB,yCAAyC;IACzC,OAAO,EAAE,CAAC,CAAC;CACZ;AAED,sDAAsD;AACtD,MAAM,MAAM,gBAAgB,GACxB;IAAE,KAAK,EAAE,YAAY,CAAA;CAAE,GACvB;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,QAAQ,CAAA;CAAE,GACxC;IAAE,KAAK,EAAE,cAAc,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/C,+EAA+E;AAC/E,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,QAAQ,CAAC;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,+DAA+D;IAC/D,OAAO,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACpD,4CAA4C;IAC5C,UAAU,IAAI,IAAI,CAAC;IACnB,kFAAkF;IAClF,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;IACjC,yDAAyD;IACzD,SAAS,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAC/D,sEAAsE;IACtE,QAAQ,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;CACnE"} \ No newline at end of file diff --git a/packages/engine-core/dist/ports/multiplayer.js b/packages/engine-core/dist/ports/multiplayer.js new file mode 100644 index 0000000..96ee7ef --- /dev/null +++ b/packages/engine-core/dist/ports/multiplayer.js @@ -0,0 +1,11 @@ +/** + * MultiplayerPort – contrato agnóstico de transporte multijugador. + * + * El core SOLO habla con esta interfaz. Los adapters (PartyKit, headless, …) la + * implementan fuera del core. Ningún import de red/`window`/proveedor aquí. + * + * Ver docs/architecture/09-multiplayer.md §3 y ADR-0008. + */ +/** Versión del protocolo de red. Súbela ante cambios incompatibles del sobre. */ +export const NET_PROTOCOL_VERSION = 1; +//# sourceMappingURL=multiplayer.js.map \ No newline at end of file diff --git a/packages/engine-core/dist/ports/multiplayer.js.map b/packages/engine-core/dist/ports/multiplayer.js.map new file mode 100644 index 0000000..56e4aa7 --- /dev/null +++ b/packages/engine-core/dist/ports/multiplayer.js.map @@ -0,0 +1 @@ +{"version":3,"file":"multiplayer.js","sourceRoot":"","sources":["../../src/ports/multiplayer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,iFAAiF;AACjF,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC"} \ No newline at end of file diff --git a/packages/engine-core/src/__tests__/eventClassification.test.ts b/packages/engine-core/src/__tests__/eventClassification.test.ts new file mode 100644 index 0000000..60856f6 --- /dev/null +++ b/packages/engine-core/src/__tests__/eventClassification.test.ts @@ -0,0 +1,29 @@ +import { describe, it, expect } from "vitest"; +import { + EVENT_CLASSIFICATION, + classifyEvent, + shouldReplicate, + isWorld, +} from "../game/net/eventClassification"; + +describe("eventClassification", () => { + it("classifies pickup as world+private", () => { + expect(classifyEvent("item:pickedUp")).toEqual(["world", "private"]); + }); + it("dialog never crosses the wire", () => { + expect(shouldReplicate("dialog:triggered")).toBe(false); + }); + it("player:moved is presence", () => { + expect(shouldReplicate("player:moved")).toBe(true); + expect(isWorld("player:moved")).toBe(false); + }); + it("net events are private (never replicated)", () => { + expect(shouldReplicate("net:playerJoined")).toBe(false); + expect(shouldReplicate("net:status")).toBe(false); + }); + it("every classified type has at least one class", () => { + for (const classes of Object.values(EVENT_CLASSIFICATION)) { + expect(classes.length).toBeGreaterThan(0); + } + }); +}); diff --git a/packages/engine-core/src/__tests__/itemClaim.test.ts b/packages/engine-core/src/__tests__/itemClaim.test.ts new file mode 100644 index 0000000..a4158ff --- /dev/null +++ b/packages/engine-core/src/__tests__/itemClaim.test.ts @@ -0,0 +1,23 @@ +import { describe, it, expect } from "vitest"; +import { resolveClaim } from "../game/net/claims"; + +describe("resolveClaim", () => { + it("exactly one winner for concurrent claims", () => { + const res = resolveClaim([ + { entityId: "key", by: "A", ts: 5 }, + { entityId: "key", by: "B", ts: 5 }, // same ts → tie-break by id + ]); + expect(res.filter((r) => r.granted)).toHaveLength(1); + expect(res.find((r) => r.granted)!.by).toBe("A"); + }); + it("first writer (lower ts) wins", () => { + const res = resolveClaim([ + { entityId: "key", by: "A", ts: 9 }, + { entityId: "key", by: "B", ts: 3 }, + ]); + expect(res.find((r) => r.granted)!.by).toBe("B"); + }); + it("empty input yields no results", () => { + expect(resolveClaim([])).toEqual([]); + }); +}); diff --git a/packages/engine-core/src/__tests__/multiplayerPort.test.ts b/packages/engine-core/src/__tests__/multiplayerPort.test.ts new file mode 100644 index 0000000..0107b1f --- /dev/null +++ b/packages/engine-core/src/__tests__/multiplayerPort.test.ts @@ -0,0 +1,67 @@ +import { describe, it, expect, vi } from "vitest"; +import { + HeadlessMultiplayerAdapter, + InMemoryHub, +} from "../ports/headlessMultiplayer"; +import { NET_PROTOCOL_VERSION, type NetEnvelope } from "../ports/multiplayer"; + +const env = (from: string, room = "r1"): NetEnvelope => ({ + v: NET_PROTOCOL_VERSION, + room, + from, + ts: 1, + kind: "event", + payload: { type: "ping" }, +}); + +describe("MultiplayerPort headless", () => { + it("delivers a sent message to peers but not to self", () => { + const hub = new InMemoryHub(); + const a = new HeadlessMultiplayerAdapter(hub, "A"); + const b = new HeadlessMultiplayerAdapter(hub, "B"); + a.connect({ room: "r1" }); + b.connect({ room: "r1" }); + const aSeen = vi.fn(); + const bSeen = vi.fn(); + a.onMessage(aSeen); + b.onMessage(bSeen); + a.send(env("A")); + expect(bSeen).toHaveBeenCalledTimes(1); + expect(aSeen).not.toHaveBeenCalled(); + }); + + it("does not deliver across different rooms", () => { + const hub = new InMemoryHub(); + const a = new HeadlessMultiplayerAdapter(hub, "A"); + const b = new HeadlessMultiplayerAdapter(hub, "B"); + a.connect({ room: "r1" }); + b.connect({ room: "r2" }); + const bSeen = vi.fn(); + b.onMessage(bSeen); + a.send(env("A", "r1")); + expect(bSeen).not.toHaveBeenCalled(); + }); + + it("reports connected/disconnected status", () => { + const hub = new InMemoryHub(); + const a = new HeadlessMultiplayerAdapter(hub, "A"); + const seen: string[] = []; + a.onStatus((s) => seen.push(s.state)); + a.connect({ room: "r1" }); + a.disconnect(); + expect(seen).toEqual(["connected", "disconnected"]); + }); + + it("stops receiving after disconnect", () => { + const hub = new InMemoryHub(); + const a = new HeadlessMultiplayerAdapter(hub, "A"); + const b = new HeadlessMultiplayerAdapter(hub, "B"); + a.connect({ room: "r1" }); + b.connect({ room: "r1" }); + const bSeen = vi.fn(); + b.onMessage(bSeen); + b.disconnect(); + a.send(env("A")); + expect(bSeen).not.toHaveBeenCalled(); + }); +}); diff --git a/packages/engine-core/src/__tests__/multiplayerSession.test.ts b/packages/engine-core/src/__tests__/multiplayerSession.test.ts new file mode 100644 index 0000000..6a56199 --- /dev/null +++ b/packages/engine-core/src/__tests__/multiplayerSession.test.ts @@ -0,0 +1,101 @@ +import { describe, it, expect } from "vitest"; +import { InMemoryHub, HeadlessMultiplayerAdapter } from "../ports/headlessMultiplayer"; +import { createMultiplayerSession } from "../game/net/MultiplayerSession"; +import { createRemotePlayersStore } from "../game/net/remotePlayersStore"; +import { createSelfDescriptor } from "../game/net/playerIdentity"; +import type { GameEvent, GameEventType } from "../game/events/types"; + +// Bus de test: registro por tipo + emit que invoca a los listeners de ese tipo. +function makeBus() { + const map = new Map void>>(); + return { + on: (t: GameEventType, h: (e: GameEvent) => void) => { + const arr = map.get(t) ?? []; + arr.push(h); + map.set(t, arr); + return () => map.set(t, (map.get(t) ?? []).filter((x) => x !== h)); + }, + emit: (e: GameEvent) => (map.get(e.type) ?? []).forEach((h) => h(e)), + }; +} + +function peer(hub: InMemoryHub, id: string, applied: GameEvent[]) { + const bus = makeBus(); + const remotePlayers = createRemotePlayersStore(); + const session = createMultiplayerSession({ + port: new HeadlessMultiplayerAdapter(hub, id), + bus, + room: "r1", + remotePlayers, + self: createSelfDescriptor({ + playerId: id, + sceneId: "town", + position: [0, 0, 0], + displayName: id, + }), + applyRemoteEvent: (e) => { + applied.push(e); + bus.emit(e); + }, // re-emite al bus local + now: () => 1, + presenceThrottleMs: 0, // sin throttle para tests deterministas + }); + return { bus, remotePlayers, session }; +} + +describe("MultiplayerSession", () => { + it("replicates a world event to the other peer", () => { + const hub = new InMemoryHub(); + const appliedB: GameEvent[] = []; + const a = peer(hub, "A", []); + peer(hub, "B", appliedB); + a.bus.emit({ type: "item:dropped", itemId: "key", outcome: "place" }); + expect(appliedB).toContainEqual({ + type: "item:dropped", + itemId: "key", + outcome: "place", + }); + }); + + it("does NOT replicate a private event", () => { + const hub = new InMemoryHub(); + const appliedB: GameEvent[] = []; + const a = peer(hub, "A", []); + peer(hub, "B", appliedB); + a.bus.emit({ type: "dialog:triggered", text: "hi", source: "test" }); + expect(appliedB).toHaveLength(0); + }); + + it("does not echo a remote-applied event back to the wire", () => { + const hub = new InMemoryHub(); + const appliedA: GameEvent[] = []; + const appliedB: GameEvent[] = []; + const a = peer(hub, "A", appliedA); + peer(hub, "B", appliedB); + a.bus.emit({ type: "item:dropped", itemId: "key", outcome: "place" }); + expect(appliedB.filter((e) => e.type === "item:dropped")).toHaveLength(1); + expect(appliedA.filter((e) => e.type === "item:dropped")).toHaveLength(0); + }); + + it("upserts remote presence and emits net:playerJoined", () => { + const hub = new InMemoryHub(); + const joined: GameEvent[] = []; + const a = peer(hub, "A", []); + a.bus.on("net:playerJoined", (e) => joined.push(e)); + peer(hub, "B", []); // B se conecta → manda presence + expect( + a.remotePlayers.getInScene("town").some((p) => p.playerId === "B"), + ).toBe(true); + expect(joined.some((e) => e.type === "net:playerJoined")).toBe(true); + }); + + it("propagates presence position via player:moved", () => { + const hub = new InMemoryHub(); + const a = peer(hub, "A", []); + const b = peer(hub, "B", []); + b.bus.emit({ type: "player:moved", position: [5, 0, 7], action: "east" }); + const bOnA = a.remotePlayers.getInScene("town").find((p) => p.playerId === "B"); + expect(bOnA?.position).toEqual([5, 0, 7]); + expect(bOnA?.action).toBe("east"); + }); +}); diff --git a/packages/engine-core/src/__tests__/netAgnosticism.test.ts b/packages/engine-core/src/__tests__/netAgnosticism.test.ts new file mode 100644 index 0000000..7f6fd10 --- /dev/null +++ b/packages/engine-core/src/__tests__/netAgnosticism.test.ts @@ -0,0 +1,43 @@ +import { describe, it, expect } from "vitest"; +import { readFileSync, readdirSync, statSync } from "node:fs"; +import { join } from "node:path"; + +const FORBIDDEN = [ + /\bwindow\b/, + /\bdocument\b/, + /WebSocket/, + /localStorage/, + /partysocket/, + /from ["'].*\/apps\//, +]; + +function walk(dir: string): string[] { + return readdirSync(dir).flatMap((f) => { + const p = join(dir, f); + if (statSync(p).isDirectory()) return walk(p); + return p.endsWith(".ts") && !p.endsWith(".test.ts") ? [p] : []; + }); +} + +/** Quita comentarios para que menciones en prosa no cuenten como uso real. */ +function stripComments(code: string): string { + return code + .replace(/\/\*[\s\S]*?\*\//g, "") // block comments + .replace(/(^|[^:])\/\/.*$/gm, "$1"); // line comments (no rompe http://) +} + +describe("core agnosticism (net)", () => { + it("game/net and ports/multiplayer never touch the network or window", () => { + const files = [ + ...walk(join(__dirname, "..", "game", "net")), + join(__dirname, "..", "ports", "multiplayer.ts"), + join(__dirname, "..", "ports", "headlessMultiplayer.ts"), + ]; + for (const f of files) { + const code = stripComments(readFileSync(f, "utf8")); + for (const re of FORBIDDEN) { + expect(re.test(code), `${f} matched ${re}`).toBe(false); + } + } + }); +}); diff --git a/packages/engine-core/src/__tests__/optimisticReconcile.test.ts b/packages/engine-core/src/__tests__/optimisticReconcile.test.ts new file mode 100644 index 0000000..998850e --- /dev/null +++ b/packages/engine-core/src/__tests__/optimisticReconcile.test.ts @@ -0,0 +1,32 @@ +import { describe, it, expect, vi } from "vitest"; +import { createOptimisticReconciler } from "../game/net/optimistic"; + +describe("optimistic reconciler", () => { + it("confirm does not roll back", () => { + const r = createOptimisticReconciler(); + const rollback = vi.fn(); + r.track("key", rollback); + r.confirm("key"); + expect(rollback).not.toHaveBeenCalled(); + expect(r.size()).toBe(0); + }); + it("reject rolls back exactly once", () => { + const r = createOptimisticReconciler(); + const rollback = vi.fn(); + r.track("key", rollback); + r.reject("key"); + expect(rollback).toHaveBeenCalledTimes(1); + expect(r.size()).toBe(0); + }); + it("onSnapshot reverts all unconfirmed predictions", () => { + const r = createOptimisticReconciler(); + const a = vi.fn(); + const b = vi.fn(); + r.track("k1", a); + r.track("k2", b); + r.onSnapshot(); + expect(a).toHaveBeenCalledTimes(1); + expect(b).toHaveBeenCalledTimes(1); + expect(r.size()).toBe(0); + }); +}); diff --git a/packages/engine-core/src/__tests__/presence.test.ts b/packages/engine-core/src/__tests__/presence.test.ts new file mode 100644 index 0000000..6a2100c --- /dev/null +++ b/packages/engine-core/src/__tests__/presence.test.ts @@ -0,0 +1,24 @@ +import { describe, it, expect, vi } from "vitest"; +import { throttleTrailing } from "../game/net/throttle"; + +describe("throttleTrailing", () => { + it("runs immediately then coalesces, flushing the last call", () => { + let t = 0; + const scheduled: Array<{ cb: () => void; at: number }> = []; + const clock = { + now: () => t, + schedule: (cb: () => void, d: number) => scheduled.push({ cb, at: t + d }), + }; + const fn = vi.fn(); + const throttled = throttleTrailing(fn, 100, clock); + throttled(); // t=0 → runs (1) + t = 30; + throttled(); // within window → schedules trailing + t = 60; + throttled(); // still within → already scheduled + expect(fn).toHaveBeenCalledTimes(1); + t = 100; + scheduled.forEach((s) => s.cb()); // flush trailing + expect(fn).toHaveBeenCalledTimes(2); // last call flushed + }); +}); diff --git a/packages/engine-core/src/__tests__/remotePlayersStore.test.ts b/packages/engine-core/src/__tests__/remotePlayersStore.test.ts new file mode 100644 index 0000000..42894ce --- /dev/null +++ b/packages/engine-core/src/__tests__/remotePlayersStore.test.ts @@ -0,0 +1,33 @@ +import { describe, it, expect } from "vitest"; +import { createRemotePlayersStore } from "../game/net/remotePlayersStore"; +import { generateRandomName } from "../game/net/playerIdentity"; + +describe("remotePlayersStore", () => { + it("upsert merges partials and filters by scene", () => { + const s = createRemotePlayersStore(); + s.upsert({ playerId: "B", sceneId: "town", position: [1, 0, 2] }); + s.upsert({ playerId: "C", sceneId: "cave", position: [0, 0, 0] }); + expect(s.getInScene("town").map((p) => p.playerId)).toEqual(["B"]); + s.upsert({ playerId: "B", position: [3, 0, 4] }); // keeps sceneId=town + expect(s.getInScene("town")[0]!.position).toEqual([3, 0, 4]); + }); + it("pruneStale removes old players", () => { + const s = createRemotePlayersStore(); + s.upsert({ playerId: "B", sceneId: "town", lastSeenTs: 1000 }); + expect(s.pruneStale(500, 2000)).toEqual(["B"]); + expect(s.getAll()).toHaveLength(0); + }); + it("notifies subscribers on change", () => { + const s = createRemotePlayersStore(); + let n = 0; + const unsub = s.subscribe(() => n++); + s.upsert({ playerId: "B", sceneId: "town" }); + s.remove("B"); + unsub(); + s.upsert({ playerId: "C", sceneId: "town" }); + expect(n).toBe(2); + }); + it("generateRandomName is deterministic with injected rng", () => { + expect(generateRandomName(() => 0)).toMatch(/^Viajero-000$/); + }); +}); diff --git a/packages/engine-core/src/__tests__/worldStateLww.test.ts b/packages/engine-core/src/__tests__/worldStateLww.test.ts new file mode 100644 index 0000000..b2a16eb --- /dev/null +++ b/packages/engine-core/src/__tests__/worldStateLww.test.ts @@ -0,0 +1,27 @@ +import { describe, it, expect } from "vitest"; +import { WorldStateLww } from "../game/net/worldState"; +import { Hlc } from "../game/net/clock"; + +describe("WorldStateLww", () => { + it("keeps the higher ts", () => { + const w = new WorldStateLww(); + expect(w.merge("door1", "open", { value: false, ts: 1, by: "A" })).toBe(true); + expect(w.merge("door1", "open", { value: true, ts: 2, by: "B" })).toBe(true); + expect(w.merge("door1", "open", { value: false, ts: 1, by: "C" })).toBe(false); + expect(w.get("door1", "open")).toBe(true); + }); + it("round-trips via snapshot/load", () => { + const w = new WorldStateLww(); + w.merge("door1", "open", { value: true, ts: 5, by: "A" }); + const w2 = new WorldStateLww(); + w2.load(w.snapshot()); + expect(w2.get("door1", "open")).toBe(true); + }); + it("Hlc is monotonic even within the same wall ms", () => { + const hlc = new Hlc(); + const a = hlc.now(1000); + const b = hlc.now(1000); + const c = hlc.now(1000); + expect(a < b && b < c).toBe(true); + }); +}); diff --git a/packages/engine-core/src/game/commands/types.ts b/packages/engine-core/src/game/commands/types.ts index db3bf41..5865e04 100644 --- a/packages/engine-core/src/game/commands/types.ts +++ b/packages/engine-core/src/game/commands/types.ts @@ -31,6 +31,10 @@ export type GameCommand = | { type: "audio:setVolume"; target: AudioMuteTarget; volume: number } // i18n | { type: "i18n:setLocale"; locale: Locale } - | { type: "i18n:registerDictionary"; locale: Locale; dict: DialogDictionary }; + | { type: "i18n:registerDictionary"; locale: Locale; dict: DialogDictionary } + // Net + | { type: "net:join"; room: string; displayName?: string } + | { type: "net:leave" } + | { type: "net:setName"; displayName: string }; export type GameCommandType = GameCommand["type"]; diff --git a/packages/engine-core/src/game/events/types.ts b/packages/engine-core/src/game/events/types.ts index ad205f4..37aedbd 100644 --- a/packages/engine-core/src/game/events/types.ts +++ b/packages/engine-core/src/game/events/types.ts @@ -1,4 +1,6 @@ import type { AudioSettings, GameScene, GameVec3, Locale, SoundCategory } from "../types"; +import type { PlayerDescriptor } from "../net/playerIdentity"; +import type { ConnectionStatus, PlayerId } from "../../ports/multiplayer"; /** * Union exhaustiva de todos los eventos que el motor puede emitir. @@ -45,7 +47,11 @@ export type GameEvent = | { type: "audio:settingsChanged"; settings: AudioSettings } // i18n | { type: "i18n:localeChanged"; locale: Locale; previous: Locale } - | { type: "i18n:dictionaryUpdated"; locale: Locale; keysAdded: number }; + | { type: "i18n:dictionaryUpdated"; locale: Locale; keysAdded: number } + // Net (locales para UI; nunca se replican — ver eventClassification) + | { type: "net:playerJoined"; player: PlayerDescriptor } + | { type: "net:playerLeft"; playerId: PlayerId } + | { type: "net:status"; status: ConnectionStatus }; export type GameEventType = GameEvent["type"]; diff --git a/packages/engine-core/src/game/net/MultiplayerSession.ts b/packages/engine-core/src/game/net/MultiplayerSession.ts new file mode 100644 index 0000000..be1142d --- /dev/null +++ b/packages/engine-core/src/game/net/MultiplayerSession.ts @@ -0,0 +1,155 @@ +import type { GameEvent, GameEventType } from "../events/types"; +import type { MultiplayerPort, NetEnvelope, RoomId } from "../../ports/multiplayer"; +import { NET_PROTOCOL_VERSION } from "../../ports/multiplayer"; +import type { PlayerDescriptor } from "./playerIdentity"; +import type { RemotePlayersStore } from "./remotePlayersStore"; +import { EVENT_CLASSIFICATION, shouldReplicate, isWorld } from "./eventClassification"; +import { throttleTrailing, type ThrottleClock } from "./throttle"; +import type { OptimisticReconciler } from "./optimistic"; + +/** Bus mínimo que la sesión necesita (lo cumple el handle de createGameRuntime). */ +export interface SessionBus { + on: (type: GameEventType, handler: (e: GameEvent) => void) => () => void; + emit: (event: GameEvent) => void; +} + +export interface MultiplayerSessionOptions { + port: MultiplayerPort; + bus: SessionBus; + room: RoomId; + self: PlayerDescriptor; + remotePlayers: RemotePlayersStore; + /** Aplica un evento world remoto al estado local (el host lo cablea a los stores). */ + applyRemoteEvent: (event: GameEvent) => void; + /** Reloj lógico para `ts`. Default Date.now (task 05 puede inyectar HLC). */ + now?: () => number; + /** ms entre envíos de presence. Default 80 (~12.5 Hz). 0 = sin throttle. */ + presenceThrottleMs?: number; + /** Reloj/scheduler para el throttle (inyectable en tests). */ + clock?: ThrottleClock; + /** Reconciliador optimista (task 09) para claim-result/snapshot. */ + reconciler?: OptimisticReconciler; +} + +export interface MultiplayerSession { + dispose: () => void; + getSelf: () => PlayerDescriptor; + /** Actualiza el descriptor local y difunde presence (usado por setName/task 06). */ + updateSelf: (patch: Partial) => void; +} + +export function createMultiplayerSession( + opts: MultiplayerSessionOptions, +): MultiplayerSession { + const { port, bus, room, remotePlayers, applyRemoteEvent } = opts; + const now = opts.now ?? (() => Date.now()); + let self = { ...opts.self }; + let applyingRemote = false; // ⟵ anti-bucle: true mientras aplicamos algo recibido + + const wrap = (kind: NetEnvelope["kind"], payload: unknown): NetEnvelope => ({ + v: NET_PROTOCOL_VERSION, + room, + from: self.playerId, + ts: now(), + kind, + payload, + }); + + const rawSendPresence = () => { + self = { ...self, lastSeenTs: now() }; + port.send(wrap("presence", self)); + }; + + const clock: ThrottleClock = opts.clock ?? { + now: () => Date.now(), + schedule: (cb, d) => { + setTimeout(cb, d); + }, + }; + const throttleMs = opts.presenceThrottleMs ?? 80; + const sendPresence = + throttleMs > 0 ? throttleTrailing(rawSendPresence, throttleMs, clock) : rawSendPresence; + + // ── Salida: suscribe a TODOS los tipos de evento ──────────────────────────── + const types = Object.keys(EVENT_CLASSIFICATION) as GameEventType[]; + const unsubs = types.map((type) => + bus.on(type, (event) => { + if (applyingRemote) return; // no re-difundir lo aplicado desde la red + if (!shouldReplicate(type)) return; // private → nunca sale + if (isWorld(type)) { + port.send(wrap("event", event)); + } + if (type === "player:moved") { + const e = event as Extract; + self = { ...self, position: e.position, action: e.action }; + sendPresence(); + } else if (type === "scene:changed") { + self = { + ...self, + sceneId: (event as Extract).sceneId, + }; + sendPresence(); + } else if (type === "transition:completed") { + self = { + ...self, + sceneId: (event as Extract) + .toSceneId, + }; + sendPresence(); + } + }), + ); + + // ── Entrada: aplica envelopes remotos ─────────────────────────────────────── + const offMsg = port.onMessage((m) => { + if (m.from === self.playerId) return; // defensivo (headless ya filtra self) + if (m.kind === "presence") { + const d = m.payload as PlayerDescriptor & { __left?: boolean }; + if (d.__left) { + remotePlayers.remove(d.playerId); + bus.emit({ type: "net:playerLeft", playerId: d.playerId }); + return; + } + const isNew = remotePlayers.getAll().every((p) => p.playerId !== d.playerId); + remotePlayers.upsert(d); + if (isNew) bus.emit({ type: "net:playerJoined", player: d }); + } else if (m.kind === "event") { + applyingRemote = true; + try { + applyRemoteEvent(m.payload as GameEvent); + } finally { + applyingRemote = false; + } + } else if (m.kind === "claim-result") { + const r = m.payload as { entityId: string; granted: boolean }; + if (r.granted) opts.reconciler?.confirm(r.entityId); + else opts.reconciler?.reject(r.entityId); + } else if (m.kind === "snapshot") { + opts.reconciler?.onSnapshot(); + } + }); + + const offStatus = port.onStatus((status) => { + bus.emit({ type: "net:status", status }); + if (status.state === "connected" && status.selfId) { + self = { ...self, playerId: status.selfId }; + } + }); + + port.connect({ room, selfId: self.playerId }); + rawSendPresence(); // anúnciate al entrar (inmediato, sin throttle) + + return { + dispose: () => { + unsubs.forEach((u) => u()); + offMsg(); + offStatus(); + port.disconnect(); + }, + getSelf: () => self, + updateSelf: (patch) => { + self = { ...self, ...patch }; + sendPresence(); + }, + }; +} diff --git a/packages/engine-core/src/game/net/claims.ts b/packages/engine-core/src/game/net/claims.ts new file mode 100644 index 0000000..597fabf --- /dev/null +++ b/packages/engine-core/src/game/net/claims.ts @@ -0,0 +1,26 @@ +import type { PlayerId } from "../../ports/multiplayer"; + +export interface ItemClaim { + entityId: string; + by: PlayerId; + ts: number; +} +export interface ClaimResult { + entityId: string; + by: PlayerId; + granted: boolean; +} + +/** + * Resuelve un conjunto de claims sobre el MISMO entityId (orden de llegada irrelevante). + * Gana el de menor ts (first-writer-wins); empate → menor playerId. Determinista. + */ +export function resolveClaim(claims: ItemClaim[]): ClaimResult[] { + if (claims.length === 0) return []; + const winner = [...claims].sort((a, b) => a.ts - b.ts || (a.by < b.by ? -1 : 1))[0]!; + return claims.map((c) => ({ + entityId: c.entityId, + by: c.by, + granted: c.by === winner.by, + })); +} diff --git a/packages/engine-core/src/game/net/clock.ts b/packages/engine-core/src/game/net/clock.ts new file mode 100644 index 0000000..399c4f7 --- /dev/null +++ b/packages/engine-core/src/game/net/clock.ts @@ -0,0 +1,27 @@ +/** HLC: combina reloj físico y contador lógico → orden total sin sincronizar relojes. */ +const COUNTER_BITS = 12; // hasta 4096 eventos por ms +const COUNTER_MASK = (1 << COUNTER_BITS) - 1; + +export class Hlc { + private lastPhysical = 0; + private counter = 0; + + /** Devuelve un timestamp codificado (number) monótono creciente. */ + now(wall: number = Date.now()): number { + if (wall > this.lastPhysical) { + this.lastPhysical = wall; + this.counter = 0; + } else { + this.counter = (this.counter + 1) & COUNTER_MASK; + } + return this.lastPhysical * (COUNTER_MASK + 1) + this.counter; + } + + /** Actualiza el reloj al recibir un ts remoto (mantiene la causalidad). */ + update(remoteTs: number, wall: number = Date.now()): number { + const remotePhysical = Math.floor(remoteTs / (COUNTER_MASK + 1)); + this.lastPhysical = Math.max(this.lastPhysical, remotePhysical, wall); + this.counter = (this.counter + 1) & COUNTER_MASK; + return this.lastPhysical * (COUNTER_MASK + 1) + this.counter; + } +} diff --git a/packages/engine-core/src/game/net/eventClassification.ts b/packages/engine-core/src/game/net/eventClassification.ts new file mode 100644 index 0000000..0d12225 --- /dev/null +++ b/packages/engine-core/src/game/net/eventClassification.ts @@ -0,0 +1,58 @@ +import type { GameEventType } from "../events/types"; + +/** Clase de sincronización de un evento. Un evento puede pertenecer a varias. */ +export type SyncClass = "world" | "presence" | "private"; + +/** + * Clasificación exhaustiva. `satisfies` obliga a cubrir TODOS los GameEventType: + * si añades un evento nuevo y no lo clasificas, TypeScript falla aquí. + * + * - world → estado compartido, replicado a todos, persistente (puertas, ítems colocados). + * - presence → efímero por jugador, fan-out a misma escena (posición, escena). + * - private → local, NUNCA cruza la red (diálogos, audio, animación de walk). + */ +export const EVENT_CLASSIFICATION = { + // Scene + "scene:changed": ["presence"], // cambia MI escena → actualiza mi presence + "scene:respawnRequested": ["private"], + // Player + "player:moved": ["presence"], // alta frecuencia; throttle en el borde + "player:collided": ["private"], + // Inventory (pickup quita del world y añade a mi inventario) + "item:pickedUp": ["world", "private"], + "item:dropped": ["world"], // place/consume mutan placedItems compartidos + // Dialog + "dialog:triggered": ["private"], + "dialog:dismissed": ["private"], + // Transitions + "transition:triggered": ["private"], + "transition:started": ["private"], + "transition:completed": ["presence"], // cambio de escena propio + "transition:colliderClicked": ["private"], + // Player walking (se deriva de presence en remotos) + "player:walkStarted": ["private"], + "player:walkCompleted": ["private"], + "player:walkAborted": ["private"], + // Audio (local) + "audio:sfxRequested": ["private"], + "audio:musicRequested": ["private"], + "audio:musicStopped": ["private"], + "audio:settingsChanged": ["private"], + // i18n (local) + "i18n:localeChanged": ["private"], + "i18n:dictionaryUpdated": ["private"], + // Net (locales para UI; nunca se replican) + "net:playerJoined": ["private"], + "net:playerLeft": ["private"], + "net:status": ["private"], +} satisfies Record; + +export function classifyEvent(type: GameEventType): SyncClass[] { + return EVENT_CLASSIFICATION[type] ?? ["private"]; +} +export const isWorld = (t: GameEventType): boolean => classifyEvent(t).includes("world"); +export const isPresence = (t: GameEventType): boolean => + classifyEvent(t).includes("presence"); +/** ¿Debe salir a la red? (world o presence). Los `private` jamás. */ +export const shouldReplicate = (t: GameEventType): boolean => + isWorld(t) || isPresence(t); diff --git a/packages/engine-core/src/game/net/index.ts b/packages/engine-core/src/game/net/index.ts new file mode 100644 index 0000000..6e3dc95 --- /dev/null +++ b/packages/engine-core/src/game/net/index.ts @@ -0,0 +1,9 @@ +export * from "./eventClassification"; +export * from "./playerIdentity"; +export * from "./remotePlayersStore"; +export * from "./MultiplayerSession"; +export * from "./clock"; +export * from "./worldState"; +export * from "./claims"; +export * from "./throttle"; +export * from "./optimistic"; diff --git a/packages/engine-core/src/game/net/optimistic.ts b/packages/engine-core/src/game/net/optimistic.ts new file mode 100644 index 0000000..af3ebfe --- /dev/null +++ b/packages/engine-core/src/game/net/optimistic.ts @@ -0,0 +1,40 @@ +export interface PendingAction { + entityId: string; + rollback: () => void; +} + +/** + * Buffer de acciones optimistas pendientes de confirmación. Cada acción aporta + * su propio `rollback` (cómo deshacerla). Reconciliación determinista. + */ +export function createOptimisticReconciler() { + const pending = new Map(); + return { + /** Registra una predicción local ya aplicada. */ + track(entityId: string, rollback: () => void): void { + pending.set(entityId, { entityId, rollback }); + }, + /** El servidor confirmó: descarta la predicción (no revierte). */ + confirm(entityId: string): void { + pending.delete(entityId); + }, + /** El servidor rechazó: revierte y descarta. */ + reject(entityId: string): void { + const p = pending.get(entityId); + if (p) { + p.rollback(); + pending.delete(entityId); + } + }, + /** Reconexión: revierte TODO lo no confirmado antes de aplicar el snapshot. */ + onSnapshot(): void { + pending.forEach((p) => p.rollback()); + pending.clear(); + }, + size(): number { + return pending.size; + }, + }; +} + +export type OptimisticReconciler = ReturnType; diff --git a/packages/engine-core/src/game/net/playerIdentity.ts b/packages/engine-core/src/game/net/playerIdentity.ts new file mode 100644 index 0000000..0e488a9 --- /dev/null +++ b/packages/engine-core/src/game/net/playerIdentity.ts @@ -0,0 +1,59 @@ +import type { GameVec3 } from "../types"; +import type { PlayerId } from "../../ports/multiplayer"; + +/** Personaje seleccionable. Hoy solo "Dave"; reservado para multi-character futuro. */ +export type CharacterId = "Dave"; +export const DEFAULT_CHARACTER_ID: CharacterId = "Dave"; + +export type PlayerAction = "idle" | "north" | "south" | "west" | "east"; + +/** Descriptor de un jugador. Serializable: viaja como presence en NetEnvelope.payload. */ +export interface PlayerDescriptor { + playerId: PlayerId; + displayName: string; + characterId: CharacterId; + sceneId: string; + position: GameVec3; + action: PlayerAction; + /** Último timestamp visto (para limpiar jugadores stale). */ + lastSeenTs: number; +} + +const NAME_PREFIXES = [ + "Viajero", + "Errante", + "Nómada", + "Curioso", + "Vecino", + "Explorador", +] as const; + +/** Genera un nombre anónimo legible, p.ej. "Viajero-A3F". RNG inyectable para tests. */ +export function generateRandomName(rng: () => number = Math.random): string { + const prefix = NAME_PREFIXES[Math.floor(rng() * NAME_PREFIXES.length)]!; + const suffix = Math.floor(rng() * 0xfff) + .toString(16) + .toUpperCase() + .padStart(3, "0"); + return `${prefix}-${suffix}`; +} + +/** Crea el descriptor inicial del jugador local. */ +export function createSelfDescriptor(opts: { + playerId: PlayerId; + sceneId: string; + position: GameVec3; + displayName?: string; + characterId?: CharacterId; + now?: () => number; +}): PlayerDescriptor { + return { + playerId: opts.playerId, + displayName: opts.displayName ?? generateRandomName(), + characterId: opts.characterId ?? DEFAULT_CHARACTER_ID, + sceneId: opts.sceneId, + position: opts.position, + action: "idle", + lastSeenTs: (opts.now ?? Date.now)(), + }; +} diff --git a/packages/engine-core/src/game/net/remotePlayersStore.ts b/packages/engine-core/src/game/net/remotePlayersStore.ts new file mode 100644 index 0000000..2e14e97 --- /dev/null +++ b/packages/engine-core/src/game/net/remotePlayersStore.ts @@ -0,0 +1,63 @@ +import type { PlayerDescriptor } from "./playerIdentity"; +import type { PlayerId } from "../../ports/multiplayer"; + +export interface RemotePlayersStore { + /** Inserta o actualiza un jugador remoto (merge parcial sobre el existente). */ + upsert: (descriptor: Partial & { playerId: PlayerId }) => void; + remove: (playerId: PlayerId) => void; + /** Solo los jugadores presentes en la escena dada (interest management en el borde). */ + getInScene: (sceneId: string) => PlayerDescriptor[]; + getAll: () => PlayerDescriptor[]; + /** Elimina jugadores sin presence en > maxAgeMs. Devuelve los ids eliminados. */ + pruneStale: (maxAgeMs: number, now?: number) => PlayerId[]; + reset: () => void; + /** Notifica en cada cambio (para que el renderer re-renderice). */ + subscribe: (listener: () => void) => () => void; +} + +export function createRemotePlayersStore(): RemotePlayersStore { + const players = new Map(); + const listeners = new Set<() => void>(); + const notify = () => listeners.forEach((l) => l()); + + return { + upsert: (d) => { + const prev = players.get(d.playerId); + players.set(d.playerId, { + playerId: d.playerId, + displayName: d.displayName ?? prev?.displayName ?? d.playerId, + characterId: d.characterId ?? prev?.characterId ?? "Dave", + sceneId: d.sceneId ?? prev?.sceneId ?? "", + position: d.position ?? prev?.position ?? [0, 0, 0], + action: d.action ?? prev?.action ?? "idle", + lastSeenTs: d.lastSeenTs ?? Date.now(), + }); + notify(); + }, + remove: (id) => { + if (players.delete(id)) notify(); + }, + getInScene: (sceneId) => + [...players.values()].filter((p) => p.sceneId === sceneId), + getAll: () => [...players.values()], + pruneStale: (maxAgeMs, now = Date.now()) => { + const removed: PlayerId[] = []; + for (const [id, p] of players) { + if (now - p.lastSeenTs > maxAgeMs) { + players.delete(id); + removed.push(id); + } + } + if (removed.length) notify(); + return removed; + }, + reset: () => { + players.clear(); + notify(); + }, + subscribe: (l) => { + listeners.add(l); + return () => listeners.delete(l); + }, + }; +} diff --git a/packages/engine-core/src/game/net/throttle.ts b/packages/engine-core/src/game/net/throttle.ts new file mode 100644 index 0000000..8baef7d --- /dev/null +++ b/packages/engine-core/src/game/net/throttle.ts @@ -0,0 +1,35 @@ +/** Reloj/scheduler inyectable para el throttle (permite tests deterministas). */ +export interface ThrottleClock { + now: () => number; + schedule: (cb: () => void, delay: number) => void; +} + +/** + * Throttle con trailing: ejecuta `fn` como mucho 1 vez por `ms`, pero garantiza + * que la ÚLTIMA llamada dentro de la ventana se ejecuta (con el estado final). + */ +export function throttleTrailing( + fn: () => void, + ms: number, + clock: ThrottleClock, +): () => void { + let lastRun = -Infinity; + let scheduled = false; + return () => { + const t = clock.now(); + const elapsed = t - lastRun; + if (elapsed >= ms) { + lastRun = t; + fn(); + return; + } + if (!scheduled) { + scheduled = true; + clock.schedule(() => { + scheduled = false; + lastRun = clock.now(); + fn(); + }, ms - elapsed); + } + }; +} diff --git a/packages/engine-core/src/game/net/worldState.ts b/packages/engine-core/src/game/net/worldState.ts new file mode 100644 index 0000000..a8e0043 --- /dev/null +++ b/packages/engine-core/src/game/net/worldState.ts @@ -0,0 +1,36 @@ +import type { PlayerId } from "../../ports/multiplayer"; + +export interface LwwRegister { + value: V; + ts: number; + by: PlayerId; +} + +/** Mapa de registros LWW por `${entityId}:${field}`. Determinista entre clientes. */ +export class WorldStateLww { + private map = new Map(); + private key = (entityId: string, field: string) => `${entityId}:${field}`; + + get(entityId: string, field: string): V | undefined { + return this.map.get(this.key(entityId, field))?.value as V | undefined; + } + + /** Aplica un registro remoto/local. Devuelve true si ganó (cambió el estado). */ + merge(entityId: string, field: string, reg: LwwRegister): boolean { + const k = this.key(entityId, field); + const cur = this.map.get(k); + // Gana mayor ts; empate → mayor playerId (criterio estable arbitrario). + if (!cur || reg.ts > cur.ts || (reg.ts === cur.ts && reg.by > cur.by)) { + this.map.set(k, reg); + return true; + } + return false; + } + + snapshot(): Record { + return Object.fromEntries(this.map); + } + load(snap: Record): void { + this.map = new Map(Object.entries(snap)); + } +} diff --git a/packages/engine-core/src/index.ts b/packages/engine-core/src/index.ts index 38bc77f..5b65c15 100644 --- a/packages/engine-core/src/index.ts +++ b/packages/engine-core/src/index.ts @@ -4,6 +4,7 @@ export * from "./game/state"; export * from "./game/commands"; export * from "./game/events"; export * from "./game/i18n"; +export * from "./game/net"; export * from "./events"; export * from "./ports"; diff --git a/packages/engine-core/src/ports/headlessMultiplayer.ts b/packages/engine-core/src/ports/headlessMultiplayer.ts new file mode 100644 index 0000000..0e18181 --- /dev/null +++ b/packages/engine-core/src/ports/headlessMultiplayer.ts @@ -0,0 +1,96 @@ +import type { + ConnectOptions, + ConnectionStatus, + MultiplayerPort, + NetEnvelope, + PlayerId, +} from "./multiplayer"; + +/** + * Bus en memoria que conecta varios HeadlessMultiplayerAdapter (simula la red + * en tests). Reenvía cada `send` a los demás adapters de la MISMA room. + */ +interface HubPeer { + room: string; + inbound: (m: NetEnvelope) => void; +} + +export class InMemoryHub { + private peers = new Map(); + + register( + id: PlayerId, + room: string, + inbound: (m: NetEnvelope) => void, + ): () => void { + this.peers.set(id, { room, inbound }); + return () => this.peers.delete(id); + } + + /** Fan-out a los peers de la MISMA room que el mensaje, menos al emisor. */ + broadcast(from: PlayerId, _room: string, message: NetEnvelope): void { + for (const [id, peer] of this.peers) { + if (id === from) continue; + if (peer.room !== message.room) continue; // aísla por room del receptor + peer.inbound(message); + } + } +} + +let _autoId = 0; + +/** Adapter de loopback para tests. Implementa MultiplayerPort contra un InMemoryHub. */ +export class HeadlessMultiplayerAdapter implements MultiplayerPort { + readonly selfId: PlayerId; + private room = ""; + private connected = false; + private unregister: (() => void) | null = null; + private msgHandlers: Array<(m: NetEnvelope) => void> = []; + private statusHandlers: Array<(s: ConnectionStatus) => void> = []; + + constructor( + private hub: InMemoryHub, + selfId?: PlayerId, + ) { + this.selfId = selfId ?? `headless-${++_autoId}`; + } + + connect(opts: ConnectOptions): void { + this.room = opts.room; + this.connected = true; + this.unregister = this.hub.register(this.selfId, this.room, (m) => { + this.msgHandlers.forEach((h) => h(m)); + }); + this.emitStatus({ state: "connected", selfId: this.selfId }); + } + + disconnect(): void { + this.connected = false; + this.unregister?.(); + this.unregister = null; + this.emitStatus({ state: "disconnected" }); + } + + send(message: NetEnvelope): void { + if (!this.connected) return; + this.hub.broadcast(this.selfId, this.room, message); + } + + onMessage(handler: (m: NetEnvelope) => void): () => void { + this.msgHandlers.push(handler); + return () => { + this.msgHandlers = this.msgHandlers.filter((h) => h !== handler); + }; + } + + onStatus(handler: (s: ConnectionStatus) => void): () => void { + this.statusHandlers.push(handler); + return () => { + this.statusHandlers = this.statusHandlers.filter((h) => h !== handler); + }; + } + + private emitStatus(s: ConnectionStatus): void { + this.statusHandlers.forEach((h) => h(s)); + } +} diff --git a/packages/engine-core/src/ports/index.ts b/packages/engine-core/src/ports/index.ts index 7bce3d8..514cc15 100644 --- a/packages/engine-core/src/ports/index.ts +++ b/packages/engine-core/src/ports/index.ts @@ -28,3 +28,15 @@ export { HeadlessAudioAdapter, type HeadlessAudioCall } from "./headlessAudio"; export type { I18nPort } from "./i18n"; export { HeadlessI18nAdapter, type HeadlessI18nCall } from "./headlessI18n"; + +export type { + PlayerId, + RoomId, + NetEnvelope, + NetEnvelopeKind, + ConnectionStatus, + ConnectOptions, + MultiplayerPort, +} from "./multiplayer"; +export { NET_PROTOCOL_VERSION } from "./multiplayer"; +export { HeadlessMultiplayerAdapter, InMemoryHub } from "./headlessMultiplayer"; diff --git a/packages/engine-core/src/ports/multiplayer.ts b/packages/engine-core/src/ports/multiplayer.ts new file mode 100644 index 0000000..d9cf4ce --- /dev/null +++ b/packages/engine-core/src/ports/multiplayer.ts @@ -0,0 +1,69 @@ +/** + * MultiplayerPort – contrato agnóstico de transporte multijugador. + * + * El core SOLO habla con esta interfaz. Los adapters (PartyKit, headless, …) la + * implementan fuera del core. Ningún import de red/`window`/proveedor aquí. + * + * Ver docs/architecture/09-multiplayer.md §3 y ADR-0008. + */ + +/** Identificadores. */ +export type PlayerId = string; +export type RoomId = string; + +/** Versión del protocolo de red. Súbela ante cambios incompatibles del sobre. */ +export const NET_PROTOCOL_VERSION = 1; + +/** Tipo de carga del sobre. `payload` se interpreta según este discriminador. */ +export type NetEnvelopeKind = + | "command" // payload: GameCommand (intent del cliente) + | "event" // payload: GameEvent (mutación world confirmada) + | "presence" // payload: PlayerDescriptor parcial (posición/escena) + | "snapshot" // payload: estado world completo al unirse + | "claim" // payload: { entityId } reclamo de ítem + | "claim-result"; // payload: { entityId; granted: boolean } + +/** Sobre serializable que viaja por el cable. SIEMPRE JSON-serializable. */ +export interface NetEnvelope { + /** Versión de protocolo (NET_PROTOCOL_VERSION). */ + v: number; + /** Room/partida destino. */ + room: RoomId; + /** Emisor. */ + from: PlayerId; + /** Reloj lógico (HLC en task 05; Date.now() hasta entonces). Para ordenar/LWW. */ + ts: number; + /** Discriminador de payload. */ + kind: NetEnvelopeKind; + /** Carga; su forma depende de `kind`. */ + payload: T; +} + +/** Estado de conexión reportado por el transporte. */ +export type ConnectionStatus = + | { state: "connecting" } + | { state: "connected"; selfId: PlayerId } + | { state: "disconnected"; reason?: string }; + +/** Opciones para conectar a una room. `selfId` puede asignarlo el servidor. */ +export interface ConnectOptions { + room: RoomId; + selfId?: PlayerId; +} + +/** + * Puerto agnóstico de transporte multijugador. Implementado fuera del core por + * adapters (PartyKit, headless, …). El core SOLO habla con esta interfaz. + */ +export interface MultiplayerPort { + /** Abre la conexión a la room. Idempotente si ya conectado. */ + connect(opts: ConnectOptions): Promise | void; + /** Cierra la conexión y libera recursos. */ + disconnect(): void; + /** Envía un sobre a los peers (o al relay, que hace fan-out). Fire-and-forget. */ + send(message: NetEnvelope): void; + /** Suscribe a sobres entrantes. Devuelve unsubscribe. */ + onMessage(handler: (message: NetEnvelope) => void): () => void; + /** Suscribe a cambios de estado de conexión. Devuelve unsubscribe. */ + onStatus(handler: (status: ConnectionStatus) => void): () => void; +} diff --git a/packages/engine-renderer-r3f/dist/GameTouchSpriteRuntime.d.ts.map b/packages/engine-renderer-r3f/dist/GameTouchSpriteRuntime.d.ts.map index c5ceb0b..9e023bd 100644 --- a/packages/engine-renderer-r3f/dist/GameTouchSpriteRuntime.d.ts.map +++ b/packages/engine-renderer-r3f/dist/GameTouchSpriteRuntime.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"GameTouchSpriteRuntime.d.ts","sourceRoot":"","sources":["../src/GameTouchSpriteRuntime.tsx"],"names":[],"mappings":"AAUA,OAAO,EAGL,KAAK,iBAAiB,EAEvB,MAAM,gBAAgB,CAAC;AAOxB,OAAO,EAAmF,KAAK,mBAAmB,EAAE,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAwElM,wBAAgB,sBAAsB,CAAC,EACrC,eAAe,EACf,KAAK,EACL,eAAe,EACf,cAAc,EACd,kBAA0B,EAC1B,eAA6B,EAC7B,uBAA8B,EAC9B,YAAY,EACZ,oBAAoB,EACpB,UAAU,EACV,aAAa,EACb,aAAa,EACb,oBAAoB,EACpB,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,cAAc,EAEd,cAAsD,EACtD,eAAe,EACf,SAAoB,EACpB,iBAAwB,EACxB,YAAY,EACZ,kBAAkB,EAClB,kBAA0B,EAC1B,qBAAqB,GACtB,EAAE;IACD,eAAe,EAAE,iBAAiB,CAAC;IACnC,KAAK,EAAE,OAAO,CAAC;IACf,eAAe,EAAE,OAAO,CAAC;IACzB,cAAc,EAAE,OAAO,CAAC;IACxB,yEAAyE;IACzE,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,+EAA+E;IAC/E,eAAe,CAAC,EAAE,WAAW,GAAG,QAAQ,CAAC;IACzC;;;;OAIG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,YAAY,EAAE,YAAY,CAAC;IAC3B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,cAAc,CAAC,EAAE,mBAAmB,CAAC;IACrC;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACjE;;;OAGG;IACH,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;IAChD;;;;;OAKG;IACH,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,CACnB,OAAO,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,aAAa,KAC5C,IAAI,CAAC;IACV;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;;;;OAMG;IACH,qBAAqB,CAAC,EAAE,CACtB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,KACZ;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,GAAG,SAAS,CAAC;CAClD,2CAioBA"} \ No newline at end of file +{"version":3,"file":"GameTouchSpriteRuntime.d.ts","sourceRoot":"","sources":["../src/GameTouchSpriteRuntime.tsx"],"names":[],"mappings":"AAUA,OAAO,EAGL,KAAK,iBAAiB,EAEvB,MAAM,gBAAgB,CAAC;AAOxB,OAAO,EAAmF,KAAK,mBAAmB,EAAE,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAwElM,wBAAgB,sBAAsB,CAAC,EACrC,eAAe,EACf,KAAK,EACL,eAAe,EACf,cAAc,EACd,kBAA0B,EAC1B,eAA6B,EAC7B,uBAA8B,EAC9B,YAAY,EACZ,oBAAoB,EACpB,UAAU,EACV,aAAa,EACb,aAAa,EACb,oBAAoB,EACpB,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,cAAc,EAEd,cAAsD,EACtD,eAAe,EACf,SAAoB,EACpB,iBAAwB,EACxB,YAAY,EACZ,kBAAkB,EAClB,kBAA0B,EAC1B,qBAAqB,GACtB,EAAE;IACD,eAAe,EAAE,iBAAiB,CAAC;IACnC,KAAK,EAAE,OAAO,CAAC;IACf,eAAe,EAAE,OAAO,CAAC;IACzB,cAAc,EAAE,OAAO,CAAC;IACxB,yEAAyE;IACzE,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,+EAA+E;IAC/E,eAAe,CAAC,EAAE,WAAW,GAAG,QAAQ,CAAC;IACzC;;;;OAIG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,YAAY,EAAE,YAAY,CAAC;IAC3B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,cAAc,CAAC,EAAE,mBAAmB,CAAC;IACrC;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACjE;;;OAGG;IACH,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;IAChD;;;;;OAKG;IACH,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,CACnB,OAAO,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,aAAa,KAC5C,IAAI,CAAC;IACV;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;;;;OAMG;IACH,qBAAqB,CAAC,EAAE,CACtB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,KACZ;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,GAAG,SAAS,CAAC;CAClD,2CA4qBA"} \ No newline at end of file diff --git a/packages/engine-renderer-r3f/dist/GameTouchSpriteRuntime.js b/packages/engine-renderer-r3f/dist/GameTouchSpriteRuntime.js index 31ec8d1..cf557f6 100644 --- a/packages/engine-renderer-r3f/dist/GameTouchSpriteRuntime.js +++ b/packages/engine-renderer-r3f/dist/GameTouchSpriteRuntime.js @@ -83,6 +83,12 @@ getMobileInput = () => ({ active: false, x: 0, z: 0 }), addWallWithData, getPhra const wallPointStartRef = useRef(null); const lastBoundaryHitRef = useRef(0); const lastStuckHitRef = useRef(0); + // Wall-slide detection: compare position delta each frame against the + // velocity we set last frame. If an axis moved much less than expected, + // a collider is blocking it — zero that component so the character slides + // along the unblocked axis instead of pressing into the wall. + const prevBodyPositionRef = useRef(null); + const prevBodyVelSetRef = useRef({ vx: 0, vz: 0 }); const playerSpawn = useSceneStore((s) => s.scene.playerSpawn); const playerPosition = useSceneStore((s) => s.playerPosition); const playerWalkingState = useSceneStore((s) => s.playerWalkingState); @@ -363,6 +369,30 @@ getMobileInput = () => ({ active: false, x: 0, z: 0 }), addWallWithData, getPhra if (!body) { return; } + // Wall-slide detection: compare last frame's intended velocity against the + // actual position change recorded by physics. If an axis barely moved + // relative to what was expected, a rigid-body is blocking it — suppress + // that component this frame so the character slides along the free axis + // rather than sticking against the obstacle surface. + const frameStartPos = body.translation(); + let slideBlockX = false; + let slideBlockZ = false; + { + const pp = prevBodyPositionRef.current; + const { vx: pvx, vz: pvz } = prevBodyVelSetRef.current; + if (pp && (Math.abs(pvx) > 0.3 || Math.abs(pvz) > 0.3)) { + const adx = frameStartPos.x - pp.x; + const adz = frameStartPos.z - pp.z; + // Expected displacement (approximated with current delta — consecutive + // frame durations are close enough for this heuristic). + const edx = pvx * delta; + const edz = pvz * delta; + if (Math.abs(edx) > 0.002) + slideBlockX = Math.abs(adx) < Math.abs(edx) * 0.25; + if (Math.abs(edz) > 0.002) + slideBlockZ = Math.abs(adz) < Math.abs(edz) * 0.25; + } + } const { moveLeft, moveRight, moveUp, moveDown, anyKeyPressed } = getKeyboardMovement(); const joystick = getMobileInput(); // Block input during walk animation @@ -418,6 +448,14 @@ getMobileInput = () => ({ active: false, x: 0, z: 0 }), addWallWithData, getPhra } horizontal = applyDeadzone(horizontal, MOVEMENT_INPUT_DEADZONE); vertical = applyDeadzone(vertical, MOVEMENT_INPUT_DEADZONE); + // Apply wall-slide: if a collider blocked an axis last frame, do not push + // into it again this frame. The perpendicular axis is kept intact so the + // character slides along the surface. Only suppress when *trying* to move + // in the blocked direction (same sign), not when already idle on that axis. + if (slideBlockX && horizontal !== 0) + horizontal = 0; + if (slideBlockZ && vertical !== 0) + vertical = 0; // During walk animation, calculate direction from current to target position let nextAction; if (isWalking && playerWalkingState?.targetPosition) { @@ -537,6 +575,12 @@ getMobileInput = () => ({ active: false, x: 0, z: 0 }), addWallWithData, getPhra colliderWireframeRef.current.scale.set(1, spriteScale, 1); colliderWireframeRef.current.position.y = spriteScale - 0.95; } + // Persist velocity and position for next-frame wall-slide detection. + // Reading linvel() here returns the velocity we set above (after all + // in-frame corrections: wall-slide zeroing, boundary clamping, stuck reset). + const finalLinvel = body.linvel(); + prevBodyVelSetRef.current = { vx: finalLinvel.x, vz: finalLinvel.z }; + prevBodyPositionRef.current = { x: safePosition.x, z: safePosition.z }; }); const wallPointPreview = debug && wallToolMode === "points" && wallPointPreviewState?.resetSignal === wallPointResetSignal ? wallPointPreviewState @@ -546,7 +590,7 @@ getMobileInput = () => ({ active: false, x: 0, z: 0 }), addWallWithData, getPhra handleHoverWorld(x, z); handleHoverPointWallTool(x, z); } - : undefined, debug: debug && showDebugGround, depthNearZ: DEPTH_NEAR_Z, depthFarZ: DEPTH_FAR_Z }), _jsx(SceneWalls, { debug: debug && showDebugWalls, opacityMode: wallOpacityMode, interactionsEnabled: wallInteractionsEnabled, onStartWallMove: handleStartWallMove, onStartWallResize: handleStartWallResize, selectedWallIndex: selectedWallIndex, onSelectWall: onSelectWall }), debug && wallToolMode === "points" && (_jsx(SceneWallPointPreview, { preview: wallPointPreview, groundY: ground.y })), _jsx(SceneCollisionSphere, {}), _jsxs(RigidBody, { ref: characterBodyRef, type: "dynamic", colliders: false, position: renderPosition, gravityScale: 1.2, linearDamping: 7, angularDamping: 20, ccd: true, enabledRotations: [false, false, false], children: [_jsx(CuboidCollider, { ref: characterColliderRef, args: [0.55, 0.95, 0.18], friction: 2.2, restitution: 0 }), debug && showPlayerCollider && ( + : undefined, debug: debug && showDebugGround, depthNearZ: DEPTH_NEAR_Z, depthFarZ: DEPTH_FAR_Z }), _jsx(SceneWalls, { debug: debug && showDebugWalls, opacityMode: wallOpacityMode, interactionsEnabled: wallInteractionsEnabled, onStartWallMove: handleStartWallMove, onStartWallResize: handleStartWallResize, selectedWallIndex: selectedWallIndex, onSelectWall: onSelectWall }), debug && wallToolMode === "points" && (_jsx(SceneWallPointPreview, { preview: wallPointPreview, groundY: ground.y })), _jsx(SceneCollisionSphere, {}), _jsxs(RigidBody, { ref: characterBodyRef, type: "dynamic", colliders: false, position: renderPosition, gravityScale: 1.2, linearDamping: 7, angularDamping: 20, ccd: true, enabledRotations: [false, false, false], children: [_jsx(CuboidCollider, { ref: characterColliderRef, args: [0.55, 0.95, 0.18], friction: 0.05, restitution: 0 }), debug && showPlayerCollider && ( // box base height = 2; the useFrame above scales Y to `spriteScale` // and offsets Y position so the wireframe exactly mirrors the // physics collider (whose halfY is also set to `spriteScale`). diff --git a/packages/engine-renderer-r3f/dist/GameTouchSpriteRuntime.js.map b/packages/engine-renderer-r3f/dist/GameTouchSpriteRuntime.js.map index e63e54b..19cdbb1 100644 --- a/packages/engine-renderer-r3f/dist/GameTouchSpriteRuntime.js.map +++ b/packages/engine-renderer-r3f/dist/GameTouchSpriteRuntime.js.map @@ -1 +1 @@ -{"version":3,"file":"GameTouchSpriteRuntime.js","sourceRoot":"","sources":["../src/GameTouchSpriteRuntime.tsx"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"GameTouchSpriteRuntime.js","sourceRoot":"","sources":["../src/GameTouchSpriteRuntime.tsx"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/engine-renderer-r3f/dist/hooks/useClickToMoveController.d.ts.map b/packages/engine-renderer-r3f/dist/hooks/useClickToMoveController.d.ts.map index 6dd1863..fb6130f 100644 --- a/packages/engine-renderer-r3f/dist/hooks/useClickToMoveController.d.ts.map +++ b/packages/engine-renderer-r3f/dist/hooks/useClickToMoveController.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"useClickToMoveController.d.ts","sourceRoot":"","sources":["../../src/hooks/useClickToMoveController.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAQpE,KAAK,8BAA8B,GAAG;IACpC,gBAAgB,EAAE,MAAM,CAAC;IACzB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,KAAK,iBAAiB,GAAG;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACzC,CAAC;AAQF,wBAAgB,wBAAwB,CACtC,MAAM,GAAE,OAAO,CAAC,8BAA8B,CAAM;mBAclB,MAAM,KAAK,MAAM;sBAMd,aAAa,EAAE;;iCAStC,MAAM,YACN,MAAM,SACT,MAAM,kBACG,OAAO,KACtB,iBAAiB;iCAwCR,MAAM,YACN,MAAM,SACT,MAAM,kBACG,OAAO,KACtB;QAAE,KAAK,EAAE,OAAO,CAAA;KAAE;EAgCxB"} \ No newline at end of file +{"version":3,"file":"useClickToMoveController.d.ts","sourceRoot":"","sources":["../../src/hooks/useClickToMoveController.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAgBpE,KAAK,8BAA8B,GAAG;IACpC,gBAAgB,EAAE,MAAM,CAAC;IACzB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,KAAK,iBAAiB,GAAG;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACzC,CAAC;AAQF,wBAAgB,wBAAwB,CACtC,MAAM,GAAE,OAAO,CAAC,8BAA8B,CAAM;mBAclB,MAAM,KAAK,MAAM;sBAMd,aAAa,EAAE;;iCAStC,MAAM,YACN,MAAM,SACT,MAAM,kBACG,OAAO,KACtB,iBAAiB;iCAuDR,MAAM,YACN,MAAM,SACT,MAAM,kBACG,OAAO,KACtB;QAAE,KAAK,EAAE,OAAO,CAAA;KAAE;EAuCxB"} \ No newline at end of file diff --git a/packages/engine-renderer-r3f/dist/hooks/useClickToMoveController.js b/packages/engine-renderer-r3f/dist/hooks/useClickToMoveController.js index 7f4bb79..950e579 100644 --- a/packages/engine-renderer-r3f/dist/hooks/useClickToMoveController.js +++ b/packages/engine-renderer-r3f/dist/hooks/useClickToMoveController.js @@ -1,6 +1,11 @@ "use client"; import { useCallback, useRef } from "react"; import { MathUtils } from "three"; +// After this many ms of barely moving, start nudging perpendicular to the +// desired direction so the character slides around the obstacle instead of +// pressing into it. At SLIDE_SWITCH_MS the nudge flips to the opposite side. +const SLIDE_TRIGGER_MS = 150; +const SLIDE_SWITCH_MS = 350; const DEFAULT_CONFIG = { arrivalThreshold: 0.15, stuckMovementEpsilon: 0.015, @@ -57,6 +62,20 @@ export function useClickToMoveController(config = {}) { } return { horizontal: 0, vertical: 0 }; } + // Slide assist: when the character has been making slow progress for long + // enough, blend in a perpendicular nudge so it slides around the surface + // of the obstacle instead of pressing into it and freezing. + const prog = progressRef.current; + if (prog && prog.stuckMs >= SLIDE_TRIGGER_MS) { + const sign = prog.slideSign; + const perpX = (-dz / dist) * sign; + const perpZ = (dx / dist) * sign; + const t = MathUtils.clamp((prog.stuckMs - SLIDE_TRIGGER_MS) / 200, 0, 0.85); + return { + horizontal: MathUtils.clamp(dx / dist * (1 - t) + perpX * t, -1, 1), + vertical: MathUtils.clamp(dz / dist * (1 - t) + perpZ * t, -1, 1), + }; + } return { horizontal: MathUtils.clamp(dx / dist, -1, 1), vertical: MathUtils.clamp(dz / dist, -1, 1), @@ -69,12 +88,18 @@ export function useClickToMoveController(config = {}) { } const prev = progressRef.current; if (!prev) { - progressRef.current = { x: currentX, z: currentZ, stuckMs: 0 }; + progressRef.current = { x: currentX, z: currentZ, stuckMs: 0, slideSign: 1 }; return { stuck: false }; } const moved = Math.sqrt((currentX - prev.x) ** 2 + (currentZ - prev.z) ** 2); if (moved < mergedConfig.stuckMovementEpsilon) { prev.stuckMs += delta * 1000; + // Flip the perpendicular slide direction halfway through the timeout so + // the character tries the other side of the obstacle if the first side + // didn't work. + if (prev.stuckMs >= SLIDE_SWITCH_MS && prev.stuckMs - delta * 1000 < SLIDE_SWITCH_MS) { + prev.slideSign = prev.slideSign === 1 ? -1 : 1; + } if (prev.stuckMs > mergedConfig.stuckTimeoutMs) { progressRef.current = null; cancelTarget(); @@ -85,6 +110,7 @@ export function useClickToMoveController(config = {}) { prev.x = currentX; prev.z = currentZ; prev.stuckMs = 0; + prev.slideSign = 1; } return { stuck: false }; }, [cancelTarget, mergedConfig.stuckMovementEpsilon, mergedConfig.stuckTimeoutMs]); diff --git a/packages/engine-renderer-r3f/dist/hooks/useClickToMoveController.js.map b/packages/engine-renderer-r3f/dist/hooks/useClickToMoveController.js.map index 234fb15..9b71e39 100644 --- a/packages/engine-renderer-r3f/dist/hooks/useClickToMoveController.js.map +++ b/packages/engine-renderer-r3f/dist/hooks/useClickToMoveController.js.map @@ -1 +1 @@ -{"version":3,"file":"useClickToMoveController.js","sourceRoot":"","sources":["../../src/hooks/useClickToMoveController.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"useClickToMoveController.js","sourceRoot":"","sources":["../../src/hooks/useClickToMoveController.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGlC,0EAA0E;AAC1E,2EAA2E;AAC3E,6EAA6E;AAC7E,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAC7B,MAAM,eAAe,GAAG,GAAG,CAAC;AAsB5B,MAAM,cAAc,GAAmC;IACrD,gBAAgB,EAAE,IAAI;IACtB,oBAAoB,EAAE,KAAK;IAC3B,cAAc,EAAE,GAAG;CACpB,CAAC;AAEF,MAAM,UAAU,wBAAwB,CACtC,SAAkD,EAAE;IAEpD,MAAM,YAAY,GAAmC,EAAE,GAAG,cAAc,EAAE,GAAG,MAAM,EAAE,CAAC;IAEtF,MAAM,SAAS,GAAG,MAAM,CAAuB,IAAI,CAAC,CAAC;IACrD,MAAM,QAAQ,GAAG,MAAM,CAAkB,EAAE,CAAC,CAAC;IAC7C,MAAM,WAAW,GAAG,MAAM,CAA4B,IAAI,CAAC,CAAC;IAE5D,MAAM,YAAY,GAAG,WAAW,CAAC,GAAG,EAAE;QACpC,SAAS,CAAC,OAAO,GAAG,IAAI,CAAC;QACzB,QAAQ,CAAC,OAAO,GAAG,EAAE,CAAC;QACtB,WAAW,CAAC,OAAO,GAAG,IAAI,CAAC;IAC7B,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,SAAS,GAAG,WAAW,CAAC,CAAC,CAAS,EAAE,CAAS,EAAE,EAAE;QACrD,SAAS,CAAC,OAAO,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAC7B,QAAQ,CAAC,OAAO,GAAG,EAAE,CAAC;QACtB,WAAW,CAAC,OAAO,GAAG,IAAI,CAAC;IAC7B,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,QAAQ,GAAG,WAAW,CAAC,CAAC,KAAsB,EAAE,EAAE;QACtD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAC/B,QAAQ,CAAC,OAAO,GAAG,KAAK,CAAC;QACzB,SAAS,CAAC,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC;QACpD,WAAW,CAAC,OAAO,GAAG,IAAI,CAAC;IAC7B,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,gBAAgB,GAAG,WAAW,CAClC,CACE,QAAgB,EAChB,QAAgB,EAChB,KAAa,EACb,cAAuB,EACJ,EAAE;QACrB,IAAI,cAAc;YAAE,OAAO,EAAE,UAAU,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;QAE1D,OAAO,QAAQ,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACnC,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAE,CAAC;YAClC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,GAAG,QAAQ,CAAC;YAC7B,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,GAAG,QAAQ,CAAC;YAC7B,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,GAAG,YAAY,CAAC,gBAAgB,EAAE,CAAC;gBACjE,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YAC3B,CAAC;iBAAM,CAAC;gBACN,MAAM;YACR,CAAC;QACH,CAAC;QAED,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC,OAAO,CAAC;QACxD,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,UAAU,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;QAEnD,MAAM,EAAE,GAAG,MAAM,CAAC,CAAC,GAAG,QAAQ,CAAC;QAC/B,MAAM,EAAE,GAAG,MAAM,CAAC,CAAC,GAAG,QAAQ,CAAC;QAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;QAE1C,IAAI,IAAI,GAAG,YAAY,CAAC,gBAAgB,EAAE,CAAC;YACzC,IAAI,QAAQ,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;gBAAE,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YAC1D,IAAI,QAAQ,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAClC,SAAS,CAAC,OAAO,GAAG,IAAI,CAAC;gBACzB,OAAO,EAAE,UAAU,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC;YAC9D,CAAC;YACD,OAAO,EAAE,UAAU,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;QACxC,CAAC;QAED,0EAA0E;QAC1E,yEAAyE;QACzE,4DAA4D;QAC5D,MAAM,IAAI,GAAG,WAAW,CAAC,OAAO,CAAC;QACjC,IAAI,IAAI,IAAI,IAAI,CAAC,OAAO,IAAI,gBAAgB,EAAE,CAAC;YAC7C,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC;YAC5B,MAAM,KAAK,GAAG,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;YAClC,MAAM,KAAK,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;YACjC,MAAM,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,GAAG,gBAAgB,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;YAC5E,OAAO;gBACL,UAAU,EAAE,SAAS,CAAC,KAAK,CAAC,EAAE,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;gBACnE,QAAQ,EAAE,SAAS,CAAC,KAAK,CAAC,EAAE,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;aAClE,CAAC;QACJ,CAAC;QAED,OAAO;YACL,UAAU,EAAE,SAAS,CAAC,KAAK,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;YAC7C,QAAQ,EAAE,SAAS,CAAC,KAAK,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;SAC5C,CAAC;IACJ,CAAC,EACD,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAChC,CAAC;IAEF,MAAM,gBAAgB,GAAG,WAAW,CAClC,CACE,QAAgB,EAChB,QAAgB,EAChB,KAAa,EACb,cAAuB,EACH,EAAE;QACtB,IAAI,cAAc,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;YACzC,WAAW,CAAC,OAAO,GAAG,IAAI,CAAC;YAC3B,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;QAC1B,CAAC;QAED,MAAM,IAAI,GAAG,WAAW,CAAC,OAAO,CAAC;QACjC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,WAAW,CAAC,OAAO,GAAG,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;YAC7E,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;QAC1B,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QAC7E,IAAI,KAAK,GAAG,YAAY,CAAC,oBAAoB,EAAE,CAAC;YAC9C,IAAI,CAAC,OAAO,IAAI,KAAK,GAAG,IAAI,CAAC;YAC7B,wEAAwE;YACxE,uEAAuE;YACvE,eAAe;YACf,IAAI,IAAI,CAAC,OAAO,IAAI,eAAe,IAAI,IAAI,CAAC,OAAO,GAAG,KAAK,GAAG,IAAI,GAAG,eAAe,EAAE,CAAC;gBACrF,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACjD,CAAC;YACD,IAAI,IAAI,CAAC,OAAO,GAAG,YAAY,CAAC,cAAc,EAAE,CAAC;gBAC/C,WAAW,CAAC,OAAO,GAAG,IAAI,CAAC;gBAC3B,YAAY,EAAE,CAAC;gBACf,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;YACzB,CAAC;QACH,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,CAAC,GAAG,QAAQ,CAAC;YAClB,IAAI,CAAC,CAAC,GAAG,QAAQ,CAAC;YAClB,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;YACjB,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC;QACrB,CAAC;QAED,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;IAC1B,CAAC,EACD,CAAC,YAAY,EAAE,YAAY,CAAC,oBAAoB,EAAE,YAAY,CAAC,cAAc,CAAC,CAC/E,CAAC;IAEF,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,CAAC;AACnF,CAAC"} \ No newline at end of file diff --git a/packages/engine-renderer-r3f/dist/index.d.ts b/packages/engine-renderer-r3f/dist/index.d.ts index c355a65..567e87e 100644 --- a/packages/engine-renderer-r3f/dist/index.d.ts +++ b/packages/engine-renderer-r3f/dist/index.d.ts @@ -18,6 +18,7 @@ export { SceneWallPointPreview } from "./scene/SceneWallPointPreview"; export { SceneTransitions } from "./scene/SceneTransitions"; export { GameTouchSpriteRuntime } from "./GameTouchSpriteRuntime"; export { default as SpeechBubble } from "./SpeechBubble"; +export { RemotePlayers, type RemotePlayersProps } from "./net/RemotePlayers"; export { usePlayerWalkAnimation } from "./hooks/usePlayerWalkAnimation"; export { useAudioSystem } from "./hooks/useAudioSystem"; export { useClickToMoveController } from "./hooks/useClickToMoveController"; diff --git a/packages/engine-renderer-r3f/dist/index.d.ts.map b/packages/engine-renderer-r3f/dist/index.d.ts.map index 1e412c5..dbaccef 100644 --- a/packages/engine-renderer-r3f/dist/index.d.ts.map +++ b/packages/engine-renderer-r3f/dist/index.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB,UAAU,CAAC;AAGxC,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,YAAY,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAGvE,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAG5D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,YAAY,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAGpE,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,YAAY,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAG5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAGzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AAC/E,YAAY,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AAGjF,OAAO,EAAE,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,EACL,kBAAkB,EAClB,KAAK,yBAAyB,GAC/B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACjF,OAAO,EACL,cAAc,EACd,KAAK,mBAAmB,EACxB,KAAK,0BAA0B,GAChC,MAAM,6BAA6B,CAAC"} \ No newline at end of file +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB,UAAU,CAAC;AAGxC,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,YAAY,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAGvE,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAG5D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,YAAY,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAGpE,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,YAAY,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAG5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAGzD,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAG7E,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AAC/E,YAAY,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AAGjF,OAAO,EAAE,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,EACL,kBAAkB,EAClB,KAAK,yBAAyB,GAC/B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACjF,OAAO,EACL,cAAc,EACd,KAAK,mBAAmB,EACxB,KAAK,0BAA0B,GAChC,MAAM,6BAA6B,CAAC"} \ No newline at end of file diff --git a/packages/engine-renderer-r3f/dist/index.js b/packages/engine-renderer-r3f/dist/index.js index 249aeae..c8ce5ee 100644 --- a/packages/engine-renderer-r3f/dist/index.js +++ b/packages/engine-renderer-r3f/dist/index.js @@ -19,6 +19,8 @@ export { SceneTransitions } from "./scene/SceneTransitions"; // Runtime export { GameTouchSpriteRuntime } from "./GameTouchSpriteRuntime"; export { default as SpeechBubble } from "./SpeechBubble"; +// Net +export { RemotePlayers } from "./net/RemotePlayers"; // Hooks export { usePlayerWalkAnimation } from "./hooks/usePlayerWalkAnimation"; export { useAudioSystem } from "./hooks/useAudioSystem"; diff --git a/packages/engine-renderer-r3f/dist/index.js.map b/packages/engine-renderer-r3f/dist/index.js.map index 04e4851..ed85e3b 100644 --- a/packages/engine-renderer-r3f/dist/index.js.map +++ b/packages/engine-renderer-r3f/dist/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,gBAAgB,GAAG,OAAO,CAAC;AAExC,cAAc;AACd,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAG7D,WAAW;AACX,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAE5D,SAAS;AACT,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAE9D,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAEpE,QAAQ;AACR,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAE5D,UAAU;AACV,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEzD,QAAQ;AACR,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AAG/E,OAAO;AACP,OAAO,EAAE,OAAO,EAAsB,MAAM,iBAAiB,CAAC;AAC9D,OAAO,EACL,kBAAkB,GAEnB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,YAAY,EAA0B,MAAM,2BAA2B,CAAC;AACjF,OAAO,EACL,cAAc,GAGf,MAAM,6BAA6B,CAAC"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,gBAAgB,GAAG,OAAO,CAAC;AAExC,cAAc;AACd,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAG7D,WAAW;AACX,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAE5D,SAAS;AACT,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAE9D,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAEpE,QAAQ;AACR,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAE5D,UAAU;AACV,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEzD,MAAM;AACN,OAAO,EAAE,aAAa,EAA2B,MAAM,qBAAqB,CAAC;AAE7E,QAAQ;AACR,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AAG/E,OAAO;AACP,OAAO,EAAE,OAAO,EAAsB,MAAM,iBAAiB,CAAC;AAC9D,OAAO,EACL,kBAAkB,GAEnB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,YAAY,EAA0B,MAAM,2BAA2B,CAAC;AACjF,OAAO,EACL,cAAc,GAGf,MAAM,6BAA6B,CAAC"} \ No newline at end of file diff --git a/packages/engine-renderer-r3f/dist/net/RemotePlayers.d.ts b/packages/engine-renderer-r3f/dist/net/RemotePlayers.d.ts new file mode 100644 index 0000000..4eae0a7 --- /dev/null +++ b/packages/engine-renderer-r3f/dist/net/RemotePlayers.d.ts @@ -0,0 +1,8 @@ +import type { RemotePlayersStore } from "@pointclick-engine/engine-core"; +export interface RemotePlayersProps { + store: RemotePlayersStore; + currentSceneId: string; +} +/** Dibuja los avatares de los demás jugadores en la escena actual. */ +export declare function RemotePlayers({ store, currentSceneId }: RemotePlayersProps): import("react/jsx-runtime").JSX.Element; +//# sourceMappingURL=RemotePlayers.d.ts.map \ No newline at end of file diff --git a/packages/engine-renderer-r3f/dist/net/RemotePlayers.d.ts.map b/packages/engine-renderer-r3f/dist/net/RemotePlayers.d.ts.map new file mode 100644 index 0000000..e8f4b44 --- /dev/null +++ b/packages/engine-renderer-r3f/dist/net/RemotePlayers.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"RemotePlayers.d.ts","sourceRoot":"","sources":["../../src/net/RemotePlayers.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAEV,kBAAkB,EACnB,MAAM,gCAAgC,CAAC;AA2CxC,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,kBAAkB,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,sEAAsE;AACtE,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,kBAAkB,2CAU1E"} \ No newline at end of file diff --git a/packages/engine-renderer-r3f/dist/net/RemotePlayers.js b/packages/engine-renderer-r3f/dist/net/RemotePlayers.js new file mode 100644 index 0000000..3b91456 --- /dev/null +++ b/packages/engine-renderer-r3f/dist/net/RemotePlayers.js @@ -0,0 +1,41 @@ +"use client"; +import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime"; +import { useEffect, useReducer, useRef } from "react"; +import { useFrame } from "@react-three/fiber"; +import { Vector3 } from "three"; +import DavidSprite from "../sprite/DavidSprite"; +import { GAME_CHARACTER_SPRITES } from "../sprite/clips"; +/** Suscribe a la store (re-render en cada cambio). */ +function useRemotePlayers(store) { + const [, force] = useReducer((x) => x + 1, 0); + useEffect(() => store.subscribe(() => force()), [store]); + return store.getAll(); +} +function RemotePlayerSprite({ player }) { + const meshRef = useRef(null); + const target = useRef(new Vector3(player.position[0], player.position[1], player.position[2])); + const initialized = useRef(false); + // Actualiza el objetivo cada render (presence llega throttled ~12Hz). + target.current.set(player.position[0], player.position[1], player.position[2]); + const sprites = GAME_CHARACTER_SPRITES[player.characterId] ?? GAME_CHARACTER_SPRITES.Dave; + const animation = sprites[player.action] ?? sprites.idle; + useFrame((_, dt) => { + const m = meshRef.current; + if (!m) + return; + if (!initialized.current) { + m.position.copy(target.current); + initialized.current = true; + return; + } + m.position.lerp(target.current, Math.min(1, dt * 10)); // suavizado a 60fps + }); + return (_jsx(DavidSprite, { animation: animation, meshRef: meshRef, isPaused: player.action === "idle" })); +} +/** Dibuja los avatares de los demás jugadores en la escena actual. */ +export function RemotePlayers({ store, currentSceneId }) { + const players = useRemotePlayers(store); + const inScene = players.filter((p) => p.sceneId === currentSceneId); + return (_jsx(_Fragment, { children: inScene.map((p) => (_jsx(RemotePlayerSprite, { player: p }, p.playerId))) })); +} +//# sourceMappingURL=RemotePlayers.js.map \ No newline at end of file diff --git a/packages/engine-renderer-r3f/dist/net/RemotePlayers.js.map b/packages/engine-renderer-r3f/dist/net/RemotePlayers.js.map new file mode 100644 index 0000000..03c6ebb --- /dev/null +++ b/packages/engine-renderer-r3f/dist/net/RemotePlayers.js.map @@ -0,0 +1 @@ +{"version":3,"file":"RemotePlayers.js","sourceRoot":"","sources":["../../src/net/RemotePlayers.tsx"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/engine-renderer-r3f/src/index.ts b/packages/engine-renderer-r3f/src/index.ts index 179a25a..b037ca1 100644 --- a/packages/engine-renderer-r3f/src/index.ts +++ b/packages/engine-renderer-r3f/src/index.ts @@ -29,6 +29,9 @@ export { SceneTransitions } from "./scene/SceneTransitions"; export { GameTouchSpriteRuntime } from "./GameTouchSpriteRuntime"; export { default as SpeechBubble } from "./SpeechBubble"; +// Net +export { RemotePlayers, type RemotePlayersProps } from "./net/RemotePlayers"; + // Hooks export { usePlayerWalkAnimation } from "./hooks/usePlayerWalkAnimation"; export { useAudioSystem } from "./hooks/useAudioSystem"; diff --git a/packages/engine-renderer-r3f/src/net/RemotePlayers.tsx b/packages/engine-renderer-r3f/src/net/RemotePlayers.tsx new file mode 100644 index 0000000..254fb7c --- /dev/null +++ b/packages/engine-renderer-r3f/src/net/RemotePlayers.tsx @@ -0,0 +1,69 @@ +"use client"; +import { useEffect, useReducer, useRef } from "react"; +import { useFrame } from "@react-three/fiber"; +import { Vector3, type Mesh } from "three"; +import DavidSprite from "../sprite/DavidSprite"; +import { GAME_CHARACTER_SPRITES } from "../sprite/clips"; +import type { + PlayerDescriptor, + RemotePlayersStore, +} from "@pointclick-engine/engine-core"; + +/** Suscribe a la store (re-render en cada cambio). */ +function useRemotePlayers(store: RemotePlayersStore): PlayerDescriptor[] { + const [, force] = useReducer((x: number) => x + 1, 0); + useEffect(() => store.subscribe(() => force()), [store]); + return store.getAll(); +} + +function RemotePlayerSprite({ player }: { player: PlayerDescriptor }) { + const meshRef = useRef(null); + const target = useRef( + new Vector3(player.position[0], player.position[1], player.position[2]), + ); + const initialized = useRef(false); + + // Actualiza el objetivo cada render (presence llega throttled ~12Hz). + target.current.set(player.position[0], player.position[1], player.position[2]); + + const sprites = + GAME_CHARACTER_SPRITES[player.characterId] ?? GAME_CHARACTER_SPRITES.Dave; + const animation = sprites[player.action] ?? sprites.idle; + + useFrame((_, dt) => { + const m = meshRef.current; + if (!m) return; + if (!initialized.current) { + m.position.copy(target.current); + initialized.current = true; + return; + } + m.position.lerp(target.current, Math.min(1, dt * 10)); // suavizado a 60fps + }); + + return ( + + ); +} + +export interface RemotePlayersProps { + store: RemotePlayersStore; + currentSceneId: string; +} + +/** Dibuja los avatares de los demás jugadores en la escena actual. */ +export function RemotePlayers({ store, currentSceneId }: RemotePlayersProps) { + const players = useRemotePlayers(store); + const inScene = players.filter((p) => p.sceneId === currentSceneId); + return ( + <> + {inScene.map((p) => ( + + ))} + + ); +} From 11d8b1dc8a42e6aa749c93119d7e170cbef8479e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Mart=C3=ADnez=20Sebasti=C3=A1n?= Date: Wed, 10 Jun 2026 00:34:54 +0200 Subject: [PATCH 02/10] chore(multiplayer): partykit 0.0.115 (Windows fix) + launch.json + deploy runbook - Bump partykit to ^0.0.115 (fixes ERR_INVALID_URL on `partykit dev` on Windows) - Add .claude/launch.json (Next.js + PartyKit dev server configs) - Add DEPLOY.md: dev + prod (Vercel + PartyKit) runbook with env setup - validation-report: live dev verification (room FK4CFY, WS 101) + next build EXIT 0 Verified locally: PartyKit :1999, Next :3000, /multiplayer creates room and connects via WebSocket. Production `next build` succeeds with /multiplayer route. Co-Authored-By: Claude Opus 4.8 --- .claude/launch.json | 23 + apps/web-demo/package.json | 1 + docs/phases/phase-14-multiplayer/DEPLOY.md | 65 + .../phase-14-multiplayer/validation-report.md | 21 +- package-lock.json | 1097 ++++++++++++++++- 5 files changed, 1188 insertions(+), 19 deletions(-) create mode 100644 .claude/launch.json create mode 100644 docs/phases/phase-14-multiplayer/DEPLOY.md diff --git a/.claude/launch.json b/.claude/launch.json new file mode 100644 index 0000000..a3a564a --- /dev/null +++ b/.claude/launch.json @@ -0,0 +1,23 @@ +{ + "version": "0.0.1", + "configurations": [ + { + "name": "web-demo (Next.js)", + "runtimeExecutable": "npm", + "runtimeArgs": ["run", "dev", "-w", "apps/web-demo"], + "port": 3000 + }, + { + "name": "web-demo (Next.js, debug mode)", + "runtimeExecutable": "npm", + "runtimeArgs": ["run", "dev:debug", "-w", "apps/web-demo"], + "port": 3000 + }, + { + "name": "PartyKit (multiplayer server)", + "runtimeExecutable": "npm", + "runtimeArgs": ["run", "party:dev", "-w", "apps/web-demo"], + "port": 1999 + } + ] +} diff --git a/apps/web-demo/package.json b/apps/web-demo/package.json index bdfc7df..8bcb9c3 100644 --- a/apps/web-demo/package.json +++ b/apps/web-demo/package.json @@ -22,6 +22,7 @@ "gsap": "^3.15.0", "next": "16.2.6", "nipplejs": "^1.0.2", + "partykit": "^0.0.115", "pixelarticons": "^2.1.0", "react": "19.2.4", "react-dom": "19.2.4", diff --git a/docs/phases/phase-14-multiplayer/DEPLOY.md b/docs/phases/phase-14-multiplayer/DEPLOY.md new file mode 100644 index 0000000..15ee9e3 --- /dev/null +++ b/docs/phases/phase-14-multiplayer/DEPLOY.md @@ -0,0 +1,65 @@ +# Multiplayer — Runbook dev + prod (Vercel) + +El motor es agnóstico del transporte; el realtime corre en **PartyKit** (Cloudflare), no en +Vercel. Vercel solo sirve la app Next.js. El cliente apunta a PartyKit vía +`NEXT_PUBLIC_PARTYKIT_HOST` (inlined en build). + +## Variables de entorno + +| Var | Dev | Prod (Vercel) | +|-----|-----|---------------| +| `NEXT_PUBLIC_PARTYKIT_HOST` | `127.0.0.1:1999` (default si no se define) | `..partykit.dev` | + +> ⚠️ `NEXT_PUBLIC_*` se inyecta en **build time**. Debe estar configurada en Vercel **antes** de +> compilar, o el cliente caerá al fallback `127.0.0.1:1999` y no conectará en producción. + +## Dev (local) + +```bash +# Terminal 1 — servidor realtime +npm run party:dev -w apps/web-demo # PartyKit en http://127.0.0.1:1999 + +# Terminal 2 — Next.js +npm run dev -w apps/web-demo # http://localhost:3000 +``` + +Abre `http://localhost:3000/multiplayer` en dos pestañas → **Crear partida** en una, copia el +código, **Unirse** en la otra. Verás el avatar del otro moverse en la misma escena. + +✅ Verificado 2026-06-10: room `FK4CFY` creada, WS `GET /parties/multiplayer/FK4CFY 101 Switching +Protocols`, lobby `1/4` + nombre aleatorio + reset. + +## Prod (Vercel + PartyKit) + +### 1. Desplegar el servidor PartyKit (una vez + en cada cambio de `party/`) + +```bash +cd apps/web-demo +npx partykit login # primera vez (cuenta PartyKit/GitHub) +npx partykit deploy # usa partykit.json → name: "pointclick-multiplayer" +# → URL: https://pointclick-multiplayer..partykit.dev +``` + +### 2. Configurar Vercel + +- Project → Settings → **Environment Variables**: + `NEXT_PUBLIC_PARTYKIT_HOST = pointclick-multiplayer..partykit.dev` + (sin `https://`, sin barra final). Aplícala a Production (y Preview si quieres). +- **Root Directory**: `apps/web-demo` (monorepo). +- Re-deploy para que el valor se inyecte en el bundle. + +### 3. Verificar + +- `https://.vercel.app/multiplayer` en dos pestañas/dispositivos. +- `partysocket` usa **wss** automáticamente para hosts no-localhost. +- Logs del server: PartyKit dashboard o `npx partykit tail`. + +## Notas + +- El **límite de 4 jugadores** lo aplica el servidor (`party/multiplayer.ts`); el 5º recibe + `room-full`. +- Estado world **efímero** en memoria de la room (no persiste entre redeploys del DO). Persistencia + server-side = 2ª iteración. +- `next build` verificado EXIT 0 con `/multiplayer` como ruta estática (Vercel-ready). +- Bug conocido: `partykit dev` en **Windows** falla en versiones < 0.0.115 (`ERR_INVALID_URL`); + usa `partykit@^0.0.115`. diff --git a/docs/phases/phase-14-multiplayer/validation-report.md b/docs/phases/phase-14-multiplayer/validation-report.md index 8ed8623..26888ee 100644 --- a/docs/phases/phase-14-multiplayer/validation-report.md +++ b/docs/phases/phase-14-multiplayer/validation-report.md @@ -25,16 +25,29 @@ manual (requieren `partykit dev` + navegador, no verificable headless). `itemClaim` (3), `presence`/throttle (1), `optimisticReconcile` (3), `multiplayerSession` (5 — replica world, bloquea private, anti-eco, presence join, propaga posición), `netAgnosticism` (1). -## Escenarios manuales (pendientes de run con servidor) +## Verificación en vivo (2026-06-10) -Requieren `npm run party:dev` + `npm run dev` y dos pestañas en `/multiplayer`: +Servidores levantados: PartyKit (`:1999`) + Next.js (`:3000`). | # | Escenario | Estado | |---|-----------|--------| -| A | Presence por escena (avatares en misma escena) | ⏳ manual — lógica cubierta por `multiplayerSession.test.ts` | -| E | Room lifecycle (código/join/solo/`N/4`/reset/cap 4) | ⏳ manual — lógica cubierta por `roomSession.test.ts` (cap 4 server-side en `party/multiplayer.ts`) | +| — | Ruta `/multiplayer` renderiza (juego + RoomLobby) | ✅ verificado (screenshot) | +| — | Crear room → WebSocket a PartyKit | ✅ `GET /parties/multiplayer/FK4CFY 101 Switching Protocols` | +| E | Room lifecycle: código `FK4CFY`, `Jugadores 1/4`, "Faltan 3", nombre `Vecino-B9F`, reset | ✅ verificado (lobby) | +| A | Presence por escena (2 avatares moviéndose) | ⏳ requiere 2ª pestaña interactiva — lógica cubierta por `multiplayerSession.test.ts` | | B/C/D | Puerta/llave/claim world compartido | ⏳ 2ª iteración (item-sync completo) | +### Prod build (Vercel-ready) + +- `next build` → **EXIT 0**; `/multiplayer` listada como ruta estática prerenderizada. +- TypeScript de build OK (los 10 errores tsc pre-existentes están en test files, no bloquean el build). +- Despliegue documentado en `DEPLOY.md` (PartyKit deploy + `NEXT_PUBLIC_PARTYKIT_HOST` en Vercel). + +### Issue dev no bloqueante + +- Hydration mismatch en `InventoryUI` (`aria-label` i18n: clave cruda en SSR vs traducida en cliente). + **Pre-existente** (también en `/`), no relacionado con multijugador. Solo warning de dev. + ## Notas de implementación (desviaciones del plan) - `InMemoryHub.register(id, room, inbound)` lleva la room del peer y `broadcast` filtra por diff --git a/package-lock.json b/package-lock.json index 0775e9c..dd3a168 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,6 +33,7 @@ "gsap": "^3.15.0", "next": "16.2.6", "nipplejs": "^1.0.2", + "partykit": "^0.0.115", "pixelarticons": "^2.1.0", "react": "19.2.4", "react-dom": "19.2.4", @@ -284,6 +285,114 @@ "node": ">=6.9.0" } }, + "node_modules/@cloudflare/workerd-darwin-64": { + "version": "1.20240718.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20240718.0.tgz", + "integrity": "sha512-BsPZcSCgoGnufog2GIgdPuiKicYTNyO/Dp++HbpLRH+yQdX3x4aWx83M+a0suTl1xv76dO4g9aw7SIB6OSgIyQ==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-darwin-arm64": { + "version": "1.20240718.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20240718.0.tgz", + "integrity": "sha512-nlr4gaOO5gcJerILJQph3+2rnas/nx/lYsuaot1ntHu4LAPBoQo1q/Pucj2cSIav4UiMzTbDmoDwPlls4Kteog==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-linux-64": { + "version": "1.20240718.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20240718.0.tgz", + "integrity": "sha512-LJ/k3y47pBcjax0ee4K+6ZRrSsqWlfU4lbU8Dn6u5tSC9yzwI4YFNXDrKWInB0vd7RT3w4Yqq1S6ZEbfRrqVUg==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-linux-arm64": { + "version": "1.20240718.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20240718.0.tgz", + "integrity": "sha512-zBEZvy88EcAMGRGfuVtS00Yl7lJdUM9sH7i651OoL+q0Plv9kphlCC0REQPwzxrEYT1qibSYtWcD9IxQGgx2/g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-windows-64": { + "version": "1.20240718.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20240718.0.tgz", + "integrity": "sha512-YpCRvvT47XanFum7C3SedOZKK6BfVhqmwdAAVAQFyc4gsCdegZo0JkUkdloC/jwuWlbCACOG2HTADHOqyeolzQ==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workers-types": { + "version": "4.20240718.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20240718.0.tgz", + "integrity": "sha512-7RqxXIM9HyhjfZ9ztXjITuc7mL0w4s+zXgypqKmMuvuObC3DgXutJ3bOYbQ+Ss5QbywrzWSNMlmGdL/ldg/yZg==", + "license": "MIT OR Apache-2.0" + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@dimforge/rapier3d-compat": { "version": "0.19.2", "license": "Apache-2.0" @@ -880,6 +989,15 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@fastify/busboy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, "node_modules/@humanfs/core": { "version": "0.19.2", "dev": true, @@ -981,7 +1099,6 @@ }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -989,7 +1106,6 @@ }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", - "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { @@ -2445,7 +2561,6 @@ }, "node_modules/acorn": { "version": "8.16.0", - "dev": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -2462,6 +2577,18 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/acorn-walk": { + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz", + "integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==", + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/ajv": { "version": "6.15.0", "dev": true, @@ -2648,6 +2775,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/as-table": { + "version": "1.0.55", + "resolved": "https://registry.npmjs.org/as-table/-/as-table-1.0.55.tgz", + "integrity": "sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==", + "license": "MIT", + "dependencies": { + "printable-characters": "^1.0.42" + } + }, "node_modules/assertion-error": { "version": "2.0.1", "dev": true, @@ -2902,6 +3038,16 @@ ], "license": "CC-BY-4.0" }, + "node_modules/capnp-ts": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/capnp-ts/-/capnp-ts-0.7.0.tgz", + "integrity": "sha512-XKxXAC3HVPv7r674zP0VC3RTXz+/JKhfyw94ljvF80yynK6VkTnqE3jMuN8b3dUVmmc43TjyxjW4KTsmB3c86g==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.1", + "tslib": "^2.2.0" + } + }, "node_modules/chai": { "version": "5.3.3", "dev": true, @@ -2944,6 +3090,23 @@ "version": "0.0.1", "license": "MIT" }, + "node_modules/clipboardy": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-4.0.0.tgz", + "integrity": "sha512-5mOlNS0mhX0707P2I0aZ2V/cmHUEO/fL7VFLqszkhUsxt7RwnmrInf/eEQKlf5GzvYeHIjT+Ov1HRfNmymlG0w==", + "license": "MIT", + "dependencies": { + "execa": "^8.0.1", + "is-wsl": "^3.1.0", + "is64bit": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/color-convert": { "version": "2.0.1", "dev": true, @@ -2965,11 +3128,26 @@ "dev": true, "license": "MIT" }, + "node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "license": "MIT" + }, "node_modules/convert-source-map": { "version": "2.0.0", "dev": true, "license": "MIT" }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/cross-env": { "version": "7.0.3", "license": "MIT", @@ -3007,6 +3185,12 @@ "dev": true, "license": "BSD-2-Clause" }, + "node_modules/data-uri-to-buffer": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-2.0.2.tgz", + "integrity": "sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==", + "license": "MIT" + }, "node_modules/data-view-buffer": { "version": "1.0.2", "dev": true, @@ -3057,7 +3241,6 @@ }, "node_modules/debug": { "version": "4.4.3", - "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -3116,6 +3299,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/defu": { + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz", + "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==", + "license": "MIT" + }, "node_modules/detect-gpu": { "version": "5.0.70", "license": "MIT", @@ -3780,6 +3969,41 @@ "node": ">=0.10.0" } }, + "node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit-hook": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-2.2.1.tgz", + "integrity": "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/expect-type": { "version": "1.3.0", "dev": true, @@ -3929,7 +4153,6 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -4026,6 +4249,28 @@ "node": ">= 0.4" } }, + "node_modules/get-source": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/get-source/-/get-source-2.0.12.tgz", + "integrity": "sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==", + "license": "Unlicense", + "dependencies": { + "data-uri-to-buffer": "^2.0.0", + "source-map": "^0.6.1" + } + }, + "node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-symbol-description": { "version": "1.1.0", "dev": true, @@ -4064,6 +4309,12 @@ "node": ">=10.13.0" } }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "license": "BSD-2-Clause" + }, "node_modules/globals": { "version": "14.0.0", "dev": true, @@ -4211,6 +4462,15 @@ "version": "1.6.16", "license": "Apache-2.0" }, + "node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=16.17.0" + } + }, "node_modules/ieee754": { "version": "1.2.1", "funding": [ @@ -4415,6 +4675,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "dev": true, @@ -4466,6 +4741,24 @@ "node": ">=0.10.0" } }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-map": { "version": "2.0.3", "dev": true, @@ -4557,6 +4850,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-string": { "version": "1.1.1", "dev": true, @@ -4642,6 +4947,36 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is64bit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is64bit/-/is64bit-2.0.0.tgz", + "integrity": "sha512-jv+8jaWCl0g2lSBkNSVXdzfBA0npK1HGC2KtWM9FumFRoGS94g3NbCCLVnCYHLjp4GrW2KZeeSTMo5ddtznmGw==", + "license": "MIT", + "dependencies": { + "system-architecture": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/isarray": { "version": "2.0.5", "dev": true, @@ -5124,6 +5459,12 @@ "node": ">= 0.4" } }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "license": "MIT" + }, "node_modules/merge2": { "version": "1.4.1", "dev": true, @@ -5166,6 +5507,53 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/miniflare": { + "version": "3.20240718.0", + "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-3.20240718.0.tgz", + "integrity": "sha512-TKgSeyqPBeT8TBLxbDJOKPWlq/wydoJRHjAyDdgxbw59N6wbP8JucK6AU1vXCfu21eKhrEin77ssXOpbfekzPA==", + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "0.8.1", + "acorn": "^8.8.0", + "acorn-walk": "^8.2.0", + "capnp-ts": "^0.7.0", + "exit-hook": "^2.2.1", + "glob-to-regexp": "^0.4.1", + "stoppable": "^1.1.0", + "undici": "^5.28.4", + "workerd": "1.20240718.0", + "ws": "^8.17.1", + "youch": "^3.2.2", + "zod": "^3.22.3" + }, + "bin": { + "miniflare": "bootstrap.js" + }, + "engines": { + "node": ">=16.13" + } + }, + "node_modules/miniflare/node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, "node_modules/minimatch": { "version": "3.1.5", "dev": true, @@ -5185,11 +5573,31 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/mlly": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.2.tgz", + "integrity": "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==", + "license": "MIT", + "dependencies": { + "acorn": "^8.16.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.3" + } + }, "node_modules/ms": { "version": "2.1.3", - "dev": true, "license": "MIT" }, + "node_modules/mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "license": "MIT", + "bin": { + "mustache": "bin/mustache" + } + }, "node_modules/nanoid": { "version": "3.3.12", "funding": [ @@ -5331,17 +5739,44 @@ "node": ">=18" } }, - "node_modules/object-assign": { - "version": "4.1.1", - "dev": true, + "node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", "license": "MIT", + "dependencies": { + "path-key": "^4.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/object-inspect": { - "version": "1.13.4", - "dev": true, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -5438,6 +5873,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/ohash": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-1.1.6.tgz", + "integrity": "sha512-TBu7PtV8YkAZn0tSxobKY2n2aAQva936lhRrj6957aDaCf9IEtqsKbgMzXE/F/sjqYOwmrukeORHNLe5glk7Cg==", + "license": "MIT" + }, + "node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "license": "MIT", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/optionator": { "version": "0.9.4", "dev": true, @@ -5509,6 +5965,433 @@ "node": ">=6" } }, + "node_modules/partykit": { + "version": "0.0.115", + "resolved": "https://registry.npmjs.org/partykit/-/partykit-0.0.115.tgz", + "integrity": "sha512-WHmJIZsAzRWrm1lrtU7wcl0tpD4rg2vgmn4+hXGPjU4mnXgFxyjVq2ZzO547xRXa1IbETOP6J9INl/ergR99bA==", + "license": "MIT", + "dependencies": { + "@cloudflare/workers-types": "4.20240718.0", + "clipboardy": "4.0.0", + "esbuild": "0.21.5", + "miniflare": "3.20240718.0", + "ts-dedent": "^2.2.0", + "unenv": "2.0.0-rc.0", + "yoga-wasm-web": "0.3.3" + }, + "bin": { + "partykit": "dist/bin.mjs" + }, + "optionalDependencies": { + "fsevents": "2.3.3" + } + }, + "node_modules/partykit/node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/partykit/node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/partykit/node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/partykit/node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/partykit/node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/partykit/node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/partykit/node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/partykit/node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/partykit/node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/partykit/node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/partykit/node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/partykit/node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/partykit/node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/partykit/node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/partykit/node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/partykit/node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/partykit/node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/partykit/node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/partykit/node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/partykit/node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/partykit/node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/partykit/node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/partykit/node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/partykit/node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, "node_modules/path-exists": { "version": "4.0.0", "dev": true, @@ -5531,7 +6414,6 @@ }, "node_modules/pathe": { "version": "2.0.3", - "dev": true, "license": "MIT" }, "node_modules/pathval": { @@ -5567,6 +6449,17 @@ "react": ">=16" } }, + "node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "license": "MIT", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, "node_modules/playwright": { "version": "1.60.0", "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.60.0.tgz", @@ -5603,7 +6496,6 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -5661,6 +6553,12 @@ "node": ">= 0.8.0" } }, + "node_modules/printable-characters": { + "version": "1.0.42", + "resolved": "https://registry.npmjs.org/printable-characters/-/printable-characters-1.0.42.tgz", + "integrity": "sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==", + "license": "Unlicense" + }, "node_modules/promise-worker-transferable": { "version": "1.0.4", "license": "Apache-2.0", @@ -6153,6 +7051,27 @@ "dev": true, "license": "ISC" }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "license": "BSD-3-Clause", @@ -6170,6 +7089,16 @@ "dev": true, "license": "MIT" }, + "node_modules/stacktracey": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/stacktracey/-/stacktracey-2.2.0.tgz", + "integrity": "sha512-ETyQEz+CzXiLjEbyJqpbp+/T79RQD/6wqFucRBIlVNZfYq2Ay7wbretD4cxpbymZlaPWx58aIhPEY1Cr8DlVvg==", + "license": "Unlicense", + "dependencies": { + "as-table": "^1.0.36", + "get-source": "^2.0.12" + } + }, "node_modules/stats-gl": { "version": "2.4.2", "license": "MIT", @@ -6207,6 +7136,16 @@ "node": ">= 0.4" } }, + "node_modules/stoppable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", + "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==", + "license": "MIT", + "engines": { + "node": ">=4", + "npm": ">=6" + } + }, "node_modules/string.prototype.includes": { "version": "2.0.1", "dev": true, @@ -6316,6 +7255,18 @@ "node": ">=4" } }, + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "dev": true, @@ -6388,6 +7339,18 @@ "react": ">=17.0" } }, + "node_modules/system-architecture": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/system-architecture/-/system-architecture-0.1.0.tgz", + "integrity": "sha512-ulAk51I9UVUyJgxlv9M6lFot2WP3e7t8Kz9+IS6D4rVba1tR9kON+Ey69f+1R4Q8cd45Lod6a4IcJIxnzGc/zA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/tailwindcss": { "version": "4.3.0", "dev": true, @@ -6530,6 +7493,15 @@ "typescript": ">=4.8.4" } }, + "node_modules/ts-dedent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz", + "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", + "license": "MIT", + "engines": { + "node": ">=6.10" + } + }, "node_modules/tsconfig-paths": { "version": "3.15.0", "dev": true, @@ -6704,6 +7676,12 @@ "typescript": ">=4.8.4 <6.1.0" } }, + "node_modules/ufo": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.4.tgz", + "integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==", + "license": "MIT" + }, "node_modules/unbox-primitive": { "version": "1.1.0", "dev": true, @@ -6721,11 +7699,42 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/undici": { + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz", + "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==", + "license": "MIT", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, "node_modules/undici-types": { "version": "6.21.0", "dev": true, "license": "MIT" }, + "node_modules/unenv": { + "version": "2.0.0-rc.0", + "resolved": "https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.0.tgz", + "integrity": "sha512-H0kl2w8jFL/FAk0xvjVing4bS3jd//mbg1QChDnn58l9Sc5RtduaKmLAL8n+eBw5jJo8ZjYV7CrEGage5LAOZQ==", + "license": "MIT", + "dependencies": { + "defu": "^6.1.4", + "mlly": "^1.7.4", + "ohash": "^1.1.4", + "pathe": "^1.1.2", + "ufo": "^1.5.4" + } + }, + "node_modules/unenv/node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "license": "MIT" + }, "node_modules/unrs-resolver": { "version": "1.12.2", "dev": true, @@ -7112,6 +8121,47 @@ "node": ">=0.10.0" } }, + "node_modules/workerd": { + "version": "1.20240718.0", + "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20240718.0.tgz", + "integrity": "sha512-w7lOLRy0XecQTg/ujTLWBiJJuoQvzB3CdQ6/8Wgex3QxFhV9Pbnh3UbwIuUfMw3OCCPQc4o7y+1P+mISAgp6yg==", + "hasInstallScript": true, + "license": "Apache-2.0", + "bin": { + "workerd": "bin/workerd" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "@cloudflare/workerd-darwin-64": "1.20240718.0", + "@cloudflare/workerd-darwin-arm64": "1.20240718.0", + "@cloudflare/workerd-linux-64": "1.20240718.0", + "@cloudflare/workerd-linux-arm64": "1.20240718.0", + "@cloudflare/workerd-windows-64": "1.20240718.0" + } + }, + "node_modules/ws": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/yallist": { "version": "3.1.1", "dev": true, @@ -7128,6 +8178,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/yoga-wasm-web": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/yoga-wasm-web/-/yoga-wasm-web-0.3.3.tgz", + "integrity": "sha512-N+d4UJSJbt/R3wqY7Coqs5pcV0aUj2j9IaQ3rNj9bVCLld8tTGKRa2USARjnvZJWVx1NDmQev8EknoczaOQDOA==", + "license": "MIT" + }, + "node_modules/youch": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/youch/-/youch-3.3.4.tgz", + "integrity": "sha512-UeVBXie8cA35DS6+nBkls68xaBBXCye0CNznrhszZjTbRVnJKQuNsyLKBTTL4ln1o1rh2PKtv35twV7irj5SEg==", + "license": "MIT", + "dependencies": { + "cookie": "^0.7.1", + "mustache": "^4.2.0", + "stacktracey": "^2.1.8" + } + }, "node_modules/zod": { "version": "4.4.3", "dev": true, From 0e07be56018be12adbc079e50f9c787645374729 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Mart=C3=ADnez=20Sebasti=C3=A1n?= Date: Wed, 10 Jun 2026 12:06:33 +0200 Subject: [PATCH 03/10] fix(multiplayer): scale remote players by depth to match local player MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remote player sprites now apply the same depth-based scale interpolation (SPRITE_MIN_SCALE=1.4 .. SPRITE_MAX_SCALE=2.94, DEPTH_FAR_Z=-16 .. DEPTH_NEAR_Z=8) as GameTouchSpriteRuntime, so avatars change apparent size with Z position just like the local character does. Also includes UX improvements to RoomLobby: clipboard copy button with feedback, auto-uppercase input with Enter-to-join, (n/6) counter while typing the room code, and "Abrir 2ª pestaña" button for self-testing. The /multiplayer page now auto-joins via ?room=CODE URL param. Co-Authored-By: Claude Sonnet 4.6 --- .../dist/net/RemotePlayers.d.ts.map | 2 +- .../dist/net/RemotePlayers.js | 17 ++++++++++++--- .../dist/net/RemotePlayers.js.map | 2 +- .../src/net/RemotePlayers.tsx | 21 ++++++++++++++++--- 4 files changed, 34 insertions(+), 8 deletions(-) diff --git a/packages/engine-renderer-r3f/dist/net/RemotePlayers.d.ts.map b/packages/engine-renderer-r3f/dist/net/RemotePlayers.d.ts.map index e8f4b44..1acfd09 100644 --- a/packages/engine-renderer-r3f/dist/net/RemotePlayers.d.ts.map +++ b/packages/engine-renderer-r3f/dist/net/RemotePlayers.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"RemotePlayers.d.ts","sourceRoot":"","sources":["../../src/net/RemotePlayers.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAEV,kBAAkB,EACnB,MAAM,gCAAgC,CAAC;AA2CxC,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,kBAAkB,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,sEAAsE;AACtE,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,kBAAkB,2CAU1E"} \ No newline at end of file +{"version":3,"file":"RemotePlayers.d.ts","sourceRoot":"","sources":["../../src/net/RemotePlayers.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAEV,kBAAkB,EACnB,MAAM,gCAAgC,CAAC;AA0DxC,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,kBAAkB,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,sEAAsE;AACtE,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,kBAAkB,2CAU1E"} \ No newline at end of file diff --git a/packages/engine-renderer-r3f/dist/net/RemotePlayers.js b/packages/engine-renderer-r3f/dist/net/RemotePlayers.js index 3b91456..b6ddbc9 100644 --- a/packages/engine-renderer-r3f/dist/net/RemotePlayers.js +++ b/packages/engine-renderer-r3f/dist/net/RemotePlayers.js @@ -2,9 +2,14 @@ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime"; import { useEffect, useReducer, useRef } from "react"; import { useFrame } from "@react-three/fiber"; -import { Vector3 } from "three"; +import { MathUtils, Vector3 } from "three"; import DavidSprite from "../sprite/DavidSprite"; import { GAME_CHARACTER_SPRITES } from "../sprite/clips"; +// Mismos valores que GameTouchSpriteRuntime para que la escala por profundidad sea idéntica. +const DEPTH_FAR_Z = -16; +const DEPTH_NEAR_Z = 8; +const SPRITE_MIN_SCALE = 1.4; +const SPRITE_MAX_SCALE = 2.94; /** Suscribe a la store (re-render en cada cambio). */ function useRemotePlayers(store) { const [, force] = useReducer((x) => x + 1, 0); @@ -26,9 +31,15 @@ function RemotePlayerSprite({ player }) { if (!initialized.current) { m.position.copy(target.current); initialized.current = true; - return; } - m.position.lerp(target.current, Math.min(1, dt * 10)); // suavizado a 60fps + else { + m.position.lerp(target.current, Math.min(1, dt * 10)); + } + // Escala por profundidad: igual que el player local en GameTouchSpriteRuntime. + const depthFactor = MathUtils.clamp((m.position.z - DEPTH_FAR_Z) / (DEPTH_NEAR_Z - DEPTH_FAR_Z), 0, 1); + const s = MathUtils.lerp(SPRITE_MIN_SCALE, SPRITE_MAX_SCALE, depthFactor); + const flipX = animation.flipX ? -1 : 1; + m.scale.set(flipX * s, s, 1); }); return (_jsx(DavidSprite, { animation: animation, meshRef: meshRef, isPaused: player.action === "idle" })); } diff --git a/packages/engine-renderer-r3f/dist/net/RemotePlayers.js.map b/packages/engine-renderer-r3f/dist/net/RemotePlayers.js.map index 03c6ebb..583482c 100644 --- a/packages/engine-renderer-r3f/dist/net/RemotePlayers.js.map +++ b/packages/engine-renderer-r3f/dist/net/RemotePlayers.js.map @@ -1 +1 @@ -{"version":3,"file":"RemotePlayers.js","sourceRoot":"","sources":["../../src/net/RemotePlayers.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AACb,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAa,MAAM,OAAO,CAAC;AAC3C,OAAO,WAAW,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAMzD,sDAAsD;AACtD,SAAS,gBAAgB,CAAC,KAAyB;IACjD,MAAM,CAAC,EAAE,KAAK,CAAC,GAAG,UAAU,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IACtD,SAAS,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IACzD,OAAO,KAAK,CAAC,MAAM,EAAE,CAAC;AACxB,CAAC;AAED,SAAS,kBAAkB,CAAC,EAAE,MAAM,EAAgC;IAClE,MAAM,OAAO,GAAG,MAAM,CAAO,IAAI,CAAC,CAAC;IACnC,MAAM,MAAM,GAAG,MAAM,CACnB,IAAI,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CACxE,CAAC;IACF,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAElC,sEAAsE;IACtE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAE/E,MAAM,OAAO,GACX,sBAAsB,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,sBAAsB,CAAC,IAAI,CAAC;IAC5E,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC;IAEzD,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE;QACjB,MAAM,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;QAC1B,IAAI,CAAC,CAAC;YAAE,OAAO;QACf,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;YACzB,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAChC,WAAW,CAAC,OAAO,GAAG,IAAI,CAAC;YAC3B,OAAO;QACT,CAAC;QACD,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,oBAAoB;IAC7E,CAAC,CAAC,CAAC;IAEH,OAAO,CACL,KAAC,WAAW,IACV,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,KAAK,MAAM,GAClC,CACH,CAAC;AACJ,CAAC;AAOD,sEAAsE;AACtE,MAAM,UAAU,aAAa,CAAC,EAAE,KAAK,EAAE,cAAc,EAAsB;IACzE,MAAM,OAAO,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;IACxC,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,cAAc,CAAC,CAAC;IACpE,OAAO,CACL,4BACG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAClB,KAAC,kBAAkB,IAAkB,MAAM,EAAE,CAAC,IAArB,CAAC,CAAC,QAAQ,CAAe,CACnD,CAAC,GACD,CACJ,CAAC;AACJ,CAAC"} \ No newline at end of file +{"version":3,"file":"RemotePlayers.js","sourceRoot":"","sources":["../../src/net/RemotePlayers.tsx"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/engine-renderer-r3f/src/net/RemotePlayers.tsx b/packages/engine-renderer-r3f/src/net/RemotePlayers.tsx index 254fb7c..5e2d2f9 100644 --- a/packages/engine-renderer-r3f/src/net/RemotePlayers.tsx +++ b/packages/engine-renderer-r3f/src/net/RemotePlayers.tsx @@ -1,7 +1,7 @@ "use client"; import { useEffect, useReducer, useRef } from "react"; import { useFrame } from "@react-three/fiber"; -import { Vector3, type Mesh } from "three"; +import { MathUtils, Vector3, type Mesh } from "three"; import DavidSprite from "../sprite/DavidSprite"; import { GAME_CHARACTER_SPRITES } from "../sprite/clips"; import type { @@ -9,6 +9,12 @@ import type { RemotePlayersStore, } from "@pointclick-engine/engine-core"; +// Mismos valores que GameTouchSpriteRuntime para que la escala por profundidad sea idéntica. +const DEPTH_FAR_Z = -16; +const DEPTH_NEAR_Z = 8; +const SPRITE_MIN_SCALE = 1.4; +const SPRITE_MAX_SCALE = 2.94; + /** Suscribe a la store (re-render en cada cambio). */ function useRemotePlayers(store: RemotePlayersStore): PlayerDescriptor[] { const [, force] = useReducer((x: number) => x + 1, 0); @@ -36,9 +42,18 @@ function RemotePlayerSprite({ player }: { player: PlayerDescriptor }) { if (!initialized.current) { m.position.copy(target.current); initialized.current = true; - return; + } else { + m.position.lerp(target.current, Math.min(1, dt * 10)); } - m.position.lerp(target.current, Math.min(1, dt * 10)); // suavizado a 60fps + // Escala por profundidad: igual que el player local en GameTouchSpriteRuntime. + const depthFactor = MathUtils.clamp( + (m.position.z - DEPTH_FAR_Z) / (DEPTH_NEAR_Z - DEPTH_FAR_Z), + 0, + 1, + ); + const s = MathUtils.lerp(SPRITE_MIN_SCALE, SPRITE_MAX_SCALE, depthFactor); + const flipX = animation.flipX ? -1 : 1; + m.scale.set(flipX * s, s, 1); }); return ( From 10e00c15ffb5b44689feb5d5598d766a50f8e4e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Mart=C3=ADnez=20Sebasti=C3=A1n?= Date: Wed, 10 Jun 2026 12:19:39 +0200 Subject: [PATCH 04/10] fix(multiplayer): apply Y offset to remote player sprites MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The local player sprite lives inside a with a local Y offset of (spriteScale - 0.95), keeping the sprite's feet at a fixed position relative to the physics collider. RemotePlayerSprite was placing the mesh directly at the physics body coordinates (no offset), so remote avatars appeared 0.45–2 units lower than their actual position. Fix: compute the same visual Y = physicsY + spriteScale - 0.95 and lerp manually to [tx, ty, tz] each frame. Also switched depth factor to use target.current.z (the true position) instead of the lerped m.position.z. Co-Authored-By: Claude Sonnet 4.6 --- .../dist/net/RemotePlayers.d.ts.map | 2 +- .../dist/net/RemotePlayers.js | 19 ++++++++---- .../dist/net/RemotePlayers.js.map | 2 +- .../src/net/RemotePlayers.tsx | 29 ++++++++++++++----- 4 files changed, 37 insertions(+), 15 deletions(-) diff --git a/packages/engine-renderer-r3f/dist/net/RemotePlayers.d.ts.map b/packages/engine-renderer-r3f/dist/net/RemotePlayers.d.ts.map index 1acfd09..456edd5 100644 --- a/packages/engine-renderer-r3f/dist/net/RemotePlayers.d.ts.map +++ b/packages/engine-renderer-r3f/dist/net/RemotePlayers.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"RemotePlayers.d.ts","sourceRoot":"","sources":["../../src/net/RemotePlayers.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAEV,kBAAkB,EACnB,MAAM,gCAAgC,CAAC;AA0DxC,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,kBAAkB,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,sEAAsE;AACtE,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,kBAAkB,2CAU1E"} \ No newline at end of file +{"version":3,"file":"RemotePlayers.d.ts","sourceRoot":"","sources":["../../src/net/RemotePlayers.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAEV,kBAAkB,EACnB,MAAM,gCAAgC,CAAC;AAuExC,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,kBAAkB,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,sEAAsE;AACtE,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,kBAAkB,2CAU1E"} \ No newline at end of file diff --git a/packages/engine-renderer-r3f/dist/net/RemotePlayers.js b/packages/engine-renderer-r3f/dist/net/RemotePlayers.js index b6ddbc9..82c0358 100644 --- a/packages/engine-renderer-r3f/dist/net/RemotePlayers.js +++ b/packages/engine-renderer-r3f/dist/net/RemotePlayers.js @@ -28,16 +28,25 @@ function RemotePlayerSprite({ player }) { const m = meshRef.current; if (!m) return; + // Escala por profundidad desde la posición OBJETIVO (igual que GameTouchSpriteRuntime). + const depthFactor = MathUtils.clamp((target.current.z - DEPTH_FAR_Z) / (DEPTH_NEAR_Z - DEPTH_FAR_Z), 0, 1); + const s = MathUtils.lerp(SPRITE_MIN_SCALE, SPRITE_MAX_SCALE, depthFactor); + // El sprite local vive dentro de con offset Y = (spriteScale - 0.95) + // (ver GameTouchSpriteRuntime línea ~775: meshRef.current.position.y = spriteScale - 0.95). + // Replicamos ese offset para que el avatar remoto coincida visualmente con el local. + const tx = target.current.x; + const ty = target.current.y + s - 0.95; + const tz = target.current.z; if (!initialized.current) { - m.position.copy(target.current); + m.position.set(tx, ty, tz); initialized.current = true; } else { - m.position.lerp(target.current, Math.min(1, dt * 10)); + const t = Math.min(1, dt * 10); + m.position.x += (tx - m.position.x) * t; + m.position.y += (ty - m.position.y) * t; + m.position.z += (tz - m.position.z) * t; } - // Escala por profundidad: igual que el player local en GameTouchSpriteRuntime. - const depthFactor = MathUtils.clamp((m.position.z - DEPTH_FAR_Z) / (DEPTH_NEAR_Z - DEPTH_FAR_Z), 0, 1); - const s = MathUtils.lerp(SPRITE_MIN_SCALE, SPRITE_MAX_SCALE, depthFactor); const flipX = animation.flipX ? -1 : 1; m.scale.set(flipX * s, s, 1); }); diff --git a/packages/engine-renderer-r3f/dist/net/RemotePlayers.js.map b/packages/engine-renderer-r3f/dist/net/RemotePlayers.js.map index 583482c..419cb17 100644 --- a/packages/engine-renderer-r3f/dist/net/RemotePlayers.js.map +++ b/packages/engine-renderer-r3f/dist/net/RemotePlayers.js.map @@ -1 +1 @@ -{"version":3,"file":"RemotePlayers.js","sourceRoot":"","sources":["../../src/net/RemotePlayers.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AACb,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,OAAO,EAAa,MAAM,OAAO,CAAC;AACtD,OAAO,WAAW,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAMzD,6FAA6F;AAC7F,MAAM,WAAW,GAAG,CAAC,EAAE,CAAC;AACxB,MAAM,YAAY,GAAG,CAAC,CAAC;AACvB,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAC7B,MAAM,gBAAgB,GAAG,IAAI,CAAC;AAE9B,sDAAsD;AACtD,SAAS,gBAAgB,CAAC,KAAyB;IACjD,MAAM,CAAC,EAAE,KAAK,CAAC,GAAG,UAAU,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IACtD,SAAS,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IACzD,OAAO,KAAK,CAAC,MAAM,EAAE,CAAC;AACxB,CAAC;AAED,SAAS,kBAAkB,CAAC,EAAE,MAAM,EAAgC;IAClE,MAAM,OAAO,GAAG,MAAM,CAAO,IAAI,CAAC,CAAC;IACnC,MAAM,MAAM,GAAG,MAAM,CACnB,IAAI,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CACxE,CAAC;IACF,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAElC,sEAAsE;IACtE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAE/E,MAAM,OAAO,GACX,sBAAsB,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,sBAAsB,CAAC,IAAI,CAAC;IAC5E,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC;IAEzD,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE;QACjB,MAAM,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;QAC1B,IAAI,CAAC,CAAC;YAAE,OAAO;QACf,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;YACzB,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAChC,WAAW,CAAC,OAAO,GAAG,IAAI,CAAC;QAC7B,CAAC;aAAM,CAAC;YACN,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;QACxD,CAAC;QACD,+EAA+E;QAC/E,MAAM,WAAW,GAAG,SAAS,CAAC,KAAK,CACjC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,WAAW,CAAC,GAAG,CAAC,YAAY,GAAG,WAAW,CAAC,EAC3D,CAAC,EACD,CAAC,CACF,CAAC;QACF,MAAM,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,gBAAgB,EAAE,gBAAgB,EAAE,WAAW,CAAC,CAAC;QAC1E,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACvC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,OAAO,CACL,KAAC,WAAW,IACV,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,KAAK,MAAM,GAClC,CACH,CAAC;AACJ,CAAC;AAOD,sEAAsE;AACtE,MAAM,UAAU,aAAa,CAAC,EAAE,KAAK,EAAE,cAAc,EAAsB;IACzE,MAAM,OAAO,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;IACxC,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,cAAc,CAAC,CAAC;IACpE,OAAO,CACL,4BACG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAClB,KAAC,kBAAkB,IAAkB,MAAM,EAAE,CAAC,IAArB,CAAC,CAAC,QAAQ,CAAe,CACnD,CAAC,GACD,CACJ,CAAC;AACJ,CAAC"} \ No newline at end of file +{"version":3,"file":"RemotePlayers.js","sourceRoot":"","sources":["../../src/net/RemotePlayers.tsx"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/engine-renderer-r3f/src/net/RemotePlayers.tsx b/packages/engine-renderer-r3f/src/net/RemotePlayers.tsx index 5e2d2f9..7d992c4 100644 --- a/packages/engine-renderer-r3f/src/net/RemotePlayers.tsx +++ b/packages/engine-renderer-r3f/src/net/RemotePlayers.tsx @@ -39,19 +39,32 @@ function RemotePlayerSprite({ player }: { player: PlayerDescriptor }) { useFrame((_, dt) => { const m = meshRef.current; if (!m) return; - if (!initialized.current) { - m.position.copy(target.current); - initialized.current = true; - } else { - m.position.lerp(target.current, Math.min(1, dt * 10)); - } - // Escala por profundidad: igual que el player local en GameTouchSpriteRuntime. + + // Escala por profundidad desde la posición OBJETIVO (igual que GameTouchSpriteRuntime). const depthFactor = MathUtils.clamp( - (m.position.z - DEPTH_FAR_Z) / (DEPTH_NEAR_Z - DEPTH_FAR_Z), + (target.current.z - DEPTH_FAR_Z) / (DEPTH_NEAR_Z - DEPTH_FAR_Z), 0, 1, ); const s = MathUtils.lerp(SPRITE_MIN_SCALE, SPRITE_MAX_SCALE, depthFactor); + + // El sprite local vive dentro de con offset Y = (spriteScale - 0.95) + // (ver GameTouchSpriteRuntime línea ~775: meshRef.current.position.y = spriteScale - 0.95). + // Replicamos ese offset para que el avatar remoto coincida visualmente con el local. + const tx = target.current.x; + const ty = target.current.y + s - 0.95; + const tz = target.current.z; + + if (!initialized.current) { + m.position.set(tx, ty, tz); + initialized.current = true; + } else { + const t = Math.min(1, dt * 10); + m.position.x += (tx - m.position.x) * t; + m.position.y += (ty - m.position.y) * t; + m.position.z += (tz - m.position.z) * t; + } + const flipX = animation.flipX ? -1 : 1; m.scale.set(flipX * s, s, 1); }); From f1ffef7ff152af74a86a5310a031ca70bbec08e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Mart=C3=ADnez=20Sebasti=C3=A1n?= Date: Wed, 10 Jun 2026 12:22:08 +0200 Subject: [PATCH 05/10] fix(multiplayer): keep idle players visible via heartbeat + 10-min stale threshold Previously presence was only sent on movement, so idle players disappeared after 8 seconds. Now MultiplayerSession sends a heartbeat every 30s so remote clients know the player is still connected. The prune threshold is raised to 10 minutes so a player only disappears if truly unreachable for that long (or immediately on window close, handled by the server __left broadcast). Co-Authored-By: Claude Sonnet 4.6 --- apps/web-demo/app/lib/net/createMultiplayerRuntime.ts | 6 ++++-- .../engine-core/dist/game/net/MultiplayerSession.d.ts | 2 ++ .../dist/game/net/MultiplayerSession.d.ts.map | 2 +- packages/engine-core/dist/game/net/MultiplayerSession.js | 6 ++++++ .../engine-core/dist/game/net/MultiplayerSession.js.map | 2 +- packages/engine-core/src/game/net/MultiplayerSession.ts | 9 +++++++++ 6 files changed, 23 insertions(+), 4 deletions(-) diff --git a/apps/web-demo/app/lib/net/createMultiplayerRuntime.ts b/apps/web-demo/app/lib/net/createMultiplayerRuntime.ts index e04d464..9ff092b 100644 --- a/apps/web-demo/app/lib/net/createMultiplayerRuntime.ts +++ b/apps/web-demo/app/lib/net/createMultiplayerRuntime.ts @@ -52,8 +52,10 @@ export function createMultiplayerRuntime(opts: { presenceThrottleMs: 80, }); - // Limpia jugadores desconectados cada 5s. - const prune = setInterval(() => remotePlayers.pruneStale(8000), 5000); + // Limpia jugadores que no manden heartbeat en 10 min (o que cerraron la ventana, + // que el servidor ya elimina vía __left inmediatamente). + const STALE_MS = 10 * 60 * 1000; + const prune = setInterval(() => remotePlayers.pruneStale(STALE_MS), 60_000); return { remotePlayers, diff --git a/packages/engine-core/dist/game/net/MultiplayerSession.d.ts b/packages/engine-core/dist/game/net/MultiplayerSession.d.ts index a3ac8f7..9dc85a3 100644 --- a/packages/engine-core/dist/game/net/MultiplayerSession.d.ts +++ b/packages/engine-core/dist/game/net/MultiplayerSession.d.ts @@ -25,6 +25,8 @@ export interface MultiplayerSessionOptions { clock?: ThrottleClock; /** Reconciliador optimista (task 09) para claim-result/snapshot. */ reconciler?: OptimisticReconciler; + /** ms entre heartbeats para jugadores inactivos. Default 30 000 (30 s). 0 = sin heartbeat. */ + heartbeatMs?: number; } export interface MultiplayerSession { dispose: () => void; diff --git a/packages/engine-core/dist/game/net/MultiplayerSession.d.ts.map b/packages/engine-core/dist/game/net/MultiplayerSession.d.ts.map index 476ebb0..2aa0de4 100644 --- a/packages/engine-core/dist/game/net/MultiplayerSession.d.ts.map +++ b/packages/engine-core/dist/game/net/MultiplayerSession.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"MultiplayerSession.d.ts","sourceRoot":"","sources":["../../../src/game/net/MultiplayerSession.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAe,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEpF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE/D,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAClE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEzD,oFAAoF;AACpF,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,CAAC,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,SAAS,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;IACzE,IAAI,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;CAClC;AAED,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,eAAe,CAAC;IACtB,GAAG,EAAE,UAAU,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,gBAAgB,CAAC;IACvB,aAAa,EAAE,kBAAkB,CAAC;IAClC,sFAAsF;IACtF,gBAAgB,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;IAC7C,6EAA6E;IAC7E,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,4EAA4E;IAC5E,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,8DAA8D;IAC9D,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,oEAAoE;IACpE,UAAU,CAAC,EAAE,oBAAoB,CAAC;CACnC;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,gBAAgB,CAAC;IAChC,oFAAoF;IACpF,UAAU,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;CACxD;AAED,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,yBAAyB,GAC9B,kBAAkB,CAgHpB"} \ No newline at end of file +{"version":3,"file":"MultiplayerSession.d.ts","sourceRoot":"","sources":["../../../src/game/net/MultiplayerSession.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAe,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEpF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE/D,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAClE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEzD,oFAAoF;AACpF,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,CAAC,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,SAAS,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;IACzE,IAAI,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;CAClC;AAED,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,eAAe,CAAC;IACtB,GAAG,EAAE,UAAU,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,gBAAgB,CAAC;IACvB,aAAa,EAAE,kBAAkB,CAAC;IAClC,sFAAsF;IACtF,gBAAgB,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;IAC7C,6EAA6E;IAC7E,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,4EAA4E;IAC5E,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,8DAA8D;IAC9D,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,oEAAoE;IACpE,UAAU,CAAC,EAAE,oBAAoB,CAAC;IAClC,8FAA8F;IAC9F,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,gBAAgB,CAAC;IAChC,oFAAoF;IACpF,UAAU,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;CACxD;AAED,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,yBAAyB,GAC9B,kBAAkB,CAuHpB"} \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/MultiplayerSession.js b/packages/engine-core/dist/game/net/MultiplayerSession.js index b5511e9..9012446 100644 --- a/packages/engine-core/dist/game/net/MultiplayerSession.js +++ b/packages/engine-core/dist/game/net/MultiplayerSession.js @@ -101,8 +101,14 @@ export function createMultiplayerSession(opts) { }); port.connect({ room, selfId: self.playerId }); rawSendPresence(); // anúnciate al entrar (inmediato, sin throttle) + // Heartbeat: mantiene la presence viva aunque el jugador esté inactivo. + // El receptor solo descartará al jugador si supera el stale threshold (p.ej. 10 min). + const heartbeatMs = opts.heartbeatMs ?? 30000; + const heartbeatTimer = heartbeatMs > 0 ? setInterval(rawSendPresence, heartbeatMs) : null; return { dispose: () => { + if (heartbeatTimer !== null) + clearInterval(heartbeatTimer); unsubs.forEach((u) => u()); offMsg(); offStatus(); diff --git a/packages/engine-core/dist/game/net/MultiplayerSession.js.map b/packages/engine-core/dist/game/net/MultiplayerSession.js.map index 7f9959d..7b40fe4 100644 --- a/packages/engine-core/dist/game/net/MultiplayerSession.js.map +++ b/packages/engine-core/dist/game/net/MultiplayerSession.js.map @@ -1 +1 @@ -{"version":3,"file":"MultiplayerSession.js","sourceRoot":"","sources":["../../../src/game/net/MultiplayerSession.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"MultiplayerSession.js","sourceRoot":"","sources":["../../../src/game/net/MultiplayerSession.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/engine-core/src/game/net/MultiplayerSession.ts b/packages/engine-core/src/game/net/MultiplayerSession.ts index be1142d..6806eee 100644 --- a/packages/engine-core/src/game/net/MultiplayerSession.ts +++ b/packages/engine-core/src/game/net/MultiplayerSession.ts @@ -29,6 +29,8 @@ export interface MultiplayerSessionOptions { clock?: ThrottleClock; /** Reconciliador optimista (task 09) para claim-result/snapshot. */ reconciler?: OptimisticReconciler; + /** ms entre heartbeats para jugadores inactivos. Default 30 000 (30 s). 0 = sin heartbeat. */ + heartbeatMs?: number; } export interface MultiplayerSession { @@ -139,8 +141,15 @@ export function createMultiplayerSession( port.connect({ room, selfId: self.playerId }); rawSendPresence(); // anúnciate al entrar (inmediato, sin throttle) + // Heartbeat: mantiene la presence viva aunque el jugador esté inactivo. + // El receptor solo descartará al jugador si supera el stale threshold (p.ej. 10 min). + const heartbeatMs = opts.heartbeatMs ?? 30_000; + const heartbeatTimer = + heartbeatMs > 0 ? setInterval(rawSendPresence, heartbeatMs) : null; + return { dispose: () => { + if (heartbeatTimer !== null) clearInterval(heartbeatTimer); unsubs.forEach((u) => u()); offMsg(); offStatus(); From aa8e5cc6f374c81dc64204d59bfd349d979263d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Mart=C3=ADnez=20Sebasti=C3=A1n?= Date: Wed, 10 Jun 2026 12:24:42 +0200 Subject: [PATCH 06/10] feat(multiplayer): add physics colliders to remote player sprites MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remote players now use a kinematicPosition RigidBody + CuboidCollider (same dimensions as the local player: 0.55×0.95×0.18) so the local player's dynamic body collides against them. Position is lerped each frame via setNextKinematicTranslation, keeping smooth movement while Rapier handles the collision response. Sprite Y offset (spriteScale-0.95) is now applied as a local mesh offset inside the RigidBody, consistent with how the local player sprite is positioned. Co-Authored-By: Claude Sonnet 4.6 --- .../dist/net/RemotePlayers.d.ts.map | 2 +- .../dist/net/RemotePlayers.js | 42 ++++++------- .../dist/net/RemotePlayers.js.map | 2 +- .../src/net/RemotePlayers.tsx | 63 +++++++++++-------- 4 files changed, 60 insertions(+), 49 deletions(-) diff --git a/packages/engine-renderer-r3f/dist/net/RemotePlayers.d.ts.map b/packages/engine-renderer-r3f/dist/net/RemotePlayers.d.ts.map index 456edd5..5976ec0 100644 --- a/packages/engine-renderer-r3f/dist/net/RemotePlayers.d.ts.map +++ b/packages/engine-renderer-r3f/dist/net/RemotePlayers.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"RemotePlayers.d.ts","sourceRoot":"","sources":["../../src/net/RemotePlayers.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAEV,kBAAkB,EACnB,MAAM,gCAAgC,CAAC;AAuExC,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,kBAAkB,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,sEAAsE;AACtE,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,kBAAkB,2CAU1E"} \ No newline at end of file +{"version":3,"file":"RemotePlayers.d.ts","sourceRoot":"","sources":["../../src/net/RemotePlayers.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAEV,kBAAkB,EACnB,MAAM,gCAAgC,CAAC;AAkFxC,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,kBAAkB,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,sEAAsE;AACtE,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,kBAAkB,2CAU1E"} \ No newline at end of file diff --git a/packages/engine-renderer-r3f/dist/net/RemotePlayers.js b/packages/engine-renderer-r3f/dist/net/RemotePlayers.js index 82c0358..5afb0d3 100644 --- a/packages/engine-renderer-r3f/dist/net/RemotePlayers.js +++ b/packages/engine-renderer-r3f/dist/net/RemotePlayers.js @@ -1,7 +1,8 @@ "use client"; -import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime"; +import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; import { useEffect, useReducer, useRef } from "react"; import { useFrame } from "@react-three/fiber"; +import { RigidBody, CuboidCollider } from "@react-three/rapier"; import { MathUtils, Vector3 } from "three"; import DavidSprite from "../sprite/DavidSprite"; import { GAME_CHARACTER_SPRITES } from "../sprite/clips"; @@ -17,40 +18,37 @@ function useRemotePlayers(store) { return store.getAll(); } function RemotePlayerSprite({ player }) { + const bodyRef = useRef(null); const meshRef = useRef(null); + // target = posición de física recibida por red (~12 Hz) const target = useRef(new Vector3(player.position[0], player.position[1], player.position[2])); - const initialized = useRef(false); - // Actualiza el objetivo cada render (presence llega throttled ~12Hz). + // smoothPos = posición interpolada que se aplica al body kinematic cada frame + const smoothPos = useRef(new Vector3(player.position[0], player.position[1], player.position[2])); + // Actualiza el objetivo cada render (presence llega throttled ~12 Hz). target.current.set(player.position[0], player.position[1], player.position[2]); const sprites = GAME_CHARACTER_SPRITES[player.characterId] ?? GAME_CHARACTER_SPRITES.Dave; const animation = sprites[player.action] ?? sprites.idle; useFrame((_, dt) => { + const body = bodyRef.current; const m = meshRef.current; - if (!m) + if (!body || !m) return; - // Escala por profundidad desde la posición OBJETIVO (igual que GameTouchSpriteRuntime). + // Lerp suave hacia la posición objetivo. + const t = Math.min(1, dt * 10); + smoothPos.current.x += (target.current.x - smoothPos.current.x) * t; + smoothPos.current.y += (target.current.y - smoothPos.current.y) * t; + smoothPos.current.z += (target.current.z - smoothPos.current.z) * t; + // Mueve el cuerpo kinematic — Rapier propaga la colisión con el player local. + body.setNextKinematicTranslation(smoothPos.current); + // Escala por profundidad (igual que GameTouchSpriteRuntime). const depthFactor = MathUtils.clamp((target.current.z - DEPTH_FAR_Z) / (DEPTH_NEAR_Z - DEPTH_FAR_Z), 0, 1); const s = MathUtils.lerp(SPRITE_MIN_SCALE, SPRITE_MAX_SCALE, depthFactor); - // El sprite local vive dentro de con offset Y = (spriteScale - 0.95) - // (ver GameTouchSpriteRuntime línea ~775: meshRef.current.position.y = spriteScale - 0.95). - // Replicamos ese offset para que el avatar remoto coincida visualmente con el local. - const tx = target.current.x; - const ty = target.current.y + s - 0.95; - const tz = target.current.z; - if (!initialized.current) { - m.position.set(tx, ty, tz); - initialized.current = true; - } - else { - const t = Math.min(1, dt * 10); - m.position.x += (tx - m.position.x) * t; - m.position.y += (ty - m.position.y) * t; - m.position.z += (tz - m.position.z) * t; - } + // Offset Y del sprite dentro del RigidBody: mismo que el player local. + m.position.y = s - 0.95; const flipX = animation.flipX ? -1 : 1; m.scale.set(flipX * s, s, 1); }); - return (_jsx(DavidSprite, { animation: animation, meshRef: meshRef, isPaused: player.action === "idle" })); + return (_jsxs(RigidBody, { ref: bodyRef, type: "kinematicPosition", colliders: false, position: [player.position[0], player.position[1], player.position[2]], enabledRotations: [false, false, false], children: [_jsx(CuboidCollider, { args: [0.55, 0.95, 0.18], friction: 0.05, restitution: 0 }), _jsx(DavidSprite, { animation: animation, meshRef: meshRef, isPaused: player.action === "idle" })] })); } /** Dibuja los avatares de los demás jugadores en la escena actual. */ export function RemotePlayers({ store, currentSceneId }) { diff --git a/packages/engine-renderer-r3f/dist/net/RemotePlayers.js.map b/packages/engine-renderer-r3f/dist/net/RemotePlayers.js.map index 419cb17..f36c34d 100644 --- a/packages/engine-renderer-r3f/dist/net/RemotePlayers.js.map +++ b/packages/engine-renderer-r3f/dist/net/RemotePlayers.js.map @@ -1 +1 @@ -{"version":3,"file":"RemotePlayers.js","sourceRoot":"","sources":["../../src/net/RemotePlayers.tsx"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"RemotePlayers.js","sourceRoot":"","sources":["../../src/net/RemotePlayers.tsx"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/engine-renderer-r3f/src/net/RemotePlayers.tsx b/packages/engine-renderer-r3f/src/net/RemotePlayers.tsx index 7d992c4..72b021c 100644 --- a/packages/engine-renderer-r3f/src/net/RemotePlayers.tsx +++ b/packages/engine-renderer-r3f/src/net/RemotePlayers.tsx @@ -1,6 +1,8 @@ "use client"; import { useEffect, useReducer, useRef } from "react"; import { useFrame } from "@react-three/fiber"; +import { RigidBody, CuboidCollider } from "@react-three/rapier"; +import type { RapierRigidBody } from "@react-three/rapier"; import { MathUtils, Vector3, type Mesh } from "three"; import DavidSprite from "../sprite/DavidSprite"; import { GAME_CHARACTER_SPRITES } from "../sprite/clips"; @@ -23,13 +25,19 @@ function useRemotePlayers(store: RemotePlayersStore): PlayerDescriptor[] { } function RemotePlayerSprite({ player }: { player: PlayerDescriptor }) { + const bodyRef = useRef(null); const meshRef = useRef(null); + + // target = posición de física recibida por red (~12 Hz) const target = useRef( new Vector3(player.position[0], player.position[1], player.position[2]), ); - const initialized = useRef(false); + // smoothPos = posición interpolada que se aplica al body kinematic cada frame + const smoothPos = useRef( + new Vector3(player.position[0], player.position[1], player.position[2]), + ); - // Actualiza el objetivo cada render (presence llega throttled ~12Hz). + // Actualiza el objetivo cada render (presence llega throttled ~12 Hz). target.current.set(player.position[0], player.position[1], player.position[2]); const sprites = @@ -37,10 +45,20 @@ function RemotePlayerSprite({ player }: { player: PlayerDescriptor }) { const animation = sprites[player.action] ?? sprites.idle; useFrame((_, dt) => { + const body = bodyRef.current; const m = meshRef.current; - if (!m) return; + if (!body || !m) return; - // Escala por profundidad desde la posición OBJETIVO (igual que GameTouchSpriteRuntime). + // Lerp suave hacia la posición objetivo. + const t = Math.min(1, dt * 10); + smoothPos.current.x += (target.current.x - smoothPos.current.x) * t; + smoothPos.current.y += (target.current.y - smoothPos.current.y) * t; + smoothPos.current.z += (target.current.z - smoothPos.current.z) * t; + + // Mueve el cuerpo kinematic — Rapier propaga la colisión con el player local. + body.setNextKinematicTranslation(smoothPos.current); + + // Escala por profundidad (igual que GameTouchSpriteRuntime). const depthFactor = MathUtils.clamp( (target.current.z - DEPTH_FAR_Z) / (DEPTH_NEAR_Z - DEPTH_FAR_Z), 0, @@ -48,33 +66,28 @@ function RemotePlayerSprite({ player }: { player: PlayerDescriptor }) { ); const s = MathUtils.lerp(SPRITE_MIN_SCALE, SPRITE_MAX_SCALE, depthFactor); - // El sprite local vive dentro de con offset Y = (spriteScale - 0.95) - // (ver GameTouchSpriteRuntime línea ~775: meshRef.current.position.y = spriteScale - 0.95). - // Replicamos ese offset para que el avatar remoto coincida visualmente con el local. - const tx = target.current.x; - const ty = target.current.y + s - 0.95; - const tz = target.current.z; - - if (!initialized.current) { - m.position.set(tx, ty, tz); - initialized.current = true; - } else { - const t = Math.min(1, dt * 10); - m.position.x += (tx - m.position.x) * t; - m.position.y += (ty - m.position.y) * t; - m.position.z += (tz - m.position.z) * t; - } + // Offset Y del sprite dentro del RigidBody: mismo que el player local. + m.position.y = s - 0.95; const flipX = animation.flipX ? -1 : 1; m.scale.set(flipX * s, s, 1); }); return ( - + + + + ); } From d9659775706ad95301eba1f275f105572c6cec54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Mart=C3=ADnez=20Sebasti=C3=A1n?= Date: Wed, 10 Jun 2026 13:06:30 +0200 Subject: [PATCH 07/10] fix(multiplayer): eliminate walk animation flicker when remote player blocks path The wall-slide detection (slideBlockX/Z) fires every other frame when a kinematic remote-player body is blocking the local player's movement axis. This alternated `horizontal` between 0 and the true value at 60 fps, causing resolveAction(0,0)="idle" on alternate frames and resetting the DavidSprite animation every ~16 ms. Fix: snapshot rawHorizontal/rawVertical before slide-zeroing and feed them to resolveAction for animation purposes. Physics still receives the zeroed velocity (correct collision response), but the animation keeps showing the intended walk direction until the player genuinely stops. Co-Authored-By: Claude Sonnet 4.6 --- .../dist/GameTouchSpriteRuntime.d.ts.map | 2 +- .../engine-renderer-r3f/dist/GameTouchSpriteRuntime.js | 9 ++++++++- .../dist/GameTouchSpriteRuntime.js.map | 2 +- .../engine-renderer-r3f/src/GameTouchSpriteRuntime.tsx | 10 +++++++++- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/packages/engine-renderer-r3f/dist/GameTouchSpriteRuntime.d.ts.map b/packages/engine-renderer-r3f/dist/GameTouchSpriteRuntime.d.ts.map index 9e023bd..de686c7 100644 --- a/packages/engine-renderer-r3f/dist/GameTouchSpriteRuntime.d.ts.map +++ b/packages/engine-renderer-r3f/dist/GameTouchSpriteRuntime.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"GameTouchSpriteRuntime.d.ts","sourceRoot":"","sources":["../src/GameTouchSpriteRuntime.tsx"],"names":[],"mappings":"AAUA,OAAO,EAGL,KAAK,iBAAiB,EAEvB,MAAM,gBAAgB,CAAC;AAOxB,OAAO,EAAmF,KAAK,mBAAmB,EAAE,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAwElM,wBAAgB,sBAAsB,CAAC,EACrC,eAAe,EACf,KAAK,EACL,eAAe,EACf,cAAc,EACd,kBAA0B,EAC1B,eAA6B,EAC7B,uBAA8B,EAC9B,YAAY,EACZ,oBAAoB,EACpB,UAAU,EACV,aAAa,EACb,aAAa,EACb,oBAAoB,EACpB,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,cAAc,EAEd,cAAsD,EACtD,eAAe,EACf,SAAoB,EACpB,iBAAwB,EACxB,YAAY,EACZ,kBAAkB,EAClB,kBAA0B,EAC1B,qBAAqB,GACtB,EAAE;IACD,eAAe,EAAE,iBAAiB,CAAC;IACnC,KAAK,EAAE,OAAO,CAAC;IACf,eAAe,EAAE,OAAO,CAAC;IACzB,cAAc,EAAE,OAAO,CAAC;IACxB,yEAAyE;IACzE,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,+EAA+E;IAC/E,eAAe,CAAC,EAAE,WAAW,GAAG,QAAQ,CAAC;IACzC;;;;OAIG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,YAAY,EAAE,YAAY,CAAC;IAC3B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,cAAc,CAAC,EAAE,mBAAmB,CAAC;IACrC;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACjE;;;OAGG;IACH,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;IAChD;;;;;OAKG;IACH,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,CACnB,OAAO,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,aAAa,KAC5C,IAAI,CAAC;IACV;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;;;;OAMG;IACH,qBAAqB,CAAC,EAAE,CACtB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,KACZ;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,GAAG,SAAS,CAAC;CAClD,2CA4qBA"} \ No newline at end of file +{"version":3,"file":"GameTouchSpriteRuntime.d.ts","sourceRoot":"","sources":["../src/GameTouchSpriteRuntime.tsx"],"names":[],"mappings":"AAUA,OAAO,EAGL,KAAK,iBAAiB,EAEvB,MAAM,gBAAgB,CAAC;AAOxB,OAAO,EAAmF,KAAK,mBAAmB,EAAE,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAwElM,wBAAgB,sBAAsB,CAAC,EACrC,eAAe,EACf,KAAK,EACL,eAAe,EACf,cAAc,EACd,kBAA0B,EAC1B,eAA6B,EAC7B,uBAA8B,EAC9B,YAAY,EACZ,oBAAoB,EACpB,UAAU,EACV,aAAa,EACb,aAAa,EACb,oBAAoB,EACpB,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,cAAc,EAEd,cAAsD,EACtD,eAAe,EACf,SAAoB,EACpB,iBAAwB,EACxB,YAAY,EACZ,kBAAkB,EAClB,kBAA0B,EAC1B,qBAAqB,GACtB,EAAE;IACD,eAAe,EAAE,iBAAiB,CAAC;IACnC,KAAK,EAAE,OAAO,CAAC;IACf,eAAe,EAAE,OAAO,CAAC;IACzB,cAAc,EAAE,OAAO,CAAC;IACxB,yEAAyE;IACzE,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,+EAA+E;IAC/E,eAAe,CAAC,EAAE,WAAW,GAAG,QAAQ,CAAC;IACzC;;;;OAIG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,YAAY,EAAE,YAAY,CAAC;IAC3B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,cAAc,CAAC,EAAE,mBAAmB,CAAC;IACrC;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACjE;;;OAGG;IACH,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;IAChD;;;;;OAKG;IACH,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,CACnB,OAAO,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,aAAa,KAC5C,IAAI,CAAC;IACV;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;;;;OAMG;IACH,qBAAqB,CAAC,EAAE,CACtB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,KACZ;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,GAAG,SAAS,CAAC;CAClD,2CAorBA"} \ No newline at end of file diff --git a/packages/engine-renderer-r3f/dist/GameTouchSpriteRuntime.js b/packages/engine-renderer-r3f/dist/GameTouchSpriteRuntime.js index cf557f6..e0ce3f5 100644 --- a/packages/engine-renderer-r3f/dist/GameTouchSpriteRuntime.js +++ b/packages/engine-renderer-r3f/dist/GameTouchSpriteRuntime.js @@ -448,6 +448,12 @@ getMobileInput = () => ({ active: false, x: 0, z: 0 }), addWallWithData, getPhra } horizontal = applyDeadzone(horizontal, MOVEMENT_INPUT_DEADZONE); vertical = applyDeadzone(vertical, MOVEMENT_INPUT_DEADZONE); + // Snapshot the intended direction BEFORE slide-zeroing so the animation + // keeps showing the walk direction even when a kinematic body (e.g. a + // remote player) is blocking the axis. Without this, slideBlockX zeroes + // `horizontal` → resolveAction(0,0) = "idle" every other frame → flicker. + const rawHorizontal = horizontal; + const rawVertical = vertical; // Apply wall-slide: if a collider blocked an axis last frame, do not push // into it again this frame. The perpendicular axis is kept intact so the // character slides along the surface. Only suppress when *trying* to move @@ -466,7 +472,8 @@ getMobileInput = () => ({ active: false, x: 0, z: 0 }), addWallWithData, getPhra nextAction = resolveAction(dx, dz); } else { - nextAction = resolveAction(horizontal, vertical); + // Use pre-zeroed direction so a blocked axis doesn't collapse to idle. + nextAction = resolveAction(rawHorizontal, rawVertical); } if (currentActionRef.current !== nextAction) { logRuntimeState("action-change", { diff --git a/packages/engine-renderer-r3f/dist/GameTouchSpriteRuntime.js.map b/packages/engine-renderer-r3f/dist/GameTouchSpriteRuntime.js.map index 19cdbb1..1f682e2 100644 --- a/packages/engine-renderer-r3f/dist/GameTouchSpriteRuntime.js.map +++ b/packages/engine-renderer-r3f/dist/GameTouchSpriteRuntime.js.map @@ -1 +1 @@ -{"version":3,"file":"GameTouchSpriteRuntime.js","sourceRoot":"","sources":["../src/GameTouchSpriteRuntime.tsx"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"GameTouchSpriteRuntime.js","sourceRoot":"","sources":["../src/GameTouchSpriteRuntime.tsx"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/engine-renderer-r3f/src/GameTouchSpriteRuntime.tsx b/packages/engine-renderer-r3f/src/GameTouchSpriteRuntime.tsx index f471855..462861c 100644 --- a/packages/engine-renderer-r3f/src/GameTouchSpriteRuntime.tsx +++ b/packages/engine-renderer-r3f/src/GameTouchSpriteRuntime.tsx @@ -646,6 +646,13 @@ export function GameTouchSpriteRuntime({ horizontal = applyDeadzone(horizontal, MOVEMENT_INPUT_DEADZONE); vertical = applyDeadzone(vertical, MOVEMENT_INPUT_DEADZONE); + // Snapshot the intended direction BEFORE slide-zeroing so the animation + // keeps showing the walk direction even when a kinematic body (e.g. a + // remote player) is blocking the axis. Without this, slideBlockX zeroes + // `horizontal` → resolveAction(0,0) = "idle" every other frame → flicker. + const rawHorizontal = horizontal; + const rawVertical = vertical; + // Apply wall-slide: if a collider blocked an axis last frame, do not push // into it again this frame. The perpendicular axis is kept intact so the // character slides along the surface. Only suppress when *trying* to move @@ -662,7 +669,8 @@ export function GameTouchSpriteRuntime({ const dz = targetPos[1] - currentPos[1]; nextAction = resolveAction(dx, dz); } else { - nextAction = resolveAction(horizontal, vertical); + // Use pre-zeroed direction so a blocked axis doesn't collapse to idle. + nextAction = resolveAction(rawHorizontal, rawVertical); } if (currentActionRef.current !== nextAction) { From 43410a22d83793f114b696c002590d2197c4f746 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Mart=C3=ADnez=20Sebasti=C3=A1n?= Date: Wed, 10 Jun 2026 13:17:59 +0200 Subject: [PATCH 08/10] fix(multiplayer): stop RigidBody teleporting remote player on each presence update Passing a dynamic `position` prop to caused @react-three/rapier to snap the kinematic body to the raw network position on every ~12 Hz presence re-render, overriding the smooth setNextKinematicTranslation lerp and producing visible stutter. Fix: freeze the `position` prop at mount via `spawnPosition` ref; all subsequent movement flows exclusively through setNextKinematicTranslation in useFrame. Also drive the depth-scale factor from smoothPos.current.z (was target.current.z) so sprite scale tracks the smooth path, not the 12 Hz raw position. Co-Authored-By: Claude Sonnet 4.6 --- .../engine-renderer-r3f/src/net/RemotePlayers.tsx | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/engine-renderer-r3f/src/net/RemotePlayers.tsx b/packages/engine-renderer-r3f/src/net/RemotePlayers.tsx index 72b021c..c10f553 100644 --- a/packages/engine-renderer-r3f/src/net/RemotePlayers.tsx +++ b/packages/engine-renderer-r3f/src/net/RemotePlayers.tsx @@ -28,6 +28,16 @@ function RemotePlayerSprite({ player }: { player: PlayerDescriptor }) { const bodyRef = useRef(null); const meshRef = useRef(null); + // Frozen at mount — only used as RigidBody's initial position prop. + // All subsequent movement goes through setNextKinematicTranslation in + // useFrame so that smooth interpolation is never overridden by a prop + // update (which would teleport the body to the raw network position). + const spawnPosition = useRef<[number, number, number]>([ + player.position[0], + player.position[1], + player.position[2], + ]); + // target = posición de física recibida por red (~12 Hz) const target = useRef( new Vector3(player.position[0], player.position[1], player.position[2]), @@ -60,7 +70,7 @@ function RemotePlayerSprite({ player }: { player: PlayerDescriptor }) { // Escala por profundidad (igual que GameTouchSpriteRuntime). const depthFactor = MathUtils.clamp( - (target.current.z - DEPTH_FAR_Z) / (DEPTH_NEAR_Z - DEPTH_FAR_Z), + (smoothPos.current.z - DEPTH_FAR_Z) / (DEPTH_NEAR_Z - DEPTH_FAR_Z), 0, 1, ); @@ -78,7 +88,7 @@ function RemotePlayerSprite({ player }: { player: PlayerDescriptor }) { ref={bodyRef} type="kinematicPosition" colliders={false} - position={[player.position[0], player.position[1], player.position[2]]} + position={spawnPosition.current} enabledRotations={[false, false, false]} > From 683cc21c38bd049e4a8f49d82810fa3afcd66ad8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Mart=C3=ADnez=20Sebasti=C3=A1n?= Date: Wed, 10 Jun 2026 13:28:12 +0200 Subject: [PATCH 09/10] fix(multiplayer): pin PartySocket id to our UUID to prevent ghost duplicate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without `id: opts.selfId`, PartySocket generates its own ID and the server echoes it back as status.selfId. MultiplayerSession then updates self.playerId to the server-assigned conn.id, so all subsequent presences use a different playerId than the initial one. Peers who stored the UUID-based initial presence see the new conn.id as a brand-new player — spawning a ghost avatar at the original spawn position and a real one following the actual movement. Passing `id: opts.selfId` pins the PartyKit party-key (_pk query param) so conn.id === our UUID throughout the session. status.selfId now matches our self.playerId, no ghost entry is created, and onClose correctly resolves the disconnected player by UUID. Co-Authored-By: Claude Sonnet 4.6 --- apps/web-demo/app/lib/net/partyKitAdapter.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/web-demo/app/lib/net/partyKitAdapter.ts b/apps/web-demo/app/lib/net/partyKitAdapter.ts index 0ac3f8d..b712a5f 100644 --- a/apps/web-demo/app/lib/net/partyKitAdapter.ts +++ b/apps/web-demo/app/lib/net/partyKitAdapter.ts @@ -15,7 +15,12 @@ export function createPartyKitAdapter(host: string): MultiplayerPort { return { connect(opts: ConnectOptions) { statusHandlers.forEach((h) => h({ state: "connecting" })); - socket = new PartySocket({ host, party: "multiplayer", room: opts.room }); + // Pass our stable UUID as the PartyKit party-key so conn.id on the + // server equals selfId. Without this, PartySocket generates its own ID, + // the server echoes it back as status.selfId, MultiplayerSession updates + // self.playerId to the new ID, and subsequent presences look like a + // second player to peers who already stored the initial UUID-based entry. + socket = new PartySocket({ host, party: "multiplayer", room: opts.room, id: opts.selfId }); socket.addEventListener("message", (e: MessageEvent) => { let env: { kind?: string; payload?: unknown }; try { From 4467361744fca2ec32f7c25c1e8f3e34fc59f110 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Mart=C3=ADnez=20Sebasti=C3=A1n?= Date: Wed, 10 Jun 2026 13:42:08 +0200 Subject: [PATCH 10/10] feat(multiplayer): sync placed items across clients in real-time + late join MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause: item:dropped only carried {itemId, outcome, interactionId}. Remote clients received the event but had no data to render the placed item, and placedItems lived in a local useState unreachable from the net layer. Changes: - item:dropped GameEvent now carries placedItem?: PlacedSceneItem (only for outcome "place") and promotes "pickup-success" to the outcome union. - RuntimeDropEvent carries the same placedItem field; legacyAdapter passes it through so the full item data reaches the event bus. - placedItems migrated from useState to usePlacedItemsStore (Zustand) so any addItem/removeItemById call — local or remote — triggers reactive re-render. Store gains addItem, removeItemByInteractionId, removeItemById actions. - applyRemoteEvent in createMultiplayerRuntime applies item:dropped to the store before emitting to the bus (no double-apply; server excludes sender). - MultiplayerSession accepts applySnapshot option; server now stores full placedItem in the world snapshot so late joiners hydrate placed items on connect. - Party server snapshot updated to persist {value, placedItem} for placed items and clears value on pickup/consume. Co-Authored-By: Claude Sonnet 4.6 --- .../runtime/useInventoryRuntimeController.ts | 78 ++++++------------- .../app/lib/net/createMultiplayerRuntime.ts | 30 ++++++- apps/web-demo/app/store/placedItemsStore.ts | 14 +++- apps/web-demo/party/multiplayer.ts | 23 +++++- .../dist/game/events/legacyAdapter.d.ts.map | 2 +- .../dist/game/events/legacyAdapter.js | 1 + .../dist/game/events/legacyAdapter.js.map | 2 +- .../engine-core/dist/game/events/types.d.ts | 6 +- .../dist/game/events/types.d.ts.map | 2 +- .../dist/game/net/MultiplayerSession.d.ts | 2 + .../dist/game/net/MultiplayerSession.d.ts.map | 2 +- .../dist/game/net/MultiplayerSession.js | 1 + .../dist/game/net/MultiplayerSession.js.map | 2 +- .../engine-core/dist/game/types/index.d.ts | 2 + .../dist/game/types/index.d.ts.map | 2 +- .../engine-core/dist/game/types/index.js.map | 2 +- .../src/game/events/legacyAdapter.ts | 3 +- packages/engine-core/src/game/events/types.ts | 6 +- .../src/game/net/MultiplayerSession.ts | 3 + packages/engine-core/src/game/types/index.ts | 2 + .../dist/net/RemotePlayers.d.ts.map | 2 +- .../dist/net/RemotePlayers.js | 13 +++- .../dist/net/RemotePlayers.js.map | 2 +- 23 files changed, 122 insertions(+), 80 deletions(-) diff --git a/apps/web-demo/app/lib/engine/runtime/useInventoryRuntimeController.ts b/apps/web-demo/app/lib/engine/runtime/useInventoryRuntimeController.ts index d1131e4..dc52858 100644 --- a/apps/web-demo/app/lib/engine/runtime/useInventoryRuntimeController.ts +++ b/apps/web-demo/app/lib/engine/runtime/useInventoryRuntimeController.ts @@ -122,10 +122,10 @@ export function useInventoryRuntimeController({ const [draggedStack, setDraggedStack] = useState( null, ); - const [placedItems, setPlacedItems] = useState([]); + // placedItems lives in the store so remote updates (via applyRemoteEvent) propagate reactively. + const placedItems = usePlacedItemsStore((s) => s.items); const pickupLockRef = useRef>(new Set()); const inventorySlotsRef = useRef(inventorySlots); - const setPlacedItemsInStore = usePlacedItemsStore((s) => s.setItems); // Keep ref in sync with current state (avoids stale closure in callbacks) useEffect(() => { @@ -150,39 +150,20 @@ export function useInventoryRuntimeController({ } }, [placedItems]); - // Manage placed items: maintain all items in state (persisted to store) + // Seed initial items for personalRoom once per device. useEffect(() => { - const { items: storedItems, initialItemsCreated } = usePlacedItemsStore.getState(); - - setPlacedItems((prev) => { - // Start with all stored items (already persisted in localStorage) - const allItems = storedItems.length > 0 ? storedItems : prev; - - // For personalRoom, create initial spawn items only once per session - // Only create if the item doesn't exist in ANY scene (not just this one) - if (sceneId === "personalRoom" && !initialItemsCreated) { - const trophyTakenOrMovedElsewhere = allItems.some((i) => i.itemId === "trophy"); - // Only recreate the trophy if it has never left this room - // If it exists anywhere, assume it was taken/moved by the player - if (!trophyTakenOrMovedElsewhere) { - return [...allItems, ...createInitialPlacedItems(sceneId)]; - } - } - - return allItems; - }); - - // Mark initial items as created AFTER setState + const { items, initialItemsCreated } = usePlacedItemsStore.getState(); if (sceneId === "personalRoom" && !initialItemsCreated) { + const trophyExists = items.some((i) => i.itemId === "trophy"); + if (!trophyExists) { + createInitialPlacedItems(sceneId).forEach((item) => + usePlacedItemsStore.getState().addItem(item), + ); + } usePlacedItemsStore.getState().markInitialItemsCreated(); } }, [sceneId]); - // Sync all placed items to localStorage via store - useEffect(() => { - setPlacedItemsInStore(placedItems); - }, [placedItems, setPlacedItemsInStore]); - const handleBoundaryHit = useCallback( (phrase: string) => { showDialog(phrase, "boundaryHit"); @@ -251,19 +232,18 @@ export function useInventoryRuntimeController({ } if (decision.kind === "place") { + const placedItemWithScene = { ...decision.placedItem, sceneId }; emitRuntimeEvent(onRuntimeEvent, { type: "onDrop", outcome: "place", itemId: payload.stack.id, interactionId: interaction.id, + placedItem: placedItemWithScene, }); setInventorySlots((currentSlots) => removeOneFromSlot(currentSlots, decision.fromSlotIndex), ); - setPlacedItems((currentPlaced) => [ - ...currentPlaced, - { ...decision.placedItem, sceneId }, // Add sceneId to track which scene this item belongs to - ]); + usePlacedItemsStore.getState().addItem(placedItemWithScene); showSpeechBubble(getRandomPhrase(decision.dialogKey), { dialogKey: decision.dialogKey, }); @@ -394,11 +374,7 @@ export function useInventoryRuntimeController({ setInventorySlots(inventoryResult.slots); // 2. Remove from placed items - setPlacedItems((currentPlaced) => - currentPlaced.filter( - (currentItem) => currentItem.id !== decision.placedItemId, - ), - ); + usePlacedItemsStore.getState().removeItemById(decision.placedItemId); emitRuntimeEvent(onRuntimeEvent, { type: "onDrop", @@ -413,14 +389,11 @@ export function useInventoryRuntimeController({ const updatePlacedItemPosition = useCallback( (id: string, axis: 0 | 1 | 2, value: number) => { - setPlacedItems((currentPlaced) => - currentPlaced.map((item) => { + const current = usePlacedItemsStore.getState().items; + usePlacedItemsStore.getState().setItems( + current.map((item) => { if (item.id !== id) return item; - const worldPosition = [...item.worldPosition] as [ - number, - number, - number, - ]; + const worldPosition = [...item.worldPosition] as [number, number, number]; worldPosition[axis] = value; return { ...item, worldPosition }; }), @@ -431,16 +404,13 @@ export function useInventoryRuntimeController({ const movePlacedItemToPlayer = useCallback( (id: string) => { - setPlacedItems((currentPlaced) => - currentPlaced.map((item) => { + const current = usePlacedItemsStore.getState().items; + usePlacedItemsStore.getState().setItems( + current.map((item) => { if (item.id !== id) return item; return { ...item, - worldPosition: [ - playerPosition[0], - item.worldPosition[1], - playerPosition[2], - ], + worldPosition: [playerPosition[0], item.worldPosition[1], playerPosition[2]], }; }), ); @@ -449,9 +419,7 @@ export function useInventoryRuntimeController({ ); const removePlacedItemById = useCallback((id: string) => { - setPlacedItems((currentPlaced) => - currentPlaced.filter((item) => item.id !== id), - ); + usePlacedItemsStore.getState().removeItemById(id); }, []); const handleStartInventoryDrag = useCallback( diff --git a/apps/web-demo/app/lib/net/createMultiplayerRuntime.ts b/apps/web-demo/app/lib/net/createMultiplayerRuntime.ts index 9ff092b..fed801f 100644 --- a/apps/web-demo/app/lib/net/createMultiplayerRuntime.ts +++ b/apps/web-demo/app/lib/net/createMultiplayerRuntime.ts @@ -5,8 +5,10 @@ import { createSelfDescriptor, getSceneState, type GameEvent, + type PlacedSceneItem, type RemotePlayersStore, } from "@pointclick-engine/engine-core"; +import { usePlacedItemsStore } from "../../store/placedItemsStore"; import { createPartyKitAdapter } from "./partyKitAdapter"; export interface MultiplayerRuntime { @@ -45,10 +47,30 @@ export function createMultiplayerRuntime(opts: { displayName: opts.displayName, }), remotePlayers, - // Re-emite el evento world remoto al bus local. La sesión activa `applyingRemote` - // mientras corre esto, así que NO se vuelve a difundir (anti-bucle). Los suscriptores - // del demo (audio, door… vía runtime.on) reaccionan al evento compartido. - applyRemoteEvent: (event: GameEvent) => runtime.emit(event), + // Apply remote world events: update shared stores THEN emit to the bus + // (audio, door logic, etc.). applyingRemote is already true here so the + // session won't re-broadcast what we emit (anti-loop guard). + applyRemoteEvent: (event: GameEvent) => { + if (event.type === "item:dropped") { + const store = usePlacedItemsStore.getState(); + if (event.outcome === "place" && event.placedItem) { + store.addItem(event.placedItem); + } else if (event.outcome === "pickup-success" && event.interactionId) { + store.removeItemByInteractionId(event.interactionId); + } + } + runtime.emit(event); + }, + applySnapshot: (world: Record) => { + const store = usePlacedItemsStore.getState(); + for (const [key, raw] of Object.entries(world)) { + if (!key.startsWith("item:") || !key.endsWith(":placed")) continue; + const entry = raw as { value: boolean; placedItem?: PlacedSceneItem }; + if (entry.value && entry.placedItem) { + store.addItem(entry.placedItem); + } + } + }, presenceThrottleMs: 80, }); diff --git a/apps/web-demo/app/store/placedItemsStore.ts b/apps/web-demo/app/store/placedItemsStore.ts index 401710d..e3d842a 100644 --- a/apps/web-demo/app/store/placedItemsStore.ts +++ b/apps/web-demo/app/store/placedItemsStore.ts @@ -5,6 +5,9 @@ import type { PlacedSceneItem } from "@pointclick-engine/engine-core"; type PlacedItemsStoreState = { items: PlacedSceneItem[]; setItems: (items: PlacedSceneItem[]) => void; + addItem: (item: PlacedSceneItem) => void; + removeItemByInteractionId: (interactionId: string) => void; + removeItemById: (id: string) => void; initialItemsCreated: boolean; markInitialItemsCreated: () => void; }; @@ -15,7 +18,16 @@ export const usePlacedItemsStore = create()( persist( (set) => ({ items: [], - setItems: (items: PlacedSceneItem[]) => set({ items }), + setItems: (items) => set({ items }), + addItem: (item) => + set((s) => { + if (s.items.some((i) => i.id === item.id)) return s; + return { items: [...s.items, item] }; + }), + removeItemByInteractionId: (interactionId) => + set((s) => ({ items: s.items.filter((i) => i.interactionId !== interactionId) })), + removeItemById: (id) => + set((s) => ({ items: s.items.filter((i) => i.id !== id) })), initialItemsCreated: false, markInitialItemsCreated: () => set({ initialItemsCreated: true }), }), diff --git a/apps/web-demo/party/multiplayer.ts b/apps/web-demo/party/multiplayer.ts index 492ebc4..692c42e 100644 --- a/apps/web-demo/party/multiplayer.ts +++ b/apps/web-demo/party/multiplayer.ts @@ -70,13 +70,28 @@ export default class MultiplayerServer implements Party.Server { ); } - /** Aplica un evento world al snapshot (item placed/removed). Simplificado. */ + /** Aplica un evento world al snapshot (item placed/removed). */ private applyWorldEvent(payload: unknown) { - const e = payload as { type?: string; itemId?: string; outcome?: string }; + const e = payload as { + type?: string; + itemId?: string; + outcome?: string; + interactionId?: string; + placedItem?: unknown; + }; if (e?.type === "item:dropped" && e.itemId) { const key = `item:${e.itemId}:placed`; - this.world[key] = { value: e.outcome === "place", ts: Date.now(), by: "server" }; + if (e.outcome === "place") { + // Store full item data so late joiners can reconstruct the scene. + this.world[key] = { + value: true, + placedItem: e.placedItem, + ts: Date.now(), + by: "server", + }; + } else { + this.world[key] = { value: false, ts: Date.now(), by: "server" }; + } } - // Extiende para puertas/interaction-state según las escenas de la demo. } } diff --git a/packages/engine-core/dist/game/events/legacyAdapter.d.ts.map b/packages/engine-core/dist/game/events/legacyAdapter.d.ts.map index cb85333..d384ff8 100644 --- a/packages/engine-core/dist/game/events/legacyAdapter.d.ts.map +++ b/packages/engine-core/dist/game/events/legacyAdapter.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"legacyAdapter.d.ts","sourceRoot":"","sources":["../../../src/game/events/legacyAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C;;;;GAIG;AACH,wBAAgB,6BAA6B,CAAC,EAAE,EAAE,YAAY,GAAG,SAAS,CAyBzE;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,CAAC,EAAE,EAAE,SAAS,GAAG,YAAY,GAAG,IAAI,CAuBhF"} \ No newline at end of file +{"version":3,"file":"legacyAdapter.d.ts","sourceRoot":"","sources":["../../../src/game/events/legacyAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C;;;;GAIG;AACH,wBAAgB,6BAA6B,CAAC,EAAE,EAAE,YAAY,GAAG,SAAS,CA0BzE;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,CAAC,EAAE,EAAE,SAAS,GAAG,YAAY,GAAG,IAAI,CAuBhF"} \ No newline at end of file diff --git a/packages/engine-core/dist/game/events/legacyAdapter.js b/packages/engine-core/dist/game/events/legacyAdapter.js index f6ac1e6..9845bff 100644 --- a/packages/engine-core/dist/game/events/legacyAdapter.js +++ b/packages/engine-core/dist/game/events/legacyAdapter.js @@ -19,6 +19,7 @@ export function legacyRuntimeEventToGameEvent(ev) { itemId: ev.itemId, outcome: ev.outcome, interactionId: ev.interactionId, + ...(ev.placedItem ? { placedItem: ev.placedItem } : {}), }; case "onDialog": return { diff --git a/packages/engine-core/dist/game/events/legacyAdapter.js.map b/packages/engine-core/dist/game/events/legacyAdapter.js.map index 1a76f12..db49dc2 100644 --- a/packages/engine-core/dist/game/events/legacyAdapter.js.map +++ b/packages/engine-core/dist/game/events/legacyAdapter.js.map @@ -1 +1 @@ -{"version":3,"file":"legacyAdapter.js","sourceRoot":"","sources":["../../../src/game/events/legacyAdapter.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,MAAM,UAAU,6BAA6B,CAAC,EAAgB;IAC5D,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC;QAChB,KAAK,QAAQ;YACX,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC;QAC5E,KAAK,WAAW;YACd,OAAO;gBACL,IAAI,EAAE,iBAAiB;gBACvB,MAAM,EAAE,EAAE,CAAC,MAAM;gBACjB,QAAQ,EAAE,EAAE,CAAC,QAAQ;aACtB,CAAC;QACJ,KAAK,QAAQ;YACX,OAAO;gBACL,IAAI,EAAE,cAAc;gBACpB,MAAM,EAAE,EAAE,CAAC,MAAM;gBACjB,OAAO,EAAE,EAAE,CAAC,OAAyC;gBACrD,aAAa,EAAE,EAAE,CAAC,aAAa;aAChC,CAAC;QACJ,KAAK,UAAU;YACb,OAAO;gBACL,IAAI,EAAE,kBAAkB;gBACxB,IAAI,EAAE,EAAE,CAAC,IAAI;gBACb,SAAS,EAAE,EAAE,CAAC,SAAS;gBACvB,MAAM,EAAE,EAAE,CAAC,MAAM;aAClB,CAAC;IACN,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,6BAA6B,CAAC,EAAa;IACzD,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC;QAChB,KAAK,cAAc;YACjB,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC;QACtE,KAAK,iBAAiB;YACpB,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE,CAAC;QACzE,KAAK,cAAc;YACjB,OAAO;gBACL,IAAI,EAAE,QAAQ;gBACd,MAAM,EAAE,EAAE,CAAC,MAAM;gBACjB,OAAO,EAAE,EAAE,CAAC,OAAO;gBACnB,aAAa,EAAE,EAAE,CAAC,aAAa;aAChC,CAAC;QACJ,KAAK,kBAAkB;YACrB,OAAO;gBACL,IAAI,EAAE,UAAU;gBAChB,IAAI,EAAE,EAAE,CAAC,IAAI;gBACb,SAAS,EAAE,EAAE,CAAC,SAAS;gBACvB,MAAM,EAAE,EAAE,CAAC,MAA4C;aACxD,CAAC;QACJ;YACE,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC"} \ No newline at end of file +{"version":3,"file":"legacyAdapter.js","sourceRoot":"","sources":["../../../src/game/events/legacyAdapter.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,MAAM,UAAU,6BAA6B,CAAC,EAAgB;IAC5D,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC;QAChB,KAAK,QAAQ;YACX,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC;QAC5E,KAAK,WAAW;YACd,OAAO;gBACL,IAAI,EAAE,iBAAiB;gBACvB,MAAM,EAAE,EAAE,CAAC,MAAM;gBACjB,QAAQ,EAAE,EAAE,CAAC,QAAQ;aACtB,CAAC;QACJ,KAAK,QAAQ;YACX,OAAO;gBACL,IAAI,EAAE,cAAc;gBACpB,MAAM,EAAE,EAAE,CAAC,MAAM;gBACjB,OAAO,EAAE,EAAE,CAAC,OAA4D;gBACxE,aAAa,EAAE,EAAE,CAAC,aAAa;gBAC/B,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,EAAE,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACxD,CAAC;QACJ,KAAK,UAAU;YACb,OAAO;gBACL,IAAI,EAAE,kBAAkB;gBACxB,IAAI,EAAE,EAAE,CAAC,IAAI;gBACb,SAAS,EAAE,EAAE,CAAC,SAAS;gBACvB,MAAM,EAAE,EAAE,CAAC,MAAM;aAClB,CAAC;IACN,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,6BAA6B,CAAC,EAAa;IACzD,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC;QAChB,KAAK,cAAc;YACjB,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC;QACtE,KAAK,iBAAiB;YACpB,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE,CAAC;QACzE,KAAK,cAAc;YACjB,OAAO;gBACL,IAAI,EAAE,QAAQ;gBACd,MAAM,EAAE,EAAE,CAAC,MAAM;gBACjB,OAAO,EAAE,EAAE,CAAC,OAAO;gBACnB,aAAa,EAAE,EAAE,CAAC,aAAa;aAChC,CAAC;QACJ,KAAK,kBAAkB;YACrB,OAAO;gBACL,IAAI,EAAE,UAAU;gBAChB,IAAI,EAAE,EAAE,CAAC,IAAI;gBACb,SAAS,EAAE,EAAE,CAAC,SAAS;gBACvB,MAAM,EAAE,EAAE,CAAC,MAA4C;aACxD,CAAC;QACJ;YACE,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC"} \ No newline at end of file diff --git a/packages/engine-core/dist/game/events/types.d.ts b/packages/engine-core/dist/game/events/types.d.ts index 9758c78..4f2d6a4 100644 --- a/packages/engine-core/dist/game/events/types.d.ts +++ b/packages/engine-core/dist/game/events/types.d.ts @@ -1,4 +1,4 @@ -import type { AudioSettings, GameScene, GameVec3, Locale, SoundCategory } from "../types"; +import type { AudioSettings, GameScene, GameVec3, Locale, PlacedSceneItem, SoundCategory } from "../types"; import type { PlayerDescriptor } from "../net/playerIdentity"; import type { ConnectionStatus, PlayerId } from "../../ports/multiplayer"; /** @@ -27,8 +27,10 @@ export type GameEvent = { } | { type: "item:dropped"; itemId: string; - outcome: "consume" | "place" | "return"; + outcome: "consume" | "place" | "return" | "pickup-success"; interactionId?: string; + /** Full placed-item data; present only for outcome "place" — used by peers to add the item to their scene. */ + placedItem?: PlacedSceneItem; } | { type: "dialog:triggered"; text: string; diff --git a/packages/engine-core/dist/game/events/types.d.ts.map b/packages/engine-core/dist/game/events/types.d.ts.map index 4dcac31..7b057fa 100644 --- a/packages/engine-core/dist/game/events/types.d.ts.map +++ b/packages/engine-core/dist/game/events/types.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/game/events/types.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/game/events/types.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/MultiplayerSession.d.ts b/packages/engine-core/dist/game/net/MultiplayerSession.d.ts index 9dc85a3..1da5807 100644 --- a/packages/engine-core/dist/game/net/MultiplayerSession.d.ts +++ b/packages/engine-core/dist/game/net/MultiplayerSession.d.ts @@ -25,6 +25,8 @@ export interface MultiplayerSessionOptions { clock?: ThrottleClock; /** Reconciliador optimista (task 09) para claim-result/snapshot. */ reconciler?: OptimisticReconciler; + /** Called once on join with the server's world snapshot so late joiners can hydrate shared state. */ + applySnapshot?: (world: Record) => void; /** ms entre heartbeats para jugadores inactivos. Default 30 000 (30 s). 0 = sin heartbeat. */ heartbeatMs?: number; } diff --git a/packages/engine-core/dist/game/net/MultiplayerSession.d.ts.map b/packages/engine-core/dist/game/net/MultiplayerSession.d.ts.map index 2aa0de4..fec8e28 100644 --- a/packages/engine-core/dist/game/net/MultiplayerSession.d.ts.map +++ b/packages/engine-core/dist/game/net/MultiplayerSession.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"MultiplayerSession.d.ts","sourceRoot":"","sources":["../../../src/game/net/MultiplayerSession.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAe,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEpF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE/D,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAClE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEzD,oFAAoF;AACpF,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,CAAC,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,SAAS,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;IACzE,IAAI,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;CAClC;AAED,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,eAAe,CAAC;IACtB,GAAG,EAAE,UAAU,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,gBAAgB,CAAC;IACvB,aAAa,EAAE,kBAAkB,CAAC;IAClC,sFAAsF;IACtF,gBAAgB,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;IAC7C,6EAA6E;IAC7E,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,4EAA4E;IAC5E,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,8DAA8D;IAC9D,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,oEAAoE;IACpE,UAAU,CAAC,EAAE,oBAAoB,CAAC;IAClC,8FAA8F;IAC9F,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,gBAAgB,CAAC;IAChC,oFAAoF;IACpF,UAAU,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;CACxD;AAED,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,yBAAyB,GAC9B,kBAAkB,CAuHpB"} \ No newline at end of file +{"version":3,"file":"MultiplayerSession.d.ts","sourceRoot":"","sources":["../../../src/game/net/MultiplayerSession.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAe,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEpF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE/D,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAClE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEzD,oFAAoF;AACpF,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,CAAC,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,SAAS,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;IACzE,IAAI,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;CAClC;AAED,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,eAAe,CAAC;IACtB,GAAG,EAAE,UAAU,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,gBAAgB,CAAC;IACvB,aAAa,EAAE,kBAAkB,CAAC;IAClC,sFAAsF;IACtF,gBAAgB,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;IAC7C,6EAA6E;IAC7E,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,4EAA4E;IAC5E,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,8DAA8D;IAC9D,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,oEAAoE;IACpE,UAAU,CAAC,EAAE,oBAAoB,CAAC;IAClC,qGAAqG;IACrG,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IACzD,8FAA8F;IAC9F,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,gBAAgB,CAAC;IAChC,oFAAoF;IACpF,UAAU,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;CACxD;AAED,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,yBAAyB,GAC9B,kBAAkB,CAwHpB"} \ No newline at end of file diff --git a/packages/engine-core/dist/game/net/MultiplayerSession.js b/packages/engine-core/dist/game/net/MultiplayerSession.js index 9012446..3c229b4 100644 --- a/packages/engine-core/dist/game/net/MultiplayerSession.js +++ b/packages/engine-core/dist/game/net/MultiplayerSession.js @@ -91,6 +91,7 @@ export function createMultiplayerSession(opts) { } else if (m.kind === "snapshot") { opts.reconciler?.onSnapshot(); + opts.applySnapshot?.(m.payload); } }); const offStatus = port.onStatus((status) => { diff --git a/packages/engine-core/dist/game/net/MultiplayerSession.js.map b/packages/engine-core/dist/game/net/MultiplayerSession.js.map index 7b40fe4..e490124 100644 --- a/packages/engine-core/dist/game/net/MultiplayerSession.js.map +++ b/packages/engine-core/dist/game/net/MultiplayerSession.js.map @@ -1 +1 @@ -{"version":3,"file":"MultiplayerSession.js","sourceRoot":"","sources":["../../../src/game/net/MultiplayerSession.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAG/D,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACvF,OAAO,EAAE,gBAAgB,EAAsB,MAAM,YAAY,CAAC;AAoClE,MAAM,UAAU,wBAAwB,CACtC,IAA+B;IAE/B,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,aAAa,EAAE,gBAAgB,EAAE,GAAG,IAAI,CAAC;IAClE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAC3C,IAAI,IAAI,GAAG,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,cAAc,GAAG,KAAK,CAAC,CAAC,sDAAsD;IAElF,MAAM,IAAI,GAAG,CAAC,IAAyB,EAAE,OAAgB,EAAe,EAAE,CAAC,CAAC;QAC1E,CAAC,EAAE,oBAAoB;QACvB,IAAI;QACJ,IAAI,EAAE,IAAI,CAAC,QAAQ;QACnB,EAAE,EAAE,GAAG,EAAE;QACT,IAAI;QACJ,OAAO;KACR,CAAC,CAAC;IAEH,MAAM,eAAe,GAAG,GAAG,EAAE;QAC3B,IAAI,GAAG,EAAE,GAAG,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,EAAE,CAAC;QACtC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC;IACpC,CAAC,CAAC;IAEF,MAAM,KAAK,GAAkB,IAAI,CAAC,KAAK,IAAI;QACzC,GAAG,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;QACrB,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE;YAClB,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QACpB,CAAC;KACF,CAAC;IACF,MAAM,UAAU,GAAG,IAAI,CAAC,kBAAkB,IAAI,EAAE,CAAC;IACjD,MAAM,YAAY,GAChB,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,eAAe,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC;IAE1F,+EAA+E;IAC/E,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAoB,CAAC;IACnE,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAChC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE;QACrB,IAAI,cAAc;YAAE,OAAO,CAAC,0CAA0C;QACtE,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC;YAAE,OAAO,CAAC,uBAAuB;QAC3D,IAAI,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YAClB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;QAClC,CAAC;QACD,IAAI,IAAI,KAAK,cAAc,EAAE,CAAC;YAC5B,MAAM,CAAC,GAAG,KAAqD,CAAC;YAChE,IAAI,GAAG,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;YAC3D,YAAY,EAAE,CAAC;QACjB,CAAC;aAAM,IAAI,IAAI,KAAK,eAAe,EAAE,CAAC;YACpC,IAAI,GAAG;gBACL,GAAG,IAAI;gBACP,OAAO,EAAG,KAAuD,CAAC,OAAO;aAC1E,CAAC;YACF,YAAY,EAAE,CAAC;QACjB,CAAC;aAAM,IAAI,IAAI,KAAK,sBAAsB,EAAE,CAAC;YAC3C,IAAI,GAAG;gBACL,GAAG,IAAI;gBACP,OAAO,EAAG,KAA8D;qBACrE,SAAS;aACb,CAAC;YACF,YAAY,EAAE,CAAC;QACjB,CAAC;IACH,CAAC,CAAC,CACH,CAAC;IAEF,+EAA+E;IAC/E,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE;QAClC,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,QAAQ;YAAE,OAAO,CAAC,sCAAsC;QAC5E,IAAI,CAAC,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC1B,MAAM,CAAC,GAAG,CAAC,CAAC,OAAkD,CAAC;YAC/D,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;gBACb,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;gBACjC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;gBAC3D,OAAO;YACT,CAAC;YACD,MAAM,KAAK,GAAG,aAAa,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC;YAC7E,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YACxB,IAAI,KAAK;gBAAE,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;QAC/D,CAAC;aAAM,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAC9B,cAAc,GAAG,IAAI,CAAC;YACtB,IAAI,CAAC;gBACH,gBAAgB,CAAC,CAAC,CAAC,OAAoB,CAAC,CAAC;YAC3C,CAAC;oBAAS,CAAC;gBACT,cAAc,GAAG,KAAK,CAAC;YACzB,CAAC;QACH,CAAC;aAAM,IAAI,CAAC,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;YACrC,MAAM,CAAC,GAAG,CAAC,CAAC,OAAiD,CAAC;YAC9D,IAAI,CAAC,CAAC,OAAO;gBAAE,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;;gBAC/C,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QAC3C,CAAC;aAAM,IAAI,CAAC,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YACjC,IAAI,CAAC,UAAU,EAAE,UAAU,EAAE,CAAC;QAChC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,EAAE;QACzC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,CAAC;QACzC,IAAI,MAAM,CAAC,KAAK,KAAK,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAClD,IAAI,GAAG,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;QAC9C,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC9C,eAAe,EAAE,CAAC,CAAC,gDAAgD;IAEnE,wEAAwE;IACxE,sFAAsF;IACtF,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,KAAM,CAAC;IAC/C,MAAM,cAAc,GAClB,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,eAAe,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAErE,OAAO;QACL,OAAO,EAAE,GAAG,EAAE;YACZ,IAAI,cAAc,KAAK,IAAI;gBAAE,aAAa,CAAC,cAAc,CAAC,CAAC;YAC3D,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;YAC3B,MAAM,EAAE,CAAC;YACT,SAAS,EAAE,CAAC;YACZ,IAAI,CAAC,UAAU,EAAE,CAAC;QACpB,CAAC;QACD,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI;QACnB,UAAU,EAAE,CAAC,KAAK,EAAE,EAAE;YACpB,IAAI,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,EAAE,CAAC;YAC7B,YAAY,EAAE,CAAC;QACjB,CAAC;KACF,CAAC;AACJ,CAAC"} \ No newline at end of file +{"version":3,"file":"MultiplayerSession.js","sourceRoot":"","sources":["../../../src/game/net/MultiplayerSession.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/engine-core/dist/game/types/index.d.ts b/packages/engine-core/dist/game/types/index.d.ts index 13753e6..2bb00f3 100644 --- a/packages/engine-core/dist/game/types/index.d.ts +++ b/packages/engine-core/dist/game/types/index.d.ts @@ -228,6 +228,8 @@ export type RuntimeDropEvent = { outcome: "place" | "consume" | "return" | "rule-miss" | "unknown-item" | "on-player" | "pickup-blocked" | "pickup-success" | "item-interact"; itemId: string; interactionId?: string; + /** Full placed-item data; set for outcome "place" so the event bus carries enough info for remote clients. */ + placedItem?: PlacedSceneItem; }; export type RuntimeDialogEvent = { type: "onDialog"; diff --git a/packages/engine-core/dist/game/types/index.d.ts.map b/packages/engine-core/dist/game/types/index.d.ts.map index 412ed09..42dae5c 100644 --- a/packages/engine-core/dist/game/types/index.d.ts.map +++ b/packages/engine-core/dist/game/types/index.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/game/types/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/game/types/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/engine-core/dist/game/types/index.js.map b/packages/engine-core/dist/game/types/index.js.map index 2b6c014..763fedd 100644 --- a/packages/engine-core/dist/game/types/index.js.map +++ b/packages/engine-core/dist/game/types/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/game/types/index.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,iCAAiC;AAwQjC,MAAM,CAAC,MAAM,sBAAsB,GAAkB;IACnD,WAAW,EAAE,KAAK;IAClB,UAAU,EAAE,KAAK;IACjB,QAAQ,EAAE,KAAK;IACf,YAAY,EAAE,GAAG;IACjB,WAAW,EAAE,GAAG;IAChB,SAAS,EAAE,GAAG;CACf,CAAC;AAqFF,6FAA6F;AAC7F,MAAM,CAAC,MAAM,mBAAmB,GAAe;IAC7C,aAAa,EAAE,IAAI;IACnB,cAAc,EAAE,IAAI;IACpB,gBAAgB,EAAE,CAAC,IAAI,CAAC;CACzB,CAAC"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/game/types/index.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,iCAAiC;AAwQjC,MAAM,CAAC,MAAM,sBAAsB,GAAkB;IACnD,WAAW,EAAE,KAAK;IAClB,UAAU,EAAE,KAAK;IACjB,QAAQ,EAAE,KAAK;IACf,YAAY,EAAE,GAAG;IACjB,WAAW,EAAE,GAAG;IAChB,SAAS,EAAE,GAAG;CACf,CAAC;AAuFF,6FAA6F;AAC7F,MAAM,CAAC,MAAM,mBAAmB,GAAe;IAC7C,aAAa,EAAE,IAAI;IACnB,cAAc,EAAE,IAAI;IACpB,gBAAgB,EAAE,CAAC,IAAI,CAAC;CACzB,CAAC"} \ No newline at end of file diff --git a/packages/engine-core/src/game/events/legacyAdapter.ts b/packages/engine-core/src/game/events/legacyAdapter.ts index ef8f1ed..15925dd 100644 --- a/packages/engine-core/src/game/events/legacyAdapter.ts +++ b/packages/engine-core/src/game/events/legacyAdapter.ts @@ -20,8 +20,9 @@ export function legacyRuntimeEventToGameEvent(ev: RuntimeEvent): GameEvent { return { type: "item:dropped", itemId: ev.itemId, - outcome: ev.outcome as "consume" | "place" | "return", + outcome: ev.outcome as "consume" | "place" | "return" | "pickup-success", interactionId: ev.interactionId, + ...(ev.placedItem ? { placedItem: ev.placedItem } : {}), }; case "onDialog": return { diff --git a/packages/engine-core/src/game/events/types.ts b/packages/engine-core/src/game/events/types.ts index 37aedbd..b441841 100644 --- a/packages/engine-core/src/game/events/types.ts +++ b/packages/engine-core/src/game/events/types.ts @@ -1,4 +1,4 @@ -import type { AudioSettings, GameScene, GameVec3, Locale, SoundCategory } from "../types"; +import type { AudioSettings, GameScene, GameVec3, Locale, PlacedSceneItem, SoundCategory } from "../types"; import type { PlayerDescriptor } from "../net/playerIdentity"; import type { ConnectionStatus, PlayerId } from "../../ports/multiplayer"; @@ -22,8 +22,10 @@ export type GameEvent = | { type: "item:dropped"; itemId: string; - outcome: "consume" | "place" | "return"; + outcome: "consume" | "place" | "return" | "pickup-success"; interactionId?: string; + /** Full placed-item data; present only for outcome "place" — used by peers to add the item to their scene. */ + placedItem?: PlacedSceneItem; } // Dialog | { type: "dialog:triggered"; text: string; dialogKey?: string; source: string } diff --git a/packages/engine-core/src/game/net/MultiplayerSession.ts b/packages/engine-core/src/game/net/MultiplayerSession.ts index 6806eee..3983cf1 100644 --- a/packages/engine-core/src/game/net/MultiplayerSession.ts +++ b/packages/engine-core/src/game/net/MultiplayerSession.ts @@ -29,6 +29,8 @@ export interface MultiplayerSessionOptions { clock?: ThrottleClock; /** Reconciliador optimista (task 09) para claim-result/snapshot. */ reconciler?: OptimisticReconciler; + /** Called once on join with the server's world snapshot so late joiners can hydrate shared state. */ + applySnapshot?: (world: Record) => void; /** ms entre heartbeats para jugadores inactivos. Default 30 000 (30 s). 0 = sin heartbeat. */ heartbeatMs?: number; } @@ -128,6 +130,7 @@ export function createMultiplayerSession( else opts.reconciler?.reject(r.entityId); } else if (m.kind === "snapshot") { opts.reconciler?.onSnapshot(); + opts.applySnapshot?.(m.payload as Record); } }); diff --git a/packages/engine-core/src/game/types/index.ts b/packages/engine-core/src/game/types/index.ts index 50c5861..ee48a95 100644 --- a/packages/engine-core/src/game/types/index.ts +++ b/packages/engine-core/src/game/types/index.ts @@ -299,6 +299,8 @@ export type RuntimeDropEvent = { | "item-interact"; itemId: string; interactionId?: string; + /** Full placed-item data; set for outcome "place" so the event bus carries enough info for remote clients. */ + placedItem?: PlacedSceneItem; }; export type RuntimeDialogEvent = { diff --git a/packages/engine-renderer-r3f/dist/net/RemotePlayers.d.ts.map b/packages/engine-renderer-r3f/dist/net/RemotePlayers.d.ts.map index 5976ec0..c1878b1 100644 --- a/packages/engine-renderer-r3f/dist/net/RemotePlayers.d.ts.map +++ b/packages/engine-renderer-r3f/dist/net/RemotePlayers.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"RemotePlayers.d.ts","sourceRoot":"","sources":["../../src/net/RemotePlayers.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAEV,kBAAkB,EACnB,MAAM,gCAAgC,CAAC;AAkFxC,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,kBAAkB,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,sEAAsE;AACtE,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,kBAAkB,2CAU1E"} \ No newline at end of file +{"version":3,"file":"RemotePlayers.d.ts","sourceRoot":"","sources":["../../src/net/RemotePlayers.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAEV,kBAAkB,EACnB,MAAM,gCAAgC,CAAC;AA4FxC,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,kBAAkB,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,sEAAsE;AACtE,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,kBAAkB,2CAU1E"} \ No newline at end of file diff --git a/packages/engine-renderer-r3f/dist/net/RemotePlayers.js b/packages/engine-renderer-r3f/dist/net/RemotePlayers.js index 5afb0d3..6e41b7f 100644 --- a/packages/engine-renderer-r3f/dist/net/RemotePlayers.js +++ b/packages/engine-renderer-r3f/dist/net/RemotePlayers.js @@ -20,6 +20,15 @@ function useRemotePlayers(store) { function RemotePlayerSprite({ player }) { const bodyRef = useRef(null); const meshRef = useRef(null); + // Frozen at mount — only used as RigidBody's initial position prop. + // All subsequent movement goes through setNextKinematicTranslation in + // useFrame so that smooth interpolation is never overridden by a prop + // update (which would teleport the body to the raw network position). + const spawnPosition = useRef([ + player.position[0], + player.position[1], + player.position[2], + ]); // target = posición de física recibida por red (~12 Hz) const target = useRef(new Vector3(player.position[0], player.position[1], player.position[2])); // smoothPos = posición interpolada que se aplica al body kinematic cada frame @@ -41,14 +50,14 @@ function RemotePlayerSprite({ player }) { // Mueve el cuerpo kinematic — Rapier propaga la colisión con el player local. body.setNextKinematicTranslation(smoothPos.current); // Escala por profundidad (igual que GameTouchSpriteRuntime). - const depthFactor = MathUtils.clamp((target.current.z - DEPTH_FAR_Z) / (DEPTH_NEAR_Z - DEPTH_FAR_Z), 0, 1); + const depthFactor = MathUtils.clamp((smoothPos.current.z - DEPTH_FAR_Z) / (DEPTH_NEAR_Z - DEPTH_FAR_Z), 0, 1); const s = MathUtils.lerp(SPRITE_MIN_SCALE, SPRITE_MAX_SCALE, depthFactor); // Offset Y del sprite dentro del RigidBody: mismo que el player local. m.position.y = s - 0.95; const flipX = animation.flipX ? -1 : 1; m.scale.set(flipX * s, s, 1); }); - return (_jsxs(RigidBody, { ref: bodyRef, type: "kinematicPosition", colliders: false, position: [player.position[0], player.position[1], player.position[2]], enabledRotations: [false, false, false], children: [_jsx(CuboidCollider, { args: [0.55, 0.95, 0.18], friction: 0.05, restitution: 0 }), _jsx(DavidSprite, { animation: animation, meshRef: meshRef, isPaused: player.action === "idle" })] })); + return (_jsxs(RigidBody, { ref: bodyRef, type: "kinematicPosition", colliders: false, position: spawnPosition.current, enabledRotations: [false, false, false], children: [_jsx(CuboidCollider, { args: [0.55, 0.95, 0.18], friction: 0.05, restitution: 0 }), _jsx(DavidSprite, { animation: animation, meshRef: meshRef, isPaused: player.action === "idle" })] })); } /** Dibuja los avatares de los demás jugadores en la escena actual. */ export function RemotePlayers({ store, currentSceneId }) { diff --git a/packages/engine-renderer-r3f/dist/net/RemotePlayers.js.map b/packages/engine-renderer-r3f/dist/net/RemotePlayers.js.map index f36c34d..3598cfb 100644 --- a/packages/engine-renderer-r3f/dist/net/RemotePlayers.js.map +++ b/packages/engine-renderer-r3f/dist/net/RemotePlayers.js.map @@ -1 +1 @@ -{"version":3,"file":"RemotePlayers.js","sourceRoot":"","sources":["../../src/net/RemotePlayers.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AACb,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAEhE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAa,MAAM,OAAO,CAAC;AACtD,OAAO,WAAW,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAMzD,6FAA6F;AAC7F,MAAM,WAAW,GAAG,CAAC,EAAE,CAAC;AACxB,MAAM,YAAY,GAAG,CAAC,CAAC;AACvB,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAC7B,MAAM,gBAAgB,GAAG,IAAI,CAAC;AAE9B,sDAAsD;AACtD,SAAS,gBAAgB,CAAC,KAAyB;IACjD,MAAM,CAAC,EAAE,KAAK,CAAC,GAAG,UAAU,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IACtD,SAAS,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IACzD,OAAO,KAAK,CAAC,MAAM,EAAE,CAAC;AACxB,CAAC;AAED,SAAS,kBAAkB,CAAC,EAAE,MAAM,EAAgC;IAClE,MAAM,OAAO,GAAG,MAAM,CAAkB,IAAI,CAAC,CAAC;IAC9C,MAAM,OAAO,GAAG,MAAM,CAAO,IAAI,CAAC,CAAC;IAEnC,wDAAwD;IACxD,MAAM,MAAM,GAAG,MAAM,CACnB,IAAI,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CACxE,CAAC;IACF,8EAA8E;IAC9E,MAAM,SAAS,GAAG,MAAM,CACtB,IAAI,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CACxE,CAAC;IAEF,uEAAuE;IACvE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAE/E,MAAM,OAAO,GACX,sBAAsB,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,sBAAsB,CAAC,IAAI,CAAC;IAC5E,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC;IAEzD,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE;QACjB,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC;QAC7B,MAAM,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;QAC1B,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC;YAAE,OAAO;QAExB,yCAAyC;QACzC,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;QAC/B,SAAS,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACpE,SAAS,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACpE,SAAS,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAEpE,8EAA8E;QAC9E,IAAI,CAAC,2BAA2B,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAEpD,6DAA6D;QAC7D,MAAM,WAAW,GAAG,SAAS,CAAC,KAAK,CACjC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,WAAW,CAAC,GAAG,CAAC,YAAY,GAAG,WAAW,CAAC,EAC/D,CAAC,EACD,CAAC,CACF,CAAC;QACF,MAAM,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,gBAAgB,EAAE,gBAAgB,EAAE,WAAW,CAAC,CAAC;QAE1E,uEAAuE;QACvE,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;QAExB,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACvC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,OAAO,CACL,MAAC,SAAS,IACR,GAAG,EAAE,OAAO,EACZ,IAAI,EAAC,mBAAmB,EACxB,SAAS,EAAE,KAAK,EAChB,QAAQ,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EACtE,gBAAgB,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,aAEvC,KAAC,cAAc,IAAC,IAAI,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,GAAI,EAC5E,KAAC,WAAW,IACV,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,KAAK,MAAM,GAClC,IACQ,CACb,CAAC;AACJ,CAAC;AAOD,sEAAsE;AACtE,MAAM,UAAU,aAAa,CAAC,EAAE,KAAK,EAAE,cAAc,EAAsB;IACzE,MAAM,OAAO,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;IACxC,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,cAAc,CAAC,CAAC;IACpE,OAAO,CACL,4BACG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAClB,KAAC,kBAAkB,IAAkB,MAAM,EAAE,CAAC,IAArB,CAAC,CAAC,QAAQ,CAAe,CACnD,CAAC,GACD,CACJ,CAAC;AACJ,CAAC"} \ No newline at end of file +{"version":3,"file":"RemotePlayers.js","sourceRoot":"","sources":["../../src/net/RemotePlayers.tsx"],"names":[],"mappings":"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"} \ No newline at end of file