summaryrefslogtreecommitdiff
path: root/src/KingSystem
diff options
context:
space:
mode:
authorLéo Lam <leo@leolam.fr>2026-09-28 03:39:31 +0200
committerLéo Lam <leo@leolam.fr>2026-10-06 03:19:39 +0200
commitc4c7c00e85df3137d57cc899302a160ff94fa71b (patch)
tree302fc5bbae0f9b9da17d1e41790b41b8fa44630a /src/KingSystem
parent38905c8c075ec4ed8f8fcf858aef46bc5e05f8e2 (diff)
aoc: Manager is ksys, the DLC managers stay game-side
aoc::Manager is created during engine start-up and called by gdt, map and StarterPackMgr; only game code uses HardModeManager and ChampionBalladManager. (AI assisted using Claude Fable 5.1 and Claude Opus 5.5)
Diffstat (limited to 'src/KingSystem')
-rw-r--r--src/KingSystem/AOC/CMakeLists.txt4
-rw-r--r--src/KingSystem/AOC/aocManager.cpp546
-rw-r--r--src/KingSystem/AOC/aocManager.h132
-rw-r--r--src/KingSystem/CMakeLists.txt1
-rw-r--r--src/KingSystem/GameData/gdtManager.cpp4
-rw-r--r--src/KingSystem/Map/mapLazyTraverseList.cpp8
-rw-r--r--src/KingSystem/Map/mapPlacementMap.cpp10
-rw-r--r--src/KingSystem/System/StarterPackMgr.cpp12
-rw-r--r--src/KingSystem/System/StarterPackMgr.h2
9 files changed, 701 insertions, 18 deletions
diff --git a/src/KingSystem/AOC/CMakeLists.txt b/src/KingSystem/AOC/CMakeLists.txt
new file mode 100644
index 00000000..4badc13f
--- /dev/null
+++ b/src/KingSystem/AOC/CMakeLists.txt
@@ -0,0 +1,4 @@
+target_sources(uking PRIVATE
+ aocManager.cpp
+ aocManager.h
+)
diff --git a/src/KingSystem/AOC/aocManager.cpp b/src/KingSystem/AOC/aocManager.cpp
new file mode 100644
index 00000000..c0c13f77
--- /dev/null
+++ b/src/KingSystem/AOC/aocManager.cpp
@@ -0,0 +1,546 @@
+#include "KingSystem/AOC/aocManager.h"
+#include <container/seadBuffer.h>
+#include <filedevice/seadFileDeviceMgr.h>
+#include <prim/seadStringBuilder.h>
+#include <resource/seadSharcArchiveRes.h>
+#include "KingSystem/Resource/resLoadRequest.h"
+#include "KingSystem/Resource/resResourceMgrTask.h"
+#include "KingSystem/Utils/InitTimeInfo.h"
+#include "KingSystem/Utils/SafeDelete.h"
+
+#ifdef NNSDK
+#include <filedevice/nin/seadNinAocFileDeviceNin.h>
+#include <nn/aoc.h>
+#include <nn/fs.h>
+#include <prim/seadStringUtil.h>
+#endif
+
+namespace ksys::aoc {
+
+namespace {
+
+struct DungeonInfo {
+ int number;
+ sead::SafeString flag;
+};
+
+util::InitConstants sInitConstants;
+DungeonInfo sDungeonInfoData[] = {
+ {120, "Defeat_OneHitDungeon001"},
+ {121, "BalladOfHeroGerudo_AppearDungeon03"},
+ {122, "Defeat_OneHitDungeon002"},
+ {123, "Defeat_OneHitDungeon003"},
+ {124, "BalladOfHeroZora_AppearDungeon01"},
+ {125, "BalladOfHeroZora_AppearDungeon02"},
+ {126, "BalladOfHeroZora_AppearDungeon03"},
+ {127, "BalladOfHeroRito_TargetHittingSuccess"},
+ {128, "BalladOfHeroRito_AppearDungeon03"},
+ {129, "BalladOfHeroRito_AppearDungeon02"},
+ {130, "BalladOfHeroGoron_FirstKillGolemR"},
+ {131, "BalladOfHeroGoron_AppearDungeon01"},
+ {132, "BalladOfHeroGoron_AppearDungeon03"},
+ {133, "BalladOfHeroGerudo_AppearDungeon02"},
+ {134, "BalladOfHeroGerudo_AppearDungeon01"},
+ {135, "Defeat_OneHitDungeon004"},
+};
+sead::Buffer<DungeonInfo> sDungeonInfo{sDungeonInfoData};
+constexpr int NumDungeons = 16;
+
+} // namespace
+
+SEAD_SINGLETON_DISPOSER_IMPL(Manager)
+
+Manager::Manager() : mVersionFile(), mGdtReinitSlot{this, &Manager::onGdtReinit} {
+ resetFlags();
+}
+
+Manager::~Manager() {
+ if (auto* gdm = gdt::Manager::instance())
+ gdm->removeReinitCallback(mGdtReinitSlot);
+
+ mAocMainFieldPackPrefix.deregister();
+ mAocPackPrefix.deregister();
+ mVersionFileDevPrefix.deregister();
+
+ if (mFileDevice) {
+ sead::FileDeviceMgr::instance()->unmount("aoc");
+ util::safeDelete(mFileDevice);
+ }
+
+#ifdef NNSDK
+ if (mAocFsCache) {
+ nn::fs::Unmount("aoc");
+ util::safeDelete(mAocFsCache);
+ }
+#endif
+}
+
+void Manager::resetFlags() {
+ mFlagAocVerAtLastPlay = gdt::InvalidHandle;
+ mFlagLatestAocVerPlayed = gdt::InvalidHandle;
+ mFlagHasAocVer1 = gdt::InvalidHandle;
+ mFlagHasAocVer2 = gdt::InvalidHandle;
+ mFlagHasAocVer3 = gdt::InvalidHandle;
+}
+
+void Manager::init(sead::Heap* heap) {
+#ifdef NNSDK
+ std::array<int, 2> dlc_info;
+ if (nn::aoc::ListAddOnContent(dlc_info.data(), 0, dlc_info.size()) == dlc_info.size() &&
+ (dlc_info[0] == 1 || dlc_info[1] == 1)) {
+ size_t cache_size = 0;
+ nn::fs::QueryMountAddOnContentCacheSize(&cache_size, 1);
+ const size_t cache_size_ = cache_size;
+ mAocFsCache = static_cast<u8*>(heap->tryAlloc(cache_size_, sizeof(void*)));
+
+ nn::fs::MountAddOnContent("aoc", 1, mAocFsCache, cache_size);
+
+ mFileDevice = new (heap) sead::NinAocFileDevice("aoc");
+ sead::FileDeviceMgr::instance()->mount(mFileDevice, "aoc");
+ loadVersionFile();
+ }
+#endif
+}
+
+void Manager::loadVersionFile() {
+ if (!mFileDevice)
+ return;
+
+ mVersionFileDevPrefix.registerPrefix("Aoc/0010/", mFileDevice, false);
+
+ res::LoadRequest req;
+ req.mRequester = "aocManager";
+ req._26 = false;
+ req.mAocFileDevice = mFileDevice;
+ const sead::SafeString path = "System/AocVersion.txt";
+ mVersionFile.file_handle.requestLoad(path, &req);
+}
+
+void Manager::loadAocMainFieldPack(OverlayArena* arena) {
+ if (!hasAoc3())
+ return;
+
+ auto* device = mFileDevice;
+ if (!device)
+ return;
+
+ res::LoadRequest req;
+ req.mRequester = "aocManager";
+ req._8 = true;
+ req._26 = false;
+ req.mAocFileDevice = device;
+ req.mArena = arena;
+ mAocMainFieldPack.requestLoad("Pack/AocMainField.pack", &req);
+}
+
+void Manager::registerAocMainFieldPack() {
+ mAocMainFieldPack.waitForReady();
+ mAocMainFieldPack.parseResource(nullptr);
+ if (mAocMainFieldPack.isSuccess())
+ mAocMainFieldPackPrefix.registerPrefix("Aoc/0010/", mAocMainFieldPack.getResource(), false);
+}
+
+void Manager::unloadAocMainFieldPack() {
+ mAocMainFieldPackPrefix.deregister();
+ mAocMainFieldPack.requestUnload();
+}
+
+sead::FileDevice* Manager::getFileDeviceForMapFile(const sead::SafeString& path) const {
+ if (!hasAoc2())
+ return nullptr;
+
+ auto* device = mFileDevice;
+
+ if (aocPackHasFile(path))
+ return nullptr;
+
+ if (path.startsWith("Map/MainField/"))
+ return device;
+
+ if (hasAoc3() && path.startsWith("Map/MainFieldDungeon/"))
+ return device;
+
+ if (isAocFile(path, "Map/", "Map/AocField/", "Map/MainFieldDungeon/", "Map/CDungeon/"))
+ return device;
+
+ return nullptr;
+}
+
+bool Manager::getFileDeviceForMap(sead::FileDevice** p_file_device, res::Handle** p_handle,
+ const sead::SafeString& path) {
+ if (!hasAoc2())
+ return false;
+
+ auto* device = mFileDevice;
+
+ if (path.startsWith("Map/MainField/")) {
+ if (mAocMainFieldPack.isSuccess())
+ *p_handle = &mAocMainFieldPack;
+ else
+ *p_file_device = device;
+ return true;
+ }
+
+ if (aocPackHasFile(path))
+ return false;
+
+ if (hasAoc3() && path.startsWith("Map/MainFieldDungeon/")) {
+ *p_file_device = device;
+ return true;
+ }
+
+ if (isAocFile(path, "Map/", "Map/AocField/", "Map/MainFieldDungeon/", "Map/CDungeon/")) {
+ *p_file_device = device;
+ return true;
+ }
+
+ return false;
+}
+
+sead::FileDevice* Manager::getFileDeviceForStaticCompound(const sead::SafeString& path) const {
+ if (!hasAoc2())
+ return nullptr;
+
+ auto* device = mFileDevice;
+
+ if (aocPackHasFile(path))
+ return nullptr;
+
+ if (isAocFile(path, "Physics/StaticCompound/", "Physics/StaticCompound/AocField/",
+ "Physics/StaticCompound/MainFieldDungeon/", "Physics/StaticCompound/CDungeon/")) {
+ return device;
+ }
+
+ return nullptr;
+}
+
+sead::FileDevice* Manager::getFileDeviceForTeraMesh(const sead::SafeString& path) const {
+ if (!hasAoc2())
+ return nullptr;
+
+ if (path.startsWith("Physics/TeraMeshRigidBody/AocField/"))
+ return mFileDevice;
+
+ return nullptr;
+}
+
+sead::FileDevice* Manager::getFileDeviceForNavMesh(const sead::SafeString& path) const {
+ if (!hasAoc2())
+ return nullptr;
+
+ auto* device = mFileDevice;
+
+ if (aocPackHasFile(path))
+ return nullptr;
+
+ if (isAocFile(path, "NavMesh/", "NavMesh/AocField/", "NavMesh/MainFieldDungeon/",
+ "NavMesh/CDungeon/")) {
+ return device;
+ }
+
+ return nullptr;
+}
+
+sead::FileDevice* Manager::getFileDeviceForTerrain(const sead::SafeString& path) const {
+ if (!hasAoc2())
+ return nullptr;
+
+ if (path.startsWith("Terrain/A/AocField"))
+ return mFileDevice;
+
+ return nullptr;
+}
+
+sead::FileDevice* Manager::getFileDeviceForGame(const sead::SafeString& path) const {
+ if (!hasAoc2())
+ return nullptr;
+
+ if (path.startsWith("Game/AocField/"))
+ return mFileDevice;
+
+ return nullptr;
+}
+
+sead::FileDevice* Manager::getFileDeviceForUI(const sead::SafeString& path) const {
+ if (!hasAoc3())
+ return nullptr;
+
+ if (path.startsWith("UI/StaffRollDLC/"))
+ return mFileDevice;
+
+ return nullptr;
+}
+
+bool Manager::isAocFile(const sead::SafeString& path, const sead::SafeString& dir,
+ const sead::SafeString& dir_aoc_field,
+ const sead::SafeString& dir_main_field_dungeon,
+ const sead::SafeString& dir_cdungeon) const {
+ if (!path.startsWith(dir))
+ return false;
+
+ if (path.startsWith(dir_aoc_field))
+ return true;
+
+ if (path.startsWith(dir_main_field_dungeon)) {
+ const auto rel_path = path.getPart(dir_main_field_dungeon.calcLength());
+ if (rel_path.startsWith("RemainsElectric"))
+ return false;
+ if (rel_path.startsWith("RemainsFire"))
+ return false;
+ if (rel_path.startsWith("RemainsWater"))
+ return false;
+ if (rel_path.startsWith("RemainsWind"))
+ return false;
+ return true;
+ }
+
+ if (path.startsWith(dir_cdungeon)) {
+ const auto rel_path = path.getPart(dir_cdungeon.calcLength());
+ return isAocDungeon(rel_path);
+ }
+
+ return false;
+}
+
+static bool isAocDungeonNumber(const sead::SafeString& number) {
+ int num;
+ sead::FixedSafeString<4> buffer;
+ buffer.copy(number, 3);
+ return sead::StringUtil::tryParseS32(&num, buffer, sead::StringUtil::CardinalNumber::Base10) &&
+ num >= 120;
+}
+
+bool Manager::isAocDungeon(const sead::SafeString& map_name) {
+ if (!map_name.startsWith("Dungeon"))
+ return true;
+ const auto number = map_name.getPart(sead::SafeString("Dungeon").calcLength());
+ return isAocDungeonNumber(number);
+}
+
+bool Manager::isAocMap(const sead::SafeString& map_type, const sead::SafeString& map_name) {
+ if (isAocField(map_type))
+ return true;
+
+ if (map_type == "MainFieldDungeon") {
+ if (map_name == "RemainsElectric")
+ return false;
+ if (map_name == "RemainsFire")
+ return false;
+ if (map_name == "RemainsWater")
+ return false;
+ if (map_name == "RemainsWind")
+ return false;
+ return true;
+ }
+
+ if (map_type == "CDungeon")
+ return isAocDungeon(map_name);
+
+ return false;
+}
+
+bool Manager::isAocField(const sead::SafeString& map_type) {
+ return map_type == "AocField";
+}
+
+sead::FileDevice* Manager::getFileDeviceForDungeonPack(const sead::SafeString& path) const {
+ if (!hasAoc3())
+ return nullptr;
+
+ auto* device = mFileDevice;
+
+ const sead::SafeString prefix = "Pack/";
+ const auto prefix_len = prefix.calcLength();
+
+ if (!path.startsWith(prefix))
+ return nullptr;
+
+ const auto rel_path = path.getPart(prefix_len);
+
+ if (rel_path.startsWith("Dungeon") && !isAocDungeon(rel_path))
+ device = nullptr;
+
+ return device;
+}
+
+void Manager::registerAocPack(res::Handle* pack) {
+ mAocPack = pack;
+ if (pack) {
+ mAocPackPrefix.registerPrefix("Aoc/0010/", pack->getResource(), true);
+ } else {
+ mAocPackPrefix.deregister();
+ }
+}
+
+bool Manager::aocPackHasFile(const sead::SafeString& path) const {
+ if (!mAocPack)
+ return false;
+
+ const auto* res = sead::DynamicCast<sead::SharcArchiveRes>(mAocPack->getResource());
+ if (!res)
+ return false;
+
+ sead::FixedStringBuilder<0x81> builder;
+ builder.copy(path.cstr());
+ res::ResourceMgrTask::instance()->addSExtensionPrefix(builder);
+ return res->isExistFile(builder);
+}
+
+bool Manager::changeMoviePath(sead::BufferedSafeString& path) const {
+ if (!hasAoc3())
+ return false;
+
+ const sead::SafeString prefix = "Movie/";
+ const auto prefix_len = prefix.calcLength();
+ if (!path.startsWith(prefix))
+ return false;
+
+ const auto rel_path = path.getPart(prefix_len);
+ if (!rel_path.startsWith("Demo6"))
+ return false;
+
+ path.prepend("aoc://");
+ return true;
+}
+
+bool Manager::parseVersion() {
+ if (!mVersionFile.readVersion())
+ return false;
+
+ if (mVersionFile.string.isEmpty()) {
+ mVersion = 0;
+ return true;
+ }
+
+ {
+ const int dot_index = mVersionFile.string.findIndex(".");
+ const int minor_index = dot_index + 1;
+ if (dot_index <= 0 || minor_index >= mVersionFile.string.calcLength()) {
+ mVersionFile.string.clear();
+ mVersion = 0;
+ return true;
+ }
+
+ u32 major, minor;
+ const auto parse = [&] {
+ sead::FixedSafeString<16> major_str;
+ major_str.copy(mVersionFile.string, dot_index);
+
+ constexpr auto base = sead::StringUtil::CardinalNumber::Base10;
+ if (!sead::StringUtil::tryParseU32(&major, major_str, base))
+ return false;
+
+ const auto minor_str = mVersionFile.string.getPart(minor_index);
+ if (!sead::StringUtil::tryParseU32(&minor, minor_str, base))
+ return false;
+
+ return true;
+ };
+
+ if (!parse()) {
+ mVersionFile.string.clear();
+ mVersion = 0;
+ return true;
+ }
+
+ mVersion = (major << 8) + minor;
+ }
+
+ checkVersion();
+ return true;
+}
+
+// NON_MATCHING: stack and duplicated branch -- volatile variables are painful
+void Manager::checkVersion() {
+ if (mVersion == 0)
+ return;
+
+ const auto fail = [this](VersionError error) {
+ mVersionFlags.setBit(error);
+ mVersion = 0;
+ };
+
+ if (mVersion < 0x300) {
+ fail(VersionError::TooOld);
+ } else if (mVersion >= 0x400) {
+ fail(VersionError::TooNew);
+ }
+
+ mVersionFlags.isOnBit(VersionError(VersionError::TooOld));
+ mVersionFlags.isOnBit(VersionError(VersionError::TooNew));
+}
+
+bool Manager::VersionFile::readVersion() {
+ if (!file_handle.requestedLoad())
+ return true;
+
+ if (file_handle.isSuccess()) {
+ auto* res = sead::DynamicCast<sead::DirectResource>(file_handle.getResource());
+ string.copy(reinterpret_cast<const char*>(res->getRawData()), res->getRawSize());
+ } else {
+ if (!file_handle.checkLoadStatus())
+ return false;
+ string.clear();
+ }
+
+ file_handle.requestUnload();
+ return true;
+}
+
+void Manager::initGameData() {
+ reinitFlags();
+ gdt::Manager::instance()->addReinitCallback(mGdtReinitSlot);
+}
+
+static const sead::SafeString& getDungeonFlag(int number) {
+ for (auto it = sDungeonInfo.begin(); it != sDungeonInfo.end(); ++it) {
+ if (it->number == number)
+ return it->flag;
+ }
+ return sead::SafeString::cEmptyString;
+}
+
+void Manager::reinitFlags() {
+ mFlagAocVerAtLastPlay = gdt::Manager::instance()->getS32Handle("AoCVerAtLastPlay");
+ mFlagLatestAocVerPlayed = gdt::Manager::instance()->getS32Handle("LatestAoCVerPlayed");
+ mFlagHasAocVer1 =
+ gdt::Manager::instance()->getBoolHandle(GameDataFlag::text(GameDataFlag::HasAoCVer1));
+ mFlagHasAocVer2 =
+ gdt::Manager::instance()->getBoolHandle(GameDataFlag::text(GameDataFlag::HasAoCVer2));
+ mFlagHasAocVer3 =
+ gdt::Manager::instance()->getBoolHandle(GameDataFlag::text(GameDataFlag::HasAoCVer3));
+
+ for (int i = 0; i < mDLCPositions.size(); ++i) {
+ gdt::FlagHandle handle = gdt::InvalidHandle;
+
+ if (i < NumDungeons) {
+ if (mDLCPositions[i].flag_handle == gdt::InvalidHandle)
+ continue;
+
+ handle = gdt::Manager::instance()->getBoolHandle(getDungeonFlag(i + 120));
+ }
+
+ mDLCPositions[i].flag_handle = handle;
+ }
+}
+
+void Manager::setGameDataFlags() const {
+ gdt::Manager::instance()->setS32(mVersion, mFlagAocVerAtLastPlay);
+
+ s32 latest_ver;
+ if (gdt::Manager::instance()->getS32(mFlagLatestAocVerPlayed, &latest_ver)) {
+ if (u32(latest_ver) < mVersion)
+ gdt::Manager::instance()->setS32(mVersion, mFlagLatestAocVerPlayed);
+ }
+
+ const auto ver = mVersion;
+ gdt::Manager::instance()->setBool(ver >= 0x100, mFlagHasAocVer1);
+ gdt::Manager::instance()->setBool(ver >= 0x200, mFlagHasAocVer2);
+ gdt::Manager::instance()->setBool(ver >= 0x300, mFlagHasAocVer3);
+}
+
+void Manager::onGdtReinit(gdt::Manager::ReinitEvent* event) {
+ reinitFlags();
+}
+
+} // namespace ksys::aoc
diff --git a/src/KingSystem/AOC/aocManager.h b/src/KingSystem/AOC/aocManager.h
new file mode 100644
index 00000000..9f1623f3
--- /dev/null
+++ b/src/KingSystem/AOC/aocManager.h
@@ -0,0 +1,132 @@
+#pragma once
+
+#include <container/seadSafeArray.h>
+#include <heap/seadDisposer.h>
+#include <math/seadVector.h>
+#include <prim/seadBitFlag.h>
+#include <prim/seadEnum.h>
+#include <prim/seadSafeString.h>
+#include "KingSystem/GameData/gdtManager.h"
+#include "KingSystem/Resource/resHandle.h"
+#include "KingSystem/Resource/resResourceMgrTask.h"
+#include "KingSystem/Utils/Types.h"
+
+namespace sead {
+class FileDevice;
+}
+
+namespace ksys {
+class OverlayArena;
+}
+
+namespace ksys::aoc {
+
+// TODO
+class Manager {
+ SEAD_SINGLETON_DISPOSER(Manager)
+ Manager();
+ ~Manager();
+
+public:
+ void init(sead::Heap* heap);
+
+ u32 getVersion() const { return mVersion; }
+
+ /// @return Whether the Master Trials DLC is supported.
+ bool hasAoc2() const { return mVersion >= 0x200; }
+
+ /// @return Whether the Champion's Ballad DLC is supported.
+ bool hasAoc3() const { return mVersion >= 0x300; }
+
+ void loadAocMainFieldPack(OverlayArena* arena);
+ void registerAocMainFieldPack();
+ void unloadAocMainFieldPack();
+
+ sead::FileDevice* getFileDeviceForMapFile(const sead::SafeString& path) const;
+ bool getFileDeviceForMap(sead::FileDevice** p_file_device, res::Handle** p_handle,
+ const sead::SafeString& path);
+ sead::FileDevice* getFileDeviceForStaticCompound(const sead::SafeString& path) const;
+ sead::FileDevice* getFileDeviceForTeraMesh(const sead::SafeString& path) const;
+ sead::FileDevice* getFileDeviceForNavMesh(const sead::SafeString& path) const;
+ sead::FileDevice* getFileDeviceForTerrain(const sead::SafeString& path) const;
+ sead::FileDevice* getFileDeviceForGame(const sead::SafeString& path) const;
+ sead::FileDevice* getFileDeviceForUI(const sead::SafeString& path) const;
+
+ bool isAocFile(const sead::SafeString& path, const sead::SafeString& dir,
+ const sead::SafeString& dir_aoc_field,
+ const sead::SafeString& dir_main_field_dungeon,
+ const sead::SafeString& dir_cdungeon) const;
+ static bool isAocDungeon(const sead::SafeString& map_name);
+ static bool isAocMap(const sead::SafeString& map_type, const sead::SafeString& map_name);
+ static bool isAocField(const sead::SafeString& map_type);
+
+ sead::FileDevice* getFileDeviceForDungeonPack(const sead::SafeString& path) const;
+ void registerAocPack(res::Handle* pack);
+ bool aocPackHasFile(const sead::SafeString& path) const;
+
+ bool changeMoviePath(sead::BufferedSafeString& path) const;
+
+ void parseAocMainFieldStaticInfo(const al::ByamlIter& iter);
+ // TODO: figure out what this does
+ bool getSomePos(sead::Vector3f* translate, u32* p_mask, u32* mask);
+
+ bool parseVersion();
+ void setGameDataFlags() const;
+
+private:
+ SEAD_ENUM(GameDataFlag, AoCVerAtLastPlay ,LatestAoCVerPlayed ,HasAoCVer1 ,HasAoCVer2 ,HasAoCVer3)
+ SEAD_ENUM(VersionError, TooNew, TooOld)
+
+ struct DLCPosition {
+ sead::Vector3f translate = sead::Vector3f::zero;
+ sead::Vector3f rotate = sead::Vector3f::zero;
+ sead::Vector3f translate2 = sead::Vector3f::zero;
+ float scale = 0.0;
+ gdt::FlagHandle flag_handle = gdt::InvalidHandle;
+ };
+ KSYS_CHECK_SIZE_NX150(DLCPosition, 0x2c);
+
+ struct VersionFile {
+ bool readVersion();
+
+ res::Handle file_handle;
+ sead::FixedSafeString<16> string;
+ };
+ KSYS_CHECK_SIZE_NX150(VersionFile, 0x78);
+
+ void loadVersionFile();
+ void checkVersion();
+
+ void resetFlags();
+ void initGameData();
+ void reinitFlags();
+ void onGdtReinit(gdt::Manager::ReinitEvent* event);
+
+ sead::FileDevice* mFileDevice{};
+
+ res::FileDevicePrefix mVersionFileDevPrefix;
+ VersionFile mVersionFile{};
+ u32 mVersion{};
+
+ res::Handle mAocMainFieldPack;
+ res::FileDevicePrefix mAocMainFieldPackPrefix;
+ res::Handle* mAocPack{};
+ res::FileDevicePrefix mAocPackPrefix;
+
+ sead::SafeArray<DLCPosition, 20> mDLCPositions;
+
+ gdt::FlagHandle mFlagAocVerAtLastPlay{};
+ gdt::FlagHandle mFlagLatestAocVerPlayed{};
+ gdt::FlagHandle mFlagHasAocVer1{};
+ gdt::FlagHandle mFlagHasAocVer2{};
+ gdt::FlagHandle mFlagHasAocVer3{};
+ gdt::Manager::ReinitSignal::Slot mGdtReinitSlot;
+
+ sead::BitFlag8 mVersionFlags{};
+#ifdef NNSDK
+ u8* mAocFsCache{};
+#endif
+};
+KSYS_CHECK_SIZE_NX150(Manager, 0x598);
+
+} // namespace ksys::aoc
diff --git a/src/KingSystem/CMakeLists.txt b/src/KingSystem/CMakeLists.txt
index f1d8fddc..93a1d8db 100644
--- a/src/KingSystem/CMakeLists.txt
+++ b/src/KingSystem/CMakeLists.txt
@@ -3,6 +3,7 @@ add_subdirectory(GameData)
add_subdirectory(Resource)
add_subdirectory(ActorSystem)
+add_subdirectory(AOC)
add_subdirectory(Camera)
add_subdirectory(Chemical)
add_subdirectory(Ecosystem)
diff --git a/src/KingSystem/GameData/gdtManager.cpp b/src/KingSystem/GameData/gdtManager.cpp
index c067801d..ff628407 100644
--- a/src/KingSystem/GameData/gdtManager.cpp
+++ b/src/KingSystem/GameData/gdtManager.cpp
@@ -8,7 +8,7 @@
#include <thread/seadThreadUtil.h>
#include <time/seadTickTime.h>
#include <type_traits>
-#include "Game/DLC/aocManager.h"
+#include "KingSystem/AOC/aocManager.h"
#include "KingSystem/GameData/gdtSaveMgr.h"
#include "KingSystem/GameData/gdtTriggerParam.h"
#include "KingSystem/Map/mapMubinIter.h"
@@ -426,7 +426,7 @@ void Manager::fixQuestFlags() {
}
void Manager::fixQuestFlagsDlc2() {
- if (uking::aoc::Manager::instance()->hasAoc3())
+ if (aoc::Manager::instance()->hasAoc3())
return;
enum {
diff --git a/src/KingSystem/Map/mapLazyTraverseList.cpp b/src/KingSystem/Map/mapLazyTraverseList.cpp
index a87d2b94..985628e1 100644
--- a/src/KingSystem/Map/mapLazyTraverseList.cpp
+++ b/src/KingSystem/Map/mapLazyTraverseList.cpp
@@ -1,6 +1,6 @@
#include "KingSystem/Map/mapLazyTraverseList.h"
-#include "Game/DLC/aocManager.h"
+#include "KingSystem/AOC/aocManager.h"
#include "KingSystem/GameData/gdtManager.h"
namespace ksys::map {
@@ -10,9 +10,9 @@ LazyTraverseList::LazyTraverseList(sead::Heap* heap) {
sead::SafeString path = "Map/MainField/LazyTraverseList.mubin";
ksys::res::LoadRequest request;
- if (uking::aoc::Manager::instance())
- uking::aoc::Manager::instance()->getFileDeviceForMap(&request.mAocFileDevice,
- &request.mPackHandle, path);
+ if (aoc::Manager::instance())
+ aoc::Manager::instance()->getFileDeviceForMap(&request.mAocFileDevice, &request.mPackHandle,
+ path);
handle.load(path, &request);
diff --git a/src/KingSystem/Map/mapPlacementMap.cpp b/src/KingSystem/Map/mapPlacementMap.cpp
index e9bf6765..05461527 100644
--- a/src/KingSystem/Map/mapPlacementMap.cpp
+++ b/src/KingSystem/Map/mapPlacementMap.cpp
@@ -1,7 +1,7 @@
#include "KingSystem/Map/mapPlacementMap.h"
#include <prim/seadScopedLock.h>
#include <thread/seadReadWriteLock.h>
-#include "Game/DLC/aocManager.h"
+#include "KingSystem/AOC/aocManager.h"
#include "KingSystem/Map/mapObject.h"
#include "KingSystem/Physics/StaticCompound/physStaticCompound.h"
#include "KingSystem/Physics/StaticCompound/physStaticCompoundRigidBodyGroup.h"
@@ -201,8 +201,8 @@ bool PlacementMap::loadDynamicMap() {
} else {
path.append("_Dynamic_NoGrudgeMerge.mubin");
}
- if (uking::aoc::Manager::instance()) {
- arg.mAocFileDevice = uking::aoc::Manager::instance()->getFileDeviceForMapFile(path);
+ if (aoc::Manager::instance()) {
+ arg.mAocFileDevice = aoc::Manager::instance()->getFileDeviceForMapFile(path);
}
return mDynamicMubinRes.requestLoad(path, &arg, 0);
}
@@ -288,8 +288,8 @@ bool PlacementMap::loadStaticCompound(int hksc_idx, bool auto_gen_mu, bool req_a
path.format("Physics/StaticCompound/%s-%d.hksc", mFolderAndFile.cstr(), hksc_idx);
}
}
- if (uking::aoc::Manager::instance()) {
- arg.mAocFileDevice = uking::aoc::Manager::instance()->getFileDeviceForStaticCompound(path);
+ if (aoc::Manager::instance()) {
+ arg.mAocFileDevice = aoc::Manager::instance()->getFileDeviceForStaticCompound(path);
}
return mRes[hksc_idx].mRes.requestLoad(path, &arg, 0);
diff --git a/src/KingSystem/System/StarterPackMgr.cpp b/src/KingSystem/System/StarterPackMgr.cpp
index 2948f05a..9ca0690b 100644
--- a/src/KingSystem/System/StarterPackMgr.cpp
+++ b/src/KingSystem/System/StarterPackMgr.cpp
@@ -117,8 +117,8 @@ void StarterPackMgr::loadTitleBGPacks() {
}
void StarterPackMgr::loadAocMainFieldPack() {
- if (uking::aoc::Manager::instance())
- uking::aoc::Manager::instance()->loadAocMainFieldPack(mOverlayArena);
+ if (aoc::Manager::instance())
+ aoc::Manager::instance()->loadAocMainFieldPack(mOverlayArena);
}
void StarterPackMgr::unloadBootupGraphicsPack() {
@@ -192,8 +192,8 @@ void StarterPackMgr::setPackToTitleBGPack() {
mTitleBGLangPack.waitForReady();
mTitleBGLangPack.parseResource(nullptr);
- if (uking::aoc::Manager::instance())
- uking::aoc::Manager::instance()->registerAocMainFieldPack();
+ if (aoc::Manager::instance())
+ aoc::Manager::instance()->registerAocMainFieldPack();
res::registerPackExtension(false, "");
res::setResourceMgrPack(&mTitleBGPack);
@@ -207,8 +207,8 @@ void StarterPackMgr::unloadTitleBGAndAocMainFieldPacksAndStuff() {
mTitleBGPack.requestUnload();
mTitleBGLangPack.requestUnload();
- if (uking::aoc::Manager::instance())
- uking::aoc::Manager::instance()->unloadAocMainFieldPack();
+ if (aoc::Manager::instance())
+ aoc::Manager::instance()->unloadAocMainFieldPack();
for (int x = 0; x < 5; x++)
res::ResourceMgrTask::instance()->waitForTaskQueuesToEmpty();
diff --git a/src/KingSystem/System/StarterPackMgr.h b/src/KingSystem/System/StarterPackMgr.h
index a579ac6d..28feb8c2 100644
--- a/src/KingSystem/System/StarterPackMgr.h
+++ b/src/KingSystem/System/StarterPackMgr.h
@@ -3,7 +3,7 @@
#include <devenv/seadEnvUtil.h>
#include <heap/seadExpHeap.h>
#include <prim/seadSafeString.h>
-#include "Game/DLC/aocManager.h"
+#include "KingSystem/AOC/aocManager.h"
#include "KingSystem/Resource/resEntryFactory.h"
#include "KingSystem/Resource/resHandle.h"
#include "KingSystem/Resource/resLoadRequest.h"