@series-inc/rundot-syncplay 5.26.0-beta.2 → 5.26.0-beta.3

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.
@@ -1,200 +0,0 @@
1
- import { defaultChecksum } from './canonical.js';
2
- export function runPredictionCullingLab(options) {
3
- validateOptions(options);
4
- const objects = createObjects(options);
5
- let previousPredicted = new Set();
6
- let predictedTotal = 0;
7
- let minPredictedObjects = Number.POSITIVE_INFINITY;
8
- let maxPredictedObjects = 0;
9
- let visibleCorrections = 0;
10
- let hiddenAuthoritativeInteractions = 0;
11
- let predictedObjectSteps = 0;
12
- let verifiedObjectSteps = 0;
13
- let predictedChecksum = '';
14
- let verifiedChecksum = '';
15
- let completeChecksum = '';
16
- const filterHistory = [];
17
- const frameHistory = [];
18
- const restoreFrame = Math.floor(options.frames * 0.6);
19
- for (let frame = 0; frame < options.frames; frame += 1) {
20
- const predictedBySlot = [];
21
- const frameState = [];
22
- for (const object of objects) {
23
- frameState.push(getObjectFrameState(object, frame, options.seed));
24
- }
25
- frameHistory.push(frameState);
26
- const localPredicted = new Set();
27
- for (let slot = 0; slot < options.players; slot += 1) {
28
- const player = getPlayerPosition(slot, frame, options.seed);
29
- const slotPredicted = [];
30
- for (const objectState of frameState) {
31
- const object = objects[objectState.id];
32
- if (shouldPredictObject(options.mode, player, object, objectState, options.radius)) {
33
- slotPredicted.push(objectState.id);
34
- if (slot === 0) {
35
- localPredicted.add(objectState.id);
36
- }
37
- }
38
- }
39
- predictedObjectSteps += slotPredicted.length;
40
- predictedBySlot.push(slotPredicted);
41
- }
42
- for (const objectState of frameState) {
43
- if (objectState.canAffectPlayer && !localPredicted.has(objectState.id)) {
44
- hiddenAuthoritativeInteractions += 1;
45
- }
46
- }
47
- for (const objectId of localPredicted) {
48
- if (!previousPredicted.has(objectId) && frame > 0) {
49
- visibleCorrections += 1;
50
- }
51
- }
52
- previousPredicted = localPredicted;
53
- filterHistory.push(predictedBySlot);
54
- predictedTotal += localPredicted.size;
55
- minPredictedObjects = Math.min(minPredictedObjects, localPredicted.size);
56
- maxPredictedObjects = Math.max(maxPredictedObjects, localPredicted.size);
57
- predictedChecksum = defaultChecksum({
58
- frame,
59
- predictedBySlot,
60
- previousChecksum: predictedChecksum,
61
- });
62
- verifiedObjectSteps += frameState.length;
63
- verifiedChecksum = defaultChecksum({
64
- frame,
65
- objects: frameState,
66
- previousChecksum: verifiedChecksum,
67
- });
68
- completeChecksum = defaultChecksum({
69
- frame,
70
- player: getPlayerPosition(0, frame, options.seed),
71
- objects: frameState,
72
- previousChecksum: completeChecksum,
73
- });
74
- }
75
- const resimulatedChecksum = resimulateVerifiedChecksum(frameHistory, restoreFrame);
76
- const predictionFilterChecksum = defaultChecksum(filterHistory);
77
- const culledObjectSteps = options.mode === 'off' ? 0 : verifiedObjectSteps * options.players - predictedObjectSteps;
78
- return {
79
- mode: options.mode,
80
- players: options.players,
81
- objects: objects.length,
82
- frames: options.frames,
83
- seed: options.seed,
84
- radius: options.radius,
85
- averagePredictedObjects: (predictedTotal / options.frames).toFixed(2),
86
- minPredictedObjects,
87
- maxPredictedObjects,
88
- visibleCorrections,
89
- hiddenAuthoritativeInteractions,
90
- predictedObjectSteps,
91
- verifiedObjectSteps,
92
- culledObjectSteps,
93
- restoreFrame,
94
- predictedChecksum,
95
- verifiedChecksum,
96
- resimulatedChecksum,
97
- predictionFilterChecksum,
98
- completeChecksum,
99
- result: hiddenAuthoritativeInteractions === 0 && verifiedChecksum === resimulatedChecksum ? 'pass' : 'fail',
100
- };
101
- }
102
- function createObjects(options) {
103
- const objects = [];
104
- for (let slot = 0; slot < options.players; slot += 1) {
105
- for (let index = 0; index < options.objectsPerPlayer; index += 1) {
106
- const id = objects.length;
107
- objects.push({
108
- id,
109
- ownerSlot: slot,
110
- offsetX: ((index * 37 + options.seed) % 90) - 45,
111
- offsetY: ((index * 53 + options.seed) % 90) - 45,
112
- alwaysPredict: index % 17 === 0,
113
- canAffectPlayer: index % 17 === 0,
114
- });
115
- }
116
- }
117
- if (options.includeHiddenThreat === true) {
118
- objects.push({
119
- id: objects.length,
120
- ownerSlot: Math.max(1, options.players - 1),
121
- offsetX: 10_000,
122
- offsetY: 10_000,
123
- alwaysPredict: false,
124
- canAffectPlayer: true,
125
- });
126
- }
127
- return objects;
128
- }
129
- function shouldPredictObject(mode, player, object, objectState, radius) {
130
- if (mode === 'off') {
131
- return true;
132
- }
133
- if (object.alwaysPredict) {
134
- return true;
135
- }
136
- const dx = objectState.x - player.x;
137
- const dy = objectState.y - player.y;
138
- return dx * dx + dy * dy <= radius * radius;
139
- }
140
- function getPlayerPosition(slot, frame, seed) {
141
- return {
142
- x: slot * 100 + ((frame * 3 + seed) % 37),
143
- y: ((frame * 5 + seed) % 41) - 20,
144
- };
145
- }
146
- function getObjectFrameState(object, frame, seed) {
147
- const owner = getPlayerPosition(object.ownerSlot, frame, seed);
148
- return {
149
- id: object.id,
150
- x: owner.x + object.offsetX + ((frame + object.id) % 7) - 3,
151
- y: owner.y + object.offsetY + ((frame * 2 + object.id) % 7) - 3,
152
- active: (frame + object.id) % 29 === 0 ? 0 : 1,
153
- canAffectPlayer: object.canAffectPlayer,
154
- };
155
- }
156
- function validateOptions(options) {
157
- if (options.mode !== 'off' && options.mode !== 'local-area') {
158
- throw new Error('prediction culling mode must be off or local-area');
159
- }
160
- if (!Number.isInteger(options.players) || options.players < 1 || options.players > 128) {
161
- throw new Error('prediction culling players must be between 1 and 128');
162
- }
163
- if (!Number.isInteger(options.objectsPerPlayer) || options.objectsPerPlayer < 1 || options.objectsPerPlayer > 128) {
164
- throw new Error('objectsPerPlayer must be between 1 and 128');
165
- }
166
- if (!Number.isInteger(options.frames) || options.frames < 1) {
167
- throw new Error('prediction culling frames must be at least 1');
168
- }
169
- if (!Number.isInteger(options.seed)) {
170
- throw new Error('prediction culling seed must be an integer');
171
- }
172
- if (!Number.isInteger(options.radius) || options.radius < 1) {
173
- throw new Error('prediction culling radius must be a positive integer');
174
- }
175
- }
176
- function resimulateVerifiedChecksum(frameHistory, restoreFrame) {
177
- let checksum = '';
178
- for (let frame = 0; frame < frameHistory.length; frame += 1) {
179
- if (frame === restoreFrame) {
180
- checksum = resimulateVerifiedChecksumPrefix(frameHistory, frame);
181
- }
182
- checksum = defaultChecksum({
183
- frame,
184
- objects: frameHistory[frame],
185
- previousChecksum: checksum,
186
- });
187
- }
188
- return checksum;
189
- }
190
- function resimulateVerifiedChecksumPrefix(frameHistory, endFrameExclusive) {
191
- let checksum = '';
192
- for (let frame = 0; frame < endFrameExclusive; frame += 1) {
193
- checksum = defaultChecksum({
194
- frame,
195
- objects: frameHistory[frame],
196
- previousChecksum: checksum,
197
- });
198
- }
199
- return checksum;
200
- }