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 | |
20 | namespace sead { |
21 | class Framework; |
22 | class MethodTreeMgr; |
23 | } // namespace sead |
24 | |
25 | namespace ksys::map { |
26 | class MubinIter; |
27 | } |
28 | |
29 | namespace ksys::gdt { |
30 | |
31 | namespace detail { |
32 | |
33 | template <typename T> |
34 | struct 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 | |
61 | class TriggerParamRef { |
62 | public: |
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 | |
198 | private: |
199 | TriggerParam** mParam1; |
200 | TriggerParam** mParam; |
201 | bool mCheckPermissions; |
202 | bool mPropagateParam1Changes; |
203 | bool mChangeOnlyOnce; |
204 | }; |
205 | KSYS_CHECK_SIZE_NX150(TriggerParamRef, 0x20); |
206 | |
207 | class IManager { |
208 | public: |
209 | virtual ~IManager() = 0; |
210 | }; |
211 | |
212 | inline IManager::~IManager() = default; |
213 | |
214 | class 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 | |
221 | public: |
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 | |
522 | private: |
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 | }; |
675 | KSYS_CHECK_SIZE_NX150(Manager, 0xdc8); |
676 | |
677 | } // namespace ksys::gdt |
678 | |