@rpgjs/vite 5.0.0-alpha.33 → 5.0.0-alpha.35

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.
package/dist/index.js CHANGED
@@ -8253,10 +8253,8 @@ class PartyConnection {
8253
8253
  this.messageQueue = [];
8254
8254
  this.isProcessingQueue = false;
8255
8255
  this.sequenceCounter = 0;
8256
- this.lastSendTime = 0;
8257
- this.outgoingFlushTimeout = null;
8258
8256
  this.incomingQueue = [];
8259
- this.incomingFlushTimeout = null;
8257
+ this.isProcessingIncomingQueue = false;
8260
8258
  this.id = id || this.generateId();
8261
8259
  this.uri = uri || "";
8262
8260
  }
@@ -8320,22 +8318,12 @@ class PartyConnection {
8320
8318
  }
8321
8319
  }
8322
8320
  /**
8323
- * Processes the outgoing queue with TCP-like batching.
8324
- *
8325
- * - If latency is enabled, schedule a single flush after latencyMs to batch messages.
8326
- * - At flush, send all queued messages in order, applying bandwidth delays per message.
8321
+ * Processes the outgoing queue in order.
8322
+ *
8323
+ * Each message receives its own fixed latency (if enabled), while preserving
8324
+ * original spacing and order.
8327
8325
  */
8328
8326
  async processMessageQueue() {
8329
- if (this.messageQueue.length === 0) return;
8330
- const shouldBatchWithLatency = PartyConnection.latencyEnabled && PartyConnection.latencyMs > 0;
8331
- if (shouldBatchWithLatency) {
8332
- if (this.outgoingFlushTimeout) return;
8333
- this.outgoingFlushTimeout = setTimeout(async () => {
8334
- this.outgoingFlushTimeout = null;
8335
- await this.flushSendQueue();
8336
- }, PartyConnection.latencyMs);
8337
- return;
8338
- }
8339
8327
  await this.flushSendQueue();
8340
8328
  }
8341
8329
  /**
@@ -8346,6 +8334,9 @@ class PartyConnection {
8346
8334
  this.isProcessingQueue = true;
8347
8335
  while (this.messageQueue.length > 0) {
8348
8336
  const queueItem = this.messageQueue.shift();
8337
+ if (this.shouldApplyLatency(queueItem.message)) {
8338
+ await this.waitUntil(queueItem.timestamp + PartyConnection.latencyMs);
8339
+ }
8349
8340
  if (PartyConnection.bandwidthEnabled && PartyConnection.bandwidthKbps > 0) {
8350
8341
  if (!PartyConnection.bandwidthFilter || queueItem.message.includes(PartyConnection.bandwidthFilter)) {
8351
8342
  const messageSizeBits = queueItem.message.length * 8;
@@ -8360,6 +8351,22 @@ class PartyConnection {
8360
8351
  }
8361
8352
  this.isProcessingQueue = false;
8362
8353
  }
8354
+ shouldApplyLatency(message) {
8355
+ if (!PartyConnection.latencyEnabled || PartyConnection.latencyMs <= 0) {
8356
+ return false;
8357
+ }
8358
+ if (!PartyConnection.latencyFilter) {
8359
+ return true;
8360
+ }
8361
+ return message.includes(PartyConnection.latencyFilter);
8362
+ }
8363
+ async waitUntil(targetTimestamp) {
8364
+ const delayMs = targetTimestamp - Date.now();
8365
+ if (delayMs <= 0) {
8366
+ return;
8367
+ }
8368
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
8369
+ }
8363
8370
  /**
8364
8371
  * Closes the WebSocket connection
8365
8372
  */
@@ -8386,9 +8393,9 @@ class PartyConnection {
8386
8393
  }
8387
8394
  /**
8388
8395
  * Buffers incoming messages to simulate TCP latency on reception.
8389
- *
8390
- * All messages that arrive within the latency window are flushed together,
8391
- * preserving order. The provided processor is called with the ordered batch.
8396
+ *
8397
+ * Messages are processed in strict order. Each message keeps its own fixed
8398
+ * latency delay relative to the moment it arrived.
8392
8399
  *
8393
8400
  * @param {string} message - Raw incoming message
8394
8401
  * @param {(messages: string[]) => Promise<void>} processor - Async batch processor
@@ -8399,19 +8406,32 @@ class PartyConnection {
8399
8406
  * })
8400
8407
  */
8401
8408
  bufferIncoming(message, processor) {
8402
- this.incomingQueue.push(message);
8403
- const latencyMs = PartyConnection.latencyEnabled && PartyConnection.latencyMs > 0 ? PartyConnection.latencyMs : 0;
8404
- if (this.incomingFlushTimeout) return;
8405
- this.incomingFlushTimeout = setTimeout(async () => {
8406
- const batch = this.incomingQueue;
8407
- this.incomingQueue = [];
8408
- this.incomingFlushTimeout = null;
8409
+ this.incomingQueue.push({
8410
+ message,
8411
+ timestamp: Date.now(),
8412
+ processor
8413
+ });
8414
+ if (!this.isProcessingIncomingQueue) {
8415
+ void this.processIncomingQueue();
8416
+ }
8417
+ }
8418
+ async processIncomingQueue() {
8419
+ if (this.isProcessingIncomingQueue) {
8420
+ return;
8421
+ }
8422
+ this.isProcessingIncomingQueue = true;
8423
+ while (this.incomingQueue.length > 0) {
8424
+ const item = this.incomingQueue.shift();
8425
+ if (this.shouldApplyLatency(item.message)) {
8426
+ await this.waitUntil(item.timestamp + PartyConnection.latencyMs);
8427
+ }
8409
8428
  try {
8410
- await processor(batch);
8429
+ await item.processor([item.message]);
8411
8430
  } catch (err) {
8412
- console.error("Error processing incoming batch:", err);
8431
+ console.error("Error processing incoming message:", err);
8413
8432
  }
8414
- }, latencyMs);
8433
+ }
8434
+ this.isProcessingIncomingQueue = false;
8415
8435
  }
8416
8436
  /**
8417
8437
  * Configures packet loss simulation settings
@@ -8632,12 +8652,15 @@ async function importWebSocketServer() {
8632
8652
  }
8633
8653
  }
8634
8654
  async function updateMap(roomId, rpgServer) {
8655
+ if (!roomId.startsWith("map-")) {
8656
+ return;
8657
+ }
8635
8658
  try {
8636
8659
  const mapId = roomId.startsWith("map-") ? roomId.slice(4) : roomId;
8637
8660
  const defaultMapPayload = {
8638
8661
  id: mapId,
8639
- width: 1e3,
8640
- height: 1e3,
8662
+ width: 0,
8663
+ height: 0,
8641
8664
  events: []
8642
8665
  };
8643
8666
  const req = {
@@ -8786,22 +8809,71 @@ function serverPlugin(serverModule) {
8786
8809
  }
8787
8810
  server.middlewares.use("/parties", async (req, res, next) => {
8788
8811
  try {
8789
- console.log(`RPG-JS HTTP request: ${req.method} ${req.url}`);
8790
- if (req.url?.includes("/test")) {
8812
+ const host = req.headers.host || "localhost";
8813
+ const incomingUrl = req.url || "/";
8814
+ const parsedUrl = new URL(incomingUrl, `http://${host}`);
8815
+ const normalizedPath = parsedUrl.pathname.startsWith("/parties") ? parsedUrl.pathname : `/parties${parsedUrl.pathname.startsWith("/") ? parsedUrl.pathname : `/${parsedUrl.pathname}`}`;
8816
+ const pathParts = normalizedPath.split("/").filter(Boolean);
8817
+ if (pathParts[0] !== "parties" || pathParts[1] !== "main" || pathParts.length < 4) {
8818
+ next();
8819
+ return;
8820
+ }
8821
+ const roomId = pathParts[2];
8822
+ const requestPath = `/${pathParts.slice(3).join("/")}`;
8823
+ const { room, rpgServer } = await ensureRoomAndServer(roomId);
8824
+ room.context.parties = buildPartiesContext();
8825
+ const bodyText = await new Promise((resolve, reject) => {
8826
+ const chunks = [];
8827
+ req.on("data", (chunk) => {
8828
+ chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
8829
+ });
8830
+ req.on("end", () => {
8831
+ resolve(Buffer.concat(chunks).toString("utf8"));
8832
+ });
8833
+ req.on("error", reject);
8834
+ });
8835
+ const requestHeaders = new Headers();
8836
+ Object.entries(req.headers).forEach(([key, value]) => {
8837
+ if (Array.isArray(value)) {
8838
+ if (value[0] !== void 0) requestHeaders.set(key, value[0]);
8839
+ return;
8840
+ }
8841
+ if (typeof value === "string") {
8842
+ requestHeaders.set(key, value);
8843
+ }
8844
+ });
8845
+ const requestLike = {
8846
+ url: `http://${host}/parties/main/${roomId}${requestPath}${parsedUrl.search}`,
8847
+ method: (req.method || "GET").toUpperCase(),
8848
+ headers: requestHeaders,
8849
+ json: async () => {
8850
+ if (!bodyText) return void 0;
8851
+ return JSON.parse(bodyText);
8852
+ },
8853
+ text: async () => bodyText
8854
+ };
8855
+ const result = await rpgServer.onRequest(requestLike);
8856
+ if (result instanceof Response) {
8857
+ res.statusCode = result.status;
8858
+ result.headers.forEach((value, key) => {
8859
+ res.setHeader(key, value);
8860
+ });
8861
+ res.end(await result.text());
8862
+ return;
8863
+ }
8864
+ if (typeof result === "string") {
8791
8865
  res.statusCode = 200;
8792
- res.setHeader("Content-Type", "application/json");
8793
- res.end(
8794
- JSON.stringify({
8795
- message: "RPG-JS server is running",
8796
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
8797
- })
8798
- );
8866
+ res.setHeader("Content-Type", "text/plain");
8867
+ res.end(result);
8799
8868
  return;
8800
8869
  }
8801
- next();
8870
+ res.statusCode = 200;
8871
+ res.setHeader("Content-Type", "application/json");
8872
+ res.end(JSON.stringify(result ?? {}));
8802
8873
  } catch (error) {
8803
8874
  console.error("Error handling RPG-JS request:", error);
8804
8875
  res.statusCode = 500;
8876
+ res.setHeader("Content-Type", "application/json");
8805
8877
  res.end(JSON.stringify({ error: "Internal server error" }));
8806
8878
  }
8807
8879
  });