1 #include <bz/game/scene_internal.h>
3 #include <bz/collision/particle_collision.h>
4 //#include <bz/fx/agent_simulation.h>
5 #include <bz/fx/particle_simulation.h>
6 #include <bz/fx/particle_system.h>
7 #include <bz/game/actor_internal.h>
8 #include <bz/game/tilemap.h>
9 #include <bz/gfx/aseprite.h>
10 #include <bz/gfx/font_internal.h>
11 #include <bz/gfx/gfx_internal.h>
12 #include <bz/gfx/particle_drawing.h>
13 #include <bz/math/math.h>
14 #include <bz/memory/allocator.h>
15 #include <bz/resources/resource.h>
16 #include <bz/scripting/bindings_internal.h>
17 #include <bz/scripting/script.h>
18 #include <bz/types/identifier_internal.h>
20 #include <string.h> // strncpy
22 struct BZSceneActorDefinition
{
23 //char identifier[kBZMaxIdentifierLength]; // fixme
24 BZIdentifierHash identifierHash
;
30 typedef struct BZSceneActorDefinition BZSceneActorDefinition
;
32 /*struct BZSceneParticleSystem {
33 char identifier[kBZMaxIdentifierLength]; // fixme
34 BZIdentifierHash identifierHash;
35 BZParticleSystemID particleSystem;
37 typedef struct BZSceneParticleSystem BZSceneParticleSystem;*/
40 char identifier
[kBZMaxIdentifierLength
]; // fixme
41 BZIdentifierHash identifierHash
;
42 BZDrawQueueID drawQueue
;
44 BZParticleSimulationID particleSimulation
;
45 BZCollisionSpaceID collisionSpace
;
46 BZIdentifierHash particleCollisionTagHash
;
47 float particleCollisionRadiusMultiplier
;
51 ////#define kMaxActorInstances 50//256
55 BZScriptBindingMetadata scriptMetadata
;
59 typedef struct BZSceneActor BZSceneActor
;
61 #define kBZScriptingEnvironmentPublicCount 256
62 #define kBZScriptingEnvironmentEventCount 256
64 struct BZScriptingEnvironmentPublic
{
65 BZIdentifierHash identifierHash
;
68 typedef struct BZScriptingEnvironmentPublic BZScriptingEnvironmentPublic
;
71 BZIdentifierHash identifierHash
;
72 BZSceneEventData data
;
74 typedef struct BZSceneEvent BZSceneEvent
;
77 // BZScriptingEnvironmentID sceneEnvironment;
78 // BZScriptID sceneScript;
79 // BZScriptBindingMetadata sceneScriptMetadata;
80 // BZScriptInstanceID sceneScriptInstance;
81 BZSceneActorDefinition
*actorDefinitions
;
82 size_t actorDefinitionCount
;
87 int32_t minActorPriority
;
88 int32_t maxActorPriority
;
90 size_t lastActorIndex
;
91 size_t actorInstanceCount
;
92 BZSceneActor
*actorInstances
;
94 BZScriptingEnvironmentPublic publics
[kBZScriptingEnvironmentPublicCount
];
96 BZAudioPlaybackEngineID audioEngine
;
98 // BZAgentSimulationID agentSimulation;
101 BZSceneEvent
*currentEvents
;
102 size_t nextEnqueuedEvent
;
103 BZSceneEvent
*enqueuedEvents
;
105 // char targetSceneIdentifier[kBZMaxIdentifierLength]; // fixme
108 uint8_t gSystemTicksPerSecond
;
110 static void bzGameSceneActorLoadDefinition(BZSceneActorDefinition
*definitionOut
, BZSceneID scene
, BZMemoryArenaID arena
, const char *identifierFmt
, ...) {
111 bzMakeIdentifier(identifier
, identifierFmt
);
112 definitionOut
->identifierHash
= bzIdentifierHashFromIdentifier(identifier
);
114 BZResourceID handle
= bzResourcesOpenResource("scene", "assets/actors/%s.actor.json", identifier
);
115 bzAssertMessage(handle
!= NULL
, "Invalid actor definition '%s'", identifier
);
117 size_t length
= bzResourcesFileLength(handle
);
118 char *data
= alloca(length
);//(char *)bzMemoryAlloc(kBZSystemMemoryArena, length);//alloca(length); // FIXME, need working space off the stack
119 bzResourcesReadBytes(handle
, data
, length
);
120 bzResourcesCloseResource(handle
);
122 //json_set_allocation_functions
123 JSON_Value
*actorDefinitionJson
= json_parse_string(data
);
124 JSON_Object
*actorDefinitionJsonObject
= json_object(actorDefinitionJson
);
126 const char *scriptName
= json_object_get_string(actorDefinitionJsonObject
, "script");
127 if (scriptName
!= NULL
) {
128 definitionOut
->module
= bzScriptingLoadScriptModule(arena
, "%s", scriptName
);
129 definitionOut
->instanceSize
= svmGetModuleInstanceSize(definitionOut
->module
);
132 definitionOut
->priority
= json_object_get_number(actorDefinitionJsonObject
, "priority");
133 scene
->minActorPriority
= bzMin(scene
->minActorPriority
, definitionOut
->priority
);
134 scene
->maxActorPriority
= bzMax(scene
->maxActorPriority
, definitionOut
->priority
);
136 json_value_free(actorDefinitionJson
);
138 bzLog("Opened actor %s", identifier
);
141 static BZActorID
bzGameSceneSetupActor(BZSceneActor
*sceneActor
, BZSceneID scene
, const BZSceneActorDefinition
*definition
, const char *identifierFmt
, ...) {
142 BZActorID actor
= &sceneActor
->actor
;
143 BZScriptBindingMetadata
*metadata
= &sceneActor
->scriptMetadata
;
145 bzInsertIdentifier(actor
->identifier
, identifierFmt
);
146 actor
->identifierHash
= bzIdentifierHashFromIdentifier(actor
->identifier
);
148 bzAssertMessage(definition
!= NULL
, "Could not find definition for '%s'", actor
->identifier
);
150 sceneActor
->priority
= definition
->priority
;
152 actor
->instance
= svnResetModuleInstanceMemory(definition
->module
, actor
->instance
, metadata
, bzScriptingBindingsLookupNativeFunction
);
153 bzScriptingInitialiseMetadata((BZScriptBindingMetadata
*)&sceneActor
->scriptMetadata
, actor
, scene
, scene
->lastActorIndex
);
155 sceneActor
->running
= true;
160 BZSceneID
bzGameSceneSwitch(BZMemoryArenaID arena
, BZAudioPlaybackEngineID audioEngine
, const char *identifierFmt
, ...) {
161 bzMakeIdentifier(identifier
, identifierFmt
);
163 BZSceneID scene
= bzMemoryAlloc(arena
, sizeof(BZScene
));
165 BZResourceID handle
= bzResourcesOpenResource("scene", "assets/scenes/%s.scene.json", identifier
);
166 size_t length
= bzResourcesFileLength(handle
);
167 char *data
= alloca(length
);//(char *)bzMemoryAlloc(kBZSystemMemoryArena, length);//alloca(length); // FIXME, need working space off the stack
168 bzResourcesReadBytes(handle
, data
, length
);
169 bzResourcesCloseResource(handle
);
171 //json_set_allocation_functions
172 JSON_Value
*sceneJson
= json_parse_string(data
);
173 JSON_Object
*sceneJsonObject
= json_object(sceneJson
);
175 const char *soundbankName
= json_object_get_string(sceneJsonObject
, "soundbank");
176 if (soundbankName
!= NULL
&& audioEngine
!= NULL
) {
177 scene
->audioEngine
= audioEngine
;
178 bzAudioPlaybackUseSoundbank(scene
->audioEngine
, arena
, soundbankName
);
181 const char *spritesheetName
= json_object_get_string(sceneJsonObject
, "spritesheet");
182 if (spritesheetName
!= NULL
) {
183 size_t imageFrames
, imageWidth
, imageHeight
;
184 void *imageData
= bzGfxLoadAsepriteImage(arena
, &imageFrames
, &imageWidth
, &imageHeight
, spritesheetName
); // FIXME, temp arena
185 bzGfxPrepareSpritesheet(arena
, imageFrames
, imageWidth
, imageHeight
, imageData
);
189 const char *fontName
= json_object_get_string(sceneJsonObject
, "font");
190 if (fontName
!= NULL
) {
191 BZFont
*font
= bzGfxLoadFont(arena
, fontName
); // FIXME, temp arena??
192 bzGfxPrepareFont(arena
, font
);
195 JSON_Array
*actorDefinitionsArray
= json_object_get_array(sceneJsonObject
, "actors");
196 size_t actorDefinitionsArrayCount
= json_array_get_count(actorDefinitionsArray
);
197 scene
->actorDefinitionCount
= actorDefinitionsArrayCount
;
199 size_t startDefinition
= 0;
200 const char *sceneActorName
= json_object_get_string(sceneJsonObject
, "scene_actor");
201 if (sceneActorName
!= NULL
) {
202 scene
->actorDefinitionCount
+= 1;
206 scene
->actorDefinitions
= (BZSceneActorDefinition
*)bzMemoryAlloc(arena
, scene
->actorDefinitionCount
* sizeof(BZSceneActorDefinition
));
208 size_t maxInstanceSize
= 0;
210 if (sceneActorName
!= NULL
) {
211 bzGameSceneActorLoadDefinition(&scene
->actorDefinitions
[0], scene
, arena
, "%s", sceneActorName
); // fixme
212 maxInstanceSize
= scene
->actorDefinitions
[0].instanceSize
;
215 for (size_t i
= 0; i
< actorDefinitionsArrayCount
; ++i
) {
216 const char *actorName
= json_array_get_string(actorDefinitionsArray
, i
);
217 size_t outIdx
= i
+ startDefinition
;
218 bzGameSceneActorLoadDefinition(&scene
->actorDefinitions
[outIdx
], scene
, arena
, "%s", actorName
); // fixme
219 maxInstanceSize
= bzMax(maxInstanceSize
, scene
->actorDefinitions
[outIdx
].instanceSize
);
222 // FIXME, alignment for instance size
224 scene
->lastActorIndex
= 0;
225 scene
->actorInstanceCount
= 1024;
227 scene
->actorInstances
= (BZSceneActor
*)bzMemoryAlloc(arena
, scene
->actorInstanceCount
* sizeof(BZSceneActor
));
228 for (size_t i
= 0; i
< scene
->actorInstanceCount
; ++i
) {
229 scene
->actorInstances
[i
].actor
.instance
= bzMemoryAlloc(arena
, maxInstanceSize
);
232 if (sceneActorName
!= NULL
) {
233 bzGameSceneSetupActor(&scene
->actorInstances
[0], scene
, &scene
->actorDefinitions
[0], "scene");
236 // int hasAgents = json_object_get_boolean(sceneJsonObject, "agents");
237 // if (hasAgents > 0) {
238 // scene->agentSimulation = bzFXCreateAgentSimulation(arena, scene->actorInstanceCount, "%s.agents", identifier);
241 JSON_Array
*layerDefinitionsArray
= json_object_get_array(sceneJsonObject
, "layers");
242 scene
->layerCount
= json_array_get_count(layerDefinitionsArray
);
243 scene
->layers
= bzMemoryAlloc(arena
, scene
->layerCount
* sizeof(BZSceneLayer
));
244 for (size_t i
= 0; i
< scene
->layerCount
; ++i
) {
245 JSON_Object
*layerDefinition
= json_array_get_object(layerDefinitionsArray
, i
);
246 stbsp_snprintf(scene
->layers
[i
].identifier
, kBZMaxIdentifierLength
, "%s", json_object_get_string(layerDefinition
, "identifier"));
247 scene
->layers
[i
].identifierHash
= bzIdentifierHashFromIdentifier(scene
->layers
[i
].identifier
);
249 const char *particleSystemName
= json_object_get_string(layerDefinition
, "particles");
250 if (particleSystemName
!= NULL
) {
251 BZParticleSystemID particleSystem
= bzFXLoadParticleSystem(arena
, "%s", particleSystemName
); // FIXME, pool these...
252 int hasCollision2
= json_object_get_boolean(layerDefinition
, "collision"); // FIXME
253 scene
->layers
[i
].particleSimulation
= bzFXCreateParticleSimulation(arena
, (hasCollision2
> 0) ? 1024 : (5 * 1024), particleSystem
, "%s.particles", scene
->layers
[i
].identifier
); // FIXME, memory
256 if (json_object_has_value_of_type(layerDefinition
, "output", JSONNumber
)) {
257 scene
->layers
[i
].outputBuffer
= (int)json_object_get_number(layerDefinition
, "output");
258 if (particleSystemName
== NULL
|| json_object_get_boolean(layerDefinition
, "custom-particle") > 0) {
259 scene
->layers
[i
].drawQueue
= bzGfxDrawQueueCreate(arena
, "scene.%s.drawQueue", scene
->layers
[i
].identifier
);
263 const char *tilemapName
= json_object_get_string(layerDefinition
, "tilemap");
264 if (tilemapName
!= NULL
) {
265 scene
->layers
[i
].tilemap
= bzGameLoadTilemap(arena
, "%s", tilemapName
);
268 int hasCollision
= json_object_get_boolean(layerDefinition
, "collision");
269 if (hasCollision
> 0) {
270 if (scene
->layers
[i
].particleSimulation
== NULL
) {
271 scene
->layers
[i
].collisionSpace
= bzCollisionMakeSpace(arena
, scene
->actorInstanceCount
, "%s.collision", scene
->layers
[i
].identifier
);
273 scene
->layers
[i
].collisionSpace
= bzCollisionMakeSpace(arena
, 1024, "%s.particle.collision", scene
->layers
[i
].identifier
);
275 if (json_object_has_value_of_type(layerDefinition
, "collision-radius", JSONNumber
)) {
276 scene
->layers
[i
].particleCollisionRadiusMultiplier
= json_object_get_number(layerDefinition
, "collision-radius");
278 scene
->layers
[i
].particleCollisionRadiusMultiplier
= 1.0f
;
280 scene
->layers
[i
].particleCollisionTagHash
= bzIdentifierHashFromIdentifier(particleSystemName
);
285 scene
->currentEvents
= bzMemoryAlloc(arena
, kBZScriptingEnvironmentEventCount
* sizeof(BZSceneEvent
));
286 scene
->enqueuedEvents
= bzMemoryAlloc(arena
, kBZScriptingEnvironmentEventCount
* sizeof(BZSceneEvent
));
288 json_value_free(sceneJson
);
290 bzLog("Opened scene %s", identifier
);
295 bool bzGameSceneUpdate(BZSceneID scene
, uint8_t pauseFlags
, uint8_t systemTicks
) {
296 float deltaTime
= (float)systemTicks
/ (float)gSystemTicksPerSecond
;
298 for (size_t i
= 0; i
< scene
->layerCount
; ++i
) {
299 BZSceneLayer
*layer
= &scene
->layers
[i
];
300 if (layer
->particleSimulation
== NULL
) {
301 bzGfxDrawQueueClear(layer
->drawQueue
);
303 if (layer
->collisionSpace
!= NULL
) {
304 bzCollisionResetSpace(layer
->collisionSpace
);
308 // if (scene->agentSimulation != NULL) {
309 // SVMOperand playerX;
310 // bzScriptingGetEnvironmentPublic(&playerX, scene, bzIdentifierHashFromIdentifier("shipX"));
312 // SVMOperand playerY;
313 // bzScriptingGetEnvironmentPublic(&playerY, scene, bzIdentifierHashFromIdentifier("shipY"));
315 // BZVector playerPos = bzVectorMake(FIXED_TO_FLOAT(playerX.floatLiteral), FIXED_TO_FLOAT(playerY.floatLiteral));
317 // bzFXUpdateAgentSimulation(scene->agentSimulation, deltaTime, NULL, &playerPos);
320 for (size_t i
= 0; i
< scene
->layerCount
; ++i
) {
321 BZSceneLayer
*layer
= &scene
->layers
[i
];
322 if (layer
->particleSimulation
!= NULL
) {
323 bzFXUpdateParticleSystem(layer
->particleSimulation
, deltaTime
);
324 if (layer
->collisionSpace
!= NULL
) {
325 bzCollisionPopulateParticles(layer
->collisionSpace
, layer
->particleSimulation
, layer
->particleCollisionTagHash
, layer
->particleCollisionRadiusMultiplier
);
330 for (int32_t priority
= scene
->minActorPriority
; priority
<= scene
->maxActorPriority
; ++priority
) {
331 for (size_t i
= 0; i
< scene
->actorInstanceCount
; ++i
) {
332 BZSceneActor
*sceneActor
= &scene
->actorInstances
[i
];
333 if (sceneActor
->running
&& sceneActor
->priority
== priority
) {
334 SVMRunOutcome outcome
= svmRunModuleInstance(sceneActor
->actor
.instance
);
335 sceneActor
->running
= (outcome
== SVMRunOutcomeSuspended
);
340 scene
->ticks
+= systemTicks
;
342 scene
->eventCount
= scene
->nextEnqueuedEvent
;
343 scene
->nextEnqueuedEvent
= 0;
345 BZSceneEvent
*tmp
= scene
->currentEvents
;
346 scene
->currentEvents
= scene
->enqueuedEvents
;
347 scene
->enqueuedEvents
= tmp
;
349 return scene
->actorInstances
[0].running
;
352 void bzGameSceneDraw(BZSceneID scene
) {
353 for (size_t i
= 0; i
< scene
->layerCount
; ++i
) {
354 bzSetOutputBuffer(scene
->layers
[i
].outputBuffer
);
355 if (scene
->layers
[i
].particleSimulation
!= NULL
) {
356 bzGfxDrawParticles(scene
->layers
[i
].particleSimulation
, scene
->layers
[i
].drawQueue
);
358 bzGfxDrawQueueRun(scene
->layers
[i
].drawQueue
);
361 //if (scene->layers[i].collisionSpace != NULL) {
362 // bzCollisionDrawDebug(scene->layers[i].collisionSpace);
365 // if (i == 3 && scene->agentSimulation != NULL) { // FIXME
366 // bzFXAgentSimulationDrawDebug(scene->agentSimulation);
373 BZActorID
bzGameSceneAddActor(BZSceneID scene
, const char *identifierFmt
, ...) {
374 bzMakeIdentifier(identifier
, identifierFmt
);
376 BZIdentifierHash definitionIdentifierHash
= bzIdentifierHashFromIdentifier(identifier
);
377 BZSceneActorDefinition
*definition
= NULL
;
378 for (size_t i
= 0; i
< scene
->actorDefinitionCount
; ++i
) { // fixme
379 if (definitionIdentifierHash
== scene
->actorDefinitions
[i
].identifierHash
) {
380 definition
= &scene
->actorDefinitions
[i
];
384 bzAssertMessage(definition
!= NULL
, "Undefined actor '%s'", identifier
);
386 BZSceneActor
*sceneActor
= NULL
;
387 for (size_t i
= 0; i
< scene
->actorInstanceCount
; ++i
) {
388 ++scene
->lastActorIndex
;
390 size_t idx
= (scene
->lastActorIndex
% (scene
->actorInstanceCount
- 1)) + 1; // 0 is only for the scene script
391 if (scene
->actorInstances
[idx
].running
== false) {
392 sceneActor
= &scene
->actorInstances
[idx
];
396 bzAssertMessage(sceneActor
!= NULL
, "Out of actors");
398 definition
->spawnCount
+= 1;
400 return bzGameSceneSetupActor(sceneActor
, scene
, definition
, "%s-%u", identifier
, definition
->spawnCount
);
403 BZActorID
bzGameSceneFindActor(BZSceneID scene
, const char *identifierFmt
, ...) {
404 bzMakeIdentifier(identifier
, identifierFmt
);
405 BZIdentifierHash identifierHash
= bzIdentifierHashFromIdentifier(identifier
);
406 for (size_t i
= 0; i
< scene
->actorInstanceCount
; ++i
) { // fixme
407 if (scene
->actorInstances
[i
].actor
.identifierHash
== identifierHash
) {
408 return &scene
->actorInstances
[i
].actor
;
414 float bzGameSceneGetTime(BZSceneID scene
) {
415 float time
= (float)scene
->ticks
/ (float)gSystemTicksPerSecond
;
419 bool bzGameSceneQueryEvent(BZSceneEventData
*dataOut
, BZSceneID scene
, BZIdentifierHash eventIdentifier
) {
420 for (size_t i
= 0; i
< scene
->eventCount
; ++i
) {
421 BZSceneEvent
*event
= &scene
->currentEvents
[i
];
422 if (event
->identifierHash
== eventIdentifier
) {
423 if (dataOut
!= NULL
) {
424 *dataOut
= event
->data
;
432 void bzGameScenePostEvent(BZSceneID scene
, BZIdentifierHash eventIdentifier
, const BZSceneEventData
*data
) {
433 bzAssert(scene
->nextEnqueuedEvent
< kBZScriptingEnvironmentEventCount
);
434 BZSceneEvent
*event
= &scene
->enqueuedEvents
[scene
->nextEnqueuedEvent
++];
435 event
->identifierHash
= eventIdentifier
;
441 BZSceneLayer
*getLayer(BZSceneID scene
, BZIdentifierHash layerIdentifierHash
) {
442 for (size_t i
= 0; i
< scene
->layerCount
; ++i
) {
443 if (scene
->layers
[i
].identifierHash
== layerIdentifierHash
) {
444 return &scene
->layers
[i
];
450 BZTilemapID
bzGameGetSceneLayerTilemap(BZSceneID scene
, BZIdentifierHash layerIdentifierHash
) {
451 BZSceneLayer
*layer
= getLayer(scene
, layerIdentifierHash
);
453 return layer
->tilemap
;
459 BZDrawQueueID
bzGameGetSceneLayerDrawQueue(BZSceneID scene
, BZIdentifierHash layerIdentifierHash
) {
460 BZSceneLayer
*layer
= getLayer(scene
, layerIdentifierHash
);
462 return layer
->drawQueue
;
468 BZParticleSimulationID
bzGameGetSceneLayerParticleSimulation(BZSceneID scene
, BZIdentifierHash layerIdentifierHash
) {
469 BZSceneLayer
*layer
= getLayer(scene
, layerIdentifierHash
);
471 return layer
->particleSimulation
;
477 BZCollisionSpaceID
bzGameGetSceneLayerCollisionSpace(BZSceneID scene
, BZIdentifierHash layerIdentifierHash
) {
478 BZSceneLayer
*layer
= getLayer(scene
, layerIdentifierHash
);
480 return layer
->collisionSpace
;
488 extern void bzGameSceneSetTimeTicksPerSecond(uint8_t tps);
489 extern void bzGameSceneSetTimePauseFlags(uint8_t timeIdx, uint8_t pauseFlags); // Pause timer on these flags
490 extern float bzGameSceneTime(uint8_t timeIdx);
492 void bzGameSceneSetTimeTicksPerSecond(uint8_t tps) {
496 void bzGameSceneSetTimePauseFlags(uint8_t timeIdx, uint8_t pauseFlags) {
497 times[timeIdx].pauseFlags = pauseFlags;
500 float bzGameSceneTime(uint8_t timeIdx) {
501 float time = (float)times[timeIdx].ticks / (float)sceneTPS;
506 //BZAgentSimulationID bzGameGetAgentSimulation(BZSceneID scene) {
507 // return scene->agentSimulation;
510 BZAudioPlaybackEngineID
bzGameGetAudioPlaybackEngine(BZSceneID scene
) {
511 return scene
->audioEngine
;
514 bool bzScriptingGetEnvironmentPublic(SVMOperand
*out
, BZSceneID scene
, BZIdentifierHash identifierHash
) {
515 for (size_t i
= 0; i
< kBZScriptingEnvironmentPublicCount
; ++i
) {
516 if (scene
->publics
[i
].identifierHash
== identifierHash
) {
518 out
->__raw
= scene
->publics
[i
].value
.__raw
;
526 void bzScriptingSetEnvironmentPublic(BZSceneID scene
, BZIdentifierHash identifierHash
, SVMOperand value
) {
527 for (size_t i
= 0; i
< kBZScriptingEnvironmentPublicCount
; ++i
) {
528 if (scene
->publics
[i
].identifierHash
== 0) {
529 scene
->publics
[i
].identifierHash
= identifierHash
;
531 if (scene
->publics
[i
].identifierHash
== identifierHash
) {
532 scene
->publics
[i
].value
.__raw
= value
.__raw
;
536 bzError("Out of globals!!");
539 size_t bzGameGetSceneLayerCount(BZSceneID scene
) {
540 return scene
->layerCount
;
543 BZSceneLayerID
bzGameGetSceneLayerAtIndex(BZSceneID scene
, size_t idx
) {
544 bzAssert(idx
< scene
->layerCount
);
545 return &scene
->layers
[idx
];
549 BZCollisionSpaceID
bzGameGetSceneLayerCollisionSpace2(BZSceneLayerID layer
) {
550 return layer
->collisionSpace
;
553 BZParticleSimulationID
bzGameGetSceneLayerParticleSimulation2(BZSceneLayerID layer
) {
554 return layer
->particleSimulation
;