@waica/engine 0.4.1 → 0.5.0
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/authoring-defaults.d.ts +11 -0
- package/dist/authoring-defaults.js +51 -0
- package/dist/component.d.ts +10 -1
- package/dist/component.js +1 -0
- package/dist/components/animated-sprite.d.ts +1 -0
- package/dist/components/animated-sprite.js +10 -0
- package/dist/components/sprite.d.ts +1 -0
- package/dist/components/sprite.js +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/state/state-machine.d.ts +2 -1
- package/dist/state/state-machine.js +7 -1
- package/package.json +1 -1
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ComponentClass } from './component.js';
|
|
2
|
+
/**
|
|
3
|
+
* The public authoring surface of a component class: own enumerable fields
|
|
4
|
+
* plus setter-backed accessors (walking the whole prototype chain, so a
|
|
5
|
+
* getter/setter pair inherited from a base class counts), read through the
|
|
6
|
+
* getter so the value is the public one. Excludes `_`-prefixed keys, the
|
|
7
|
+
* base Component wiring (`entity`, `game`), anything the class (or an
|
|
8
|
+
* ancestor) declares `transient`, and values that are `undefined` or not
|
|
9
|
+
* JSON-serializable (`Map`, `Set`, functions, class instances).
|
|
10
|
+
*/
|
|
11
|
+
export declare function authoringDefaults(Class: ComponentClass, onError?: (error: unknown) => void): Record<string, unknown>;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
const EXCLUDED_KEYS = new Set(['entity', 'game']);
|
|
2
|
+
function isSerializable(value) {
|
|
3
|
+
if (value === null)
|
|
4
|
+
return true;
|
|
5
|
+
const kind = typeof value;
|
|
6
|
+
if (kind === 'string' || kind === 'number' || kind === 'boolean')
|
|
7
|
+
return true;
|
|
8
|
+
if (kind !== 'object')
|
|
9
|
+
return false;
|
|
10
|
+
if (Array.isArray(value))
|
|
11
|
+
return true;
|
|
12
|
+
const proto = Object.getPrototypeOf(value);
|
|
13
|
+
return proto === Object.prototype || proto === null;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* The public authoring surface of a component class: own enumerable fields
|
|
17
|
+
* plus setter-backed accessors (walking the whole prototype chain, so a
|
|
18
|
+
* getter/setter pair inherited from a base class counts), read through the
|
|
19
|
+
* getter so the value is the public one. Excludes `_`-prefixed keys, the
|
|
20
|
+
* base Component wiring (`entity`, `game`), anything the class (or an
|
|
21
|
+
* ancestor) declares `transient`, and values that are `undefined` or not
|
|
22
|
+
* JSON-serializable (`Map`, `Set`, functions, class instances).
|
|
23
|
+
*/
|
|
24
|
+
export function authoringDefaults(Class, onError) {
|
|
25
|
+
let instance;
|
|
26
|
+
try {
|
|
27
|
+
instance = new Class();
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
onError?.(error);
|
|
31
|
+
return {};
|
|
32
|
+
}
|
|
33
|
+
const transient = new Set(Class.transient ?? []);
|
|
34
|
+
const keys = new Set(Object.keys(instance));
|
|
35
|
+
for (let proto = Object.getPrototypeOf(instance); proto && proto !== Object.prototype; proto = Object.getPrototypeOf(proto)) {
|
|
36
|
+
for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(proto))) {
|
|
37
|
+
if (descriptor.set)
|
|
38
|
+
keys.add(key);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const result = {};
|
|
42
|
+
for (const key of keys) {
|
|
43
|
+
if (EXCLUDED_KEYS.has(key) || key.startsWith('_') || transient.has(key))
|
|
44
|
+
continue;
|
|
45
|
+
const value = instance[key];
|
|
46
|
+
if (value === undefined || !isSerializable(value))
|
|
47
|
+
continue;
|
|
48
|
+
result[key] = value;
|
|
49
|
+
}
|
|
50
|
+
return result;
|
|
51
|
+
}
|
package/dist/component.d.ts
CHANGED
|
@@ -7,8 +7,10 @@ export interface ParamSpec {
|
|
|
7
7
|
min?: number;
|
|
8
8
|
max?: number;
|
|
9
9
|
step?: number;
|
|
10
|
-
/** Allowed values for a string param; rendered as a dropdown. */
|
|
10
|
+
/** Allowed values for a string param; rendered as a dropdown. Takes precedence over ref. */
|
|
11
11
|
options?: string[];
|
|
12
|
+
/** Project value this string param names; rendered and validated as a typed reference. */
|
|
13
|
+
ref?: 'prefab' | 'stat' | 'action' | 'clip';
|
|
12
14
|
}
|
|
13
15
|
export interface ComponentClass<T extends Component = Component> {
|
|
14
16
|
new (): T;
|
|
@@ -21,6 +23,12 @@ export interface ComponentClass<T extends Component = Component> {
|
|
|
21
23
|
displayName?: string;
|
|
22
24
|
/** Which properties the inspector exposes, with their ranges. */
|
|
23
25
|
params?: Record<string, ParamSpec>;
|
|
26
|
+
/**
|
|
27
|
+
* Instance fields holding runtime state rather than authorable defaults.
|
|
28
|
+
* Excluded from authoringDefaults(); a subclass that does not redeclare
|
|
29
|
+
* this inherits its base's list.
|
|
30
|
+
*/
|
|
31
|
+
transient?: readonly string[];
|
|
24
32
|
}
|
|
25
33
|
/** Cardinal unit normal pointing away from the contacted Solid surface. */
|
|
26
34
|
export interface ContactNormal {
|
|
@@ -43,6 +51,7 @@ export declare abstract class Component {
|
|
|
43
51
|
static componentName: string;
|
|
44
52
|
static displayName?: string;
|
|
45
53
|
static params?: Record<string, ParamSpec>;
|
|
54
|
+
static transient?: readonly string[];
|
|
46
55
|
entity: Entity;
|
|
47
56
|
game: Game;
|
|
48
57
|
/** Runs once the component is mounted on its entity. */
|
package/dist/component.js
CHANGED
|
@@ -19,6 +19,16 @@ export class AnimatedSprite extends Component {
|
|
|
19
19
|
offsetY: { label: 'y offset' },
|
|
20
20
|
layer: { label: 'layer', min: -5, max: 5, step: 1 },
|
|
21
21
|
};
|
|
22
|
+
static transient = [
|
|
23
|
+
'current',
|
|
24
|
+
'player',
|
|
25
|
+
'sheets',
|
|
26
|
+
'texs',
|
|
27
|
+
'mesh',
|
|
28
|
+
'frame',
|
|
29
|
+
'frameScaleX',
|
|
30
|
+
'frameScaleY',
|
|
31
|
+
];
|
|
22
32
|
/** Spritesheet URL. */
|
|
23
33
|
texture = '';
|
|
24
34
|
/** Sheet grid dimensions. */
|
|
@@ -12,6 +12,7 @@ export class Sprite extends Component {
|
|
|
12
12
|
offsetY: { label: 'y offset' },
|
|
13
13
|
layer: { label: 'layer', min: -5, max: 5, step: 1 },
|
|
14
14
|
};
|
|
15
|
+
static transient = ['mesh'];
|
|
15
16
|
// Size, color and offset are reactive so inspector edits update the live quad.
|
|
16
17
|
// Texture still needs a rebuild. TODO(H1): fully reactive props.
|
|
17
18
|
_width = 1;
|
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export { CAMERA_DEFAULTS, resolveSceneCamera, stepSceneCamera } from './camera.j
|
|
|
4
4
|
export type { SceneCameraJson, CameraLimitsJson, ResolvedSceneCamera } from './camera.js';
|
|
5
5
|
export { Entity } from './entity.js';
|
|
6
6
|
export { Component } from './component.js';
|
|
7
|
+
export { authoringDefaults } from './authoring-defaults.js';
|
|
7
8
|
export type { ComponentClass, ContactNormal, ParamSpec, SolidContact, } from './component.js';
|
|
8
9
|
export { collectModuleComponents, mergeRegistryComponents } from './component-registry.js';
|
|
9
10
|
export type { ComponentModule } from './component-registry.js';
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@ export { Game } from './game.js';
|
|
|
2
2
|
export { CAMERA_DEFAULTS, resolveSceneCamera, stepSceneCamera } from './camera.js';
|
|
3
3
|
export { Entity } from './entity.js';
|
|
4
4
|
export { Component } from './component.js';
|
|
5
|
+
export { authoringDefaults } from './authoring-defaults.js';
|
|
5
6
|
export { collectModuleComponents, mergeRegistryComponents } from './component-registry.js';
|
|
6
7
|
export { Input, DEFAULT_BINDINGS } from './input.js';
|
|
7
8
|
export { Stats } from './stats.js';
|
|
@@ -13,7 +13,7 @@ export interface StateTransitionJson {
|
|
|
13
13
|
* transitions instead of a real state.
|
|
14
14
|
*/
|
|
15
15
|
export interface StateJson {
|
|
16
|
-
/** Clip
|
|
16
|
+
/** Clip reference resolved against the sibling AnimatedSprite; defaults to the state's name. */
|
|
17
17
|
clip?: string;
|
|
18
18
|
transitions?: StateTransitionJson[];
|
|
19
19
|
}
|
|
@@ -53,6 +53,7 @@ export declare class StateMachine extends Component {
|
|
|
53
53
|
label: string;
|
|
54
54
|
};
|
|
55
55
|
};
|
|
56
|
+
static transient: string[];
|
|
56
57
|
/** The character's role — names the logic set providing its state code. */
|
|
57
58
|
role: string;
|
|
58
59
|
/** Starting state; defaults to the first declared state. */
|
|
@@ -47,6 +47,7 @@ export class StateMachine extends Component {
|
|
|
47
47
|
static params = {
|
|
48
48
|
role: { label: 'Role' },
|
|
49
49
|
};
|
|
50
|
+
static transient = ['current', 'elapsed', 'instanceHooks', 'signals', 'warnedClips'];
|
|
50
51
|
/** The character's role — names the logic set providing its state code. */
|
|
51
52
|
role = '';
|
|
52
53
|
/** Starting state; defaults to the first declared state. */
|
|
@@ -96,7 +97,12 @@ export class StateMachine extends Component {
|
|
|
96
97
|
// capped so a degenerate cyclic graph can't hang the loop.
|
|
97
98
|
for (let hops = 0; hops < 8; hops++) {
|
|
98
99
|
const edge = nextTransition(this.states, this.current, this.env());
|
|
99
|
-
|
|
100
|
+
// A '*' edge is re-merged against whatever state the loop just
|
|
101
|
+
// entered, so a still-queued signal (signals.clear() only runs after
|
|
102
|
+
// this loop) keeps firing every remaining hop. Without this guard
|
|
103
|
+
// that replays onExit/onEnter on the state hops already settled into
|
|
104
|
+
// — goto() has the same guard for the same reason.
|
|
105
|
+
if (!edge || edge.to === this.current)
|
|
100
106
|
break;
|
|
101
107
|
// A transition fired by a key press spends it: one press, one
|
|
102
108
|
// transition — it can't fire again from the state just entered.
|