@rpgjs/server 5.0.0-alpha.8 → 5.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/dist/Gui/DialogGui.d.ts +5 -0
  2. package/dist/Gui/GameoverGui.d.ts +23 -0
  3. package/dist/Gui/Gui.d.ts +6 -0
  4. package/dist/Gui/MenuGui.d.ts +22 -3
  5. package/dist/Gui/NotificationGui.d.ts +1 -2
  6. package/dist/Gui/SaveLoadGui.d.ts +13 -0
  7. package/dist/Gui/ShopGui.d.ts +28 -3
  8. package/dist/Gui/TitleGui.d.ts +23 -0
  9. package/dist/Gui/index.d.ts +10 -1
  10. package/dist/Player/BattleManager.d.ts +44 -32
  11. package/dist/Player/ClassManager.d.ts +24 -4
  12. package/dist/Player/ComponentManager.d.ts +100 -7
  13. package/dist/Player/Components.d.ts +345 -0
  14. package/dist/Player/EffectManager.d.ts +50 -4
  15. package/dist/Player/ElementManager.d.ts +77 -4
  16. package/dist/Player/GoldManager.d.ts +1 -1
  17. package/dist/Player/GuiManager.d.ts +233 -5
  18. package/dist/Player/ItemFixture.d.ts +1 -1
  19. package/dist/Player/ItemManager.d.ts +431 -4
  20. package/dist/Player/MoveManager.d.ts +301 -34
  21. package/dist/Player/ParameterManager.d.ts +364 -28
  22. package/dist/Player/Player.d.ts +558 -14
  23. package/dist/Player/SkillManager.d.ts +187 -13
  24. package/dist/Player/StateManager.d.ts +75 -4
  25. package/dist/Player/VariableManager.d.ts +62 -4
  26. package/dist/RpgServer.d.ts +278 -63
  27. package/dist/RpgServerEngine.d.ts +2 -1
  28. package/dist/decorators/event.d.ts +46 -0
  29. package/dist/decorators/map.d.ts +299 -0
  30. package/dist/index.d.ts +10 -0
  31. package/dist/index.js +17920 -29866
  32. package/dist/index.js.map +1 -1
  33. package/dist/logs/log.d.ts +2 -3
  34. package/dist/module-CaCW1SDh.js +11018 -0
  35. package/dist/module-CaCW1SDh.js.map +1 -0
  36. package/dist/module.d.ts +43 -1
  37. package/dist/node/connection.d.ts +51 -0
  38. package/dist/node/index.d.ts +5 -0
  39. package/dist/node/index.js +551 -0
  40. package/dist/node/index.js.map +1 -0
  41. package/dist/node/map.d.ts +16 -0
  42. package/dist/node/room.d.ts +21 -0
  43. package/dist/node/transport.d.ts +28 -0
  44. package/dist/node/types.d.ts +47 -0
  45. package/dist/presets/index.d.ts +0 -9
  46. package/dist/rooms/BaseRoom.d.ts +132 -0
  47. package/dist/rooms/lobby.d.ts +10 -2
  48. package/dist/rooms/map.d.ts +1359 -32
  49. package/dist/services/save.d.ts +43 -0
  50. package/dist/storage/index.d.ts +1 -0
  51. package/dist/storage/localStorage.d.ts +23 -0
  52. package/package.json +25 -10
  53. package/src/Gui/DialogGui.ts +19 -4
  54. package/src/Gui/GameoverGui.ts +39 -0
  55. package/src/Gui/Gui.ts +23 -1
  56. package/src/Gui/MenuGui.ts +155 -6
  57. package/src/Gui/NotificationGui.ts +1 -2
  58. package/src/Gui/SaveLoadGui.ts +60 -0
  59. package/src/Gui/ShopGui.ts +146 -16
  60. package/src/Gui/TitleGui.ts +39 -0
  61. package/src/Gui/index.ts +15 -2
  62. package/src/Player/BattleManager.ts +39 -56
  63. package/src/Player/ClassManager.ts +82 -74
  64. package/src/Player/ComponentManager.ts +401 -37
  65. package/src/Player/Components.ts +380 -0
  66. package/src/Player/EffectManager.ts +50 -96
  67. package/src/Player/ElementManager.ts +74 -152
  68. package/src/Player/GuiManager.ts +284 -149
  69. package/src/Player/ItemManager.ts +747 -341
  70. package/src/Player/MoveManager.ts +1532 -750
  71. package/src/Player/ParameterManager.ts +636 -106
  72. package/src/Player/Player.ts +1273 -79
  73. package/src/Player/SkillManager.ts +558 -197
  74. package/src/Player/StateManager.ts +131 -258
  75. package/src/Player/VariableManager.ts +85 -157
  76. package/src/RpgServer.ts +293 -62
  77. package/src/decorators/event.ts +61 -0
  78. package/src/decorators/map.ts +343 -0
  79. package/src/index.ts +11 -1
  80. package/src/logs/log.ts +10 -3
  81. package/src/module.ts +126 -3
  82. package/src/node/connection.ts +254 -0
  83. package/src/node/index.ts +22 -0
  84. package/src/node/map.ts +328 -0
  85. package/src/node/room.ts +63 -0
  86. package/src/node/transport.ts +532 -0
  87. package/src/node/types.ts +61 -0
  88. package/src/presets/index.ts +1 -10
  89. package/src/rooms/BaseRoom.ts +232 -0
  90. package/src/rooms/lobby.ts +25 -7
  91. package/src/rooms/map.ts +2682 -206
  92. package/src/services/save.ts +147 -0
  93. package/src/storage/index.ts +1 -0
  94. package/src/storage/localStorage.ts +76 -0
  95. package/tests/battle.spec.ts +375 -0
  96. package/tests/change-map.spec.ts +72 -0
  97. package/tests/class.spec.ts +274 -0
  98. package/tests/custom-websocket.spec.ts +127 -0
  99. package/tests/effect.spec.ts +219 -0
  100. package/tests/element.spec.ts +221 -0
  101. package/tests/event.spec.ts +80 -0
  102. package/tests/gold.spec.ts +99 -0
  103. package/tests/item.spec.ts +609 -0
  104. package/tests/module.spec.ts +38 -0
  105. package/tests/move.spec.ts +601 -0
  106. package/tests/node-transport.spec.ts +223 -0
  107. package/tests/player-param.spec.ts +45 -0
  108. package/tests/prediction-reconciliation.spec.ts +182 -0
  109. package/tests/random-move.spec.ts +65 -0
  110. package/tests/skill.spec.ts +658 -0
  111. package/tests/state.spec.ts +467 -0
  112. package/tests/variable.spec.ts +185 -0
  113. package/tests/world-maps.spec.ts +896 -0
  114. package/vite.config.ts +36 -3
  115. package/dist/Player/Event.d.ts +0 -0
  116. package/src/Player/Event.ts +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/node/connection.ts","../../src/node/room.ts","../../src/node/transport.ts"],"sourcesContent":["import type { RpgWebSocketConnection } from \"./types\";\n\ntype RuntimeProcess = {\n env?: Record<string, string | undefined>;\n};\n\nfunction readEnvVariable(name: string): string | undefined {\n const value = (globalThis as { process?: RuntimeProcess }).process?.env?.[name];\n return typeof value === \"string\" ? value : undefined;\n}\n\nexport class PartyConnection {\n public id: string;\n public uri: string;\n private _state: any = {};\n private messageQueue: Array<{ message: string; timestamp: number; sequence: number }> = [];\n private isProcessingQueue = false;\n private sequenceCounter = 0;\n private incomingQueue: Array<{\n message: string;\n timestamp: number;\n processor: (messages: string[]) => Promise<void>;\n }> = [];\n private isProcessingIncomingQueue = false;\n\n public static packetLossRate = parseFloat(readEnvVariable(\"RPGJS_PACKET_LOSS_RATE\") || \"0.1\");\n public static packetLossEnabled = readEnvVariable(\"RPGJS_ENABLE_PACKET_LOSS\") === \"true\";\n public static packetLossFilter = readEnvVariable(\"RPGJS_PACKET_LOSS_FILTER\") || \"\";\n public static bandwidthEnabled = readEnvVariable(\"RPGJS_ENABLE_BANDWIDTH\") === \"true\";\n public static bandwidthKbps = parseInt(readEnvVariable(\"RPGJS_BANDWIDTH_KBPS\") || \"100\");\n public static bandwidthFilter = readEnvVariable(\"RPGJS_BANDWIDTH_FILTER\") || \"\";\n public static latencyEnabled = readEnvVariable(\"RPGJS_ENABLE_LATENCY\") === \"true\";\n public static latencyMs = parseInt(readEnvVariable(\"RPGJS_LATENCY_MS\") || \"50\");\n public static latencyFilter = readEnvVariable(\"RPGJS_LATENCY_FILTER\") || \"\";\n\n constructor(private ws: RpgWebSocketConnection, id?: string, uri?: string) {\n this.id = id || this.generateId();\n this.uri = uri || \"\";\n }\n\n private generateId(): string {\n return `conn_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;\n }\n\n async send(data: any): Promise<void> {\n if (this.ws.readyState !== 1) {\n return;\n }\n\n const message = typeof data === \"string\" ? data : JSON.stringify(data);\n const timestamp = Date.now();\n const sequence = ++this.sequenceCounter;\n\n this.messageQueue.push({ message, timestamp, sequence });\n\n if (!this.isProcessingQueue) {\n void this.processMessageQueue();\n }\n }\n\n private async processMessageQueue(): Promise<void> {\n if (this.isProcessingQueue) {\n return;\n }\n this.isProcessingQueue = true;\n\n while (this.messageQueue.length > 0) {\n const queueItem = this.messageQueue.shift()!;\n\n if (this.shouldApplyLatency(queueItem.message)) {\n await this.waitUntil(queueItem.timestamp + PartyConnection.latencyMs);\n }\n\n if (PartyConnection.bandwidthEnabled && PartyConnection.bandwidthKbps > 0) {\n if (!PartyConnection.bandwidthFilter || queueItem.message.includes(PartyConnection.bandwidthFilter)) {\n const messageSizeBits = queueItem.message.length * 8;\n const transmissionTimeMs = (messageSizeBits / (PartyConnection.bandwidthKbps * 1000)) * 1000;\n const bandwidthDelayMs = Math.max(transmissionTimeMs, 10);\n console.log(\n `\\x1b[34m[BANDWIDTH SIMULATION]\\x1b[0m Connection ${this.id}: Message #${queueItem.sequence} transmission time: ${bandwidthDelayMs.toFixed(1)}ms`,\n );\n await new Promise((resolve) => setTimeout(resolve, bandwidthDelayMs));\n }\n }\n\n this.ws.send(queueItem.message);\n }\n\n this.isProcessingQueue = false;\n }\n\n private shouldApplyLatency(message: string): boolean {\n if (!PartyConnection.latencyEnabled || PartyConnection.latencyMs <= 0) {\n return false;\n }\n if (!PartyConnection.latencyFilter) {\n return true;\n }\n return message.includes(PartyConnection.latencyFilter);\n }\n\n private async waitUntil(targetTimestamp: number): Promise<void> {\n const delayMs = targetTimestamp - Date.now();\n if (delayMs <= 0) {\n return;\n }\n await new Promise((resolve) => setTimeout(resolve, delayMs));\n }\n\n close(): void {\n if (this.ws.readyState === 1) {\n this.ws.close();\n }\n }\n\n setState(value: any): void {\n this._state = value;\n }\n\n get state(): any {\n return this._state;\n }\n\n bufferIncoming(message: string, processor: (messages: string[]) => Promise<void>): void {\n this.incomingQueue.push({\n message,\n timestamp: Date.now(),\n processor,\n });\n\n if (!this.isProcessingIncomingQueue) {\n void this.processIncomingQueue();\n }\n }\n\n private async processIncomingQueue(): Promise<void> {\n if (this.isProcessingIncomingQueue) {\n return;\n }\n this.isProcessingIncomingQueue = true;\n\n while (this.incomingQueue.length > 0) {\n const item = this.incomingQueue.shift()!;\n if (this.shouldApplyLatency(item.message)) {\n await this.waitUntil(item.timestamp + PartyConnection.latencyMs);\n }\n try {\n await item.processor([item.message]);\n } catch (err) {\n console.error(\"Error processing incoming message:\", err);\n }\n }\n\n this.isProcessingIncomingQueue = false;\n }\n\n static configurePacketLoss(enabled: boolean, rate: number, filter?: string): void {\n PartyConnection.packetLossEnabled = enabled;\n PartyConnection.packetLossRate = Math.max(0, Math.min(1, rate));\n PartyConnection.packetLossFilter = filter || \"\";\n\n if (enabled && rate > 0) {\n const filterInfo = filter ? ` (filtered: \"${filter}\")` : \"\";\n console.log(`\\x1b[35m[PACKET LOSS SIMULATION]\\x1b[0m Enabled with ${(rate * 100).toFixed(1)}% loss rate${filterInfo}`);\n } else if (enabled) {\n console.log(\"\\x1b[35m[PACKET LOSS SIMULATION]\\x1b[0m Enabled but rate is 0% (no messages will be dropped)\");\n } else {\n console.log(\"\\x1b[35m[PACKET LOSS SIMULATION]\\x1b[0m Disabled\");\n }\n }\n\n static getPacketLossStatus(): { enabled: boolean; rate: number; filter: string } {\n return {\n enabled: PartyConnection.packetLossEnabled,\n rate: PartyConnection.packetLossRate,\n filter: PartyConnection.packetLossFilter,\n };\n }\n\n static configureBandwidth(enabled: boolean, kbps: number, filter?: string): void {\n PartyConnection.bandwidthEnabled = enabled;\n PartyConnection.bandwidthKbps = Math.max(1, kbps);\n PartyConnection.bandwidthFilter = filter || \"\";\n\n if (enabled && kbps > 0) {\n const filterInfo = filter ? ` (filtered: \"${filter}\")` : \"\";\n console.log(`\\x1b[35m[BANDWIDTH SIMULATION]\\x1b[0m Enabled with ${kbps} kbps bandwidth${filterInfo}`);\n } else if (enabled) {\n console.log(\"\\x1b[35m[BANDWIDTH SIMULATION]\\x1b[0m Enabled but bandwidth is 0 kbps (no delay will be applied)\");\n } else {\n console.log(\"\\x1b[35m[BANDWIDTH SIMULATION]\\x1b[0m Disabled\");\n }\n }\n\n static getBandwidthStatus(): { enabled: boolean; kbps: number; filter: string } {\n return {\n enabled: PartyConnection.bandwidthEnabled,\n kbps: PartyConnection.bandwidthKbps,\n filter: PartyConnection.bandwidthFilter,\n };\n }\n\n static configureLatency(enabled: boolean, ms: number, filter?: string): void {\n PartyConnection.latencyEnabled = enabled;\n PartyConnection.latencyMs = Math.max(0, ms);\n PartyConnection.latencyFilter = filter || \"\";\n\n if (enabled && ms > 0) {\n const filterInfo = filter ? ` (filtered: \"${filter}\")` : \"\";\n console.log(`\\x1b[35m[LATENCY SIMULATION]\\x1b[0m Enabled with ${ms}ms fixed latency${filterInfo}`);\n } else if (enabled) {\n console.log(\"\\x1b[35m[LATENCY SIMULATION]\\x1b[0m Enabled but latency is 0ms (no delay will be applied)\");\n } else {\n console.log(\"\\x1b[35m[LATENCY SIMULATION]\\x1b[0m Disabled\");\n }\n }\n\n static getLatencyStatus(): { enabled: boolean; ms: number; filter: string } {\n return {\n enabled: PartyConnection.latencyEnabled,\n ms: PartyConnection.latencyMs,\n filter: PartyConnection.latencyFilter,\n };\n }\n}\n\nexport function logNetworkSimulationStatus(): void {\n const packetLossStatus = PartyConnection.getPacketLossStatus();\n const bandwidthStatus = PartyConnection.getBandwidthStatus();\n const latencyStatus = PartyConnection.getLatencyStatus();\n\n if (packetLossStatus.enabled) {\n const filterInfo = packetLossStatus.filter ? ` (filter: \"${packetLossStatus.filter}\")` : \"\";\n console.log(\n `\\x1b[36m[NETWORK SIMULATION]\\x1b[0m Packet loss simulation: ${(packetLossStatus.rate * 100).toFixed(1)}% loss rate${filterInfo}`,\n );\n } else {\n console.log(\"\\x1b[36m[NETWORK SIMULATION]\\x1b[0m Packet loss simulation: disabled\");\n }\n\n if (bandwidthStatus.enabled) {\n const filterInfo = bandwidthStatus.filter ? ` (filter: \"${bandwidthStatus.filter}\")` : \"\";\n console.log(`\\x1b[36m[NETWORK SIMULATION]\\x1b[0m Bandwidth simulation: ${bandwidthStatus.kbps} kbps${filterInfo}`);\n } else {\n console.log(\"\\x1b[36m[NETWORK SIMULATION]\\x1b[0m Bandwidth simulation: disabled\");\n }\n\n if (latencyStatus.enabled) {\n const filterInfo = latencyStatus.filter ? ` (filter: \"${latencyStatus.filter}\")` : \"\";\n console.log(`\\x1b[36m[NETWORK SIMULATION]\\x1b[0m Latency simulation: ${latencyStatus.ms}ms ping${filterInfo}`);\n } else {\n console.log(\"\\x1b[36m[NETWORK SIMULATION]\\x1b[0m Latency simulation: disabled\");\n }\n}\n","import { PartyConnection } from \"./connection\";\n\nexport class PartyRoom {\n public id: string;\n public internalID: string;\n public env: Record<string, any> = {};\n public context: any = {};\n\n private connections = new Map<string, PartyConnection>();\n private storageData = new Map<string, any>();\n\n constructor(id: string) {\n this.id = id;\n this.internalID = `internal_${id}_${Date.now()}`;\n }\n\n async broadcast(message: any, except: string[] = []): Promise<void> {\n const data = typeof message === \"string\" ? message : JSON.stringify(message);\n const sendPromises: Promise<void>[] = [];\n\n for (const [connectionId, connection] of this.connections) {\n if (!except.includes(connectionId)) {\n sendPromises.push(connection.send(data));\n }\n }\n\n await Promise.all(sendPromises);\n }\n\n getConnection(id: string): PartyConnection | undefined {\n return this.connections.get(id);\n }\n\n getConnections(tag?: string): IterableIterator<PartyConnection> {\n void tag;\n return this.connections.values();\n }\n\n addConnection(connection: PartyConnection): void {\n this.connections.set(connection.id, connection);\n }\n\n removeConnection(connectionId: string): void {\n this.connections.delete(connectionId);\n }\n\n get storage() {\n return {\n put: async (key: string, value: any) => {\n this.storageData.set(key, value);\n },\n get: async <T = any>(key: string): Promise<T | undefined> => {\n return this.storageData.get(key) as T;\n },\n delete: async (key: string) => {\n this.storageData.delete(key);\n },\n list: async () => {\n return Array.from(this.storageData.entries());\n },\n };\n }\n}\n","import type { IncomingHttpHeaders, IncomingMessage, ServerResponse } from \"node:http\";\nimport type { Duplex } from \"node:stream\";\nimport { injector } from \"@signe/di\";\nimport { context as serverContext } from \"../core/context\";\nimport { setInject } from \"../core/inject\";\nimport { provideServerModules } from \"../module\";\nimport { PartyConnection } from \"./connection\";\nimport { createMapUpdateHeaders, resolveMapUpdateToken, updateMap } from \"./map\";\nimport { PartyRoom } from \"./room\";\nimport type {\n CreateRpgServerTransportOptions,\n HandleNodeRequestOptions,\n RpgTransportRequestLike,\n RpgTransportServer,\n RpgTransportServerConstructor,\n RpgWebSocketConnection,\n RpgWebSocketRequestLike,\n RpgWebSocketServer,\n SendMapUpdateOptions,\n} from \"./types\";\n\ntype PartiesFetchInit = {\n body?: any;\n headers?: HeadersInit | IncomingHttpHeaders | Map<string, string | undefined>;\n method?: string;\n};\n\nfunction normalizePathPrefix(path: string, fallback: string): string {\n const trimmed = (path || fallback).trim();\n if (!trimmed) {\n return fallback;\n }\n const prefixed = trimmed.startsWith(\"/\") ? trimmed : `/${trimmed}`;\n return prefixed !== \"/\" ? prefixed.replace(/\\/+$/, \"\") : prefixed;\n}\n\nfunction hasPathPrefix(pathname: string, prefix: string): boolean {\n return pathname === prefix || pathname.startsWith(`${prefix}/`);\n}\n\nfunction prependMountedPath(pathname: string, mountedPath?: string): string {\n if (!mountedPath) {\n return pathname;\n }\n const normalizedMountedPath = normalizePathPrefix(mountedPath, \"/\");\n if (hasPathPrefix(pathname, normalizedMountedPath)) {\n return pathname;\n }\n if (pathname === \"/\") {\n return normalizedMountedPath;\n }\n return `${normalizedMountedPath}${pathname.startsWith(\"/\") ? pathname : `/${pathname}`}`.replace(/\\/{2,}/g, \"/\");\n}\n\nfunction parseHttpRoute(pathname: string, partiesPath: string): { roomId: string; requestPath: string } | null {\n if (!hasPathPrefix(pathname, partiesPath)) {\n return null;\n }\n\n const remainder = pathname.slice(partiesPath.length);\n const segments = remainder.split(\"/\").filter(Boolean);\n if (segments.length < 2) {\n return null;\n }\n\n return {\n roomId: segments[0],\n requestPath: `/${segments.slice(1).join(\"/\")}`,\n };\n}\n\nfunction parseSocketRoute(pathname: string, partiesPath: string): { roomId: string } | null {\n if (!hasPathPrefix(pathname, partiesPath)) {\n return null;\n }\n\n const remainder = pathname.slice(partiesPath.length);\n const segments = remainder.split(\"/\").filter(Boolean);\n if (segments.length < 1) {\n return null;\n }\n\n return { roomId: segments[0] };\n}\n\nfunction toHeaders(\n input?: Headers | HeadersInit | IncomingHttpHeaders | Map<string, string | undefined>,\n): Headers {\n if (!input) {\n return new Headers();\n }\n if (input instanceof Headers) {\n return new Headers(input);\n }\n if (Array.isArray(input)) {\n return new Headers(input);\n }\n if (input instanceof Map) {\n const headers = new Headers();\n for (const [key, value] of input) {\n if (typeof value !== \"undefined\") {\n headers.set(key, value);\n }\n }\n return headers;\n }\n\n const headers = new Headers();\n Object.entries(input).forEach(([key, value]) => {\n if (Array.isArray(value)) {\n if (typeof value[0] !== \"undefined\") {\n headers.set(key, value[0]);\n }\n return;\n }\n if (typeof value !== \"undefined\") {\n headers.set(key, String(value));\n }\n });\n return headers;\n}\n\nfunction createRequestLike(url: string, method: string, headers: Headers, bodyText: string): RpgTransportRequestLike {\n return {\n url,\n method,\n headers,\n json: async () => {\n if (!bodyText) {\n return undefined;\n }\n return JSON.parse(bodyText);\n },\n text: async () => bodyText,\n };\n}\n\nasync function normalizeEngineResponse(result: any): Promise<Response> {\n if (result instanceof Response) {\n return result;\n }\n if (typeof result === \"string\") {\n return new Response(result, {\n status: 200,\n headers: {\n \"Content-Type\": \"text/plain\",\n },\n });\n }\n\n return new Response(JSON.stringify(result ?? {}), {\n status: 200,\n headers: {\n \"Content-Type\": \"application/json\",\n },\n });\n}\n\nasync function sendNodeResponse(res: ServerResponse, response: Response): Promise<void> {\n res.statusCode = response.status;\n response.headers.forEach((value, key) => {\n res.setHeader(key, value);\n });\n res.end(await response.text());\n}\n\nasync function readNodeBody(req: IncomingMessage): Promise<string> {\n return await new Promise<string>((resolve, reject) => {\n const chunks: Buffer[] = [];\n req.on(\"data\", (chunk: Buffer | string) => {\n chunks.push(typeof chunk === \"string\" ? Buffer.from(chunk) : chunk);\n });\n req.on(\"end\", () => {\n resolve(Buffer.concat(chunks).toString(\"utf8\"));\n });\n req.on(\"error\", reject);\n });\n}\n\nfunction resolveUrlFromSocketRequest(request: RpgWebSocketRequestLike): { headers: Headers; method?: string; rawUrl: string; url: URL } {\n const headers = toHeaders(request.headers);\n const host = headers.get(\"host\") || \"localhost\";\n const rawUrl = request.url || \"/\";\n const url = new URL(rawUrl, `http://${host}`);\n return {\n headers,\n method: request.method,\n rawUrl,\n url,\n };\n}\n\nfunction createConnectionContext(url: URL, headers: Headers, method?: string): any {\n const normalizedHeaders = new Map<string, string>();\n headers.forEach((value, key) => {\n normalizedHeaders.set(key.toLowerCase(), value);\n });\n\n return {\n request: {\n headers: {\n has: (name: string) => normalizedHeaders.has(name.toLowerCase()),\n get: (name: string) => normalizedHeaders.get(name.toLowerCase()),\n entries: () => normalizedHeaders.entries(),\n keys: () => normalizedHeaders.keys(),\n values: () => normalizedHeaders.values(),\n },\n method,\n url: url.toString(),\n },\n url,\n };\n}\n\nexport class RpgServerTransport {\n private serverContextInitialized = false;\n private partiesPath: string;\n private readonly initializeMaps: boolean;\n private readonly mapUpdateToken: string;\n private readonly tiledBasePaths?: string[];\n private readonly rooms = new Map<string, PartyRoom>();\n private readonly servers = new Map<string, RpgTransportServer>();\n private lastKnownHost = \"\";\n\n constructor(\n private readonly serverModule: RpgTransportServerConstructor,\n options: CreateRpgServerTransportOptions = {},\n ) {\n this.initializeMaps = options.initializeMaps ?? true;\n this.mapUpdateToken = resolveMapUpdateToken(options.mapUpdateToken);\n this.partiesPath = normalizePathPrefix(options.partiesPath || \"/parties/main\", \"/parties/main\");\n this.tiledBasePaths = options.tiledBasePaths;\n }\n\n private async ensureServerContext(): Promise<void> {\n if (this.serverContextInitialized) {\n return;\n }\n\n setInject(serverContext);\n await injector(serverContext, [provideServerModules([])]);\n this.serverContextInitialized = true;\n }\n\n getRoom(roomId: string): PartyRoom | undefined {\n return this.rooms.get(roomId);\n }\n\n getServer(roomId: string): RpgTransportServer | undefined {\n return this.servers.get(roomId);\n }\n\n private async ensureRoomAndServer(roomId: string, host?: string): Promise<{ room: PartyRoom; rpgServer: RpgTransportServer }> {\n if (host) {\n this.lastKnownHost = host;\n }\n\n let room = this.rooms.get(roomId);\n if (!room) {\n room = new PartyRoom(roomId);\n this.rooms.set(roomId, room);\n console.log(`Created new room: ${roomId}`);\n }\n\n let rpgServer = this.servers.get(roomId);\n if (!rpgServer) {\n await this.ensureServerContext();\n rpgServer = new this.serverModule(room);\n this.servers.set(roomId, rpgServer);\n console.log(`Created new server instance for room: ${roomId}`);\n\n if (typeof rpgServer.onStart === \"function\") {\n try {\n await rpgServer.onStart();\n console.log(`Server started for room: ${roomId}`);\n } catch (error) {\n console.error(`Error starting server for room ${roomId}:`, error);\n }\n }\n\n if (this.initializeMaps) {\n await updateMap(roomId, rpgServer, {\n host: host || this.lastKnownHost,\n mapUpdateToken: this.mapUpdateToken,\n tiledBasePaths: this.tiledBasePaths,\n });\n }\n }\n\n room.context.parties = this.buildPartiesContext();\n return { room, rpgServer };\n }\n\n private buildPartiesContext() {\n return {\n main: {\n get: async (targetRoomId: string) => {\n return {\n fetch: async (path: string, init?: PartiesFetchInit) => {\n const method = (init?.method || \"GET\").toUpperCase();\n const headers = toHeaders(init?.headers);\n const requestPath = path.startsWith(\"/\") ? path : `/${path}`;\n let bodyText = \"\";\n\n if (typeof init?.body === \"string\") {\n bodyText = init.body;\n } else if (typeof init?.body !== \"undefined\") {\n bodyText = JSON.stringify(init.body);\n }\n\n return this.dispatchRoomRequest(\n targetRoomId,\n createRequestLike(\n `http://localhost${this.partiesPath}/${targetRoomId}${requestPath}`,\n method,\n headers,\n bodyText,\n ),\n this.lastKnownHost,\n );\n },\n };\n },\n },\n } as any;\n }\n\n private async dispatchRoomRequest(roomId: string, requestLike: RpgTransportRequestLike, host?: string): Promise<Response> {\n const { room, rpgServer } = await this.ensureRoomAndServer(roomId, host);\n room.context.parties = this.buildPartiesContext();\n const result = await rpgServer.onRequest?.(requestLike);\n return normalizeEngineResponse(result);\n }\n\n async fetch(request: Request | string | URL, init?: RequestInit): Promise<Response> {\n const webRequest = request instanceof Request ? request : new Request(String(request), init);\n const url = new URL(webRequest.url);\n const route = parseHttpRoute(url.pathname, this.partiesPath);\n if (!route) {\n return new Response(JSON.stringify({ error: \"Not found\" }), {\n status: 404,\n headers: {\n \"Content-Type\": \"application/json\",\n },\n });\n }\n\n const bodyText = await webRequest.text();\n return this.dispatchRoomRequest(\n route.roomId,\n createRequestLike(webRequest.url, webRequest.method.toUpperCase(), toHeaders(webRequest.headers), bodyText),\n url.host,\n );\n }\n\n async updateMap(mapId: string, payload: any, options: SendMapUpdateOptions = {}): Promise<Response> {\n const roomId = mapId.startsWith(\"map-\") ? mapId : `map-${mapId}`;\n const headers = createMapUpdateHeaders(this.mapUpdateToken, options.headers);\n if (!headers.has(\"content-type\")) {\n headers.set(\"content-type\", \"application/json\");\n }\n\n return this.dispatchRoomRequest(\n roomId,\n createRequestLike(\n `http://localhost${this.partiesPath}/${roomId}/map/update`,\n \"POST\",\n headers,\n JSON.stringify(payload),\n ),\n options.host ?? this.lastKnownHost,\n );\n }\n\n async handleNodeRequest(\n req: IncomingMessage,\n res: ServerResponse,\n next?: () => void,\n options: HandleNodeRequestOptions = {},\n ): Promise<boolean> {\n try {\n const headers = toHeaders(req.headers);\n const host = headers.get(\"host\") || \"localhost\";\n const url = new URL(req.url || \"/\", `http://${host}`);\n const normalizedPathname = prependMountedPath(url.pathname, options.mountedPath);\n const normalizedUrl = new URL(url.toString());\n normalizedUrl.pathname = normalizedPathname;\n\n const route = parseHttpRoute(normalizedUrl.pathname, this.partiesPath);\n if (!route) {\n next?.();\n return false;\n }\n\n const bodyText = await readNodeBody(req);\n const response = await this.dispatchRoomRequest(\n route.roomId,\n createRequestLike(normalizedUrl.toString(), (req.method || \"GET\").toUpperCase(), headers, bodyText),\n host,\n );\n\n await sendNodeResponse(res, response);\n return true;\n } catch (error) {\n console.error(\"Error handling RPG-JS request:\", error);\n res.statusCode = 500;\n res.setHeader(\"Content-Type\", \"application/json\");\n res.end(JSON.stringify({ error: \"Internal server error\" }));\n return true;\n }\n }\n\n async acceptWebSocket(ws: RpgWebSocketConnection, request: RpgWebSocketRequestLike): Promise<boolean> {\n const normalizedRequest = resolveUrlFromSocketRequest(request);\n const route = parseSocketRoute(normalizedRequest.url.pathname, this.partiesPath);\n if (!route) {\n return false;\n }\n\n try {\n console.log(`WebSocket upgrade request: ${normalizedRequest.url.pathname}`);\n\n const queryParams = Object.fromEntries(normalizedRequest.url.searchParams.entries());\n console.log(`Room: ${route.roomId}, Query params:`, queryParams);\n\n const { room, rpgServer } = await this.ensureRoomAndServer(route.roomId, normalizedRequest.url.host);\n room.context.parties = this.buildPartiesContext();\n\n const connection = new PartyConnection(ws, queryParams._pk, normalizedRequest.rawUrl);\n room.addConnection(connection);\n\n console.log(`WebSocket connection established: ${connection.id} in room: ${route.roomId}`);\n\n let isClosed = false;\n const cleanup = async (logMessage?: string, error?: Error) => {\n if (isClosed) {\n return;\n }\n isClosed = true;\n if (logMessage) {\n console.log(logMessage);\n }\n if (error) {\n console.error(\"WebSocket error:\", error);\n }\n room.removeConnection(connection.id);\n await rpgServer.onClose?.(connection as any);\n };\n\n ws.on(\"message\", async (data: Buffer | string) => {\n try {\n const rawMessage = typeof data === \"string\" ? data : data.toString();\n\n if (PartyConnection.packetLossEnabled && PartyConnection.packetLossRate > 0) {\n if (!PartyConnection.packetLossFilter || rawMessage.includes(PartyConnection.packetLossFilter)) {\n const random = Math.random();\n if (random < PartyConnection.packetLossRate) {\n console.log(\n `\\x1b[31m[PACKET LOSS]\\x1b[0m Connection ${connection.id}: Server dropped an incoming packet (${(PartyConnection.packetLossRate * 100).toFixed(1)}% loss rate)`,\n );\n console.log(`\\x1b[33m[PACKET DATA]\\x1b[0m ${rawMessage.slice(0, 100)}${rawMessage.length > 100 ? \"...\" : \"\"}`);\n return;\n }\n }\n }\n\n connection.bufferIncoming(rawMessage, async (batch: string[]) => {\n for (const message of batch) {\n await rpgServer.onMessage?.(message, connection as any);\n }\n });\n } catch (error) {\n console.error(\"Error processing WebSocket message:\", error);\n }\n });\n\n ws.on(\"close\", () => {\n void cleanup(`WebSocket connection closed: ${connection.id} from room: ${route.roomId}`);\n });\n\n ws.on(\"error\", (error: Error) => {\n void cleanup(undefined, error);\n });\n\n if (typeof rpgServer.onConnect === \"function\") {\n await rpgServer.onConnect(\n connection as any,\n createConnectionContext(normalizedRequest.url, normalizedRequest.headers, normalizedRequest.method) as any,\n );\n }\n\n await connection.send({\n type: \"connected\",\n id: connection.id,\n message: \"Connected to RPG-JS server\",\n });\n\n return true;\n } catch (error) {\n console.error(\"Error establishing WebSocket connection:\", error);\n ws.close();\n return true;\n }\n }\n\n async handleUpgrade(\n wsServer: RpgWebSocketServer,\n request: IncomingMessage,\n socket: Duplex,\n head: Buffer,\n ): Promise<boolean> {\n const headers = toHeaders(request.headers);\n const host = headers.get(\"host\") || \"localhost\";\n const url = new URL(request.url || \"/\", `http://${host}`);\n if (!parseSocketRoute(url.pathname, this.partiesPath)) {\n return false;\n }\n\n wsServer.handleUpgrade(request, socket, head, (ws) => {\n void this.acceptWebSocket(ws, request);\n });\n\n return true;\n }\n}\n\nexport function createRpgServerTransport(\n serverModule: RpgTransportServerConstructor,\n options?: CreateRpgServerTransportOptions,\n): RpgServerTransport {\n return new RpgServerTransport(serverModule, options);\n}\n"],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import { RpgTransportServer } from './types';
2
+ interface ResolveMapOptions {
3
+ host?: string;
4
+ headers?: Headers;
5
+ mapUpdateToken?: string;
6
+ tiledBasePaths?: string[];
7
+ }
8
+ export declare const MAP_UPDATE_TOKEN_HEADER = "x-rpgjs-map-update-token";
9
+ export declare const MAP_UPDATE_TOKEN_ENV = "RPGJS_MAP_UPDATE_TOKEN";
10
+ export declare function resolveMapUpdateToken(explicitToken?: string): string;
11
+ export declare function createMapUpdateHeaders(token?: string, init?: HeadersInit): Headers;
12
+ export declare function readMapUpdateToken(headers: Headers): string;
13
+ export declare function isMapUpdateAuthorized(headers: Headers, expectedToken?: string): boolean;
14
+ export declare function enrichMapWithParsedTiledData(payload: any, options?: ResolveMapOptions): Promise<void>;
15
+ export declare function updateMap(roomId: string, rpgServer: RpgTransportServer, options?: ResolveMapOptions): Promise<void>;
16
+ export {};
@@ -0,0 +1,21 @@
1
+ import { PartyConnection } from './connection';
2
+ export declare class PartyRoom {
3
+ id: string;
4
+ internalID: string;
5
+ env: Record<string, any>;
6
+ context: any;
7
+ private connections;
8
+ private storageData;
9
+ constructor(id: string);
10
+ broadcast(message: any, except?: string[]): Promise<void>;
11
+ getConnection(id: string): PartyConnection | undefined;
12
+ getConnections(tag?: string): IterableIterator<PartyConnection>;
13
+ addConnection(connection: PartyConnection): void;
14
+ removeConnection(connectionId: string): void;
15
+ get storage(): {
16
+ put: (key: string, value: any) => Promise<void>;
17
+ get: <T = any>(key: string) => Promise<T | undefined>;
18
+ delete: (key: string) => Promise<void>;
19
+ list: () => Promise<[string, any][]>;
20
+ };
21
+ }
@@ -0,0 +1,28 @@
1
+ import { IncomingMessage, ServerResponse } from 'node:http';
2
+ import { Duplex } from 'node:stream';
3
+ import { PartyRoom } from './room';
4
+ import { CreateRpgServerTransportOptions, HandleNodeRequestOptions, RpgTransportServer, RpgTransportServerConstructor, RpgWebSocketConnection, RpgWebSocketRequestLike, RpgWebSocketServer, SendMapUpdateOptions } from './types';
5
+ export declare class RpgServerTransport {
6
+ private readonly serverModule;
7
+ private serverContextInitialized;
8
+ private partiesPath;
9
+ private readonly initializeMaps;
10
+ private readonly mapUpdateToken;
11
+ private readonly tiledBasePaths?;
12
+ private readonly rooms;
13
+ private readonly servers;
14
+ private lastKnownHost;
15
+ constructor(serverModule: RpgTransportServerConstructor, options?: CreateRpgServerTransportOptions);
16
+ private ensureServerContext;
17
+ getRoom(roomId: string): PartyRoom | undefined;
18
+ getServer(roomId: string): RpgTransportServer | undefined;
19
+ private ensureRoomAndServer;
20
+ private buildPartiesContext;
21
+ private dispatchRoomRequest;
22
+ fetch(request: Request | string | URL, init?: RequestInit): Promise<Response>;
23
+ updateMap(mapId: string, payload: any, options?: SendMapUpdateOptions): Promise<Response>;
24
+ handleNodeRequest(req: IncomingMessage, res: ServerResponse, next?: () => void, options?: HandleNodeRequestOptions): Promise<boolean>;
25
+ acceptWebSocket(ws: RpgWebSocketConnection, request: RpgWebSocketRequestLike): Promise<boolean>;
26
+ handleUpgrade(wsServer: RpgWebSocketServer, request: IncomingMessage, socket: Duplex, head: Buffer): Promise<boolean>;
27
+ }
28
+ export declare function createRpgServerTransport(serverModule: RpgTransportServerConstructor, options?: CreateRpgServerTransportOptions): RpgServerTransport;
@@ -0,0 +1,47 @@
1
+ import { IncomingHttpHeaders, IncomingMessage } from 'node:http';
2
+ import { Duplex } from 'node:stream';
3
+ import { RpgServerEngine } from '../RpgServerEngine';
4
+ export interface RpgWebSocketConnection {
5
+ readyState: number;
6
+ send(data: string): void;
7
+ close(): void;
8
+ on(event: string, callback: (...args: any[]) => void): void;
9
+ }
10
+ export interface RpgWebSocketServer {
11
+ handleUpgrade(request: IncomingMessage, socket: Duplex, head: Buffer, callback: (ws: RpgWebSocketConnection) => void): void;
12
+ close(): void;
13
+ }
14
+ export interface RpgTransportRequestLike {
15
+ url: string;
16
+ method?: string;
17
+ headers?: Headers | HeadersInit | IncomingHttpHeaders | Map<string, string | undefined>;
18
+ text(): Promise<string>;
19
+ json(): Promise<any>;
20
+ }
21
+ export interface RpgWebSocketRequestLike {
22
+ url?: string;
23
+ method?: string;
24
+ headers?: Headers | HeadersInit | IncomingHttpHeaders | Map<string, string | undefined>;
25
+ }
26
+ export type RpgTransportServer = RpgServerEngine & {
27
+ onStart?(): void | Promise<void>;
28
+ onRequest?(req: RpgTransportRequestLike): any | Promise<any>;
29
+ onMessage?(message: string, connection: any): void | Promise<void>;
30
+ onClose?(connection: any): void | Promise<void>;
31
+ onConnect?(connection: any, context: any): void | Promise<void>;
32
+ maps?: any[];
33
+ };
34
+ export type RpgTransportServerConstructor = new (room: any) => RpgTransportServer;
35
+ export interface CreateRpgServerTransportOptions {
36
+ initializeMaps?: boolean;
37
+ mapUpdateToken?: string;
38
+ partiesPath?: string;
39
+ tiledBasePaths?: string[];
40
+ }
41
+ export interface HandleNodeRequestOptions {
42
+ mountedPath?: string;
43
+ }
44
+ export interface SendMapUpdateOptions {
45
+ headers?: HeadersInit | IncomingHttpHeaders | Map<string, string | undefined>;
46
+ host?: string;
47
+ }
@@ -1,12 +1,3 @@
1
- export declare const MAXHP: string;
2
- export declare const MAXSP: string;
3
- export declare const ATK: string;
4
- export declare const PDEF: string;
5
- export declare const SDEF: string;
6
- export declare const STR: string;
7
- export declare const AGI: string;
8
- export declare const INT: string;
9
- export declare const DEX: string;
10
1
  export declare const MAXHP_CURVE: {
11
2
  start: number;
12
3
  end: number;
@@ -0,0 +1,132 @@
1
+ import { Hooks } from '../../../common/src';
2
+ import { RpgPlayer } from '../Player/Player';
3
+ /**
4
+ * Base class for rooms that need database functionality
5
+ *
6
+ * This class provides common database management functionality that is shared
7
+ * between RpgMap and LobbyRoom. It includes methods for adding and managing
8
+ * items, classes, and other game data in the room's database.
9
+ *
10
+ * ## Architecture
11
+ *
12
+ * Both RpgMap and LobbyRoom need to store game entities (items, classes, skills, etc.)
13
+ * in a database. This base class provides the common implementation to avoid code duplication.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * class MyCustomRoom extends BaseRoom {
18
+ * // Your custom room implementation
19
+ * }
20
+ * ```
21
+ */
22
+ export declare abstract class BaseRoom {
23
+ /**
24
+ * Signal containing the room's database of items, classes, and other game data
25
+ *
26
+ * This database can be dynamically populated using `addInDatabase()` and
27
+ * `removeInDatabase()` methods. It's used to store game entities like items,
28
+ * classes, skills, etc. that are available in this room.
29
+ *
30
+ * @example
31
+ * ```ts
32
+ * // Add data to database
33
+ * room.addInDatabase('Potion', PotionClass);
34
+ *
35
+ * // Access database
36
+ * const potion = room.database()['Potion'];
37
+ * ```
38
+ */
39
+ database: import('@signe/reactive').WritableObjectSignal<{}>;
40
+ onStart(): Promise<void>;
41
+ /**
42
+ * Add data to the room's database
43
+ *
44
+ * Adds an item, class, or other game entity to the room's database.
45
+ * If the ID already exists and `force` is not enabled, the addition is ignored.
46
+ *
47
+ * ## Architecture
48
+ *
49
+ * This method is used by the item management system to store item definitions
50
+ * in the room's database. When a player adds an item, the system first checks
51
+ * if the item exists in the database, and if not, adds it using this method.
52
+ *
53
+ * @param id - Unique identifier for the data
54
+ * @param data - The data to add (can be a class, object, etc.)
55
+ * @param options - Optional configuration
56
+ * @param options.force - If true, overwrites existing data with the same ID
57
+ * @returns `true` if data was added, `false` if it was ignored (ID already exists)
58
+ *
59
+ * @example
60
+ * ```ts
61
+ * // Add a class to the database
62
+ * room.addInDatabase('Potion', PotionClass);
63
+ *
64
+ * // Add an item object to the database
65
+ * room.addInDatabase('custom-item', {
66
+ * name: 'Custom Item',
67
+ * price: 100
68
+ * });
69
+ *
70
+ * // Force overwrite existing data
71
+ * room.addInDatabase('Potion', UpdatedPotionClass, { force: true });
72
+ * ```
73
+ */
74
+ addInDatabase(id: string, data: any, options?: {
75
+ force?: boolean;
76
+ }): boolean;
77
+ /**
78
+ * Remove data from the room's database
79
+ *
80
+ * This method allows you to remove items or data from the room's database.
81
+ *
82
+ * @param id - Unique identifier of the data to remove
83
+ * @returns `true` if data was removed, `false` if ID didn't exist
84
+ *
85
+ * @example
86
+ * ```ts
87
+ * // Remove an item from the database
88
+ * room.removeInDatabase('Potion');
89
+ *
90
+ * // Check if removal was successful
91
+ * const removed = room.removeInDatabase('custom-item');
92
+ * if (removed) {
93
+ * console.log('Item removed successfully');
94
+ * }
95
+ * ```
96
+ */
97
+ removeInDatabase(id: string): boolean;
98
+ /**
99
+ * Get the hooks system for this map
100
+ *
101
+ * Returns the dependency-injected Hooks instance that allows you to trigger
102
+ * and listen to various game events.
103
+ *
104
+ * @returns The Hooks instance for this map
105
+ *
106
+ * @example
107
+ * ```ts
108
+ * // Trigger a custom hook
109
+ * map.hooks.callHooks('custom-event', data).subscribe();
110
+ * ```
111
+ */
112
+ get hooks(): Hooks;
113
+ /**
114
+ * Resolve complex snapshot entries (e.g. inventory items) before load.
115
+ */
116
+ onSessionRestore({ userSnapshot, user }: {
117
+ userSnapshot: any;
118
+ user?: RpgPlayer;
119
+ }): Promise<any>;
120
+ listSaveSlots(player: RpgPlayer, value: {
121
+ requestId: string;
122
+ }): Promise<import('../../../common/src').SaveSlotList>;
123
+ saveSlot(player: RpgPlayer, value: {
124
+ requestId: string;
125
+ index: number;
126
+ meta?: any;
127
+ }): Promise<void>;
128
+ loadSlot(player: RpgPlayer, value: {
129
+ requestId: string;
130
+ index: number;
131
+ }): Promise<void>;
132
+ }
@@ -1,6 +1,14 @@
1
1
  import { MockConnection } from '@signe/room';
2
2
  import { RpgPlayer } from '../Player/Player';
3
- export declare class LobbyRoom {
3
+ import { BaseRoom } from './BaseRoom';
4
+ export declare class LobbyRoom extends BaseRoom {
4
5
  players: import('@signe/reactive').WritableObjectSignal<{}>;
5
- onJoin(player: RpgPlayer, conn: MockConnection): void;
6
+ autoSync: boolean;
7
+ constructor(room: any);
8
+ onJoin(player: RpgPlayer, conn: MockConnection): Promise<void>;
9
+ guiInteraction(player: RpgPlayer, value: {
10
+ guiId: string;
11
+ name: string;
12
+ data: any;
13
+ }): Promise<void>;
6
14
  }