From 8e0d05234f278343ef1c0a4a5000fd71a8190c57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 16 May 2021 13:34:45 +0200 Subject: [PATCH] ksys/act: Start adding LodInfo --- data/uking_functions.csv | 8 +- src/KingSystem/ActorSystem/CMakeLists.txt | 3 + .../ActorSystem/LOD/actLodState.cpp | 331 ++++++++++++++++++ src/KingSystem/ActorSystem/LOD/actLodState.h | 58 +++ src/KingSystem/ActorSystem/actActor.h | 2 + src/KingSystem/Map/mapObject.h | 2 +- src/KingSystem/Map/mapPlacementMgr.h | 14 +- src/KingSystem/System/CMakeLists.txt | 2 + .../System/OcclusionQueryCylinder.cpp | 1 + .../System/OcclusionQueryCylinder.h | 25 ++ 10 files changed, 439 insertions(+), 7 deletions(-) create mode 100644 src/KingSystem/ActorSystem/LOD/actLodState.cpp create mode 100644 src/KingSystem/ActorSystem/LOD/actLodState.h create mode 100644 src/KingSystem/System/OcclusionQueryCylinder.cpp create mode 100644 src/KingSystem/System/OcclusionQueryCylinder.h diff --git a/data/uking_functions.csv b/data/uking_functions.csv index ec7f5db2..1b444a42 100644 --- a/data/uking_functions.csv +++ b/data/uking_functions.csv @@ -94039,10 +94039,10 @@ 0x000000710124aebc,FarActorMerge::requestDraw,152, 0x000000710124af54,FarActorMerge::x,252, 0x000000710124b050,Actor::makeField598,5784, -0x000000710124c6e8,act598::ctor,18196, -0x0000007101250dfc,act598::x,112, -0x0000007101250e6c,sub_7101250E6C,40, -0x0000007101250e94,sub_7101250E94,68, +0x000000710124c6e8,act598::ctor,18196,_ZN4ksys3act8LodStateC1EPN4sead4HeapENS2_7BitFlagIjEEPNS0_5ActorEif? +0x0000007101250dfc,act598::x,112,_ZN4ksys3act8LodState9initFlagsEv? +0x0000007101250e6c,sub_7101250E6C,40,_ZN4ksys3act8LodStateD1Ev +0x0000007101250e94,sub_7101250E94,68,_ZN4ksys3act8LodStateD0Ev 0x0000007101250ed8,sub_7101250ED8,752, 0x00000071012511c8,sub_71012511C8,52, 0x00000071012511fc,sub_71012511FC,36, diff --git a/src/KingSystem/ActorSystem/CMakeLists.txt b/src/KingSystem/ActorSystem/CMakeLists.txt index d7bf5721..27fd0a4a 100644 --- a/src/KingSystem/ActorSystem/CMakeLists.txt +++ b/src/KingSystem/ActorSystem/CMakeLists.txt @@ -1,4 +1,7 @@ target_sources(uking PRIVATE + LOD/actLodState.cpp + LOD/actLodState.h + Profiles/actPlayerBase.cpp Profiles/actPlayerBase.h Profiles/actRopeBase.cpp diff --git a/src/KingSystem/ActorSystem/LOD/actLodState.cpp b/src/KingSystem/ActorSystem/LOD/actLodState.cpp new file mode 100644 index 00000000..0a53f016 --- /dev/null +++ b/src/KingSystem/ActorSystem/LOD/actLodState.cpp @@ -0,0 +1,331 @@ +#include "KingSystem/ActorSystem/LOD/actLodState.h" +#include "KingSystem/ActorSystem/actActor.h" +#include "KingSystem/ActorSystem/actActorParam.h" +#include "KingSystem/ActorSystem/actActorUtil.h" +#include "KingSystem/Map/mapObject.h" +#include "KingSystem/Map/mapPlacementMgr.h" +#include "KingSystem/Resource/resResourceLod.h" +#include "KingSystem/System/OcclusionQueryCylinder.h" + +namespace ksys::act { + +// NON_MATCHING: reorders at the beginning because of initFlags -- should be equivalent +LodState::LodState(sead::Heap* heap, sead::BitFlag32 flags, Actor* actor, + int disable_calc_skip_frame, float x) + : mFlags14(flags), mActor(actor), _44(x), mDisableCalcSkipFrame(disable_calc_skip_frame) { + initFlags(); + + if (mActor->getProfile().include("Enemy") || mActor->getProfile().include("Swarm") || + mActor->getProfile().include("EnemySwarm")) { + _24 = 0; + } + if (mActor->getProfile().include("NPC")) { + _24 = 1; + } + if (mActor->getName() == "GameRomHorseBone") { + _24 = 1; + } + _25 = _24; + + if (mActor->getMapObject()) { + mDispDistance = mActor->getMapObject()->getDispDistance(); + } + + const bool is_air_octa_platform = isAirOctaPlatform(mActor->getName()); + if (!mActor->checkFlag(Actor::ActorFlag::_39) || mActor->getProfile().startsWith("Guardian")) { + if (is_air_octa_platform) { + mOcclusionQueryCylinder = new (heap) OcclusionQueryCylinder; + mOcclusionQueryCylinder->init(heap); + } + } else { + mOcclusionQueryCylinder = new (heap) OcclusionQueryCylinder; + mOcclusionQueryCylinder->init(heap); + } + + if (is_air_octa_platform) + mFlags26.set(0x40); + + if (auto* lod = mActor->getParam()->getRes().mLod) { + if (lod->mDisableConstActor.ref()) + mFlags14.set(0x1000000); + mDistanceScale = lod->mDistanceScale.ref(); + if (lod->mDisableCalcRescueDistLimit.ref()) + mFlags14.set(0x4000000); + } + + int type = 8; + if (mActor->getProfile().include("Giant") || mActor->getProfile().include("Guardian")) { + type = 1; + } else if (mActor->getProfile().include("Enemy") || mActor->getProfile().include("Swarm") || + mActor->getProfile().include("EnemySwarm")) { + type = 0; + } else if (mActor->getProfile() == "NPC") { + type = 2; + } else if (mActor->getProfile().include("Horse")) { + type = 7; + } else if (mActor->getName().include("Insect")) { + type = 4; + } else if (mActor->getName().include("Fish")) { + type = 5; + } else if (mActor->getName().include("Weapon")) { + type = 6; + } else if (mActor->getName().include("Animal")) { + type = 3; + } + mActorType = type; + _70 = 60; + + float dist = 500.0f; + + if (!hasTag(mActor, tags::Door)) { + if (mActor->getName() == "SignalFireWood" || + mActor->getName() == "DgnObj_EntranceShutter_A_01" || + mActor->getName() == "DgnObj_WarpPoint_A_01" || + mActor->getName() == "DgnObj_EntranceTerminal_A_01" || + mActor->getName().startsWith("DgnObj_DungeonEntrance_A_01") || + mActor->getName().startsWith("DgnObj_RemainsLithograph_A") || + mActor->getName().startsWith("DgnObj_RemainsLithogragh_A") || + mActor->getName() == "GreatFairyBeforeRevival" || + mActor->getName() == "TwnObj_FairySpringClose_A_01" || + mActor->getName() == "TwnObj_FairySpring_A_01" || + mActor->getName() == "Rito_BrosRock_Relief" || + mActor->getName() == "TwnObj_HyruleCastleSealCover_A_01" || + mActor->getName() == "FldObj_DownloadTerminalBody_A_01" || + mActor->getName() == "FldObj_DownloadTerminal_A_01" || + mActor->getName() == "FldObj_MapTowerWingBefore_A_01" || + mActor->getName() == "FldObj_MapTower_A_01" || + mActor->getName().startsWith("Item_CookSet") || + mActor->getName() == "DgnObj_WarpPointSP" || + mActor->getName() == "DgnObj_EntranceTerminalSP" || + mActor->getName() == "DgnObj_EntranceShutterSP" || + mActor->getName() == "DgnObj_EntranceElevatorSP" || + mActor->getName() == "DgnObj_DLC_ChampionsDungeonEntrance_A_01" || + mActor->getName().startsWith("FldObj_DLC_HeroMapRelief_Mark_A") || + mActor->getName().startsWith("FldObj_DLC_HeroMap_") || + mActor->getName() == "FldObj_DLC_HeroMapRelief_A_01") { + _70 = 60; + dist = 10.0f; + } else if (mActor->getName() == "Bros_Rock_01" || mActor->getName() == "Bros_Rock_02" || + mActor->getName() == "Bros_Rock_03" || mActor->getName() == "Bros_Rock_04" || + mActor->getName() == "Bros_Rock_05") { + _70 = 60; + dist = 30.0f; + } else if (mActor->getName() == "TwnObj_GanonGrudgeSolid_Eyeball_A_01") { + _70 = 60; + dist = 110.0f; + } else if (mActor->getName().include("TwnObj_HyruleCastleObject") || + mActor->getName().include("TwnObj_HyruleCastle_GateBridgeDoor")) { + _70 = 60; + dist = 50.0f; + } else if (mActor->getName() == "WallCrack" || mActor->getName() == "Obj_RockBroken_A_02" || + mActor->getName() == "TwnObj_HyruleCastleSealCover_A_01" || + mActor->getName() == "TwnObj_HyruleCastleMap_BossModel_A_01") { + _70 = 120; + dist = 100.0f; + } else if (mActor->getName().startsWith("MergedGrudge") && mActor->getMapObject()) { + int field_body_group = -1; + mActor->getMapObject()->getMubinIter().tryGetParamIntByKey(&field_body_group, + "FieldBodyGroup"); + if (field_body_group >= 0) { + dist = 500.0f; + } else { + _70 = 60; + dist = 10.0f; + } + } else if (mActor->getName() == "FldObj_GoronCannonSwitch_A_01" || + mActor->getName() == "FldObj_GoronCannon_A_01") { + _70 = 120; + dist = 50.0f; + } else if (mActor->getName().startsWith("Mannequin_")) { + _70 = 120; + dist = 5.0f; + } else if (mActor->getName().startsWith("KorokAnswerResponce") || + mActor->getName().startsWith("FldObj_AreaStopClimbing")) { + _70 = 900; + dist = 0.0f; + } else if (is_air_octa_platform) { + _24 = 0; + u32 hashid = 0; + if (!actor->getMapObjIter().tryGetParamUIntByKey(&hashid, "HashId") || + (hashid != 0x8F7A380B && hashid != 0x57F2CB61)) { + _78 = 85.0f; + mFlags26.set(0x30); + } + } + } + + auto* pm = map::PlacementMgr::instance(); + map::PlacementStruct1* ps1 = nullptr; + if (pm && pm->mPlacementActors && (ps1 = pm->mPlacementActors->mStruct1)) { + if (!ps1->mIsOneHitChallengeActive) { + if (ps1->mFlags.isOnBit(15)) { + if (actor->getName() == "DgnObj_DLC_IbutsuEx_Candle_A_01" || + actor->getName() == "TBox_Dungeon_Stone" || + actor->getName() == "DgnObj_DLC_SwordLight_A_01") { + _70 = 240; + dist = 10.0f; + } else if (actor->getName() == "DgnObj_DLC_IbutsuExLava_A_01" || + actor->getName() == "DgnObj_DLC_SwitchStep_A_01" || + actor->getName() == "DgnObj_DLC_CapShutter" || + actor->getName() == "DgnObj_DLC_IbutsuExD_AncientBallSwitch_A_01" || + actor->getName() == "DungeonPit") { + _70 = 120; + dist = 50.0f; + } else if (actor->getName() == "DgnObj_DLC_IbutsuEx_F_GoalSystem_A_01" || + actor->getName() == "DgnObj_DLC_GoalShield_A" || + actor->getName() == "Npc_DungeonPriestDlc2nd_Boss" || + actor->getName() == "DgnObj_DLC_IbutsuExFloor_A_02") { + _70 = 15; + dist = 30.0f; + } else if (actor->getName() == "DgnObj_DLC_IbutsuExOutWall_A_01") { + _70 = 240; + dist = 0.0f; + } else if (actor->getName().include("CylinderWall")) { + _70 = 240; + dist = 65.0f; + } else if (actor->getName() == "DgnObj_DLC_IbutsuEx_A_01") { + _70 = 240; + dist = 125.0f; + } else if (actor->getName() == "DgnObj_DLC_IbutsuEx_F_02") { + _70 = 60; + dist = 30.0f; + } else if (actor->getName() == "DgnObj_RemainsTerminalBody_A" || + actor->getName() == "FldObj_Terminal_A_01" || + actor->getName() == "DgnObj_DLC_ShutterFence_A_01" || + actor->getName() == "FldObj_DownloadTerminal_A_01" || + actor->getName() == "EventTag") { + _70 = 60; + dist = 30.0f; + } else if (actor->getName() == "DgnObj_DLC_IbutsuEx_E_Faucet_A_01" || + actor->getName() == "DgnObj_DLC_IbutsuEx_E_Faucet_A_02" || + actor->getName() == "SwitchTimeLag" || actor->getName() == "Area" || + actor->getName() == "ActorObserverTag") { + _70 = 60; + dist = 80.0f; + } else if (actor->getName() == "DgnObj_DLC_ShutterFence_A_01" || + actor->getName() == "DgnObj_DLC_ShutterFenceFrame_A_01") { + _70 = 60; + dist = 120.0f; + } else if (actor->getName() == "DgnObj_ElectricCable_FinalTrial" || + actor->getName() == "DgnObj_SwitchElectric0_FinalTrial" || + actor->getName() == "DgnObj_DLC_IbutsuEx_B_ElectricWire_A_02") { + _70 = 60; + dist = 90.0f; + } else if (actor->getName() == "DgnObj_DLC_IbutsuEx_B_MagnePoleAcceptor_A_01") { + _70 = 60; + dist = 75.0f; + } else if (actor->getName() == "ElectricGenerator") { + _70 = 60; + dist = 35.0f; + } else if (actor->getName() == "DgnObj_DLC_IbutsuExD_Hole_A_02") { + _70 = 60; + dist = 100.0f; + } else if (actor->getName() == "DgnObj_AncientBall_B_01") { + _70 = 60; + dist = 90.0f; + } else if (actor->getName() == "DgnObj_DLC_IbutsuEXD_FirePillar_A_01" || + actor->getName() == "DgnObj_DLC_IbutsuEXD_FirePillar_A_02") { + _70 = 60; + dist = 75.0f; + } else if (actor->getName() == "DgnObj_DLC_IbutsuExD_WallSpike_A_01" || + actor->getName() == "DgnObj_DLC_IbutsuExD_Cylinder_A_01") { + _70 = 60; + dist = 60.0f; + } else if (actor->getName() == "DgnObj_DLC_IbutsuEx_E_WaterPump_A_01" || + actor->getName() == "DgnObj_DungeonWater50x50_A_01") { + _70 = 60; + dist = 100.0f; + } else if (actor->getName() == "DgnObj_DLC_IbutsuEx_E_WaterPump_A_02") { + _70 = 60; + dist = 140.0f; + } else if (actor->getName() == "DgnObj_DLC_IbutsuEx_E_WaterPump_A_03") { + _70 = 60; + dist = 75.0f; + } else if (actor->getName() == "DgnObj_DLC_IbutsuEx_E_Shaft_A_01" || + actor->getName() == "DgnObj_DLC_IbutsuObj_StonePoleAcceptor_A_01") { + _70 = 60; + dist = 50.0f; + } else if (actor->getName() == "DgnObj_DLC_IbutsuEx_E_Scaffold_A_02" || + actor->getName() == "DgnObj_DLC_IbutsuEx_E_Scaffold_A_03") { + _70 = 60; + dist = 60.0f; + } + } + } else { + if (actor->getName() == "FldObj_FlagLarge_A_01") { + _70 = 120; + dist = 70.0f; + } else if (actor->getName() == "FldObj_SoilRock_MapTower_A_01" || + actor->getName() == "TwnObj_HunterHouseLamp_A_02") { + _70 = 900; + dist = 0.0f; + } else if (actor->getName() == "TwnObj_GoddesStatue_A_01" || + actor->getName() == "FireWoodDie") { + _70 = 120; + dist = 50.0f; + } else if (actor->getName().include("FenceWoodDamage") || + actor->getName().startsWith("FldObj_Damage")) { + _70 = 30; + dist = 13.0f; + } else if (actor->getName().include("ShieldFence")) { + _70 = 30; + dist = 30.0f; + } + } + } + _6c = dist * dist; + + float value_68 = 1.0; + if (mActor->getName().startsWith("Enemy_Lynel")) { + value_68 = 2.0; + } + _68 = value_68; + + if (actor->getName() == "Npc_RitoHatago001" || actor->getName() == "Npc_TabantaHatago001" || + actor->getName() == "Npc_FaronWoods001") { + mFlags8.set(0x100000000); + } + + if (actor->getName().startsWith("Npc_Zora") && !actor->getName().isEqual("Npc_Zora003") && + !actor->getName().isEqual("Npc_ZoraB001") && !actor->getName().isEqual("Npc_Zora004")) { + mFlags8.set(0x200000000); + } + + _74 = 0.0f; + if (actor->checkFlag(Actor::ActorFlag::_29) && actor->getProfile() == "NPC") { + _74 = 900.0f; + } + + if (actor->getName().startsWith("FldObj_FlagLarge")) { + _50 = 3.0f; + } +} + +LodState::~LodState() { + if (mOcclusionQueryCylinder) + delete mOcclusionQueryCylinder; +} + +// NON_MATCHING: ????? reordering +void LodState::initFlags() { + _28 = 1.0; + _40 = 0.0; + mFlags26.reset(2); + mFlags8.set(0xFFFFFFFF'00000000); + if (!mFlags8.isOn(0x20000000)) { + mFlags8.reset(0xEFFFFFFF); + mFlags8.set(0xCFC360BF); + mFlags8.reset(0x40); + } else { + mFlags8.set(0xEFFFFFFF); + mFlags8.set(0xEFC360BF); + mFlags8.reset(0x40); + } + mFlags8.reset(0x3C9F00); + mFlags8.set(0x4000); + mFlags14.set(0x2000000); + _60 = 0xFFFF; + _64 = -3; +} + +} // namespace ksys::act diff --git a/src/KingSystem/ActorSystem/LOD/actLodState.h b/src/KingSystem/ActorSystem/LOD/actLodState.h new file mode 100644 index 00000000..817e1a82 --- /dev/null +++ b/src/KingSystem/ActorSystem/LOD/actLodState.h @@ -0,0 +1,58 @@ +#pragma once + +#include +#include +#include "KingSystem/Utils/Types.h" + +namespace sead { +class Heap; +} + +namespace ksys { +class OcclusionQueryCylinder; +} + +namespace ksys::act { + +class Actor; + +class LodState { +public: + LodState(sead::Heap* heap, sead::BitFlag32 flags, Actor* actor, int disable_calc_skip_frame, + float x); + virtual ~LodState(); + +private: + void initFlags(); + + sead::BitFlag64 mFlags8; + sead::BitFlag32 mFlags10; + sead::BitFlag32 mFlags14; + sead::BitFlag32 mFlags18; + u32 _1c = 4; + u32 mActorType = 9; + u8 _24 = 0xff; + u8 _25; + sead::BitFlag16 mFlags26; + float _28 = 1.0; + Actor* mActor = nullptr; + OcclusionQueryCylinder* mOcclusionQueryCylinder = nullptr; + float _40 = 0.0; + float _44 = 0.0; + float _48 = 0.0; + float mDistanceScale = 1.0; + float _50 = 1.0; + float mDispDistance = 0.0; + float _58 = -1.0; + int mDisableCalcSkipFrame = 0; + u32 _60 = 0; + int _64 = -3; + float _68; + float _6c; + u32 _70; + float _74; + float _78 = 0.0; +}; +KSYS_CHECK_SIZE_NX150(LodState, 0x80); + +} // namespace ksys::act diff --git a/src/KingSystem/ActorSystem/actActor.h b/src/KingSystem/ActorSystem/actActor.h index e4d1ae95..3c109432 100644 --- a/src/KingSystem/ActorSystem/actActor.h +++ b/src/KingSystem/ActorSystem/actActor.h @@ -33,8 +33,10 @@ public: enum class ActorFlag { _18 = 0x18, _25 = 0x25, + _29 = 0x29, _2b = 0x2b, _2e = 0x2e, + _39 = 0x39, }; enum class ActorFlag2 { diff --git a/src/KingSystem/Map/mapObject.h b/src/KingSystem/Map/mapObject.h index 710c35c0..0bc7fb5e 100644 --- a/src/KingSystem/Map/mapObject.h +++ b/src/KingSystem/Map/mapObject.h @@ -102,7 +102,7 @@ public: f32 getDispDistance(const PlacementActors* pa, bool get_diameter, bool ignore_radius) const; f32 getDispDistance(const ActorData* data, bool get_diameter, u32 unused, bool ignore_radius) const; - f32 getDispDistance(bool get_diameter, bool ignore_radius) const; + f32 getDispDistance(bool get_diameter = false, bool ignore_radius = false) const; f32 getTraverseDist(const ActorData* data, bool get_diameter, u32 unused, bool ignore_radius) const; diff --git a/src/KingSystem/Map/mapPlacementMgr.h b/src/KingSystem/Map/mapPlacementMgr.h index 8a8f0220..9aa98458 100644 --- a/src/KingSystem/Map/mapPlacementMgr.h +++ b/src/KingSystem/Map/mapPlacementMgr.h @@ -93,11 +93,21 @@ public: }; KSYS_CHECK_SIZE_NX150(ActorData, 0x1A0); +// FIXME: move this to another header and rename +// FIXME: incomplete +class PlacementStruct1 { +public: + sead::BitFlag16 mFlags; + bool mIsOneHitChallengeActive; +}; + class PlacementActors { public: - u8 TEMP1[0x538]; + u8 _0[0xe0 - 0x0]; + PlacementStruct1* mStruct1; + u8 _e8[0x538 - 0xe8]; sead::SafeArray mActorData; - u8 TEMP2[0x46598]; + u8 _261b38[0x2a80d0 - 0x261b38]; }; KSYS_CHECK_SIZE_NX150(PlacementActors, 0x2A80D0); diff --git a/src/KingSystem/System/CMakeLists.txt b/src/KingSystem/System/CMakeLists.txt index b133dc38..d59a029b 100644 --- a/src/KingSystem/System/CMakeLists.txt +++ b/src/KingSystem/System/CMakeLists.txt @@ -12,6 +12,8 @@ target_sources(uking PRIVATE HavokWorkerMgr.h KingEditor.cpp KingEditor.h + OcclusionQueryCylinder.cpp + OcclusionQueryCylinder.h OverlayArena.cpp OverlayArena.h OverlayArenaSystem.cpp diff --git a/src/KingSystem/System/OcclusionQueryCylinder.cpp b/src/KingSystem/System/OcclusionQueryCylinder.cpp new file mode 100644 index 00000000..532b5925 --- /dev/null +++ b/src/KingSystem/System/OcclusionQueryCylinder.cpp @@ -0,0 +1 @@ +#include "KingSystem/System/OcclusionQueryCylinder.h" diff --git a/src/KingSystem/System/OcclusionQueryCylinder.h b/src/KingSystem/System/OcclusionQueryCylinder.h new file mode 100644 index 00000000..92e6f9b3 --- /dev/null +++ b/src/KingSystem/System/OcclusionQueryCylinder.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include "KingSystem/Utils/Types.h" + +namespace sead { +class Heap; +} + +namespace ksys { + +// FIXME: requires agl::cull::OcclusionQueryCylinder +class OcclusionQueryCylinder { +public: + OcclusionQueryCylinder(); + virtual ~OcclusionQueryCylinder(); + + void init(sead::Heap* heap); + +private: + u8 _8[0xa0 - 0x8]; +}; +KSYS_CHECK_SIZE_NX150(OcclusionQueryCylinder, 0xa0); + +} // namespace ksys