@quake2ts/shared 0.0.1
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/dist/browser/index.global.js +2 -0
- package/dist/browser/index.global.js.map +1 -0
- package/dist/cjs/index.cjs +6569 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/esm/index.js +6200 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/types/audio/constants.d.ts +24 -0
- package/dist/types/audio/constants.d.ts.map +1 -0
- package/dist/types/bsp/collision.d.ts +201 -0
- package/dist/types/bsp/collision.d.ts.map +1 -0
- package/dist/types/bsp/contents.d.ts +72 -0
- package/dist/types/bsp/contents.d.ts.map +1 -0
- package/dist/types/bsp/spatial.d.ts +13 -0
- package/dist/types/bsp/spatial.d.ts.map +1 -0
- package/dist/types/index.d.ts +38 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/inventory-helpers.d.ts +19 -0
- package/dist/types/inventory-helpers.d.ts.map +1 -0
- package/dist/types/io/binaryStream.d.ts +38 -0
- package/dist/types/io/binaryStream.d.ts.map +1 -0
- package/dist/types/io/binaryWriter.d.ts +26 -0
- package/dist/types/io/binaryWriter.d.ts.map +1 -0
- package/dist/types/io/index.d.ts +4 -0
- package/dist/types/io/index.d.ts.map +1 -0
- package/dist/types/io/messageBuilder.d.ts +21 -0
- package/dist/types/io/messageBuilder.d.ts.map +1 -0
- package/dist/types/items/ammo.d.ts +40 -0
- package/dist/types/items/ammo.d.ts.map +1 -0
- package/dist/types/items/index.d.ts +8 -0
- package/dist/types/items/index.d.ts.map +1 -0
- package/dist/types/items/powerups.d.ts +31 -0
- package/dist/types/items/powerups.d.ts.map +1 -0
- package/dist/types/items/weaponInfo.d.ts +5 -0
- package/dist/types/items/weaponInfo.d.ts.map +1 -0
- package/dist/types/items/weapons.d.ts +27 -0
- package/dist/types/items/weapons.d.ts.map +1 -0
- package/dist/types/math/angles.d.ts +19 -0
- package/dist/types/math/angles.d.ts.map +1 -0
- package/dist/types/math/anorms.d.ts +2 -0
- package/dist/types/math/anorms.d.ts.map +1 -0
- package/dist/types/math/color.d.ts +12 -0
- package/dist/types/math/color.d.ts.map +1 -0
- package/dist/types/math/mat4.d.ts +7 -0
- package/dist/types/math/mat4.d.ts.map +1 -0
- package/dist/types/math/random.d.ts +60 -0
- package/dist/types/math/random.d.ts.map +1 -0
- package/dist/types/math/vec3.d.ts +79 -0
- package/dist/types/math/vec3.d.ts.map +1 -0
- package/dist/types/net/driver.d.ts +10 -0
- package/dist/types/net/driver.d.ts.map +1 -0
- package/dist/types/net/index.d.ts +3 -0
- package/dist/types/net/index.d.ts.map +1 -0
- package/dist/types/net/netchan.d.ts +85 -0
- package/dist/types/net/netchan.d.ts.map +1 -0
- package/dist/types/pmove/apply.d.ts +5 -0
- package/dist/types/pmove/apply.d.ts.map +1 -0
- package/dist/types/pmove/categorize.d.ts +36 -0
- package/dist/types/pmove/categorize.d.ts.map +1 -0
- package/dist/types/pmove/config.d.ts +5 -0
- package/dist/types/pmove/config.d.ts.map +1 -0
- package/dist/types/pmove/constants.d.ts +76 -0
- package/dist/types/pmove/constants.d.ts.map +1 -0
- package/dist/types/pmove/currents.d.ts +58 -0
- package/dist/types/pmove/currents.d.ts.map +1 -0
- package/dist/types/pmove/dimensions.d.ts +14 -0
- package/dist/types/pmove/dimensions.d.ts.map +1 -0
- package/dist/types/pmove/duck.d.ts +39 -0
- package/dist/types/pmove/duck.d.ts.map +1 -0
- package/dist/types/pmove/fly.d.ts +34 -0
- package/dist/types/pmove/fly.d.ts.map +1 -0
- package/dist/types/pmove/index.d.ts +18 -0
- package/dist/types/pmove/index.d.ts.map +1 -0
- package/dist/types/pmove/jump.d.ts +28 -0
- package/dist/types/pmove/jump.d.ts.map +1 -0
- package/dist/types/pmove/move.d.ts +78 -0
- package/dist/types/pmove/move.d.ts.map +1 -0
- package/dist/types/pmove/pmove.d.ts +40 -0
- package/dist/types/pmove/pmove.d.ts.map +1 -0
- package/dist/types/pmove/slide.d.ts +63 -0
- package/dist/types/pmove/slide.d.ts.map +1 -0
- package/dist/types/pmove/snap.d.ts +40 -0
- package/dist/types/pmove/snap.d.ts.map +1 -0
- package/dist/types/pmove/special.d.ts +39 -0
- package/dist/types/pmove/special.d.ts.map +1 -0
- package/dist/types/pmove/stuck.d.ts +21 -0
- package/dist/types/pmove/stuck.d.ts.map +1 -0
- package/dist/types/pmove/types.d.ts +72 -0
- package/dist/types/pmove/types.d.ts.map +1 -0
- package/dist/types/pmove/view.d.ts +19 -0
- package/dist/types/pmove/view.d.ts.map +1 -0
- package/dist/types/pmove/water.d.ts +21 -0
- package/dist/types/pmove/water.d.ts.map +1 -0
- package/dist/types/protocol/bitpack.d.ts +17 -0
- package/dist/types/protocol/bitpack.d.ts.map +1 -0
- package/dist/types/protocol/configstrings.d.ts +73 -0
- package/dist/types/protocol/configstrings.d.ts.map +1 -0
- package/dist/types/protocol/constants.d.ts +36 -0
- package/dist/types/protocol/constants.d.ts.map +1 -0
- package/dist/types/protocol/contracts.d.ts +17 -0
- package/dist/types/protocol/contracts.d.ts.map +1 -0
- package/dist/types/protocol/crc.d.ts +5 -0
- package/dist/types/protocol/crc.d.ts.map +1 -0
- package/dist/types/protocol/cvar.d.ts +15 -0
- package/dist/types/protocol/cvar.d.ts.map +1 -0
- package/dist/types/protocol/effects.d.ts +33 -0
- package/dist/types/protocol/effects.d.ts.map +1 -0
- package/dist/types/protocol/entity.d.ts +46 -0
- package/dist/types/protocol/entity.d.ts.map +1 -0
- package/dist/types/protocol/entityEvent.d.ts +13 -0
- package/dist/types/protocol/entityEvent.d.ts.map +1 -0
- package/dist/types/protocol/entityState.d.ts +26 -0
- package/dist/types/protocol/entityState.d.ts.map +1 -0
- package/dist/types/protocol/index.d.ts +19 -0
- package/dist/types/protocol/index.d.ts.map +1 -0
- package/dist/types/protocol/layout.d.ts +9 -0
- package/dist/types/protocol/layout.d.ts.map +1 -0
- package/dist/types/protocol/ops.d.ts +44 -0
- package/dist/types/protocol/ops.d.ts.map +1 -0
- package/dist/types/protocol/player-state.d.ts +40 -0
- package/dist/types/protocol/player-state.d.ts.map +1 -0
- package/dist/types/protocol/player.d.ts +28 -0
- package/dist/types/protocol/player.d.ts.map +1 -0
- package/dist/types/protocol/renderFx.d.ts +23 -0
- package/dist/types/protocol/renderFx.d.ts.map +1 -0
- package/dist/types/protocol/stats.d.ts +61 -0
- package/dist/types/protocol/stats.d.ts.map +1 -0
- package/dist/types/protocol/tempEntity.d.ts +67 -0
- package/dist/types/protocol/tempEntity.d.ts.map +1 -0
- package/dist/types/protocol/usercmd.d.ts +33 -0
- package/dist/types/protocol/usercmd.d.ts.map +1 -0
- package/dist/types/protocol/writeUserCmd.d.ts +4 -0
- package/dist/types/protocol/writeUserCmd.d.ts.map +1 -0
- package/dist/types/replay/index.d.ts +3 -0
- package/dist/types/replay/index.d.ts.map +1 -0
- package/dist/types/replay/io.d.ts +7 -0
- package/dist/types/replay/io.d.ts.map +1 -0
- package/dist/types/replay/schema.d.ts +41 -0
- package/dist/types/replay/schema.d.ts.map +1 -0
- package/dist/types/testing.d.ts +6 -0
- package/dist/types/testing.d.ts.map +1 -0
- package/package.json +43 -0
- package/src/audio/constants.ts +35 -0
- package/src/bsp/collision.ts +1075 -0
- package/src/bsp/contents.ts +108 -0
- package/src/bsp/spatial.ts +116 -0
- package/src/index.ts +37 -0
- package/src/inventory-helpers.ts +81 -0
- package/src/io/binaryStream.ts +159 -0
- package/src/io/binaryWriter.ts +146 -0
- package/src/io/index.ts +3 -0
- package/src/io/messageBuilder.ts +117 -0
- package/src/items/ammo.ts +47 -0
- package/src/items/index.ts +8 -0
- package/src/items/powerups.ts +32 -0
- package/src/items/weaponInfo.ts +45 -0
- package/src/items/weapons.ts +28 -0
- package/src/math/angles.ts +135 -0
- package/src/math/anorms.ts +165 -0
- package/src/math/color.ts +42 -0
- package/src/math/mat4.ts +58 -0
- package/src/math/random.ts +182 -0
- package/src/math/vec3.ts +379 -0
- package/src/net/driver.ts +9 -0
- package/src/net/index.ts +2 -0
- package/src/net/netchan.ts +451 -0
- package/src/pmove/apply.ts +151 -0
- package/src/pmove/categorize.ts +162 -0
- package/src/pmove/config.ts +5 -0
- package/src/pmove/constants.ts +94 -0
- package/src/pmove/currents.ts +287 -0
- package/src/pmove/dimensions.ts +40 -0
- package/src/pmove/duck.ts +154 -0
- package/src/pmove/fly.ts +197 -0
- package/src/pmove/index.ts +18 -0
- package/src/pmove/jump.ts +92 -0
- package/src/pmove/move.ts +527 -0
- package/src/pmove/pmove.ts +446 -0
- package/src/pmove/slide.ts +267 -0
- package/src/pmove/snap.ts +89 -0
- package/src/pmove/special.ts +207 -0
- package/src/pmove/stuck.ts +258 -0
- package/src/pmove/types.ts +82 -0
- package/src/pmove/view.ts +57 -0
- package/src/pmove/water.ts +56 -0
- package/src/protocol/bitpack.ts +139 -0
- package/src/protocol/configstrings.ts +104 -0
- package/src/protocol/constants.ts +40 -0
- package/src/protocol/contracts.ts +149 -0
- package/src/protocol/crc.ts +32 -0
- package/src/protocol/cvar.ts +15 -0
- package/src/protocol/effects.ts +33 -0
- package/src/protocol/entity.ts +304 -0
- package/src/protocol/entityEvent.ts +14 -0
- package/src/protocol/entityState.ts +28 -0
- package/src/protocol/index.ts +19 -0
- package/src/protocol/layout.ts +9 -0
- package/src/protocol/ops.ts +49 -0
- package/src/protocol/player-state.ts +51 -0
- package/src/protocol/player.ts +165 -0
- package/src/protocol/renderFx.ts +22 -0
- package/src/protocol/stats.ts +161 -0
- package/src/protocol/tempEntity.ts +69 -0
- package/src/protocol/usercmd.ts +63 -0
- package/src/protocol/writeUserCmd.ts +30 -0
- package/src/replay/index.ts +2 -0
- package/src/replay/io.ts +37 -0
- package/src/replay/schema.ts +42 -0
- package/src/testing.ts +200 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
const STATE_SIZE = 624;
|
|
2
|
+
const MIDDLE_WORD = 397;
|
|
3
|
+
const MATRIX_A = 0x9908b0df;
|
|
4
|
+
const UPPER_MASK = 0x80000000;
|
|
5
|
+
const LOWER_MASK = 0x7fffffff;
|
|
6
|
+
const TWO_POW_32 = 0x100000000;
|
|
7
|
+
|
|
8
|
+
export interface MersenneTwisterState {
|
|
9
|
+
readonly index: number;
|
|
10
|
+
readonly state: readonly number[];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Minimal MT19937 implementation mirroring the rerelease's std::mt19937 usage in g_local.h.
|
|
15
|
+
* The generator outputs deterministic unsigned 32-bit integers which drive the
|
|
16
|
+
* higher-level helpers such as frandom/crandom/irandom.
|
|
17
|
+
*/
|
|
18
|
+
export class MersenneTwister19937 {
|
|
19
|
+
private state = new Uint32Array(STATE_SIZE);
|
|
20
|
+
private index = STATE_SIZE;
|
|
21
|
+
|
|
22
|
+
constructor(seed = 5489) {
|
|
23
|
+
this.seed(seed);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
seed(seed: number): void {
|
|
27
|
+
this.state[0] = seed >>> 0;
|
|
28
|
+
for (let i = 1; i < STATE_SIZE; i++) {
|
|
29
|
+
const prev = this.state[i - 1] ^ (this.state[i - 1] >>> 30);
|
|
30
|
+
const next = Math.imul(prev >>> 0, 1812433253) + i;
|
|
31
|
+
this.state[i] = next >>> 0;
|
|
32
|
+
}
|
|
33
|
+
this.index = STATE_SIZE;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
nextUint32(): number {
|
|
37
|
+
if (this.index >= STATE_SIZE) {
|
|
38
|
+
this.twist();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
let y = this.state[this.index++];
|
|
42
|
+
y ^= y >>> 11;
|
|
43
|
+
y ^= (y << 7) & 0x9d2c5680;
|
|
44
|
+
y ^= (y << 15) & 0xefc60000;
|
|
45
|
+
y ^= y >>> 18;
|
|
46
|
+
return y >>> 0;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
private twist(): void {
|
|
50
|
+
for (let i = 0; i < STATE_SIZE; i++) {
|
|
51
|
+
const y = (this.state[i] & UPPER_MASK) | (this.state[(i + 1) % STATE_SIZE] & LOWER_MASK);
|
|
52
|
+
let next = this.state[(i + MIDDLE_WORD) % STATE_SIZE] ^ (y >>> 1);
|
|
53
|
+
if ((y & 1) !== 0) {
|
|
54
|
+
next ^= MATRIX_A;
|
|
55
|
+
}
|
|
56
|
+
this.state[i] = next >>> 0;
|
|
57
|
+
}
|
|
58
|
+
this.index = 0;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
getState(): MersenneTwisterState {
|
|
62
|
+
return {
|
|
63
|
+
index: this.index,
|
|
64
|
+
state: Array.from(this.state),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
setState(snapshot: MersenneTwisterState): void {
|
|
69
|
+
if (snapshot.state.length !== STATE_SIZE) {
|
|
70
|
+
throw new Error(`Expected ${STATE_SIZE} MT state values, received ${snapshot.state.length}`);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
this.index = snapshot.index;
|
|
74
|
+
this.state = Uint32Array.from(snapshot.state, (value) => value >>> 0);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface RandomGeneratorOptions {
|
|
79
|
+
readonly seed?: number;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface RandomGeneratorState {
|
|
83
|
+
readonly mt: MersenneTwisterState;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Deterministic helper mirroring the random helpers defined in rerelease g_local.h.
|
|
88
|
+
*/
|
|
89
|
+
export class RandomGenerator {
|
|
90
|
+
private readonly mt: MersenneTwister19937;
|
|
91
|
+
|
|
92
|
+
constructor(options: RandomGeneratorOptions = {}) {
|
|
93
|
+
this.mt = new MersenneTwister19937(options.seed);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
seed(seed: number): void {
|
|
97
|
+
this.mt.seed(seed);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Uniform float in [0, 1). */
|
|
101
|
+
frandom(): number {
|
|
102
|
+
return this.mt.nextUint32() / TWO_POW_32;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Uniform float in [min, max). */
|
|
106
|
+
frandomRange(minInclusive: number, maxExclusive: number): number {
|
|
107
|
+
return minInclusive + (maxExclusive - minInclusive) * this.frandom();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Uniform float in [0, max). */
|
|
111
|
+
frandomMax(maxExclusive: number): number {
|
|
112
|
+
return this.frandomRange(0, maxExclusive);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** Uniform float in [-1, 1). */
|
|
116
|
+
crandom(): number {
|
|
117
|
+
return this.frandomRange(-1, 1);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** Uniform float in (-1, 1). */
|
|
121
|
+
crandomOpen(): number {
|
|
122
|
+
const epsilon = Number.EPSILON;
|
|
123
|
+
return this.frandomRange(-1 + epsilon, 1);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** Raw uint32 sample. */
|
|
127
|
+
irandomUint32(): number {
|
|
128
|
+
return this.mt.nextUint32();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** Uniform integer in [min, max). */
|
|
132
|
+
irandomRange(minInclusive: number, maxExclusive: number): number {
|
|
133
|
+
if (maxExclusive - minInclusive <= 1) {
|
|
134
|
+
return minInclusive;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const span = maxExclusive - minInclusive;
|
|
138
|
+
const limit = TWO_POW_32 - (TWO_POW_32 % span);
|
|
139
|
+
let sample: number;
|
|
140
|
+
do {
|
|
141
|
+
sample = this.mt.nextUint32();
|
|
142
|
+
} while (sample >= limit);
|
|
143
|
+
return minInclusive + (sample % span);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** Uniform integer in [0, max). */
|
|
147
|
+
irandom(maxExclusive: number): number {
|
|
148
|
+
if (maxExclusive <= 0) {
|
|
149
|
+
return 0;
|
|
150
|
+
}
|
|
151
|
+
return this.irandomRange(0, maxExclusive);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** Uniform time in milliseconds [min, max). */
|
|
155
|
+
randomTimeRange(minMs: number, maxMs: number): number {
|
|
156
|
+
if (maxMs <= minMs) {
|
|
157
|
+
return minMs;
|
|
158
|
+
}
|
|
159
|
+
return this.irandomRange(minMs, maxMs);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** Uniform time in milliseconds [0, max). */
|
|
163
|
+
randomTime(maxMs: number): number {
|
|
164
|
+
return this.irandom(maxMs);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
randomIndex<T extends { length: number }>(container: T): number {
|
|
168
|
+
return this.irandom(container.length);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
getState(): RandomGeneratorState {
|
|
172
|
+
return { mt: this.mt.getState() };
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
setState(snapshot: RandomGeneratorState): void {
|
|
176
|
+
this.mt.setState(snapshot.mt);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export function createRandomGenerator(options?: RandomGeneratorOptions): RandomGenerator {
|
|
181
|
+
return new RandomGenerator(options);
|
|
182
|
+
}
|
package/src/math/vec3.ts
ADDED
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
export interface Vec3 {
|
|
2
|
+
readonly x: number;
|
|
3
|
+
readonly y: number;
|
|
4
|
+
readonly z: number;
|
|
5
|
+
readonly [index: number]: number;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const ZERO_VEC3: Vec3 = { x: 0, y: 0, z: 0 };
|
|
9
|
+
|
|
10
|
+
// Matches STOP_EPSILON from rerelease q_vec3.h
|
|
11
|
+
export const STOP_EPSILON = 0.1;
|
|
12
|
+
|
|
13
|
+
const DEG_TO_RAD = Math.PI / 180;
|
|
14
|
+
|
|
15
|
+
export interface Bounds3 {
|
|
16
|
+
readonly mins: Vec3;
|
|
17
|
+
readonly maxs: Vec3;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type Mat3Row = readonly [number, number, number];
|
|
21
|
+
export type Mat3 = readonly [Mat3Row, Mat3Row, Mat3Row];
|
|
22
|
+
|
|
23
|
+
export function copyVec3(a: Vec3): Vec3 {
|
|
24
|
+
return { x: a.x, y: a.y, z: a.z };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function addVec3(a: Vec3, b: Vec3): Vec3 {
|
|
28
|
+
return { x: a.x + b.x, y: a.y + b.y, z: a.z + b.z };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function subtractVec3(a: Vec3, b: Vec3): Vec3 {
|
|
32
|
+
return { x: a.x - b.x, y: a.y - b.y, z: a.z - b.z };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function multiplyVec3(a: Vec3, b: Vec3): Vec3 {
|
|
36
|
+
return { x: a.x * b.x, y: a.y * b.y, z: a.z * b.z };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function scaleVec3(a: Vec3, scalar: number): Vec3 {
|
|
40
|
+
return { x: a.x * scalar, y: a.y * scalar, z: a.z * scalar };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function negateVec3(a: Vec3): Vec3 {
|
|
44
|
+
return scaleVec3(a, -1);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function dotVec3(a: Vec3, b: Vec3): number {
|
|
48
|
+
return a.x * b.x + a.y * b.y + a.z * b.z;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function crossVec3(a: Vec3, b: Vec3): Vec3 {
|
|
52
|
+
return {
|
|
53
|
+
x: a.y * b.z - a.z * b.y,
|
|
54
|
+
y: a.z * b.x - a.x * b.z,
|
|
55
|
+
z: a.x * b.y - a.y * b.x,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function lengthSquaredVec3(a: Vec3): number {
|
|
60
|
+
return dotVec3(a, a);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function lengthVec3(a: Vec3): number {
|
|
64
|
+
return Math.sqrt(lengthSquaredVec3(a));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function distance(a: Vec3, b: Vec3): number {
|
|
68
|
+
return lengthVec3(subtractVec3(a, b));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function vec3Equals(a: Vec3, b: Vec3): boolean {
|
|
72
|
+
return a.x === b.x && a.y === b.y && a.z === b.z;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Returns the normalized vector. If the vector is zero-length, the
|
|
77
|
+
* input is returned to mirror the rerelease q_vec3 semantics.
|
|
78
|
+
*/
|
|
79
|
+
export function normalizeVec3(a: Vec3): Vec3 {
|
|
80
|
+
const len = lengthVec3(a);
|
|
81
|
+
return len === 0 ? a : scaleVec3(a, 1 / len);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Projects a point onto a plane defined by the given normal.
|
|
86
|
+
* Based on ProjectPointOnPlane in the rerelease q_vec3 helpers.
|
|
87
|
+
*/
|
|
88
|
+
export function projectPointOnPlane(point: Vec3, normal: Vec3): Vec3 {
|
|
89
|
+
const invDenom = 1 / dotVec3(normal, normal);
|
|
90
|
+
const d = dotVec3(normal, point) * invDenom;
|
|
91
|
+
return subtractVec3(point, scaleVec3(normal, invDenom * d));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Computes a perpendicular vector to the provided direction using the
|
|
96
|
+
* smallest axial component heuristic used by the rerelease.
|
|
97
|
+
* Assumes the input is normalized.
|
|
98
|
+
*/
|
|
99
|
+
export function perpendicularVec3(src: Vec3): Vec3 {
|
|
100
|
+
let pos = 0;
|
|
101
|
+
let minElement = Math.abs(src.x);
|
|
102
|
+
|
|
103
|
+
if (Math.abs(src.y) < minElement) {
|
|
104
|
+
pos = 1;
|
|
105
|
+
minElement = Math.abs(src.y);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (Math.abs(src.z) < minElement) {
|
|
109
|
+
pos = 2;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const axis = pos === 0 ? { x: 1, y: 0, z: 0 } : pos === 1 ? { x: 0, y: 1, z: 0 } : { x: 0, y: 0, z: 1 };
|
|
113
|
+
return normalizeVec3(projectPointOnPlane(axis, src));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function closestPointToBox(point: Vec3, mins: Vec3, maxs: Vec3): Vec3 {
|
|
117
|
+
return {
|
|
118
|
+
x: point.x < mins.x ? mins.x : point.x > maxs.x ? maxs.x : point.x,
|
|
119
|
+
y: point.y < mins.y ? mins.y : point.y > maxs.y ? maxs.y : point.y,
|
|
120
|
+
z: point.z < mins.z ? mins.z : point.z > maxs.z ? maxs.z : point.z,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function distanceBetweenBoxesSquared(aMins: Vec3, aMaxs: Vec3, bMins: Vec3, bMaxs: Vec3): number {
|
|
125
|
+
let lengthSq = 0;
|
|
126
|
+
|
|
127
|
+
if (aMaxs.x < bMins.x) {
|
|
128
|
+
const d = aMaxs.x - bMins.x;
|
|
129
|
+
lengthSq += d * d;
|
|
130
|
+
} else if (aMins.x > bMaxs.x) {
|
|
131
|
+
const d = aMins.x - bMaxs.x;
|
|
132
|
+
lengthSq += d * d;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (aMaxs.y < bMins.y) {
|
|
136
|
+
const d = aMaxs.y - bMins.y;
|
|
137
|
+
lengthSq += d * d;
|
|
138
|
+
} else if (aMins.y > bMaxs.y) {
|
|
139
|
+
const d = aMins.y - bMaxs.y;
|
|
140
|
+
lengthSq += d * d;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (aMaxs.z < bMins.z) {
|
|
144
|
+
const d = aMaxs.z - bMins.z;
|
|
145
|
+
lengthSq += d * d;
|
|
146
|
+
} else if (aMins.z > bMaxs.z) {
|
|
147
|
+
const d = aMins.z - bMaxs.z;
|
|
148
|
+
lengthSq += d * d;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return lengthSq;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export function createEmptyBounds3(): Bounds3 {
|
|
155
|
+
return {
|
|
156
|
+
mins: { x: Number.POSITIVE_INFINITY, y: Number.POSITIVE_INFINITY, z: Number.POSITIVE_INFINITY },
|
|
157
|
+
maxs: { x: Number.NEGATIVE_INFINITY, y: Number.NEGATIVE_INFINITY, z: Number.NEGATIVE_INFINITY },
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function addPointToBounds(point: Vec3, bounds: Bounds3): Bounds3 {
|
|
162
|
+
return {
|
|
163
|
+
mins: {
|
|
164
|
+
x: Math.min(bounds.mins.x, point.x),
|
|
165
|
+
y: Math.min(bounds.mins.y, point.y),
|
|
166
|
+
z: Math.min(bounds.mins.z, point.z),
|
|
167
|
+
},
|
|
168
|
+
maxs: {
|
|
169
|
+
x: Math.max(bounds.maxs.x, point.x),
|
|
170
|
+
y: Math.max(bounds.maxs.y, point.y),
|
|
171
|
+
z: Math.max(bounds.maxs.z, point.z),
|
|
172
|
+
},
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export function boxesIntersect(a: Bounds3, b: Bounds3): boolean {
|
|
177
|
+
return (
|
|
178
|
+
a.mins.x <= b.maxs.x &&
|
|
179
|
+
a.maxs.x >= b.mins.x &&
|
|
180
|
+
a.mins.y <= b.maxs.y &&
|
|
181
|
+
a.maxs.y >= b.mins.y &&
|
|
182
|
+
a.mins.z <= b.maxs.z &&
|
|
183
|
+
a.maxs.z >= b.mins.z
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Mirrors PM_ClipVelocity from `rerelease/p_move.cpp`: slide the incoming velocity off
|
|
189
|
+
* a plane normal, applying an overbounce scale and zeroing tiny components so callers can
|
|
190
|
+
* detect blocked axes using STOP_EPSILON.
|
|
191
|
+
*/
|
|
192
|
+
export function clipVelocityVec3(inVel: Vec3, normal: Vec3, overbounce: number): Vec3 {
|
|
193
|
+
const backoff = dotVec3(inVel, normal) * overbounce;
|
|
194
|
+
|
|
195
|
+
let outX = inVel.x - normal.x * backoff;
|
|
196
|
+
let outY = inVel.y - normal.y * backoff;
|
|
197
|
+
let outZ = inVel.z - normal.z * backoff;
|
|
198
|
+
|
|
199
|
+
if (outX > -STOP_EPSILON && outX < STOP_EPSILON) {
|
|
200
|
+
outX = 0;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (outY > -STOP_EPSILON && outY < STOP_EPSILON) {
|
|
204
|
+
outY = 0;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (outZ > -STOP_EPSILON && outZ < STOP_EPSILON) {
|
|
208
|
+
outZ = 0;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return { x: outX, y: outY, z: outZ };
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Slide a velocity across one or more clip planes using the same plane set resolution logic
|
|
216
|
+
* seen in the inner loop of `PM_StepSlideMove_Generic` (rerelease `p_move.cpp`). When a single
|
|
217
|
+
* plane is provided this devolves to PM_ClipVelocity; with two planes it projects onto the
|
|
218
|
+
* crease defined by their cross product; with more planes it zeroes the velocity to avoid
|
|
219
|
+
* oscillations.
|
|
220
|
+
*/
|
|
221
|
+
export function clipVelocityAgainstPlanes(
|
|
222
|
+
velocity: Vec3,
|
|
223
|
+
planes: readonly Vec3[],
|
|
224
|
+
overbounce: number,
|
|
225
|
+
primalVelocity?: Vec3,
|
|
226
|
+
): Vec3 {
|
|
227
|
+
if (planes.length === 0) {
|
|
228
|
+
return velocity;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
let working = velocity;
|
|
232
|
+
|
|
233
|
+
for (let i = 0; i < planes.length; i++) {
|
|
234
|
+
working = clipVelocityVec3(working, planes[i], overbounce);
|
|
235
|
+
|
|
236
|
+
let j = 0;
|
|
237
|
+
for (; j < planes.length; j++) {
|
|
238
|
+
if (j === i) {
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (dotVec3(working, planes[j]) < 0) {
|
|
243
|
+
break;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (j === planes.length) {
|
|
248
|
+
if (primalVelocity && dotVec3(working, primalVelocity) <= 0) {
|
|
249
|
+
return ZERO_VEC3;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return working;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (planes.length === 2) {
|
|
257
|
+
const dir = crossVec3(planes[0], planes[1]);
|
|
258
|
+
const d = dotVec3(dir, velocity);
|
|
259
|
+
const creaseVelocity = scaleVec3(dir, d);
|
|
260
|
+
|
|
261
|
+
if (primalVelocity && dotVec3(creaseVelocity, primalVelocity) <= 0) {
|
|
262
|
+
return ZERO_VEC3;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return creaseVelocity;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if (primalVelocity && dotVec3(working, primalVelocity) <= 0) {
|
|
269
|
+
return ZERO_VEC3;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return ZERO_VEC3;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Alias retained for ergonomics; mirrors PM_ClipVelocity semantics.
|
|
277
|
+
*/
|
|
278
|
+
export function slideClipVelocityVec3(inVel: Vec3, normal: Vec3, overbounce: number): Vec3 {
|
|
279
|
+
return clipVelocityVec3(inVel, normal, overbounce);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Project an offset from a point in forward/right(/up) space into world space.
|
|
284
|
+
* Mirrors G_ProjectSource and G_ProjectSource2 in rerelease q_vec3.
|
|
285
|
+
*/
|
|
286
|
+
export function projectSourceVec3(point: Vec3, distance: Vec3, forward: Vec3, right: Vec3): Vec3 {
|
|
287
|
+
return {
|
|
288
|
+
x: point.x + forward.x * distance.x + right.x * distance.y,
|
|
289
|
+
y: point.y + forward.y * distance.x + right.y * distance.y,
|
|
290
|
+
z: point.z + forward.z * distance.x + right.z * distance.y + distance.z,
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
export function projectSourceVec3WithUp(point: Vec3, distance: Vec3, forward: Vec3, right: Vec3, up: Vec3): Vec3 {
|
|
295
|
+
return {
|
|
296
|
+
x: point.x + forward.x * distance.x + right.x * distance.y + up.x * distance.z,
|
|
297
|
+
y: point.y + forward.y * distance.x + right.y * distance.y + up.y * distance.z,
|
|
298
|
+
z: point.z + forward.z * distance.x + right.z * distance.y + up.z * distance.z,
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Spherical linear interpolation between two vectors, mirroring q_vec3::slerp.
|
|
304
|
+
* This is intended for direction vectors; callers should pre-normalize if needed.
|
|
305
|
+
*/
|
|
306
|
+
export function slerpVec3(from: Vec3, to: Vec3, t: number): Vec3 {
|
|
307
|
+
const dot = dotVec3(from, to);
|
|
308
|
+
let aFactor: number;
|
|
309
|
+
let bFactor: number;
|
|
310
|
+
|
|
311
|
+
if (Math.abs(dot) > 0.9995) {
|
|
312
|
+
aFactor = 1 - t;
|
|
313
|
+
bFactor = t;
|
|
314
|
+
} else {
|
|
315
|
+
const ang = Math.acos(dot);
|
|
316
|
+
const sinOmega = Math.sin(ang);
|
|
317
|
+
const sinAOmega = Math.sin((1 - t) * ang);
|
|
318
|
+
const sinBOmega = Math.sin(t * ang);
|
|
319
|
+
aFactor = sinAOmega / sinOmega;
|
|
320
|
+
bFactor = sinBOmega / sinOmega;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
return {
|
|
324
|
+
x: from.x * aFactor + to.x * bFactor,
|
|
325
|
+
y: from.y * aFactor + to.y * bFactor,
|
|
326
|
+
z: from.z * aFactor + to.z * bFactor,
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
export function concatRotationMatrices(a: Mat3, b: Mat3): Mat3 {
|
|
331
|
+
const row = (rowIndex: number): Mat3Row => [
|
|
332
|
+
a[rowIndex][0] * b[0][0] + a[rowIndex][1] * b[1][0] + a[rowIndex][2] * b[2][0],
|
|
333
|
+
a[rowIndex][0] * b[0][1] + a[rowIndex][1] * b[1][1] + a[rowIndex][2] * b[2][1],
|
|
334
|
+
a[rowIndex][0] * b[0][2] + a[rowIndex][1] * b[1][2] + a[rowIndex][2] * b[2][2],
|
|
335
|
+
];
|
|
336
|
+
|
|
337
|
+
const result = [row(0), row(1), row(2)] as Mat3;
|
|
338
|
+
return result;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
export function rotatePointAroundVector(dir: Vec3, point: Vec3, degrees: number): Vec3 {
|
|
342
|
+
const axisLength = lengthVec3(dir);
|
|
343
|
+
if (axisLength === 0) {
|
|
344
|
+
return point;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
const vf = normalizeVec3(dir);
|
|
348
|
+
const vr = perpendicularVec3(vf);
|
|
349
|
+
const vup = crossVec3(vr, vf);
|
|
350
|
+
|
|
351
|
+
const m: Mat3 = [
|
|
352
|
+
[vr.x, vup.x, vf.x],
|
|
353
|
+
[vr.y, vup.y, vf.y],
|
|
354
|
+
[vr.z, vup.z, vf.z],
|
|
355
|
+
];
|
|
356
|
+
|
|
357
|
+
const im: Mat3 = [
|
|
358
|
+
[m[0][0], m[1][0], m[2][0]],
|
|
359
|
+
[m[0][1], m[1][1], m[2][1]],
|
|
360
|
+
[m[0][2], m[1][2], m[2][2]],
|
|
361
|
+
];
|
|
362
|
+
|
|
363
|
+
const radians = degrees * DEG_TO_RAD;
|
|
364
|
+
const cos = Math.cos(radians);
|
|
365
|
+
const sin = Math.sin(radians);
|
|
366
|
+
const zrot: Mat3 = [
|
|
367
|
+
[cos, sin, 0],
|
|
368
|
+
[-sin, cos, 0],
|
|
369
|
+
[0, 0, 1],
|
|
370
|
+
];
|
|
371
|
+
|
|
372
|
+
const rot = concatRotationMatrices(concatRotationMatrices(m, zrot), im);
|
|
373
|
+
|
|
374
|
+
return {
|
|
375
|
+
x: rot[0][0] * point.x + rot[0][1] * point.y + rot[0][2] * point.z,
|
|
376
|
+
y: rot[1][0] * point.x + rot[1][1] * point.y + rot[1][2] * point.z,
|
|
377
|
+
z: rot[2][0] * point.x + rot[2][1] * point.y + rot[2][2] * point.z,
|
|
378
|
+
};
|
|
379
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface NetDriver {
|
|
2
|
+
connect(url: string): Promise<void>;
|
|
3
|
+
disconnect(): void;
|
|
4
|
+
send(data: Uint8Array): void;
|
|
5
|
+
onMessage(callback: (data: Uint8Array) => void): void;
|
|
6
|
+
onClose(callback: () => void): void;
|
|
7
|
+
onError(callback: (error: Error) => void): void;
|
|
8
|
+
isConnected(): boolean;
|
|
9
|
+
}
|
package/src/net/index.ts
ADDED