@rpgjs/vite 5.0.0-beta.7 → 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 +23 -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 +1345 -166
- 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
|
|
|
@@ -8027,6 +8035,8 @@ function map(project, thisArg) {
|
|
|
8027
8035
|
}));
|
|
8028
8036
|
});
|
|
8029
8037
|
}
|
|
8038
|
+
Array.isArray;
|
|
8039
|
+
Array.isArray;
|
|
8030
8040
|
function mergeInternals(source, subscriber, project, concurrent, onBeforeNext, expand, innerSubScheduler, additionalFinalizer) {
|
|
8031
8041
|
var buffer = [];
|
|
8032
8042
|
var active = 0;
|
|
@@ -8277,8 +8287,8 @@ var getGlobalReactiveStore = () => {
|
|
|
8277
8287
|
}
|
|
8278
8288
|
let globalObj;
|
|
8279
8289
|
if (typeof window !== "undefined") globalObj = window;
|
|
8290
|
+
else if (typeof process !== "undefined" && process.versions && process.versions.node) globalObj = Function("return this")();
|
|
8280
8291
|
else if (typeof self !== "undefined") globalObj = self;
|
|
8281
|
-
else if (typeof Function !== "undefined") globalObj = Function("return this")();
|
|
8282
8292
|
else {
|
|
8283
8293
|
console.warn("Unable to find global object, using local instance");
|
|
8284
8294
|
return {
|
|
@@ -8367,6 +8377,7 @@ var createSyncClass = (currentClass, parentKey = null, parentClass = null, path
|
|
|
8367
8377
|
currentClass.$path = path;
|
|
8368
8378
|
if (parentClass) currentClass.$valuesChanges = parentClass.$valuesChanges;
|
|
8369
8379
|
if (parentKey) setMetadata(currentClass, "id", parentKey);
|
|
8380
|
+
applyDecoratedSignalMetadata(currentClass);
|
|
8370
8381
|
if (currentClass.$snapshot) for (const key of currentClass.$snapshot.keys()) {
|
|
8371
8382
|
const signal = currentClass.$snapshot.get(key);
|
|
8372
8383
|
const syncToClient = signal.options?.syncToClient ?? true;
|
|
@@ -8389,8 +8400,20 @@ var createSyncClass = (currentClass, parentKey = null, parentClass = null, path
|
|
|
8389
8400
|
});
|
|
8390
8401
|
}
|
|
8391
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
|
+
}
|
|
8392
8415
|
var type = (_signal, path, options = {}, currentInstance) => {
|
|
8393
|
-
const { syncToClient = true, persist: persist2 = true, transform } = options;
|
|
8416
|
+
const { syncToClient = true, persist: persist2 = true, transform, skipInitialSync = false } = options;
|
|
8394
8417
|
let init = true;
|
|
8395
8418
|
const handleObjectSubject = (value, propPath) => {
|
|
8396
8419
|
const newPath = `${propPath}${value.key ? `.${value.key}` : ""}`;
|
|
@@ -8422,14 +8445,15 @@ var type = (_signal, path, options = {}, currentInstance) => {
|
|
|
8422
8445
|
const savePath = (propPath, value) => {
|
|
8423
8446
|
const transformedValue = transform && value !== "$delete" ? transform(value) : value;
|
|
8424
8447
|
if (syncToClient) currentInstance.$valuesChanges.set(propPath, transformedValue);
|
|
8425
|
-
if (persist2 && currentInstance.$path !== void 0) currentInstance.$valuesChanges.setPersist(
|
|
8448
|
+
if (persist2 && currentInstance.$path !== void 0) currentInstance.$valuesChanges.setPersist(propPath, transformedValue);
|
|
8426
8449
|
};
|
|
8427
8450
|
const setupSubscription = (signal, signalPath) => {
|
|
8428
8451
|
if (!isSignal(signal)) return;
|
|
8429
|
-
if (syncToClient && currentInstance.$valuesChanges) {
|
|
8452
|
+
if (syncToClient && !skipInitialSync && currentInstance.$valuesChanges) {
|
|
8430
8453
|
const initialValue = signal();
|
|
8431
8454
|
const transformedInitialValue = transform ? transform(initialValue) : initialValue;
|
|
8432
|
-
currentInstance.$
|
|
8455
|
+
const initialPath = currentInstance.$path !== void 0 ? `${currentInstance.$path ? `${currentInstance.$path}.` : ""}${signalPath}` : signalPath;
|
|
8456
|
+
currentInstance.$valuesChanges.set(initialPath, transformedInitialValue);
|
|
8433
8457
|
}
|
|
8434
8458
|
signal.options = options;
|
|
8435
8459
|
signal.observable.subscribe((value) => {
|
|
@@ -8461,7 +8485,7 @@ var type = (_signal, path, options = {}, currentInstance) => {
|
|
|
8461
8485
|
init = false;
|
|
8462
8486
|
return _signal;
|
|
8463
8487
|
};
|
|
8464
|
-
function
|
|
8488
|
+
function normalizeSyncOptions(options) {
|
|
8465
8489
|
let classType;
|
|
8466
8490
|
let persist2 = true;
|
|
8467
8491
|
let syncToClient = true;
|
|
@@ -8473,18 +8497,27 @@ function sync(options) {
|
|
|
8473
8497
|
if (options.hasOwnProperty("syncToClient")) syncToClient = options.syncToClient;
|
|
8474
8498
|
if (options.hasOwnProperty("transform")) transform = options.transform;
|
|
8475
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);
|
|
8476
8513
|
return function(target, propertyKey) {
|
|
8514
|
+
setSyncMetadata(target, propertyKey, normalizedOptions);
|
|
8477
8515
|
const privatePropertyKey = `__${propertyKey}`;
|
|
8478
8516
|
const getter = function() {
|
|
8479
8517
|
return this[privatePropertyKey];
|
|
8480
8518
|
};
|
|
8481
8519
|
const setter = function(newVal) {
|
|
8482
|
-
this[privatePropertyKey] = type(newVal, propertyKey,
|
|
8483
|
-
classType,
|
|
8484
|
-
persist: persist2,
|
|
8485
|
-
syncToClient,
|
|
8486
|
-
transform
|
|
8487
|
-
}, this);
|
|
8520
|
+
this[privatePropertyKey] = type(newVal, propertyKey, normalizedOptions, this);
|
|
8488
8521
|
};
|
|
8489
8522
|
Object.defineProperty(target, propertyKey, {
|
|
8490
8523
|
get: getter,
|
|
@@ -8584,13 +8617,6 @@ var toCloneableSyncValue = (value, seen = /* @__PURE__ */ new WeakSet()) => {
|
|
|
8584
8617
|
}
|
|
8585
8618
|
return output;
|
|
8586
8619
|
};
|
|
8587
|
-
var Direction = /* @__PURE__ */ function(Direction) {
|
|
8588
|
-
Direction["Up"] = "up";
|
|
8589
|
-
Direction["Down"] = "down";
|
|
8590
|
-
Direction["Left"] = "left";
|
|
8591
|
-
Direction["Right"] = "right";
|
|
8592
|
-
return Direction;
|
|
8593
|
-
}({});
|
|
8594
8620
|
var RpgCommonPlayer = class {
|
|
8595
8621
|
constructor() {
|
|
8596
8622
|
this.name = signal("");
|
|
@@ -8599,7 +8625,7 @@ var RpgCommonPlayer = class {
|
|
|
8599
8625
|
this.y = signal(0);
|
|
8600
8626
|
this.z = signal(0);
|
|
8601
8627
|
this.tint = signal("white");
|
|
8602
|
-
this.direction = signal(
|
|
8628
|
+
this.direction = signal("down");
|
|
8603
8629
|
this.speed = signal(4);
|
|
8604
8630
|
this.graphics = signal([]);
|
|
8605
8631
|
this.canMove = signal(true);
|
|
@@ -8748,6 +8774,9 @@ var RpgCommonPlayer = class {
|
|
|
8748
8774
|
getDirection() {
|
|
8749
8775
|
return this.direction();
|
|
8750
8776
|
}
|
|
8777
|
+
isEvent() {
|
|
8778
|
+
return false;
|
|
8779
|
+
}
|
|
8751
8780
|
};
|
|
8752
8781
|
__decorate([id(), __decorateMetadata("design:type", String)], RpgCommonPlayer.prototype, "id", void 0);
|
|
8753
8782
|
__decorate([sync(), __decorateMetadata("design:type", Object)], RpgCommonPlayer.prototype, "name", void 0);
|
|
@@ -9340,7 +9369,6 @@ var Context = class {
|
|
|
9340
9369
|
return this.values[key];
|
|
9341
9370
|
}
|
|
9342
9371
|
};
|
|
9343
|
-
function setInject(_context) {}
|
|
9344
9372
|
var context = new Context();
|
|
9345
9373
|
context["side"] = "server";
|
|
9346
9374
|
var MAP_UPDATE_TOKEN_HEADER = "x-rpgjs-map-update-token";
|
|
@@ -9422,8 +9450,17 @@ function getTiledBasePaths(paths) {
|
|
|
9422
9450
|
function resolveMapUpdateToken(explicitToken) {
|
|
9423
9451
|
return explicitToken ?? readEnvVariable$1("RPGJS_MAP_UPDATE_TOKEN") ?? "";
|
|
9424
9452
|
}
|
|
9453
|
+
function normalizeMapUpdateHeaders(init) {
|
|
9454
|
+
if (!init) return void 0;
|
|
9455
|
+
if (init instanceof Headers || Array.isArray(init)) return init;
|
|
9456
|
+
if (init instanceof Map) return Array.from(init.entries()).filter((entry) => entry[1] !== void 0);
|
|
9457
|
+
return Object.entries(init).flatMap(([key, value]) => {
|
|
9458
|
+
if (value === void 0) return [];
|
|
9459
|
+
return Array.isArray(value) ? value.map((item) => [key, item]) : [[key, value]];
|
|
9460
|
+
});
|
|
9461
|
+
}
|
|
9425
9462
|
function createMapUpdateHeaders(token, init) {
|
|
9426
|
-
const headers = new Headers(init);
|
|
9463
|
+
const headers = new Headers(normalizeMapUpdateHeaders(init));
|
|
9427
9464
|
if (!headers.has("content-type")) headers.set("content-type", "application/json");
|
|
9428
9465
|
const resolvedToken = resolveMapUpdateToken(token);
|
|
9429
9466
|
if (resolvedToken) headers.set(MAP_UPDATE_TOKEN_HEADER, resolvedToken);
|
|
@@ -9839,50 +9876,457 @@ function logNetworkSimulationStatus() {
|
|
|
9839
9876
|
console.log(`\x1b[36m[NETWORK SIMULATION]\x1b[0m Latency simulation: ${latencyStatus.ms}ms ping${filterInfo}`);
|
|
9840
9877
|
} else console.log("\x1B[36m[NETWORK SIMULATION]\x1B[0m Latency simulation: disabled");
|
|
9841
9878
|
}
|
|
9842
|
-
var
|
|
9843
|
-
|
|
9844
|
-
|
|
9845
|
-
|
|
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) {
|
|
9846
10098
|
this.connections = /* @__PURE__ */ new Map();
|
|
9847
|
-
this.
|
|
9848
|
-
this.id = id;
|
|
9849
|
-
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
|
+
};
|
|
9850
10117
|
}
|
|
9851
|
-
|
|
9852
|
-
|
|
9853
|
-
|
|
9854
|
-
|
|
9855
|
-
|
|
10118
|
+
blockConcurrencyWhile(callback) {
|
|
10119
|
+
return callback();
|
|
10120
|
+
}
|
|
10121
|
+
broadcast(msg, without = []) {
|
|
10122
|
+
for (const connection of this.connections.values()) if (!without.includes(connection.id)) connection.send(msg);
|
|
9856
10123
|
}
|
|
9857
10124
|
getConnection(id) {
|
|
9858
|
-
|
|
10125
|
+
let connection;
|
|
10126
|
+
for (const current of this.connections.values()) if (current.id === id || current.sessionId === id) connection = current;
|
|
10127
|
+
return connection;
|
|
9859
10128
|
}
|
|
9860
|
-
getConnections(
|
|
9861
|
-
return this.connections.values();
|
|
10129
|
+
getConnections() {
|
|
10130
|
+
return Array.from(this.connections.values());
|
|
9862
10131
|
}
|
|
9863
10132
|
addConnection(connection) {
|
|
9864
10133
|
this.connections.set(connection.id, connection);
|
|
9865
10134
|
}
|
|
9866
|
-
|
|
9867
|
-
|
|
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);
|
|
9868
10141
|
}
|
|
9869
|
-
|
|
9870
|
-
|
|
9871
|
-
|
|
9872
|
-
|
|
9873
|
-
|
|
9874
|
-
|
|
9875
|
-
|
|
9876
|
-
|
|
9877
|
-
|
|
9878
|
-
|
|
9879
|
-
|
|
9880
|
-
|
|
9881
|
-
|
|
9882
|
-
|
|
9883
|
-
|
|
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;
|
|
10168
|
+
}
|
|
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);
|
|
9884
10256
|
}
|
|
9885
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
|
+
}
|
|
9886
10330
|
function normalizePathPrefix(path, fallback) {
|
|
9887
10331
|
const trimmed = (path || fallback).trim();
|
|
9888
10332
|
if (!trimmed) return fallback;
|
|
@@ -9987,25 +10431,12 @@ function resolveUrlFromSocketRequest(request) {
|
|
|
9987
10431
|
url
|
|
9988
10432
|
};
|
|
9989
10433
|
}
|
|
9990
|
-
function
|
|
9991
|
-
|
|
9992
|
-
|
|
9993
|
-
|
|
9994
|
-
}
|
|
9995
|
-
return
|
|
9996
|
-
request: {
|
|
9997
|
-
headers: {
|
|
9998
|
-
has: (name) => normalizedHeaders.has(name.toLowerCase()),
|
|
9999
|
-
get: (name) => normalizedHeaders.get(name.toLowerCase()),
|
|
10000
|
-
entries: () => normalizedHeaders.entries(),
|
|
10001
|
-
keys: () => normalizedHeaders.keys(),
|
|
10002
|
-
values: () => normalizedHeaders.values()
|
|
10003
|
-
},
|
|
10004
|
-
method,
|
|
10005
|
-
url: url.toString()
|
|
10006
|
-
},
|
|
10007
|
-
url
|
|
10008
|
-
};
|
|
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;
|
|
10009
10440
|
}
|
|
10010
10441
|
var RpgServerTransport = class {
|
|
10011
10442
|
constructor(serverModule, options = {}) {
|
|
@@ -10018,10 +10449,33 @@ var RpgServerTransport = class {
|
|
|
10018
10449
|
this.mapUpdateToken = resolveMapUpdateToken(options.mapUpdateToken);
|
|
10019
10450
|
this.partiesPath = normalizePathPrefix(options.partiesPath || "/parties/main", "/parties/main");
|
|
10020
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
|
+
});
|
|
10021
10476
|
}
|
|
10022
10477
|
async ensureServerContext() {
|
|
10023
10478
|
if (this.serverContextInitialized) return;
|
|
10024
|
-
setInject(context);
|
|
10025
10479
|
await injector(context, [provideServerModules([])]);
|
|
10026
10480
|
this.serverContextInitialized = true;
|
|
10027
10481
|
}
|
|
@@ -10033,52 +10487,17 @@ var RpgServerTransport = class {
|
|
|
10033
10487
|
}
|
|
10034
10488
|
async ensureRoomAndServer(roomId, host) {
|
|
10035
10489
|
if (host) this.lastKnownHost = host;
|
|
10036
|
-
|
|
10037
|
-
|
|
10038
|
-
|
|
10039
|
-
|
|
10040
|
-
console.log(`Created new room: ${roomId}`);
|
|
10041
|
-
}
|
|
10042
|
-
let rpgServer = this.servers.get(roomId);
|
|
10043
|
-
if (!rpgServer) {
|
|
10044
|
-
await this.ensureServerContext();
|
|
10045
|
-
rpgServer = new this.serverModule(room);
|
|
10046
|
-
this.servers.set(roomId, rpgServer);
|
|
10047
|
-
console.log(`Created new server instance for room: ${roomId}`);
|
|
10048
|
-
if (typeof rpgServer.onStart === "function") try {
|
|
10049
|
-
await rpgServer.onStart();
|
|
10050
|
-
console.log(`Server started for room: ${roomId}`);
|
|
10051
|
-
} catch (error) {
|
|
10052
|
-
console.error(`Error starting server for room ${roomId}:`, error);
|
|
10053
|
-
}
|
|
10054
|
-
if (this.initializeMaps) await updateMap(roomId, rpgServer, {
|
|
10055
|
-
host: host || this.lastKnownHost,
|
|
10056
|
-
mapUpdateToken: this.mapUpdateToken,
|
|
10057
|
-
tiledBasePaths: this.tiledBasePaths
|
|
10058
|
-
});
|
|
10059
|
-
}
|
|
10060
|
-
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}`);
|
|
10061
10494
|
return {
|
|
10062
10495
|
room,
|
|
10063
10496
|
rpgServer
|
|
10064
10497
|
};
|
|
10065
10498
|
}
|
|
10066
|
-
buildPartiesContext() {
|
|
10067
|
-
return { main: { get: async (targetRoomId) => {
|
|
10068
|
-
return { fetch: async (path, init) => {
|
|
10069
|
-
const method = (init?.method || "GET").toUpperCase();
|
|
10070
|
-
const headers = toHeaders(init?.headers);
|
|
10071
|
-
const requestPath = path.startsWith("/") ? path : `/${path}`;
|
|
10072
|
-
let bodyText = "";
|
|
10073
|
-
if (typeof init?.body === "string") bodyText = init.body;
|
|
10074
|
-
else if (typeof init?.body !== "undefined") bodyText = JSON.stringify(init.body);
|
|
10075
|
-
return this.dispatchRoomRequest(targetRoomId, createRequestLike(`http://localhost${this.partiesPath}/${targetRoomId}${requestPath}`, method, headers, bodyText), this.lastKnownHost);
|
|
10076
|
-
} };
|
|
10077
|
-
} } };
|
|
10078
|
-
}
|
|
10079
10499
|
async dispatchRoomRequest(roomId, requestLike, host) {
|
|
10080
|
-
const {
|
|
10081
|
-
room.context.parties = this.buildPartiesContext();
|
|
10500
|
+
const { rpgServer } = await this.ensureRoomAndServer(roomId, host);
|
|
10082
10501
|
return normalizeEngineResponse(await rpgServer.onRequest?.(requestLike));
|
|
10083
10502
|
}
|
|
10084
10503
|
async fetch(request, init) {
|
|
@@ -10111,8 +10530,7 @@ var RpgServerTransport = class {
|
|
|
10111
10530
|
next?.();
|
|
10112
10531
|
return false;
|
|
10113
10532
|
}
|
|
10114
|
-
|
|
10115
|
-
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));
|
|
10116
10534
|
return true;
|
|
10117
10535
|
} catch (error) {
|
|
10118
10536
|
console.error("Error handling RPG-JS request:", error);
|
|
@@ -10130,51 +10548,17 @@ var RpgServerTransport = class {
|
|
|
10130
10548
|
console.log(`WebSocket upgrade request: ${normalizedRequest.url.pathname}`);
|
|
10131
10549
|
const queryParams = Object.fromEntries(normalizedRequest.url.searchParams.entries());
|
|
10132
10550
|
console.log(`Room: ${route.roomId}, Query params:`, queryParams);
|
|
10133
|
-
|
|
10134
|
-
|
|
10135
|
-
const connection =
|
|
10136
|
-
|
|
10137
|
-
|
|
10138
|
-
|
|
10139
|
-
|
|
10140
|
-
if (isClosed) return;
|
|
10141
|
-
isClosed = true;
|
|
10142
|
-
if (logMessage) console.log(logMessage);
|
|
10143
|
-
if (error) console.error("WebSocket error:", error);
|
|
10144
|
-
room.removeConnection(connection.id);
|
|
10145
|
-
await rpgServer.onClose?.(connection);
|
|
10146
|
-
};
|
|
10147
|
-
ws.on("message", async (data) => {
|
|
10148
|
-
try {
|
|
10149
|
-
const rawMessage = typeof data === "string" ? data : data.toString();
|
|
10150
|
-
if (PartyConnection.packetLossEnabled && PartyConnection.packetLossRate > 0) {
|
|
10151
|
-
if (!PartyConnection.packetLossFilter || rawMessage.includes(PartyConnection.packetLossFilter)) {
|
|
10152
|
-
if (Math.random() < PartyConnection.packetLossRate) {
|
|
10153
|
-
console.log(`\x1b[31m[PACKET LOSS]\x1b[0m Connection ${connection.id}: Server dropped an incoming packet (${(PartyConnection.packetLossRate * 100).toFixed(1)}% loss rate)`);
|
|
10154
|
-
console.log(`\x1b[33m[PACKET DATA]\x1b[0m ${rawMessage.slice(0, 100)}${rawMessage.length > 100 ? "..." : ""}`);
|
|
10155
|
-
return;
|
|
10156
|
-
}
|
|
10157
|
-
}
|
|
10158
|
-
}
|
|
10159
|
-
connection.bufferIncoming(rawMessage, async (batch) => {
|
|
10160
|
-
for (const message of batch) await rpgServer.onMessage?.(message, connection);
|
|
10161
|
-
});
|
|
10162
|
-
} catch (error) {
|
|
10163
|
-
console.error("Error processing WebSocket message:", error);
|
|
10164
|
-
}
|
|
10165
|
-
});
|
|
10166
|
-
ws.on("close", () => {
|
|
10167
|
-
cleanup(`WebSocket connection closed: ${connection.id} from room: ${route.roomId}`);
|
|
10168
|
-
});
|
|
10169
|
-
ws.on("error", (error) => {
|
|
10170
|
-
cleanup(void 0, error);
|
|
10171
|
-
});
|
|
10172
|
-
if (typeof rpgServer.onConnect === "function") await rpgServer.onConnect(connection, createConnectionContext(normalizedRequest.url, normalizedRequest.headers, normalizedRequest.method));
|
|
10173
|
-
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({
|
|
10174
10558
|
type: "connected",
|
|
10175
10559
|
id: connection.id,
|
|
10176
10560
|
message: "Connected to RPG-JS server"
|
|
10177
|
-
});
|
|
10561
|
+
}));
|
|
10178
10562
|
return true;
|
|
10179
10563
|
} catch (error) {
|
|
10180
10564
|
console.error("Error establishing WebSocket connection:", error);
|
|
@@ -10184,7 +10568,11 @@ var RpgServerTransport = class {
|
|
|
10184
10568
|
}
|
|
10185
10569
|
async handleUpgrade(wsServer, request, socket, head) {
|
|
10186
10570
|
const host = toHeaders(request.headers).get("host") || "localhost";
|
|
10187
|
-
|
|
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;
|
|
10188
10576
|
wsServer.handleUpgrade(request, socket, head, (ws) => {
|
|
10189
10577
|
this.acceptWebSocket(ws, request);
|
|
10190
10578
|
});
|
|
@@ -10196,7 +10584,7 @@ function createRpgServerTransport(serverModule, options) {
|
|
|
10196
10584
|
}
|
|
10197
10585
|
//#endregion
|
|
10198
10586
|
//#region src/server-plugin.ts
|
|
10199
|
-
async function importWebSocketServer() {
|
|
10587
|
+
async function importWebSocketServer$1() {
|
|
10200
10588
|
if (typeof process === "undefined" || !process.versions?.node) {
|
|
10201
10589
|
console.warn("Not in Node.js environment, WebSocket server not available");
|
|
10202
10590
|
return null;
|
|
@@ -10217,7 +10605,7 @@ function serverPlugin(serverModule) {
|
|
|
10217
10605
|
name: "server-plugin",
|
|
10218
10606
|
async configureServer(server) {
|
|
10219
10607
|
try {
|
|
10220
|
-
const WebSocketServerClass = await importWebSocketServer();
|
|
10608
|
+
const WebSocketServerClass = await importWebSocketServer$1();
|
|
10221
10609
|
if (WebSocketServerClass) {
|
|
10222
10610
|
wsServer = new WebSocketServerClass({ noServer: true });
|
|
10223
10611
|
console.log("WebSocket server initialized successfully");
|
|
@@ -10418,6 +10806,797 @@ function rpgjs({ server, entryPoints }) {
|
|
|
10418
10806
|
];
|
|
10419
10807
|
}
|
|
10420
10808
|
//#endregion
|
|
10421
|
-
|
|
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 };
|
|
10422
11601
|
|
|
10423
11602
|
//# sourceMappingURL=index.js.map
|