@woosh/meep-engine 2.48.17 → 2.48.19
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/package.json +1 -1
- package/src/core/binary/dec2hex.spec.js +13 -0
- package/src/core/bvh2/bvh3/ExplicitBinaryBoundingVolumeHierarchy.d.ts +18 -0
- package/src/core/bvh2/bvh3/ExplicitBinaryBoundingVolumeHierarchy.js +18 -0
- package/src/core/bvh2/bvh3/ExplicitBinaryBoundingVolumeHierarchy.spec.js +56 -0
- package/src/core/cache/Cache.d.ts +5 -0
- package/src/core/cache/Cache.js +8 -1
- package/src/core/cache/Cache.spec.js +47 -3
- package/src/core/codegen/LineBuilder.js +117 -106
- package/src/core/collection/HashMap.spec.js +32 -0
- package/src/core/collection/list/List.js +6 -4
- package/src/core/geom/Matrix4.js +4 -1
- package/src/core/geom/Quaternion.js +4 -0
- package/src/core/geom/Vector3.js +9 -31
- package/src/core/graph/Edge.js +11 -2
- package/src/core/graph/v2/Graph.js +36 -31
- package/src/core/graph/v2/Graph.spec.js +309 -1
- package/src/core/math/fract.spec.js +11 -0
- package/src/core/math/isPowerOfTwo.spec.js +9 -0
- package/src/core/math/isPowerOrTwo.js +5 -0
- package/src/core/math/newton_solver_1d.js +1 -1
- package/src/core/math/newton_solver_1d.spec.js +9 -0
- package/src/core/math/pingpong.spec.js +11 -0
- package/src/core/math/random/randomBytes.js +16 -0
- package/src/core/math/random/randomFloatBetween.spec.js +8 -0
- package/src/core/math/random/randomFromArray.js +3 -3
- package/src/core/math/random/randomIntegerBetween.js +5 -0
- package/src/core/math/random/randomIntegerBetween.spec.js +7 -0
- package/src/core/math/statistics/halton_sequence.spec.js +17 -0
- package/src/engine/asset/AssetManager.d.ts +11 -1
- package/src/engine/asset/AssetManager.spec.js +2 -2
- package/src/engine/control/ControlContext.js +2 -1
- package/src/engine/ecs/EntityBuilder.d.ts +6 -0
- package/src/engine/ecs/EntityBuilder.js +2 -22
- package/src/engine/ecs/EntityBuilder.spec.js +71 -1
- package/src/engine/ecs/EntityBuilderFlags.js +20 -0
- package/src/engine/ecs/EntityComponentDataset.js +3 -6
- package/src/engine/ecs/dynamic_actions/DynamicActorSystem.js +2 -1
- package/src/engine/ecs/gui/menu/radial/RadialContextMenu.js +2 -1
- package/src/engine/ecs/guid/GUID.js +48 -26
- package/src/engine/ecs/guid/GUID.spec.js +56 -10
- package/src/engine/ecs/speaker/VoiceSystem.js +2 -1
- package/src/engine/ecs/transform/Transform.d.ts +11 -1
- package/src/engine/ecs/transform/Transform.js +6 -3
- package/src/engine/ecs/transform/Transform.spec.js +67 -1
- package/src/engine/graphics/ecs/decal/v2/prototypeDecalSystem.js +2 -1
- package/src/engine/physics/fluid/Fluid.js +3 -0
- /package/src/core/geom/{Matrix3.js → m3_determinant.js} +0 -0
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { assert } from "../../assert.js";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Inclusive random between two boundaries, result is integer
|
|
3
5
|
* @param {function} random
|
|
@@ -6,6 +8,9 @@
|
|
|
6
8
|
* @returns {number}
|
|
7
9
|
*/
|
|
8
10
|
export function randomIntegerBetween(random, min, max) {
|
|
11
|
+
assert.isInteger(min, 'min');
|
|
12
|
+
assert.isInteger(max, 'max');
|
|
13
|
+
|
|
9
14
|
const span = max - min;
|
|
10
15
|
|
|
11
16
|
const roll = random();
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { randomIntegerBetween } from "./randomIntegerBetween.js";
|
|
2
|
+
import { returnOne, returnZero } from "../../function/Functions.js";
|
|
3
|
+
|
|
4
|
+
test("limits", () => {
|
|
5
|
+
expect(randomIntegerBetween(returnZero, -3, 7)).toEqual(-3);
|
|
6
|
+
expect(randomIntegerBetween(returnOne, -3, 7)).toEqual(7);
|
|
7
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { halton_sequence } from "./halton_sequence.js";
|
|
2
|
+
|
|
3
|
+
test("unique values in base 10", () => {
|
|
4
|
+
|
|
5
|
+
const values = [];
|
|
6
|
+
|
|
7
|
+
for (let i = 0; i < 10; i++) {
|
|
8
|
+
values.push(halton_sequence(10, i));
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
values.sort();
|
|
12
|
+
|
|
13
|
+
for (let i = 1; i < 10; i++) {
|
|
14
|
+
expect(values[i]).not.toEqual(values[i - 1]);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
});
|
|
@@ -13,6 +13,14 @@ interface AssetManagerOptions<CTX> {
|
|
|
13
13
|
executor?: ConcurrentExecutor
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
interface GetOptions<T> {
|
|
17
|
+
type: string
|
|
18
|
+
path: string
|
|
19
|
+
callback: (asset: Asset<T>) => any
|
|
20
|
+
failure: (reason: any) => any
|
|
21
|
+
progress: (current: number, total: number) => any
|
|
22
|
+
}
|
|
23
|
+
|
|
16
24
|
export declare class AssetManager<CTX> {
|
|
17
25
|
constructor(options?: AssetManagerOptions<CTX>)
|
|
18
26
|
|
|
@@ -24,13 +32,15 @@ export declare class AssetManager<CTX> {
|
|
|
24
32
|
|
|
25
33
|
shutdown(immediate?: boolean): Promise<void>
|
|
26
34
|
|
|
35
|
+
get<T>(options: GetOptions<T>): void
|
|
36
|
+
|
|
27
37
|
promise<T>(path: string, type: string, options?: PromiseOptions): Promise<Asset<T>>
|
|
28
38
|
|
|
29
39
|
remove(path: string, type: string): boolean
|
|
30
40
|
|
|
31
41
|
clear(): void
|
|
32
42
|
|
|
33
|
-
registerLoader<T>(type: string, loader: AssetLoader<T, CTX>): Promise<AssetLoader<T,CTX>>
|
|
43
|
+
registerLoader<T>(type: string, loader: AssetLoader<T, CTX>): Promise<AssetLoader<T, CTX>>
|
|
34
44
|
|
|
35
45
|
unregisterLoader(type: string): Promise<void>
|
|
36
46
|
|
|
@@ -16,7 +16,7 @@ function dummyEngine() {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
class DummyLoader extends AssetLoader {
|
|
19
|
-
load(scope,path, success, failure, progress) {
|
|
19
|
+
load(scope, path, success, failure, progress) {
|
|
20
20
|
success(new Asset(() => 1));
|
|
21
21
|
}
|
|
22
22
|
}
|
|
@@ -29,7 +29,7 @@ test('successful get', async () => {
|
|
|
29
29
|
am.startup();
|
|
30
30
|
|
|
31
31
|
return new Promise(function (resolve, reject) {
|
|
32
|
-
am.get('bla', 'a', resolve, reject);
|
|
32
|
+
am.get({ path: 'bla', type: 'a', callback: resolve, failure: reject });
|
|
33
33
|
});
|
|
34
34
|
});
|
|
35
35
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import EntityBuilder
|
|
1
|
+
import EntityBuilder from "../ecs/EntityBuilder.js";
|
|
2
2
|
import { ControlContextState } from "./ControlContextState.js";
|
|
3
3
|
import { IllegalStateException } from "../../core/fsm/exceptions/IllegalStateException.js";
|
|
4
4
|
import { SerializationMetadata } from "../ecs/components/SerializationMetadata.js";
|
|
5
|
+
import { EntityBuilderFlags } from "../ecs/EntityBuilderFlags.js";
|
|
5
6
|
|
|
6
7
|
export class ControlContext {
|
|
7
8
|
constructor() {
|
|
@@ -11,6 +11,8 @@ export default class EntityBuilder {
|
|
|
11
11
|
|
|
12
12
|
removeComponent<T>(componentType: Type<T>): T | null
|
|
13
13
|
|
|
14
|
+
removeAllComponents(): void
|
|
15
|
+
|
|
14
16
|
getComponent<T>(componentType: Type<T>): T | null
|
|
15
17
|
|
|
16
18
|
getComponentSafe<T>(componentType: Type<T>): T
|
|
@@ -30,4 +32,8 @@ export default class EntityBuilder {
|
|
|
30
32
|
removeEventListener(eventName: string, listener: (data?: any) => void, context?: any): EntityBuilder
|
|
31
33
|
|
|
32
34
|
static readFromDataset(entity: number, dataset: EntityComponentDataset): EntityBuilder
|
|
35
|
+
|
|
36
|
+
getFlag(flag: number): boolean
|
|
37
|
+
|
|
38
|
+
setFlag(flag: number, value: number): void
|
|
33
39
|
}
|
|
@@ -2,27 +2,7 @@ import Signal from "../../core/events/signal/Signal.js";
|
|
|
2
2
|
import { assert } from "../../core/assert.js";
|
|
3
3
|
import { EventType } from "./EntityManager.js";
|
|
4
4
|
import { isDefined } from "../../core/process/matcher/Matchers.js";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
*
|
|
8
|
-
* @enum
|
|
9
|
-
*/
|
|
10
|
-
export const EntityBuilderFlags = {
|
|
11
|
-
/**
|
|
12
|
-
* Whether the entity is built, set internally
|
|
13
|
-
*/
|
|
14
|
-
Built: 1,
|
|
15
|
-
/**
|
|
16
|
-
* If component type is not registered on the {@link EntityComponentDataset} when calling {@link #build} - will register the component first
|
|
17
|
-
*/
|
|
18
|
-
RegisterComponents: 2,
|
|
19
|
-
/**
|
|
20
|
-
* Entity builder will watch destruction of the entity (subscribe to event), this will make the EntityBuilder automatically
|
|
21
|
-
* recognize when the corresponding entity is destroyed outside the EntityBuilder API
|
|
22
|
-
* NOTE: useful to turn off to save a bit of memory, as those event listeners take up a bit of space. Feel free to turn this flag off when you don't care to keep the reference to the EntityBuilder
|
|
23
|
-
*/
|
|
24
|
-
WatchDestruction: 4
|
|
25
|
-
};
|
|
5
|
+
import { EntityBuilderFlags } from "./EntityBuilderFlags.js";
|
|
26
6
|
|
|
27
7
|
/**
|
|
28
8
|
* Set of default flags
|
|
@@ -152,7 +132,7 @@ class EntityBuilder {
|
|
|
152
132
|
*/
|
|
153
133
|
add(componentInstance) {
|
|
154
134
|
if (componentInstance === undefined) {
|
|
155
|
-
throw new Error(
|
|
135
|
+
throw new Error(`Can not add ${componentInstance} to EntityBuilder`);
|
|
156
136
|
}
|
|
157
137
|
|
|
158
138
|
assert.notOk(this.hasComponent(Object.getPrototypeOf(componentInstance).constructor), 'Component of this type already exists');
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import EntityBuilder
|
|
1
|
+
import EntityBuilder from "./EntityBuilder.js";
|
|
2
2
|
import { EntityComponentDataset } from "./EntityComponentDataset.js";
|
|
3
|
+
import { EntityBuilderFlags } from "./EntityBuilderFlags.js";
|
|
3
4
|
|
|
4
5
|
|
|
5
6
|
class DummyComponent {
|
|
@@ -62,3 +63,72 @@ test("'Built' flag is reset when entity is removed without invoking 'destroy' me
|
|
|
62
63
|
|
|
63
64
|
expect(b.getFlag(EntityBuilderFlags.Built)).toBe(false);
|
|
64
65
|
});
|
|
66
|
+
|
|
67
|
+
test("removeAllComponents from empty", () => {
|
|
68
|
+
const entity = new EntityBuilder();
|
|
69
|
+
|
|
70
|
+
expect(() => entity.removeAllComponents()).not.toThrow()
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test("removeAllComponents with 1 entity", () => {
|
|
74
|
+
const entity = new EntityBuilder();
|
|
75
|
+
|
|
76
|
+
entity.add(new DummyComponent());
|
|
77
|
+
|
|
78
|
+
expect(entity.hasComponent(DummyComponent)).toBe(true);
|
|
79
|
+
|
|
80
|
+
entity.removeAllComponents();
|
|
81
|
+
|
|
82
|
+
expect(entity.hasComponent(DummyComponent)).toBe(false);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test("removeComponent when component is not preset", () => {
|
|
86
|
+
const entity = new EntityBuilder();
|
|
87
|
+
|
|
88
|
+
expect(entity.removeComponent(DummyComponent)).toBe(null);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test("removeComponent when component is preset", () => {
|
|
92
|
+
const entity = new EntityBuilder();
|
|
93
|
+
|
|
94
|
+
const component = new DummyComponent();
|
|
95
|
+
|
|
96
|
+
entity.add(component)
|
|
97
|
+
|
|
98
|
+
expect(entity.removeComponent(DummyComponent)).toBe(component);
|
|
99
|
+
|
|
100
|
+
expect(entity.hasComponent(DummyComponent)).toBe(false);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test("getComponentSafe throws when component is missing", () => {
|
|
104
|
+
|
|
105
|
+
const entity = new EntityBuilder();
|
|
106
|
+
|
|
107
|
+
expect(() => entity.getComponentSafe(DummyComponent)).toThrow();
|
|
108
|
+
|
|
109
|
+
});
|
|
110
|
+
test("getComponentSafe throws when component is present", () => {
|
|
111
|
+
|
|
112
|
+
const entity = new EntityBuilder();
|
|
113
|
+
|
|
114
|
+
const component = new DummyComponent();
|
|
115
|
+
entity.add(component);
|
|
116
|
+
|
|
117
|
+
expect(() => entity.getComponentSafe(DummyComponent)).not.toThrow();
|
|
118
|
+
|
|
119
|
+
expect(entity.getComponentSafe(DummyComponent)).toBe(component);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
test("adding component to live entity results in component being added to the dataset", () => {
|
|
123
|
+
|
|
124
|
+
const entity = new EntityBuilder();
|
|
125
|
+
|
|
126
|
+
const ecd = sampleDataset();
|
|
127
|
+
|
|
128
|
+
entity.build(ecd)
|
|
129
|
+
|
|
130
|
+
const component = new DummyComponent();
|
|
131
|
+
entity.add(component);
|
|
132
|
+
|
|
133
|
+
expect(ecd.getComponent(entity.entity, DummyComponent)).toBe(component);
|
|
134
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* @enum
|
|
4
|
+
*/
|
|
5
|
+
export const EntityBuilderFlags = {
|
|
6
|
+
/**
|
|
7
|
+
* Whether the entity is built, set internally
|
|
8
|
+
*/
|
|
9
|
+
Built: 1,
|
|
10
|
+
/**
|
|
11
|
+
* If component type is not registered on the {@link EntityComponentDataset} when calling {@link #build} - will register the component first
|
|
12
|
+
*/
|
|
13
|
+
RegisterComponents: 2,
|
|
14
|
+
/**
|
|
15
|
+
* Entity builder will watch destruction of the entity (subscribe to event), this will make the EntityBuilder automatically
|
|
16
|
+
* recognize when the corresponding entity is destroyed outside the EntityBuilder API
|
|
17
|
+
* NOTE: useful to turn off to save a bit of memory, as those event listeners take up a bit of space. Feel free to turn this flag off when you don't care to keep the reference to the EntityBuilder
|
|
18
|
+
*/
|
|
19
|
+
WatchDestruction: 4
|
|
20
|
+
};
|
|
@@ -1071,7 +1071,7 @@ export class EntityComponentDataset {
|
|
|
1071
1071
|
* @param {function} callback
|
|
1072
1072
|
* @param {*} [thisArg]
|
|
1073
1073
|
*/
|
|
1074
|
-
getComponentAsync
|
|
1074
|
+
getComponentAsync(entityId, componentClass, callback, thisArg) {
|
|
1075
1075
|
const component = this.getComponent(entityId, componentClass);
|
|
1076
1076
|
|
|
1077
1077
|
const handler = (options) => {
|
|
@@ -1274,11 +1274,8 @@ export class EntityComponentDataset {
|
|
|
1274
1274
|
*/
|
|
1275
1275
|
traverseComponentsByIndex(componentTypeIndex, visitor, thisArg) {
|
|
1276
1276
|
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
assert.isFunction(visitor, "visitor");
|
|
1280
|
-
}
|
|
1281
|
-
|
|
1277
|
+
assert.isNumber(componentTypeIndex, "componentTypeIndex");
|
|
1278
|
+
assert.isFunction(visitor, "visitor");
|
|
1282
1279
|
|
|
1283
1280
|
this.__traverseComponentsByIndex_via_property(componentTypeIndex, visitor, thisArg);
|
|
1284
1281
|
}
|
|
@@ -5,7 +5,7 @@ import { DataScope } from "../../../../../model/game/unit/actions/data/DataScope
|
|
|
5
5
|
import { Blackboard } from "../../intelligence/blackboard/Blackboard.js";
|
|
6
6
|
import { compareNumbersDescending, returnTrue } from "../../../core/function/Functions.js";
|
|
7
7
|
import { EntityProxyScope } from "../binding/EntityProxyScope.js";
|
|
8
|
-
import EntityBuilder
|
|
8
|
+
import EntityBuilder from "../EntityBuilder.js";
|
|
9
9
|
import { BehaviorComponent } from "../../intelligence/behavior/ecs/BehaviorComponent.js";
|
|
10
10
|
import { SequenceBehavior } from "../../intelligence/behavior/composite/SequenceBehavior.js";
|
|
11
11
|
import { DieBehavior } from "../../intelligence/behavior/ecs/DieBehavior.js";
|
|
@@ -22,6 +22,7 @@ import { randomFloatBetween } from "../../../core/math/random/randomFloatBetween
|
|
|
22
22
|
import { randomMultipleFromArray } from "../../../core/collection/array/randomMultipleFromArray.js";
|
|
23
23
|
import { ResourceAccessSpecification } from "../../../core/model/ResourceAccessSpecification.js";
|
|
24
24
|
import { ResourceAccessKind } from "../../../core/model/ResourceAccessKind.js";
|
|
25
|
+
import { EntityBuilderFlags } from "../EntityBuilderFlags.js";
|
|
25
26
|
|
|
26
27
|
/**
|
|
27
28
|
* In seconds
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { SerializationMetadata } from "../../../components/SerializationMetadata.js";
|
|
5
5
|
|
|
6
|
-
import EntityBuilder
|
|
6
|
+
import EntityBuilder from "../../../EntityBuilder.js";
|
|
7
7
|
import GUIElement from "../../GUIElement.js";
|
|
8
8
|
import { MouseEvents } from "../../../../input/devices/events/MouseEvents.js";
|
|
9
9
|
import { TouchEvents } from "../../../../input/devices/events/TouchEvents.js";
|
|
@@ -12,6 +12,7 @@ import RadialMenuView from "../../../../../view/elements/radial/RadialMenu.js";
|
|
|
12
12
|
import { animateAppearance } from "./AnimateAppearance.js";
|
|
13
13
|
import { animateDisappearance } from "./AnimateDisappearance.js";
|
|
14
14
|
import { RadialMenuSettings } from "./RadialMenuSettings.js";
|
|
15
|
+
import { EntityBuilderFlags } from "../../../EntityBuilderFlags.js";
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
*
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { seededRandom } from "../../../core/math/random/seededRandom.js";
|
|
2
2
|
import { randomUint8 } from "../../../core/math/random/randomUint8.js";
|
|
3
|
-
import { is_typed_array_equals } from "../../../core/collection/array/typed/is_typed_array_equals.js";
|
|
4
3
|
import { dec2hex } from "../../../core/binary/dec2hex.js";
|
|
5
4
|
import { array_copy } from "../../../core/collection/array/copyArray.js";
|
|
5
|
+
import { randomBytes } from "../../../core/math/random/randomBytes.js";
|
|
6
|
+
import { assert } from "../../../core/assert.js";
|
|
6
7
|
|
|
7
8
|
// Previous uuid creation time
|
|
8
9
|
let _lastMSecs = 0;
|
|
@@ -10,23 +11,8 @@ let _lastNSecs = 0;
|
|
|
10
11
|
|
|
11
12
|
const random = seededRandom(Date.now());
|
|
12
13
|
|
|
13
|
-
/**
|
|
14
|
-
*
|
|
15
|
-
* @param {Uint8Array} result
|
|
16
|
-
* @param {number} result_offset
|
|
17
|
-
* @param {function():number} random
|
|
18
|
-
* @param {number} count
|
|
19
|
-
*/
|
|
20
|
-
function randomBytes(result, result_offset, random, count) {
|
|
21
|
-
for (let i = 0; i < count; i++) {
|
|
22
|
-
|
|
23
|
-
result[result_offset + i] = randomUint8(random);
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
14
|
// node and clockseq need to be initialized to random values.
|
|
29
|
-
|
|
15
|
+
const _nodeId = new Uint8Array(6);
|
|
30
16
|
|
|
31
17
|
// Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1)
|
|
32
18
|
randomBytes(_nodeId, 0, random, 6);
|
|
@@ -41,15 +27,14 @@ let _clockseq = ((randomUint8(random) << 8) | randomUint8(random)) & 0x3fff;
|
|
|
41
27
|
export class GUID {
|
|
42
28
|
#data = new Uint8Array(16);
|
|
43
29
|
|
|
44
|
-
constructor() {
|
|
45
|
-
this.v1();
|
|
46
|
-
}
|
|
47
|
-
|
|
48
30
|
/**
|
|
49
31
|
*
|
|
50
32
|
* @param {number[]|Uint8Array|ArrayLike<number>} bytes
|
|
51
33
|
*/
|
|
52
34
|
set data(bytes) {
|
|
35
|
+
assert.isArrayLike(bytes, 'bytes');
|
|
36
|
+
assert.greaterThanOrEqual(bytes.length, 16, 'bytes.length >= 16');
|
|
37
|
+
|
|
53
38
|
array_copy(bytes, 0, this.#data, 0, 16);
|
|
54
39
|
}
|
|
55
40
|
|
|
@@ -136,12 +121,27 @@ export class GUID {
|
|
|
136
121
|
}
|
|
137
122
|
}
|
|
138
123
|
|
|
124
|
+
/**
|
|
125
|
+
*
|
|
126
|
+
* @return {GUID}
|
|
127
|
+
*/
|
|
128
|
+
static v1() {
|
|
129
|
+
const uuid = new GUID();
|
|
130
|
+
|
|
131
|
+
uuid.v1();
|
|
132
|
+
|
|
133
|
+
return uuid;
|
|
134
|
+
}
|
|
135
|
+
|
|
139
136
|
/***
|
|
140
137
|
* String in UUID format
|
|
141
138
|
* @see https://github.com/uuidjs/uuid/blob/8f028c4ea42ce41a9a9dc5fa634abe525b2e2066/src/parse.js#L3
|
|
142
139
|
* @param {string} string
|
|
143
140
|
*/
|
|
144
141
|
parse(string) {
|
|
142
|
+
assert.isString(string, 'string');
|
|
143
|
+
assert.greaterThanOrEqual(string.length, 36, 'string.length');
|
|
144
|
+
|
|
145
145
|
let v;
|
|
146
146
|
const arr = this.#data;
|
|
147
147
|
|
|
@@ -173,6 +173,19 @@ export class GUID {
|
|
|
173
173
|
arr[15] = v & 0xff;
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
+
/**
|
|
177
|
+
*
|
|
178
|
+
* @param {string} string
|
|
179
|
+
* @return {GUID}
|
|
180
|
+
*/
|
|
181
|
+
static parse(string) {
|
|
182
|
+
const r = new GUID();
|
|
183
|
+
|
|
184
|
+
r.parse(string);
|
|
185
|
+
|
|
186
|
+
return r;
|
|
187
|
+
}
|
|
188
|
+
|
|
176
189
|
/**
|
|
177
190
|
* @see https://github.com/uuidjs/uuid/blob/8f028c4ea42ce41a9a9dc5fa634abe525b2e2066/src/stringify.js#L16
|
|
178
191
|
* @returns {string}
|
|
@@ -218,7 +231,16 @@ export class GUID {
|
|
|
218
231
|
* @returns {boolean}
|
|
219
232
|
*/
|
|
220
233
|
equals(other) {
|
|
221
|
-
|
|
234
|
+
const this_data = this.#data;
|
|
235
|
+
const other_data = other.#data;
|
|
236
|
+
|
|
237
|
+
for (let i = 0; i < 16; i++) {
|
|
238
|
+
if (this_data[i] !== other_data[i]) {
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return true;
|
|
222
244
|
}
|
|
223
245
|
|
|
224
246
|
/**
|
|
@@ -228,10 +250,10 @@ export class GUID {
|
|
|
228
250
|
const data = this.#data;
|
|
229
251
|
|
|
230
252
|
// use some non-metadata bytes as a hash
|
|
231
|
-
return data[
|
|
232
|
-
| data[
|
|
233
|
-
| data[
|
|
234
|
-
| data[
|
|
253
|
+
return data[3] // low byte of "time_low", very likely to differ between two UUIDs
|
|
254
|
+
| data[5] << 8 // low byte of "time_mid"
|
|
255
|
+
| data[9] << 16 // "clock_seq_low"
|
|
256
|
+
| data[15] << 24 // low byte of "node"
|
|
235
257
|
;
|
|
236
258
|
}
|
|
237
259
|
|
|
@@ -1,19 +1,15 @@
|
|
|
1
1
|
import { GUID } from "./GUID.js";
|
|
2
2
|
|
|
3
3
|
test("uniqueness out of 2", () => {
|
|
4
|
-
const a =
|
|
5
|
-
const b =
|
|
4
|
+
const a = GUID.v1();
|
|
5
|
+
const b = GUID.v1();
|
|
6
6
|
|
|
7
7
|
expect(a.equals(b)).toBe(false);
|
|
8
8
|
});
|
|
9
9
|
|
|
10
|
-
|
|
11
10
|
test("equality", () => {
|
|
12
|
-
const a =
|
|
13
|
-
const b =
|
|
14
|
-
|
|
15
|
-
a.parse("a88bb73a-c89f-11ed-afa1-0242ac120002");
|
|
16
|
-
b.parse("a88bb73a-c89f-11ed-afa1-0242ac120002");
|
|
11
|
+
const a = GUID.parse("a88bb73a-c89f-11ed-afa1-0242ac120002");
|
|
12
|
+
const b = GUID.parse("a88bb73a-c89f-11ed-afa1-0242ac120002");
|
|
17
13
|
|
|
18
14
|
expect(a.equals(b)).toBe(true);
|
|
19
15
|
|
|
@@ -28,10 +24,24 @@ test("hash stability", () => {
|
|
|
28
24
|
expect(guid.hash()).toBe(guid.hash());
|
|
29
25
|
});
|
|
30
26
|
|
|
27
|
+
test("copy", () => {
|
|
28
|
+
const a = GUID.parse("a88bb73a-c89f-11ed-afa1-0242ac120002");
|
|
29
|
+
const a_string = a.toString();
|
|
30
|
+
|
|
31
|
+
const b = GUID.parse("bb75b300-c89f-11ed-afa1-0242ac120002");
|
|
32
|
+
|
|
33
|
+
expect(a.equals(b)).toBe(false);
|
|
34
|
+
|
|
35
|
+
b.copy(a);
|
|
36
|
+
|
|
37
|
+
expect(a.equals(b)).toBe(true);
|
|
38
|
+
|
|
39
|
+
// make sure that "a" is not changed
|
|
40
|
+
expect(a.toString()).toEqual(a_string);
|
|
41
|
+
});
|
|
31
42
|
|
|
32
43
|
test("to/from JSON consistency", () => {
|
|
33
|
-
const a =
|
|
34
|
-
a.parse("bb75b300-c89f-11ed-afa1-0242ac120002");
|
|
44
|
+
const a = GUID.parse("bb75b300-c89f-11ed-afa1-0242ac120002");
|
|
35
45
|
|
|
36
46
|
const b = new GUID();
|
|
37
47
|
|
|
@@ -39,3 +49,39 @@ test("to/from JSON consistency", () => {
|
|
|
39
49
|
|
|
40
50
|
expect(b.equals(a)).toBe(true)
|
|
41
51
|
});
|
|
52
|
+
|
|
53
|
+
test(".data setter performs a copy instead of assignment", () => {
|
|
54
|
+
const id = new GUID();
|
|
55
|
+
|
|
56
|
+
const data = new Uint8Array(16);
|
|
57
|
+
|
|
58
|
+
id.data = data;
|
|
59
|
+
|
|
60
|
+
expect(id.data).not.toBe(data);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test(".data set/get", () => {
|
|
64
|
+
const a = new GUID();
|
|
65
|
+
|
|
66
|
+
const sample_0 = [
|
|
67
|
+
0xFF, 0xFF, 0xFF, 0xFF,
|
|
68
|
+
0xFF, 0xFF, 0xFF, 0xFF,
|
|
69
|
+
0xFF, 0xFF, 0xFF, 0xFF,
|
|
70
|
+
0xFF, 0xFF, 0xFF, 0xFF,
|
|
71
|
+
];
|
|
72
|
+
|
|
73
|
+
a.data = sample_0;
|
|
74
|
+
|
|
75
|
+
expect(Array.from(a.data)).toEqual(sample_0);
|
|
76
|
+
|
|
77
|
+
const sample_1 = [
|
|
78
|
+
0x00, 0x01, 0x02, 0x03,
|
|
79
|
+
0x04, 0x05, 0x06, 0x07,
|
|
80
|
+
0x08, 0x09, 0x0A, 0x0B,
|
|
81
|
+
0x0C, 0x0D, 0x0E, 0x0F,
|
|
82
|
+
];
|
|
83
|
+
|
|
84
|
+
a.data = sample_1;
|
|
85
|
+
|
|
86
|
+
expect(Array.from(a.data)).toEqual(sample_1);
|
|
87
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { max2 } from "../../../core/math/max2.js";
|
|
2
2
|
import { Voice } from "./Voice.js";
|
|
3
|
-
import EntityBuilder
|
|
3
|
+
import EntityBuilder from "../EntityBuilder.js";
|
|
4
4
|
import GUIElement from "../gui/GUIElement.js";
|
|
5
5
|
import { SerializationMetadata } from "../components/SerializationMetadata.js";
|
|
6
6
|
import HeadsUpDisplay from "../gui/hud/HeadsUpDisplay.js";
|
|
@@ -32,6 +32,7 @@ import { globalMetrics } from "../../metrics/GlobalMetrics.js";
|
|
|
32
32
|
import { MetricsCategory } from "../../metrics/MetricsCategory.js";
|
|
33
33
|
import { ResourceAccessSpecification } from "../../../core/model/ResourceAccessSpecification.js";
|
|
34
34
|
import { ResourceAccessKind } from "../../../core/model/ResourceAccessKind.js";
|
|
35
|
+
import { EntityBuilderFlags } from "../EntityBuilderFlags.js";
|
|
35
36
|
|
|
36
37
|
/**
|
|
37
38
|
* Delay before the user notices the text and begins to read
|
|
@@ -6,7 +6,7 @@ export class Transform {
|
|
|
6
6
|
public readonly rotation: Quaternion
|
|
7
7
|
public readonly scale: Vector3
|
|
8
8
|
|
|
9
|
-
public readonly matrix:ArrayLike<number>
|
|
9
|
+
public readonly matrix: ArrayLike<number>
|
|
10
10
|
|
|
11
11
|
public lookAt(target: Vector3): void
|
|
12
12
|
|
|
@@ -22,6 +22,8 @@ export class Transform {
|
|
|
22
22
|
rotation?: { x: number, y: number, z: number, w: number },
|
|
23
23
|
}): void
|
|
24
24
|
|
|
25
|
+
toJSON(): any
|
|
26
|
+
|
|
25
27
|
copy(other: Transform): void
|
|
26
28
|
|
|
27
29
|
clone(): Transform
|
|
@@ -37,4 +39,12 @@ export class Transform {
|
|
|
37
39
|
multiplyTransforms(a: Transform, b: Transform): void
|
|
38
40
|
|
|
39
41
|
makeIdentity(): void
|
|
42
|
+
|
|
43
|
+
setFlag(flag: number): void
|
|
44
|
+
|
|
45
|
+
getFlag(flag: number): boolean
|
|
46
|
+
|
|
47
|
+
clearFlag(flag: number): void
|
|
48
|
+
|
|
49
|
+
writeFlag(flag: number, value: boolean): void
|
|
40
50
|
}
|
|
@@ -10,6 +10,7 @@ import { TransformFlags } from "./TransformFlags.js";
|
|
|
10
10
|
import { allocate_transform_m4 } from "../../graphics/ecs/mesh-v2/allocate_transform_m4.js";
|
|
11
11
|
import { assert } from "../../../core/assert.js";
|
|
12
12
|
import { m4_multiply } from "../../../core/geom/3d/matrix/m4_multiply.js";
|
|
13
|
+
import { MATRIX_4_IDENTITY } from "../../../core/geom/3d/matrix/MATRIX_4_IDENTITY.js";
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
*
|
|
@@ -315,9 +316,11 @@ export class Transform {
|
|
|
315
316
|
* - scale: [1,1,1]
|
|
316
317
|
*/
|
|
317
318
|
makeIdentity() {
|
|
318
|
-
this.
|
|
319
|
-
|
|
320
|
-
|
|
319
|
+
this.fromMatrix4(MATRIX_4_IDENTITY);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
toString() {
|
|
323
|
+
return `{ position: ${this.position}, rotation: ${this.rotation}, scale: ${this.scale} }`;
|
|
321
324
|
}
|
|
322
325
|
}
|
|
323
326
|
|