@adatechnology/game-crowd-three 0.3.8 → 0.4.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/chunk-PXT6DYGJ.js +1707 -0
- package/dist/chunk-PXT6DYGJ.js.map +1 -0
- package/dist/index.d.ts +12 -291
- package/dist/index.global.js +8899 -4990
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +30 -1075
- package/dist/index.js.map +1 -1
- package/dist/testing-sTAa84Ib.d.ts +442 -0
- package/dist/testing.d.ts +7 -0
- package/dist/testing.js +19 -0
- package/dist/testing.js.map +1 -0
- package/package.json +14 -9
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
import { CrowdStore, Corpse, Civilian, Crowd, CrowdType, Herd, Flock, CrowdUpdateContext, CrowdPack, InfectionModelLike, CrowdPhysicsOptions } from '@adatechnology/game-crowd';
|
|
2
|
+
import { IdentityLook, BodyVariant, BakeBuilders, BakeSpec, KitAccessory, Three } from '@adatechnology/game-characters-three';
|
|
3
|
+
import { ModuleHost, TestableModule } from '@adatechnology/game-contracts';
|
|
4
|
+
import { Player } from '@adatechnology/game-player';
|
|
5
|
+
import * as THREE_NS from 'three';
|
|
6
|
+
import { InstancePose } from '@adatechnology/game-characters';
|
|
7
|
+
|
|
8
|
+
var numbers = {
|
|
9
|
+
lodDistances: [
|
|
10
|
+
18,
|
|
11
|
+
55
|
|
12
|
+
],
|
|
13
|
+
lodHysteresis: 1.5,
|
|
14
|
+
behindFrom: 30,
|
|
15
|
+
behindFactor: 0.35,
|
|
16
|
+
behindMargin: 3,
|
|
17
|
+
farCull: 200,
|
|
18
|
+
gaitMax: 1.4,
|
|
19
|
+
attackEnter: 2.56,
|
|
20
|
+
attackLeave: 4.84,
|
|
21
|
+
swell: 0.9,
|
|
22
|
+
swellPivot: 0.5,
|
|
23
|
+
ageBase: 0.75,
|
|
24
|
+
agePer: 0.08,
|
|
25
|
+
armBase: 1,
|
|
26
|
+
armPer: 0.4,
|
|
27
|
+
corpseNear: 18,
|
|
28
|
+
corpseFade: 60,
|
|
29
|
+
corpseDarken: 0.7,
|
|
30
|
+
corpseRise: 1.8,
|
|
31
|
+
corpseAgeBase: 0.8,
|
|
32
|
+
corpseAgeDark: 0.2,
|
|
33
|
+
childHeight: 0.66,
|
|
34
|
+
childBuild: 0.75,
|
|
35
|
+
bittenLook: 0.3,
|
|
36
|
+
civilianSkinStep: 0.25,
|
|
37
|
+
civilianBake: 0.8,
|
|
38
|
+
civilianBatch: 4
|
|
39
|
+
};
|
|
40
|
+
var poses = {
|
|
41
|
+
dormant: "fallen",
|
|
42
|
+
airborne: "leap",
|
|
43
|
+
eating: "eat",
|
|
44
|
+
pileStep: "attack",
|
|
45
|
+
swing: "scream",
|
|
46
|
+
crawl: "crawl",
|
|
47
|
+
grab: "attack",
|
|
48
|
+
calling: "scream",
|
|
49
|
+
"default": "walk",
|
|
50
|
+
corpse: "fallen",
|
|
51
|
+
civilian: "walk"
|
|
52
|
+
};
|
|
53
|
+
var defaults = {
|
|
54
|
+
numbers: numbers,
|
|
55
|
+
poses: poses
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/** The numbers of the look a body is given from its identity (T4b.7, D11). Every one is a default a game can change. */
|
|
59
|
+
declare const VARIETY_DEFAULTS: {
|
|
60
|
+
readonly capChance: 0.16;
|
|
61
|
+
readonly backpackChance: 0.2;
|
|
62
|
+
readonly hoodChance: 0.1;
|
|
63
|
+
/** Chance of a wound in a region at the youngest infection age, and how much each age step adds. */
|
|
64
|
+
readonly woundBase: 0.05;
|
|
65
|
+
readonly woundPerAge: 0.12;
|
|
66
|
+
/** Share of the wounds that are severe. */
|
|
67
|
+
readonly severeShare: 0.35;
|
|
68
|
+
/** Steps of the infection age of the pack (0 .. ageSteps). */
|
|
69
|
+
readonly ageSteps: 3;
|
|
70
|
+
/** How much of a shove's push (0..1) tilts the body. */
|
|
71
|
+
readonly leanScale: 0.3;
|
|
72
|
+
};
|
|
73
|
+
type CrowdVarietyNumbers = {
|
|
74
|
+
readonly [K in keyof typeof VARIETY_DEFAULTS]: number;
|
|
75
|
+
};
|
|
76
|
+
/** The whole look of an agent, all of it from its identity and its state in the store: it never changes with the level of detail. */
|
|
77
|
+
declare const lookOfAgent: (store: CrowdStore, i: number, N: CrowdVarietyNumbers, extra?: Pick<IdentityLook, "clipA" | "clipB" | "clipBlend" | "clipSpeed" | "clips">) => IdentityLook;
|
|
78
|
+
|
|
79
|
+
type CrowdRenderNumbers = typeof defaults.numbers;
|
|
80
|
+
type CrowdPoseMap = {
|
|
81
|
+
readonly [K in keyof typeof defaults.poses]: InstancePose;
|
|
82
|
+
};
|
|
83
|
+
/** The game's numbers for the drawing (G 67098 `hordeRender`, G 70177 `npcRender`) and the instance pose of each state. */
|
|
84
|
+
declare const CROWD_RENDER_DEFAULTS: {
|
|
85
|
+
readonly sources: Readonly<Record<string, string>>;
|
|
86
|
+
readonly numbers: CrowdRenderNumbers;
|
|
87
|
+
readonly poses: CrowdPoseMap;
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* One body for a batch: the 12 numbers of the shader's `iA`, `iB` and `iC` (`a`: x, z, yaw, phase; `b`: height and build over the variant's,
|
|
91
|
+
* stride, pose; `c`: missing parts, age look, arms, skin), the shirt colour as hex with the shade it is multiplied by, the eye colour (none:
|
|
92
|
+
* no glow) and the ground height.
|
|
93
|
+
*/
|
|
94
|
+
type CrowdInstance = {
|
|
95
|
+
readonly a: readonly [number, number, number, number];
|
|
96
|
+
readonly b: readonly [number, number, number, number];
|
|
97
|
+
readonly c: readonly [number, number, number, number];
|
|
98
|
+
readonly color: number;
|
|
99
|
+
readonly shade: number;
|
|
100
|
+
readonly eye: number | null;
|
|
101
|
+
readonly y: number;
|
|
102
|
+
/** The identity `iD` (with `variety`): wounds, trousers, gait style, accessories, clips, lean. See `packIdentity`. */
|
|
103
|
+
readonly d?: readonly [number, number, number, number];
|
|
104
|
+
/** The accessory bits of the look (with `variety`), so a renderer routes the instance to the accessory batches. */
|
|
105
|
+
readonly accessories?: number;
|
|
106
|
+
/** The crowd type index of the agent (with `variety`). */
|
|
107
|
+
readonly type?: number;
|
|
108
|
+
};
|
|
109
|
+
/** A baked variant as the drawing reads it: its own height and build (the instance scales the agent's against them). */
|
|
110
|
+
type VariantSize = {
|
|
111
|
+
readonly s: number;
|
|
112
|
+
readonly bulk: number;
|
|
113
|
+
};
|
|
114
|
+
/** Where the frame is seen from. `target` is who the agents attack (the attack pose); `hidden` leaves an agent out (a floor the viewer is not on). */
|
|
115
|
+
type CrowdFrame = {
|
|
116
|
+
readonly camera: {
|
|
117
|
+
readonly x: number;
|
|
118
|
+
readonly z: number;
|
|
119
|
+
};
|
|
120
|
+
/** The view's yaw: forward is `(-sin, -cos)`. */
|
|
121
|
+
readonly viewYaw: number;
|
|
122
|
+
readonly target?: {
|
|
123
|
+
readonly x: number;
|
|
124
|
+
readonly z: number;
|
|
125
|
+
readonly alive: boolean;
|
|
126
|
+
} | null;
|
|
127
|
+
readonly hidden?: (i: number) => boolean;
|
|
128
|
+
/** How much of the level budget to use this frame, 0..1 (default 1); the renderer lowers it when the frames run long. */
|
|
129
|
+
readonly detailScale?: number;
|
|
130
|
+
};
|
|
131
|
+
/** Takes one instance for the batch of `variant` at level `level` (0 near, 1 middle, 2 far). */
|
|
132
|
+
type CrowdInstanceSink = (variant: number, level: number, instance: CrowdInstance) => void;
|
|
133
|
+
/** Takes one body on the ground that was not an agent (a civilian killed outright): the plain body batch. */
|
|
134
|
+
type PlainCorpseSink = (instance: CrowdInstance) => void;
|
|
135
|
+
type CrowdInstancesOptions = {
|
|
136
|
+
readonly numbers?: Partial<CrowdRenderNumbers>;
|
|
137
|
+
readonly poses?: Partial<CrowdPoseMap>;
|
|
138
|
+
/** The eye colour of each crowd type, by type index (G `_eye`); null for a type that has none. */
|
|
139
|
+
readonly eyes: readonly (number | null)[];
|
|
140
|
+
/** Identity for every agent (T4b.7), default off: each instance carries `d`, `accessories` and `type`, and the stagger pose; the game's numbers do not change. */
|
|
141
|
+
readonly variety?: {
|
|
142
|
+
readonly numbers?: Partial<CrowdVarietyNumbers>;
|
|
143
|
+
readonly impostorFrom?: number;
|
|
144
|
+
readonly segmentClips?: boolean;
|
|
145
|
+
readonly budget?: readonly number[];
|
|
146
|
+
};
|
|
147
|
+
};
|
|
148
|
+
type CrowdInstances = {
|
|
149
|
+
readonly numbers: CrowdRenderNumbers;
|
|
150
|
+
/** Writes the agents seen this frame, keeps each one's level of detail and attack pose in the store (`lod`, `attackPose`) and returns how many went out. */
|
|
151
|
+
agents(store: CrowdStore, variants: readonly VariantSize[], frame: CrowdFrame, sink: CrowdInstanceSink): number;
|
|
152
|
+
/** Writes the bodies on the ground: an agent's on its variant, the others on the plain batch. `life` is the seconds a body lasts (the crowd's `corpseSeconds`). */
|
|
153
|
+
corpses(entries: readonly {
|
|
154
|
+
readonly age: number;
|
|
155
|
+
readonly data: Corpse;
|
|
156
|
+
}[], variants: readonly VariantSize[], frame: CrowdFrame, life: number, sink: CrowdInstanceSink, plain: PlainCorpseSink): void;
|
|
157
|
+
/** Writes the civilians that are still people (not dead, turned or gone); `colorOf` gives each one's shirt. */
|
|
158
|
+
civilians(list: readonly Civilian[], colorOf: (civilian: Civilian) => number, sink: (civilian: Civilian, instance: CrowdInstance) => void): void;
|
|
159
|
+
};
|
|
160
|
+
/**
|
|
161
|
+
* The drawing of a crowd as instances, without three.js: a literal port of the team game's `hordeRender` (G 67098-67136) and `npcRender`
|
|
162
|
+
* (G 70177-70184). The renderer of `game-crowd-three` hands each instance to a `BodyBatch` of `game-characters-three`; any other drawing can take them.
|
|
163
|
+
*/
|
|
164
|
+
declare function createCrowdInstances(options: CrowdInstancesOptions): CrowdInstances;
|
|
165
|
+
|
|
166
|
+
/** Variety on the instanced path (T4b.7, D11 and D12): identity for every body, accessories, real shadows only near and blobs beyond. Absent, the renderer is the game's. */
|
|
167
|
+
type CrowdRendererVariety = {
|
|
168
|
+
readonly numbers?: Partial<CrowdVarietyNumbers>;
|
|
169
|
+
/** The accessory batches, drawn by the kit's builders (default `KIT_ACCESSORIES`); `false` for none. */
|
|
170
|
+
readonly accessories?: readonly KitAccessory[] | false;
|
|
171
|
+
/** Instances an accessory batch holds at the near and the middle level (default 480 and 1400). */
|
|
172
|
+
readonly accessoryCapacity?: readonly [number, number];
|
|
173
|
+
/** Only the nearest level casts a real shadow (default true). */
|
|
174
|
+
readonly nearShadows?: boolean;
|
|
175
|
+
/** Draws the depth of the near level first so its lit pass shades each pixel once (default true): the room's lights make an overdrawn fragment the dearest part of a crowd close to the camera. */
|
|
176
|
+
readonly nearDepthPrepass?: boolean;
|
|
177
|
+
/** One dark disc under each body beyond the nearest level (default true). */
|
|
178
|
+
readonly blobShadows?: boolean;
|
|
179
|
+
/** Walk the bodies of the near and middle levels from the clip texture (12 bones, 24 texels, nearest filtered; step 3 of the ladder). Default off: the shader's own walk. */
|
|
180
|
+
readonly segmentClips?: boolean;
|
|
181
|
+
/**
|
|
182
|
+
* How many bodies each mesh level may draw (default 160, 320 and 600 for the near, middle and far levels, and half of the near budget for the bodies on the ground that keep the near mesh; `false` for the nominal distances only). A crowd packed near the camera pulls the edges in,
|
|
183
|
+
* so the bodies past a level's budget draw at the next one, and the last go to the impostor. Under `adapt` the budget shrinks while the crowd takes the GPU longer than `gpuHighMs` and grows back under `gpuLowMs` (timer queries; where the
|
|
184
|
+
* GPU has none, while the frames run longer than `highMs` and back under `lowMs`).
|
|
185
|
+
*/
|
|
186
|
+
readonly budget?: false | {
|
|
187
|
+
readonly levels?: readonly number[];
|
|
188
|
+
readonly adapt?: false | {
|
|
189
|
+
readonly gpuHighMs?: number;
|
|
190
|
+
readonly gpuLowMs?: number;
|
|
191
|
+
readonly highMs?: number;
|
|
192
|
+
readonly lowMs?: number;
|
|
193
|
+
readonly minScale?: number;
|
|
194
|
+
};
|
|
195
|
+
};
|
|
196
|
+
/** The far tier (default on, from 90 m): one atlas for every type, one draw call; `false` keeps the far mesh to the cull distance. */
|
|
197
|
+
readonly impostor?: false | {
|
|
198
|
+
readonly from?: number;
|
|
199
|
+
readonly capacity?: number;
|
|
200
|
+
readonly light?: {
|
|
201
|
+
readonly r: number;
|
|
202
|
+
readonly g: number;
|
|
203
|
+
readonly b: number;
|
|
204
|
+
};
|
|
205
|
+
};
|
|
206
|
+
};
|
|
207
|
+
type CrowdRendererOptions = {
|
|
208
|
+
readonly crowd: Crowd;
|
|
209
|
+
/** The rich builders the bodies are baked from (`game-characters-three`: the Bestiário builder, optionally the survivors'). */
|
|
210
|
+
readonly builders: BakeBuilders;
|
|
211
|
+
/** The name the rich builder knows a crowd type by (default its id). */
|
|
212
|
+
readonly typeName?: (type: CrowdType, index: number) => string;
|
|
213
|
+
/** The civilians to draw and the body each one is baked from (G 68469 `PB`: a human spec or a portrait). Without it no civilian is drawn. */
|
|
214
|
+
readonly civilians?: {
|
|
215
|
+
readonly list: () => readonly Civilian[];
|
|
216
|
+
readonly body: (civilian: Civilian) => BakeSpec;
|
|
217
|
+
readonly color?: (civilian: Civilian) => number;
|
|
218
|
+
};
|
|
219
|
+
/** The plain body for bodies on the ground that were not agents (default the instanced body at the middle level, G `BODY_LOD[1]`). */
|
|
220
|
+
readonly plainBody?: THREE_NS.BufferGeometry;
|
|
221
|
+
/** Whether the bodies on the ground are drawn this frame (default always). */
|
|
222
|
+
readonly drawCorpses?: () => boolean;
|
|
223
|
+
readonly numbers?: Partial<CrowdRenderNumbers>;
|
|
224
|
+
readonly poses?: Partial<CrowdPoseMap>;
|
|
225
|
+
readonly variety?: CrowdRendererVariety;
|
|
226
|
+
};
|
|
227
|
+
type CrowdRenderer = {
|
|
228
|
+
/** Holds every batch; add it to the scene. */
|
|
229
|
+
readonly group: THREE_NS.Group;
|
|
230
|
+
readonly instances: CrowdInstances;
|
|
231
|
+
/** Bakes every type's variants now (otherwise a type is baked the first time one of its bodies is drawn). */
|
|
232
|
+
bake(): void;
|
|
233
|
+
/**
|
|
234
|
+
* Bakes and makes every batch the frame would make on demand (the bodies on the ground, the blob shadows, the impostors, the accessories of the near and middle levels), so that a host that compiles
|
|
235
|
+
* its scene (`ProgramWarmup`) links the body, accessory, blob and impostor programs and their depth and distance materials before play, and no batch is made during it.
|
|
236
|
+
*/
|
|
237
|
+
prepare(): void;
|
|
238
|
+
/** Draws the frame: the agents, the bodies on the ground and the civilians. */
|
|
239
|
+
update(dt: number, frame: CrowdFrame): void;
|
|
240
|
+
/** Agents drawn at each level of detail in the last frame (G `lodCounts`). */
|
|
241
|
+
readonly lodCounts: readonly [number, number, number];
|
|
242
|
+
/** The share of the level budget in use, 1 down to the adaptive floor. */
|
|
243
|
+
readonly detailScale: number;
|
|
244
|
+
/** The smoothed GPU time of the crowd's draws in milliseconds (0 until the timer answers, or without one). */
|
|
245
|
+
readonly gpuMs: number;
|
|
246
|
+
/** Agents drawn as impostors in the last frame. */
|
|
247
|
+
readonly impostorCount: number;
|
|
248
|
+
/** Batches with something to draw. */
|
|
249
|
+
readonly drawCalls: number;
|
|
250
|
+
readonly bakeMs: number;
|
|
251
|
+
readonly variants: readonly BodyVariant[];
|
|
252
|
+
dispose(): void;
|
|
253
|
+
};
|
|
254
|
+
/**
|
|
255
|
+
* The crowd drawn on the instanced path: every type's variants baked at the three levels of detail (G 67079 `ZVAR`, the variants and seeds of
|
|
256
|
+
* `game-characters`), a few draw calls for thousands of agents, the bodies on the ground and the civilians. The instances are `createCrowdInstances`
|
|
257
|
+
* (the port of `hordeRender` and `npcRender`); the batches are `game-characters-three`'s.
|
|
258
|
+
*/
|
|
259
|
+
declare function createCrowdRenderer(three: Three, options: CrowdRendererOptions): CrowdRenderer;
|
|
260
|
+
|
|
261
|
+
/** One drawn animal, as `game-animals-three` builds it (structural: this package does not depend on it). */
|
|
262
|
+
type DrawnAnimal = {
|
|
263
|
+
readonly root: THREE_NS.Object3D;
|
|
264
|
+
readonly wings: readonly {
|
|
265
|
+
readonly shoulder: THREE_NS.Object3D;
|
|
266
|
+
readonly elbow: THREE_NS.Object3D;
|
|
267
|
+
readonly side: number;
|
|
268
|
+
}[];
|
|
269
|
+
phase: number;
|
|
270
|
+
};
|
|
271
|
+
/** What draws the animals: `game-animals-three`'s `createAnimalsThree(THREE)` is one as it is. */
|
|
272
|
+
type AnimalDrawer<TSpecies = unknown> = {
|
|
273
|
+
build(species: TSpecies, options?: {
|
|
274
|
+
readonly phase?: number;
|
|
275
|
+
}): DrawnAnimal;
|
|
276
|
+
animate(rig: DrawnAnimal, params: {
|
|
277
|
+
readonly time: number;
|
|
278
|
+
readonly delta: number;
|
|
279
|
+
readonly clip: string;
|
|
280
|
+
}): void;
|
|
281
|
+
setVisualState?(rig: DrawnAnimal, state: 'alive' | 'infected' | 'dead'): void;
|
|
282
|
+
};
|
|
283
|
+
type HerdViewOptions<TSpecies> = {
|
|
284
|
+
readonly herd: Herd;
|
|
285
|
+
readonly drawer: AnimalDrawer<TSpecies>;
|
|
286
|
+
/** The species card of an animal's species id (`game-animals-species` `getSpecies`). */
|
|
287
|
+
readonly species: (id: string) => TSpecies | undefined;
|
|
288
|
+
/** The vultures: the flock that moves the herd's sky animals, in the order they were added. */
|
|
289
|
+
readonly flock?: Flock;
|
|
290
|
+
};
|
|
291
|
+
type HerdView = {
|
|
292
|
+
readonly group: THREE_NS.Group;
|
|
293
|
+
/** Builds what is new in the herd and moves every drawn animal to its place this frame (G 66697-66708). */
|
|
294
|
+
update(dt: number): void;
|
|
295
|
+
readonly count: number;
|
|
296
|
+
clear(): void;
|
|
297
|
+
};
|
|
298
|
+
/**
|
|
299
|
+
* The herd drawn with the animals' own rigs: each animal where `game-crowd`'s herd put it, turned to its heading and animated with its clip (G 66697
|
|
300
|
+
* `E.pele.mesh.position.set(E.x, 0, E.z)`, `animQuad`); the vultures where the flock puts them, gliding with the wings half open (G 66704-66708).
|
|
301
|
+
*/
|
|
302
|
+
declare function createHerdView<TSpecies>(three: {
|
|
303
|
+
readonly Group: new () => THREE_NS.Group;
|
|
304
|
+
}, options: HerdViewOptions<TSpecies>): HerdView;
|
|
305
|
+
|
|
306
|
+
/** The ground a scene lays out its things on: the crowd area centre. */
|
|
307
|
+
type CrowdScenePlace = {
|
|
308
|
+
readonly cx: number;
|
|
309
|
+
readonly cz: number;
|
|
310
|
+
};
|
|
311
|
+
/** What the host project lends the scenes to draw with: its wall piece and the ids of the catalogue items it has (`ModuleHost.addObject`). Without them a scene only writes the grid. */
|
|
312
|
+
type CrowdSceneProps = {
|
|
313
|
+
/** An Object3D wall of this length and height, base at the origin along x (the kit's `wallPiece`). */
|
|
314
|
+
readonly wall?: (three: typeof THREE_NS, size: {
|
|
315
|
+
readonly length: number;
|
|
316
|
+
readonly height: number;
|
|
317
|
+
}) => THREE_NS.Object3D | undefined;
|
|
318
|
+
/** Item ids of the host's catalogue: the gas cylinder, the car and the car's fuel tank. */
|
|
319
|
+
readonly items?: {
|
|
320
|
+
readonly gasCylinder?: string;
|
|
321
|
+
readonly car?: string;
|
|
322
|
+
readonly carTank?: string;
|
|
323
|
+
};
|
|
324
|
+
};
|
|
325
|
+
/** A place for the crowd to be born in, with the walls and doors of its own. The bench applies it after the seed and before the physics and the count. */
|
|
326
|
+
interface CrowdBenchScene {
|
|
327
|
+
readonly id: string;
|
|
328
|
+
/** Writes the walls and the doors of the scene to the crowd's grid. */
|
|
329
|
+
layout(crowd: Crowd, place: CrowdScenePlace): void;
|
|
330
|
+
/** Bears `count` agents of `type` (-1: the pack's mix), the `first`-th of the scene onwards; `unit` is the seeded stream of the scene. */
|
|
331
|
+
spawn(crowd: Crowd, request: {
|
|
332
|
+
readonly first: number;
|
|
333
|
+
readonly count: number;
|
|
334
|
+
readonly type: number;
|
|
335
|
+
readonly unit: () => number;
|
|
336
|
+
}, place: CrowdScenePlace): void;
|
|
337
|
+
/** The context of `crowd.update`: where the bands are centred and where the flow converges. */
|
|
338
|
+
context?(place: CrowdScenePlace): Pick<CrowdUpdateContext, 'bandCentre' | 'flowTarget'>;
|
|
339
|
+
/** Where the camera stands to see the scene. */
|
|
340
|
+
view(place: CrowdScenePlace): {
|
|
341
|
+
readonly eye: readonly [number, number, number];
|
|
342
|
+
readonly target: readonly [number, number, number];
|
|
343
|
+
};
|
|
344
|
+
/** Puts the scene's things in the host's world; returns what takes them away. */
|
|
345
|
+
props?(host: ModuleHost, place: CrowdScenePlace, props: CrowdSceneProps): () => void;
|
|
346
|
+
}
|
|
347
|
+
/** A horde pressed against a wall of 30 m with a door of 1.2 m, born behind it; the player stands on the other side. */
|
|
348
|
+
declare const DENSE_WALL: CrowdBenchScene;
|
|
349
|
+
/** A horde coming down a street of 12 m at a row of six gas cylinders and a car; the player stands at the end of the street. */
|
|
350
|
+
declare const CHAIN_LINE: CrowdBenchScene;
|
|
351
|
+
declare const BUILTIN_SCENES: Readonly<Record<string, CrowdBenchScene>>;
|
|
352
|
+
|
|
353
|
+
declare const CROWD_AREA_ID = "crowd_area";
|
|
354
|
+
/** The species card the bench reads: the gait rates (`game-animals-species` cards are these). */
|
|
355
|
+
type CrowdBenchSpecies = {
|
|
356
|
+
readonly walkHz: number;
|
|
357
|
+
readonly runHz: number;
|
|
358
|
+
};
|
|
359
|
+
/** What a crowd effect is in the host's effect catalogue (`host.effects`): its id and, optionally, the option it plays with. */
|
|
360
|
+
type CrowdEffectMap = Readonly<Record<string, {
|
|
361
|
+
readonly effect: string;
|
|
362
|
+
readonly param?: number | string;
|
|
363
|
+
} | null>>;
|
|
364
|
+
/** The room's effects for the crowd's (the Oficina de VFX recipes of `game-vfx`): blood on a hit, a severed limb, the bloater's cloud, a spark, dust. */
|
|
365
|
+
declare const CROWD_EFFECTS: CrowdEffectMap;
|
|
366
|
+
type CrowdTestModuleOptions = {
|
|
367
|
+
readonly locale?: string;
|
|
368
|
+
/** The bodies the crowd draws from (types, ages, outfits): the host's content (`game-characters-undead` `undeadCrowdPack()`, or a game's own). */
|
|
369
|
+
readonly pack: CrowdPack;
|
|
370
|
+
/** The rich builders the bodies are baked from, made once three.js is lent. Without it the crowd runs and nothing is drawn. */
|
|
371
|
+
readonly builders?: (three: Three) => BakeBuilders;
|
|
372
|
+
/** The name the rich builder knows a type by (default its id). */
|
|
373
|
+
readonly typeName?: (type: CrowdType, index: number) => string;
|
|
374
|
+
/** The bench's name of a type (default its id). */
|
|
375
|
+
readonly typeLabel?: (type: CrowdType, locale: string) => string;
|
|
376
|
+
/** The bodies of the civilians (baked human specs), one per civilian, in order; without them the civilians run but are not drawn. */
|
|
377
|
+
readonly civilianBodies?: readonly BakeSpec[];
|
|
378
|
+
/** The animals: the species card of an id, its size (`game-animals` `quadrupedLayout(body).size`, `birdSize(body)`) and, optionally, what draws them. */
|
|
379
|
+
readonly animals?: {
|
|
380
|
+
readonly species: (id: string) => CrowdBenchSpecies | undefined;
|
|
381
|
+
readonly size: (species: CrowdBenchSpecies) => number;
|
|
382
|
+
readonly drawer?: (three: Three) => AnimalDrawer<CrowdBenchSpecies>;
|
|
383
|
+
};
|
|
384
|
+
/** A region model to bring agents from (`game-infection` `create(...)`) and the region the area is in. */
|
|
385
|
+
readonly infection?: {
|
|
386
|
+
readonly create: () => InfectionModelLike;
|
|
387
|
+
readonly region: string;
|
|
388
|
+
readonly active?: (model: InfectionModelLike) => number;
|
|
389
|
+
};
|
|
390
|
+
/** The effect ids of the host for the crowd's effects (default `CROWD_EFFECTS`; null leaves one out). */
|
|
391
|
+
readonly effects?: CrowdEffectMap;
|
|
392
|
+
readonly seed?: number;
|
|
393
|
+
/** Variety for the drawing (identity, accessories, near shadows, blobs): see `CrowdRendererVariety`. Default off. */
|
|
394
|
+
readonly variety?: CrowdRendererVariety;
|
|
395
|
+
/** The physics options of the crowd (personality, contact, balance...): see `CrowdPhysicsOptions`. Default off; the bench's `physics` control turns on the package defaults when this is absent. */
|
|
396
|
+
readonly crowdPhysics?: CrowdPhysicsOptions;
|
|
397
|
+
/** Scenes the bench can be born in, by id, over the built-in `dense_wall` and `chain_line`. */
|
|
398
|
+
readonly scenes?: Readonly<Record<string, CrowdBenchScene>>;
|
|
399
|
+
/** What the scenes draw with: the host project's wall piece and catalogue item ids. */
|
|
400
|
+
readonly props?: CrowdSceneProps;
|
|
401
|
+
/** Bake every type and make the drawing as soon as the module is on a frame, so the first play frame pays no bake and the room's warm-up draws the batches. Default off. */
|
|
402
|
+
readonly eager?: boolean;
|
|
403
|
+
/** Agents when the area opens (default 0, so a room that only carries the module stays calm). */
|
|
404
|
+
readonly startCount?: number;
|
|
405
|
+
/** Where the crowd is born around (default 0, -45: in front of the room's start). */
|
|
406
|
+
readonly center?: readonly [number, number];
|
|
407
|
+
};
|
|
408
|
+
/** What the scenarios use of the context the test room passes. */
|
|
409
|
+
interface CrowdScenarioLike {
|
|
410
|
+
expect(condition: boolean, label: string, data?: Record<string, unknown>): void;
|
|
411
|
+
}
|
|
412
|
+
type CrowdTestModule = TestableModule<CrowdScenarioLike> & {
|
|
413
|
+
readonly crowd: Crowd;
|
|
414
|
+
readonly player: Player;
|
|
415
|
+
readonly renderer: CrowdRenderer | null;
|
|
416
|
+
};
|
|
417
|
+
/**
|
|
418
|
+
* The crowd area of a test room, against the generic contracts only: a horde of any pack drawn on the instanced path (the baked variants of
|
|
419
|
+
* `game-characters-three`), the room's camera as the `game-player` body it hunts, civilians, the herd and the vultures, and a bridge to a region
|
|
420
|
+
* model. Sounds go to `host.audio` (the crowd's bank is registered there), effects to `host.effects`. The pack and the bodies come in by option:
|
|
421
|
+
* this package knows no game.
|
|
422
|
+
*/
|
|
423
|
+
declare function createCrowdTestModule(options: CrowdTestModuleOptions): CrowdTestModule;
|
|
424
|
+
|
|
425
|
+
type Keys<K extends string> = Readonly<Record<K, string>>;
|
|
426
|
+
type CrowdBenchText = {
|
|
427
|
+
readonly group: string;
|
|
428
|
+
readonly name: string;
|
|
429
|
+
readonly mix: string;
|
|
430
|
+
readonly controls: Keys<'scene' | 'physics' | 'count' | 'type' | 'night' | 'seed' | 'spawn' | 'noise' | 'hit' | 'kill_all' | 'join' | 'flee' | 'herd' | 'materialize' | 'push' | 'reset'>;
|
|
431
|
+
readonly hints: Keys<'scene' | 'physics' | 'count' | 'type' | 'night' | 'noise' | 'hit' | 'join' | 'flee' | 'herd' | 'materialize' | 'push'>;
|
|
432
|
+
readonly layers: Keys<'corpses' | 'civilians' | 'animals'>;
|
|
433
|
+
readonly metrics: Keys<'agents' | 'drawn' | 'lod_near' | 'lod_middle' | 'lod_far' | 'draw_calls' | 'bake_ms' | 'active' | 'kills' | 'corpses' | 'civilians' | 'health' | 'grabbed' | 'message' | 'falls_pressure' | 'falls_chain' | 'falls_landing' | 'climbers' | 'mound_max' | 'thrown_peak' | 'max_overlap' | 'chain_links' | 'crowd_ms_p99' | 'detail_scale' | 'crowd_gpu_ms'>;
|
|
434
|
+
readonly sceneNames: Keys<'open' | 'dense_wall' | 'chain_line'>;
|
|
435
|
+
readonly scenarios: Keys<'relevance' | 'lod' | 'attack_pose' | 'corpse_darkens' | 'civilians_flee' | 'herd_calls' | 'vultures' | 'infection' | 'determinism'>;
|
|
436
|
+
readonly messages: Keys<'called' | 'burst_hit' | 'swing_knock' | 'pounce_knock' | 'migration' | 'door_broken' | 'alarm' | 'bark' | 'growl' | 'bitten' | 'turned' | 'died'>;
|
|
437
|
+
readonly yes: string;
|
|
438
|
+
readonly no: string;
|
|
439
|
+
};
|
|
440
|
+
declare const crowdBenchTextOf: (locale: string) => CrowdBenchText;
|
|
441
|
+
|
|
442
|
+
export { type AnimalDrawer as A, lookOfAgent as B, type CrowdInstance as C, type DrawnAnimal as D, BUILTIN_SCENES as E, CHAIN_LINE as F, type CrowdBenchScene as G, type HerdView as H, type CrowdScenePlace as I, type CrowdSceneProps as J, DENSE_WALL as K, type PlainCorpseSink as P, type VariantSize as V, CROWD_AREA_ID as a, CROWD_EFFECTS as b, CROWD_RENDER_DEFAULTS as c, type CrowdBenchSpecies as d, type CrowdBenchText as e, type CrowdEffectMap as f, type CrowdFrame as g, type CrowdInstanceSink as h, type CrowdInstances as i, type CrowdInstancesOptions as j, type CrowdPoseMap as k, type CrowdRenderNumbers as l, type CrowdRenderer as m, type CrowdRendererOptions as n, type CrowdRendererVariety as o, type CrowdScenarioLike as p, type CrowdTestModule as q, type CrowdTestModuleOptions as r, type CrowdVarietyNumbers as s, type HerdViewOptions as t, VARIETY_DEFAULTS as u, createCrowdInstances as v, createCrowdRenderer as w, createCrowdTestModule as x, createHerdView as y, crowdBenchTextOf as z };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { E as BUILTIN_SCENES, F as CHAIN_LINE, a as CROWD_AREA_ID, b as CROWD_EFFECTS, G as CrowdBenchScene, d as CrowdBenchSpecies, e as CrowdBenchText, f as CrowdEffectMap, p as CrowdScenarioLike, I as CrowdScenePlace, J as CrowdSceneProps, q as CrowdTestModule, r as CrowdTestModuleOptions, K as DENSE_WALL, x as createCrowdTestModule, z as crowdBenchTextOf } from './testing-sTAa84Ib.js';
|
|
2
|
+
import '@adatechnology/game-crowd';
|
|
3
|
+
import '@adatechnology/game-characters-three';
|
|
4
|
+
import '@adatechnology/game-contracts';
|
|
5
|
+
import '@adatechnology/game-player';
|
|
6
|
+
import 'three';
|
|
7
|
+
import '@adatechnology/game-characters';
|
package/dist/testing.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BUILTIN_SCENES,
|
|
3
|
+
CHAIN_LINE,
|
|
4
|
+
CROWD_AREA_ID,
|
|
5
|
+
CROWD_EFFECTS,
|
|
6
|
+
DENSE_WALL,
|
|
7
|
+
createCrowdTestModule,
|
|
8
|
+
crowdBenchTextOf
|
|
9
|
+
} from "./chunk-PXT6DYGJ.js";
|
|
10
|
+
export {
|
|
11
|
+
BUILTIN_SCENES,
|
|
12
|
+
CHAIN_LINE,
|
|
13
|
+
CROWD_AREA_ID,
|
|
14
|
+
CROWD_EFFECTS,
|
|
15
|
+
DENSE_WALL,
|
|
16
|
+
createCrowdTestModule,
|
|
17
|
+
crowdBenchTextOf
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=testing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adatechnology/game-crowd-three",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "three.js drawing for @adatechnology/game-crowd: every agent, body on the ground and civilian as instances (a literal port of the team game's hordeRender and npcRender: view culling, LOD with hysteresis, attack pose, the pose by state), the renderer on the baked variants of game-characters-three, the herd on the animals' own rigs, the crowd's sound bank and the crowd test area.",
|
|
6
6
|
"keywords": [
|
|
@@ -32,18 +32,23 @@
|
|
|
32
32
|
"types": "./dist/index.d.ts",
|
|
33
33
|
"import": "./dist/index.js"
|
|
34
34
|
},
|
|
35
|
+
"./testing": {
|
|
36
|
+
"types": "./dist/testing.d.ts",
|
|
37
|
+
"import": "./dist/testing.js"
|
|
38
|
+
},
|
|
35
39
|
"./global": "./dist/index.global.js"
|
|
36
40
|
},
|
|
37
41
|
"files": [
|
|
38
42
|
"dist"
|
|
39
43
|
],
|
|
40
44
|
"dependencies": {
|
|
41
|
-
"@adatechnology/game-
|
|
42
|
-
"@adatechnology/game-
|
|
43
|
-
"@adatechnology/game-characters-three": "^0.
|
|
44
|
-
"@adatechnology/game-contracts": "^0.
|
|
45
|
-
"@adatechnology/game-crowd": "^0.
|
|
46
|
-
"@adatechnology/game-player": "^0.
|
|
45
|
+
"@adatechnology/game-audio": "^0.4.0",
|
|
46
|
+
"@adatechnology/game-characters": "^0.2.8",
|
|
47
|
+
"@adatechnology/game-characters-three": "^0.8.0",
|
|
48
|
+
"@adatechnology/game-contracts": "^0.22.0",
|
|
49
|
+
"@adatechnology/game-crowd": "^0.3.0",
|
|
50
|
+
"@adatechnology/game-player": "^0.5.0",
|
|
51
|
+
"@adatechnology/game-shapes-three": "^0.3.0"
|
|
47
52
|
},
|
|
48
53
|
"peerDependencies": {
|
|
49
54
|
"three": "^0.160.0"
|
|
@@ -57,9 +62,9 @@
|
|
|
57
62
|
"typescript": "^5.7.3",
|
|
58
63
|
"vitest": "^3.2.4",
|
|
59
64
|
"@adatechnology/game-animals": "^0.1.0",
|
|
60
|
-
"@adatechnology/game-animals-three": "^0.3.6",
|
|
61
65
|
"@adatechnology/game-animals-species": "^0.1.0",
|
|
62
|
-
"@adatechnology/game-
|
|
66
|
+
"@adatechnology/game-animals-three": "^0.4.0",
|
|
67
|
+
"@adatechnology/game-characters-undead": "^0.3.0",
|
|
63
68
|
"@adatechnology/game-infection": "^0.1.0",
|
|
64
69
|
"@adatechnology/golden-tool": "^0.0.0"
|
|
65
70
|
},
|