From 2c47c801f68c72cdda659772d88d9c164bf1afb1 Mon Sep 17 00:00:00 2001 From: theo3 Date: Mon, 26 Oct 2020 01:19:55 -0700 Subject: [PATCH] partially implement ecosystem --- data/uking_functions.csv | 22 +-- src/KingSystem/CMakeLists.txt | 1 + src/KingSystem/Ecosystem/CMakeLists.txt | 4 + src/KingSystem/Ecosystem/ecoSystem.cpp | 198 ++++++++++++++++++++++++ src/KingSystem/Ecosystem/ecoSystem.h | 126 +++++++++++++++ src/KingSystem/Ecosystem/ecoUtil.cpp | 10 ++ src/KingSystem/Ecosystem/ecoUtil.h | 10 ++ src/KingSystem/World/CMakeLists.txt | 3 + src/KingSystem/World/worldManager.h | 83 ++++++++++ 9 files changed, 446 insertions(+), 11 deletions(-) create mode 100644 src/KingSystem/Ecosystem/ecoSystem.cpp create mode 100644 src/KingSystem/Ecosystem/ecoSystem.h create mode 100644 src/KingSystem/Ecosystem/ecoUtil.cpp create mode 100644 src/KingSystem/Ecosystem/ecoUtil.h create mode 100644 src/KingSystem/World/CMakeLists.txt create mode 100644 src/KingSystem/World/worldManager.h diff --git a/data/uking_functions.csv b/data/uking_functions.csv index 8f48fa5d..45327903 100644 --- a/data/uking_functions.csv +++ b/data/uking_functions.csv @@ -77847,18 +77847,18 @@ 0x0000007100e412d0,sub_7100E412D0,416, 0x0000007100e41470,sub_7100E41470,276, 0x0000007100e41584,sub_7100E41584,248, -0x0000007100e4167c,Ecosystem::Disposer::dtor,100, -0x0000007100e416e0,Ecosystem::Disposer::dtorDelete,108, -0x0000007100e4174c,Ecosystem::createInstance,208, +0x0000007100e4167c,Ecosystem::Disposer::dtor,100,_ZN4ksys3eco9Ecosystem18SingletonDisposer_D2Ev +0x0000007100e416e0,Ecosystem::Disposer::dtorDelete,108,_ZN4ksys3eco9Ecosystem18SingletonDisposer_D0Ev +0x0000007100e4174c,Ecosystem::createInstance,208,_ZN4ksys3eco9Ecosystem14createInstanceEPN4sead4HeapE 0x0000007100e4181c,Ecosystem::init,1056, -0x0000007100e41c3c,Ecosystem::calc_stubbed,4, -0x0000007100e41c40,eco::getCurrentAreaNum,292, +0x0000007100e41c3c,Ecosystem::calc_stubbed,4,_ZN4ksys3eco9Ecosystem4calcEv +0x0000007100e41c40,eco::getCurrentAreaNum,292,_ZNK4ksys3eco9Ecosystem17getCurrentAreaNumEPNS0_10EcoMapInfoEff? 0x0000007100e41d64,Ecosystem::__auto1,636, -0x0000007100e41fe0,Ecosystem::getStatusEffectInfo,384, -0x0000007100e42160,Ecosystem::getAreaNameByNum,120, -0x0000007100e421d8,Ecosystem::getClimateNameByNum,120, -0x0000007100e42250,Ecosystem::__auto2,120, -0x0000007100e422c8,sub_7100E422C8,356, +0x0000007100e41fe0,Ecosystem::getStatusEffectInfo,384,_ZNK4ksys3eco9Ecosystem19getStatusEffectInfoENS0_12StatusEffectEiPNS0_16StatusEffectInfoE? +0x0000007100e42160,Ecosystem::getAreaNameByNum,120,_ZNK4ksys3eco9Ecosystem16getAreaNameByNumEiPPKc +0x0000007100e421d8,Ecosystem::getClimateNameByNum,120,_ZNK4ksys3eco9Ecosystem19getClimateNameByNumEiPPKc +0x0000007100e42250,Ecosystem::__auto2,120,_ZNK4ksys3eco9Ecosystem20getEnvSoundNameByNumEiPPKc +0x0000007100e422c8,sub_7100E422C8,356,_ZNK4ksys3eco9Ecosystem17getEcoTraitsByNumEiPNS0_15EcosystemTraitsE? 0x0000007100e4242c,sub_7100E4242C,96, 0x0000007100e4248c,sub_7100E4248C,104, 0x0000007100e424f4,Ecosystem::LevelSensor::ctor,40,_ZN4ksys3eco11LevelSensorC1Ev @@ -80401,7 +80401,7 @@ 0x0000007100ee788c,Actor::createDrops,36, 0x0000007100ee78b0,eco::getEcosystemActorName,1192, 0x0000007100ee7d58,eco::sub_7100EE7D58,344, -0x0000007100ee7eb0,eco::currentAreaNumIs64,56, +0x0000007100ee7eb0,eco::currentAreaNumIs64,56,_ZN4ksys3eco18currentAreaNumIs64ERKN4sead7Vector3IfEE 0x0000007100ee7ee8,sub_7100EE7EE8,2112, 0x0000007100ee8728,sub_7100EE8728,388, 0x0000007100ee88ac,wm::isRainingOrSnowingOrThunderStorm,200, diff --git a/src/KingSystem/CMakeLists.txt b/src/KingSystem/CMakeLists.txt index cc426f8a..1aba9d67 100644 --- a/src/KingSystem/CMakeLists.txt +++ b/src/KingSystem/CMakeLists.txt @@ -11,3 +11,4 @@ add_subdirectory(Sound) add_subdirectory(System) add_subdirectory(Terrain) add_subdirectory(Utils) +add_subdirectory(World) \ No newline at end of file diff --git a/src/KingSystem/Ecosystem/CMakeLists.txt b/src/KingSystem/Ecosystem/CMakeLists.txt index bb6801e4..f45f7d24 100644 --- a/src/KingSystem/Ecosystem/CMakeLists.txt +++ b/src/KingSystem/Ecosystem/CMakeLists.txt @@ -1,4 +1,8 @@ target_sources(uking PRIVATE ecoLevelSensor.cpp ecoLevelSensor.h + ecoSystem.cpp + ecoSystem.h + ecoUtil.cpp + ecoUtil.h ) diff --git a/src/KingSystem/Ecosystem/ecoSystem.cpp b/src/KingSystem/Ecosystem/ecoSystem.cpp new file mode 100644 index 00000000..96680112 --- /dev/null +++ b/src/KingSystem/Ecosystem/ecoSystem.cpp @@ -0,0 +1,198 @@ +#include "KingSystem/Ecosystem/ecoSystem.h" + +namespace ksys::eco { + +static const char* sStatusEffectNames[22] = {"StatusEffect", + "LifeRecover", + "LifeMaxUp", + "GutsPerformance", + "ResistHot", + "ResistCold", + "ResistElectric", + "MovingSpeed", + "SwimingSpeed", + "SwimingAnimRate", + "ClimbingSpeed", + "AttackUp", + "DefenseUp", + "Quietness", + "DesertMovingSpeed", + "ThrowingPower", + "SnowMovingSpeed", + "GutsRecoverSpeed", + "ResistThunder", + "ArmorChargeAttackAddLevel", + "ReduceAncientEnemyDamge", + "MaterSwordAttackUp"}; + +SEAD_SINGLETON_DISPOSER_IMPL(Ecosystem) + +void Ecosystem::calc() {} + +// NON_MATCHING: FP instructions rearranged. +s32 Ecosystem::getCurrentAreaNum(EcoMapInfo* info, f32 posX, f32 posZ) const { + posX = sead::clamp(posX, -5000.0F, 4999.0F); + posZ = sead::clamp(posZ, -4000.0F, 4000.0F); + f32 epsilon1 = (posX + 5000.0F >= 0.0F) ? 0.5F : -0.5F; + f32 epsilon2 = (posZ + 4000.0F >= 0.0F) ? 0.5F : -0.5F; + s32 x = posX + 5000.0F + epsilon1; + s32 z = (posZ + 4000.0F + epsilon2) / info->mHeader->divisor; + + s32 row = sead::clamp(z, (s32)0, info->mHeader->num_rows - 2); + + if (info->mHeader->divisor == 10) + x = x / 10; + + s32* offsets = (s32*)info->mRowOffsets + row; + s32 val0 = offsets[0]; + s32 val1 = offsets[1]; + + if (val0 >= val1) + return -1; + + Segment* segmentEnd = reinterpret_cast((char*)info->mRows + 2 * val1); + Segment* segment = reinterpret_cast((char*)info->mRows + 2 * val0); + s32 totalLength = 0; + while (true) { + totalLength += segment->length; + if (x < totalLength) + return segment->value; + ++segment; + if (segment >= segmentEnd) + return -1; + } +} + +void Ecosystem::getAreaNameByNum(s32 areaNum, const char** out) const { + *out = nullptr; + + if (areaNum < 0 || (s32)mAreaDataSize <= areaNum) + return; + + al::ByamlIter iter; + + if (mAreaDataIter->tryGetIterByIndex(&iter, areaNum)) + iter.tryGetStringByKey(out, "Area"); +} + +// NON_MATCHING: Equivalent, minor conditional differences and register usage +void Ecosystem::getStatusEffectInfo(StatusEffect statusEffectIdx, s32 idx, + eco::StatusEffectInfo* out) const { + al::ByamlIter listIter; + if (!mStatusEffectListIter->tryGetIterByIndex(&listIter, 0)) + return; + + al::ByamlIter iter; + if (!listIter.tryGetIterByKey(&iter, sStatusEffectNames[statusEffectIdx])) { + out->ng = true; + out->val._s32 = 0; + return; + } + + bool special = false; + al::ByamlIter result; + if (iter.tryGetIterByIndex(&result, 0)) { + result.tryGetBoolByKey(&special, "special"); + if (special) { + out->ng = true; + out->val._s32 = 0; + return; + } + } + + al::ByamlIter result2; + if (!iter.tryGetIterByIndex(&result2, 1)) + return; + + al::ByamlIter a1; + result2.tryGetIterByIndex(&a1, 0); + s32 numLevels = a1.getSize(); + if (numLevels > 0) { + if (idx > numLevels - 1) { + idx = numLevels - 1; + } + } else { + out->ng = true; + out->val._s32 = 0; + return; + } + + al::ByamlIter dict; + if (!a1.tryGetIterByIndex(&dict, idx)) + return; + + f32 val = 0; + s32 val2 = 0; + + if (dict.tryGetFloatByKey(&val, "val")) { + out->ng = false; + out->val._f32 = val; + return; + } + + if (dict.tryGetIntByKey(&val2, "val")) { + out->ng = false; + out->val._f32 = val2; + } +} + +void Ecosystem::getClimateNameByNum(s32 areaNum, const char** out) const { + *out = nullptr; + + if (areaNum < 0 || (s32)mAreaDataSize <= areaNum) + return; + + al::ByamlIter iter; + + if (mAreaDataIter->tryGetIterByIndex(&iter, areaNum)) + iter.tryGetStringByKey(out, "Climate"); +} + +void Ecosystem::getEnvSoundNameByNum(s32 areaNum, const char** out) const { + *out = nullptr; + + if (areaNum < 0 || (s32)mAreaDataSize <= areaNum) + return; + + al::ByamlIter iter; + + if (mAreaDataIter->tryGetIterByIndex(&iter, areaNum)) + iter.tryGetStringByKey(out, "EnvSound"); +} + +void Ecosystem::getEcoTraitsByNum(s32 areaNum, EcosystemTraits* out) const { + out->idx = 0; + + if (areaNum < 0 || (s32)mAreaDataSize <= areaNum) + return; + + al::ByamlIter areaIter; + if (!mAreaDataIter->tryGetIterByIndex(&areaIter, areaNum)) + return; + + al::ByamlIter iter; + if (!areaIter.tryGetIterByKey(&iter, "Procedural")) + return; + + s32 size = iter.getSize(); + if (size < 0) + return; + + for (s32 i = 0; i != size; ++i) { + if (++out->idx > 3) + out->idx = 0; + + EcoTraitGrp* grp = &out->grps[i]; + grp->terrain_material._int = -1; + grp->vegetation._int = -1; + grp->geology._int = -1; + grp->defoliation._int = -1; + + iter.tryGetIntByKey(&grp->terrain_material._int, "terrain_material"); + iter.tryGetIntByKey(&grp->vegetation._int, "vegetation"); + iter.tryGetIntByKey(&grp->geology._int, "geology"); + iter.tryGetIntByKey(&grp->defoliation._int, "defoliation"); + } +} + +} // namespace ksys::eco diff --git a/src/KingSystem/Ecosystem/ecoSystem.h b/src/KingSystem/Ecosystem/ecoSystem.h new file mode 100644 index 00000000..c7b85aee --- /dev/null +++ b/src/KingSystem/Ecosystem/ecoSystem.h @@ -0,0 +1,126 @@ +#pragma once + +#include +#include +#include +#include +#include "KingSystem/Ecosystem/ecoLevelSensor.h" +#include "KingSystem/Utils/Byaml/Byaml.h" + +namespace ksys::eco { + +struct EcoMapHeader { + u32 unknown; + s32 num_rows; + s32 divisor; +}; +struct Segment { + s16 value; + s16 length; +}; + +class EcoMapInfo { +public: + EcoMapHeader* mHeader; + u32* mRowOffsets; + char* mRows; +}; + +enum ActorType {}; + +struct ActorSpawnInfo; + +union StatusEffectVal { + f32 _f32; + s32 _s32; +}; + +struct StatusEffectInfo { + bool ng; + StatusEffectVal val; +}; + +enum StatusEffect { + StatusEffect_LifeRecover = 0x0, + StatusEffect_LifeMaxUp = 0x1, + StatusEffect_GutsPerformance = 0x2, + StatusEffect_ResistHot = 0x3, + StatusEffect_ResistCold = 0x4, + StatusEffect_ResistElectric = 0x5, + StatusEffect_MovingSpeed = 0x6, + StatusEffect_SwimingSpeed = 0x7, + StatusEffect_SwimingAnimRate = 0x8, + StatusEffect_ClimbingSpeed = 0x9, + StatusEffect_AttackUp = 0xA, + StatusEffect_DefenseUp = 0xB, + StatusEffect_Quietness = 0xC, + StatusEffect_DesertMovingSpeed = 0xD, + StatusEffect_ThrowingPower = 0xE, + StatusEffect_SnowMovingSpeed = 0xF, + StatusEffect_GutsRecoverSpeed = 0x10, + StatusEffect_ResistThunder = 0x11, + StatusEffect_ArmorChargeAttackAddLevel = 0x12, + StatusEffect_ReduceAncientEnemyDamge = 0x13, + StatusEffect_MaterSwordAttackUp = 0x14, +}; + +union EcoTrait { + s32 _int; + struct { + u8 _b0; + u8 _b1; + u8 _b2; + u8 _b3; + }; +}; + +struct EcoTraitGrp { + EcoTrait terrain_material; + EcoTrait vegetation; + EcoTrait geology; + EcoTrait defoliation; +}; + +struct EcosystemTraits { + u32 idx; + EcoTraitGrp grps[3]; +}; +KSYS_CHECK_SIZE_NX150(EcosystemTraits, 0x34); + +class Ecosystem { + SEAD_SINGLETON_DISPOSER(Ecosystem) +private: + Ecosystem() = default; + virtual ~Ecosystem(); + +public: + res::Handle mFieldMapAreaFile; + res::Handle mAreaDataFile; + res::Handle mMapTowerFile; + res::Handle mStatusEffectListFile; + res::Handle mLoadBalancerFile; + + al::ByamlIter* mAreaDataIter{}; + u32 mAreaDataSize{}; + al::ByamlIter* mStatusEffectListIter{}; + LevelSensor* mLevelSensor{}; + EcoMapInfo mFieldMapArea{}; + EcoMapInfo mMapTower{}; + EcoMapInfo mLoadBalancer{}; + u32 mFlags{}; + u32 mLast; + + void init(); + void calc(); + + s32 getCurrentAreaNum(EcoMapInfo* info, f32 posX, f32 posZ) const; + + void getActorSpawnInfo(s32 areaNum, ActorType actorTypeIdx, ActorSpawnInfo* out) const; + void getStatusEffectInfo(StatusEffect statusEffectIdx, s32 idx, StatusEffectInfo* out) const; + void getAreaNameByNum(s32 areaNum, const char** out) const; + void getClimateNameByNum(s32 areaNum, const char** out) const; + void getEnvSoundNameByNum(s32 areaNum, const char** out) const; + void getEcoTraitsByNum(s32 areaNum, EcosystemTraits* out) const; +}; + +} // namespace ksys::eco diff --git a/src/KingSystem/Ecosystem/ecoUtil.cpp b/src/KingSystem/Ecosystem/ecoUtil.cpp new file mode 100644 index 00000000..f651de6a --- /dev/null +++ b/src/KingSystem/Ecosystem/ecoUtil.cpp @@ -0,0 +1,10 @@ +#include "KingSystem/Ecosystem/ecoUtil.h" + +namespace ksys::eco { + +bool currentAreaNumIs64(const sead::Vector3f& pos) { + return Ecosystem::instance()->getCurrentAreaNum(&Ecosystem::instance()->mFieldMapArea, pos.x, + pos.z) == 64; +} + +} // namespace ksys::eco diff --git a/src/KingSystem/Ecosystem/ecoUtil.h b/src/KingSystem/Ecosystem/ecoUtil.h new file mode 100644 index 00000000..225e2de4 --- /dev/null +++ b/src/KingSystem/Ecosystem/ecoUtil.h @@ -0,0 +1,10 @@ +#pragma once + +#include +#include "KingSystem/Ecosystem/ecoSystem.h" + +namespace ksys::eco { + +bool currentAreaNumIs64(const sead::Vector3f& pos); + +} // namespace ksys::eco diff --git a/src/KingSystem/World/CMakeLists.txt b/src/KingSystem/World/CMakeLists.txt new file mode 100644 index 00000000..451e82b6 --- /dev/null +++ b/src/KingSystem/World/CMakeLists.txt @@ -0,0 +1,3 @@ +target_sources(uking PRIVATE + worldManager.h +) diff --git a/src/KingSystem/World/worldManager.h b/src/KingSystem/World/worldManager.h new file mode 100644 index 00000000..ca0a2e98 --- /dev/null +++ b/src/KingSystem/World/worldManager.h @@ -0,0 +1,83 @@ +#pragma once + +#include +#include +#include "KingSystem/Resource/resHandle.h" +#include "KingSystem/Utils/ParamIO.h" +#include "agl/Utils/aglAtomicPtrArray.h" +#include "agl/Utils/aglParameter.h" +#include "agl/Utils/aglParameterObj.h" + +namespace ksys::world { + +class Climate {}; + +class WorldInfo : public ParamIO { +public: + WorldInfo() : ParamIO("winfo", 0) {} + ~WorldInfo(); + + bool ParamIO_m0() override { return true; } + + res::Handle mResHandle; + u32 mNumClimates = 0; + Climate* mClimates = nullptr; +}; + +class DungeonEnv : public ParamIO { +public: + DungeonEnv() : ParamIO("dgenv", 0) {} + ~DungeonEnv(); + + bool ParamIO_m0() override { return true; } + + res::Handle mResHandle; + + agl::utl::Parameter mLightLongitude; + agl::utl::Parameter> mDungeonSize; + agl::utl::Parameter> mString538; + agl::utl::ParameterObj mDungeonEnvObj; + sead::PtrArray mgrs{}; + sead::DirectResource* mInfoRes = nullptr; +}; + +// FIXME: incomplete +class Manager : public sead::hostio::Node { + Manager(); + + WorldInfo mWorldInfo; + DungeonEnv mDungeonEnv; + + agl::utl::AtomicPtrArray mAtomicPtrArray{0, 0}; + u32 _5e0 = 1; + u32 mCalcType = 3; + sead::FixedSizeJQ mJobQueue; + f32 mWindPowerIf78C = 5.0; + f32 mTempDirectDayExtra = 100000.0; + f32 mTempDirectNightExtra = 100000.0; + f32 mTempDirectDay = 100000.0; + f32 mTempDirectNight = 100000.0; + s32 _794; + s32 mStageType = 0; + s32 mStageType2 = 0; + u8 mGameSceneInitialised = 0; + sead::Vector3f mPrevPlayerPos{}; + sead::Vector3f mPlayerPos{}; + sead::Vector3f mPrevCameraPos{}; + sead::Vector3f mCameraPos{}; + f32 _770 = 0.0; + s32 _778 = 0; + s32 _78c = 0; + s32 _7ac = 0; + void* _7a4 = nullptr; + void* _79c = nullptr; + f32 mWindPowerAocField = 0.75; + u8 mWorldInfoLoaded = 0; + u8 mWeatherType = 0xFF; + u8 _7d2 = 0; + u8 _7d3 = 1; + u8 _7d4 = 0; + u8 mInFinalTrialBossBattleArea = 0; +}; + +} // namespace ksys::world