@genex-ai/multiplayer 0.17.6 → 0.17.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/PROTOCOL.md +102 -31
- package/README.md +35 -14
- package/WORLD-GLTF.md +109 -0
- package/WORLD-SCENE.md +135 -0
- package/dist/authority/fast-udp.d.ts +4 -2
- package/dist/authority/fast-udp.js +8 -46
- package/dist/authority/fast-webtransport.d.ts +26 -4
- package/dist/authority/fast-webtransport.js +12 -115
- package/dist/authority/index.d.ts +379 -41
- package/dist/authority/index.js +247 -47
- package/dist/authority/module.d.ts +2 -1
- package/dist/authority/module.js +1 -1
- package/dist/bridge-authority.d.ts +3 -2
- package/dist/bridge-authority.global.js +10 -9
- package/dist/bridge-authority.js +11 -6
- package/dist/bridge.global.js +5 -5
- package/dist/bridge.js +3 -3
- package/dist/chunk-2NGXXQDS.js +1916 -0
- package/dist/{chunk-7QVOIHJF.js → chunk-DJ2XYETS.js} +2 -2
- package/dist/{chunk-Y6XHXDIK.js → chunk-MQYARUGU.js} +864 -539
- package/dist/{chunk-K3SF5VDS.js → chunk-OD6NRSX2.js} +3 -1
- package/dist/{chunk-UX3F6YTV.js → chunk-TEHGMFAG.js} +1 -1
- package/dist/chunk-TSYEWPVO.js +44 -0
- package/dist/chunk-TVTVIMIH.js +675 -0
- package/dist/{chunk-ZSWF4VCN.js → chunk-WEMRRIHH.js} +80 -2
- package/dist/chunk-YWQ3ALYY.js +69 -0
- package/dist/{chunk-5JGRFT2N.js → chunk-ZDGSUR6E.js} +879 -1898
- package/dist/{fast-client-CZ41v-oB.d.ts → fast-client--A88q0kk.d.ts} +85 -4
- package/dist/index.js +3 -3
- package/dist/level-build-CbRqrYJq.d.ts +140 -0
- package/dist/{module-DqtFb5wA.d.ts → module-CSpXrzFc.d.ts} +151 -400
- package/dist/{physics-predict-49udN3a1.d.ts → physics-predict-C7ZB1gDG.d.ts} +18 -3
- package/dist/protocol.d.ts +90 -2
- package/dist/protocol.js +17 -1
- package/dist/shot-world-D22tqOUT.d.ts +485 -0
- package/dist/world-fit/index.d.ts +549 -0
- package/dist/world-fit/index.js +4763 -0
- package/dist/world-fit/three.d.ts +77 -0
- package/dist/world-fit/three.js +140 -0
- package/package.json +15 -3
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { a as LevelHull, L as LevelScene } from '../level-build-CbRqrYJq.js';
|
|
2
|
+
export { b as LEVEL_LIMITS, e as LevelRefusal, f as LevelRefusalCode, R as RawWorldScene } from '../level-build-CbRqrYJq.js';
|
|
3
|
+
|
|
4
|
+
/** What this reads of `THREE.BufferAttribute`. */
|
|
5
|
+
interface ThreeAttribute {
|
|
6
|
+
readonly count: number;
|
|
7
|
+
getX(i: number): number;
|
|
8
|
+
getY(i: number): number;
|
|
9
|
+
getZ(i: number): number;
|
|
10
|
+
}
|
|
11
|
+
/** What this reads of `THREE.BufferGeometry`. */
|
|
12
|
+
interface ThreeGeometry {
|
|
13
|
+
readonly attributes: {
|
|
14
|
+
readonly position?: ThreeAttribute;
|
|
15
|
+
};
|
|
16
|
+
readonly index: {
|
|
17
|
+
readonly count: number;
|
|
18
|
+
getX(i: number): number;
|
|
19
|
+
} | null;
|
|
20
|
+
readonly drawRange?: {
|
|
21
|
+
readonly start: number;
|
|
22
|
+
readonly count: number;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/** What this reads of `THREE.Object3D`. Real three.js objects fit; nothing else is touched. */
|
|
26
|
+
interface ThreeObject {
|
|
27
|
+
readonly name: string;
|
|
28
|
+
readonly userData: Record<string, unknown>;
|
|
29
|
+
readonly children: readonly ThreeObject[];
|
|
30
|
+
readonly matrixWorld: {
|
|
31
|
+
readonly elements: ArrayLike<number>;
|
|
32
|
+
};
|
|
33
|
+
updateWorldMatrix?(updateParents: boolean, updateChildren: boolean): void;
|
|
34
|
+
readonly isMesh?: boolean;
|
|
35
|
+
readonly isSkinnedMesh?: boolean;
|
|
36
|
+
readonly isInstancedMesh?: boolean;
|
|
37
|
+
readonly isBatchedMesh?: boolean;
|
|
38
|
+
readonly isLOD?: boolean;
|
|
39
|
+
readonly levels?: readonly {
|
|
40
|
+
readonly object: ThreeObject;
|
|
41
|
+
}[];
|
|
42
|
+
readonly geometry?: ThreeGeometry;
|
|
43
|
+
readonly morphTargetInfluences?: readonly number[];
|
|
44
|
+
readonly count?: number;
|
|
45
|
+
readonly instanceMatrix?: {
|
|
46
|
+
readonly array: ArrayLike<number>;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/** What a `GLTFLoader` hands back, enough of it: animations say which nodes move. */
|
|
50
|
+
interface ThreeModel {
|
|
51
|
+
readonly scene: ThreeObject;
|
|
52
|
+
readonly animations?: readonly {
|
|
53
|
+
readonly tracks: readonly {
|
|
54
|
+
readonly name: string;
|
|
55
|
+
}[];
|
|
56
|
+
}[];
|
|
57
|
+
}
|
|
58
|
+
interface SceneFromThreeOptions {
|
|
59
|
+
/** Room units in one three.js unit. Default 1: a game that draws the server's numbers directly, as `(x, z, -y)`. */
|
|
60
|
+
readonly scale?: number;
|
|
61
|
+
/** What a report's areas are in, and how a missing hull is sized. */
|
|
62
|
+
readonly unitsPerMeter?: number;
|
|
63
|
+
readonly hull?: LevelHull;
|
|
64
|
+
/** The level's name in the fit's report. */
|
|
65
|
+
readonly level?: string;
|
|
66
|
+
/** Spawns not marked in the scene, in the room's axes and units. */
|
|
67
|
+
readonly spawns?: readonly {
|
|
68
|
+
readonly at: readonly [number, number, number];
|
|
69
|
+
readonly name?: string;
|
|
70
|
+
readonly tags?: readonly string[];
|
|
71
|
+
}[];
|
|
72
|
+
}
|
|
73
|
+
/** Turns a three.js level into the scene format. Throws {@link LevelRefusal}, as the glTF reader does. World matrices are
|
|
74
|
+
* brought up to date and nothing else in the scene changes. */
|
|
75
|
+
declare function sceneFromThree(input: ThreeObject | ThreeModel, options?: SceneFromThreeOptions): LevelScene;
|
|
76
|
+
|
|
77
|
+
export { LevelScene, type SceneFromThreeOptions, type ThreeAttribute, type ThreeGeometry, type ThreeModel, type ThreeObject, sceneFromThree };
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LEVEL_LIMITS,
|
|
3
|
+
LevelCollide,
|
|
4
|
+
LevelRefusal,
|
|
5
|
+
LevelRefusalCode,
|
|
6
|
+
buildLevelScene,
|
|
7
|
+
inheritMark,
|
|
8
|
+
levelMarkOf,
|
|
9
|
+
levelSettingsOf,
|
|
10
|
+
multiplyMatrix,
|
|
11
|
+
namesInRefusal,
|
|
12
|
+
spawnNameOf
|
|
13
|
+
} from "../chunk-TVTVIMIH.js";
|
|
14
|
+
|
|
15
|
+
// src/world-fit/three.ts
|
|
16
|
+
var DEFAULT_UNITS_PER_METER = 39.37;
|
|
17
|
+
var MATRIX_ELEMENTS = 16;
|
|
18
|
+
var isModel = (v) => "scene" in v && !("children" in v);
|
|
19
|
+
function animatedNames(model) {
|
|
20
|
+
const out = /* @__PURE__ */ new Set();
|
|
21
|
+
for (const clip of model.animations ?? []) {
|
|
22
|
+
for (const track of clip.tracks) {
|
|
23
|
+
const dot = track.name.lastIndexOf(".");
|
|
24
|
+
if (dot > 0 && /\.(position|quaternion|scale)$/.test(track.name)) out.add(track.name.slice(0, dot));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return out;
|
|
28
|
+
}
|
|
29
|
+
function primitiveOf(geometry, cache) {
|
|
30
|
+
const seen = cache.get(geometry);
|
|
31
|
+
if (seen !== void 0) return seen;
|
|
32
|
+
const position = geometry.attributes.position;
|
|
33
|
+
if (position === void 0 || position.count === 0) {
|
|
34
|
+
cache.set(geometry, null);
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
const positions = new Float64Array(position.count * 3);
|
|
38
|
+
for (let i = 0; i < position.count; i++) {
|
|
39
|
+
positions[i * 3] = position.getX(i);
|
|
40
|
+
positions[i * 3 + 1] = position.getY(i);
|
|
41
|
+
positions[i * 3 + 2] = position.getZ(i);
|
|
42
|
+
}
|
|
43
|
+
const full = geometry.index === null ? position.count : geometry.index.count;
|
|
44
|
+
const start = Math.max(0, geometry.drawRange?.start ?? 0);
|
|
45
|
+
const end = Math.min(full, start + (geometry.drawRange?.count ?? Number.POSITIVE_INFINITY));
|
|
46
|
+
const usable = Math.floor(Math.max(0, end - start) / 3) * 3;
|
|
47
|
+
const indices = new Uint32Array(usable);
|
|
48
|
+
for (let i = 0; i < usable; i++) indices[i] = geometry.index === null ? start + i : geometry.index.getX(start + i);
|
|
49
|
+
const primitive = { positions, indices };
|
|
50
|
+
cache.set(geometry, primitive);
|
|
51
|
+
return primitive;
|
|
52
|
+
}
|
|
53
|
+
function instancesOf(object) {
|
|
54
|
+
const world = object.matrixWorld.elements;
|
|
55
|
+
if (object.isInstancedMesh !== true) return [world];
|
|
56
|
+
const out = [];
|
|
57
|
+
const array = object.instanceMatrix?.array ?? [];
|
|
58
|
+
const count = object.count ?? 0;
|
|
59
|
+
for (let i = 0; i < count; i++) {
|
|
60
|
+
const own = new Float64Array(MATRIX_ELEMENTS);
|
|
61
|
+
for (let k = 0; k < MATRIX_ELEMENTS; k++) own[k] = array[i * MATRIX_ELEMENTS + k];
|
|
62
|
+
out.push(multiplyMatrix(world, own));
|
|
63
|
+
}
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
function sceneFromThree(input, options = {}) {
|
|
67
|
+
const root = isModel(input) ? input.scene : input;
|
|
68
|
+
const animated = isModel(input) ? animatedNames(input) : /* @__PURE__ */ new Set();
|
|
69
|
+
root.updateWorldMatrix?.(true, true);
|
|
70
|
+
const settings = levelSettingsOf(root.userData.genex, "the root");
|
|
71
|
+
const meshes = [];
|
|
72
|
+
const spawns = [];
|
|
73
|
+
const notes = [];
|
|
74
|
+
const skinned = [];
|
|
75
|
+
const morphed = [];
|
|
76
|
+
const geometries = /* @__PURE__ */ new Map();
|
|
77
|
+
let triangles = 0;
|
|
78
|
+
let visited = 0;
|
|
79
|
+
const rootMark = levelMarkOf(root.name, root.userData.genex, root.name === "" ? "the root" : root.name, true);
|
|
80
|
+
const stack = [];
|
|
81
|
+
const pushChildren = (object, mark, path) => {
|
|
82
|
+
if (object.isLOD === true && object.levels !== void 0) {
|
|
83
|
+
const near = object.levels[0]?.object;
|
|
84
|
+
if (near !== void 0) stack.push({ object: near, mark, path });
|
|
85
|
+
if (object.levels.length > 1) notes.push(`${path === "" ? "an LOD" : path}: only its nearest level collides`);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
for (let i = object.children.length - 1; i >= 0; i--) stack.push({ object: object.children[i], mark, path });
|
|
89
|
+
};
|
|
90
|
+
if (root.isMesh === true) stack.push({ object: root, mark: {}, path: "" });
|
|
91
|
+
else pushChildren(root, rootMark, "");
|
|
92
|
+
for (let frame = stack.pop(); frame !== void 0; frame = stack.pop()) {
|
|
93
|
+
const { object } = frame;
|
|
94
|
+
visited++;
|
|
95
|
+
if (visited > LEVEL_LIMITS.maxNodes) throw new LevelRefusal(LevelRefusalCode.TooLarge, `the level holds over ${LEVEL_LIMITS.maxNodes} objects`);
|
|
96
|
+
const name = object.name === "" ? `object_${visited}` : object.name;
|
|
97
|
+
const own = levelMarkOf(name, object.userData.genex, name);
|
|
98
|
+
const mark = inheritMark(frame.mark, animated.has(object.name) ? { ...own, movable: true } : own);
|
|
99
|
+
const path = frame.path === "" ? name : `${frame.path}/${name}`;
|
|
100
|
+
pushChildren(object, mark, path);
|
|
101
|
+
if (own.spawn === true) {
|
|
102
|
+
const world = object.matrixWorld.elements;
|
|
103
|
+
spawns.push({ name: spawnNameOf(name), at: [world[12], world[13], world[14]], tags: own.tags ?? [] });
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (object.isMesh !== true || mark.collide === LevelCollide.None) continue;
|
|
107
|
+
if (mark.movable !== true) {
|
|
108
|
+
if (object.isSkinnedMesh === true) {
|
|
109
|
+
skinned.push(name);
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
if ((object.morphTargetInfluences ?? []).some((w) => w !== 0)) {
|
|
113
|
+
morphed.push(name);
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (object.isBatchedMesh === true) throw new LevelRefusal(LevelRefusalCode.Unsupported, `${name} is a BatchedMesh, which this cannot read: use plain or instanced meshes for what collides, or mark it nocol_`);
|
|
118
|
+
if (object.geometry === void 0) continue;
|
|
119
|
+
const primitive = primitiveOf(object.geometry, geometries);
|
|
120
|
+
if (primitive === null) continue;
|
|
121
|
+
const instances = instancesOf(object);
|
|
122
|
+
triangles += primitive.indices.length / 3 * instances.length;
|
|
123
|
+
if (triangles > LEVEL_LIMITS.maxTriangles) throw new LevelRefusal(LevelRefusalCode.TooLarge, `the level holds over ${LEVEL_LIMITS.maxTriangles} triangles (${name} is where it passes); give what no one walks on a nocol_ mark or a collision proxy`);
|
|
124
|
+
meshes.push({ name, path, mark, instances, primitives: [primitive] });
|
|
125
|
+
}
|
|
126
|
+
if (skinned.length > 0) throw new LevelRefusal(LevelRefusalCode.Skinned, `a room's world is static and these are skinned: ${namesInRefusal(skinned)}. Mark them nocol_ and collide with a static proxy, or movable_`);
|
|
127
|
+
if (morphed.length > 0) throw new LevelRefusal(LevelRefusalCode.Morphed, `a room's world is static and these are posed by morph targets: ${namesInRefusal(morphed)}. Mark them nocol_ and collide with a static proxy, or movable_`);
|
|
128
|
+
const unitsPerMeter = options.unitsPerMeter ?? settings.unitsPerMeter ?? DEFAULT_UNITS_PER_METER;
|
|
129
|
+
const hull = options.hull ?? settings.hull;
|
|
130
|
+
return buildLevelScene(
|
|
131
|
+
{ meshes, spawns, notes },
|
|
132
|
+
{ scale: options.scale ?? 1, unitsPerMeter, ...hull === void 0 ? {} : { hull }, ...options.spawns === void 0 ? {} : { spawns: options.spawns }, source: { engine: "three.js", ...options.level === void 0 ? {} : { level: options.level }, tool: "sceneFromThree" } }
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
export {
|
|
136
|
+
LEVEL_LIMITS,
|
|
137
|
+
LevelRefusal,
|
|
138
|
+
LevelRefusalCode,
|
|
139
|
+
sceneFromThree
|
|
140
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@genex-ai/multiplayer",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.9",
|
|
4
4
|
"description": "The multiplayer client wrapper + shared room schema for genex.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -51,12 +51,24 @@
|
|
|
51
51
|
"types": "./dist/authority/fast-webtransport.d.ts",
|
|
52
52
|
"import": "./dist/authority/fast-webtransport.js"
|
|
53
53
|
},
|
|
54
|
+
"./world-fit": {
|
|
55
|
+
"@genex-ai/source": "./src/world-fit/index.ts",
|
|
56
|
+
"types": "./dist/world-fit/index.d.ts",
|
|
57
|
+
"import": "./dist/world-fit/index.js"
|
|
58
|
+
},
|
|
59
|
+
"./world-fit/three": {
|
|
60
|
+
"@genex-ai/source": "./src/world-fit/three.ts",
|
|
61
|
+
"types": "./dist/world-fit/three.d.ts",
|
|
62
|
+
"import": "./dist/world-fit/three.js"
|
|
63
|
+
},
|
|
54
64
|
"./bridge.global.js": "./dist/bridge.global.js",
|
|
55
65
|
"./bridge-authority.global.js": "./dist/bridge-authority.global.js"
|
|
56
66
|
},
|
|
57
67
|
"files": [
|
|
58
68
|
"dist",
|
|
59
|
-
"PROTOCOL.md"
|
|
69
|
+
"PROTOCOL.md",
|
|
70
|
+
"WORLD-SCENE.md",
|
|
71
|
+
"WORLD-GLTF.md"
|
|
60
72
|
],
|
|
61
73
|
"scripts": {
|
|
62
74
|
"build": "tsup",
|
|
@@ -90,7 +102,7 @@
|
|
|
90
102
|
"@colyseus/uwebsockets-transport": "^0.18.4",
|
|
91
103
|
"@colyseus/ws-transport": "^0.18.4",
|
|
92
104
|
"@genex-ai/embed-sdk": "workspace:*",
|
|
93
|
-
"@genex-ai/physics": "file:../authority-host/vendor/genex-ai-physics-0.1.
|
|
105
|
+
"@genex-ai/physics": "file:../authority-host/vendor/genex-ai-physics-0.1.1.tgz",
|
|
94
106
|
"publint": "^0.3.0",
|
|
95
107
|
"tsup": "^8.0.0",
|
|
96
108
|
"typescript": "^5.8.0"
|