@rpgjs/vite 5.0.0-beta.8 → 5.0.0-beta.9
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/CHANGELOG.md +11 -0
- package/dist/compatibility-v4/flag-transform.d.ts +6 -0
- package/dist/compatibility-v4/index.d.ts +22 -0
- package/dist/compatibility-v4/load-config-file.d.ts +2 -0
- package/dist/compatibility-v4/require-transform.d.ts +2 -0
- package/dist/compatibility-v4/utils.d.ts +55 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1329 -164
- package/dist/index.js.map +1 -1
- package/dist/rpgjs-plugin.d.ts +1 -0
- package/package.json +17 -9
- package/src/compatibility-v4/flag-transform.ts +61 -0
- package/src/compatibility-v4/index.ts +713 -0
- package/src/compatibility-v4/load-config-file.ts +38 -0
- package/src/compatibility-v4/require-transform.ts +67 -0
- package/src/compatibility-v4/utils.ts +170 -0
- package/src/index.ts +2 -1
- package/tests/compatibility-v4.spec.ts +105 -0
- package/tests/fixtures/v4-game/rpg.toml +11 -0
- package/tests/fixtures/v4-game/src/modules/main/characters/assets/hero.svg +2 -0
- package/tests/fixtures/v4-game/src/modules/main/characters/hero.ts +2 -0
- package/tests/fixtures/v4-game/src/modules/main/client.ts +4 -0
- package/tests/fixtures/v4-game/src/modules/main/database/potion.ts +6 -0
- package/tests/fixtures/v4-game/src/modules/main/events/npc.ts +4 -0
- package/tests/fixtures/v4-game/src/modules/main/gui/menu.vue +2 -0
- package/tests/fixtures/v4-game/src/modules/main/maps/map.tmx +2 -0
- package/tests/fixtures/v4-game/src/modules/main/maps/map.ts +7 -0
- package/tests/fixtures/v4-game/src/modules/main/player.ts +4 -0
- package/tests/fixtures/v4-game/src/modules/main/scene-map.ts +4 -0
- package/tests/fixtures/v4-game/src/modules/main/server.ts +4 -0
- package/tests/fixtures/v4-game/src/modules/main/sounds/theme.ogg +2 -0
- package/tests/fixtures/v4-game/src/modules/main/sounds/theme.ts +5 -0
- package/tests/fixtures/v4-game/src/modules/main/sprite.ts +4 -0
- package/tests/fixtures/v4-game/src/modules/main/worlds/maps/world-map.tmx +6 -0
- package/tests/fixtures/v4-game/src/modules/main/worlds/world.world +13 -0
- package/vite.config.ts +7 -1
package/dist/index.js
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
|
-
import { copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, statSync } from "fs";
|
|
2
|
-
import { dirname, extname, join, relative } from "path";
|
|
3
|
-
import { build, defineConfig } from "vite";
|
|
1
|
+
import fs, { copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, statSync } from "fs";
|
|
2
|
+
import path, { dirname, extname, join, relative } from "path";
|
|
3
|
+
import { build, defineConfig, loadEnv } from "vite";
|
|
4
4
|
import canvasengine from "@canvasengine/compiler";
|
|
5
5
|
import dts from "vite-plugin-dts";
|
|
6
6
|
import { existsSync as existsSync$1, rmSync } from "node:fs";
|
|
7
7
|
import { resolve } from "node:path";
|
|
8
|
+
import { EventEmitter } from "node:events";
|
|
9
|
+
import "node:module";
|
|
10
|
+
import sizeOf from "image-size";
|
|
11
|
+
import * as parser from "@babel/parser";
|
|
12
|
+
import _traverse from "@babel/traverse";
|
|
13
|
+
import _generate from "@babel/generator";
|
|
14
|
+
import { identifier, importDeclaration, importDefaultSpecifier, stringLiteral } from "@babel/types";
|
|
15
|
+
import toml from "@iarna/toml";
|
|
8
16
|
//#region src/tiled-map-folder-plugin.ts
|
|
9
17
|
/**
|
|
10
18
|
* Vite plugin that serves a data folder in development mode and copies it to assets during build
|
|
@@ -6801,7 +6809,7 @@ function replaceConfigImport() {
|
|
|
6801
6809
|
};
|
|
6802
6810
|
}
|
|
6803
6811
|
//#endregion
|
|
6804
|
-
//#region ../server/dist/module-
|
|
6812
|
+
//#region ../server/dist/module-CW79w6Lk.js
|
|
6805
6813
|
/******************************************************************************
|
|
6806
6814
|
Copyright (c) Microsoft Corporation.
|
|
6807
6815
|
|
|
@@ -8369,6 +8377,7 @@ var createSyncClass = (currentClass, parentKey = null, parentClass = null, path
|
|
|
8369
8377
|
currentClass.$path = path;
|
|
8370
8378
|
if (parentClass) currentClass.$valuesChanges = parentClass.$valuesChanges;
|
|
8371
8379
|
if (parentKey) setMetadata(currentClass, "id", parentKey);
|
|
8380
|
+
applyDecoratedSignalMetadata(currentClass);
|
|
8372
8381
|
if (currentClass.$snapshot) for (const key of currentClass.$snapshot.keys()) {
|
|
8373
8382
|
const signal = currentClass.$snapshot.get(key);
|
|
8374
8383
|
const syncToClient = signal.options?.syncToClient ?? true;
|
|
@@ -8391,8 +8400,20 @@ var createSyncClass = (currentClass, parentKey = null, parentClass = null, path
|
|
|
8391
8400
|
});
|
|
8392
8401
|
}
|
|
8393
8402
|
};
|
|
8403
|
+
function applyDecoratedSignalMetadata(currentClass) {
|
|
8404
|
+
const syncMetadata = currentClass.constructor?._syncMetadata;
|
|
8405
|
+
if (!syncMetadata) return;
|
|
8406
|
+
for (const [propertyKey, options] of syncMetadata) {
|
|
8407
|
+
const signal = currentClass[propertyKey];
|
|
8408
|
+
if (!isSignal(signal) || signal.options) continue;
|
|
8409
|
+
currentClass[propertyKey] = type(signal, propertyKey, {
|
|
8410
|
+
...options,
|
|
8411
|
+
skipInitialSync: true
|
|
8412
|
+
}, currentClass);
|
|
8413
|
+
}
|
|
8414
|
+
}
|
|
8394
8415
|
var type = (_signal, path, options = {}, currentInstance) => {
|
|
8395
|
-
const { syncToClient = true, persist: persist2 = true, transform } = options;
|
|
8416
|
+
const { syncToClient = true, persist: persist2 = true, transform, skipInitialSync = false } = options;
|
|
8396
8417
|
let init = true;
|
|
8397
8418
|
const handleObjectSubject = (value, propPath) => {
|
|
8398
8419
|
const newPath = `${propPath}${value.key ? `.${value.key}` : ""}`;
|
|
@@ -8424,14 +8445,15 @@ var type = (_signal, path, options = {}, currentInstance) => {
|
|
|
8424
8445
|
const savePath = (propPath, value) => {
|
|
8425
8446
|
const transformedValue = transform && value !== "$delete" ? transform(value) : value;
|
|
8426
8447
|
if (syncToClient) currentInstance.$valuesChanges.set(propPath, transformedValue);
|
|
8427
|
-
if (persist2 && currentInstance.$path !== void 0) currentInstance.$valuesChanges.setPersist(
|
|
8448
|
+
if (persist2 && currentInstance.$path !== void 0) currentInstance.$valuesChanges.setPersist(propPath, transformedValue);
|
|
8428
8449
|
};
|
|
8429
8450
|
const setupSubscription = (signal, signalPath) => {
|
|
8430
8451
|
if (!isSignal(signal)) return;
|
|
8431
|
-
if (syncToClient && currentInstance.$valuesChanges) {
|
|
8452
|
+
if (syncToClient && !skipInitialSync && currentInstance.$valuesChanges) {
|
|
8432
8453
|
const initialValue = signal();
|
|
8433
8454
|
const transformedInitialValue = transform ? transform(initialValue) : initialValue;
|
|
8434
|
-
currentInstance.$
|
|
8455
|
+
const initialPath = currentInstance.$path !== void 0 ? `${currentInstance.$path ? `${currentInstance.$path}.` : ""}${signalPath}` : signalPath;
|
|
8456
|
+
currentInstance.$valuesChanges.set(initialPath, transformedInitialValue);
|
|
8435
8457
|
}
|
|
8436
8458
|
signal.options = options;
|
|
8437
8459
|
signal.observable.subscribe((value) => {
|
|
@@ -8463,7 +8485,7 @@ var type = (_signal, path, options = {}, currentInstance) => {
|
|
|
8463
8485
|
init = false;
|
|
8464
8486
|
return _signal;
|
|
8465
8487
|
};
|
|
8466
|
-
function
|
|
8488
|
+
function normalizeSyncOptions(options) {
|
|
8467
8489
|
let classType;
|
|
8468
8490
|
let persist2 = true;
|
|
8469
8491
|
let syncToClient = true;
|
|
@@ -8475,18 +8497,27 @@ function sync(options) {
|
|
|
8475
8497
|
if (options.hasOwnProperty("syncToClient")) syncToClient = options.syncToClient;
|
|
8476
8498
|
if (options.hasOwnProperty("transform")) transform = options.transform;
|
|
8477
8499
|
}
|
|
8500
|
+
return {
|
|
8501
|
+
classType,
|
|
8502
|
+
persist: persist2,
|
|
8503
|
+
syncToClient,
|
|
8504
|
+
transform
|
|
8505
|
+
};
|
|
8506
|
+
}
|
|
8507
|
+
function setSyncMetadata(target, propertyKey, options) {
|
|
8508
|
+
if (!target.constructor._syncMetadata) target.constructor._syncMetadata = /* @__PURE__ */ new Map();
|
|
8509
|
+
target.constructor._syncMetadata.set(propertyKey, options);
|
|
8510
|
+
}
|
|
8511
|
+
function sync(options) {
|
|
8512
|
+
const normalizedOptions = normalizeSyncOptions(options);
|
|
8478
8513
|
return function(target, propertyKey) {
|
|
8514
|
+
setSyncMetadata(target, propertyKey, normalizedOptions);
|
|
8479
8515
|
const privatePropertyKey = `__${propertyKey}`;
|
|
8480
8516
|
const getter = function() {
|
|
8481
8517
|
return this[privatePropertyKey];
|
|
8482
8518
|
};
|
|
8483
8519
|
const setter = function(newVal) {
|
|
8484
|
-
this[privatePropertyKey] = type(newVal, propertyKey,
|
|
8485
|
-
classType,
|
|
8486
|
-
persist: persist2,
|
|
8487
|
-
syncToClient,
|
|
8488
|
-
transform
|
|
8489
|
-
}, this);
|
|
8520
|
+
this[privatePropertyKey] = type(newVal, propertyKey, normalizedOptions, this);
|
|
8490
8521
|
};
|
|
8491
8522
|
Object.defineProperty(target, propertyKey, {
|
|
8492
8523
|
get: getter,
|
|
@@ -8586,13 +8617,6 @@ var toCloneableSyncValue = (value, seen = /* @__PURE__ */ new WeakSet()) => {
|
|
|
8586
8617
|
}
|
|
8587
8618
|
return output;
|
|
8588
8619
|
};
|
|
8589
|
-
var Direction = /* @__PURE__ */ function(Direction) {
|
|
8590
|
-
Direction["Up"] = "up";
|
|
8591
|
-
Direction["Down"] = "down";
|
|
8592
|
-
Direction["Left"] = "left";
|
|
8593
|
-
Direction["Right"] = "right";
|
|
8594
|
-
return Direction;
|
|
8595
|
-
}({});
|
|
8596
8620
|
var RpgCommonPlayer = class {
|
|
8597
8621
|
constructor() {
|
|
8598
8622
|
this.name = signal("");
|
|
@@ -8601,7 +8625,7 @@ var RpgCommonPlayer = class {
|
|
|
8601
8625
|
this.y = signal(0);
|
|
8602
8626
|
this.z = signal(0);
|
|
8603
8627
|
this.tint = signal("white");
|
|
8604
|
-
this.direction = signal(
|
|
8628
|
+
this.direction = signal("down");
|
|
8605
8629
|
this.speed = signal(4);
|
|
8606
8630
|
this.graphics = signal([]);
|
|
8607
8631
|
this.canMove = signal(true);
|
|
@@ -9345,7 +9369,6 @@ var Context = class {
|
|
|
9345
9369
|
return this.values[key];
|
|
9346
9370
|
}
|
|
9347
9371
|
};
|
|
9348
|
-
function setInject(_context) {}
|
|
9349
9372
|
var context = new Context();
|
|
9350
9373
|
context["side"] = "server";
|
|
9351
9374
|
var MAP_UPDATE_TOKEN_HEADER = "x-rpgjs-map-update-token";
|
|
@@ -9853,50 +9876,457 @@ function logNetworkSimulationStatus() {
|
|
|
9853
9876
|
console.log(`\x1b[36m[NETWORK SIMULATION]\x1b[0m Latency simulation: ${latencyStatus.ms}ms ping${filterInfo}`);
|
|
9854
9877
|
} else console.log("\x1B[36m[NETWORK SIMULATION]\x1B[0m Latency simulation: disabled");
|
|
9855
9878
|
}
|
|
9856
|
-
var
|
|
9857
|
-
|
|
9858
|
-
|
|
9859
|
-
|
|
9879
|
+
var DEFAULT_PARTIES_PATH = "/parties/main";
|
|
9880
|
+
var WEBSOCKET_OPEN = 1;
|
|
9881
|
+
function createMemoryNodeRoomStorage(options = {}) {
|
|
9882
|
+
return new MemoryNodeRoomStorage(options);
|
|
9883
|
+
}
|
|
9884
|
+
function createNodeRoomTransport(ServerClass, options = {}) {
|
|
9885
|
+
return new NodeRoomTransport(ServerClass, options);
|
|
9886
|
+
}
|
|
9887
|
+
var MemoryNodeRoomStorage = class {
|
|
9888
|
+
constructor(options = {}) {
|
|
9889
|
+
this.rooms = /* @__PURE__ */ new Map();
|
|
9890
|
+
if (options.snapshot) this.restore(options.snapshot);
|
|
9891
|
+
}
|
|
9892
|
+
getStorage(namespace, roomId) {
|
|
9893
|
+
const key = getStorageKey(namespace, roomId);
|
|
9894
|
+
let memory = this.rooms.get(key);
|
|
9895
|
+
if (!memory) {
|
|
9896
|
+
memory = /* @__PURE__ */ new Map();
|
|
9897
|
+
this.rooms.set(key, memory);
|
|
9898
|
+
}
|
|
9899
|
+
return new MemoryNodeRoomStorageInstance(memory);
|
|
9900
|
+
}
|
|
9901
|
+
snapshot() {
|
|
9902
|
+
const snapshot = {};
|
|
9903
|
+
for (const [roomKey, memory] of this.rooms) {
|
|
9904
|
+
if (memory.size === 0) continue;
|
|
9905
|
+
snapshot[roomKey] = Array.from(memory.entries()).map(([key, value]) => [key, cloneStorageValue(value)]);
|
|
9906
|
+
}
|
|
9907
|
+
return snapshot;
|
|
9908
|
+
}
|
|
9909
|
+
restore(snapshot) {
|
|
9910
|
+
this.clear();
|
|
9911
|
+
for (const [roomKey, entries] of Object.entries(snapshot)) this.rooms.set(roomKey, new Map(entries.map(([key, value]) => [key, cloneStorageValue(value)])));
|
|
9912
|
+
}
|
|
9913
|
+
clear() {
|
|
9914
|
+
this.rooms.clear();
|
|
9915
|
+
}
|
|
9916
|
+
};
|
|
9917
|
+
var MemoryNodeRoomStorageInstance = class {
|
|
9918
|
+
constructor(memory) {
|
|
9919
|
+
this.memory = memory;
|
|
9920
|
+
}
|
|
9921
|
+
async put(keyOrEntries, value) {
|
|
9922
|
+
if (typeof keyOrEntries === "string") {
|
|
9923
|
+
this.memory.set(keyOrEntries, value);
|
|
9924
|
+
return;
|
|
9925
|
+
}
|
|
9926
|
+
for (const [key, entryValue] of Object.entries(keyOrEntries)) this.memory.set(key, entryValue);
|
|
9927
|
+
}
|
|
9928
|
+
async get(key) {
|
|
9929
|
+
return this.memory.get(key);
|
|
9930
|
+
}
|
|
9931
|
+
async delete(keyOrKeys) {
|
|
9932
|
+
if (Array.isArray(keyOrKeys)) {
|
|
9933
|
+
let deleted = 0;
|
|
9934
|
+
for (const key of keyOrKeys) if (this.memory.delete(key)) deleted += 1;
|
|
9935
|
+
return deleted;
|
|
9936
|
+
}
|
|
9937
|
+
return this.memory.delete(keyOrKeys);
|
|
9938
|
+
}
|
|
9939
|
+
async list(options = {}) {
|
|
9940
|
+
let entries = Array.from(this.memory.entries());
|
|
9941
|
+
if (options.prefix !== void 0) entries = entries.filter(([key]) => key.startsWith(options.prefix));
|
|
9942
|
+
if (options.start !== void 0) entries = entries.filter(([key]) => key >= options.start);
|
|
9943
|
+
if (options.startAfter !== void 0) entries = entries.filter(([key]) => key > options.startAfter);
|
|
9944
|
+
if (options.end !== void 0) entries = entries.filter(([key]) => key < options.end);
|
|
9945
|
+
entries.sort(([a], [b]) => a.localeCompare(b));
|
|
9946
|
+
if (options.reverse) entries.reverse();
|
|
9947
|
+
if (options.limit !== void 0) entries = entries.slice(0, options.limit);
|
|
9948
|
+
return new Map(entries);
|
|
9949
|
+
}
|
|
9950
|
+
};
|
|
9951
|
+
var NodeRoomTransport = class {
|
|
9952
|
+
constructor(ServerClass, options = {}) {
|
|
9953
|
+
this.ServerClass = ServerClass;
|
|
9954
|
+
this.records = /* @__PURE__ */ new Map();
|
|
9955
|
+
this.partiesPath = normalizePath(options.partiesPath ?? DEFAULT_PARTIES_PATH);
|
|
9956
|
+
this.env = options.env ?? {};
|
|
9957
|
+
this.rooms = {
|
|
9958
|
+
main: ServerClass,
|
|
9959
|
+
...options.rooms ?? {}
|
|
9960
|
+
};
|
|
9961
|
+
this.storage = options.storage ?? createMemoryNodeRoomStorage();
|
|
9962
|
+
this.externalParties = options.externalParties ?? {};
|
|
9963
|
+
}
|
|
9964
|
+
async fetch(pathOrRequest, init) {
|
|
9965
|
+
const request = typeof pathOrRequest === "string" ? new Request(toLocalUrl(pathOrRequest), init) : pathOrRequest;
|
|
9966
|
+
const parsed = this.parsePartyRequest(request.url);
|
|
9967
|
+
if (!parsed) return new Response("Not Found", { status: 404 });
|
|
9968
|
+
return (await this.getRecord(parsed.namespace, parsed.roomId)).server.onRequest?.(request) ?? new Response("Not Found", { status: 404 });
|
|
9969
|
+
}
|
|
9970
|
+
async handleNodeRequest(req, res, next) {
|
|
9971
|
+
const url = getRequestUrl(req);
|
|
9972
|
+
if (!this.parsePartyRequest(url)) {
|
|
9973
|
+
if (next) {
|
|
9974
|
+
next();
|
|
9975
|
+
return;
|
|
9976
|
+
}
|
|
9977
|
+
await writeNodeResponse(res, new Response("Not Found", { status: 404 }));
|
|
9978
|
+
return;
|
|
9979
|
+
}
|
|
9980
|
+
try {
|
|
9981
|
+
const request = await createWebRequest(req, url);
|
|
9982
|
+
await writeNodeResponse(res, await this.fetch(request));
|
|
9983
|
+
} catch (error) {
|
|
9984
|
+
if (next) {
|
|
9985
|
+
next(error);
|
|
9986
|
+
return;
|
|
9987
|
+
}
|
|
9988
|
+
await writeNodeResponse(res, new Response("Internal Server Error", { status: 500 }));
|
|
9989
|
+
}
|
|
9990
|
+
}
|
|
9991
|
+
handleUpgrade(wsServer, request, socket, head) {
|
|
9992
|
+
const parsed = this.parsePartyRequest(getRequestUrl(request));
|
|
9993
|
+
if (!parsed) {
|
|
9994
|
+
socket.destroy();
|
|
9995
|
+
return;
|
|
9996
|
+
}
|
|
9997
|
+
wsServer.handleUpgrade(request, socket, head, (webSocket) => {
|
|
9998
|
+
this.acceptWebSocket(webSocket, request, parsed).catch(() => {
|
|
9999
|
+
webSocket.close(1011, "Unable to start room connection");
|
|
10000
|
+
});
|
|
10001
|
+
wsServer.emit?.("connection", webSocket, request);
|
|
10002
|
+
});
|
|
10003
|
+
}
|
|
10004
|
+
async acceptWebSocket(webSocket, request, parsedPath) {
|
|
10005
|
+
const url = request instanceof Request ? request.url : getRequestUrl(request);
|
|
10006
|
+
const parsed = parsedPath ?? this.parsePartyRequest(url);
|
|
10007
|
+
if (!parsed) {
|
|
10008
|
+
webSocket.close(1008, "Invalid room path");
|
|
10009
|
+
throw new Error(`Unable to route WebSocket URL: ${url}`);
|
|
10010
|
+
}
|
|
10011
|
+
const record = await this.getRecord(parsed.namespace, parsed.roomId);
|
|
10012
|
+
const connection = new NodeConnection(webSocket, url, getConnectionIdFromUrl(url));
|
|
10013
|
+
const connectRequest = request instanceof Request ? request : await createWebRequest(request, url, false);
|
|
10014
|
+
await record.server.onConnect?.(connection, { request: connectRequest });
|
|
10015
|
+
const onMessage = (data) => {
|
|
10016
|
+
record.server.onMessage?.(normalizeWebSocketMessage(data), connection);
|
|
10017
|
+
};
|
|
10018
|
+
const onClose = () => {
|
|
10019
|
+
record.room.deleteConnection(connection.id, connection);
|
|
10020
|
+
record.server.onClose?.(connection);
|
|
10021
|
+
};
|
|
10022
|
+
const onError = (error) => {
|
|
10023
|
+
record.server.onError?.(connection, error);
|
|
10024
|
+
};
|
|
10025
|
+
webSocket.on("message", onMessage);
|
|
10026
|
+
webSocket.on("close", onClose);
|
|
10027
|
+
webSocket.on("error", onError);
|
|
10028
|
+
record.room.addConnection(connection);
|
|
10029
|
+
return connection;
|
|
10030
|
+
}
|
|
10031
|
+
getRoom(namespace, roomId) {
|
|
10032
|
+
return this.getRecord(namespace, roomId).then((record) => record.room);
|
|
10033
|
+
}
|
|
10034
|
+
getNamespacePath(namespace, roomId) {
|
|
10035
|
+
return `/${[
|
|
10036
|
+
...trimSlashes(this.getPartiesBase()).split("/").slice(0, -1),
|
|
10037
|
+
namespace,
|
|
10038
|
+
encodeURIComponent(roomId)
|
|
10039
|
+
].join("/")}`;
|
|
10040
|
+
}
|
|
10041
|
+
async getRecord(namespace, roomId) {
|
|
10042
|
+
const key = `${namespace}:${roomId}`;
|
|
10043
|
+
const existing = this.records.get(key);
|
|
10044
|
+
if (existing) return existing;
|
|
10045
|
+
const recordPromise = this.createRecord(namespace, roomId);
|
|
10046
|
+
this.records.set(key, recordPromise);
|
|
10047
|
+
try {
|
|
10048
|
+
return await recordPromise;
|
|
10049
|
+
} catch (error) {
|
|
10050
|
+
this.records.delete(key);
|
|
10051
|
+
throw error;
|
|
10052
|
+
}
|
|
10053
|
+
}
|
|
10054
|
+
async createRecord(namespace, roomId) {
|
|
10055
|
+
const ServerClass = this.rooms[namespace] ?? this.ServerClass;
|
|
10056
|
+
const room = new NodeRoom({
|
|
10057
|
+
id: roomId,
|
|
10058
|
+
name: namespace,
|
|
10059
|
+
env: this.env,
|
|
10060
|
+
storage: await this.resolveStorage(namespace, roomId),
|
|
10061
|
+
transport: this
|
|
10062
|
+
});
|
|
10063
|
+
const server = new ServerClass(room);
|
|
10064
|
+
const record = {
|
|
10065
|
+
room,
|
|
10066
|
+
server,
|
|
10067
|
+
started: Promise.resolve(server.onStart?.()).then(() => void 0)
|
|
10068
|
+
};
|
|
10069
|
+
await record.started;
|
|
10070
|
+
return record;
|
|
10071
|
+
}
|
|
10072
|
+
async resolveStorage(namespace, roomId) {
|
|
10073
|
+
if (typeof this.storage === "function") return this.storage(namespace, roomId);
|
|
10074
|
+
return this.storage.getStorage(namespace, roomId);
|
|
10075
|
+
}
|
|
10076
|
+
parsePartyRequest(url) {
|
|
10077
|
+
const requestUrl = new URL(url, "http://localhost");
|
|
10078
|
+
const partiesBase = this.getPartiesBase();
|
|
10079
|
+
const segments = trimSlashes(requestUrl.pathname).split("/");
|
|
10080
|
+
const baseSegments = trimSlashes(partiesBase).split("/").slice(0, -1);
|
|
10081
|
+
if (segments.length < baseSegments.length + 2) return null;
|
|
10082
|
+
for (let index = 0; index < baseSegments.length; index++) if (segments[index] !== baseSegments[index]) return null;
|
|
10083
|
+
const namespace = decodeURIComponent(segments[baseSegments.length]);
|
|
10084
|
+
const roomId = decodeURIComponent(segments[baseSegments.length + 1]);
|
|
10085
|
+
const rest = segments.slice(baseSegments.length + 2).join("/");
|
|
10086
|
+
return {
|
|
10087
|
+
namespace,
|
|
10088
|
+
roomId,
|
|
10089
|
+
restPath: rest ? `/${rest}` : "/"
|
|
10090
|
+
};
|
|
10091
|
+
}
|
|
10092
|
+
getPartiesBase() {
|
|
10093
|
+
return this.partiesPath;
|
|
10094
|
+
}
|
|
10095
|
+
};
|
|
10096
|
+
var NodeRoom = class {
|
|
10097
|
+
constructor(options) {
|
|
9860
10098
|
this.connections = /* @__PURE__ */ new Map();
|
|
9861
|
-
this.
|
|
9862
|
-
this.id = id;
|
|
9863
|
-
this.internalID =
|
|
10099
|
+
this.analytics = {};
|
|
10100
|
+
this.id = options.id;
|
|
10101
|
+
this.internalID = `${options.name}:${options.id}`;
|
|
10102
|
+
this.name = options.name;
|
|
10103
|
+
this.env = options.env;
|
|
10104
|
+
this.storage = options.storage;
|
|
10105
|
+
this.parties = createPartiesContext(options.transport);
|
|
10106
|
+
this.context = {
|
|
10107
|
+
parties: this.parties,
|
|
10108
|
+
ai: {},
|
|
10109
|
+
vectorize: {},
|
|
10110
|
+
analytics: this.analytics,
|
|
10111
|
+
assets: { fetch: async () => null },
|
|
10112
|
+
bindings: {
|
|
10113
|
+
r2: {},
|
|
10114
|
+
kv: {}
|
|
10115
|
+
}
|
|
10116
|
+
};
|
|
10117
|
+
}
|
|
10118
|
+
blockConcurrencyWhile(callback) {
|
|
10119
|
+
return callback();
|
|
9864
10120
|
}
|
|
9865
|
-
|
|
9866
|
-
const
|
|
9867
|
-
const sendPromises = [];
|
|
9868
|
-
for (const [connectionId, connection] of this.connections) if (!except.includes(connectionId)) sendPromises.push(connection.send(data));
|
|
9869
|
-
await Promise.all(sendPromises);
|
|
10121
|
+
broadcast(msg, without = []) {
|
|
10122
|
+
for (const connection of this.connections.values()) if (!without.includes(connection.id)) connection.send(msg);
|
|
9870
10123
|
}
|
|
9871
10124
|
getConnection(id) {
|
|
9872
|
-
|
|
10125
|
+
let connection;
|
|
10126
|
+
for (const current of this.connections.values()) if (current.id === id || current.sessionId === id) connection = current;
|
|
10127
|
+
return connection;
|
|
9873
10128
|
}
|
|
9874
|
-
getConnections(
|
|
9875
|
-
return this.connections.values();
|
|
10129
|
+
getConnections() {
|
|
10130
|
+
return Array.from(this.connections.values());
|
|
9876
10131
|
}
|
|
9877
10132
|
addConnection(connection) {
|
|
9878
10133
|
this.connections.set(connection.id, connection);
|
|
9879
10134
|
}
|
|
9880
|
-
|
|
9881
|
-
|
|
10135
|
+
deleteConnection(id, connection) {
|
|
10136
|
+
if (connection) {
|
|
10137
|
+
this.connections.delete(connection.id);
|
|
10138
|
+
return;
|
|
10139
|
+
}
|
|
10140
|
+
for (const [connectionKey, current] of this.connections) if (current.id === id || current.sessionId === id) this.connections.delete(connectionKey);
|
|
9882
10141
|
}
|
|
9883
|
-
|
|
9884
|
-
|
|
9885
|
-
|
|
9886
|
-
|
|
9887
|
-
|
|
9888
|
-
|
|
9889
|
-
|
|
9890
|
-
|
|
9891
|
-
|
|
9892
|
-
|
|
9893
|
-
|
|
9894
|
-
|
|
9895
|
-
|
|
9896
|
-
|
|
9897
|
-
|
|
10142
|
+
};
|
|
10143
|
+
var NodeConnection = class {
|
|
10144
|
+
constructor(webSocket, uri, sessionId) {
|
|
10145
|
+
this.webSocket = webSocket;
|
|
10146
|
+
this.id = createConnectionId();
|
|
10147
|
+
this.socket = this;
|
|
10148
|
+
this.state = null;
|
|
10149
|
+
this.attachment = null;
|
|
10150
|
+
this.sessionId = sessionId || this.id;
|
|
10151
|
+
this.uri = uri;
|
|
10152
|
+
}
|
|
10153
|
+
send(data) {
|
|
10154
|
+
if (this.webSocket.readyState === void 0 || this.webSocket.readyState === WEBSOCKET_OPEN) this.webSocket.send(data);
|
|
10155
|
+
}
|
|
10156
|
+
close(code, reason) {
|
|
10157
|
+
this.webSocket.close(code, reason);
|
|
10158
|
+
}
|
|
10159
|
+
setState(state) {
|
|
10160
|
+
this.state = typeof state === "function" ? state(this.state) : state;
|
|
10161
|
+
return this.state;
|
|
10162
|
+
}
|
|
10163
|
+
serializeAttachment(attachment) {
|
|
10164
|
+
this.attachment = attachment;
|
|
10165
|
+
}
|
|
10166
|
+
deserializeAttachment() {
|
|
10167
|
+
return this.attachment;
|
|
9898
10168
|
}
|
|
9899
10169
|
};
|
|
10170
|
+
function createPartiesContext(transport) {
|
|
10171
|
+
return new Proxy({}, { get(_target, namespace) {
|
|
10172
|
+
const externalNamespace = transport.externalParties[namespace];
|
|
10173
|
+
if (externalNamespace) return externalNamespace;
|
|
10174
|
+
return { get(roomId) {
|
|
10175
|
+
return {
|
|
10176
|
+
connect: () => {
|
|
10177
|
+
throw new Error("Party stub connect() is not implemented by @signe/room/node");
|
|
10178
|
+
},
|
|
10179
|
+
async socket(pathOrInit, init) {
|
|
10180
|
+
const path = typeof pathOrInit === "string" ? pathOrInit : "/";
|
|
10181
|
+
const requestInit = typeof pathOrInit === "string" ? init : pathOrInit;
|
|
10182
|
+
const request = new Request(toLocalUrl(`${transport.getNamespacePath(namespace, roomId)}${normalizeStubPath(path)}`), requestInit);
|
|
10183
|
+
const pair = createInMemoryWebSocketPair();
|
|
10184
|
+
transport.acceptWebSocket(pair.server, request).catch(() => {
|
|
10185
|
+
pair.client.close(1011, "Unable to start room connection");
|
|
10186
|
+
});
|
|
10187
|
+
return pair.client;
|
|
10188
|
+
},
|
|
10189
|
+
fetch(pathOrInit, init) {
|
|
10190
|
+
const path = typeof pathOrInit === "string" ? pathOrInit : "/";
|
|
10191
|
+
const requestInit = typeof pathOrInit === "string" ? init : pathOrInit;
|
|
10192
|
+
return transport.fetch(`${transport.getNamespacePath(namespace, roomId)}${normalizeStubPath(path)}`, requestInit);
|
|
10193
|
+
}
|
|
10194
|
+
};
|
|
10195
|
+
} };
|
|
10196
|
+
} });
|
|
10197
|
+
}
|
|
10198
|
+
function createInMemoryWebSocketPair() {
|
|
10199
|
+
const client = new InMemoryWebSocket();
|
|
10200
|
+
const server = new InMemoryWebSocket();
|
|
10201
|
+
client.setPeer(server);
|
|
10202
|
+
server.setPeer(client);
|
|
10203
|
+
return {
|
|
10204
|
+
client,
|
|
10205
|
+
server
|
|
10206
|
+
};
|
|
10207
|
+
}
|
|
10208
|
+
var InMemoryWebSocket = class {
|
|
10209
|
+
constructor() {
|
|
10210
|
+
this.readyState = WEBSOCKET_OPEN;
|
|
10211
|
+
this.emitter = new EventEmitter();
|
|
10212
|
+
}
|
|
10213
|
+
setPeer(peer) {
|
|
10214
|
+
this.peer = peer;
|
|
10215
|
+
}
|
|
10216
|
+
send(data, cb) {
|
|
10217
|
+
if (this.readyState !== WEBSOCKET_OPEN || this.peer?.readyState !== WEBSOCKET_OPEN) {
|
|
10218
|
+
cb?.(/* @__PURE__ */ new Error("WebSocket is not open"));
|
|
10219
|
+
return;
|
|
10220
|
+
}
|
|
10221
|
+
queueMicrotask(() => {
|
|
10222
|
+
this.peer?.emitMessage(data);
|
|
10223
|
+
cb?.();
|
|
10224
|
+
});
|
|
10225
|
+
}
|
|
10226
|
+
close(code, reason) {
|
|
10227
|
+
if (this.readyState !== WEBSOCKET_OPEN) return;
|
|
10228
|
+
this.readyState = 3;
|
|
10229
|
+
this.emitter.emit("close", code, reason);
|
|
10230
|
+
if (this.peer?.readyState === WEBSOCKET_OPEN) {
|
|
10231
|
+
this.peer.readyState = 3;
|
|
10232
|
+
this.peer.emitter.emit("close", code, reason);
|
|
10233
|
+
}
|
|
10234
|
+
}
|
|
10235
|
+
on(event, listener) {
|
|
10236
|
+
this.emitter.on(event, listener);
|
|
10237
|
+
return this;
|
|
10238
|
+
}
|
|
10239
|
+
off(event, listener) {
|
|
10240
|
+
this.emitter.off(event, listener);
|
|
10241
|
+
return this;
|
|
10242
|
+
}
|
|
10243
|
+
removeListener(event, listener) {
|
|
10244
|
+
this.emitter.removeListener(event, listener);
|
|
10245
|
+
return this;
|
|
10246
|
+
}
|
|
10247
|
+
addEventListener(type, listener) {
|
|
10248
|
+
if (type === "message") {
|
|
10249
|
+
this.on("message", (data) => listener({ data }));
|
|
10250
|
+
return;
|
|
10251
|
+
}
|
|
10252
|
+
this.on(type, (event) => listener(event));
|
|
10253
|
+
}
|
|
10254
|
+
emitMessage(data) {
|
|
10255
|
+
if (this.readyState === WEBSOCKET_OPEN) this.emitter.emit("message", data);
|
|
10256
|
+
}
|
|
10257
|
+
};
|
|
10258
|
+
async function createWebRequest(req, url, includeBody = true) {
|
|
10259
|
+
const headers = new Headers();
|
|
10260
|
+
for (const [key, value] of Object.entries(req.headers)) if (Array.isArray(value)) for (const item of value) headers.append(key, item);
|
|
10261
|
+
else if (value !== void 0) headers.set(key, String(value));
|
|
10262
|
+
const method = req.method ?? "GET";
|
|
10263
|
+
const body = includeBody && !["GET", "HEAD"].includes(method) ? await readIncomingBody(req) : void 0;
|
|
10264
|
+
return new Request(url, {
|
|
10265
|
+
method,
|
|
10266
|
+
headers,
|
|
10267
|
+
body
|
|
10268
|
+
});
|
|
10269
|
+
}
|
|
10270
|
+
async function readIncomingBody(req) {
|
|
10271
|
+
const chunks = [];
|
|
10272
|
+
for await (const chunk of req) if (typeof chunk === "string") chunks.push(new TextEncoder().encode(chunk));
|
|
10273
|
+
else chunks.push(chunk);
|
|
10274
|
+
const size = chunks.reduce((total, chunk) => total + chunk.byteLength, 0);
|
|
10275
|
+
const body = new Uint8Array(size);
|
|
10276
|
+
let offset = 0;
|
|
10277
|
+
for (const chunk of chunks) {
|
|
10278
|
+
body.set(chunk, offset);
|
|
10279
|
+
offset += chunk.byteLength;
|
|
10280
|
+
}
|
|
10281
|
+
return body;
|
|
10282
|
+
}
|
|
10283
|
+
async function writeNodeResponse(res, response) {
|
|
10284
|
+
res.statusCode = response.status;
|
|
10285
|
+
response.headers.forEach((value, key) => {
|
|
10286
|
+
res.setHeader(key, value);
|
|
10287
|
+
});
|
|
10288
|
+
const body = new Uint8Array(await response.arrayBuffer());
|
|
10289
|
+
res.end(body);
|
|
10290
|
+
}
|
|
10291
|
+
function getRequestUrl(req) {
|
|
10292
|
+
return `${req.headers["x-forwarded-proto"] ?? "http"}://${req.headers.host ?? "localhost"}${req.url ?? "/"}`;
|
|
10293
|
+
}
|
|
10294
|
+
function normalizeWebSocketMessage(data) {
|
|
10295
|
+
if (typeof data === "string") return data;
|
|
10296
|
+
if (data instanceof ArrayBuffer) return new TextDecoder().decode(data);
|
|
10297
|
+
if (ArrayBuffer.isView(data)) return new TextDecoder().decode(data);
|
|
10298
|
+
return String(data);
|
|
10299
|
+
}
|
|
10300
|
+
function normalizePath(path) {
|
|
10301
|
+
return `/${trimSlashes(path)}`;
|
|
10302
|
+
}
|
|
10303
|
+
function normalizeStubPath(path) {
|
|
10304
|
+
if (!path || path === "/") return "";
|
|
10305
|
+
return path.startsWith("/") ? path : `/${path}`;
|
|
10306
|
+
}
|
|
10307
|
+
function toLocalUrl(path) {
|
|
10308
|
+
return path.startsWith("http://") || path.startsWith("https://") ? path : `http://localhost${path.startsWith("/") ? path : `/${path}`}`;
|
|
10309
|
+
}
|
|
10310
|
+
function getConnectionIdFromUrl(url) {
|
|
10311
|
+
return new URL(url).searchParams.get("id")?.trim() || void 0;
|
|
10312
|
+
}
|
|
10313
|
+
function trimSlashes(value) {
|
|
10314
|
+
return value.replace(/^\/+|\/+$/g, "");
|
|
10315
|
+
}
|
|
10316
|
+
function getStorageKey(namespace, roomId) {
|
|
10317
|
+
return `${encodeURIComponent(namespace)}:${encodeURIComponent(roomId)}`;
|
|
10318
|
+
}
|
|
10319
|
+
function cloneStorageValue(value) {
|
|
10320
|
+
if (typeof structuredClone === "function") try {
|
|
10321
|
+
return structuredClone(value);
|
|
10322
|
+
} catch {
|
|
10323
|
+
return value;
|
|
10324
|
+
}
|
|
10325
|
+
return value;
|
|
10326
|
+
}
|
|
10327
|
+
function createConnectionId() {
|
|
10328
|
+
return Math.random().toString(36).slice(2, 12);
|
|
10329
|
+
}
|
|
9900
10330
|
function normalizePathPrefix(path, fallback) {
|
|
9901
10331
|
const trimmed = (path || fallback).trim();
|
|
9902
10332
|
if (!trimmed) return fallback;
|
|
@@ -10001,25 +10431,12 @@ function resolveUrlFromSocketRequest(request) {
|
|
|
10001
10431
|
url
|
|
10002
10432
|
};
|
|
10003
10433
|
}
|
|
10004
|
-
function
|
|
10005
|
-
|
|
10006
|
-
|
|
10007
|
-
|
|
10008
|
-
}
|
|
10009
|
-
return
|
|
10010
|
-
request: {
|
|
10011
|
-
headers: {
|
|
10012
|
-
has: (name) => normalizedHeaders.has(name.toLowerCase()),
|
|
10013
|
-
get: (name) => normalizedHeaders.get(name.toLowerCase()),
|
|
10014
|
-
entries: () => normalizedHeaders.entries(),
|
|
10015
|
-
keys: () => normalizedHeaders.keys(),
|
|
10016
|
-
values: () => normalizedHeaders.values()
|
|
10017
|
-
},
|
|
10018
|
-
method,
|
|
10019
|
-
url: url.toString()
|
|
10020
|
-
},
|
|
10021
|
-
url
|
|
10022
|
-
};
|
|
10434
|
+
function ensureNodeSessionIdQuery(url) {
|
|
10435
|
+
if (!url.searchParams.has("id")) {
|
|
10436
|
+
const partySocketId = url.searchParams.get("_pk");
|
|
10437
|
+
if (partySocketId) url.searchParams.set("id", partySocketId);
|
|
10438
|
+
}
|
|
10439
|
+
return url;
|
|
10023
10440
|
}
|
|
10024
10441
|
var RpgServerTransport = class {
|
|
10025
10442
|
constructor(serverModule, options = {}) {
|
|
@@ -10032,10 +10449,33 @@ var RpgServerTransport = class {
|
|
|
10032
10449
|
this.mapUpdateToken = resolveMapUpdateToken(options.mapUpdateToken);
|
|
10033
10450
|
this.partiesPath = normalizePathPrefix(options.partiesPath || "/parties/main", "/parties/main");
|
|
10034
10451
|
this.tiledBasePaths = options.tiledBasePaths;
|
|
10452
|
+
const owner = this;
|
|
10453
|
+
class RpgNodeServer extends serverModule {
|
|
10454
|
+
constructor(room) {
|
|
10455
|
+
super(room);
|
|
10456
|
+
owner.rooms.set(room.id, room);
|
|
10457
|
+
owner.servers.set(room.id, this);
|
|
10458
|
+
console.log(`Created new server instance for room: ${room.id}`);
|
|
10459
|
+
}
|
|
10460
|
+
async onStart() {
|
|
10461
|
+
await owner.ensureServerContext();
|
|
10462
|
+
await super.onStart?.();
|
|
10463
|
+
const roomId = this.room?.id;
|
|
10464
|
+
console.log(`Server started for room: ${roomId}`);
|
|
10465
|
+
if (owner.initializeMaps && roomId) await updateMap(roomId, this, {
|
|
10466
|
+
host: owner.lastKnownHost,
|
|
10467
|
+
mapUpdateToken: owner.mapUpdateToken,
|
|
10468
|
+
tiledBasePaths: owner.tiledBasePaths
|
|
10469
|
+
});
|
|
10470
|
+
}
|
|
10471
|
+
}
|
|
10472
|
+
this.transport = createNodeRoomTransport(RpgNodeServer, {
|
|
10473
|
+
partiesPath: this.partiesPath,
|
|
10474
|
+
storage: createMemoryNodeRoomStorage()
|
|
10475
|
+
});
|
|
10035
10476
|
}
|
|
10036
10477
|
async ensureServerContext() {
|
|
10037
10478
|
if (this.serverContextInitialized) return;
|
|
10038
|
-
setInject(context);
|
|
10039
10479
|
await injector(context, [provideServerModules([])]);
|
|
10040
10480
|
this.serverContextInitialized = true;
|
|
10041
10481
|
}
|
|
@@ -10047,52 +10487,17 @@ var RpgServerTransport = class {
|
|
|
10047
10487
|
}
|
|
10048
10488
|
async ensureRoomAndServer(roomId, host) {
|
|
10049
10489
|
if (host) this.lastKnownHost = host;
|
|
10050
|
-
|
|
10051
|
-
|
|
10052
|
-
|
|
10053
|
-
|
|
10054
|
-
console.log(`Created new room: ${roomId}`);
|
|
10055
|
-
}
|
|
10056
|
-
let rpgServer = this.servers.get(roomId);
|
|
10057
|
-
if (!rpgServer) {
|
|
10058
|
-
await this.ensureServerContext();
|
|
10059
|
-
rpgServer = new this.serverModule(room);
|
|
10060
|
-
this.servers.set(roomId, rpgServer);
|
|
10061
|
-
console.log(`Created new server instance for room: ${roomId}`);
|
|
10062
|
-
if (typeof rpgServer.onStart === "function") try {
|
|
10063
|
-
await rpgServer.onStart();
|
|
10064
|
-
console.log(`Server started for room: ${roomId}`);
|
|
10065
|
-
} catch (error) {
|
|
10066
|
-
console.error(`Error starting server for room ${roomId}:`, error);
|
|
10067
|
-
}
|
|
10068
|
-
if (this.initializeMaps) await updateMap(roomId, rpgServer, {
|
|
10069
|
-
host: host || this.lastKnownHost,
|
|
10070
|
-
mapUpdateToken: this.mapUpdateToken,
|
|
10071
|
-
tiledBasePaths: this.tiledBasePaths
|
|
10072
|
-
});
|
|
10073
|
-
}
|
|
10074
|
-
room.context.parties = this.buildPartiesContext();
|
|
10490
|
+
await this.transport.getRoom("main", roomId);
|
|
10491
|
+
const room = this.rooms.get(roomId);
|
|
10492
|
+
const rpgServer = this.servers.get(roomId);
|
|
10493
|
+
if (!room || !rpgServer) throw new Error(`Unable to initialize room: ${roomId}`);
|
|
10075
10494
|
return {
|
|
10076
10495
|
room,
|
|
10077
10496
|
rpgServer
|
|
10078
10497
|
};
|
|
10079
10498
|
}
|
|
10080
|
-
buildPartiesContext() {
|
|
10081
|
-
return { main: { get: async (targetRoomId) => {
|
|
10082
|
-
return { fetch: async (path, init) => {
|
|
10083
|
-
const method = (init?.method || "GET").toUpperCase();
|
|
10084
|
-
const headers = toHeaders(init?.headers);
|
|
10085
|
-
const requestPath = path.startsWith("/") ? path : `/${path}`;
|
|
10086
|
-
let bodyText = "";
|
|
10087
|
-
if (typeof init?.body === "string") bodyText = init.body;
|
|
10088
|
-
else if (typeof init?.body !== "undefined") bodyText = JSON.stringify(init.body);
|
|
10089
|
-
return this.dispatchRoomRequest(targetRoomId, createRequestLike(`http://localhost${this.partiesPath}/${targetRoomId}${requestPath}`, method, headers, bodyText), this.lastKnownHost);
|
|
10090
|
-
} };
|
|
10091
|
-
} } };
|
|
10092
|
-
}
|
|
10093
10499
|
async dispatchRoomRequest(roomId, requestLike, host) {
|
|
10094
|
-
const {
|
|
10095
|
-
room.context.parties = this.buildPartiesContext();
|
|
10500
|
+
const { rpgServer } = await this.ensureRoomAndServer(roomId, host);
|
|
10096
10501
|
return normalizeEngineResponse(await rpgServer.onRequest?.(requestLike));
|
|
10097
10502
|
}
|
|
10098
10503
|
async fetch(request, init) {
|
|
@@ -10125,8 +10530,7 @@ var RpgServerTransport = class {
|
|
|
10125
10530
|
next?.();
|
|
10126
10531
|
return false;
|
|
10127
10532
|
}
|
|
10128
|
-
|
|
10129
|
-
await sendNodeResponse(res, await this.dispatchRoomRequest(route.roomId, createRequestLike(normalizedUrl.toString(), (req.method || "GET").toUpperCase(), headers, bodyText), host));
|
|
10533
|
+
await sendNodeResponse(res, await this.dispatchRoomRequest(route.roomId, createRequestLike(normalizedUrl.toString(), (req.method || "GET").toUpperCase(), headers, await readNodeBody(req)), host));
|
|
10130
10534
|
return true;
|
|
10131
10535
|
} catch (error) {
|
|
10132
10536
|
console.error("Error handling RPG-JS request:", error);
|
|
@@ -10144,51 +10548,17 @@ var RpgServerTransport = class {
|
|
|
10144
10548
|
console.log(`WebSocket upgrade request: ${normalizedRequest.url.pathname}`);
|
|
10145
10549
|
const queryParams = Object.fromEntries(normalizedRequest.url.searchParams.entries());
|
|
10146
10550
|
console.log(`Room: ${route.roomId}, Query params:`, queryParams);
|
|
10147
|
-
|
|
10148
|
-
|
|
10149
|
-
const connection =
|
|
10150
|
-
|
|
10151
|
-
|
|
10152
|
-
|
|
10153
|
-
|
|
10154
|
-
if (isClosed) return;
|
|
10155
|
-
isClosed = true;
|
|
10156
|
-
if (logMessage) console.log(logMessage);
|
|
10157
|
-
if (error) console.error("WebSocket error:", error);
|
|
10158
|
-
room.removeConnection(connection.id);
|
|
10159
|
-
await rpgServer.onClose?.(connection);
|
|
10160
|
-
};
|
|
10161
|
-
ws.on("message", async (data) => {
|
|
10162
|
-
try {
|
|
10163
|
-
const rawMessage = typeof data === "string" ? data : data.toString();
|
|
10164
|
-
if (PartyConnection.packetLossEnabled && PartyConnection.packetLossRate > 0) {
|
|
10165
|
-
if (!PartyConnection.packetLossFilter || rawMessage.includes(PartyConnection.packetLossFilter)) {
|
|
10166
|
-
if (Math.random() < PartyConnection.packetLossRate) {
|
|
10167
|
-
console.log(`\x1b[31m[PACKET LOSS]\x1b[0m Connection ${connection.id}: Server dropped an incoming packet (${(PartyConnection.packetLossRate * 100).toFixed(1)}% loss rate)`);
|
|
10168
|
-
console.log(`\x1b[33m[PACKET DATA]\x1b[0m ${rawMessage.slice(0, 100)}${rawMessage.length > 100 ? "..." : ""}`);
|
|
10169
|
-
return;
|
|
10170
|
-
}
|
|
10171
|
-
}
|
|
10172
|
-
}
|
|
10173
|
-
connection.bufferIncoming(rawMessage, async (batch) => {
|
|
10174
|
-
for (const message of batch) await rpgServer.onMessage?.(message, connection);
|
|
10175
|
-
});
|
|
10176
|
-
} catch (error) {
|
|
10177
|
-
console.error("Error processing WebSocket message:", error);
|
|
10178
|
-
}
|
|
10179
|
-
});
|
|
10180
|
-
ws.on("close", () => {
|
|
10181
|
-
cleanup(`WebSocket connection closed: ${connection.id} from room: ${route.roomId}`);
|
|
10182
|
-
});
|
|
10183
|
-
ws.on("error", (error) => {
|
|
10184
|
-
cleanup(void 0, error);
|
|
10185
|
-
});
|
|
10186
|
-
if (typeof rpgServer.onConnect === "function") await rpgServer.onConnect(connection, createConnectionContext(normalizedRequest.url, normalizedRequest.headers, normalizedRequest.method));
|
|
10187
|
-
await connection.send({
|
|
10551
|
+
this.lastKnownHost = normalizedRequest.url.host;
|
|
10552
|
+
ensureNodeSessionIdQuery(normalizedRequest.url);
|
|
10553
|
+
const connection = await this.transport.acceptWebSocket(ws, new Request(normalizedRequest.url.toString(), {
|
|
10554
|
+
headers: normalizedRequest.headers,
|
|
10555
|
+
method: normalizedRequest.method || "GET"
|
|
10556
|
+
}));
|
|
10557
|
+
await connection.send(JSON.stringify({
|
|
10188
10558
|
type: "connected",
|
|
10189
10559
|
id: connection.id,
|
|
10190
10560
|
message: "Connected to RPG-JS server"
|
|
10191
|
-
});
|
|
10561
|
+
}));
|
|
10192
10562
|
return true;
|
|
10193
10563
|
} catch (error) {
|
|
10194
10564
|
console.error("Error establishing WebSocket connection:", error);
|
|
@@ -10198,7 +10568,11 @@ var RpgServerTransport = class {
|
|
|
10198
10568
|
}
|
|
10199
10569
|
async handleUpgrade(wsServer, request, socket, head) {
|
|
10200
10570
|
const host = toHeaders(request.headers).get("host") || "localhost";
|
|
10201
|
-
|
|
10571
|
+
const url = new URL(request.url || "/", `http://${host}`);
|
|
10572
|
+
if (!parseSocketRoute(url.pathname, this.partiesPath)) return false;
|
|
10573
|
+
ensureNodeSessionIdQuery(url);
|
|
10574
|
+
request.url = `${url.pathname}${url.search}`;
|
|
10575
|
+
this.lastKnownHost = host;
|
|
10202
10576
|
wsServer.handleUpgrade(request, socket, head, (ws) => {
|
|
10203
10577
|
this.acceptWebSocket(ws, request);
|
|
10204
10578
|
});
|
|
@@ -10210,7 +10584,7 @@ function createRpgServerTransport(serverModule, options) {
|
|
|
10210
10584
|
}
|
|
10211
10585
|
//#endregion
|
|
10212
10586
|
//#region src/server-plugin.ts
|
|
10213
|
-
async function importWebSocketServer() {
|
|
10587
|
+
async function importWebSocketServer$1() {
|
|
10214
10588
|
if (typeof process === "undefined" || !process.versions?.node) {
|
|
10215
10589
|
console.warn("Not in Node.js environment, WebSocket server not available");
|
|
10216
10590
|
return null;
|
|
@@ -10231,7 +10605,7 @@ function serverPlugin(serverModule) {
|
|
|
10231
10605
|
name: "server-plugin",
|
|
10232
10606
|
async configureServer(server) {
|
|
10233
10607
|
try {
|
|
10234
|
-
const WebSocketServerClass = await importWebSocketServer();
|
|
10608
|
+
const WebSocketServerClass = await importWebSocketServer$1();
|
|
10235
10609
|
if (WebSocketServerClass) {
|
|
10236
10610
|
wsServer = new WebSocketServerClass({ noServer: true });
|
|
10237
10611
|
console.log("WebSocket server initialized successfully");
|
|
@@ -10432,6 +10806,797 @@ function rpgjs({ server, entryPoints }) {
|
|
|
10432
10806
|
];
|
|
10433
10807
|
}
|
|
10434
10808
|
//#endregion
|
|
10435
|
-
|
|
10809
|
+
//#region src/compatibility-v4/flag-transform.ts
|
|
10810
|
+
function flagTransform(options = {}) {
|
|
10811
|
+
function getImportSide(importer) {
|
|
10812
|
+
if (importer?.includes("?server") || importer?.includes("server-entry")) return "server";
|
|
10813
|
+
if (importer?.includes("?client") || importer?.includes("client-entry") || importer?.includes("standalone-entry")) return "client";
|
|
10814
|
+
return options.side ?? "client";
|
|
10815
|
+
}
|
|
10816
|
+
function hasFlag(id, flag) {
|
|
10817
|
+
return id.endsWith(`?${flag}`) || id.includes(`?${flag}&`);
|
|
10818
|
+
}
|
|
10819
|
+
function getSideFromId(id) {
|
|
10820
|
+
return id.match(/[?&]side=(client|server)/)?.[1] === "server" ? "server" : "client";
|
|
10821
|
+
}
|
|
10822
|
+
return {
|
|
10823
|
+
name: "rpgjs-v4-flag-transform",
|
|
10824
|
+
async resolveId(source, importer, resolveOptions) {
|
|
10825
|
+
for (const flag of [
|
|
10826
|
+
"client!",
|
|
10827
|
+
"server!",
|
|
10828
|
+
"rpg!",
|
|
10829
|
+
"mmorpg!",
|
|
10830
|
+
"production!",
|
|
10831
|
+
"development!"
|
|
10832
|
+
]) {
|
|
10833
|
+
if (!source.startsWith(flag)) continue;
|
|
10834
|
+
const id = source.slice(flag.length);
|
|
10835
|
+
const resolution = await this.resolve(id, importer, {
|
|
10836
|
+
skipSelf: true,
|
|
10837
|
+
...resolveOptions
|
|
10838
|
+
});
|
|
10839
|
+
if (!resolution) return null;
|
|
10840
|
+
const importSide = getImportSide(importer);
|
|
10841
|
+
return {
|
|
10842
|
+
...resolution,
|
|
10843
|
+
id: `${resolution.id}?${flag.slice(0, -1)}&side=${importSide}`
|
|
10844
|
+
};
|
|
10845
|
+
}
|
|
10846
|
+
return null;
|
|
10847
|
+
},
|
|
10848
|
+
transform(code, id) {
|
|
10849
|
+
const { mode = "development", type = "mmorpg" } = options;
|
|
10850
|
+
const side = getSideFromId(id);
|
|
10851
|
+
if (mode === "test") return {
|
|
10852
|
+
code,
|
|
10853
|
+
map: null
|
|
10854
|
+
};
|
|
10855
|
+
if (hasFlag(id, side === "client" ? "server" : "client") && type !== "rpg") return {
|
|
10856
|
+
code: "export default null;",
|
|
10857
|
+
map: null
|
|
10858
|
+
};
|
|
10859
|
+
if (hasFlag(id, "production") && mode !== "production" || hasFlag(id, "development") && mode !== "development" || hasFlag(id, "rpg") && type !== "rpg" || hasFlag(id, "mmorpg") && type !== "mmorpg") return {
|
|
10860
|
+
code: "export default null;",
|
|
10861
|
+
map: null
|
|
10862
|
+
};
|
|
10863
|
+
return {
|
|
10864
|
+
code,
|
|
10865
|
+
map: null
|
|
10866
|
+
};
|
|
10867
|
+
}
|
|
10868
|
+
};
|
|
10869
|
+
}
|
|
10870
|
+
//#endregion
|
|
10871
|
+
//#region src/compatibility-v4/require-transform.ts
|
|
10872
|
+
var traverse = _traverse.default ?? _traverse;
|
|
10873
|
+
var generate = _generate.default ?? _generate;
|
|
10874
|
+
function readStaticRequireArg(arg, ast) {
|
|
10875
|
+
if (!arg) return "";
|
|
10876
|
+
if (arg.type === "StringLiteral") return arg.value;
|
|
10877
|
+
if (arg.type === "Identifier") {
|
|
10878
|
+
let value = "";
|
|
10879
|
+
traverse(ast, { VariableDeclarator(path) {
|
|
10880
|
+
if (path.node.id?.name === arg.name && path.node.init?.type === "StringLiteral") value = path.node.init.value;
|
|
10881
|
+
} });
|
|
10882
|
+
return value;
|
|
10883
|
+
}
|
|
10884
|
+
if (arg.type === "BinaryExpression" && arg.operator === "+") {
|
|
10885
|
+
const left = readStaticRequireArg(arg.left, ast);
|
|
10886
|
+
const right = readStaticRequireArg(arg.right, ast);
|
|
10887
|
+
return left && right ? left + right : "";
|
|
10888
|
+
}
|
|
10889
|
+
return "";
|
|
10890
|
+
}
|
|
10891
|
+
function vitePluginRequire() {
|
|
10892
|
+
return {
|
|
10893
|
+
name: "rpgjs-v4-require-transform",
|
|
10894
|
+
transform(code, id) {
|
|
10895
|
+
if (!/(.jsx?|.tsx?)(\?.*)?$/.test(id) || !/^(?!.*node_modules(?:\/|\\)(?!rpgjs-|@rpgjs)).*$/.test(id)) return {
|
|
10896
|
+
code,
|
|
10897
|
+
map: null
|
|
10898
|
+
};
|
|
10899
|
+
const ast = parser.parse(code, {
|
|
10900
|
+
sourceType: "module",
|
|
10901
|
+
plugins: [
|
|
10902
|
+
"typescript",
|
|
10903
|
+
"jsx",
|
|
10904
|
+
"decorators-legacy",
|
|
10905
|
+
"classProperties"
|
|
10906
|
+
]
|
|
10907
|
+
});
|
|
10908
|
+
let changed = false;
|
|
10909
|
+
traverse(ast, { CallExpression(path) {
|
|
10910
|
+
if (!path.node.callee || path.node.callee.type !== "Identifier" || path.node.callee.name !== "require") return;
|
|
10911
|
+
const request = readStaticRequireArg(path.node.arguments[0], ast);
|
|
10912
|
+
if (!request) return;
|
|
10913
|
+
const variableName = `__rpgjs_v4_require_${path.scope.generateUidIdentifier("asset").name}`;
|
|
10914
|
+
ast.program.body.unshift(importDeclaration([importDefaultSpecifier(identifier(variableName))], stringLiteral(request)));
|
|
10915
|
+
path.replaceWith(identifier(variableName));
|
|
10916
|
+
changed = true;
|
|
10917
|
+
} });
|
|
10918
|
+
if (!changed) return {
|
|
10919
|
+
code,
|
|
10920
|
+
map: null
|
|
10921
|
+
};
|
|
10922
|
+
return {
|
|
10923
|
+
code: generate(ast, {}).code,
|
|
10924
|
+
map: null
|
|
10925
|
+
};
|
|
10926
|
+
}
|
|
10927
|
+
};
|
|
10928
|
+
}
|
|
10929
|
+
//#endregion
|
|
10930
|
+
//#region src/compatibility-v4/utils.ts
|
|
10931
|
+
function dedent(strings, ...values) {
|
|
10932
|
+
const fullString = strings.reduce((acc, str, i) => acc + str + (values[i] ?? ""), "");
|
|
10933
|
+
const lines = fullString.split("\n");
|
|
10934
|
+
let minIndent = Infinity;
|
|
10935
|
+
for (const line of lines) {
|
|
10936
|
+
if (!line.trim()) continue;
|
|
10937
|
+
minIndent = Math.min(minIndent, line.match(/^\s*/)?.[0].length ?? 0);
|
|
10938
|
+
}
|
|
10939
|
+
if (minIndent === Infinity) return fullString.trim();
|
|
10940
|
+
return lines.map((line) => line.trim() ? line.slice(minIndent) : line).join("\n").trim();
|
|
10941
|
+
}
|
|
10942
|
+
function warn(message) {
|
|
10943
|
+
console.warn(`[RPG-JS v4 compatibility] ${message}`);
|
|
10944
|
+
}
|
|
10945
|
+
function toPosix(value) {
|
|
10946
|
+
return value.replace(/\\/g, "/");
|
|
10947
|
+
}
|
|
10948
|
+
function formatVariableName(value) {
|
|
10949
|
+
return value.replace(/\./g, "").replace(/[.@/\\ -]/g, "_").replace(/[^A-Za-z0-9_$]/g, "_");
|
|
10950
|
+
}
|
|
10951
|
+
function transformPathIfModule(moduleName) {
|
|
10952
|
+
if (moduleName.startsWith("@rpgjs") || moduleName.startsWith("rpgjs-")) return path.join("node_modules", moduleName);
|
|
10953
|
+
return moduleName;
|
|
10954
|
+
}
|
|
10955
|
+
function resolveModuleImport(moduleName) {
|
|
10956
|
+
return moduleName.replace(/^\.\//, "");
|
|
10957
|
+
}
|
|
10958
|
+
function getAllFiles(dirPath) {
|
|
10959
|
+
if (!fs.existsSync(dirPath)) return [];
|
|
10960
|
+
const files = [];
|
|
10961
|
+
const dirents = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
10962
|
+
for (const dirent of dirents) {
|
|
10963
|
+
const fullPath = path.join(dirPath, dirent.name);
|
|
10964
|
+
if (dirent.isDirectory()) files.push(...getAllFiles(fullPath));
|
|
10965
|
+
else files.push(fullPath);
|
|
10966
|
+
}
|
|
10967
|
+
return files;
|
|
10968
|
+
}
|
|
10969
|
+
function importPathForFile(file, root) {
|
|
10970
|
+
const srcPath = path.join(root, "src");
|
|
10971
|
+
if (file.startsWith(srcPath + path.sep)) return `@/${toPosix(path.relative(srcPath, file))}`;
|
|
10972
|
+
return `./${toPosix(path.relative(root, file))}`;
|
|
10973
|
+
}
|
|
10974
|
+
function importString(modulePath, fileName, variableName = fileName, projectRoot = process.cwd()) {
|
|
10975
|
+
const file = path.resolve(projectRoot, transformPathIfModule(modulePath), `${fileName}.ts`);
|
|
10976
|
+
if (!fs.existsSync(file)) return "";
|
|
10977
|
+
return `import ${variableName} from '${importPathForFile(file, projectRoot)}'`;
|
|
10978
|
+
}
|
|
10979
|
+
function searchFolderAndTransformToImportString(folderPath, modulePath, extensionFilter, returnCb, options, projectRoot = process.cwd()) {
|
|
10980
|
+
const folder = path.resolve(projectRoot, transformPathIfModule(modulePath), folderPath);
|
|
10981
|
+
if (!fs.existsSync(folder)) return {
|
|
10982
|
+
variablesString: "",
|
|
10983
|
+
importString: "",
|
|
10984
|
+
folder: "",
|
|
10985
|
+
relativePath: ""
|
|
10986
|
+
};
|
|
10987
|
+
const extensions = Array.isArray(extensionFilter) ? extensionFilter : [extensionFilter];
|
|
10988
|
+
let importString = "";
|
|
10989
|
+
let relativePath = "";
|
|
10990
|
+
return {
|
|
10991
|
+
variablesString: getAllFiles(folder).filter((file) => extensions.some((ext) => file.endsWith(ext))).filter((file) => options?.customFilter ? options.customFilter(file) : true).map((file) => {
|
|
10992
|
+
const importPath = importPathForFile(file, projectRoot);
|
|
10993
|
+
const variableName = formatVariableName(importPath);
|
|
10994
|
+
relativePath = importPath;
|
|
10995
|
+
importString += `\nimport ${variableName} from '${importPath}'`;
|
|
10996
|
+
return returnCb ? returnCb(importPath, variableName, file) : variableName;
|
|
10997
|
+
}).join(","),
|
|
10998
|
+
importString,
|
|
10999
|
+
folder,
|
|
11000
|
+
relativePath
|
|
11001
|
+
};
|
|
11002
|
+
}
|
|
11003
|
+
function replaceEnvVars(obj, envs) {
|
|
11004
|
+
if (obj == null) return obj;
|
|
11005
|
+
if (typeof obj === "string" && obj.startsWith("$ENV:")) return envs[obj.slice(5)];
|
|
11006
|
+
if (Array.isArray(obj)) return obj.map((item) => replaceEnvVars(item, envs));
|
|
11007
|
+
if (typeof obj === "object") return Object.fromEntries(Object.entries(obj).map(([key, value]) => [key, replaceEnvVars(value, envs)]));
|
|
11008
|
+
return obj;
|
|
11009
|
+
}
|
|
11010
|
+
//#endregion
|
|
11011
|
+
//#region src/compatibility-v4/load-config-file.ts
|
|
11012
|
+
function loadConfigFileSync(mode = "development", root = process.cwd()) {
|
|
11013
|
+
const tomlFile = path.resolve(root, "rpg.toml");
|
|
11014
|
+
const jsonFile = path.resolve(root, "rpg.json");
|
|
11015
|
+
let config = {};
|
|
11016
|
+
if (fs.existsSync(tomlFile)) config = toml.parse(fs.readFileSync(tomlFile, "utf8"));
|
|
11017
|
+
else if (fs.existsSync(jsonFile)) config = JSON.parse(fs.readFileSync(jsonFile, "utf8"));
|
|
11018
|
+
config = replaceEnvVars(config, loadEnv(mode, root, ""));
|
|
11019
|
+
config.autostart = config.autostart ?? true;
|
|
11020
|
+
config.modulesRoot = config.modulesRoot ?? "";
|
|
11021
|
+
config.compilerOptions ??= {};
|
|
11022
|
+
config.compilerOptions.build ??= {};
|
|
11023
|
+
config.compilerOptions.build.pwaEnabled ??= true;
|
|
11024
|
+
config.compilerOptions.build.outputDir ??= "dist";
|
|
11025
|
+
if (config.modules) config.modules = config.modules.map((module) => {
|
|
11026
|
+
if (module.startsWith(".")) return "./" + path.join(config.modulesRoot, module);
|
|
11027
|
+
return module;
|
|
11028
|
+
});
|
|
11029
|
+
config.startMap = config.startMap || config.start?.map;
|
|
11030
|
+
return config;
|
|
11031
|
+
}
|
|
11032
|
+
//#endregion
|
|
11033
|
+
//#region src/compatibility-v4/index.ts
|
|
11034
|
+
var MODULE_NAME = "virtual:rpgjs-v4-modules";
|
|
11035
|
+
var CLIENT_CONFIG = "virtual:rpgjs-v4-client-config";
|
|
11036
|
+
var SERVER_ENTRY = "virtual:rpgjs-v4-server-entry";
|
|
11037
|
+
var CLIENT_ENTRY = "virtual:rpgjs-v4-client-entry";
|
|
11038
|
+
var STANDALONE_ENTRY = "virtual:rpgjs-v4-standalone-entry";
|
|
11039
|
+
var LEGACY_MOBILE_GUI = "virtual:rpgjs-v4-legacy-mobile-gui";
|
|
11040
|
+
var LEGACY_DEFAULT_GUI = "virtual:rpgjs-v4-legacy-default-gui";
|
|
11041
|
+
var LEGACY_GAMEPAD = "virtual:rpgjs-v4-legacy-gamepad";
|
|
11042
|
+
var LEGACY_MODULES = {
|
|
11043
|
+
"@rpgjs/mobile-gui": LEGACY_MOBILE_GUI,
|
|
11044
|
+
"@rpgjs/default-gui": LEGACY_DEFAULT_GUI,
|
|
11045
|
+
"@rpgjs/gamepad": LEGACY_GAMEPAD
|
|
11046
|
+
};
|
|
11047
|
+
var TILED_EXTENSIONS = [
|
|
11048
|
+
".tmx",
|
|
11049
|
+
".tsx",
|
|
11050
|
+
".png",
|
|
11051
|
+
".jpg",
|
|
11052
|
+
".jpeg",
|
|
11053
|
+
".gif",
|
|
11054
|
+
".webp",
|
|
11055
|
+
".svg"
|
|
11056
|
+
];
|
|
11057
|
+
async function importWebSocketServer() {
|
|
11058
|
+
if (typeof process === "undefined" || !process.versions?.node) return null;
|
|
11059
|
+
try {
|
|
11060
|
+
const { createRequire } = await import("module");
|
|
11061
|
+
const ws = createRequire(import.meta.url)("ws");
|
|
11062
|
+
return ws.WebSocketServer || ws.default?.WebSocketServer || ws;
|
|
11063
|
+
} catch {
|
|
11064
|
+
return null;
|
|
11065
|
+
}
|
|
11066
|
+
}
|
|
11067
|
+
function verifyDefaultExport(importObject) {
|
|
11068
|
+
if (!importObject.variablesString) return "[]";
|
|
11069
|
+
return dedent`
|
|
11070
|
+
[${importObject.variablesString}].map((value) => {
|
|
11071
|
+
if (!value) throw new Error('Missing default export in ${importObject.relativePath}')
|
|
11072
|
+
return value
|
|
11073
|
+
})
|
|
11074
|
+
`;
|
|
11075
|
+
}
|
|
11076
|
+
function normalizeDatabase(variableList) {
|
|
11077
|
+
if (!variableList) return "{}";
|
|
11078
|
+
return dedent`
|
|
11079
|
+
Object.assign({}, ...[${variableList}].map((value) => {
|
|
11080
|
+
if (!value) return {}
|
|
11081
|
+
if (typeof value === 'function') {
|
|
11082
|
+
return { [value.id || value.name]: value }
|
|
11083
|
+
}
|
|
11084
|
+
return value
|
|
11085
|
+
}))
|
|
11086
|
+
`;
|
|
11087
|
+
}
|
|
11088
|
+
function stripQuery(url) {
|
|
11089
|
+
return url.split("?", 1)[0].split("#", 1)[0];
|
|
11090
|
+
}
|
|
11091
|
+
function normalizePublicBasePath(basePath = "map") {
|
|
11092
|
+
return basePath.trim().replace(/^\/+|\/+$/g, "") || "map";
|
|
11093
|
+
}
|
|
11094
|
+
function getMimeType(file) {
|
|
11095
|
+
switch (path.extname(file).toLowerCase()) {
|
|
11096
|
+
case ".tmx":
|
|
11097
|
+
case ".tsx":
|
|
11098
|
+
case ".world": return "application/xml";
|
|
11099
|
+
case ".png": return "image/png";
|
|
11100
|
+
case ".jpg":
|
|
11101
|
+
case ".jpeg": return "image/jpeg";
|
|
11102
|
+
case ".gif": return "image/gif";
|
|
11103
|
+
case ".webp": return "image/webp";
|
|
11104
|
+
case ".svg": return "image/svg+xml";
|
|
11105
|
+
default: return "application/octet-stream";
|
|
11106
|
+
}
|
|
11107
|
+
}
|
|
11108
|
+
function isTiledAsset(file) {
|
|
11109
|
+
return TILED_EXTENSIONS.includes(path.extname(file).toLowerCase());
|
|
11110
|
+
}
|
|
11111
|
+
function moduleRootPath(modulePath, projectRoot = process.cwd()) {
|
|
11112
|
+
return path.resolve(projectRoot, transformPathIfModule(modulePath));
|
|
11113
|
+
}
|
|
11114
|
+
function hasTiledAssets(directory) {
|
|
11115
|
+
return fs.existsSync(directory) && getAllFiles(directory).some(isTiledAsset);
|
|
11116
|
+
}
|
|
11117
|
+
function getTiledAssetRoots(modulePath, projectRoot = process.cwd()) {
|
|
11118
|
+
const moduleRoot = moduleRootPath(modulePath, projectRoot);
|
|
11119
|
+
const roots = [];
|
|
11120
|
+
const mapsRoot = path.join(moduleRoot, "maps");
|
|
11121
|
+
const worldsRoot = path.join(moduleRoot, "worlds");
|
|
11122
|
+
if (hasTiledAssets(mapsRoot)) roots.push({
|
|
11123
|
+
root: mapsRoot,
|
|
11124
|
+
moduleRoot
|
|
11125
|
+
});
|
|
11126
|
+
if (fs.existsSync(worldsRoot)) for (const dirent of fs.readdirSync(worldsRoot, { withFileTypes: true })) {
|
|
11127
|
+
if (!dirent.isDirectory()) continue;
|
|
11128
|
+
const root = path.join(worldsRoot, dirent.name);
|
|
11129
|
+
if (hasTiledAssets(root)) roots.push({
|
|
11130
|
+
root,
|
|
11131
|
+
moduleRoot
|
|
11132
|
+
});
|
|
11133
|
+
}
|
|
11134
|
+
return roots;
|
|
11135
|
+
}
|
|
11136
|
+
function getAllTiledAssetRoots(modules, projectRoot = process.cwd()) {
|
|
11137
|
+
return modules.filter((module) => module.startsWith(".")).flatMap((module) => getTiledAssetRoots(module, projectRoot));
|
|
11138
|
+
}
|
|
11139
|
+
function mapIdFromTmx(file, assetRoot) {
|
|
11140
|
+
return toPosix(path.relative(assetRoot, file)).replace(/\.tmx$/i, "");
|
|
11141
|
+
}
|
|
11142
|
+
function publicTiledFilePath(file, assetRoot, basePath = "map") {
|
|
11143
|
+
return `/${normalizePublicBasePath(basePath)}/${toPosix(path.relative(assetRoot, file))}`;
|
|
11144
|
+
}
|
|
11145
|
+
function hasSiblingMapScript(file) {
|
|
11146
|
+
return fs.existsSync(file.replace(/\.tmx$/i, ".ts"));
|
|
11147
|
+
}
|
|
11148
|
+
function createTiledMapEntries(modulePath, options, projectRoot = process.cwd()) {
|
|
11149
|
+
return getTiledAssetRoots(modulePath, projectRoot).flatMap(({ root }) => getAllFiles(root).filter((file) => file.toLowerCase().endsWith(".tmx")).filter((file) => !hasSiblingMapScript(file)).map((file) => {
|
|
11150
|
+
return `{ id: '${mapIdFromTmx(file, root)}', file: '${publicTiledFilePath(file, root, options.tiledMapBasePath)}' }`;
|
|
11151
|
+
})).join(",");
|
|
11152
|
+
}
|
|
11153
|
+
function mapIdFromWorldFileName(fileName) {
|
|
11154
|
+
const withoutExtension = toPosix(fileName).replace(/\.tmx$/i, "");
|
|
11155
|
+
return withoutExtension.split("/").filter(Boolean).at(-1) ?? withoutExtension;
|
|
11156
|
+
}
|
|
11157
|
+
function loadWorldFile(file) {
|
|
11158
|
+
const world = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
11159
|
+
const maps = Array.isArray(world.maps) ? world.maps.map((map) => ({
|
|
11160
|
+
...map,
|
|
11161
|
+
id: map.id ?? (map.fileName ? mapIdFromWorldFileName(map.fileName) : void 0),
|
|
11162
|
+
worldX: map.worldX ?? map.x ?? 0,
|
|
11163
|
+
worldY: map.worldY ?? map.y ?? 0,
|
|
11164
|
+
width: map.width ?? map.widthPx ?? 0,
|
|
11165
|
+
height: map.height ?? map.heightPx ?? 0
|
|
11166
|
+
})) : [];
|
|
11167
|
+
return {
|
|
11168
|
+
...world,
|
|
11169
|
+
id: world.id ?? path.basename(file, ".world"),
|
|
11170
|
+
maps
|
|
11171
|
+
};
|
|
11172
|
+
}
|
|
11173
|
+
function createWorldMapEntries(modulePath, projectRoot = process.cwd()) {
|
|
11174
|
+
const worldsRoot = path.join(moduleRootPath(modulePath, projectRoot), "worlds");
|
|
11175
|
+
if (!fs.existsSync(worldsRoot)) return "";
|
|
11176
|
+
return getAllFiles(worldsRoot).filter((file) => file.endsWith(".world")).map((file) => JSON.stringify(loadWorldFile(file))).join(",");
|
|
11177
|
+
}
|
|
11178
|
+
function copyTiledAssets(assetRoots, outputDir, basePath = "map") {
|
|
11179
|
+
const publicBasePath = normalizePublicBasePath(basePath);
|
|
11180
|
+
const copied = /* @__PURE__ */ new Set();
|
|
11181
|
+
for (const { root } of assetRoots) for (const file of getAllFiles(root).filter(isTiledAsset)) {
|
|
11182
|
+
const relativePath = toPosix(path.relative(root, file));
|
|
11183
|
+
const target = path.join(outputDir, publicBasePath, relativePath);
|
|
11184
|
+
if (copied.has(target)) warn(`Tiled asset collision while copying ${relativePath}`);
|
|
11185
|
+
copied.add(target);
|
|
11186
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
11187
|
+
fs.copyFileSync(file, target);
|
|
11188
|
+
}
|
|
11189
|
+
}
|
|
11190
|
+
function serveTiledAssets(server, assetRoots, basePath = "map") {
|
|
11191
|
+
const publicBasePath = `/${normalizePublicBasePath(basePath)}`;
|
|
11192
|
+
server.middlewares.use((req, res, next) => {
|
|
11193
|
+
if (!req.url?.startsWith(publicBasePath)) return next();
|
|
11194
|
+
const requestPath = decodeURIComponent(stripQuery(req.url).slice(publicBasePath.length).replace(/^\/+/, ""));
|
|
11195
|
+
for (const { root } of assetRoots) {
|
|
11196
|
+
const file = path.resolve(root, requestPath);
|
|
11197
|
+
if (!file.startsWith(root + path.sep) && file !== root) continue;
|
|
11198
|
+
if (!fs.existsSync(file) || !fs.statSync(file).isFile() || !isTiledAsset(file)) continue;
|
|
11199
|
+
res.setHeader("Content-Type", getMimeType(file));
|
|
11200
|
+
res.setHeader("Cache-Control", "no-cache");
|
|
11201
|
+
res.end(fs.readFileSync(file));
|
|
11202
|
+
return;
|
|
11203
|
+
}
|
|
11204
|
+
res.statusCode = 404;
|
|
11205
|
+
res.end("Not Found");
|
|
11206
|
+
});
|
|
11207
|
+
}
|
|
11208
|
+
function loadServerModuleFiles(modulePath, options, config, projectRoot = process.cwd()) {
|
|
11209
|
+
const modulesCreated = options.modulesCreated ?? [];
|
|
11210
|
+
if (!modulesCreated.includes(modulePath)) modulesCreated.push(modulePath);
|
|
11211
|
+
const importPlayer = importString(modulePath, "player", "player", projectRoot);
|
|
11212
|
+
const importEngine = importString(modulePath, "server", "server", projectRoot);
|
|
11213
|
+
const mapStandaloneFilesString = searchFolderAndTransformToImportString("maps", modulePath, ".ts", void 0, void 0, projectRoot);
|
|
11214
|
+
const mapFilesString = createTiledMapEntries(modulePath, options, projectRoot);
|
|
11215
|
+
const worldFilesString = createWorldMapEntries(modulePath, projectRoot);
|
|
11216
|
+
const eventsFilesString = searchFolderAndTransformToImportString("events", modulePath, ".ts", void 0, void 0, projectRoot);
|
|
11217
|
+
const databaseFilesString = searchFolderAndTransformToImportString("database", modulePath, ".ts", void 0, void 0, projectRoot);
|
|
11218
|
+
const hasMaps = !!mapFilesString && !!mapStandaloneFilesString.variablesString;
|
|
11219
|
+
const hitbox = config.start?.hitbox;
|
|
11220
|
+
const startHook = modulesCreated.length === 1 && (config.start?.graphic || hitbox || config.startMap) ? dedent`
|
|
11221
|
+
const __rpgjsV4Player = player || {}
|
|
11222
|
+
const __rpgjsV4LastConnected = __rpgjsV4Player.onConnected
|
|
11223
|
+
__rpgjsV4Player.onConnected = async (player) => {
|
|
11224
|
+
if (__rpgjsV4LastConnected) await __rpgjsV4LastConnected(player)
|
|
11225
|
+
${config.start?.graphic ? `player.setGraphic('${config.start.graphic}')` : ""}
|
|
11226
|
+
${hitbox ? `player.setHitbox(${hitbox[0]}, ${hitbox[1]})` : ""}
|
|
11227
|
+
${config.startMap ? `await player.changeMap('${config.startMap}')` : ""}
|
|
11228
|
+
}
|
|
11229
|
+
` : "";
|
|
11230
|
+
return dedent`
|
|
11231
|
+
${importPlayer || "const player = {}"}
|
|
11232
|
+
${importEngine}
|
|
11233
|
+
${mapStandaloneFilesString.importString}
|
|
11234
|
+
${eventsFilesString.importString}
|
|
11235
|
+
${databaseFilesString.importString}
|
|
11236
|
+
|
|
11237
|
+
${startHook}
|
|
11238
|
+
|
|
11239
|
+
export default {
|
|
11240
|
+
player: ${startHook ? "__rpgjsV4Player" : "player"},
|
|
11241
|
+
${importEngine ? "engine: server," : ""}
|
|
11242
|
+
events: ${verifyDefaultExport(eventsFilesString)},
|
|
11243
|
+
database: ${normalizeDatabase(databaseFilesString.variablesString)},
|
|
11244
|
+
maps: [${mapFilesString}${hasMaps ? "," : ""}${mapStandaloneFilesString.variablesString}],
|
|
11245
|
+
worldMaps: [${worldFilesString}]
|
|
11246
|
+
}
|
|
11247
|
+
`;
|
|
11248
|
+
}
|
|
11249
|
+
function createServerEntryLoad() {
|
|
11250
|
+
return dedent`
|
|
11251
|
+
import { createServer, provideServerModules } from '@rpgjs/server'
|
|
11252
|
+
import { provideTiledMap } from '@rpgjs/tiledmap/server'
|
|
11253
|
+
import modules from '${MODULE_NAME}'
|
|
11254
|
+
|
|
11255
|
+
export default createServer({
|
|
11256
|
+
providers: [
|
|
11257
|
+
provideServerModules(modules),
|
|
11258
|
+
provideTiledMap()
|
|
11259
|
+
]
|
|
11260
|
+
})
|
|
11261
|
+
`;
|
|
11262
|
+
}
|
|
11263
|
+
function loadSpriteSheet(directoryName, modulePath, options, projectRoot = process.cwd(), warning = false) {
|
|
11264
|
+
const importSprites = searchFolderAndTransformToImportString(directoryName, modulePath, ".ts", void 0, void 0, projectRoot);
|
|
11265
|
+
let propImagesString = "";
|
|
11266
|
+
let variablesString = importSprites.variablesString;
|
|
11267
|
+
if (importSprites.importString) {
|
|
11268
|
+
const images = getAllFiles(importSprites.folder).filter((file) => {
|
|
11269
|
+
return [
|
|
11270
|
+
".png",
|
|
11271
|
+
".jpg",
|
|
11272
|
+
".jpeg",
|
|
11273
|
+
".gif",
|
|
11274
|
+
".bmp",
|
|
11275
|
+
".webp",
|
|
11276
|
+
".svg"
|
|
11277
|
+
].some((ext) => file.toLowerCase().endsWith(ext));
|
|
11278
|
+
});
|
|
11279
|
+
if (!images.length) warn(`No spritesheet image found in ${directoryName}`);
|
|
11280
|
+
else {
|
|
11281
|
+
const imageImports = images.map((file) => {
|
|
11282
|
+
const filename = path.basename(file);
|
|
11283
|
+
const basename = filename.replace(path.extname(filename), "");
|
|
11284
|
+
const importPath = `${importPathForFile(file, projectRoot)}?url`;
|
|
11285
|
+
return {
|
|
11286
|
+
basename,
|
|
11287
|
+
importPath,
|
|
11288
|
+
variableName: formatVariableName(importPath)
|
|
11289
|
+
};
|
|
11290
|
+
});
|
|
11291
|
+
const objectString = imageImports.map(({ basename, variableName }) => `"${basename}": ${variableName}`).join(",\n");
|
|
11292
|
+
const imageImportString = imageImports.map(({ importPath, variableName }) => `import ${variableName} from '${importPath}'`).join("\n");
|
|
11293
|
+
const generatedSpritesheetsVariable = `__rpgjsV4Spritesheets_${formatVariableName(directoryName)}`;
|
|
11294
|
+
variablesString = `...${generatedSpritesheetsVariable}`;
|
|
11295
|
+
const dimensions = sizeOf(fs.readFileSync(images.at(-1)));
|
|
11296
|
+
propImagesString = dedent`
|
|
11297
|
+
${imageImportString}
|
|
11298
|
+
const ${generatedSpritesheetsVariable} = [${importSprites.variablesString}].flatMap((spritesheet) => {
|
|
11299
|
+
return Object.entries({ ${objectString} }).map(([id, image]) => ({
|
|
11300
|
+
...spritesheet,
|
|
11301
|
+
...(spritesheet.prototype ?? {}),
|
|
11302
|
+
id,
|
|
11303
|
+
image,
|
|
11304
|
+
}))
|
|
11305
|
+
})
|
|
11306
|
+
;[${importSprites.variablesString}].forEach((spritesheet) => {
|
|
11307
|
+
spritesheet.images = { ${objectString} }
|
|
11308
|
+
spritesheet.prototype ||= {}
|
|
11309
|
+
spritesheet.prototype.width = ${dimensions.width ?? 0}
|
|
11310
|
+
spritesheet.prototype.height = ${dimensions.height ?? 0}
|
|
11311
|
+
})
|
|
11312
|
+
${generatedSpritesheetsVariable}.forEach((spritesheet) => {
|
|
11313
|
+
spritesheet.width = ${dimensions.width ?? 0}
|
|
11314
|
+
spritesheet.height = ${dimensions.height ?? 0}
|
|
11315
|
+
})
|
|
11316
|
+
`;
|
|
11317
|
+
}
|
|
11318
|
+
} else if (warning) warn(`No spritesheet folder found in ${directoryName}`);
|
|
11319
|
+
return {
|
|
11320
|
+
...importSprites,
|
|
11321
|
+
variablesString,
|
|
11322
|
+
propImagesString
|
|
11323
|
+
};
|
|
11324
|
+
}
|
|
11325
|
+
function loadClientFiles(modulePath, options, config, projectRoot = process.cwd()) {
|
|
11326
|
+
const importSpriteString = importString(modulePath, "sprite", "sprite", projectRoot);
|
|
11327
|
+
const importSceneMapString = importString(modulePath, "scene-map", "sceneMap", projectRoot);
|
|
11328
|
+
const importEngine = importString(modulePath, "client", "engine", projectRoot);
|
|
11329
|
+
const guiFilesString = searchFolderAndTransformToImportString("gui", modulePath, [
|
|
11330
|
+
".vue",
|
|
11331
|
+
".tsx",
|
|
11332
|
+
".jsx",
|
|
11333
|
+
".ce"
|
|
11334
|
+
], void 0, void 0, projectRoot);
|
|
11335
|
+
const soundStandaloneFilesString = searchFolderAndTransformToImportString("sounds", modulePath, ".ts", void 0, void 0, projectRoot);
|
|
11336
|
+
const soundFilesString = searchFolderAndTransformToImportString("sounds", modulePath, [".mp3", ".ogg"], void 0, { customFilter: (file) => !fs.existsSync(file.replace(/\.(mp3|ogg)$/, ".ts")) }, projectRoot);
|
|
11337
|
+
const spritesheets = [];
|
|
11338
|
+
for (const directory of config.spritesheetDirectories ?? []) spritesheets.push(loadSpriteSheet(directory, modulePath, options, projectRoot));
|
|
11339
|
+
if (!(config.spritesheetDirectories ?? []).includes("characters")) spritesheets.push(loadSpriteSheet("characters", modulePath, options, projectRoot));
|
|
11340
|
+
const spritesheetRoot = path.resolve(projectRoot, transformPathIfModule(modulePath), "spritesheets");
|
|
11341
|
+
if (fs.existsSync(spritesheetRoot)) {
|
|
11342
|
+
for (const dirent of fs.readdirSync(spritesheetRoot, { withFileTypes: true })) if (dirent.isDirectory()) spritesheets.push(loadSpriteSheet(path.join("spritesheets", dirent.name), modulePath, options, projectRoot, true));
|
|
11343
|
+
}
|
|
11344
|
+
const activeSpritesheets = spritesheets.filter((spritesheet) => spritesheet.importString);
|
|
11345
|
+
const hasSounds = !!soundFilesString.variablesString && !!soundStandaloneFilesString.variablesString;
|
|
11346
|
+
return dedent`
|
|
11347
|
+
${importSpriteString || "const sprite = {}"}
|
|
11348
|
+
${importSceneMapString}
|
|
11349
|
+
${importEngine}
|
|
11350
|
+
${activeSpritesheets.map((spritesheet) => spritesheet.importString).join("\n")}
|
|
11351
|
+
${guiFilesString.importString}
|
|
11352
|
+
${soundFilesString.importString}
|
|
11353
|
+
${soundStandaloneFilesString.importString}
|
|
11354
|
+
|
|
11355
|
+
${activeSpritesheets.map((spritesheet) => spritesheet.propImagesString).join("\n")}
|
|
11356
|
+
|
|
11357
|
+
export default {
|
|
11358
|
+
spritesheets: [${activeSpritesheets.map((spritesheet) => spritesheet.variablesString).join(",")}],
|
|
11359
|
+
sprite,
|
|
11360
|
+
${importEngine ? "engine," : ""}
|
|
11361
|
+
sceneMap: ${importSceneMapString ? "sceneMap" : "{}"},
|
|
11362
|
+
gui: [${guiFilesString.variablesString}],
|
|
11363
|
+
sounds: [${soundFilesString.variablesString}${hasSounds ? "," : ""}${soundStandaloneFilesString.variablesString}]
|
|
11364
|
+
}
|
|
11365
|
+
`;
|
|
11366
|
+
}
|
|
11367
|
+
function createModuleLoad(id, variableName, modulePath, options, config, projectRoot = process.cwd()) {
|
|
11368
|
+
if (modulePath === LEGACY_MOBILE_GUI) return dedent`
|
|
11369
|
+
import { withMobile } from '@rpgjs/client'
|
|
11370
|
+
export default { client: withMobile(), server: {} }
|
|
11371
|
+
`;
|
|
11372
|
+
if (modulePath === LEGACY_DEFAULT_GUI || modulePath === LEGACY_GAMEPAD) return "export default { client: {}, server: {} }";
|
|
11373
|
+
const clientFile = `virtual:${variableName}-client`;
|
|
11374
|
+
const serverFile = `virtual:${variableName}-server`;
|
|
11375
|
+
if (id.startsWith(`${serverFile}?server`)) return loadServerModuleFiles(modulePath, options, config, projectRoot);
|
|
11376
|
+
if (id.startsWith(`${clientFile}?client`)) return loadClientFiles(modulePath, options, config, projectRoot);
|
|
11377
|
+
const modulePathId = path.resolve(projectRoot, transformPathIfModule(modulePath));
|
|
11378
|
+
const packageJson = path.join(modulePathId, "package.json");
|
|
11379
|
+
const indexFile = path.join(modulePathId, "index.ts");
|
|
11380
|
+
if (fs.existsSync(packageJson)) {
|
|
11381
|
+
const { main: entryPoint } = JSON.parse(fs.readFileSync(packageJson, "utf8"));
|
|
11382
|
+
if (entryPoint) {
|
|
11383
|
+
const entryFile = path.join(modulePathId, entryPoint);
|
|
11384
|
+
return dedent`
|
|
11385
|
+
import mod from '${modulePath.startsWith(".") ? importPathForFile(entryFile, projectRoot) : resolveModuleImport(toPosix(path.join(modulePath, entryPoint)))}'
|
|
11386
|
+
export default mod
|
|
11387
|
+
`;
|
|
11388
|
+
}
|
|
11389
|
+
} else if (fs.existsSync(indexFile)) return dedent`
|
|
11390
|
+
import mod from '${importPathForFile(indexFile, projectRoot)}'
|
|
11391
|
+
export default mod
|
|
11392
|
+
`;
|
|
11393
|
+
return dedent`
|
|
11394
|
+
import client from 'client!${clientFile}'
|
|
11395
|
+
import server from 'server!${serverFile}'
|
|
11396
|
+
export default { client, server }
|
|
11397
|
+
`;
|
|
11398
|
+
}
|
|
11399
|
+
function createModulesLoad(modules) {
|
|
11400
|
+
const modulesToImport = modules.reduce((acc, module) => {
|
|
11401
|
+
const resolvedModule = LEGACY_MODULES[module] ?? module;
|
|
11402
|
+
acc[formatVariableName(resolvedModule)] = resolvedModule;
|
|
11403
|
+
return acc;
|
|
11404
|
+
}, {});
|
|
11405
|
+
return dedent`
|
|
11406
|
+
${Object.entries(modulesToImport).map(([variableName, module]) => `import ${variableName} from '${resolveModuleImport(module)}'`).join("\n")}
|
|
11407
|
+
export default [${Object.keys(modulesToImport).join(",")}]
|
|
11408
|
+
`;
|
|
11409
|
+
}
|
|
11410
|
+
function createClientConfigLoad(config, options = {}) {
|
|
11411
|
+
return dedent`
|
|
11412
|
+
import { provideClientGlobalConfig, provideClientModules } from '@rpgjs/client'
|
|
11413
|
+
import { provideTiledMap } from '@rpgjs/tiledmap/client'
|
|
11414
|
+
import modules from '${MODULE_NAME}'
|
|
11415
|
+
export default {
|
|
11416
|
+
providers: [
|
|
11417
|
+
provideTiledMap({ basePath: '${normalizePublicBasePath(options.tiledMapBasePath)}' }),
|
|
11418
|
+
provideClientGlobalConfig(${JSON.stringify(config)}),
|
|
11419
|
+
provideClientModules(modules)
|
|
11420
|
+
]
|
|
11421
|
+
}
|
|
11422
|
+
`;
|
|
11423
|
+
}
|
|
11424
|
+
function createStandaloneEntryLoad() {
|
|
11425
|
+
return dedent`
|
|
11426
|
+
import { mergeConfig } from '@signe/di'
|
|
11427
|
+
import { provideRpg, startGame } from '@rpgjs/client'
|
|
11428
|
+
import server from '${SERVER_ENTRY}'
|
|
11429
|
+
import configClient from '${CLIENT_CONFIG}'
|
|
11430
|
+
|
|
11431
|
+
startGame(mergeConfig(configClient, {
|
|
11432
|
+
providers: [provideRpg(server)]
|
|
11433
|
+
}))
|
|
11434
|
+
`;
|
|
11435
|
+
}
|
|
11436
|
+
function createClientEntryLoad() {
|
|
11437
|
+
return dedent`
|
|
11438
|
+
import { mergeConfig } from '@signe/di'
|
|
11439
|
+
import { provideMmorpg, startGame } from '@rpgjs/client'
|
|
11440
|
+
import configClient from '${CLIENT_CONFIG}'
|
|
11441
|
+
|
|
11442
|
+
startGame(mergeConfig(configClient, {
|
|
11443
|
+
providers: [provideMmorpg({})]
|
|
11444
|
+
}))
|
|
11445
|
+
`;
|
|
11446
|
+
}
|
|
11447
|
+
function normalizeModules(config) {
|
|
11448
|
+
return config.modules?.length ? config.modules : ["./src/modules/main"];
|
|
11449
|
+
}
|
|
11450
|
+
function normalizeAliases(aliases = {}) {
|
|
11451
|
+
return Object.fromEntries(Object.entries(aliases).map(([key, value]) => [key, value.startsWith(".") ? path.resolve(process.cwd(), value) : value]));
|
|
11452
|
+
}
|
|
11453
|
+
function compatibilityV4Plugin(options = {}) {
|
|
11454
|
+
let viteMode = "development";
|
|
11455
|
+
let config = loadConfigFileSync(viteMode);
|
|
11456
|
+
let modules = normalizeModules(config);
|
|
11457
|
+
let modulesCreated = [];
|
|
11458
|
+
let viteRoot = process.cwd();
|
|
11459
|
+
let viteOutputDir = path.resolve(viteRoot, config.compilerOptions?.build?.outputDir ?? "dist");
|
|
11460
|
+
let resolvedOptions = {
|
|
11461
|
+
type: options.type ?? config.type ?? process.env.RPG_TYPE ?? "rpg",
|
|
11462
|
+
tiledMapBasePath: normalizePublicBasePath(options.tiledMapBasePath),
|
|
11463
|
+
serveMode: true,
|
|
11464
|
+
side: options.side ?? "client",
|
|
11465
|
+
...options,
|
|
11466
|
+
config
|
|
11467
|
+
};
|
|
11468
|
+
let wsServer = null;
|
|
11469
|
+
const flagOptions = {
|
|
11470
|
+
side: resolvedOptions.side,
|
|
11471
|
+
mode: viteMode,
|
|
11472
|
+
type: resolvedOptions.type
|
|
11473
|
+
};
|
|
11474
|
+
return [
|
|
11475
|
+
flagTransform(flagOptions),
|
|
11476
|
+
vitePluginRequire(),
|
|
11477
|
+
{
|
|
11478
|
+
name: "rpgjs-v4-compatibility",
|
|
11479
|
+
enforce: "pre",
|
|
11480
|
+
config() {
|
|
11481
|
+
return {
|
|
11482
|
+
resolve: {
|
|
11483
|
+
alias: {
|
|
11484
|
+
"@": path.resolve(process.cwd(), "src"),
|
|
11485
|
+
...normalizeAliases(config.compilerOptions?.alias)
|
|
11486
|
+
},
|
|
11487
|
+
extensions: [
|
|
11488
|
+
".ts",
|
|
11489
|
+
".js",
|
|
11490
|
+
".jsx",
|
|
11491
|
+
".json",
|
|
11492
|
+
".vue",
|
|
11493
|
+
".css",
|
|
11494
|
+
".scss",
|
|
11495
|
+
".sass",
|
|
11496
|
+
".html",
|
|
11497
|
+
".tmx",
|
|
11498
|
+
".tsx",
|
|
11499
|
+
".toml",
|
|
11500
|
+
".ce"
|
|
11501
|
+
]
|
|
11502
|
+
},
|
|
11503
|
+
assetsInclude: [
|
|
11504
|
+
"**/*.tmx",
|
|
11505
|
+
"**/*.world",
|
|
11506
|
+
"{!(gui)/**/*}.tsx"
|
|
11507
|
+
]
|
|
11508
|
+
};
|
|
11509
|
+
},
|
|
11510
|
+
configResolved(viteConfig) {
|
|
11511
|
+
viteMode = viteConfig.mode || "development";
|
|
11512
|
+
viteRoot = viteConfig.root;
|
|
11513
|
+
viteOutputDir = path.resolve(viteRoot, viteConfig.build.outDir || "dist");
|
|
11514
|
+
config = loadConfigFileSync(viteMode, viteConfig.root);
|
|
11515
|
+
modules = normalizeModules(config);
|
|
11516
|
+
modulesCreated = [];
|
|
11517
|
+
resolvedOptions = {
|
|
11518
|
+
...resolvedOptions,
|
|
11519
|
+
type: options.type ?? config.type ?? process.env.RPG_TYPE ?? "rpg",
|
|
11520
|
+
serveMode: viteConfig.command === "serve",
|
|
11521
|
+
mode: viteMode,
|
|
11522
|
+
config
|
|
11523
|
+
};
|
|
11524
|
+
flagOptions.side = resolvedOptions.side;
|
|
11525
|
+
flagOptions.mode = viteMode;
|
|
11526
|
+
flagOptions.type = resolvedOptions.type;
|
|
11527
|
+
},
|
|
11528
|
+
transformIndexHtml: {
|
|
11529
|
+
order: "pre",
|
|
11530
|
+
handler(html) {
|
|
11531
|
+
const script = `<script type="module">\nimport '${resolvedOptions.type === "mmorpg" ? CLIENT_ENTRY : STANDALONE_ENTRY}'\n<\/script>`;
|
|
11532
|
+
if (html.includes("<script type=\"module\"")) return html.replace(/<script\s+type="module"\s+src="[^"]*"[^>]*><\/script>/gi, script);
|
|
11533
|
+
return html.replace(/<\/head>/i, ` ${script}\n </head>`);
|
|
11534
|
+
}
|
|
11535
|
+
},
|
|
11536
|
+
handleHotUpdate() {
|
|
11537
|
+
modulesCreated = [];
|
|
11538
|
+
},
|
|
11539
|
+
resolveId(source) {
|
|
11540
|
+
if ([
|
|
11541
|
+
MODULE_NAME,
|
|
11542
|
+
CLIENT_CONFIG,
|
|
11543
|
+
SERVER_ENTRY,
|
|
11544
|
+
CLIENT_ENTRY,
|
|
11545
|
+
STANDALONE_ENTRY,
|
|
11546
|
+
...Object.values(LEGACY_MODULES)
|
|
11547
|
+
].includes(source)) return source;
|
|
11548
|
+
for (const module of modules) {
|
|
11549
|
+
const moduleName = resolveModuleImport(module);
|
|
11550
|
+
const variableName = formatVariableName(moduleName);
|
|
11551
|
+
if (source === moduleName || source === `virtual:${variableName}-client` || source === `virtual:${variableName}-server`) return source;
|
|
11552
|
+
}
|
|
11553
|
+
return null;
|
|
11554
|
+
},
|
|
11555
|
+
load(id) {
|
|
11556
|
+
if (id === MODULE_NAME) return createModulesLoad(modules);
|
|
11557
|
+
if (id === CLIENT_CONFIG) return createClientConfigLoad(config, resolvedOptions);
|
|
11558
|
+
if (id === SERVER_ENTRY) return createServerEntryLoad();
|
|
11559
|
+
if (id === CLIENT_ENTRY) return createClientEntryLoad();
|
|
11560
|
+
if (id === STANDALONE_ENTRY) return createStandaloneEntryLoad();
|
|
11561
|
+
if (Object.values(LEGACY_MODULES).includes(id)) return createModuleLoad(id, formatVariableName(id), id, {
|
|
11562
|
+
...resolvedOptions,
|
|
11563
|
+
modulesCreated
|
|
11564
|
+
}, config);
|
|
11565
|
+
for (const module of modules) {
|
|
11566
|
+
const moduleName = resolveModuleImport(module);
|
|
11567
|
+
const variableName = formatVariableName(moduleName);
|
|
11568
|
+
if (id === moduleName || id.startsWith(`virtual:${variableName}-client?client`) || id.startsWith(`virtual:${variableName}-server?server`)) return createModuleLoad(id, variableName, module, {
|
|
11569
|
+
...resolvedOptions,
|
|
11570
|
+
modulesCreated
|
|
11571
|
+
}, config);
|
|
11572
|
+
}
|
|
11573
|
+
return null;
|
|
11574
|
+
},
|
|
11575
|
+
async configureServer(server) {
|
|
11576
|
+
serveTiledAssets(server, getAllTiledAssetRoots(modules, server.config.root), resolvedOptions.tiledMapBasePath);
|
|
11577
|
+
if (resolvedOptions.type !== "mmorpg") return;
|
|
11578
|
+
const { default: serverModule } = await server.ssrLoadModule(SERVER_ENTRY);
|
|
11579
|
+
const transport = createRpgServerTransport(serverModule);
|
|
11580
|
+
const WebSocketServerClass = await importWebSocketServer();
|
|
11581
|
+
if (WebSocketServerClass) wsServer = new WebSocketServerClass({ noServer: true });
|
|
11582
|
+
logNetworkSimulationStatus();
|
|
11583
|
+
server.middlewares.use("/parties", async (req, res, next) => {
|
|
11584
|
+
await transport.handleNodeRequest(req, res, next, { mountedPath: "/parties" });
|
|
11585
|
+
});
|
|
11586
|
+
if (wsServer) server.httpServer?.on("upgrade", (request, socket, head) => {
|
|
11587
|
+
transport.handleUpgrade(wsServer, request, socket, head);
|
|
11588
|
+
});
|
|
11589
|
+
},
|
|
11590
|
+
buildEnd() {
|
|
11591
|
+
wsServer?.close();
|
|
11592
|
+
},
|
|
11593
|
+
generateBundle() {
|
|
11594
|
+
copyTiledAssets(getAllTiledAssetRoots(modules, viteRoot), viteOutputDir, resolvedOptions.tiledMapBasePath);
|
|
11595
|
+
}
|
|
11596
|
+
}
|
|
11597
|
+
];
|
|
11598
|
+
}
|
|
11599
|
+
//#endregion
|
|
11600
|
+
export { compatibilityV4Plugin, directivePlugin, entryPointPlugin, removeImportsPlugin, replaceConfigImport, rpgjs, rpgjsModuleViteConfig, serverPlugin, tiledMapFolderPlugin };
|
|
10436
11601
|
|
|
10437
11602
|
//# sourceMappingURL=index.js.map
|