1#pragma once
2
3#include <container/seadRingBuffer.h>
4#include <container/seadSafeArray.h>
5#include <filedevice/seadArchiveFileDevice.h>
6#include <framework/seadMethodTree.h>
7#include <heap/seadDisposer.h>
8#include <prim/seadDelegateEventSlot.h>
9#include <prim/seadTypedBitFlag.h>
10#include <thread/seadMutex.h>
11#include <type_traits>
12#include "KingSystem/GameData/gdtFlagHandle.h"
13#include "KingSystem/GameData/gdtTriggerParam.h"
14#include "KingSystem/Resource/resHandle.h"
15#include "KingSystem/System/CoreInfo.h"
16#include "KingSystem/System/KingEditor.h"
17#include "KingSystem/Utils/Byaml/Byaml.h"
18#include "KingSystem/Utils/Types.h"
19
20namespace sead {
21class Framework;
22class MethodTreeMgr;
23} // namespace sead
24
25namespace ksys::map {
26class MubinIter;
27}
28
29namespace ksys::gdt {
30
31namespace detail {
32
33template <typename T>
34struct SetterTraits {
35 static constexpr bool isVectorType() {
36 return std::is_same_v<T, sead::Vector2f> || std::is_same_v<T, sead::Vector3f> ||
37 std::is_same_v<T, sead::Vector4f>;
38 }
39
40 static constexpr bool isStringType() { return std::is_same_v<T, const char*>; }
41
42 static constexpr bool isInlineType() {
43 return std::is_same_v<T, bool> || std::is_same_v<T, s32> || std::is_same_v<T, f32> ||
44 isStringType();
45 }
46
47 using ArgType = std::conditional_t<isInlineType(), T, const T&>;
48 using WrapperArgType = std::conditional_t<isStringType(), const sead::SafeString&, ArgType>;
49 using NoCheckForceArgType = T;
50
51 static ArgType convertValue(WrapperArgType v) {
52 if constexpr (isStringType())
53 return v.cstr();
54 else
55 return v;
56 }
57};
58
59} // namespace detail
60
61class TriggerParamRef {
62public:
63 TriggerParamRef(TriggerParam** param_1, TriggerParam** param, bool check_permissions,
64 bool propagate_param_1_changes, bool change_only_once)
65 : mParam1(param_1), mParam(param), mCheckPermissions(check_permissions),
66 mPropagateParam1Changes(propagate_param_1_changes), mChangeOnlyOnce(change_only_once) {}
67
68 virtual ~TriggerParamRef() = default;
69
70 class Proxy {
71 public:
72 TriggerParam* getBuffer() const { return mUseParam1 ? *mRef.mParam1 : *mRef.mParam; }
73 TriggerParam* getBuffer0() const { return *mRef.mParam; }
74 TriggerParam* getBuffer1() const { return *mRef.mParam1; }
75
76 // region Value getters
77
78#define PROXY_GET_SET_IMPL_(GET_NAME, SET_NAME, TYPE) \
79 bool GET_NAME(TYPE* value, s32 index) const { \
80 return getBuffer()->GET_NAME(value, index, mRef.mCheckPermissions); \
81 } \
82 bool GET_NAME(TYPE* value, s32 array_index, s32 index) const { \
83 return getBuffer()->GET_NAME(value, array_index, index, mRef.mCheckPermissions); \
84 } \
85 bool GET_NAME(TYPE* value, const sead::SafeString& name) const { \
86 return getBuffer()->GET_NAME(value, name, mRef.mCheckPermissions); \
87 } \
88 bool GET_NAME(TYPE* value, const sead::SafeString& array_name, s32 index) const { \
89 return getBuffer()->GET_NAME(value, array_name, index, mRef.mCheckPermissions); \
90 } \
91 \
92 bool SET_NAME(TYPE const& value, s32 idx, bool bypass_one_trigger_check = false) { \
93 if (mRef.mChangeOnlyOnce) \
94 return false; \
95 if (!getBuffer1()->SET_NAME(value, idx, mRef.mCheckPermissions, bypass_one_trigger_check)) \
96 return false; \
97 if (mRef.mPropagateParam1Changes) \
98 getBuffer0()->SET_NAME(value, idx, mRef.mCheckPermissions, bypass_one_trigger_check); \
99 return true; \
100 } \
101 bool SET_NAME(TYPE const& value, s32 array_idx, s32 idx, \
102 bool bypass_one_trigger_check = false) { \
103 if (mRef.mChangeOnlyOnce) \
104 return false; \
105 if (!getBuffer1()->SET_NAME(value, array_idx, idx, mRef.mCheckPermissions, \
106 bypass_one_trigger_check)) \
107 return false; \
108 if (mRef.mPropagateParam1Changes) \
109 getBuffer0()->SET_NAME(value, array_idx, idx, mRef.mCheckPermissions, \
110 bypass_one_trigger_check); \
111 return true; \
112 } \
113 bool SET_NAME(TYPE const& value, const sead::SafeString& name, \
114 bool bypass_one_trigger_check = false) { \
115 if (mRef.mChangeOnlyOnce) \
116 return false; \
117 if (!getBuffer1()->SET_NAME(value, name, mRef.mCheckPermissions, true, \
118 bypass_one_trigger_check)) \
119 return false; \
120 if (mRef.mPropagateParam1Changes) \
121 getBuffer0()->SET_NAME(value, name, mRef.mCheckPermissions, true, \
122 bypass_one_trigger_check); \
123 return true; \
124 } \
125 bool SET_NAME(TYPE const& value, const sead::SafeString& name, s32 idx, \
126 bool bypass_one_trigger_check = false) { \
127 if (mRef.mChangeOnlyOnce) \
128 return false; \
129 if (!getBuffer1()->SET_NAME(value, name, idx, mRef.mCheckPermissions, true, \
130 bypass_one_trigger_check)) \
131 return false; \
132 if (mRef.mPropagateParam1Changes) \
133 getBuffer0()->SET_NAME(value, name, idx, mRef.mCheckPermissions, true, \
134 bypass_one_trigger_check); \
135 return true; \
136 }
137
138 PROXY_GET_SET_IMPL_(getBool, setBool, bool)
139 PROXY_GET_SET_IMPL_(getS32, setS32, s32)
140 PROXY_GET_SET_IMPL_(getF32, setF32, f32)
141 PROXY_GET_SET_IMPL_(getStr, setStr, char const*)
142 PROXY_GET_SET_IMPL_(getStr64, setStr64, char const*)
143 PROXY_GET_SET_IMPL_(getStr256, setStr256, char const*)
144 PROXY_GET_SET_IMPL_(getVec2f, setVec2f, sead::Vector2f)
145 PROXY_GET_SET_IMPL_(getVec3f, setVec3f, sead::Vector3f)
146 PROXY_GET_SET_IMPL_(getVec4f, setVec4f, sead::Vector4f)
147
148#undef PROXY_GET_SET_IMPL_
149
150#define PROXY_RESET_IMPL_(NAME) \
151 bool NAME(s32 idx) { return getBuffer1()->NAME(idx, mRef.mCheckPermissions); } \
152 bool NAME(s32 idx, s32 sub_idx) { \
153 return getBuffer1()->NAME(idx, sub_idx, mRef.mCheckPermissions); \
154 } \
155 bool NAME(const sead::SafeString& name) { \
156 return getBuffer1()->NAME(name, mRef.mCheckPermissions); \
157 } \
158 bool NAME(const sead::SafeString& name, s32 sub_idx) { \
159 return getBuffer1()->NAME(name, sub_idx, mRef.mCheckPermissions); \
160 }
161
162 PROXY_RESET_IMPL_(resetBool)
163 PROXY_RESET_IMPL_(resetS32)
164 PROXY_RESET_IMPL_(resetF32)
165 PROXY_RESET_IMPL_(resetStr)
166 PROXY_RESET_IMPL_(resetStr64)
167 PROXY_RESET_IMPL_(resetStr256)
168 PROXY_RESET_IMPL_(resetVec2f)
169 PROXY_RESET_IMPL_(resetVec3f)
170 PROXY_RESET_IMPL_(resetVec4f)
171
172#undef PROXY_RESET_IMPL_
173
174 private:
175 friend class TriggerParamRef;
176 Proxy(const TriggerParamRef& ref, bool param1) : mUseParam1(param1), mRef(ref) {}
177
178 bool mUseParam1;
179 const TriggerParamRef& mRef;
180 };
181
182 Proxy get() const { return Proxy(*this, false); }
183 Proxy get1() const { return Proxy(*this, true); }
184
185 void setBuffers(TriggerParam** param1, TriggerParam** param) {
186 mParam1 = param1;
187 mParam = param;
188 }
189
190 bool shouldCheckPermissions() const { return mCheckPermissions; }
191 bool shouldPropagateParam1Changes() const { return mPropagateParam1Changes; }
192 bool shouldChangeOnlyOnce() const { return mChangeOnlyOnce; }
193
194 void setCheckPermissions(bool on) { mCheckPermissions = on; }
195 void setPropagateParam1Changes(bool on) { mPropagateParam1Changes = on; }
196 void setChangeOnlyOnce(bool on) { mChangeOnlyOnce = on; }
197
198private:
199 TriggerParam** mParam1;
200 TriggerParam** mParam;
201 bool mCheckPermissions;
202 bool mPropagateParam1Changes;
203 bool mChangeOnlyOnce;
204};
205KSYS_CHECK_SIZE_NX150(TriggerParamRef, 0x20);
206
207class IManager {
208public:
209 virtual ~IManager() = 0;
210};
211
212inline IManager::~IManager() = default;
213
214class Manager : public IManager, public KingEditorComponent {
215 SEAD_SINGLETON_DISPOSER(Manager)
216 Manager();
217 ~Manager() override;
218 const char* getName() const override { return "GameData"; }
219 void syncData(char* data) override;
220
221public:
222 struct ResetEvent {
223 virtual ~ResetEvent() = default;
224 TriggerParam* param = nullptr;
225 };
226
227 struct ReinitEvent {
228 virtual ~ReinitEvent() = default;
229 };
230
231 using ResetSignal = sead::DelegateEvent<ResetEvent*>;
232 using ReinitSignal = sead::DelegateEvent<ReinitEvent*>;
233
234 void init(sead::Heap* heap, sead::Framework* framework);
235 void calc();
236
237 void addReinitCallback(ReinitSignal::Slot& slot);
238 void removeReinitCallback(ReinitSignal::Slot& slot);
239
240 void setCurrentRupeeFlagName(const sead::SafeString& name);
241 void requestResetAllFlagsToInitial();
242
243 /// Checks whether quest flags (e.g. Kass shrine quest flags) are set or cleared properly
244 /// and takes any action necessary to fix them.
245 void fixQuestFlags();
246 void fixQuestFlagsDlc2();
247
248 sead::Heap* getGameDataHeap() const { return mGameDataHeap; }
249 sead::Heap* getSaveAreaHeap() const { return mSaveAreaHeap; }
250 sead::Heap* getGameDataComHeap() const { return mGameDataComHeap; }
251
252 TriggerParamRef& getParam() { return mParam; }
253 TriggerParamRef& getParamBypassPerm() { return mParamBypassPerm; }
254
255#define GDT_GET_HANDLE_(NAME, GET_IDX_NAME) \
256 FlagHandle NAME(const sead::SafeString& name) const { \
257 const auto prefix = mCurrentFlagHandlePrefix; \
258 const auto hash = sead::HashCRC32::calcStringHash(name); \
259 return makeFlagHandle(prefix, mParam.get1().getBuffer()->GET_IDX_NAME(hash)); \
260 }
261
262 GDT_GET_HANDLE_(getBoolHandle, TriggerParam::getBoolIdx)
263 GDT_GET_HANDLE_(getS32Handle, TriggerParam::getS32Idx)
264 GDT_GET_HANDLE_(getF32Handle, TriggerParam::getF32Idx)
265 GDT_GET_HANDLE_(getStrHandle, TriggerParam::getStrIdx)
266 GDT_GET_HANDLE_(getStr64Handle, TriggerParam::getStr64Idx)
267 GDT_GET_HANDLE_(getStr256Handle, TriggerParam::getStr256Idx)
268 GDT_GET_HANDLE_(getVec2fHandle, TriggerParam::getVec2fIdx)
269 GDT_GET_HANDLE_(getVec3fHandle, TriggerParam::getVec3fIdx)
270 GDT_GET_HANDLE_(getVec4fHandle, TriggerParam::getVec4fIdx)
271
272 GDT_GET_HANDLE_(getBoolArrayHandle, TriggerParam::getBoolArrayIdx)
273 GDT_GET_HANDLE_(getS32ArrayHandle, TriggerParam::getS32ArrayIdx)
274 GDT_GET_HANDLE_(getF32ArrayHandle, TriggerParam::getF32ArrayIdx)
275 GDT_GET_HANDLE_(getStrArrayHandle, TriggerParam::getStrArrayIdx)
276 GDT_GET_HANDLE_(getStr64ArrayHandle, TriggerParam::getStr64ArrayIdx)
277 GDT_GET_HANDLE_(getStr256ArrayHandle, TriggerParam::getStr256ArrayIdx)
278 GDT_GET_HANDLE_(getVec2fArrayHandle, TriggerParam::getVec2fArrayIdx)
279 GDT_GET_HANDLE_(getVec3fArrayHandle, TriggerParam::getVec3fArrayIdx)
280 GDT_GET_HANDLE_(getVec4fArrayHandle, TriggerParam::getVec4fArrayIdx)
281
282#undef GDT_GET_HANDLE_
283
284#define GDT_GET_(NAME, T) \
285 bool NAME(FlagHandle handle, T* value, bool debug = false, \
286 bool ignore_trigger_param_result = false) { \
287 return unwrapHandle<false>(handle, debug, [&](u32 idx, TriggerParamRef& ref) { \
288 const bool result = ref.get().NAME(value, idx); \
289 return ignore_trigger_param_result || result; \
290 }); \
291 } \
292 bool NAME(FlagHandle handle, T* value, s32 sub_idx, bool debug = false, \
293 bool ignore_trigger_param_result = false) { \
294 return unwrapHandle<false>(handle, debug, [&](u32 idx, TriggerParamRef& ref) { \
295 const bool result = ref.get().NAME(value, idx, sub_idx); \
296 return ignore_trigger_param_result || result; \
297 }); \
298 }
299
300 GDT_GET_(getBool, bool)
301 GDT_GET_(getS32, s32)
302 GDT_GET_(getF32, f32)
303 GDT_GET_(getStr, char const*)
304 GDT_GET_(getStr64, char const*)
305 GDT_GET_(getStr256, char const*)
306 GDT_GET_(getVec2f, sead::Vector2f)
307 GDT_GET_(getVec3f, sead::Vector3f)
308 GDT_GET_(getVec4f, sead::Vector4f)
309
310#undef GDT_GET_
311
312#define GDT_SET_(NAME, TRAITS) \
313 /* Setters (by handle) */ \
314 KSYS_ALWAYS_INLINE bool NAME(TRAITS::ArgType value, FlagHandle handle, bool debug, \
315 bool force) { \
316 if (mBitFlags.isOn(BitFlag::_40000)) \
317 return false; \
318 return unwrapHandle<true>(handle, debug, [&](u32 idx, TriggerParamRef& ref) { \
319 return ref.get().NAME(value, idx, force); \
320 }); \
321 } \
322 bool NAME(TRAITS::ArgType value, FlagHandle handle) { \
323 return NAME(value, handle, false, false); \
324 } \
325 bool NAME##NoCheck(TRAITS::ArgType value, FlagHandle handle) { \
326 return NAME(value, handle, true, false); \
327 } \
328 bool NAME##NoCheckForce(TRAITS::NoCheckForceArgType value, FlagHandle handle) { \
329 return NAME(value, handle, true, true); \
330 } \
331 /* Setters for arrays (by handle) */ \
332 KSYS_ALWAYS_INLINE bool NAME(TRAITS::ArgType value, FlagHandle handle, bool debug, bool force, \
333 s32 sub_idx) { \
334 if (mBitFlags.isOn(BitFlag::_40000)) \
335 return false; \
336 return unwrapHandle<true>(handle, debug, [&](u32 idx, TriggerParamRef& ref) { \
337 return ref.get().NAME(value, idx, sub_idx, force); \
338 }); \
339 } \
340 bool NAME(TRAITS::ArgType value, FlagHandle handle, s32 sub_idx) { \
341 return NAME(value, handle, false, false, sub_idx); \
342 } \
343 bool NAME##NoCheck(TRAITS::ArgType value, FlagHandle handle, s32 sub_idx) { \
344 return NAME(value, handle, true, false, sub_idx); \
345 } \
346 bool NAME##NoCheckForce(TRAITS::NoCheckForceArgType value, FlagHandle handle, s32 sub_idx) { \
347 return NAME(value, handle, true, true, sub_idx); \
348 } \
349 /* Setters (by name) */ \
350 KSYS_ALWAYS_INLINE bool NAME(TRAITS::ArgType value, const sead::SafeString& name, bool debug, \
351 bool force) { \
352 if (mBitFlags.isOn(BitFlag::_40000)) \
353 return false; \
354 auto& ref = debug ? getParamBypassPerm() : getParam(); \
355 return ref.get().NAME(value, name, force); \
356 } \
357 bool NAME(TRAITS::ArgType value, const sead::SafeString& name); \
358 bool NAME##_(TRAITS::ArgType value, const sead::SafeString& name); \
359 bool NAME##NoCheck(TRAITS::ArgType value, const sead::SafeString& name); \
360 bool NAME##NoCheck_(TRAITS::ArgType value, const sead::SafeString& name); \
361 bool NAME##NoCheckForce(TRAITS::NoCheckForceArgType value, const sead::SafeString& name); \
362 /* Setters for arrays (by name) */ \
363 KSYS_ALWAYS_INLINE bool NAME(TRAITS::ArgType value, const sead::SafeString& name, bool debug, \
364 bool force, s32 sub_idx) { \
365 if (mBitFlags.isOn(BitFlag::_40000)) \
366 return false; \
367 auto& ref = debug ? getParamBypassPerm() : getParam(); \
368 return ref.get().NAME(value, name, sub_idx, force); \
369 } \
370 bool NAME(TRAITS::ArgType value, const sead::SafeString& name, s32 sub_idx); \
371 bool NAME##_(TRAITS::ArgType value, const sead::SafeString& name, s32 sub_idx); \
372 bool NAME##NoCheck(TRAITS::ArgType value, const sead::SafeString& name, s32 sub_idx); \
373 bool NAME##NoCheckForce(TRAITS::NoCheckForceArgType value, const sead::SafeString& name, \
374 s32 sub_idx); \
375 \
376 bool NAME(TRAITS::WrapperArgType value, FlagHandle handle, bool debug) { \
377 if (debug) { \
378 onChangedByDebug(); \
379 return NAME##NoCheckForce(TRAITS::convertValue(value), handle); \
380 } \
381 return NAME(TRAITS::convertValue(value), handle); \
382 } \
383 bool NAME(TRAITS::WrapperArgType value, const sead::SafeString& name, bool debug) { \
384 if (debug) { \
385 onChangedByDebug(); \
386 return NAME##NoCheckForce(TRAITS::convertValue(value), name); \
387 } \
388 return NAME(TRAITS::convertValue(value), name); \
389 } \
390 inline bool NAME##Special(TRAITS::WrapperArgType value, const sead::SafeString& name, \
391 bool debug, bool force = false) { \
392 if (debug) { \
393 onChangedByDebug(); \
394 auto& ref = debug ? getParamBypassPerm() : getParam(); \
395 return ref.get().NAME(TRAITS::convertValue(value), name, force); \
396 } \
397 return NAME(TRAITS::convertValue(value), name); \
398 } \
399 \
400 bool NAME(TRAITS::WrapperArgType value, FlagHandle handle, bool debug, s32 sub_idx) { \
401 if (debug) { \
402 onChangedByDebug(); \
403 return NAME##NoCheckForce(TRAITS::convertValue(value), handle, sub_idx); \
404 } \
405 return NAME(TRAITS::convertValue(value), handle, sub_idx); \
406 } \
407 bool NAME(TRAITS::WrapperArgType value, const sead::SafeString& name, bool debug, \
408 s32 sub_idx) { \
409 if (debug) { \
410 onChangedByDebug(); \
411 return NAME##NoCheckForce(TRAITS::convertValue(value), name, sub_idx); \
412 } \
413 return NAME(TRAITS::convertValue(value), name, sub_idx); \
414 }
415
416 GDT_SET_(setBool, detail::SetterTraits<bool>)
417 GDT_SET_(setS32, detail::SetterTraits<s32>)
418 GDT_SET_(setF32, detail::SetterTraits<f32>)
419 GDT_SET_(setStr, detail::SetterTraits<const char*>)
420 GDT_SET_(setStr64, detail::SetterTraits<const char*>)
421 GDT_SET_(setStr256, detail::SetterTraits<const char*>)
422 GDT_SET_(setVec2f, detail::SetterTraits<sead::Vector2f>)
423 GDT_SET_(setVec3f, detail::SetterTraits<sead::Vector3f>)
424 GDT_SET_(setVec4f, detail::SetterTraits<sead::Vector4f>)
425
426#undef GDT_SET_
427
428#define GDT_RESET_(NAME) \
429 bool NAME(const sead::SafeString& name); \
430 bool NAME##_(const sead::SafeString& name); \
431 bool NAME(const sead::SafeString& name, int sub_idx); \
432 KSYS_ALWAYS_INLINE bool NAME##_(FlagHandle handle, bool debug) { \
433 if (mBitFlags.isOn(BitFlag::_40000)) \
434 return false; \
435 return unwrapHandle<false>( \
436 handle, debug, [&](u32 idx, TriggerParamRef& ref) { return ref.get().NAME(idx); }); \
437 } \
438 inline bool NAME(FlagHandle handle) { return NAME##_(handle, false); } \
439 inline bool NAME##NoCheck(FlagHandle handle) { return NAME##_(handle, true); } \
440 \
441 KSYS_ALWAYS_INLINE bool NAME##_(FlagHandle handle, bool debug, s32 sub_idx) { \
442 if (mBitFlags.isOn(BitFlag::_40000)) \
443 return false; \
444 return unwrapHandle<false>(handle, debug, [&](u32 idx, TriggerParamRef& ref) { \
445 return ref.get().NAME(idx, sub_idx); \
446 }); \
447 } \
448 inline bool NAME(FlagHandle handle, s32 sub_idx) { return NAME##_(handle, false, sub_idx); } \
449 inline bool NAME##NoCheck(FlagHandle handle, s32 sub_idx) { \
450 return NAME##_(handle, true, sub_idx); \
451 } \
452 \
453 inline bool NAME(FlagHandle handle, bool debug) { \
454 if (debug) { \
455 onChangedByDebug(); \
456 return NAME##NoCheck(handle); \
457 } \
458 return NAME(handle); \
459 } \
460 inline bool NAME(FlagHandle handle, bool debug, s32 sub_idx) { \
461 if (debug) { \
462 onChangedByDebug(); \
463 return NAME##NoCheck(handle, sub_idx); \
464 } \
465 return NAME(handle, sub_idx); \
466 }
467
468 GDT_RESET_(resetBool)
469 GDT_RESET_(resetS32)
470 GDT_RESET_(resetF32)
471 GDT_RESET_(resetStr)
472 GDT_RESET_(resetStr64)
473 GDT_RESET_(resetStr256)
474 GDT_RESET_(resetVec2f)
475 GDT_RESET_(resetVec3f)
476 GDT_RESET_(resetVec4f)
477
478#undef GDT_RESET_
479
480 void incrementS32NoCheck(s32 value, const sead::SafeString& name);
481 void incrementS32(s32 value, const sead::SafeString& name);
482
483 void increaseS32CommonFlag(s32 value, const sead::SafeString& name, s32 sub_idx, bool debug) {
484 if (!mIncreaseLogger)
485 return;
486
487 mIncreaseLogger->addRecord(value, name, sub_idx, debug);
488 if (debug)
489 onChangedByDebug();
490 }
491
492 bool wasFlagCopied(const sead::SafeString& name);
493 bool wasFlagNotCopied(const sead::SafeString& name);
494
495 void copyParamToParam1();
496 void allocParam1();
497
498 FlagHandle getRevivalFlagHandle(const sead::SafeString& object_name,
499 const map::MubinIter& iter);
500 static bool getShopInfoIter(u32 hash, al::ByamlIter* out, const al::ByamlIter& iter,
501 const u32* hashes);
502 bool getShopSoldOutInfo(u32 hash, al::ByamlIter* out) const {
503 return getShopInfoIter(hash, out, getShopSoldOutInfoValues(), getShopSoldOutInfoHashes());
504 }
505 void resetBoolFlagForRadarMgr(FlagBool& flag);
506
507 void allocRetryBuffer(sead::Heap* heap);
508 void destroyRetryBuffer();
509
510 void startSyncOnLoadEnd();
511
512 const al::ByamlIter& getShopAreaInfoValues() const { return mShopAreaInfoValues; }
513 const u32* getShopAreaInfoHashes() const { return mShopAreaInfoHashes; }
514 const al::ByamlIter& getShopSoldOutInfoValues() const { return mShopSoldOutInfoValues; }
515 const u32* getShopSoldOutInfoHashes() const { return mShopSoldOutInfoHashes; }
516
517 void onAnimalMasterAppearance() {
518 mBitFlags.set(BitFlag::_8);
519 mResetFlags.set(ResetFlag::AnimalMaster);
520 }
521
522private:
523 enum class BitFlag {
524 _1 = 0x1,
525 _2 = 0x2,
526 RequestResetAllFlagsToInitial = 0x4,
527 _8 = 0x8,
528 _10 = 0x10,
529 _20 = 0x20,
530 _40 = 0x40,
531 _80 = 0x80,
532 _100 = 0x100,
533 _200 = 0x200,
534 SyncFlags = _100 | _200,
535 _400 = 0x400,
536 _800 = 0x800,
537 _1000 = 0x1000,
538 _2000 = 0x2000,
539 _4000 = 0x4000,
540 _8000 = 0x8000,
541 _10000 = 0x10000,
542 _20000 = 0x20000,
543 _40000 = 0x40000,
544 _80000 = 0x80000,
545 };
546
547 enum class ResetFlag {
548 AnimalMaster = 0x10,
549 };
550
551 struct MethodTreeNode {
552 virtual ~MethodTreeNode() = default;
553 sead::MethodTreeNode node{nullptr};
554 sead::MethodTreeMgr* method_tree_mgr = nullptr;
555 };
556
557 struct IncreaseLogger {
558 struct Record {
559 bool debug = false;
560 u32 name_hash = 0;
561 s32 sub_idx = -1;
562 s32 value = 0;
563 };
564 KSYS_CHECK_SIZE_NX150(Record, 0x10);
565
566 void addRecord(s32 value, const sead::SafeString& name, s32 sub_idx, bool debug);
567
568 u64 _0 = 0;
569 sead::SafeArray<sead::FixedRingBuffer<Record, 64>, NumCores> ring_buffers[2];
570 sead::SafeArray<Record, 0xc0> arrays[2]{};
571 };
572
573 static FlagHandle makeFlagHandle(u32 prefix, s32 idx) {
574 return FlagHandle(idx | (prefix << 24));
575 }
576
577 /// Extracts a flag index out of a FlagHandle and passes it to the specified callable.
578 /// fn must be callable with a u32 + TriggerParamRef&
579 template <bool Write, bool BypassPerm, typename Fn>
580 KSYS_ALWAYS_INLINE bool unwrapHandle(FlagHandle handle, const Fn& fn) {
581 const u32 idx = static_cast<u32>(handle);
582 auto& ref = BypassPerm ? getParamBypassPerm() : getParam();
583 const auto check = [&] { return !Write || !ref.shouldChangeOnlyOnce(); };
584
585 if (mBitFlags.isOff(BitFlag::_8000) && handle != InvalidHandle)
586 return check() && fn(idx, ref);
587
588 return idx >> 24 == mCurrentFlagHandlePrefix && check() && fn(idx & 0xFFFFFF, ref);
589 }
590
591 /// Extracts a flag index out of a FlagHandle and passes it to the specified callable.
592 /// fn must be callable with a u32 + TriggerParamRef&
593 template <bool Write, typename Fn>
594 KSYS_ALWAYS_INLINE bool unwrapHandle(FlagHandle handle, bool debug, const Fn& fn) {
595 return debug ? unwrapHandle<Write, true>(handle, fn) :
596 unwrapHandle<Write, false>(handle, fn);
597 }
598
599 void onChangedByDebug() {
600 setBool(true, "IsChangedByDebug");
601 mBitFlags.set(BitFlag::_800);
602 }
603
604 void loadGameData(const sead::SafeString& path);
605 void loadShopGameDataInfo(const sead::SafeString& path);
606 void unloadResources();
607
608 void syncStart();
609 void syncUpdate(const char* data);
610 static void parseFloats(const sead::SafeString& str, f32* values, u32 n);
611 static inline void recordFlagChange(u32 platform_core_id, TriggerParam* tparam, u8 type,
612 const s32& idx, const s32& sub_idx = -1);
613
614 template <typename T>
615 void doSyncArray(const sead::PtrArray<FlagBase>& array, u8* buffer, const char* description);
616 template <int N>
617 void doSyncArrayStr(const sead::PtrArray<FlagBase>& array, u8* buffer, const char* description,
618 u32 n = N);
619 template <typename T>
620 void doSyncArrayVec(const sead::PtrArray<FlagBase>& array, u8* buffer, const char* description,
621 u32 n);
622
623 template <typename T>
624 void doSyncArray(const sead::PtrArray<sead::PtrArray<FlagBase>>& array, u8* buffer,
625 const char* description);
626 template <int N>
627 void doSyncArrayStr(const sead::PtrArray<sead::PtrArray<FlagBase>>& array, u8* buffer,
628 const char* description, u32 n = N);
629 template <typename T>
630 void doSyncArrayVec(const sead::PtrArray<sead::PtrArray<FlagBase>>& array, u8* buffer,
631 const char* description, u32 n);
632
633 sead::Heap* mGameDataHeap = nullptr;
634 sead::Heap* mSaveAreaHeap = nullptr;
635 sead::Heap* mGameDataComHeap = nullptr;
636 res::Handle mGameDataArcHandle;
637 sead::SafeArray<res::Handle, 32> mBgdataHandles;
638 sead::ArchiveFileDevice mGameDataArc{nullptr};
639
640 res::Handle mShopGameDataInfoHandle;
641 al::ByamlIter mShopAreaInfoValues;
642 const u32* mShopAreaInfoHashes = nullptr;
643 al::ByamlIter mShopSoldOutInfoValues;
644 const u32* mShopSoldOutInfoHashes = nullptr;
645
646 TriggerParamRef mParamBypassPerm{&mFlagBuffer1, &mFlagBuffer, false, false, false};
647 TriggerParamRef mParam{&mFlagBuffer1, &mFlagBuffer, true, false, false};
648
649 IncreaseLogger* mIncreaseLogger = nullptr;
650
651 TriggerParam* mFlagBuffer1;
652 TriggerParam* mFlagBuffer;
653 TriggerParam* mRetryBuffer;
654 TriggerParam* mGimmickResetBuffer;
655
656 sead::TypedBitFlag<BitFlag> mBitFlags;
657 sead::TypedBitFlag<ResetFlag> mResetFlags;
658 u32 _c20 = 0;
659 u32 mNumFlagsToReset = 0;
660 u32 mCurrentFlagHandlePrefix = 0;
661
662 ReinitSignal mReinitSignal;
663 ResetSignal mResetSignal;
664
665 MethodTreeNode mMethodTreeNode;
666
667 void* mDelegate1 = nullptr; // FIXME: figure out what this is
668 sead::IDelegateR<const sead::SafeString&>* mGetMapNameDelegate = nullptr;
669
670 sead::FixedSafeString<64> mStr; // TODO: rename
671 u32 mTrackerBlockSaveNumberFlagCrc32 = 0;
672 u32 mSyncStep = 0;
673 sead::Mutex mMutex;
674};
675KSYS_CHECK_SIZE_NX150(Manager, 0xdc8);
676
677} // namespace ksys::gdt
678