1#include "Sequence/WorldResourceLoader.h"
2
3#include <thread/seadThread.h>
4
5#include "Library/Base/StringUtil.h"
6#include "Library/File/FileUtil.h"
7#include "Library/Memory/HeapUtil.h"
8#include "Library/Resource/ResourceHolder.h"
9#include "Library/Yaml/ByamlIter.h"
10#include "Library/Yaml/ByamlUtil.h"
11
12const s32 priority = sead::Thread::cDefaultPriority;
13
14// for some reason tools/check doesn't show this?
15WorldResourceLoader::WorldResourceLoader(GameDataHolder* dataHolder) : mDataHolder(dataHolder) {
16 using WorldResourceLoaderFunctor =
17 al::FunctorV0M<WorldResourceLoader*, void (WorldResourceLoader::*)()>;
18
19 mWorldResourceLoader = new al::AsyncFunctorThread(
20 "WorldResourceLoader", WorldResourceLoaderFunctor{this, &WorldResourceLoader::loadResource},
21 priority, 0x100000, sead::CoreId::cMain);
22}
23
24WorldResourceLoader::~WorldResourceLoader() {
25 mIsCancelled = true;
26 mCurLoadCount = 0;
27
28 if (mWorldResourceLoader) {
29 delete mWorldResourceLoader;
30 mWorldResourceLoader = nullptr;
31 }
32
33 tryDestroyWorldResource();
34}
35
36// void WorldResourceLoader::loadResource() {}
37
38void WorldResourceLoader::cancelLoadWorldResource() {
39 mIsCancelled = true;
40 mCurLoadCount = 0;
41}
42
43void WorldResourceLoader::tryDestroyWorldResource() {
44 if (mWorldResourceHeap) {
45 bool isUseSpecialHeap;
46
47 if (mCapWorldHeap) {
48 al::removeResourceCategory("ワールド常駐");
49 mCapWorldHeap->destroy();
50 mCapWorldHeap = nullptr;
51 al::removeNamedHeap(heapName: "WorldResourceCap");
52 isUseSpecialHeap = false;
53 } else {
54 isUseSpecialHeap = true;
55 }
56
57 if (mWaterfallWorldHeap) {
58 al::removeResourceCategory("ホーム常駐[Waterfall]");
59 mWaterfallWorldHeap->destroy();
60 mWaterfallWorldHeap = nullptr;
61 al::removeNamedHeap(heapName: "WorldResourceWaterfall");
62 }
63
64 al::destroyWorldResourceHeap(removeCategory: isUseSpecialHeap);
65 mWorldResourceHeap = nullptr;
66 mLoadWorldId = -1;
67 }
68
69 al::resetCurrentCategoryName();
70}
71
72bool WorldResourceLoader::requestLoadWorldHomeStageResource(s32 loadWorldId, s32 scenario) {
73 if (mWaterfallWorldHeap)
74 return false;
75 if (!isEndLoadWorldResource())
76 return false;
77 if (mLoadWorldId == loadWorldId)
78 return false;
79 if (!al::tryGetBymlFromArcName("SystemData/WorldList", "WorldResource"))
80 return false;
81 if (!mWaterfallWorldHeap)
82 tryDestroyWorldResource();
83
84 if (loadWorldId || scenario != 1) {
85 if (!mWorldResourceHeap) {
86 al::createWorldResourceHeap(useCategory: true);
87 mWorldResourceHeap = al::getWorldResourceHeap();
88 }
89 } else {
90 al::createWorldResourceHeap(useCategory: false);
91
92 mWorldResourceHeap = al::getWorldResourceHeap();
93
94 mCapWorldHeap =
95 sead::FrameHeap::create(size: 0x1F400000, name: "ワールド常駐[帽子]", parent: mWorldResourceHeap, 8,
96 direction: sead::Heap::HeapDirection::cHeapDirection_Forward, false);
97 al::addNamedHeap(heap: mCapWorldHeap, heapName: "WorldResourceCap");
98
99 mWaterfallWorldHeap =
100 sead::FrameHeap::create(size: 0, name: "ワールド常駐[滝]", parent: mWorldResourceHeap, 8,
101 direction: sead::Heap::HeapDirection::cHeapDirection_Reverse, false);
102 al::addResourceCategory("ホーム常駐[Waterfall]", 512, mWaterfallWorldHeap);
103 al::addNamedHeap(heap: mWaterfallWorldHeap, heapName: "WorldResourceWaterfall");
104
105 al::addResourceCategory("ワールド常駐", 512, mCapWorldHeap);
106 }
107
108 if (loadWorldId < 0)
109 return false;
110
111 mScenarioNo = scenario;
112 mIsScenarioRes = true;
113 unkInt3 = 0;
114 unkPtr4 = nullptr;
115 unkPtr5 = nullptr;
116 requestLoadWorldResourceCommon(loadWorldId);
117 return true;
118}
119
120bool WorldResourceLoader::isEndLoadWorldResource() const {
121 return mWorldResourceLoader->isDone();
122}
123
124void WorldResourceLoader::requestLoadWorldResourceCommon(s32 loadWorldId) {
125 mLoadWorldId = loadWorldId;
126 mIsCancelled = false;
127 mWorldResourceLoader->start();
128}
129
130bool WorldResourceLoader::requestLoadWorldResource(s32 loadWorldId) {
131 if (!isEndLoadWorldResource())
132 return false;
133
134 mIsScenarioRes = false;
135 requestLoadWorldResourceCommon(loadWorldId);
136 return true;
137}
138
139// unused func
140void WorldResourceLoader::createResourcePlayer() {}
141
142void WorldResourceLoader::tryDestroyWorldResourceOnlyCap() {
143 if (mWorldResourceHeap) {
144 if (mCapWorldHeap) {
145 al::removeResourceCategory("ワールド常駐");
146 mCapWorldHeap->destroy();
147 mCapWorldHeap = nullptr;
148 al::removeNamedHeap(heapName: "WorldResourceCap");
149 }
150 al::addResourceCategory("ワールド常駐", 512, mWorldResourceHeap);
151 mLoadWorldId = -1;
152 }
153 al::clearFileLoaderEntry();
154 al::resetCurrentCategoryName();
155}
156
157f32 WorldResourceLoader::calcLoadPercent() const {
158 if (mCurLoadCount >= mMaxLoadCount)
159 return 101.0f;
160 else
161 return (mCurLoadCount * 100.0f) / mMaxLoadCount;
162}
163
164s32 WorldResourceLoader::getLoadWorldId() const {
165 return mLoadWorldId;
166}
167
168al::Resource* WorldResourceLoader::tryLoadResource(const char* resPath, const char* ext,
169 const char* category) {
170 if (ext) {
171 if (category)
172 return al::findOrCreateResourceCategory(path: resPath, category, ext);
173 return al::findOrCreateResource(path: resPath, ext);
174 } else {
175 return al::findOrCreateResource(path: resPath, ext: nullptr);
176 }
177}
178
179void WorldResourceLoader::loadWorldResource(s32 loadWorldId, s32 scenario, bool isScenarioResources,
180 const char* resourceCategory) {
181 nn::os::GetSystemTick();
182 nn::os::GetSystemTick();
183
184 u8* bymlData = al::tryGetBymlFromArcName("SystemData/WorldList", "WorldResource");
185
186 al::ByamlIter worldResourceIter(bymlData);
187 al::ByamlIter loadWorldIter;
188 al::getByamlIterByIndex(&loadWorldIter, worldResourceIter, loadWorldId);
189 al::ByamlIter resourceListIter;
190
191 if (isScenarioResources) {
192 if (!al::tryGetByamlIterByKey(&resourceListIter, loadWorldIter,
193 al::StringTmp<32>("Scenario%d", scenario).cstr()))
194 return;
195 } else {
196 al::getByamlIterByKey(&resourceListIter, loadWorldIter, "WorldResource");
197 }
198
199 s32 resSize = resourceListIter.getSize();
200 mMaxLoadCount = resSize;
201
202 for (s32 i = 0; i < resSize; i++) {
203 al::ByamlIter resEntry;
204 resourceListIter.tryGetIterByIndex(iter: &resEntry, index: i);
205
206 const char* resName = nullptr;
207 const char* resExt = nullptr;
208 resEntry.tryGetStringByKey(string: &resName, key: "Name");
209 resEntry.tryGetStringByKey(string: &resExt, key: "Ext");
210
211 tryLoadResource(resPath: resName, ext: resExt, category: resourceCategory);
212
213 if (mIsCancelled)
214 return;
215
216 mCurLoadCount = i;
217 }
218
219 mCurLoadCount = mMaxLoadCount;
220}
221
222f32 WorldResourceLoader::calcWorldResourceHeapSize() const {
223 return ((mWorldResourceHeap->getSize() - mWorldResourceHeap->getFreeSize()) * 0.00097656f) *
224 0.00097656f;
225}
226