#include "Library/LiveActor/ActorInitUtil.h" #include #include #include "Library/Action/ActorActionKeeper.h" #include "Library/Base/HashCodeUtil.h" #include "Library/Base/Macros.h" #include "Library/Base/StringUtil.h" #include "Library/Camera/CameraDirector.h" #include "Library/Draw/GraphicsQualityController.h" #include "Library/Draw/GraphicsSystemInfo.h" #include "Library/Effect/EffectSystemInfo.h" #include "Library/Effect/PartsEffectGroup.h" #include "Library/Factory/Factory.h" #include "Library/HitSensor/HitSensorKeeper.h" #include "Library/HitSensor/SensorFunction.h" #include "Library/Light/ModelMaterialCategory.h" #include "Library/LiveActor/ActorActionFunction.h" #include "Library/LiveActor/ActorAnimFunction.h" #include "Library/LiveActor/ActorClippingFunction.h" #include "Library/LiveActor/ActorCollisionFunction.h" #include "Library/LiveActor/ActorFactory.h" #include "Library/LiveActor/ActorFlagFunction.h" #include "Library/LiveActor/ActorInitFunction.h" #include "Library/LiveActor/ActorInitInfo.h" #include "Library/LiveActor/ActorModelFunction.h" #include "Library/LiveActor/ActorPoseKeeper.h" #include "Library/LiveActor/ActorPoseUtil.h" #include "Library/LiveActor/ActorResourceFunction.h" #include "Library/LiveActor/ActorSensorFunction.h" #include "Library/LiveActor/ActorSensorUtil.h" #include "Library/LiveActor/LiveActor.h" #include "Library/LiveActor/LiveActorGroup.h" #include "Library/Model/ModelKeeper.h" #include "Library/Model/ModelLodCtrl.h" #include "Library/Model/ModelOcclusionQuery.h" #include "Library/Nerve/NerveAction.h" #include "Library/Nerve/NerveActionCtrl.h" #include "Library/Nerve/NerveKeeper.h" #include "Library/Obj/ActorDitherAnimator.h" #include "Library/Obj/FarDistanceDitherAnimator.h" #include "Library/Placement/PlacementFunction.h" #include "Library/Placement/PlacementInfo.h" #include "Library/Resource/ActorResource.h" #include "Library/Resource/Resource.h" #include "Library/Resource/ResourceFunction.h" #include "Library/Se/SeFunction.h" #include "Library/Shadow/ActorShadowUtil.h" #include "Library/Stage/StageSwitchUtil.h" #include "Library/Thread/FunctorV0M.h" #include "Library/Yaml/ByamlIter.h" #include "Library/Yaml/ByamlUtil.h" #include "Project/HitSensor/HitSensor.h" #include "Project/Item/ActorScoreKeeper.h" namespace al { using PoseKeeperCreatorFunction = void (*)(LiveActor*); const NameToCreator gActorPoseTable[] = { {"TRSV", initActorPoseTRSV}, {"TRMSV", initActorPoseTRMSV}, {"TRGMSV", initActorPoseTRGMSV}, {"TFSV", initActorPoseTFSV}, {"TFUSV", initActorPoseTFUSV}, {"TFGSV", initActorPoseTFGSV}, {"TQSV", initActorPoseTQSV}, {"TQGSV", initActorPoseTQGSV}, {"TQGMSV", initActorPoseTQGMSV}, }; void initActor(LiveActor* actor, const ActorInitInfo& initInfo) { initActorSuffix(actor, initInfo, nullptr); } ALWAYS_INLINE bool initActorPoseKeeper(const char* pose, LiveActor* actor) { if (!pose) return false; s32 poseId = -1; for (s32 i = 0; i < 9; i++) { if (isEqualString(gActorPoseTable[i].name, pose)) { poseId = i; break; } } if (poseId != -1) { gActorPoseTable[poseId].creationFunction(actor); return true; } return false; } ALWAYS_INLINE void initActorPose(LiveActor* actor, const ActorInitInfo& initInfo, Resource* modelRes, const char* suffix) { ByamlIter initPose; if (!tryGetActorInitFileIter(&initPose, modelRes, "InitPose", suffix)) return; const char* pose = nullptr; if (!initPose.tryGetStringByKey(&pose, "Pose")) return; if (!initActorPoseKeeper(pose, actor)) return; if (isEqualString(pose, "TFUSV") && tryGetByamlKeyBoolOrFalse(initPose, "IsFrontUp")) ((ActorPoseKeeperTFUSV*)actor->getPoseKeeper())->setFrontUp(true); } ALWAYS_INLINE void initActorScale(LiveActor* actor, const ActorInitInfo& initInfo, Resource* modelRes, const char* suffix) { ByamlIter initScale; if (!tryGetActorInitFileIter(&initScale, modelRes, "InitScale", suffix)) return; sead::Vector3f scale = {1.0f, 1.0f, 1.0f}; if (!tryGetByamlScale(&scale, initScale, "Scale")) return; const sead::Vector3f& prevScale = getScale(actor); scale.x = scale.x * prevScale.x; scale.y = scale.y * prevScale.y; scale.z = scale.z * prevScale.z; setScale(actor, scale); } ALWAYS_INLINE ModelLodCtrl* initActorModelLodCtrl(LiveActor* actor, Resource* modelRes, const char* suffix) { ByamlIter initLod; if (!tryGetActorInitFileIter(&initLod, modelRes, "InitLod", suffix)) return nullptr; sead::BoundBox3f modelBoundingBox; s32 lodModelCount = 5; if (isExistModel(actor)) { lodModelCount = getLodModelCount(actor); calcModelBoundingBox(&modelBoundingBox, actor); } ModelLodCtrl* modelLodCtrl = new ModelLodCtrl{ actor, getTransPtr(actor), actor->getBaseMtx(), getScalePtr(actor), modelBoundingBox, lodModelCount, }; modelLodCtrl->init(initLod); return modelLodCtrl; } ALWAYS_INLINE void initActorModel(LiveActor* actor, const ActorInitInfo& initInfo, Resource* modelRes, ActorResource* actorResource, const char* suffix) { ByamlIter initModel; if (!tryGetActorInitFileIter(&initModel, modelRes, "InitModel", suffix)) return; s32 blendAnimMax = 1; initModel.tryGetIntByKey(&blendAnimMax, "BlendAnimMax"); const char* displayRootJointName = nullptr; initModel.tryGetStringByKey(&displayRootJointName, "DisplayRootJointName"); initActorModelKeeper(actor, initInfo, actorResource, blendAnimMax); if (displayRootJointName) actor->getModelKeeper()->setDisplayRootJointMtxPtr( getJointMtxPtr(actor, displayRootJointName)); bool isCreateUniqShader = false; initModel.tryGetBoolByKey(&isCreateUniqShader, "IsCreateUniqShader"); if (isCreateUniqShader) createUniqueShader(actor); s32 partialAnimSlotNum = 0; initModel.tryGetIntByKey(&partialAnimSlotNum, "PartialAnimSlotNum"); s32 partialAnimGroupNum = partialAnimSlotNum; initModel.tryGetIntByKey(&partialAnimGroupNum, "PartialAnimGroupNum"); s32 partialAnimPartsListBufferSize = 16; initModel.tryGetIntByKey(&partialAnimPartsListBufferSize, "PartialAnimPartsListBufferSize"); if (partialAnimGroupNum >= 1) initPartialSklAnim(actor, partialAnimSlotNum, partialAnimGroupNum, partialAnimPartsListBufferSize); bool isFixedModel = false; initModel.tryGetBoolByKey(&isFixedModel, "IsFixedModel"); if (isFixedModel) setFixedModelFlag(actor); bool isIgnoreUpdateOnDrawClipping = false; initModel.tryGetBoolByKey(&isIgnoreUpdateOnDrawClipping, "IsIgnoreUpdateOnDrawClipping"); if (isIgnoreUpdateOnDrawClipping) setIgnoreUpdateDrawClipping(actor, true); ModelKeeper* modelKeeper = actor->getModelKeeper(); ModelLodCtrl* modelLodCtrl = initActorModelLodCtrl(actor, modelRes, suffix); modelKeeper->setModelLodCtrl(modelLodCtrl); if (modelLodCtrl) initInfo.actorSceneInfo.graphicsSystemInfo->getModelLodAllCtrl()->registerLodCtrl( modelLodCtrl); MaterialCategoryKeeper* materialCategoryKeeper = initInfo.actorSceneInfo.graphicsSystemInfo->getMaterialCategoryKeeper(); ModelMaterialCategory::tryCreate(modelKeeper->getModelCtrl(), modelRes, suffix, materialCategoryKeeper); GraphicsQualityInfo* graphicsQualityInfo = initInfo.actorSceneInfo.graphicsSystemInfo->getGraphicsQualityController() ->getGraphicsQualityInfo(); modelKeeper->getModelCtrl()->setGraphicsQualityInfo(graphicsQualityInfo); ModelOcclusionQuery* modelOcclusionQuery = ModelOcclusionQuery::tryCreate(actor, modelRes, suffix); modelKeeper->getModelCtrl()->setModelOcclusionQuery(modelOcclusionQuery); bool isCalcViewCore1 = false; initModel.tryGetBoolByKey(&isCalcViewCore1, "IsCalcViewCore1"); if (isCalcViewCore1) modelKeeper->getModelCtrl()->setCalcViewCore(1); bool isCalcViewCore2 = false; initModel.tryGetBoolByKey(&isCalcViewCore2, "IsCalcViewCore2"); if (isCalcViewCore2) modelKeeper->getModelCtrl()->setCalcViewCore(2); } ALWAYS_INLINE void initActorExecutor(LiveActor* actor, const ActorInitInfo& initInfo, Resource* modelRes, const char* suffix) { ByamlIter initExecutor; if (!tryGetActorInitFileIter(&initExecutor, modelRes, "InitExecutor", suffix)) { ModelKeeper* modelKeeper = actor->getModelKeeper(); if (modelKeeper && modelKeeper->getModelCtrl()->getModelObj()->GetNumShapes()) initExecutorModelUpdate(actor, initInfo); return; } const char* updaterCategoryName = nullptr; const char* drawerCategoryName = nullptr; ByamlIter iter; if (initExecutor.tryGetIterByKey(&iter, "Updater") && iter.isTypeArray()) { ByamlIter entry; s32 index = 0; while (iter.tryGetIterByIndex(&entry, index)) { entry.tryGetStringByKey(&updaterCategoryName, "CategoryName"); initExecutorUpdate(actor, initInfo, updaterCategoryName); index++; } } if (initExecutor.tryGetIterByKey(&iter, "Drawer")) { ModelKeeper* modelKeeper = actor->getModelKeeper(); if (modelKeeper && modelKeeper->getModelCtrl()->getModelObj()->GetNumShapes()) initExecutorModelUpdate(actor, initInfo); if (iter.isTypeArray()) { ByamlIter entry; s32 index = 0; while (iter.tryGetIterByIndex(&entry, index)) { entry.tryGetStringByKey(&drawerCategoryName, "CategoryName"); initExecutorDraw(actor, initInfo, drawerCategoryName); index++; } } } } ALWAYS_INLINE void initActorSensor(LiveActor* actor, const ActorInitInfo& initInfo, Resource* modelRes, const char* suffix) { ByamlIter initSensor; if (!tryGetActorInitFileIter(&initSensor, modelRes, "InitSensor", suffix)) return; s32 numSensors = initSensor.getSize(); if (numSensors <= 0) return; actor->initHitSensor(numSensors); for (s32 i = 0; i < numSensors; i++) { ByamlIter sensor; if (!initSensor.tryGetIterByIndex(&sensor, i)) continue; const char* sensorName = nullptr; if (!sensor.tryGetStringByKey(&sensorName, "Name")) continue; const char* sensorType = nullptr; if (!sensor.tryGetStringByKey(&sensorType, "Type")) continue; f32 radius = 0.0f; sensor.tryGetFloatByKey(&radius, "Radius"); s32 maxCount = 8; sensor.tryGetIntByKey(&maxCount, "MaxCount"); sead::Vector3f offset = sead::Vector3f::zero; tryGetByamlV3f(&offset, sensor); HitSensorType type = alSensorFunction::findSensorTypeByName(sensorType); if (type == HitSensorType::CollisionParts) maxCount = 0; addHitSensor(actor, initInfo, sensorName, (u32)type, radius, maxCount, offset); const char* joint = nullptr; sensor.tryGetStringByKey(&joint, "Joint"); if (joint) setHitSensorJointMtx(actor, sensorName, joint); } } ALWAYS_INLINE void initActorCollision(LiveActor* actor, const ActorInitInfo& initInfo, Resource* modelRes, const char* suffix) { ByamlIter initCollision; if (!tryGetActorInitFileIter(&initCollision, modelRes, "InitCollision", suffix)) return; const char* name = nullptr; initCollision.tryGetStringByKey(&name, "Name"); StringTmp<256> unused; if (!name) name = getBaseName(modelRes->getArchiveName()); const char* sensorName = nullptr; HitSensor* sensor = nullptr; if (initCollision.tryGetStringByKey(&sensorName, "Sensor")) sensor = getHitSensor(actor, sensorName); const char* joint = nullptr; initCollision.tryGetStringByKey(&joint, "Joint"); sead::Matrix34f* jointMtx = nullptr; if (joint) jointMtx = getJointMtxPtr(actor, joint); initActorCollisionWithResource(actor, modelRes, name, sensor, jointMtx, suffix); } ALWAYS_INLINE void initActorCollider(LiveActor* actor, const ActorInitInfo& initInfo, Resource* modelRes, const char* suffix) { ByamlIter initCollider; if (!tryGetActorInitFileIter(&initCollider, modelRes, "InitCollider", suffix)) return; f32 radius = 0.0f; initCollider.tryGetFloatByKey(&radius, "Radius"); u32 planeNum = 0; initCollider.tryGetUIntByKey(&planeNum, "PlaneNum"); sead::Vector3f offset = sead::Vector3f::zero; tryGetByamlV3f(&offset, initCollider); actor->initCollider(radius, offset.y, planeNum); } ALWAYS_INLINE void initActorEffect(LiveActor* actor, const ActorInitInfo& initInfo, Resource* modelRes, const char* suffix) { ByamlIter initEffect; if (!tryGetActorInitFileIter(&initEffect, modelRes, "InitEffect", suffix)) return; const char* name = nullptr; if (!initEffect.tryGetStringByKey(&name, "Name")) return; initActorEffectKeeper(actor, initInfo, name); } ALWAYS_INLINE void initActorSound(LiveActor* actor, const ActorInitInfo& initInfo, Resource* modelRes, const char* suffix) { ByamlIter initSound; const char* seName = nullptr; const char* bgmName = nullptr; if (tryGetActorInitFileIter(&initSound, modelRes, "InitSound", suffix)) { initSound.tryGetStringByKey(&seName, "Name"); } else if (tryGetActorInitFileIter(&initSound, modelRes, "InitAudio", suffix)) { initSound.tryGetStringByKey(&seName, "SeUserName"); initSound.tryGetStringByKey(&bgmName, "BgmUserName"); } else return; if (seName) initActorSeKeeper(actor, initInfo, seName); if (initSound.isExistKey("BgmUserName")) initActorBgmKeeper(actor, initInfo, bgmName); } ALWAYS_INLINE void initActorRail(LiveActor* actor, const ActorInitInfo& initInfo) { if (isExistRail(initInfo, "Rail")) actor->initRailKeeper(initInfo, "Rail"); } ALWAYS_INLINE void initActorGroupClipping(LiveActor* actor, const ActorInitInfo& initInfo, const ByamlIter& initClipping) { if (initClipping.isExistKey("NoGroupClipping")) return; ByamlIter groupClipping; if (!initClipping.tryGetIterByKey(&groupClipping, "GroupClipping")) return; initGroupClipping(actor, initInfo); } ALWAYS_INLINE void initActorClipping(LiveActor* actor, const ActorInitInfo& initInfo, Resource* modelRes, const char* suffix) { ByamlIter initClipping; if (!tryGetActorInitFileIter(&initClipping, modelRes, "InitClipping", suffix)) return; initActorClipping(actor, initInfo); bool invalidate = false; initClipping.tryGetBoolByKey(&invalidate, "Invalidate"); if (invalidate) invalidateClipping(actor); f32 radius = 0.0f; if (initClipping.tryGetFloatByKey(&radius, "Radius")) { setClippingInfo(actor, radius, nullptr); } else if (actor->getModelKeeper()) { const sead::Vector3f& scale = getScale(actor); f32 maxXY = sead::Mathf::max(sead::Mathf::abs(scale.x), sead::Mathf::abs(scale.y)); f32 maxXYZ = sead::Mathf::max(maxXY, sead::Mathf::abs(scale.z)); setClippingInfo(actor, calcModelBoundingSphereRadius(actor) * maxXYZ, nullptr); } sead::BoundBox3f obb; if (tryGetByamlBox3f(&obb, initClipping, "Obb")) setClippingObb(actor, obb); f32 nearClipDistance = 0.0f; if (initClipping.tryGetFloatByKey(&nearClipDistance, "NearClipDistance")) setClippingNearDistance(actor, nearClipDistance); initActorGroupClipping(actor, initInfo, initClipping); } ALWAYS_INLINE void initActorShadowMask(LiveActor* actor, const ActorInitInfo& initInfo, Resource* modelRes, const char* suffix) { bool usingDepthShadow = false; tryGetArg(&usingDepthShadow, initInfo, "UsingDepthShadow"); initDepthShadowMapCtrl(actor, modelRes, initInfo, suffix); ByamlIter initShadowMask; if (!tryGetActorInitFileIter(&initShadowMask, modelRes, "InitShadowMask", suffix)) return; initShadowMaskCtrl(actor, initInfo, initShadowMask, "InitShadowMask"); if (usingDepthShadow) invalidateShadowMaskIntensityAll(actor); } ALWAYS_INLINE void initActorFlag(LiveActor* actor, const ActorInitInfo& initInfo, Resource* modelRes, const char* suffix) { ByamlIter initFlag; if (!tryGetActorInitFileIter(&initFlag, modelRes, "InitFlag", suffix)) return; ByamlIter tmp; if (initFlag.tryGetIterByKey(&tmp, "MaterialCode")) validateMaterialCode(actor); if (initFlag.tryGetIterByKey(&tmp, "UpdatePuddleMaterial")) validatePuddleMaterial(actor); } ALWAYS_INLINE void initActorItem(LiveActor* actor, const ActorInitInfo& initInfo, Resource* modelRes, const char* suffix) { ByamlIter initItem; if (!tryGetActorInitFileIter(&initItem, modelRes, "InitItem", suffix)) return; initActorItemKeeper(actor, initInfo, initItem); } ALWAYS_INLINE void initActorScore(LiveActor* actor, const ActorInitInfo& initInfo, Resource* modelRes, const char* suffix) { ByamlIter initScore; if (!tryGetActorInitFileIter(&initScore, modelRes, "InitScore", suffix)) return; actor->initScoreKeeper(); actor->getActorScoreKeeper()->init(initScore); } ALWAYS_INLINE void initActorAction(LiveActor* actor, const ActorInitInfo& initInfo, Resource* modelRes, ActorResource* actorResource, const char* suffix) { const char* archiveName = actorResource->getModelRes()->getArchiveName(); initActorActionKeeper(actor, actorResource, archiveName, suffix); if (!actor->getModelKeeper()) return; if (!tryStartAction(actor, archiveName)) { ActorActionKeeper* actionKeeper = actor->getActorActionKeeper(); if (actionKeeper) actionKeeper->startAction(archiveName); } ModelKeeper* modelKeeper = actor->getModelKeeper(); if (!modelKeeper) return; DitherAnimator* ditherAnimator = ActorDitherAnimator::tryCreate(actor, modelRes, suffix); if (ditherAnimator) { modelKeeper->setDitherAnimator(ditherAnimator); return; } ditherAnimator = FarDistanceDitherAnimator::tryCreate(actor, modelRes, suffix); if (ditherAnimator) modelKeeper->setDitherAnimator(ditherAnimator); } void initActorImpl(LiveActor* actor, const ActorInitInfo& initInfo, const sead::SafeString& folderName, const sead::SafeString& fileName, const char* suffix) { StringTmp<256> path = {"%s/%s", folderName.cstr(), fileName.cstr()}; ActorResource* actorResource = findOrCreateActorResource(initInfo.actorResourceHolder, path.cstr(), suffix); Resource* modelRes = actorResource->getModelRes(); if (!actor->getSceneInfo()) initActorSceneInfo(actor, initInfo); initActorPose(actor, initInfo, modelRes, suffix); initActorSRT(actor, initInfo); initActorScale(actor, initInfo, modelRes, suffix); initActorModel(actor, initInfo, actorResource->getModelRes(), actorResource, suffix); initActorPrePassLightKeeper(actor, modelRes, initInfo, suffix); initActorExecutor(actor, initInfo, modelRes, suffix); initActorSensor(actor, initInfo, modelRes, suffix); initActorCollision(actor, initInfo, modelRes, suffix); initActorCollider(actor, initInfo, modelRes, suffix); initActorEffect(actor, initInfo, modelRes, suffix); initActorSound(actor, initInfo, modelRes, suffix); initActorRail(actor, initInfo); initStageSwitch(actor, initInfo); initActorClipping(actor, initInfo, modelRes, suffix); initActorOcclusionKeeper(actor, modelRes, initInfo, suffix); initActorShadowMask(actor, initInfo, modelRes, suffix); initActorFlag(actor, initInfo, modelRes, suffix); initActorItem(actor, initInfo, modelRes, suffix); initActorScore(actor, initInfo, modelRes, suffix); initScreenPointKeeper(actor, modelRes, initInfo, suffix); initHitReactionKeeper(actor, modelRes, suffix); initActorParamHolder(actor, modelRes, suffix); initActorAction(actor, initInfo, modelRes, actorResource, suffix); if (actor->getNerveKeeper() && actor->getNerveKeeper()->getActionCtrl()) resetNerveActionForInit(actor); if (!actor->getSubActorKeeper()) initSubActorKeeper(actor, initInfo, suffix, 0); } void initActorSuffix(LiveActor* actor, const ActorInitInfo& initInfo, const char* suffix) { const char* objName = nullptr; tryGetObjectName(&objName, initInfo); initActorImpl(actor, initInfo, "ObjectData", objName, suffix); } void initActorChangeModel(LiveActor* actor, const ActorInitInfo& initInfo) { initActorChangeModelSuffix(actor, initInfo, nullptr); } inline const char* getModelName(const ActorInitInfo& initInfo) { const char* name = nullptr; if (alPlacementFunction::tryGetModelName(&name, initInfo)) return name; else if (tryGetObjectName(&name, initInfo)) return name; return nullptr; } void initActorChangeModelSuffix(LiveActor* actor, const ActorInitInfo& initInfo, const char* suffix) { const char* file = getModelName(initInfo); initActorImpl(actor, initInfo, "ObjectData", file, suffix); } void initActorWithArchiveName(LiveActor* actor, const ActorInitInfo& initInfo, const sead::SafeString& archiveName, const char* suffix) { initChildActorWithArchiveNameWithPlacementInfo(actor, initInfo, archiveName, suffix); } void initChildActorWithArchiveNameWithPlacementInfo(LiveActor* actor, const ActorInitInfo& initInfo, const sead::SafeString& archiveName, const char* suffix) { initActorImpl(actor, initInfo, "ObjectData", archiveName.cstr(), suffix); } void initChildActorWithArchiveNameNoPlacementInfo(LiveActor* actor, const ActorInitInfo& initInfo, const sead::SafeString& archiveName, const char* suffix) { PlacementInfo placementInfo; ActorInitInfo childInitInfo; childInitInfo.initViewIdHost(&placementInfo, initInfo); initActorImpl(actor, childInitInfo, "ObjectData", archiveName.cstr(), suffix); } LiveActor* createChildLinkSimpleActor(const char* actorName, const char* linkName, const ActorInitInfo& initInfo, bool alive) { ActorInitInfo childInitInfo; PlacementInfo placementInfo; getLinksInfoByIndex(&placementInfo, *initInfo.placementInfo, linkName, 0); childInitInfo.initViewIdSelf(&placementInfo, initInfo); LiveActor* actor = new LiveActor(actorName); initActor(actor, childInitInfo); if (alive) actor->makeActorAlive(); else actor->makeActorDead(); return actor; } LiveActor* createChildLinkMapPartsActor(const char* actorName, const char* linkName, const ActorInitInfo& initInfo, s32 linkIndex, bool alive) { ActorInitInfo childInitInfo; PlacementInfo placementInfo; getLinksInfoByIndex(&placementInfo, *initInfo.placementInfo, linkName, linkIndex); childInitInfo.initViewIdSelf(&placementInfo, initInfo); LiveActor* actor = new LiveActor(actorName); initMapPartsActor(actor, childInitInfo, nullptr); if (alive) actor->makeActorAlive(); else actor->makeActorDead(); return actor; } void initMapPartsActor(LiveActor* actor, const ActorInitInfo& initInfo, const char* suffix) { const char* modelName; StringTmp<256> fileName; StringTmp<256> folderName; const PlacementInfo& placementInfo = *initInfo.placementInfo; modelName = nullptr; if (alPlacementFunction::tryGetModelName(&modelName, placementInfo) && !isEqualString(modelName, "")) { fileName.copy(modelName); folderName.copy("ObjectData"); } else { tryGetStringArg(&modelName, placementInfo, "UnitConfigName"); fileName.copy(modelName); folderName.copy("ObjectData"); } initActorImpl(actor, initInfo, folderName, fileName, suffix); } void initLinksActor(LiveActor* actor, const ActorInitInfo& initInfo, const char* suffix, s32 linkIndex) { ActorInitInfo childInitInfo; PlacementInfo placementInfo; getLinksInfoByIndex(&placementInfo, *initInfo.placementInfo, suffix, linkIndex); childInitInfo.initViewIdSelf(&placementInfo, initInfo); actor->init(childInitInfo); } ActorInitInfo* createLinksPlayerActorInfo(LiveActor* actor, const ActorInitInfo& initInfo) { s32 startPosNum = calcLinkChildNum(initInfo, "PlayerRestartPos"); ActorInitInfo* result = new ActorInitInfo(); if (startPosNum == 1) { PlacementInfo* placementInfo = new PlacementInfo(); getLinksInfoByIndex(placementInfo, *initInfo.placementInfo, "PlayerRestartPos", 0); result->initViewIdSelf(placementInfo, initInfo); } return result; } const char* getLinksActorClassName(const ActorInitInfo& initInfo, const char* linkName, s32 linkIndex) { ActorInitInfo childInitInfo; PlacementInfo placementInfo; const char* className = nullptr; getLinksInfoByIndex(&placementInfo, *initInfo.placementInfo, linkName, linkIndex); childInitInfo.initViewIdSelf(&placementInfo, initInfo); getClassName(&className, childInitInfo); return className; } const char* getLinksActorDisplayName(const ActorInitInfo& initInfo, const char* linkName, s32 linkIndex) { PlacementInfo placementInfo; getLinksInfoByIndex(&placementInfo, *initInfo.placementInfo, linkName, linkIndex); const char* displayName = nullptr; getDisplayName(&displayName, placementInfo); return displayName; } const char* getLinksActorObjectName(const ActorInitInfo& initInfo, const char* linkName, s32 linkIndex) { PlacementInfo placementInfo; getLinksInfoByIndex(&placementInfo, *initInfo.placementInfo, linkName, linkIndex); const char* objectName = nullptr; getObjectName(&objectName, placementInfo); return objectName; } void initCreateActorWithPlacementInfo(LiveActor* actor, const ActorInitInfo& initInfo) { actor->init(initInfo); } void initCreateActorWithPlacementInfo(LiveActor* actor, const ActorInitInfo& initInfo, const PlacementInfo& placementInfo) { ActorInitInfo childInitInfo; childInitInfo.initViewIdSelf(&placementInfo, initInfo); actor->init(childInitInfo); } void initCreateActorNoPlacementInfo(LiveActor* actor, const ActorInitInfo& initInfo) { PlacementInfo placementInfo; ActorInitInfo childInitInfo; childInitInfo.initViewIdHost(&placementInfo, initInfo); actor->init(childInitInfo); } void initCreateActorNoPlacementInfoNoViewId(LiveActor* actor, const ActorInitInfo& initInfo) { PlacementInfo placementInfo; ActorInitInfo childInitInfo; childInitInfo.initNoViewId(&placementInfo, initInfo); actor->init(childInitInfo); } ALWAYS_INLINE LiveActor* createActorFromFactory(const ActorInitInfo& childInitInfo, const PlacementInfo* placementInfo) { const ActorFactory* factory = childInitInfo.actorFactory; const char* objectName = nullptr; getObjectName(&objectName, childInitInfo); const char* className = nullptr; getClassName(&className, childInitInfo); ActorCreatorFunction creationFunction = nullptr; factory->getEntryIndex(&creationFunction, className); if (!creationFunction) return nullptr; const char* displayName; getDisplayName(&displayName, childInitInfo); LiveActor* actor = (*creationFunction)(displayName); actor->init(childInitInfo); return actor; } LiveActor* createPlacementActorFromFactory(const ActorInitInfo& initInfo, const PlacementInfo* placementInfo) { ActorInitInfo childInitInfo; childInitInfo.initViewIdSelf(placementInfo, initInfo); return createActorFromFactory(childInitInfo, placementInfo); } LiveActor* createLinksActorFromFactory(const ActorInitInfo& initInfo, const char* linkName, s32 linkNum) { ActorInitInfo childInitInfo; PlacementInfo placementInfo; getLinksInfoByIndex(&placementInfo, *initInfo.placementInfo, linkName, linkNum); childInitInfo.initViewIdSelf(&placementInfo, initInfo); return createActorFromFactory(childInitInfo, &placementInfo); } LiveActorGroup* createLinksActorGroupFromFactory(const ActorInitInfo& initInfo, const char* linkName, const char* groupName) { return tryCreateLinksActorGroupFromFactory(initInfo, linkName, groupName); } LiveActorGroup* tryCreateLinksActorGroupFromFactory(const ActorInitInfo& initInfo, const char* linkName, const char* groupName) { ActorInitInfo childInitInfo; PlacementInfo placementInfo; s32 linkChildNum = calcLinkChildNum(initInfo, linkName); if (linkChildNum < 1) return nullptr; LiveActorGroup* group = new LiveActorGroup(groupName, linkChildNum); for (s32 i = 0; i < linkChildNum; i++) { getLinksInfoByIndex(&placementInfo, *initInfo.placementInfo, linkName, i); childInitInfo.initViewIdSelf(&placementInfo, initInfo); group->registerActor(createActorFromFactory(childInitInfo, &placementInfo)); } return group; } LiveActor* tryCreateLinksActorFromFactorySingle(const ActorInitInfo& initInfo, const char* linkName) { if (calcLinkChildNum(initInfo, linkName) < 1) return nullptr; return createLinksActorFromFactory(initInfo, linkName, 0); } void createAndRegisterLinksActorFromFactory(LiveActorGroup* group, const ActorInitInfo& initInfo, const char* linkName) { ActorInitInfo childInitInfo; PlacementInfo placementInfo; s32 linkChildNum = calcLinkChildNum(initInfo, linkName); if (linkChildNum < 1) return; for (s32 i = 0; i < linkChildNum; i++) { getLinksInfoByIndex(&placementInfo, *initInfo.placementInfo, linkName, i); childInitInfo.initViewIdSelf(&placementInfo, initInfo); group->registerActor(createActorFromFactory(childInitInfo, &placementInfo)); } } void makeMapPartsModelName(sead::BufferedSafeString* modelName, sead::BufferedSafeString* path, const PlacementInfo& placementInfo) { const char* archiveName = nullptr; if (alPlacementFunction::tryGetModelName(&archiveName, placementInfo) && !isEqualString(archiveName, "")) { modelName->copy(archiveName); path->format("ObjectData/%s", archiveName); } else { tryGetStringArg(&archiveName, placementInfo, "UnitConfigName"); modelName->copy(archiveName); path->format("ObjectData/%s", archiveName); } } void makeMapPartsModelName(sead::BufferedSafeString* modelName, sead::BufferedSafeString* path, const ActorInitInfo& initInfo) { makeMapPartsModelName(modelName, path, *initInfo.placementInfo); } const char* tryGetMapPartsSuffix(const ActorInitInfo& initInfo, const char* suffix) { StringTmp<64> name = {"InitActor%s", suffix}; if (!tryGetMapPartsResourceYaml(initInfo, name.cstr())) return nullptr; return suffix; } void initMapPartsActorWithArchiveName(LiveActor* actor, const ActorInitInfo& initInfo, const char* fileName, const char* suffix) { return initActorImpl(actor, initInfo, "MapPartsData", fileName, suffix); } void initNerve(LiveActor* actor, const Nerve* nerve, s32 maxStates) { actor->initNerveKeeper(new NerveKeeper(actor, nerve, maxStates)); } void initNerveAction(LiveActor* actor, const char* actionName, alNerveFunction::NerveActionCollector* collector, s32 maxStates) { auto* nerveActionCtrl = new NerveActionCtrl(collector); initNerve(actor, nerveActionCtrl->findNerve(actionName), maxStates); actor->getNerveKeeper()->initNerveAction(nerveActionCtrl); startNerveAction(actor, actionName); } bool trySyncStageSwitchAppear(LiveActor* actor) { using LiveActorFunctor = FunctorV0M; if (listenStageSwitchOnOffAppear(actor, LiveActorFunctor{actor, &LiveActor::appear}, LiveActorFunctor{actor, &LiveActor::kill})) { actor->makeActorDead(); return true; } else { actor->makeActorAlive(); return false; } } bool trySyncStageSwitchKill(LiveActor* actor) { using LiveActorFunctor = FunctorV0M; bool result = listenStageSwitchOnOffKill(actor, LiveActorFunctor(actor, &LiveActor::kill), LiveActorFunctor(actor, &LiveActor::appear)); actor->makeActorAlive(); return result; } bool trySyncStageSwitchAppearAndKill(LiveActor* actor) { if (trySyncStageSwitchAppear(actor)) return true; return trySyncStageSwitchKill(actor); } bool tryListenStageSwitchAppear(LiveActor* actor) { using LiveActorFunctor = FunctorV0M; if (listenStageSwitchOnAppear(actor, LiveActorFunctor{actor, &LiveActor::appear})) { actor->makeActorDead(); return true; } else { actor->makeActorAlive(); return false; } } bool tryListenStageSwitchKill(LiveActor* actor) { using LiveActorFunctor = FunctorV0M; return listenStageSwitchOnKill(actor, LiveActorFunctor(actor, &LiveActor::kill)); } void syncSensorScaleY(LiveActor* actor) { f32 scaleY = getScale(actor).y; for (s32 i = 0; i < actor->getHitSensorKeeper()->getSensorNum(); i++) actor->getHitSensorKeeper()->getSensor(i)->scaleY(scaleY); } void syncSensorAndColliderScaleY(LiveActor* actor) { syncSensorScaleY(actor); f32 scaleY = getScale(actor).y; setColliderRadius(actor, scaleY * getColliderRadius(actor)); setColliderOffsetY(actor, scaleY * getColliderOffsetY(actor)); } void setMaterialCode(LiveActor* actor, const char* materialCode) { if (actor->getEffectKeeper()) tryUpdateEffectMaterialCode(actor, materialCode); if (isExistSeKeeper(actor)) tryUpdateSeMaterialCode(actor, materialCode); } void initMaterialCode(LiveActor* actor, const ActorInitInfo& initInfo) { const char* materialCode = ""; if (tryGetStringArg(&materialCode, initInfo, "MaterialCode")) setMaterialCode(actor, materialCode); } bool tryAddDisplayRotate(LiveActor* actor, const ActorInitInfo& initInfo) { sead::Vector3f rotate = {0.0f, 0.0f, 0.0f}; if (!tryGetDisplayRotate(&rotate, initInfo)) return false; sead::Matrix34f rotateMtx; rotateMtx.makeR({sead::Mathf::deg2rad(rotate.x), sead::Mathf::deg2rad(rotate.y), sead::Mathf::deg2rad(rotate.z)}); sead::Matrix34f origMtx = sead::Matrix34f::ident; makeMtxRT(&origMtx, actor); origMtx = origMtx * rotateMtx; updatePoseMtx(actor, &origMtx); return true; } bool tryAddDisplayOffset(LiveActor* actor, const ActorInitInfo& initInfo) { sead::Vector3f offset = {0.0f, 0.0f, 0.0f}; if (!tryGetDisplayOffset(&offset, initInfo)) return false; *getTransPtr(actor) += offset; return true; } bool tryAddDisplayScale(LiveActor* actor, const ActorInitInfo& initInfo) { sead::Vector3f scale = {0.0f, 0.0f, 0.0f}; if (!tryGetDisplayScale(&scale, initInfo)) return false; setScaleX(actor, getScale(actor).x * scale.x); setScaleY(actor, getScale(actor).y * scale.y); setScaleZ(actor, getScale(actor).z * scale.z); return true; } const PlacementInfo& getPlacementInfo(const ActorInitInfo& initInfo) { return *initInfo.placementInfo; } const LayoutInitInfo& getLayoutInitInfo(const ActorInitInfo& initInfo) { return *initInfo.layoutInitInfo; } AudioDirector* getAudioDirector(const ActorInitInfo& initInfo) { return initInfo.audioDirector; } CollisionDirector* getCollisionDirectorFromInfo(const ActorInitInfo& initInfo) { return initInfo.actorSceneInfo.collisionDirector; } const SceneCameraInfo* getSceneCameraInfoFromInfo(const ActorInitInfo& initInfo) { return initInfo.actorSceneInfo.cameraDirector->getSceneCameraInfo(); } GraphicsSystemInfo* getGraphicsSystemInfo(const ActorInitInfo& initInfo) { return initInfo.actorSceneInfo.graphicsSystemInfo; } agl::DrawContext* getDrawContext(const ActorInitInfo& initInfo) { return initInfo.actorSceneInfo.graphicsSystemInfo->getDrawContext(); } void getActorRecourseDataF32(f32* val, LiveActor* actor, const char* fileName, const char* entryName) { isExistModelResourceYaml(actor, fileName, nullptr); ByamlIter iter = {getModelResourceYaml(actor, fileName, nullptr)}; tryGetByamlF32(val, iter, entryName); } void getActorRecourseDataString(const char** val, LiveActor* actor, const char* fileName, const char* entryName) { isExistModelResourceYaml(actor, fileName, nullptr); ByamlIter iter = {getModelResourceYaml(actor, fileName, nullptr)}; *val = getByamlKeyString(iter, entryName); } void getActorRecourseDataV3f(sead::Vector3f* val, LiveActor* actor, const char* fileName, const char* entryName) { isExistModelResourceYaml(actor, fileName, nullptr); ByamlIter iter = {getModelResourceYaml(actor, fileName, nullptr)}; if (entryName) tryGetByamlV3f(val, iter, entryName); else tryGetByamlV3f(val, iter); } void getActorRecourseDataBox3f(sead::BoundBox3f* box, LiveActor* actor, const char* fileName, const char* entryName) { isExistModelResourceYaml(actor, fileName, nullptr); ByamlIter iter = {getModelResourceYaml(actor, fileName, nullptr)}; if (entryName) tryGetByamlBox3f(box, iter, entryName); else tryGetByamlBox3f(box, iter); } PartsEffectGroup* createPartsEffectGroup(LiveActor* actor, const ActorInitInfo& initInfo, s32 maxEffects) { const char* name; if (isExistModelResourceYaml(actor, "InitPartsEffect", nullptr)) getActorRecourseDataString(&name, actor, "InitPartsEffect", "Name"); else getActorRecourseDataString(&name, actor, "InitEffect", "Name"); PartsEffectGroup* group = new PartsEffectGroup(); group->init(maxEffects, initInfo.effectSystemInfo, name, getTransPtr(actor), tryGetScalePtr(actor), actor->getBaseMtx(), actor); return group; } } // namespace al