@series-inc/rundot-syncplay 5.23.0-beta.7
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/README.md +610 -0
- package/dist/animation.d.ts +119 -0
- package/dist/animation.js +488 -0
- package/dist/asset-cooking.d.ts +82 -0
- package/dist/asset-cooking.js +364 -0
- package/dist/authority-room.d.ts +217 -0
- package/dist/authority-room.js +701 -0
- package/dist/bot-documents.d.ts +115 -0
- package/dist/bot-documents.js +549 -0
- package/dist/bot-primitives.d.ts +152 -0
- package/dist/bot-primitives.js +472 -0
- package/dist/browser.d.ts +57 -0
- package/dist/browser.js +53 -0
- package/dist/canonical.d.ts +12 -0
- package/dist/canonical.js +288 -0
- package/dist/certification.d.ts +455 -0
- package/dist/certification.js +1855 -0
- package/dist/chaos-certification.d.ts +56 -0
- package/dist/chaos-certification.js +1397 -0
- package/dist/cjs/animation.js +495 -0
- package/dist/cjs/asset-cooking.js +372 -0
- package/dist/cjs/authority-room.js +704 -0
- package/dist/cjs/bot-documents.js +556 -0
- package/dist/cjs/bot-primitives.js +482 -0
- package/dist/cjs/browser.js +96 -0
- package/dist/cjs/canonical.js +299 -0
- package/dist/cjs/certification.js +1860 -0
- package/dist/cjs/chaos-certification.js +1402 -0
- package/dist/cjs/collections.js +36 -0
- package/dist/cjs/collision.js +96 -0
- package/dist/cjs/commands.js +987 -0
- package/dist/cjs/config-bundle.js +491 -0
- package/dist/cjs/creator.js +30 -0
- package/dist/cjs/deterministic-primitives.js +134 -0
- package/dist/cjs/deterministic-session.js +1410 -0
- package/dist/cjs/ecs-lite.js +155 -0
- package/dist/cjs/effects-adapter.js +97 -0
- package/dist/cjs/engine-complete.js +2297 -0
- package/dist/cjs/engine-core-proof.js +70 -0
- package/dist/cjs/engine-parity-matrix.js +874 -0
- package/dist/cjs/engine-parity.js +3183 -0
- package/dist/cjs/engine-runtime.js +3141 -0
- package/dist/cjs/errors.js +22 -0
- package/dist/cjs/events.js +247 -0
- package/dist/cjs/examples/counter-duel.js +157 -0
- package/dist/cjs/examples/fixed-arena.js +368 -0
- package/dist/cjs/index.js +229 -0
- package/dist/cjs/input-authority.js +150 -0
- package/dist/cjs/input-button.js +256 -0
- package/dist/cjs/input-timeline.js +418 -0
- package/dist/cjs/instant-replay.js +66 -0
- package/dist/cjs/lag-compensation3d.js +837 -0
- package/dist/cjs/local-authority-server-runner.js +1121 -0
- package/dist/cjs/local-authority-wire.js +1497 -0
- package/dist/cjs/local-authority.js +817 -0
- package/dist/cjs/local-ws-adapter.js +150 -0
- package/dist/cjs/match-log.js +61 -0
- package/dist/cjs/math.js +157 -0
- package/dist/cjs/mock-network-adapter.js +26 -0
- package/dist/cjs/movement.js +703 -0
- package/dist/cjs/movement3d.js +1246 -0
- package/dist/cjs/multiclient-authority.js +308 -0
- package/dist/cjs/multiplayer-service.js +434 -0
- package/dist/cjs/navigation.js +347 -0
- package/dist/cjs/navmesh.js +1437 -0
- package/dist/cjs/networked-client.js +691 -0
- package/dist/cjs/networked-input-authority.js +443 -0
- package/dist/cjs/node.js +47 -0
- package/dist/cjs/number-lab.js +78 -0
- package/dist/cjs/offline-session.js +370 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/pause-resume.js +43 -0
- package/dist/cjs/physics-cert.js +426 -0
- package/dist/cjs/physics2d.js +751 -0
- package/dist/cjs/physics3d.js +1996 -0
- package/dist/cjs/prediction-culling.js +203 -0
- package/dist/cjs/protocol-lab.js +1299 -0
- package/dist/cjs/r3f-render-adapter.js +209 -0
- package/dist/cjs/random.js +59 -0
- package/dist/cjs/replay-bundle.js +1598 -0
- package/dist/cjs/replay-inspect.js +236 -0
- package/dist/cjs/replay-scoring.js +68 -0
- package/dist/cjs/replay.js +356 -0
- package/dist/cjs/reports.js +181 -0
- package/dist/cjs/rollback-history.js +251 -0
- package/dist/cjs/runtime-guards.js +111 -0
- package/dist/cjs/sample-lab.js +145 -0
- package/dist/cjs/sample-scenes.js +752 -0
- package/dist/cjs/schema-artifacts.js +359 -0
- package/dist/cjs/schema-codegen.js +544 -0
- package/dist/cjs/schema-dsl-binary.js +655 -0
- package/dist/cjs/schema.js +319 -0
- package/dist/cjs/sdk-offline.js +99 -0
- package/dist/cjs/session-promotion.js +74 -0
- package/dist/cjs/session-snapshot.js +265 -0
- package/dist/cjs/session-wire.js +216 -0
- package/dist/cjs/signals.js +103 -0
- package/dist/cjs/sparse-set.js +169 -0
- package/dist/cjs/synctest.js +136 -0
- package/dist/cjs/system-lifecycle.js +286 -0
- package/dist/cjs/timers.js +61 -0
- package/dist/cjs/tools/static-checker.js +1468 -0
- package/dist/cjs/types.js +2 -0
- package/dist/cjs/venus-mp-budget.js +125 -0
- package/dist/cjs/ws-frame.js +255 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +11379 -0
- package/dist/collections.d.ts +9 -0
- package/dist/collections.js +30 -0
- package/dist/collision.d.ts +25 -0
- package/dist/collision.js +85 -0
- package/dist/commands.d.ts +137 -0
- package/dist/commands.js +977 -0
- package/dist/config-bundle.d.ts +89 -0
- package/dist/config-bundle.js +483 -0
- package/dist/creator.d.ts +20 -0
- package/dist/creator.js +11 -0
- package/dist/deterministic-primitives.d.ts +59 -0
- package/dist/deterministic-primitives.js +126 -0
- package/dist/deterministic-session.d.ts +197 -0
- package/dist/deterministic-session.js +1401 -0
- package/dist/ecs-lite.d.ts +26 -0
- package/dist/ecs-lite.js +152 -0
- package/dist/effects-adapter.d.ts +21 -0
- package/dist/effects-adapter.js +94 -0
- package/dist/engine-complete.d.ts +45 -0
- package/dist/engine-complete.js +2292 -0
- package/dist/engine-core-proof.d.ts +26 -0
- package/dist/engine-core-proof.js +66 -0
- package/dist/engine-parity-matrix.d.ts +300 -0
- package/dist/engine-parity-matrix.js +869 -0
- package/dist/engine-parity.d.ts +74 -0
- package/dist/engine-parity.js +3178 -0
- package/dist/engine-runtime.d.ts +351 -0
- package/dist/engine-runtime.js +3123 -0
- package/dist/errors.d.ts +11 -0
- package/dist/errors.js +17 -0
- package/dist/events.d.ts +45 -0
- package/dist/events.js +242 -0
- package/dist/examples/counter-duel.d.ts +43 -0
- package/dist/examples/counter-duel.js +150 -0
- package/dist/examples/fixed-arena.d.ts +110 -0
- package/dist/examples/fixed-arena.js +356 -0
- package/dist/index.d.ts +101 -0
- package/dist/index.js +66 -0
- package/dist/input-authority.d.ts +82 -0
- package/dist/input-authority.js +147 -0
- package/dist/input-button.d.ts +36 -0
- package/dist/input-button.js +249 -0
- package/dist/input-timeline.d.ts +65 -0
- package/dist/input-timeline.js +412 -0
- package/dist/instant-replay.d.ts +59 -0
- package/dist/instant-replay.js +62 -0
- package/dist/lag-compensation3d.d.ts +146 -0
- package/dist/lag-compensation3d.js +827 -0
- package/dist/local-authority-server-runner.d.ts +79 -0
- package/dist/local-authority-server-runner.js +1118 -0
- package/dist/local-authority-wire.d.ts +142 -0
- package/dist/local-authority-wire.js +1477 -0
- package/dist/local-authority.d.ts +160 -0
- package/dist/local-authority.js +810 -0
- package/dist/local-ws-adapter.d.ts +14 -0
- package/dist/local-ws-adapter.js +146 -0
- package/dist/match-log.d.ts +74 -0
- package/dist/match-log.js +57 -0
- package/dist/math.d.ts +41 -0
- package/dist/math.js +154 -0
- package/dist/mock-network-adapter.d.ts +13 -0
- package/dist/mock-network-adapter.js +23 -0
- package/dist/movement.d.ts +155 -0
- package/dist/movement.js +694 -0
- package/dist/movement3d.d.ts +195 -0
- package/dist/movement3d.js +1238 -0
- package/dist/multiclient-authority.d.ts +30 -0
- package/dist/multiclient-authority.js +305 -0
- package/dist/multiplayer-service.d.ts +153 -0
- package/dist/multiplayer-service.js +429 -0
- package/dist/navigation.d.ts +91 -0
- package/dist/navigation.js +338 -0
- package/dist/navmesh.d.ts +236 -0
- package/dist/navmesh.js +1423 -0
- package/dist/networked-client.d.ts +124 -0
- package/dist/networked-client.js +688 -0
- package/dist/networked-input-authority.d.ts +51 -0
- package/dist/networked-input-authority.js +439 -0
- package/dist/node.d.ts +22 -0
- package/dist/node.js +19 -0
- package/dist/number-lab.d.ts +15 -0
- package/dist/number-lab.js +75 -0
- package/dist/offline-session.d.ts +2 -0
- package/dist/offline-session.js +367 -0
- package/dist/pause-resume.d.ts +48 -0
- package/dist/pause-resume.js +40 -0
- package/dist/physics-cert.d.ts +40 -0
- package/dist/physics-cert.js +389 -0
- package/dist/physics2d.d.ts +142 -0
- package/dist/physics2d.js +741 -0
- package/dist/physics3d.d.ts +285 -0
- package/dist/physics3d.js +1979 -0
- package/dist/prediction-culling.d.ts +34 -0
- package/dist/prediction-culling.js +200 -0
- package/dist/protocol-lab.d.ts +115 -0
- package/dist/protocol-lab.js +1295 -0
- package/dist/r3f-render-adapter.d.ts +61 -0
- package/dist/r3f-render-adapter.js +203 -0
- package/dist/random.d.ts +13 -0
- package/dist/random.js +55 -0
- package/dist/replay-bundle.d.ts +150 -0
- package/dist/replay-bundle.js +1586 -0
- package/dist/replay-inspect.d.ts +60 -0
- package/dist/replay-inspect.js +228 -0
- package/dist/replay-scoring.d.ts +28 -0
- package/dist/replay-scoring.js +65 -0
- package/dist/replay.d.ts +17 -0
- package/dist/replay.js +351 -0
- package/dist/reports.d.ts +176 -0
- package/dist/reports.js +174 -0
- package/dist/rollback-history.d.ts +46 -0
- package/dist/rollback-history.js +247 -0
- package/dist/runtime-guards.d.ts +1 -0
- package/dist/runtime-guards.js +108 -0
- package/dist/sample-lab.d.ts +32 -0
- package/dist/sample-lab.js +134 -0
- package/dist/sample-scenes.d.ts +86 -0
- package/dist/sample-scenes.js +745 -0
- package/dist/schema-artifacts.d.ts +49 -0
- package/dist/schema-artifacts.js +356 -0
- package/dist/schema-codegen.d.ts +21 -0
- package/dist/schema-codegen.js +538 -0
- package/dist/schema-dsl-binary.d.ts +75 -0
- package/dist/schema-dsl-binary.js +648 -0
- package/dist/schema.d.ts +87 -0
- package/dist/schema.js +315 -0
- package/dist/sdk-offline.d.ts +34 -0
- package/dist/sdk-offline.js +96 -0
- package/dist/session-promotion.d.ts +26 -0
- package/dist/session-promotion.js +70 -0
- package/dist/session-snapshot.d.ts +95 -0
- package/dist/session-snapshot.js +255 -0
- package/dist/session-wire.d.ts +89 -0
- package/dist/session-wire.js +211 -0
- package/dist/signals.d.ts +31 -0
- package/dist/signals.js +99 -0
- package/dist/sparse-set.d.ts +34 -0
- package/dist/sparse-set.js +165 -0
- package/dist/synctest.d.ts +31 -0
- package/dist/synctest.js +133 -0
- package/dist/system-lifecycle.d.ts +72 -0
- package/dist/system-lifecycle.js +281 -0
- package/dist/timers.d.ts +17 -0
- package/dist/timers.js +53 -0
- package/dist/tools/index.d.ts +4 -0
- package/dist/tools/index.js +4 -0
- package/dist/tools/static-checker.d.ts +31 -0
- package/dist/tools/static-checker.js +1462 -0
- package/dist/tools/vite-plugin.d.ts +69 -0
- package/dist/tools/vite-plugin.js +203 -0
- package/dist/types.d.ts +148 -0
- package/dist/types.js +1 -0
- package/dist/venus-mp-budget.d.ts +29 -0
- package/dist/venus-mp-budget.js +122 -0
- package/dist/ws-frame.d.ts +49 -0
- package/dist/ws-frame.js +247 -0
- package/package.json +169 -0
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cookDeterministicNavigationGraph = cookDeterministicNavigationGraph;
|
|
4
|
+
exports.findDeterministicPath = findDeterministicPath;
|
|
5
|
+
exports.createDeterministicFlowField = createDeterministicFlowField;
|
|
6
|
+
exports.smoothDeterministicPath = smoothDeterministicPath;
|
|
7
|
+
exports.applyDeterministicReciprocalAvoidance = applyDeterministicReciprocalAvoidance;
|
|
8
|
+
exports.cookTilemapNavigationGraph = cookTilemapNavigationGraph;
|
|
9
|
+
exports.stepDeterministicNavigationAgents = stepDeterministicNavigationAgents;
|
|
10
|
+
const canonical_js_1 = require("./canonical.js");
|
|
11
|
+
function cookDeterministicNavigationGraph(source) {
|
|
12
|
+
const nodes = [...source.nodes].sort(compareNavNodes);
|
|
13
|
+
const edges = [...expandBidirectionalEdges(source.edges)].sort(compareNavEdges);
|
|
14
|
+
const regions = [...(source.regions ?? [])].sort(compareNavRegions);
|
|
15
|
+
const nodeIds = new Set();
|
|
16
|
+
for (const node of nodes) {
|
|
17
|
+
if (nodeIds.has(node.id)) {
|
|
18
|
+
throw new Error(`Duplicate navigation node id ${node.id}`);
|
|
19
|
+
}
|
|
20
|
+
nodeIds.add(node.id);
|
|
21
|
+
}
|
|
22
|
+
for (const edge of edges) {
|
|
23
|
+
if (!nodeIds.has(edge.from) || !nodeIds.has(edge.to)) {
|
|
24
|
+
throw new Error(`Navigation edge ${edge.from}->${edge.to} references a missing node`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const cooked = { id: source.id, nodes, edges, regions };
|
|
28
|
+
const bytes = (0, canonical_js_1.canonicalStringify)(cooked);
|
|
29
|
+
return {
|
|
30
|
+
...cooked,
|
|
31
|
+
bytes,
|
|
32
|
+
hash: (0, canonical_js_1.defaultChecksum)(bytes),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function findDeterministicPath(graph, query) {
|
|
36
|
+
const nodes = nodeMap(graph);
|
|
37
|
+
if (!nodes.has(query.start) || !nodes.has(query.goal)) {
|
|
38
|
+
return emptyPathResult();
|
|
39
|
+
}
|
|
40
|
+
const disabledRegions = new Set(query.disabledRegionIds ?? []);
|
|
41
|
+
const blockedNodes = new Set(query.blockedNodeIds ?? []);
|
|
42
|
+
if (isNodeBlocked(nodes.get(query.start), disabledRegions, blockedNodes)
|
|
43
|
+
|| isNodeBlocked(nodes.get(query.goal), disabledRegions, blockedNodes)) {
|
|
44
|
+
return emptyPathResult();
|
|
45
|
+
}
|
|
46
|
+
const adjacency = adjacencyMap(graph);
|
|
47
|
+
const open = [{ id: query.start, f: heuristic(nodes.get(query.start), nodes.get(query.goal)), g: 0, order: 0 }];
|
|
48
|
+
const cameFrom = new Map();
|
|
49
|
+
const bestCost = new Map([[query.start, 0]]);
|
|
50
|
+
const visited = new Set();
|
|
51
|
+
let pushOrder = 1;
|
|
52
|
+
while (open.length > 0) {
|
|
53
|
+
open.sort(compareQueueEntries);
|
|
54
|
+
const current = open.shift();
|
|
55
|
+
if (visited.has(current.id)) {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
visited.add(current.id);
|
|
59
|
+
if (current.id === query.goal) {
|
|
60
|
+
const path = reconstructPath(cameFrom, current.id);
|
|
61
|
+
return {
|
|
62
|
+
found: true,
|
|
63
|
+
nodes: path,
|
|
64
|
+
cost: current.g,
|
|
65
|
+
visitedNodeCount: visited.size,
|
|
66
|
+
offMeshTraversals: countOffMeshTraversals(graph, path),
|
|
67
|
+
pathHash: (0, canonical_js_1.defaultChecksum)(path),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
const neighbors = [...(adjacency.get(current.id) ?? [])].sort(compareNavEdges);
|
|
71
|
+
for (const edge of neighbors) {
|
|
72
|
+
const next = nodes.get(edge.to);
|
|
73
|
+
if (next === undefined || isNodeBlocked(next, disabledRegions, blockedNodes)) {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
const candidateCost = current.g + (edge.cost ?? 1) + (next.cost ?? 1);
|
|
77
|
+
const knownCost = bestCost.get(edge.to);
|
|
78
|
+
if (knownCost !== undefined && candidateCost >= knownCost) {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
cameFrom.set(edge.to, current.id);
|
|
82
|
+
bestCost.set(edge.to, candidateCost);
|
|
83
|
+
open.push({
|
|
84
|
+
id: edge.to,
|
|
85
|
+
f: candidateCost + heuristic(next, nodes.get(query.goal)),
|
|
86
|
+
g: candidateCost,
|
|
87
|
+
order: pushOrder,
|
|
88
|
+
});
|
|
89
|
+
pushOrder += 1;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
found: false,
|
|
94
|
+
nodes: [],
|
|
95
|
+
cost: 0,
|
|
96
|
+
visitedNodeCount: visited.size,
|
|
97
|
+
offMeshTraversals: 0,
|
|
98
|
+
pathHash: (0, canonical_js_1.defaultChecksum)([]),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function createDeterministicFlowField(graph, goal, options = {}) {
|
|
102
|
+
const nextByNodeId = {};
|
|
103
|
+
for (const node of graph.nodes) {
|
|
104
|
+
const path = findDeterministicPath(graph, {
|
|
105
|
+
...options,
|
|
106
|
+
start: node.id,
|
|
107
|
+
goal,
|
|
108
|
+
});
|
|
109
|
+
if (path.found && path.nodes.length > 1) {
|
|
110
|
+
nextByNodeId[node.id] = path.nodes[1];
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
const stable = Object.fromEntries(Object.entries(nextByNodeId).sort(compareStringEntries));
|
|
114
|
+
return {
|
|
115
|
+
goal,
|
|
116
|
+
nextByNodeId: stable,
|
|
117
|
+
hash: (0, canonical_js_1.defaultChecksum)(stable),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
function smoothDeterministicPath(graph, path) {
|
|
121
|
+
if (path.length <= 2) {
|
|
122
|
+
return path;
|
|
123
|
+
}
|
|
124
|
+
const nodes = nodeMap(graph);
|
|
125
|
+
const smoothed = [path[0]];
|
|
126
|
+
for (let index = 1; index < path.length - 1; index += 1) {
|
|
127
|
+
const prev = nodes.get(smoothed[smoothed.length - 1]);
|
|
128
|
+
const current = nodes.get(path[index]);
|
|
129
|
+
const next = nodes.get(path[index + 1]);
|
|
130
|
+
if (prev === undefined || current === undefined || next === undefined) {
|
|
131
|
+
smoothed.push(path[index]);
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
const collinear = (current.x - prev.x) * (next.y - current.y) === (current.y - prev.y) * (next.x - current.x);
|
|
135
|
+
if (!collinear || isOffMeshEdge(graph, path[index - 1], path[index]) || isOffMeshEdge(graph, path[index], path[index + 1])) {
|
|
136
|
+
smoothed.push(path[index]);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
smoothed.push(path[path.length - 1]);
|
|
140
|
+
return smoothed;
|
|
141
|
+
}
|
|
142
|
+
function applyDeterministicReciprocalAvoidance(agents) {
|
|
143
|
+
const occupancy = new Map();
|
|
144
|
+
for (const agent of [...agents].sort(compareAgents)) {
|
|
145
|
+
occupancy.set(agent.nodeId, [...(occupancy.get(agent.nodeId) ?? []), agent]);
|
|
146
|
+
}
|
|
147
|
+
let corrections = 0;
|
|
148
|
+
const adjusted = [...agents].sort(compareAgents).map((agent) => {
|
|
149
|
+
/* istanbul ignore next -- every adjusted agent was inserted into occupancy by nodeId above. */
|
|
150
|
+
const peers = occupancy.get(agent.nodeId) ?? [];
|
|
151
|
+
if (peers.length <= 1) {
|
|
152
|
+
return agent;
|
|
153
|
+
}
|
|
154
|
+
const peerIndex = peers.findIndex((peer) => peer.id === agent.id);
|
|
155
|
+
corrections += peerIndex === 0 ? 0 : 1;
|
|
156
|
+
return {
|
|
157
|
+
...agent,
|
|
158
|
+
pathIndex: (agent.pathIndex ?? 0) + peerIndex,
|
|
159
|
+
};
|
|
160
|
+
});
|
|
161
|
+
return {
|
|
162
|
+
agents: (0, canonical_js_1.cloneCanonical)(adjusted),
|
|
163
|
+
corrections,
|
|
164
|
+
hash: (0, canonical_js_1.defaultChecksum)(adjusted),
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
function cookTilemapNavigationGraph(source) {
|
|
168
|
+
const blocked = new Set(source.blocked ?? []);
|
|
169
|
+
const nodes = [];
|
|
170
|
+
const edges = [];
|
|
171
|
+
for (let y = 0; y < source.height; y += 1) {
|
|
172
|
+
for (let x = 0; x < source.width; x += 1) {
|
|
173
|
+
const id = `${x},${y}`;
|
|
174
|
+
if (blocked.has(id)) {
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
nodes.push({ id, x, y, cost: source.costs?.[id] ?? 1 });
|
|
178
|
+
for (const [dx, dy] of [[-1, 0], [0, -1]]) {
|
|
179
|
+
const neighbor = `${x + dx},${y + dy}`;
|
|
180
|
+
if (!blocked.has(neighbor) && x + dx >= 0 && y + dy >= 0) {
|
|
181
|
+
edges.push({ from: id, to: neighbor, bidirectional: true });
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
for (const [from, to] of Object.entries(source.portals ?? {}).sort(compareStringEntries)) {
|
|
187
|
+
edges.push({ from, to, cost: 1, offMesh: true });
|
|
188
|
+
}
|
|
189
|
+
return cookDeterministicNavigationGraph({
|
|
190
|
+
id: source.id,
|
|
191
|
+
nodes,
|
|
192
|
+
edges,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
function stepDeterministicNavigationAgents(graph, agents, options) {
|
|
196
|
+
const reserved = new Set();
|
|
197
|
+
const sortedAgents = [...agents].sort(compareAgents);
|
|
198
|
+
const nextAgents = [];
|
|
199
|
+
let replans = 0;
|
|
200
|
+
let avoidanceCorrections = 0;
|
|
201
|
+
let reciprocalAvoidanceCorrections = 0;
|
|
202
|
+
let offMeshTraversals = 0;
|
|
203
|
+
let visitedNodeCount = 0;
|
|
204
|
+
for (const agent of sortedAgents) {
|
|
205
|
+
let path = agent.path ?? [];
|
|
206
|
+
let pathIndex = agent.pathIndex ?? 0;
|
|
207
|
+
if (path.length === 0 || path[path.length - 1] !== agent.targetNodeId || options.frame % 31 === 0) {
|
|
208
|
+
const planned = findDeterministicPath(graph, {
|
|
209
|
+
start: agent.nodeId,
|
|
210
|
+
goal: agent.targetNodeId,
|
|
211
|
+
disabledRegionIds: options.disabledRegionIds,
|
|
212
|
+
blockedNodeIds: options.blockedNodeIds,
|
|
213
|
+
});
|
|
214
|
+
path = planned.nodes;
|
|
215
|
+
pathIndex = 0;
|
|
216
|
+
replans += 1;
|
|
217
|
+
visitedNodeCount += planned.visitedNodeCount;
|
|
218
|
+
}
|
|
219
|
+
const candidate = path[pathIndex + 1] ?? agent.nodeId;
|
|
220
|
+
if (reserved.has(candidate)) {
|
|
221
|
+
reserved.add(agent.nodeId);
|
|
222
|
+
nextAgents.push({ ...agent, path, pathIndex });
|
|
223
|
+
avoidanceCorrections += 1;
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
const moved = candidate !== agent.nodeId;
|
|
227
|
+
reserved.add(candidate);
|
|
228
|
+
if (moved && isOffMeshEdge(graph, agent.nodeId, candidate)) {
|
|
229
|
+
offMeshTraversals += 1;
|
|
230
|
+
}
|
|
231
|
+
nextAgents.push({
|
|
232
|
+
...agent,
|
|
233
|
+
nodeId: candidate,
|
|
234
|
+
path,
|
|
235
|
+
pathIndex: moved ? pathIndex + 1 : pathIndex,
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
const agentsByInputOrder = nextAgents.sort(compareAgents);
|
|
239
|
+
const reciprocal = applyDeterministicReciprocalAvoidance(agentsByInputOrder);
|
|
240
|
+
reciprocalAvoidanceCorrections += reciprocal.corrections;
|
|
241
|
+
return {
|
|
242
|
+
agents: reciprocal.agents,
|
|
243
|
+
replans,
|
|
244
|
+
avoidanceCorrections,
|
|
245
|
+
offMeshTraversals,
|
|
246
|
+
visitedNodeCount,
|
|
247
|
+
reciprocalAvoidanceCorrections,
|
|
248
|
+
agentChecksum: (0, canonical_js_1.defaultChecksum)({ agents: reciprocal.agents, reciprocalHash: reciprocal.hash }),
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
function emptyPathResult() {
|
|
252
|
+
return {
|
|
253
|
+
found: false,
|
|
254
|
+
nodes: [],
|
|
255
|
+
cost: 0,
|
|
256
|
+
visitedNodeCount: 0,
|
|
257
|
+
offMeshTraversals: 0,
|
|
258
|
+
pathHash: (0, canonical_js_1.defaultChecksum)([]),
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
function compareNavNodes(left, right) {
|
|
262
|
+
return compareStrings(left.id, right.id);
|
|
263
|
+
}
|
|
264
|
+
function compareNavEdges(left, right) {
|
|
265
|
+
return compareStrings(`${left.from}->${left.to}`, `${right.from}->${right.to}`);
|
|
266
|
+
}
|
|
267
|
+
function compareNavRegions(left, right) {
|
|
268
|
+
return compareStrings(left.id, right.id);
|
|
269
|
+
}
|
|
270
|
+
function compareAgents(left, right) {
|
|
271
|
+
return compareStrings(left.id, right.id);
|
|
272
|
+
}
|
|
273
|
+
function compareQueueEntries(left, right) {
|
|
274
|
+
const fDelta = left.f - right.f;
|
|
275
|
+
if (fDelta !== 0) {
|
|
276
|
+
return fDelta;
|
|
277
|
+
}
|
|
278
|
+
const gDelta = left.g - right.g;
|
|
279
|
+
if (gDelta !== 0) {
|
|
280
|
+
return gDelta;
|
|
281
|
+
}
|
|
282
|
+
const idDelta = compareStrings(left.id, right.id);
|
|
283
|
+
/* istanbul ignore else -- queue ids are unique after f/g tie-breakers in public graph searches. */
|
|
284
|
+
if (idDelta !== 0) {
|
|
285
|
+
return idDelta;
|
|
286
|
+
}
|
|
287
|
+
/* istanbul ignore next -- queue ids are unique after f/g/id tie-breakers in public graph searches. */
|
|
288
|
+
return left.order - right.order;
|
|
289
|
+
}
|
|
290
|
+
function compareStringEntries(left, right) {
|
|
291
|
+
return compareStrings(left[0], right[0]);
|
|
292
|
+
}
|
|
293
|
+
function compareStrings(left, right) {
|
|
294
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
295
|
+
}
|
|
296
|
+
function expandBidirectionalEdges(edges) {
|
|
297
|
+
const expanded = [];
|
|
298
|
+
for (const edge of edges) {
|
|
299
|
+
expanded.push(edge);
|
|
300
|
+
if (edge.bidirectional === true) {
|
|
301
|
+
expanded.push({
|
|
302
|
+
from: edge.to,
|
|
303
|
+
to: edge.from,
|
|
304
|
+
cost: edge.cost,
|
|
305
|
+
offMesh: edge.offMesh,
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
return expanded;
|
|
310
|
+
}
|
|
311
|
+
function nodeMap(graph) {
|
|
312
|
+
return new Map(graph.nodes.map((node) => [node.id, node]));
|
|
313
|
+
}
|
|
314
|
+
function adjacencyMap(graph) {
|
|
315
|
+
const adjacency = new Map();
|
|
316
|
+
for (const edge of graph.edges) {
|
|
317
|
+
adjacency.set(edge.from, [...(adjacency.get(edge.from) ?? []), edge]);
|
|
318
|
+
}
|
|
319
|
+
return adjacency;
|
|
320
|
+
}
|
|
321
|
+
function isNodeBlocked(node, disabledRegions, blockedNodes) {
|
|
322
|
+
return blockedNodes.has(node.id) || (node.region !== undefined && disabledRegions.has(node.region));
|
|
323
|
+
}
|
|
324
|
+
function heuristic(left, right) {
|
|
325
|
+
return Math.abs(left.x - right.x) + Math.abs(left.y - right.y);
|
|
326
|
+
}
|
|
327
|
+
function reconstructPath(cameFrom, goal) {
|
|
328
|
+
const path = [goal];
|
|
329
|
+
let current = goal;
|
|
330
|
+
while (cameFrom.has(current)) {
|
|
331
|
+
current = cameFrom.get(current);
|
|
332
|
+
path.push(current);
|
|
333
|
+
}
|
|
334
|
+
return path.reverse();
|
|
335
|
+
}
|
|
336
|
+
function countOffMeshTraversals(graph, path) {
|
|
337
|
+
let count = 0;
|
|
338
|
+
for (let index = 1; index < path.length; index += 1) {
|
|
339
|
+
if (isOffMeshEdge(graph, path[index - 1], path[index])) {
|
|
340
|
+
count += 1;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
return count;
|
|
344
|
+
}
|
|
345
|
+
function isOffMeshEdge(graph, from, to) {
|
|
346
|
+
return graph.edges.some((edge) => edge.from === from && edge.to === to && edge.offMesh === true);
|
|
347
|
+
}
|