1#include "Library/LiveActor/ActorInitUtil.h"
2
3#include <math/seadBoundBox.h>
4#include <nn/g3d/ModelObj.h>
5
6#include "Library/Action/ActorActionKeeper.h"
7#include "Library/Base/HashCodeUtil.h"
8#include "Library/Base/StringUtil.h"
9#include "Library/Camera/CameraDirector.h"
10#include "Library/Draw/GraphicsQualityController.h"
11#include "Library/Draw/GraphicsSystemInfo.h"
12#include "Library/Effect/EffectSystemInfo.h"
13#include "Library/Effect/PartsEffectGroup.h"
14#include "Library/Factory/Factory.h"
15#include "Library/HitSensor/HitSensorKeeper.h"
16#include "Library/HitSensor/SensorFunction.h"
17#include "Library/Light/ModelMaterialCategory.h"
18#include "Library/LiveActor/ActorActionFunction.h"
19#include "Library/LiveActor/ActorAnimFunction.h"
20#include "Library/LiveActor/ActorClippingFunction.h"
21#include "Library/LiveActor/ActorCollisionFunction.h"
22#include "Library/LiveActor/ActorFactory.h"
23#include "Library/LiveActor/ActorFlagFunction.h"
24#include "Library/LiveActor/ActorInitFunction.h"
25#include "Library/LiveActor/ActorInitInfo.h"
26#include "Library/LiveActor/ActorModelFunction.h"
27#include "Library/LiveActor/ActorPoseKeeper.h"
28#include "Library/LiveActor/ActorPoseUtil.h"
29#include "Library/LiveActor/ActorResourceFunction.h"
30#include "Library/LiveActor/ActorSensorFunction.h"
31#include "Library/LiveActor/ActorSensorUtil.h"
32#include "Library/LiveActor/LiveActor.h"
33#include "Library/LiveActor/LiveActorGroup.h"
34#include "Library/Model/ModelKeeper.h"
35#include "Library/Model/ModelLodCtrl.h"
36#include "Library/Model/ModelOcclusionQuery.h"
37#include "Library/Nerve/NerveAction.h"
38#include "Library/Nerve/NerveActionCtrl.h"
39#include "Library/Nerve/NerveKeeper.h"
40#include "Library/Obj/ActorDitherAnimator.h"
41#include "Library/Obj/FarDistanceDitherAnimator.h"
42#include "Library/Placement/PlacementFunction.h"
43#include "Library/Placement/PlacementInfo.h"
44#include "Library/Resource/Resource.h"
45#include "Library/Resource/ResourceHolder.h"
46#include "Library/Se/SeFunction.h"
47#include "Library/Shadow/ActorShadowUtil.h"
48#include "Library/Stage/StageSwitchUtil.h"
49#include "Library/Thread/FunctorV0M.h"
50#include "Library/Yaml/ByamlIter.h"
51#include "Library/Yaml/ByamlUtil.h"
52#include "Project/HitSensor/HitSensor.h"
53#include "Project/Item/ActorScoreKeeper.h"
54
55namespace al {
56
57using PoseKeeperCreatorFunction = void (*)(LiveActor*);
58
59const NameToCreator<PoseKeeperCreatorFunction> gActorPoseTable[] = {
60 {.name: "TRSV", .creationFunction: initActorPoseTRSV}, {.name: "TRMSV", .creationFunction: initActorPoseTRMSV}, {.name: "TRGMSV", .creationFunction: initActorPoseTRGMSV},
61 {.name: "TFSV", .creationFunction: initActorPoseTFSV}, {.name: "TFUSV", .creationFunction: initActorPoseTFUSV}, {.name: "TFGSV", .creationFunction: initActorPoseTFGSV},
62 {.name: "TQSV", .creationFunction: initActorPoseTQSV}, {.name: "TQGSV", .creationFunction: initActorPoseTQGSV}, {.name: "TQGMSV", .creationFunction: initActorPoseTQGMSV},
63};
64
65void initActor(LiveActor* actor, const ActorInitInfo& initInfo) {
66 initActorSuffix(actor, initInfo, suffix: nullptr);
67}
68
69__attribute__((always_inline)) bool initActorPoseKeeper(const char* pose, LiveActor* actor) {
70 if (!pose)
71 return false;
72 s32 poseId = -1;
73 for (s32 i = 0; i < 9; i++) {
74 if (isEqualString(str1: gActorPoseTable[i].name, str2: pose)) {
75 poseId = i;
76 break;
77 }
78 }
79 if (poseId != -1) {
80 gActorPoseTable[poseId].creationFunction(actor);
81 return true;
82 }
83 return false;
84}
85
86__attribute__((always_inline)) void initActorPose(LiveActor* actor, const ActorInitInfo& initInfo,
87 Resource* modelRes, const char* suffix) {
88 ByamlIter initPose;
89 if (!tryGetActorInitFileIter(&initPose, modelRes, "InitPose", suffix))
90 return;
91
92 const char* pose = nullptr;
93 if (!initPose.tryGetStringByKey(string: &pose, key: "Pose"))
94 return;
95
96 if (!initActorPoseKeeper(pose, actor))
97 return;
98
99 if (isEqualString(str1: pose, str2: "TFUSV") && tryGetByamlKeyBoolOrFalse(initPose, "IsFrontUp"))
100 ((ActorPoseKeeperTFUSV*)actor->getPoseKeeper())->setFrontUp(true);
101}
102
103__attribute__((always_inline)) void initActorScale(LiveActor* actor, const ActorInitInfo& initInfo,
104 Resource* modelRes, const char* suffix) {
105 ByamlIter initScale;
106 if (!tryGetActorInitFileIter(&initScale, modelRes, "InitScale", suffix))
107 return;
108
109 sead::Vector3f scale = {1.0f, 1.0f, 1.0f};
110 if (!tryGetByamlScale(&scale, initScale, "Scale"))
111 return;
112
113 const sead::Vector3f& prevScale = getScale(actor);
114 scale.x = scale.x * prevScale.x;
115 scale.y = scale.y * prevScale.y;
116 scale.z = scale.z * prevScale.z;
117 setScale(actor, scale);
118}
119
120__attribute__((always_inline)) ModelLodCtrl*
121initActorModelLodCtrl(LiveActor* actor, Resource* modelRes, const char* suffix) {
122 ByamlIter initLod;
123 if (!tryGetActorInitFileIter(&initLod, modelRes, "InitLod", suffix))
124 return nullptr;
125
126 sead::BoundBox3f modelBoundingBox;
127 s32 lodModelCount = 5;
128 if (isExistModel(actor)) {
129 lodModelCount = getLodModelCount(actor);
130 calcModelBoundingBox(&modelBoundingBox, actor);
131 }
132
133 ModelLodCtrl* modelLodCtrl = new ModelLodCtrl{
134 actor,
135 getTransPtr(actor),
136 actor->getBaseMtx(),
137 getScalePtr(actor),
138 modelBoundingBox,
139 lodModelCount,
140 };
141 modelLodCtrl->init(initLod);
142
143 return modelLodCtrl;
144}
145
146__attribute__((always_inline)) void initActorModel(LiveActor* actor, const ActorInitInfo& initInfo,
147 Resource* modelRes, ActorResource* actorResource,
148 const char* suffix) {
149 ByamlIter initModel;
150 if (!tryGetActorInitFileIter(&initModel, modelRes, "InitModel", suffix))
151 return;
152
153 s32 blendAnimMax = 1;
154 initModel.tryGetIntByKey(val: &blendAnimMax, key: "BlendAnimMax");
155 const char* displayRootJointName = nullptr;
156 initModel.tryGetStringByKey(string: &displayRootJointName, key: "DisplayRootJointName");
157
158 initActorModelKeeper(actor, initInfo, actorResource, blendAnimMax);
159 if (displayRootJointName != nullptr)
160 actor->getModelKeeper()->setDisplayRootJointMtxPtr(
161 getJointMtxPtr(actor, displayRootJointName));
162
163 bool isCreateUniqShader = false;
164 initModel.tryGetBoolByKey(val: &isCreateUniqShader, key: "IsCreateUniqShader");
165 if (isCreateUniqShader)
166 createUniqueShader(actor);
167
168 s32 partialAnimSlotNum = 0;
169 initModel.tryGetIntByKey(val: &partialAnimSlotNum, key: "PartialAnimSlotNum");
170 s32 partialAnimGroupNum = partialAnimSlotNum;
171 initModel.tryGetIntByKey(val: &partialAnimGroupNum, key: "PartialAnimGroupNum");
172 s32 partialAnimPartsListBufferSize = 16;
173 initModel.tryGetIntByKey(val: &partialAnimPartsListBufferSize, key: "PartialAnimPartsListBufferSize");
174 if (partialAnimGroupNum >= 1)
175 initPartialSklAnim(actor, partialAnimSlotNum, partialAnimGroupNum,
176 partialAnimPartsListBufferSize);
177
178 bool isFixedModel = false;
179 initModel.tryGetBoolByKey(val: &isFixedModel, key: "IsFixedModel");
180 if (isFixedModel)
181 setFixedModelFlag(actor);
182
183 bool isIgnoreUpdateOnDrawClipping = false;
184 initModel.tryGetBoolByKey(val: &isIgnoreUpdateOnDrawClipping, key: "IsIgnoreUpdateOnDrawClipping");
185 if (isIgnoreUpdateOnDrawClipping)
186 setIgnoreUpdateDrawClipping(actor, value: true);
187
188 ModelKeeper* modelKeeper = actor->getModelKeeper();
189
190 ModelLodCtrl* modelLodCtrl = initActorModelLodCtrl(actor, modelRes, suffix);
191 modelKeeper->setModelLodCtrl(modelLodCtrl);
192 if (modelLodCtrl)
193 initInfo.actorSceneInfo.graphicsSystemInfo->getModelLodAllCtrl()->registerLodCtrl(
194 modelLodCtrl);
195
196 MaterialCategoryKeeper* materialCategoryKeeper =
197 initInfo.actorSceneInfo.graphicsSystemInfo->getMaterialCategoryKeeper();
198 ModelMaterialCategory::tryCreate(modelKeeper->getModelCtrl(), modelRes, suffix,
199 materialCategoryKeeper);
200
201 GraphicsQualityInfo* graphicsQualityInfo =
202 initInfo.actorSceneInfo.graphicsSystemInfo->getGraphicsQualityController()
203 ->getGraphicsQualityInfo();
204 modelKeeper->getModelCtrl()->setGraphicsQualityInfo(graphicsQualityInfo);
205
206 ModelOcclusionQuery* modelOcclusionQuery =
207 ModelOcclusionQuery::tryCreate(actor, modelRes, suffix);
208 modelKeeper->getModelCtrl()->setModelOcclusionQuery(modelOcclusionQuery);
209
210 bool isCalcViewCore1 = false;
211 initModel.tryGetBoolByKey(val: &isCalcViewCore1, key: "IsCalcViewCore1");
212 if (isCalcViewCore1)
213 modelKeeper->getModelCtrl()->setCalcViewCore(1);
214
215 bool isCalcViewCore2 = false;
216 initModel.tryGetBoolByKey(val: &isCalcViewCore2, key: "IsCalcViewCore2");
217 if (isCalcViewCore2)
218 modelKeeper->getModelCtrl()->setCalcViewCore(2);
219}
220
221__attribute__((always_inline)) void initActorExecutor(LiveActor* actor,
222 const ActorInitInfo& initInfo,
223 Resource* modelRes, const char* suffix) {
224 ByamlIter initExecutor;
225 if (!tryGetActorInitFileIter(&initExecutor, modelRes, "InitExecutor", suffix)) {
226 ModelKeeper* modelKeeper = actor->getModelKeeper();
227 if (modelKeeper && modelKeeper->getModelCtrl()->getModelObj()->GetNumShapes())
228 initExecutorModelUpdate(actor, info: initInfo);
229 return;
230 }
231
232 const char* updaterCategoryName = nullptr;
233 const char* drawerCategoryName = nullptr;
234
235 ByamlIter iter;
236 if (initExecutor.tryGetIterByKey(iter: &iter, key: "Updater") && iter.isTypeArray()) {
237 ByamlIter entry;
238 s32 index = 0;
239 while (iter.tryGetIterByIndex(iter: &entry, index)) {
240 entry.tryGetStringByKey(string: &updaterCategoryName, key: "CategoryName");
241 initExecutorUpdate(actor, info: initInfo, updaterCategoryName);
242 index++;
243 }
244 }
245
246 if (initExecutor.tryGetIterByKey(iter: &iter, key: "Drawer")) {
247 ModelKeeper* modelKeeper = actor->getModelKeeper();
248 if (modelKeeper && modelKeeper->getModelCtrl()->getModelObj()->GetNumShapes())
249 initExecutorModelUpdate(actor, info: initInfo);
250
251 if (iter.isTypeArray()) {
252 ByamlIter entry;
253 s32 index = 0;
254 while (iter.tryGetIterByIndex(iter: &entry, index)) {
255 entry.tryGetStringByKey(string: &drawerCategoryName, key: "CategoryName");
256 initExecutorDraw(actor, info: initInfo, drawerCategoryName);
257 index++;
258 }
259 }
260 }
261}
262
263__attribute__((always_inline)) void initActorSensor(LiveActor* actor, const ActorInitInfo& initInfo,
264 Resource* modelRes, const char* suffix) {
265 ByamlIter initSensor;
266 if (!tryGetActorInitFileIter(&initSensor, modelRes, "InitSensor", suffix))
267 return;
268
269 s32 numSensors = initSensor.getSize();
270 if (numSensors <= 0)
271 return;
272
273 actor->initHitSensor(amount: numSensors);
274 for (s32 i = 0; i < numSensors; i++) {
275 ByamlIter sensor;
276 if (!initSensor.tryGetIterByIndex(iter: &sensor, index: i))
277 continue;
278
279 const char* sensorName = nullptr;
280 if (!sensor.tryGetStringByKey(string: &sensorName, key: "Name"))
281 continue;
282
283 const char* sensorType = nullptr;
284 if (!sensor.tryGetStringByKey(string: &sensorType, key: "Type"))
285 continue;
286
287 f32 radius = 0.0f;
288 sensor.tryGetFloatByKey(val: &radius, key: "Radius");
289
290 s32 maxCount = 8;
291 sensor.tryGetIntByKey(val: &maxCount, key: "MaxCount");
292
293 sead::Vector3f offset = sead::Vector3f::zero;
294 tryGetByamlV3f(&offset, sensor);
295
296 HitSensorType type = alSensorFunction::findSensorTypeByName(sensorType);
297 if (type == HitSensorType::CollisionParts)
298 maxCount = 0;
299
300 addHitSensor(actor, initInfo, sensorName, (u32)type, radius, maxCount, offset);
301
302 const char* joint = nullptr;
303 sensor.tryGetStringByKey(string: &joint, key: "Joint");
304 if (joint)
305 setHitSensorJointMtx(actor, sensorName, joint);
306 }
307}
308
309__attribute__((always_inline)) void initActorCollision(LiveActor* actor,
310 const ActorInitInfo& initInfo,
311 Resource* modelRes, const char* suffix) {
312 ByamlIter initCollision;
313 if (!tryGetActorInitFileIter(&initCollision, modelRes, "InitCollision", suffix))
314 return;
315
316 const char* name = nullptr;
317 initCollision.tryGetStringByKey(string: &name, key: "Name");
318 sead::FixedSafeString<256> unused;
319
320 if (name == nullptr)
321 name = getBaseName(name: modelRes->getArchiveName());
322
323 const char* sensorName = nullptr;
324 HitSensor* sensor = nullptr;
325 if (initCollision.tryGetStringByKey(string: &sensorName, key: "Sensor"))
326 sensor = getHitSensor(actor, sensorName);
327
328 const char* joint = nullptr;
329 initCollision.tryGetStringByKey(string: &joint, key: "Joint");
330 sead::Matrix34f* jointMtx = nullptr;
331 if (joint != nullptr)
332 jointMtx = getJointMtxPtr(actor, joint);
333
334 initActorCollisionWithResource(actor, modelRes, name, sensor, jointMtx, suffix);
335}
336
337__attribute__((always_inline)) void initActorCollider(LiveActor* actor,
338 const ActorInitInfo& initInfo,
339 Resource* modelRes, const char* suffix) {
340 ByamlIter initCollider;
341 if (!tryGetActorInitFileIter(&initCollider, modelRes, "InitCollider", suffix))
342 return;
343
344 f32 radius = 0.0f;
345 initCollider.tryGetFloatByKey(val: &radius, key: "Radius");
346
347 u32 planeNum = 0;
348 initCollider.tryGetUIntByKey(val: &planeNum, key: "PlaneNum");
349
350 sead::Vector3f offset = sead::Vector3f::zero;
351 tryGetByamlV3f(&offset, initCollider);
352
353 actor->initCollider(radius, offsetY: offset.y, allocatedHitInfo: planeNum);
354}
355
356__attribute__((always_inline)) void initActorEffect(LiveActor* actor, const ActorInitInfo& initInfo,
357 Resource* modelRes, const char* suffix) {
358 ByamlIter initEffect;
359 if (!tryGetActorInitFileIter(&initEffect, modelRes, "InitEffect", suffix))
360 return;
361
362 const char* name = nullptr;
363 if (!initEffect.tryGetStringByKey(string: &name, key: "Name"))
364 return;
365
366 initActorEffectKeeper(actor, initInfo, name);
367}
368
369__attribute__((always_inline)) void initActorSound(LiveActor* actor, const ActorInitInfo& initInfo,
370 Resource* modelRes, const char* suffix) {
371 ByamlIter initSound;
372 const char* seName = nullptr;
373 const char* bgmName = nullptr;
374 if (tryGetActorInitFileIter(&initSound, modelRes, "InitSound", suffix)) {
375 initSound.tryGetStringByKey(string: &seName, key: "Name");
376 } else if (tryGetActorInitFileIter(&initSound, modelRes, "InitAudio", suffix)) {
377 initSound.tryGetStringByKey(string: &seName, key: "SeUserName");
378 initSound.tryGetStringByKey(string: &bgmName, key: "BgmUserName");
379 } else
380 return;
381
382 if (seName != nullptr)
383 initActorSeKeeper(actor, initInfo, seName);
384 if (initSound.isExistKey(key: "BgmUserName"))
385 initActorBgmKeeper(actor, initInfo, bgmName);
386}
387
388__attribute__((always_inline)) void initActorRail(LiveActor* actor, const ActorInitInfo& initInfo) {
389 if (isExistRail(initInfo, linkName: "Rail"))
390 actor->initRailKeeper(info: initInfo, linkName: "Rail");
391}
392
393__attribute__((always_inline)) void initActorGroupClipping(LiveActor* actor,
394 const ActorInitInfo& initInfo,
395 const ByamlIter& initClipping) {
396 if (initClipping.isExistKey(key: "NoGroupClipping"))
397 return;
398
399 ByamlIter groupClipping;
400 if (!initClipping.tryGetIterByKey(iter: &groupClipping, key: "GroupClipping"))
401 return;
402
403 initGroupClipping(actor, initInfo);
404}
405
406__attribute__((always_inline)) void initActorClipping(LiveActor* actor,
407 const ActorInitInfo& initInfo,
408 Resource* modelRes, const char* suffix) {
409 ByamlIter initClipping;
410 if (!tryGetActorInitFileIter(&initClipping, modelRes, "InitClipping", suffix))
411 return;
412 initActorClipping(actor, initInfo);
413
414 bool invalidate = false;
415 initClipping.tryGetBoolByKey(val: &invalidate, key: "Invalidate");
416 if (invalidate)
417 invalidateClipping(actor);
418
419 f32 radius = 0.0f;
420 if (initClipping.tryGetFloatByKey(val: &radius, key: "Radius")) {
421 setClippingInfo(actor, radius, nullptr);
422 } else if (actor->getModelKeeper()) {
423 const sead::Vector3f& scale = getScale(actor);
424 f32 maxXY = sead::Mathf::max(a: sead::Mathf::abs(x: scale.x), b: sead::Mathf::abs(x: scale.y));
425 f32 maxXYZ = sead::Mathf::max(a: maxXY, b: sead::Mathf::abs(x: scale.z));
426
427 f32 radius = calcModelBoundingSphereRadius(actor) * maxXYZ;
428 setClippingInfo(actor, radius, nullptr);
429 }
430
431 sead::BoundBox3f obb;
432 if (tryGetByamlBox3f(&obb, initClipping, "Obb"))
433 setClippingObb(actor, boundingBox: obb);
434
435 f32 nearClipDistance = 0.0f;
436 if (initClipping.tryGetFloatByKey(val: &nearClipDistance, key: "NearClipDistance"))
437 setClippingNearDistance(actor, near: nearClipDistance);
438
439 initActorGroupClipping(actor, initInfo, initClipping);
440}
441
442__attribute__((always_inline)) void initActorShadowMask(LiveActor* actor,
443 const ActorInitInfo& initInfo,
444 Resource* modelRes, const char* suffix) {
445 bool usingDepthShadow = false;
446 tryGetArg(arg: &usingDepthShadow, initInfo, key: "UsingDepthShadow");
447 initDepthShadowMapCtrl(actor, modelRes, initInfo, suffix);
448
449 ByamlIter initShadowMask;
450 if (!tryGetActorInitFileIter(&initShadowMask, modelRes, "InitShadowMask", suffix))
451 return;
452
453 initShadowMaskCtrl(actor, initInfo, initShadowMask, "InitShadowMask");
454 if (usingDepthShadow)
455 invalidateShadowMaskIntensityAll(actor);
456}
457
458__attribute__((always_inline)) void initActorFlag(LiveActor* actor, const ActorInitInfo& initInfo,
459 Resource* modelRes, const char* suffix) {
460 ByamlIter initFlag;
461 if (!tryGetActorInitFileIter(&initFlag, modelRes, "InitFlag", suffix))
462 return;
463
464 ByamlIter tmp;
465 if (initFlag.tryGetIterByKey(iter: &tmp, key: "MaterialCode"))
466 validateMaterialCode(actor);
467 if (initFlag.tryGetIterByKey(iter: &tmp, key: "UpdatePuddleMaterial"))
468 validatePuddleMaterial(actor);
469}
470
471__attribute__((always_inline)) void initActorItem(LiveActor* actor, const ActorInitInfo& initInfo,
472 Resource* modelRes, const char* suffix) {
473 ByamlIter initItem;
474 if (!tryGetActorInitFileIter(&initItem, modelRes, "InitItem", suffix))
475 return;
476
477 initActorItemKeeper(actor, initInfo, initItem);
478}
479
480__attribute__((always_inline)) void initActorScore(LiveActor* actor, const ActorInitInfo& initInfo,
481 Resource* modelRes, const char* suffix) {
482 ByamlIter initScore;
483 if (!tryGetActorInitFileIter(&initScore, modelRes, "InitScore", suffix))
484 return;
485
486 actor->initScoreKeeper();
487 actor->getActorScoreKeeper()->init(iter: initScore);
488}
489
490__attribute__((always_inline)) void initActorAction(LiveActor* actor, const ActorInitInfo& initInfo,
491 Resource* modelRes,
492 ActorResource* actorResource,
493 const char* suffix) {
494 const char* archiveName = actorResource->getModelRes()->getArchiveName();
495 initActorActionKeeper(actor, actorResource, archiveName, suffix);
496
497 if (!actor->getModelKeeper())
498 return;
499
500 if (!tryStartAction(actor, actionName: archiveName)) {
501 ActorActionKeeper* actionKeeper = actor->getActorActionKeeper();
502 if (actionKeeper)
503 actionKeeper->startAction(actionName: archiveName);
504 }
505
506 ModelKeeper* modelKeeper = actor->getModelKeeper();
507 if (!modelKeeper)
508 return;
509
510 DitherAnimator* ditherAnimator = ActorDitherAnimator::tryCreate(actor, modelRes, suffix);
511 if (ditherAnimator) {
512 modelKeeper->setDitherAnimator(ditherAnimator);
513 return;
514 }
515
516 ditherAnimator = FarDistanceDitherAnimator::tryCreate(actor, modelRes, suffix);
517 if (ditherAnimator)
518 modelKeeper->setDitherAnimator(ditherAnimator);
519}
520
521void initActorImpl(LiveActor* actor, const ActorInitInfo& initInfo,
522 const sead::SafeString& folderName, const sead::SafeString& fileName,
523 const char* suffix) {
524 StringTmp<256> path = {"%s/%s", folderName.cstr(), fileName.cstr()};
525 ActorResource* actorResource =
526 findOrCreateActorResource(initInfo.actorResourceHolder, path.cstr(), suffix);
527 Resource* modelRes = actorResource->getModelRes();
528 if (actor->getSceneInfo() == nullptr)
529 initActorSceneInfo(actor, info: initInfo);
530
531 initActorPose(actor, initInfo, modelRes, suffix);
532 initActorSRT(actor, info: initInfo);
533 initActorScale(actor, initInfo, modelRes, suffix);
534 initActorModel(actor, initInfo, modelRes: actorResource->getModelRes(), actorResource, suffix);
535 initActorPrePassLightKeeper(actor, modelRes, initInfo, suffix);
536 initActorExecutor(actor, initInfo, modelRes, suffix);
537 initActorSensor(actor, initInfo, modelRes, suffix);
538 initActorCollision(actor, initInfo, modelRes, suffix);
539 initActorCollider(actor, initInfo, modelRes, suffix);
540 initActorEffect(actor, initInfo, modelRes, suffix);
541 initActorSound(actor, initInfo, modelRes, suffix);
542 initActorRail(actor, initInfo);
543 initStageSwitch(actor, initInfo);
544 initActorClipping(actor, initInfo, modelRes, suffix);
545 initActorOcclusionKeeper(actor, modelRes, initInfo, suffix);
546 initActorShadowMask(actor, initInfo, modelRes, suffix);
547 initActorFlag(actor, initInfo, modelRes, suffix);
548 initActorItem(actor, initInfo, modelRes, suffix);
549 initActorScore(actor, initInfo, modelRes, suffix);
550 initScreenPointKeeper(actor, modelRes, initInfo, suffix);
551 initHitReactionKeeper(actor, modelRes, suffix);
552 initActorParamHolder(actor, modelRes, suffix);
553 initActorAction(actor, initInfo, modelRes, actorResource, suffix);
554
555 if (actor->getNerveKeeper() && actor->getNerveKeeper()->getActionCtrl())
556 resetNerveActionForInit(actor);
557
558 if (!actor->getSubActorKeeper())
559 initSubActorKeeper(actor, initInfo, suffix, 0);
560}
561
562void initActorSuffix(LiveActor* actor, const ActorInitInfo& initInfo, const char* suffix) {
563 const char* objName = nullptr;
564 tryGetObjectName(name: &objName, initInfo);
565 initActorImpl(actor, initInfo, folderName: "ObjectData", fileName: objName, suffix);
566}
567
568void initActorChangeModel(LiveActor* actor, const ActorInitInfo& initInfo) {
569 initActorChangeModelSuffix(actor, initInfo, suffix: nullptr);
570}
571
572inline const char* getModelName(const ActorInitInfo& initInfo) {
573 const char* name = nullptr;
574 if (alPlacementFunction::tryGetModelName(modelName: &name, initInfo))
575 return name;
576 else if (tryGetObjectName(name: &name, initInfo))
577 return name;
578 return nullptr;
579}
580
581void initActorChangeModelSuffix(LiveActor* actor, const ActorInitInfo& initInfo,
582 const char* suffix) {
583 const char* file = getModelName(initInfo);
584 initActorImpl(actor, initInfo, folderName: "ObjectData", fileName: file, suffix);
585}
586
587void initActorWithArchiveName(LiveActor* actor, const ActorInitInfo& initInfo,
588 const sead::SafeString& archiveName, const char* suffix) {
589 initChildActorWithArchiveNameWithPlacementInfo(actor, initInfo, archiveName, suffix);
590}
591
592void initChildActorWithArchiveNameWithPlacementInfo(LiveActor* actor, const ActorInitInfo& initInfo,
593 const sead::SafeString& archiveName,
594 const char* suffix) {
595 initActorImpl(actor, initInfo, folderName: "ObjectData", fileName: archiveName.cstr(), suffix);
596}
597
598void initChildActorWithArchiveNameNoPlacementInfo(LiveActor* actor, const ActorInitInfo& initInfo,
599 const sead::SafeString& archiveName,
600 const char* suffix) {
601 PlacementInfo placementInfo;
602 ActorInitInfo childInitInfo;
603 childInitInfo.initViewIdHost(&placementInfo, initInfo);
604 initActorImpl(actor, initInfo: childInitInfo, folderName: "ObjectData", fileName: archiveName.cstr(), suffix);
605}
606
607LiveActor* createChildLinkSimpleActor(const char* actorName, const char* linkName,
608 const ActorInitInfo& initInfo, bool alive) {
609 ActorInitInfo childInitInfo;
610 PlacementInfo placementInfo;
611 getLinksInfoByIndex(linkPlacementInfo: &placementInfo, placementInfo: *initInfo.placementInfo, linkName, index: 0);
612 childInitInfo.initViewIdSelf(&placementInfo, initInfo);
613
614 LiveActor* actor = new LiveActor(actorName);
615 initActor(actor, initInfo: childInitInfo);
616
617 if (alive)
618 actor->makeActorAlive();
619 else
620 actor->makeActorDead();
621 return actor;
622}
623
624LiveActor* createChildLinkMapPartsActor(const char* actorName, const char* linkName,
625 const ActorInitInfo& initInfo, s32 linkIndex, bool alive) {
626 ActorInitInfo childInitInfo;
627 PlacementInfo placementInfo;
628 getLinksInfoByIndex(linkPlacementInfo: &placementInfo, placementInfo: *initInfo.placementInfo, linkName, index: linkIndex);
629 childInitInfo.initViewIdSelf(&placementInfo, initInfo);
630
631 LiveActor* actor = new LiveActor(actorName);
632 initMapPartsActor(actor, initInfo: childInitInfo, suffix: nullptr);
633
634 if (alive)
635 actor->makeActorAlive();
636 else
637 actor->makeActorDead();
638 return actor;
639}
640
641void initMapPartsActor(LiveActor* actor, const ActorInitInfo& initInfo, const char* suffix) {
642 const char* modelName;
643 sead::FixedSafeString<256> fileName;
644 sead::FixedSafeString<256> folderName;
645
646 const PlacementInfo& placementInfo = *initInfo.placementInfo;
647 modelName = nullptr;
648 if (alPlacementFunction::tryGetModelName(modelName: &modelName, placementInfo) &&
649 !isEqualString(str1: modelName, str2: "")) {
650 fileName = modelName;
651 folderName = "ObjectData";
652 } else {
653 tryGetStringArg(arg: &modelName, initInfo: placementInfo, key: "UnitConfigName");
654 fileName = modelName;
655 folderName = "ObjectData";
656 }
657
658 initActorImpl(actor, initInfo, folderName, fileName, suffix);
659}
660
661void initLinksActor(LiveActor* actor, const ActorInitInfo& initInfo, const char* suffix,
662 s32 linkIndex) {
663 ActorInitInfo childInitInfo;
664 PlacementInfo placementInfo;
665 getLinksInfoByIndex(linkPlacementInfo: &placementInfo, placementInfo: *initInfo.placementInfo, linkName: suffix, index: linkIndex);
666 childInitInfo.initViewIdSelf(&placementInfo, initInfo);
667 actor->init(info: childInitInfo);
668}
669
670ActorInitInfo* createLinksPlayerActorInfo(LiveActor* actor, const ActorInitInfo& initInfo) {
671 s32 startPosNum = calcLinkChildNum(initInfo, linkName: "PlayerRestartPos");
672 ActorInitInfo* result = new ActorInitInfo();
673 if (startPosNum == 1) {
674 PlacementInfo* placementInfo = new PlacementInfo();
675 getLinksInfoByIndex(linkPlacementInfo: placementInfo, placementInfo: *initInfo.placementInfo, linkName: "PlayerRestartPos", index: 0);
676 result->initViewIdSelf(placementInfo, initInfo);
677 }
678 return result;
679}
680
681const char* getLinksActorClassName(const ActorInitInfo& initInfo, const char* linkName,
682 s32 linkIndex) {
683 ActorInitInfo childInitInfo;
684 PlacementInfo placementInfo;
685
686 const char* className = nullptr;
687 getLinksInfoByIndex(linkPlacementInfo: &placementInfo, placementInfo: *initInfo.placementInfo, linkName, index: linkIndex);
688 childInitInfo.initViewIdSelf(&placementInfo, initInfo);
689 getClassName(name: &className, initInfo: childInitInfo);
690 return className;
691}
692
693const char* getLinksActorDisplayName(const ActorInitInfo& initInfo, const char* linkName,
694 s32 linkIndex) {
695 PlacementInfo placementInfo;
696 getLinksInfoByIndex(linkPlacementInfo: &placementInfo, placementInfo: *initInfo.placementInfo, linkName, index: linkIndex);
697 const char* displayName = nullptr;
698 getDisplayName(name: &displayName, placementInfo);
699 return displayName;
700}
701
702const char* getLinksActorObjectName(const ActorInitInfo& initInfo, const char* linkName,
703 s32 linkIndex) {
704 PlacementInfo placementInfo;
705 getLinksInfoByIndex(linkPlacementInfo: &placementInfo, placementInfo: *initInfo.placementInfo, linkName, index: linkIndex);
706 const char* objectName = nullptr;
707 getObjectName(name: &objectName, placementInfo);
708 return objectName;
709}
710
711void initCreateActorWithPlacementInfo(LiveActor* actor, const ActorInitInfo& initInfo) {
712 actor->init(info: initInfo);
713}
714
715void initCreateActorWithPlacementInfo(LiveActor* actor, const ActorInitInfo& initInfo,
716 const PlacementInfo& placementInfo) {
717 ActorInitInfo childInitInfo;
718 childInitInfo.initViewIdSelf(&placementInfo, initInfo);
719 actor->init(info: childInitInfo);
720}
721
722void initCreateActorNoPlacementInfo(LiveActor* actor, const ActorInitInfo& initInfo) {
723 PlacementInfo placementInfo;
724 ActorInitInfo childInitInfo;
725 childInitInfo.initViewIdSelf(&placementInfo, initInfo);
726 actor->init(info: childInitInfo);
727}
728
729void initCreateActorNoPlacementInfoNoViewId(LiveActor* actor, const ActorInitInfo& initInfo) {
730 PlacementInfo placementInfo;
731 ActorInitInfo childInitInfo;
732 childInitInfo.initNoViewId(&placementInfo, initInfo);
733 actor->init(info: childInitInfo);
734}
735
736__attribute__((always_inline)) LiveActor*
737createActorFromFactory(const ActorInitInfo& childInitInfo, const PlacementInfo* placementInfo) {
738 const ActorFactory* factory = childInitInfo.actorFactory;
739
740 const char* objectName = nullptr;
741 getObjectName(name: &objectName, initInfo: childInitInfo);
742 const char* className = nullptr;
743 getClassName(name: &className, initInfo: childInitInfo);
744
745 ActorCreatorFunction creationFunction = nullptr;
746 factory->getEntryIndex(creationPtr: &creationFunction, entryName: className);
747 if (creationFunction == nullptr)
748 return nullptr;
749
750 const char* displayName;
751 getDisplayName(name: &displayName, initInfo: childInitInfo);
752 LiveActor* actor = (*creationFunction)(displayName);
753 actor->init(info: childInitInfo);
754 return actor;
755}
756
757LiveActor* createPlacementActorFromFactory(const ActorInitInfo& initInfo,
758 const PlacementInfo* placementInfo) {
759 ActorInitInfo childInitInfo;
760 childInitInfo.initViewIdSelf(placementInfo, initInfo);
761 return createActorFromFactory(childInitInfo, placementInfo);
762}
763
764LiveActor* createLinksActorFromFactory(const ActorInitInfo& initInfo, const char* linkName,
765 s32 linkNum) {
766 ActorInitInfo childInitInfo;
767 PlacementInfo placementInfo;
768 getLinksInfoByIndex(linkPlacementInfo: &placementInfo, placementInfo: *initInfo.placementInfo, linkName, index: linkNum);
769 childInitInfo.initViewIdSelf(&placementInfo, initInfo);
770 return createActorFromFactory(childInitInfo, placementInfo: &placementInfo);
771}
772
773LiveActorGroup* createLinksActorGroupFromFactory(const ActorInitInfo& initInfo,
774 const char* linkName, const char* groupName) {
775 return tryCreateLinksActorGroupFromFactory(initInfo, linkName, groupName);
776}
777
778LiveActorGroup* tryCreateLinksActorGroupFromFactory(const ActorInitInfo& initInfo,
779 const char* linkName, const char* groupName) {
780 ActorInitInfo childInitInfo;
781 PlacementInfo placementInfo;
782 s32 linkChildNum = calcLinkChildNum(initInfo, linkName);
783 if (linkChildNum < 1)
784 return nullptr;
785
786 LiveActorGroup* group = new LiveActorGroup(groupName, linkChildNum);
787 for (s32 i = 0; i < linkChildNum; i++) {
788 getLinksInfoByIndex(linkPlacementInfo: &placementInfo, placementInfo: *initInfo.placementInfo, linkName, index: i);
789 childInitInfo.initViewIdSelf(&placementInfo, initInfo);
790 group->registerActor(createActorFromFactory(childInitInfo, placementInfo: &placementInfo));
791 }
792 return group;
793}
794
795LiveActor* tryCreateLinksActorFromFactorySingle(const ActorInitInfo& initInfo,
796 const char* linkName) {
797 if (calcLinkChildNum(initInfo, linkName) < 1)
798 return nullptr;
799 return createLinksActorFromFactory(initInfo, linkName, linkNum: 0);
800}
801
802// NON_MATCHING: Same as above
803void createAndRegisterLinksActorFromFactory(LiveActorGroup* group, const ActorInitInfo& initInfo,
804 const char* linkName) {
805 ActorInitInfo childInitInfo;
806 PlacementInfo placementInfo;
807 s32 linkChildNum = calcLinkChildNum(initInfo, linkName);
808 if (linkChildNum < 1)
809 return;
810
811 for (s32 i = 0; i < linkChildNum; i++) {
812 getLinksInfoByIndex(linkPlacementInfo: &placementInfo, placementInfo: *initInfo.placementInfo, linkName, index: i);
813 childInitInfo.initViewIdSelf(&placementInfo, initInfo);
814 group->registerActor(createActorFromFactory(childInitInfo, placementInfo: &placementInfo));
815 }
816}
817
818void makeMapPartsModelName(sead::BufferedSafeString* modelName, sead::BufferedSafeString* path,
819 const PlacementInfo& placementInfo) {
820 const char* archiveName = nullptr;
821 if (alPlacementFunction::tryGetModelName(modelName: &archiveName, placementInfo) &&
822 !isEqualString(str1: archiveName, str2: "")) {
823 modelName->copy(src: archiveName);
824 path->format(formatStr: "ObjectData/%s", archiveName);
825 } else {
826 tryGetStringArg(arg: &archiveName, initInfo: placementInfo, key: "UnitConfigName");
827 modelName->copy(src: archiveName);
828 path->format(formatStr: "ObjectData/%s", archiveName);
829 }
830}
831
832void makeMapPartsModelName(sead::BufferedSafeString* modelName, sead::BufferedSafeString* path,
833 const ActorInitInfo& initInfo) {
834 makeMapPartsModelName(modelName, path, placementInfo: *initInfo.placementInfo);
835}
836
837const char* tryGetMapPartsSuffix(const ActorInitInfo& initInfo, const char* suffix) {
838 StringTmp<64> name = {"InitActor%s", suffix};
839 if (!tryGetMapPartsResourceYaml(initInfo, name.cstr()))
840 return nullptr;
841 return suffix;
842}
843
844void initMapPartsActorWithArchiveName(LiveActor* actor, const ActorInitInfo& initInfo,
845 const char* fileName, const char* suffix) {
846 return initActorImpl(actor, initInfo, folderName: "MapPartsData", fileName, suffix);
847}
848
849void initNerve(LiveActor* actor, const Nerve* nerve, s32 maxStates) {
850 actor->initNerveKeeper(nerveKeeper: new NerveKeeper(actor, nerve, maxStates));
851}
852
853void initNerveAction(LiveActor* actor, const char* actionName,
854 alNerveFunction::NerveActionCollector* collector, s32 maxStates) {
855 auto* nerveActionCtrl = new NerveActionCtrl(collector);
856 initNerve(actor, nerve: nerveActionCtrl->findNerve(name: actionName), maxStates);
857 actor->getNerveKeeper()->initNerveAction(actionCtrl: nerveActionCtrl);
858 startNerveAction(actor, actionName);
859}
860
861bool trySyncStageSwitchAppear(LiveActor* actor) {
862 using LiveActorFunctor = FunctorV0M<LiveActor*, void (LiveActor::*)()>;
863
864 if (listenStageSwitchOnOffAppear(user: actor, actionOn: LiveActorFunctor{actor, &LiveActor::appear},
865 actionOff: LiveActorFunctor{actor, &LiveActor::kill})) {
866 actor->makeActorDead();
867 return true;
868 } else {
869 actor->makeActorAlive();
870 return false;
871 }
872}
873
874bool trySyncStageSwitchKill(LiveActor* actor) {
875 using LiveActorFunctor = FunctorV0M<LiveActor*, void (LiveActor::*)()>;
876
877 bool result = listenStageSwitchOnOffKill(user: actor, actionOn: LiveActorFunctor(actor, &LiveActor::kill),
878 actionOff: LiveActorFunctor(actor, &LiveActor::appear));
879 actor->makeActorAlive();
880
881 return result;
882}
883
884bool trySyncStageSwitchAppearAndKill(LiveActor* actor) {
885 if (trySyncStageSwitchAppear(actor))
886 return true;
887 return trySyncStageSwitchKill(actor);
888}
889
890bool tryListenStageSwitchAppear(LiveActor* actor) {
891 using LiveActorFunctor = FunctorV0M<LiveActor*, void (LiveActor::*)()>;
892
893 if (listenStageSwitchOnAppear(user: actor, action: LiveActorFunctor{actor, &LiveActor::appear})) {
894 actor->makeActorDead();
895 return true;
896 } else {
897 actor->makeActorAlive();
898 return false;
899 }
900}
901
902bool tryListenStageSwitchKill(LiveActor* actor) {
903 using LiveActorFunctor = FunctorV0M<LiveActor*, void (LiveActor::*)()>;
904
905 return listenStageSwitchOnKill(user: actor, action: LiveActorFunctor(actor, &LiveActor::kill));
906}
907
908void syncSensorScaleY(LiveActor* actor) {
909 f32 scaleY = getScale(actor).y;
910 for (s32 i = 0; i < actor->getHitSensorKeeper()->getSensorNum(); i++)
911 actor->getHitSensorKeeper()->getSensor(index: i)->scaleY(scaleY);
912}
913
914void syncSensorAndColliderScaleY(LiveActor* actor) {
915 syncSensorScaleY(actor);
916 f32 scaleY = getScale(actor).y;
917 setColliderRadius(actor, scaleY * getColliderRadius(actor));
918 setColliderOffsetY(actor, scaleY * getColliderOffsetY(actor));
919}
920
921void setMaterialCode(LiveActor* actor, const char* materialCode) {
922 if (actor->getEffectKeeper())
923 tryUpdateEffectMaterialCode(actor, materialCode);
924 if (isExistSeKeeper(actor))
925 tryUpdateSeMaterialCode(actor, materialCode);
926}
927
928void initMaterialCode(LiveActor* actor, const ActorInitInfo& initInfo) {
929 const char* materialCode = "";
930 if (tryGetStringArg(arg: &materialCode, initInfo, key: "MaterialCode"))
931 setMaterialCode(actor, materialCode);
932}
933
934bool tryAddDisplayRotate(LiveActor* actor, const ActorInitInfo& initInfo) {
935 sead::Vector3f rotate = {0.0f, 0.0f, 0.0f};
936 if (!tryGetDisplayRotate(rotate: &rotate, initInfo))
937 return false;
938
939 sead::Matrix34f rotateMtx;
940 rotateMtx.makeR(r: {sead::Mathf::deg2rad(deg: rotate.x), sead::Mathf::deg2rad(deg: rotate.y),
941 sead::Mathf::deg2rad(deg: rotate.z)});
942
943 sead::Matrix34f origMtx = sead::Matrix34f::ident;
944 makeMtxRT(mtx: &origMtx, actor);
945
946 origMtx = origMtx * rotateMtx;
947 updatePoseMtx(actor, mtx: &origMtx);
948 return true;
949}
950
951bool tryAddDisplayOffset(LiveActor* actor, const ActorInitInfo& initInfo) {
952 sead::Vector3f offset = {0.0f, 0.0f, 0.0f};
953 if (!tryGetDisplayOffset(offset: &offset, initInfo))
954 return false;
955
956 *getTransPtr(actor) += offset;
957 return true;
958}
959
960bool tryAddDisplayScale(LiveActor* actor, const ActorInitInfo& initInfo) {
961 sead::Vector3f scale = {0.0f, 0.0f, 0.0f};
962 if (!tryGetDisplayScale(scale: &scale, initInfo))
963 return false;
964
965 setScaleX(actor, x: getScale(actor).x * scale.x);
966 setScaleY(actor, y: getScale(actor).y * scale.y);
967 setScaleZ(actor, z: getScale(actor).z * scale.z);
968 return true;
969}
970
971const PlacementInfo& getPlacementInfo(const ActorInitInfo& initInfo) {
972 return *initInfo.placementInfo;
973}
974
975const LayoutInitInfo& getLayoutInitInfo(const ActorInitInfo& initInfo) {
976 return *initInfo.layoutInitInfo;
977}
978
979AudioDirector* getAudioDirector(const ActorInitInfo& initInfo) {
980 return initInfo.audioDirector;
981}
982
983CollisionDirector* getCollisionDirectorFromInfo(const ActorInitInfo& initInfo) {
984 return initInfo.actorSceneInfo.collisionDirector;
985}
986
987const SceneCameraInfo* getSceneCameraInfoFromInfo(const ActorInitInfo& initInfo) {
988 return initInfo.actorSceneInfo.cameraDirector->getSceneCameraInfo();
989}
990
991GraphicsSystemInfo* getGraphicsSystemInfo(const ActorInitInfo& initInfo) {
992 return initInfo.actorSceneInfo.graphicsSystemInfo;
993}
994
995agl::DrawContext* getDrawContext(const ActorInitInfo& initInfo) {
996 return initInfo.actorSceneInfo.graphicsSystemInfo->getDrawContext();
997}
998
999void getActorRecourseDataF32(f32* val, LiveActor* actor, const char* fileName,
1000 const char* entryName) {
1001 isExistModelResourceYaml(actor, fileName, nullptr);
1002 ByamlIter iter = {getModelResourceYaml(actor, fileName, nullptr)};
1003 tryGetByamlF32(val, iter, entryName);
1004}
1005
1006void getActorRecourseDataString(const char** val, LiveActor* actor, const char* fileName,
1007 const char* entryName) {
1008 isExistModelResourceYaml(actor, fileName, nullptr);
1009 ByamlIter iter = {getModelResourceYaml(actor, fileName, nullptr)};
1010 *val = getByamlKeyString(iter, entryName);
1011}
1012
1013void getActorRecourseDataV3f(sead::Vector3f* val, LiveActor* actor, const char* fileName,
1014 const char* entryName) {
1015 isExistModelResourceYaml(actor, fileName, nullptr);
1016 ByamlIter iter = {getModelResourceYaml(actor, fileName, nullptr)};
1017 if (entryName)
1018 tryGetByamlV3f(val, iter, entryName);
1019 else
1020 tryGetByamlV3f(val, iter);
1021}
1022
1023void getActorRecourseDataBox3f(sead::BoundBox3f* box, LiveActor* actor, const char* fileName,
1024 const char* entryName) {
1025 isExistModelResourceYaml(actor, fileName, nullptr);
1026 ByamlIter iter = {getModelResourceYaml(actor, fileName, nullptr)};
1027 if (entryName)
1028 tryGetByamlBox3f(box, iter, entryName);
1029 else
1030 tryGetByamlBox3f(box, iter);
1031}
1032
1033PartsEffectGroup* createPartsEffectGroup(LiveActor* actor, const ActorInitInfo& initInfo,
1034 s32 maxEffects) {
1035 const char* name;
1036 if (isExistModelResourceYaml(actor, "InitPartsEffect", nullptr))
1037 getActorRecourseDataString(val: &name, actor, fileName: "InitPartsEffect", entryName: "Name");
1038 else
1039 getActorRecourseDataString(val: &name, actor, fileName: "InitEffect", entryName: "Name");
1040
1041 PartsEffectGroup* group = new PartsEffectGroup();
1042 group->init(maxEffects, initInfo.effectSystemInfo, name, getTransPtr(actor),
1043 tryGetScalePtr(actor), actor->getBaseMtx(), actor);
1044 return group;
1045}
1046
1047} // namespace al
1048