Files
botw/src/KingSystem/GameData/gdtManager.cpp
T
2021-07-26 23:05:19 +12:00

1273 lines
43 KiB
C++

#include "KingSystem/GameData/gdtManager.h"
#include <algorithm>
#include <cstring>
#include <devenv/seadEnvUtil.h>
#include <framework/seadFramework.h>
#include <mc/seadCoreInfo.h>
#include <prim/seadStringUtil.h>
#include <thread/seadThreadUtil.h>
#include <time/seadTickTime.h>
#include <type_traits>
#include "Game/DLC/aocManager.h"
#include "KingSystem/GameData/gdtSaveMgr.h"
#include "KingSystem/GameData/gdtTriggerParam.h"
#include "KingSystem/Map/mapMubinIter.h"
#include "KingSystem/Resource/resEntryFactory.h"
#include "KingSystem/Resource/resLoadRequest.h"
#include "KingSystem/Resource/resResourceGameData.h"
#include "KingSystem/Resource/resSystem.h"
#include "KingSystem/System/OverlayArenaSystem.h"
#include "KingSystem/Utils/Byaml/Byaml.h"
#include "KingSystem/Utils/Byaml/ByamlArrayIter.h"
#include "KingSystem/Utils/Debug.h"
#include "KingSystem/Utils/HeapUtil.h"
#include "KingSystem/Utils/InitTimeInfo.h"
#include "KingSystem/Utils/SafeDelete.h"
namespace ksys::gdt {
SEAD_SINGLETON_DISPOSER_IMPL(Manager)
static util::InitTimeInfoEx sInitTimeInfo;
Manager::Manager() {
mRetryBuffer = nullptr;
mGimmickResetBuffer = nullptr;
mFlagBuffer1 = nullptr;
mFlagBuffer = nullptr;
}
Manager::~Manager() {
mShopGameDataInfoHandle.requestUnload();
if (mGameDataHeap) {
if (mFlagBuffer1) {
mFlagBuffer1->destroyHeap();
mFlagBuffer1 = nullptr;
}
if (mFlagBuffer) {
mFlagBuffer->destroyHeap();
mFlagBuffer = nullptr;
}
if (mRetryBuffer) {
mRetryBuffer->destroyHeap();
mRetryBuffer = nullptr;
}
if (mGimmickResetBuffer) {
mGimmickResetBuffer->destroyHeap();
mGimmickResetBuffer = nullptr;
}
if (mSaveAreaHeap) {
mSaveAreaHeap->destroy();
mSaveAreaHeap = nullptr;
}
mGameDataHeap->destroy();
mGameDataHeap = nullptr;
}
if (mGameDataComHeap) {
mGameDataComHeap->destroy();
mGameDataComHeap = nullptr;
}
}
// address differences for the static bgdata_factory that causes different regalloc
#ifdef NON_MATCHING
void Manager::init(sead::Heap* heap, sead::Framework* framework) {
sead::TickTime a;
sead::TickTime b;
mGameDataHeap = util::DualHeap::create(0xf00000, "GameDataHeap", heap, nullptr, sizeof(void*),
sead::Heap::cHeapDirection_Forward, true);
mIncreaseLogger = new (mGameDataHeap) IncreaseLogger;
SaveMgr::createInstance(mGameDataHeap);
SaveMgr::InitArg arg;
arg.heap = mGameDataHeap;
arg._8 = 0x300000;
arg.buf_size = 0x100000;
arg.buf_alignment = 0x200;
arg.size2 = 0x10000;
arg.thread_priority = sead::ThreadUtil::ConvertPrioritySeadToPlatform(18);
arg.thread_affinity = sead::CoreIdMask(sead::CoreId::cSub1);
arg._1c = 0x7000;
arg.is_demo = sead::EnvUtil::getRomType() == "Show_2017_1st";
if (sead::EnvUtil::getRomType() == "RID_Demo") {
arg.is_demo = true;
arg.save_rid_demo_dir = "Save/RID_Demo/";
}
arg._60 = nullptr;
if (util::getDebugHeap2())
arg._68 = 0x80000;
SaveMgr::instance()->init(arg);
static res::EntryFactory<res::GameData> bgdata_factory{5.0, 0xc0000};
res::registerEntryFactory(&bgdata_factory, "bgdata");
mSaveAreaHeap =
util::DualHeap::create(0x500000, "SaveAreaHeap", mGameDataHeap, nullptr, sizeof(void*),
sead::Heap::cHeapDirection_Reverse, false);
SaveMgr::instance()->loadGameSaveData();
KingEditor::instance()->registerComponent(this);
sead::FixedSafeString<1024> gamedata_sarc_path;
gamedata_sarc_path.format("%s/%s.%s", "GameData", "gamedata", "sarc");
loadGameData(gamedata_sarc_path);
sead::FixedSafeString<1024> shop_gamedata_info_path;
shop_gamedata_info_path.format("%s/%s.byml", "GameData", "ShopGameDataInfo");
loadShopGameDataInfo(shop_gamedata_info_path);
mParam.setBuffers(&mFlagBuffer1, &mFlagBuffer);
mParamBypassPerm.setBuffers(&mFlagBuffer1, &mFlagBuffer);
mMethodTreeNode.method_tree_mgr = framework->getMethodTreeMgr();
mMethodTreeNode.node.setPauseFlag(sead::MethodTreeNode::cPause_None);
mBitFlags.reset(BitFlag::_1);
unloadResources();
mBitFlags.set(BitFlag::_1000);
mNumFlagsToReset = 0;
}
#endif
void Manager::loadShopGameDataInfo(const sead::SafeString& path) {
res::LoadRequest req;
req.mRequester = "gdtManager";
req._26 = false;
if (!sead::DynamicCast<res::Resource>(mShopGameDataInfoHandle.load(path, &req)))
return;
auto* res = sead::DynamicCast<sead::DirectResource>(mShopGameDataInfoHandle.getResource());
if (!res)
return;
al::ByamlIter root{res->getRawData()};
al::ByamlIter iter;
al::ByamlIter hashes;
if (root.tryGetIterByKey(&iter, "ShopAreaInfo")) {
iter.tryGetIterByKey(&mShopAreaInfoValues, "Values");
if (iter.tryGetIterByKey(&hashes, "Hashes")) {
mShopAreaInfoHashes = al::ByamlArrayIter(hashes.getRootNode()).getDataTable();
}
}
util::PrintDebugFmt("ShopAreaInfo: %d %d", mShopAreaInfoValues.getSize(), hashes.getSize());
if (root.tryGetIterByKey(&iter, "SoldOutInfo")) {
iter.tryGetIterByKey(&mShopSoldOutInfoValues, "Values");
if (iter.tryGetIterByKey(&hashes, "Hashes")) {
mShopSoldOutInfoHashes = al::ByamlArrayIter(hashes.getRootNode()).getDataTable();
}
}
util::PrintDebugFmt("SoldOutInfo: %d %d", mShopSoldOutInfoValues.getSize(), hashes.getSize());
}
void Manager::unloadResources() {
for (s32 i = 0; i < mBgdataHandles.size(); ++i)
mBgdataHandles[i].requestUnload();
mGameDataArcHandle.requestUnload();
}
void Manager::addReinitCallback(sead::DelegateEvent<ReinitEvent*>::Slot&) {
// Stubbed in release builds.
}
void Manager::removeReinitCallback(sead::DelegateEvent<Manager::ReinitEvent*>::Slot& slot) {
// Stubbed in release builds.
}
void Manager::setCurrentRupeeFlagName(const sead::SafeString& name) {
getParam().get1().getBuffer()->setCurrentRupeeFlagName(name);
}
void Manager::requestResetAllFlagsToInitial() {
mBitFlags.set(BitFlag::RequestResetAllFlagsToInitial);
}
namespace {
template <int N>
bool loadAllFlags(Manager* mgr, sead::SafeArray<bool, N>* flags,
const sead::SafeString (&names)[N]) {
#ifdef MATCHING_HACK_NX_CLANG
#pragma clang loop unroll(full)
#endif
for (int i = 0; i < N; ++i) {
if (!mgr->getParam().get1().getBool(&(*flags)[i], names[i]))
return false;
}
return true;
}
void fixDarkWoodsFlags(Manager* mgr) {
enum {
DarkWoods_Giant_Clear,
DarkWoods_Finish,
};
sead::SafeString names[] = {
"DarkWoods_Giant_Clear",
"DarkWoods_Finish",
};
sead::SafeArray<bool, std::size(names)> flags;
if (!loadAllFlags(mgr, &flags, names))
return;
if (flags[DarkWoods_Giant_Clear] && !flags[DarkWoods_Finish])
mgr->getParamBypassPerm().get1().setBool(false, names[DarkWoods_Giant_Clear], true);
}
void fixGiantQuestFlags(Manager* mgr) {
enum {
giant_ball1,
giant_ball2,
giant_ball3,
giant_dungeon,
MainField_DgnObj_RemainsLithogragh_A_02_789666109,
MainField_DgnObj_RemainsLithogragh_A_02_2456751716,
MainField_DgnObj_RemainsLithogragh_A_02_1822262999,
};
sead::SafeString names[] = {
"giant_ball1",
"giant_ball2",
"giant_ball3",
"giant_dungeon",
"MainField_DgnObj_RemainsLithogragh_A_02_789666109",
"MainField_DgnObj_RemainsLithogragh_A_02_2456751716",
"MainField_DgnObj_RemainsLithogragh_A_02_1822262999",
};
sead::SafeArray<bool, std::size(names)> flags;
if (!loadAllFlags(mgr, &flags, names))
return;
if (flags[giant_ball1] && !flags[MainField_DgnObj_RemainsLithogragh_A_02_789666109])
mgr->setBool(true, names[MainField_DgnObj_RemainsLithogragh_A_02_789666109]);
if (flags[giant_ball2] && !flags[MainField_DgnObj_RemainsLithogragh_A_02_2456751716])
mgr->setBool(true, names[MainField_DgnObj_RemainsLithogragh_A_02_2456751716]);
if (flags[giant_ball3] && !flags[MainField_DgnObj_RemainsLithogragh_A_02_1822262999])
mgr->setBool(true, names[MainField_DgnObj_RemainsLithogragh_A_02_1822262999]);
if (flags[giant_ball1] && flags[giant_ball2] && flags[giant_ball3] && !flags[giant_dungeon])
mgr->getParamBypassPerm().get1().setBool(true, names[giant_dungeon], true);
}
void fixBowOfLightFlag(Manager* mgr) {
enum { MainField_Weapon_Bow_071_2178255681 };
sead::SafeString names[] = {"MainField_Weapon_Bow_071_2178255681"};
sead::SafeArray<bool, std::size(names)> flags;
if (loadAllFlags(mgr, &flags, names) && flags[MainField_Weapon_Bow_071_2178255681])
mgr->setBool(false, names[MainField_Weapon_Bow_071_2178255681]);
}
void fixBalladOfHeroesFlags(Manager* mgr) {
enum {
BalladOfHeroes_Step02,
BalladOfHeroes_Step03,
Defeat_OneHitDungeon001,
Defeat_OneHitDungeon002,
Defeat_OneHitDungeon003,
Defeat_OneHitDungeon004,
Lock_OneHitDungeon001,
Lock_OneHitDungeon002,
Lock_OneHitDungeon003,
Lock_OneHitDungeon004,
BalladOfHeroes_Step02_Dungeon01,
BalladOfHeroes_Step02_Dungeon02,
BalladOfHeroes_Step02_Dungeon03,
BalladOfHeroes_Step2_Dungeon4,
};
sead::SafeString names[] = {
"BalladOfHeroes_Step02",
"BalladOfHeroes_Step03",
//
"Defeat_OneHitDungeon001",
"Defeat_OneHitDungeon002",
"Defeat_OneHitDungeon003",
"Defeat_OneHitDungeon004",
//
"Lock_OneHitDungeon001",
"Lock_OneHitDungeon002",
"Lock_OneHitDungeon003",
"Lock_OneHitDungeon004",
//
"BalladOfHeroes_Step02_Dungeon01",
"BalladOfHeroes_Step02_Dungeon02",
"BalladOfHeroes_Step02_Dungeon03",
"BalladOfHeroes_Step2_Dungeon4",
};
sead::SafeArray<bool, std::size(names)> flags;
if (!loadAllFlags(mgr, &flags, names))
return;
if (!flags[BalladOfHeroes_Step02] || flags[BalladOfHeroes_Step03])
return;
s8 count = 0;
bool not_locked = false;
if (flags[Defeat_OneHitDungeon001]) {
++count;
if (!flags[Lock_OneHitDungeon001])
not_locked = true;
}
if (flags[Defeat_OneHitDungeon002]) {
++count;
if (!flags[Lock_OneHitDungeon002])
not_locked = true;
}
if (flags[Defeat_OneHitDungeon003]) {
++count;
if (!flags[Lock_OneHitDungeon003])
not_locked = true;
}
if (flags[Defeat_OneHitDungeon004]) {
++count;
if (!flags[Lock_OneHitDungeon004])
not_locked = true;
}
if (not_locked) {
if (count >= 1 && !flags[BalladOfHeroes_Step02_Dungeon01])
mgr->setBool(true, names[BalladOfHeroes_Step02_Dungeon01]);
if (count >= 2 && !flags[BalladOfHeroes_Step02_Dungeon02])
mgr->setBool(true, names[BalladOfHeroes_Step02_Dungeon02]);
if (count >= 3 && !flags[BalladOfHeroes_Step02_Dungeon03])
mgr->setBool(true, names[BalladOfHeroes_Step02_Dungeon03]);
if (count >= 4 && !flags[BalladOfHeroes_Step2_Dungeon4])
mgr->setBool(true, names[BalladOfHeroes_Step2_Dungeon4]);
}
}
void fixAllShrinesFlags(Manager* mgr) {
enum {
IsGet_Armor_005_Head,
IsGet_Armor_005_Upper,
IsGet_Armor_005_Lower,
CompleteDungeon_Finish,
};
sead::SafeString names[] = {
"IsGet_Armor_005_Head",
"IsGet_Armor_005_Upper",
"IsGet_Armor_005_Lower",
"CompleteDungeon_Finish",
};
sead::SafeArray<bool, std::size(names)> flags;
if (!loadAllFlags(mgr, &flags, names))
return;
if (flags[IsGet_Armor_005_Head] && flags[IsGet_Armor_005_Upper] &&
flags[IsGet_Armor_005_Lower] && !flags[CompleteDungeon_Finish]) {
mgr->setBool(true, names[CompleteDungeon_Finish]);
}
}
} // namespace
void Manager::fixQuestFlags() {
fixDarkWoodsFlags(this);
fixGiantQuestFlags(this);
fixBowOfLightFlag(this);
fixBalladOfHeroesFlags(this);
fixAllShrinesFlags(this);
{
enum {
NightStoneBreak,
NightStoneDungeonAppear,
};
sead::SafeString names[] = {
"NightStoneBreak",
"NightStoneDungeonAppear",
};
sead::SafeArray<bool, std::size(names)> flags;
if (loadAllFlags(this, &flags, names)) {
if (flags[NightStoneBreak] && !flags[NightStoneDungeonAppear])
getParamBypassPerm().get().setBool(false, names[NightStoneBreak], true);
}
}
{
enum {
Animal_Forest_Finish,
HateeluMini_Treasure_Finish,
Thunder_Sword_Finish,
Relief_Landing_Finish,
Shadow_Sign_Finish,
MouthofDragon_Finish,
TwoWheels_Finish,
BloodyMoonRelief_Finish,
Rito_BrosRock_Finish,
};
sead::SafeString names[] = {
"Animal_Forest_Finish",
"HateeluMini_Treasure_Finish",
"Thunder_Sword_Finish",
"Relief_Landing_Finish",
"Shadow_Sign_Finish",
"MouthofDragon_Finish",
"TwoWheels_Finish",
"BloodyMoonRelief_Finish",
// Not a shrine quest
"Rito_BrosRock_Finish",
};
sead::SafeArray<bool, std::size(names)> flags;
if (loadAllFlags(this, &flags, names)) {
if (std::all_of(flags.begin(), flags.end(), [](bool b) { return b; }))
getParamBypassPerm().get().setBool(true, "Npc_Musician_Come", true);
}
}
}
void Manager::fixQuestFlagsDlc2() {
if (uking::aoc::Manager::instance()->hasAoc3())
return;
enum {
Ichigeki_Sword_Appear,
BalladOfHeroes_Retire_Dungeon04,
BalladOfHeroes_Step02,
BalladOfHeroes_Step02_Dungeon01,
BalladOfHeroes_Step02_Dungeon02,
BalladOfHeroes_Step02_Dungeon03,
BalladOfHeroes_Step2_Dungeon4,
BalladOfHeroes_Step03,
};
sead::SafeString names[] = {
"Ichigeki_Sword_Appear",
"BalladOfHeroes_Retire_Dungeon04",
// OhO plateau phase
"BalladOfHeroes_Step02",
"BalladOfHeroes_Step02_Dungeon01",
"BalladOfHeroes_Step02_Dungeon02",
"BalladOfHeroes_Step02_Dungeon03",
"BalladOfHeroes_Step2_Dungeon4",
"BalladOfHeroes_Step03",
};
sead::SafeArray<bool, std::size(names)> flags;
if (!loadAllFlags(this, &flags, names))
return;
const bool value_BalladOfHeroes_Step2_Dungeon4 = flags[BalladOfHeroes_Step2_Dungeon4];
if (!flags[BalladOfHeroes_Step02] || flags[BalladOfHeroes_Step03])
return;
setBool(false, names[BalladOfHeroes_Step2_Dungeon4]);
setBool(false, names[BalladOfHeroes_Step02_Dungeon03]);
setBool(false, names[BalladOfHeroes_Step02_Dungeon02]);
setBool(false, names[BalladOfHeroes_Step02_Dungeon01]);
setBool(false, names[BalladOfHeroes_Step02]);
if (!value_BalladOfHeroes_Step2_Dungeon4)
setBool(false, names[BalladOfHeroes_Retire_Dungeon04]);
setBool(true, names[Ichigeki_Sword_Appear]);
const char* temp_horse;
if (getParam().get().getStr64(&temp_horse, "Horse_ActorName", 5) &&
sead::SafeString(temp_horse) == "GameRomHorseBone_AllDay") {
setStr64("", "Horse_ActorName", 5);
}
}
#define GDT_SET_IMPL_(NAME, TRAITS) \
/* Setters (by name) */ \
bool Manager::NAME(TRAITS::ArgType value, const sead::SafeString& name) { \
return NAME(value, name, false, false); \
} \
bool Manager::NAME##_(TRAITS::ArgType value, const sead::SafeString& name) { \
return NAME(value, name, false, false); \
} \
bool Manager::NAME##NoCheck(TRAITS::ArgType value, const sead::SafeString& name) { \
return NAME(value, name, true, false); \
} \
bool Manager::NAME##NoCheck_(TRAITS::ArgType value, const sead::SafeString& name) { \
return NAME(value, name, true, false); \
} \
bool Manager::NAME##NoCheckForce(TRAITS::NoCheckForceArgType value, \
const sead::SafeString& name) { \
return NAME(value, name, true, true); \
} \
/* Setters for arrays (by name) */ \
bool Manager::NAME(TRAITS::ArgType value, const sead::SafeString& name, s32 sub_idx) { \
return NAME(value, name, false, false, sub_idx); \
} \
bool Manager::NAME##_(TRAITS::ArgType value, const sead::SafeString& name, s32 sub_idx) { \
return NAME(value, name, false, false, sub_idx); \
} \
bool Manager::NAME##NoCheck(TRAITS::ArgType value, const sead::SafeString& name, \
s32 sub_idx) { \
return NAME(value, name, true, false, sub_idx); \
} \
bool Manager::NAME##NoCheckForce(TRAITS::NoCheckForceArgType value, \
const sead::SafeString& name, s32 sub_idx) { \
return NAME(value, name, true, true, sub_idx); \
}
GDT_SET_IMPL_(setBool, detail::SetterTraits<bool>)
GDT_SET_IMPL_(setS32, detail::SetterTraits<s32>)
GDT_SET_IMPL_(setF32, detail::SetterTraits<f32>)
GDT_SET_IMPL_(setStr, detail::SetterTraits<const char*>)
GDT_SET_IMPL_(setStr64, detail::SetterTraits<const char*>)
GDT_SET_IMPL_(setStr256, detail::SetterTraits<const char*>)
GDT_SET_IMPL_(setVec2f, detail::SetterTraits<sead::Vector2f>)
GDT_SET_IMPL_(setVec3f, detail::SetterTraits<sead::Vector3f>)
GDT_SET_IMPL_(setVec4f, detail::SetterTraits<sead::Vector4f>)
#undef GDT_SET_IMPL_
#define GDT_RESET_IMPL_(NAME) \
bool Manager::NAME(const sead::SafeString& name) { \
if (mBitFlags.isOn(BitFlag::_40000)) \
return false; \
return getParam().get1().NAME(name); \
} \
bool Manager::NAME##_(const sead::SafeString& name) { return NAME(name); } \
bool Manager::NAME(const sead::SafeString& name, int sub_idx) { \
if (mBitFlags.isOn(BitFlag::_40000)) \
return false; \
return getParam().get1().NAME(name, sub_idx); \
}
GDT_RESET_IMPL_(resetBool)
GDT_RESET_IMPL_(resetS32)
GDT_RESET_IMPL_(resetF32)
GDT_RESET_IMPL_(resetStr)
GDT_RESET_IMPL_(resetStr64)
GDT_RESET_IMPL_(resetStr256)
GDT_RESET_IMPL_(resetVec2f)
GDT_RESET_IMPL_(resetVec3f)
GDT_RESET_IMPL_(resetVec4f)
#undef GDT_RESET_IMPL_
void Manager::incrementS32NoCheck(s32 value, const sead::SafeString& name) {
if (mBitFlags.isOn(BitFlag::_40000))
return;
if (mBitFlags.isOn(BitFlag::_10000)) {
s32 current = 0;
if (getParamBypassPerm().get().getS32(&current, name))
setS32NoCheck(current + value, name);
} else if (mIncreaseLogger) {
mIncreaseLogger->addRecord(value, name, -1, true);
}
}
void Manager::incrementS32(s32 value, const sead::SafeString& name) {
if (mBitFlags.isOn(BitFlag::_40000))
return;
if (mBitFlags.isOn(BitFlag::_10000)) {
s32 current = 0;
if (getParam().get().getS32(&current, name))
setS32(current + value, name);
} else if (mIncreaseLogger) {
mIncreaseLogger->addRecord(value, name, -1, false);
}
}
void Manager::IncreaseLogger::addRecord(s32 value, const sead::SafeString& name, s32 sub_idx,
bool debug) {
const u32 name_hash = sead::HashCRC32::calcStringHash(name);
const auto core = sead::CoreInfo::getCurrentCoreId();
const u32 platform_core_id = sead::CoreInfo::getPlatformCoreId(core);
Record record;
record.debug = debug;
record.name_hash = name_hash;
record.sub_idx = sub_idx;
record.value = value;
ring_buffers[0][platform_core_id].pushBack(record);
}
bool Manager::wasFlagCopied(const sead::SafeString& name) {
bool value;
return getParam().get().getBuffer()->getBoolIfCopied(&value, name, false, true) && value != 0;
}
bool Manager::wasFlagNotCopied(const sead::SafeString& name) {
bool value;
return getParam().get().getBuffer()->getBoolIfCopied(&value, name, false, true) && !value;
}
void Manager::copyParamToParam1() {
mFlagBuffer1->copyChangedFlags(*mFlagBuffer, true, false, false);
}
FlagHandle Manager::getRevivalFlagHandle(const sead::SafeString& object_name,
const map::MubinIter& iter) {
if (mBitFlags.isOn(BitFlag::_40000))
return InvalidHandle;
const sead::SafeString& map_name =
mGetMapNameDelegate ? mGetMapNameDelegate->invoke() : sead::SafeString::cEmptyString;
u32 hash_id = 0;
iter.tryGetParamUIntByKey(&hash_id, "HashId");
sead::FormatFixedSafeString<128> flag_name("%s_%s_%u", map_name.cstr(), object_name.cstr(),
hash_id);
if (mBitFlags.isOn(BitFlag::_2000))
return InvalidHandle;
return getBoolHandle(flag_name);
}
void Manager::allocParam1() {
auto* parent_heap = OverlayArenaSystem::instance()->getGameDataWorkHeap();
auto* heap = util::tryCreateDualHeap(0, "param1", parent_heap, nullptr,
sead::Heap::cHeapDirection_Forward, false);
mFlagBuffer1 = new (heap) TriggerParam;
mFlagBuffer1->copyAllFlags(*mFlagBuffer, heap, true);
heap->adjust();
}
bool Manager::getShopInfoIter(u32 hash, al::ByamlIter* out, const al::ByamlIter& iter,
const u32* hashes) {
int a = 0;
int b = iter.getSize();
while (a < b) {
const auto m = (a + b) / 2;
if (hashes[m] == hash)
return iter.tryGetIterByIndex(out, m);
if (hashes[m] < hash)
a = m + 1;
else
b = m;
}
return false;
}
void Manager::allocRetryBuffer(sead::Heap* heap) {
if (mRetryBuffer)
return;
auto* buffer_heap = util::tryCreateDualHeap(0x100000, "RetryBuffer", heap, nullptr,
sead::Heap::cHeapDirection_Reverse, false);
mRetryBuffer = new (buffer_heap) TriggerParam;
mRetryBuffer->copyPermanentFlags(*mFlagBuffer1, buffer_heap);
buffer_heap->adjust();
}
void Manager::destroyRetryBuffer() {
if (mBitFlags.isOn(BitFlag::_80000))
return;
if (mRetryBuffer) {
mRetryBuffer->destroyHeap();
mRetryBuffer = nullptr;
}
}
void Manager::syncData(char* data) {
const sead::SafeString cmd = data;
if (cmd.compare("SyncStart") == 0) {
if (util::getDebugHeap()) {
if (mBitFlags.testAndClear(BitFlag::_100)) {
mSyncStep = 0;
}
mBitFlags.set(BitFlag::_200);
syncStart();
}
} else if (cmd.compare("SyncEnd") == 0) {
mSyncStep = 0;
mBitFlags.reset(BitFlag::_100);
mBitFlags.reset(BitFlag::_200);
} else {
syncUpdate(data);
onChangedByDebug();
}
}
constexpr size_t ComBufferSize = 0x1a000;
void Manager::syncStart() {
if (KingEditor::instance()->get88() == 0 || util::getDebugHeap() == nullptr)
return;
if (mGameDataComHeap) {
if (mGameDataComHeap->getFreeSize() < ComBufferSize)
return;
} else {
mGameDataComHeap =
sead::ExpHeap::tryCreate(ComBufferSize + 0x400, "GameDataCom", util::getDebugHeap(),
sizeof(void*), sead::Heap::cHeapDirection_Forward, false);
if (!mGameDataComHeap)
return;
}
u8* buffer = new (mGameDataComHeap) u8[ComBufferSize];
auto* flag_buffer = mFlagBuffer;
const int step = mSyncStep;
switch (mSyncStep) {
case 0:
doSyncArray<bool>(flag_buffer->mBoolFlags, buffer, "[SyncData][AllData][bool]");
mSyncStep = step + 1;
break;
case 1:
doSyncArray<s32>(flag_buffer->mS32Flags, buffer, "[SyncData][AllData][s32]");
mSyncStep = step + 1;
break;
case 2:
doSyncArray<f32>(flag_buffer->mF32Flags, buffer, "[SyncData][AllData][f32]");
mSyncStep = step + 1;
break;
case 3:
doSyncArrayStr<32>(flag_buffer->mStringFlags, buffer, "[SyncData][AllData][string]");
mSyncStep = step + 1;
break;
case 4:
doSyncArrayStr<64>(flag_buffer->mString64Flags, buffer, "[SyncData][AllData][string64]");
mSyncStep = step + 1;
break;
case 5:
doSyncArrayStr<256>(flag_buffer->mString256Flags, buffer, "[SyncData][AllData][string256]");
mSyncStep = step + 1;
break;
case 6:
doSyncArrayVec<sead::Vector2f>(flag_buffer->mVector2fFlags, buffer,
"[SyncData][AllData][vector2f]", 2);
mSyncStep = step + 1;
break;
case 7:
doSyncArrayVec<sead::Vector3f>(flag_buffer->mVector3fFlags, buffer,
"[SyncData][AllData][vector3f]", 3);
mSyncStep = step + 1;
break;
case 8:
doSyncArrayVec<sead::Vector4f>(flag_buffer->mVector4fFlags, buffer,
"[SyncData][AllData][vector4f]", 4);
mSyncStep = step + 1;
break;
case 9:
doSyncArray<bool>(flag_buffer->mBoolArrayFlags, buffer, "[SyncData][AllData][boolarray]");
mSyncStep = step + 1;
break;
case 10:
doSyncArray<s32>(flag_buffer->mS32ArrayFlags, buffer, "[SyncData][AllData][s32array]");
mSyncStep = step + 1;
break;
case 11:
doSyncArray<f32>(flag_buffer->mF32ArrayFlags, buffer, "[SyncData][AllData][f32array]");
mSyncStep = step + 1;
break;
case 12:
doSyncArrayStr<32>(flag_buffer->mStringArrayFlags, buffer,
"[SyncData][AllData][stringarray]");
mSyncStep = step + 1;
break;
case 13:
doSyncArrayStr<64>(flag_buffer->mString64ArrayFlags, buffer,
"[SyncData][AllData][string64array]");
mSyncStep = step + 1;
break;
case 14:
doSyncArrayStr<256>(flag_buffer->mString256ArrayFlags, buffer,
"[SyncData][AllData][string256array]");
mSyncStep = step + 1;
break;
case 15:
doSyncArrayVec<sead::Vector2f>(flag_buffer->mVector2fArrayFlags, buffer,
"[SyncData][AllData][vector2farray]", 2);
mSyncStep = step + 1;
break;
case 16:
doSyncArrayVec<sead::Vector3f>(flag_buffer->mVector3fArrayFlags, buffer,
"[SyncData][AllData][vector3farray]", 3);
mSyncStep = step + 1;
break;
case 17:
doSyncArrayVec<sead::Vector4f>(flag_buffer->mVector4fArrayFlags, buffer,
"[SyncData][AllData][vector4farray]", 4);
mSyncStep = step + 1;
break;
default:
KingEditor::instance()->log(getName(), "[SendAllData]");
mBitFlags.reset(BitFlag::SyncFlags);
mBitFlags.set(BitFlag::_100);
break;
}
util::safeDeleteArray(buffer);
}
// recordFlagChange calls not being merged, or merged in the wrong way
#ifdef NON_MATCHING
void Manager::syncUpdate(const char* data) {
const sead::SafeString cmd = data;
auto it = cmd.tokenBegin("|");
const auto end = cmd.tokenEnd("|");
if (it == end)
return;
sead::FixedSafeString<256> name;
it.getAndForward(&name);
sead::FixedSafeString<256> type;
it.getAndForward(&type);
sead::FixedSafeString<256> value;
it.getAndForward(&value);
auto* tparam = mFlagBuffer1;
int idx = -1;
const u32 pl_core_id = sead::CoreInfo::getPlatformCoreId(sead::CoreInfo::getCurrentCoreId());
const auto calc_hash = [&] { return sead::HashCRC32::calcStringHash(name); };
if (type.compare("bool") == 0) {
auto* flag = tparam->getBoolFlagAndIdx(&idx, calc_hash());
if (!flag)
return;
bool v = false;
if (value == "true")
v = true;
flag->setValue(v);
recordFlagChange(pl_core_id, tparam, flag->getType(), idx);
return;
}
if (type.compare("s32") == 0) {
auto* flag = tparam->getS32FlagAndIdx(&idx, calc_hash());
if (!flag)
return;
s32 v = 0;
sead::StringUtil::tryParseS32(&v, value, sead::StringUtil::CardinalNumber::BaseAuto);
flag->setValue(v);
recordFlagChange(pl_core_id, tparam, flag->getType(), idx);
return;
}
if (type.compare("f32") == 0) {
auto* flag = tparam->getF32FlagAndIdx(&idx, calc_hash());
if (!flag)
return;
f32 v = 0;
sead::StringUtil::tryParseF32(&v, value);
flag->setValue(v);
recordFlagChange(pl_core_id, tparam, flag->getType(), idx);
return;
}
if (type.compare("string") == 0) {
auto* flag = tparam->getStrFlagAndIdx(&idx, calc_hash());
if (!flag)
return;
flag->setValue(value);
recordFlagChange(pl_core_id, tparam, flag->getType(), idx);
return;
}
if (type.compare("string64") == 0) {
auto* flag = tparam->getStr64FlagAndIdx(&idx, calc_hash());
if (!flag)
return;
flag->setValue(value);
recordFlagChange(pl_core_id, tparam, flag->getType(), idx);
return;
}
if (type.compare("string256") == 0) {
auto* flag = tparam->getStr256FlagAndIdx(&idx, calc_hash());
if (!flag)
return;
flag->setValue(value);
recordFlagChange(pl_core_id, tparam, flag->getType(), idx);
return;
}
if (type.compare("vector2f") == 0) {
auto* flag = tparam->getVec2fFlagAndIdx(&idx, calc_hash());
if (!flag)
return;
sead::Vector2f v;
parseFloats(value, v.e.data(), v.e.size());
flag->setValue(v);
recordFlagChange(pl_core_id, tparam, flag->getType(), idx);
return;
}
if (type.compare("vector3f") == 0) {
auto* flag = tparam->getVec3fFlagAndIdx(&idx, calc_hash());
if (!flag)
return;
sead::Vector3f v;
parseFloats(value, v.e.data(), v.e.size());
flag->setValue(v);
recordFlagChange(pl_core_id, tparam, flag->getType(), idx);
return;
}
if (type.compare("vector4f") == 0) {
auto* flag = tparam->getVec4fFlagAndIdx(&idx, calc_hash());
if (!flag)
return;
sead::Vector4f v;
parseFloats(value, v.e.data(), v.e.size());
flag->setValue(v);
recordFlagChange(pl_core_id, tparam, flag->getType(), idx);
return;
}
sead::FixedSafeString<64> sub_idx_str{"-1"};
if (it != end)
it.getAndForward(&sub_idx_str);
const int sub_idx =
sead::StringUtil::parseS32(sub_idx_str, sead::StringUtil::CardinalNumber::BaseAuto);
if (type.compare("boolarray") == 0) {
auto* flag = tparam->getBoolFlagAndIdx(&idx, calc_hash(), sub_idx);
if (!flag)
return;
bool v = false;
if (value == "true")
v = true;
flag->setValue(v);
recordFlagChange(pl_core_id, tparam, flag->getType(), idx, sub_idx);
return;
}
if (type.compare("s32array") == 0) {
auto* flag = tparam->getS32FlagAndIdx(&idx, calc_hash(), sub_idx);
if (!flag)
return;
s32 v = 0;
sead::StringUtil::tryParseS32(&v, value, sead::StringUtil::CardinalNumber::BaseAuto);
flag->setValue(v);
recordFlagChange(pl_core_id, tparam, flag->getType(), idx, sub_idx);
return;
}
if (type.compare("f32array") == 0) {
auto* flag = tparam->getF32FlagAndIdx(&idx, calc_hash(), sub_idx);
if (!flag)
return;
f32 v = 0;
sead::StringUtil::tryParseF32(&v, value);
flag->setValue(v);
recordFlagChange(pl_core_id, tparam, flag->getType(), idx, sub_idx);
return;
}
if (type.compare("stringarray") == 0) {
auto* flag = tparam->getStrFlagAndIdx(&idx, calc_hash(), sub_idx);
if (!flag)
return;
flag->setValue(value);
recordFlagChange(pl_core_id, tparam, flag->getType(), idx, sub_idx);
return;
}
if (type.compare("string64array") == 0) {
auto* flag = tparam->getStr64FlagAndIdx(&idx, calc_hash(), sub_idx);
if (!flag)
return;
flag->setValue(value);
recordFlagChange(pl_core_id, tparam, flag->getType(), idx, sub_idx);
return;
}
if (type.compare("string256array") == 0) {
auto* flag = tparam->getStr256FlagAndIdx(&idx, calc_hash(), sub_idx);
if (!flag)
return;
flag->setValue(value);
recordFlagChange(pl_core_id, tparam, flag->getType(), idx, sub_idx);
return;
}
if (type.compare("vector2farray") == 0) {
auto* flag = tparam->getVec2fFlagAndIdx(&idx, calc_hash(), sub_idx);
if (!flag)
return;
sead::Vector2f v;
parseFloats(value, v.e.data(), v.e.size());
flag->setValue(v);
recordFlagChange(pl_core_id, tparam, flag->getType(), idx, sub_idx);
return;
}
if (type.compare("vector3farray") == 0) {
auto* flag = tparam->getVec3fFlagAndIdx(&idx, calc_hash(), sub_idx);
if (!flag)
return;
sead::Vector3f v;
parseFloats(value, v.e.data(), v.e.size());
flag->setValue(v);
recordFlagChange(pl_core_id, tparam, flag->getType(), idx, sub_idx);
return;
}
if (type.compare("vector4farray") == 0) {
auto* flag = tparam->getVec4fFlagAndIdx(&idx, calc_hash(), sub_idx);
if (!flag)
return;
sead::Vector4f v;
parseFloats(value, v.e.data(), v.e.size());
flag->setValue(v);
recordFlagChange(pl_core_id, tparam, flag->getType(), idx, sub_idx);
return;
}
}
#endif
void Manager::recordFlagChange(u32 platform_core_id, TriggerParam* tparam, u8 type, const s32& idx,
const s32& sub_idx) {
auto& buffer = tparam->mFlagChangeRecords[platform_core_id].ref();
buffer[tparam->mFlagChangeRecordIndices[platform_core_id]].type.mValue = type;
buffer[tparam->mFlagChangeRecordIndices[platform_core_id]].index = idx;
buffer[tparam->mFlagChangeRecordIndices[platform_core_id]].sub_index = sub_idx;
++tparam->mFlagChangeRecordIndices[platform_core_id];
}
void Manager::startSyncOnLoadEnd() {
if (!mBitFlags.isOn(BitFlag::_100) || mBitFlags.isOn(BitFlag::_200))
return;
KingEditor::instance()->log(getName(), "[LoadEnd]");
mBitFlags.reset(BitFlag::SyncFlags);
mBitFlags.set(BitFlag::_200);
mSyncStep = 0;
syncStart();
}
void Manager::parseFloats(const sead::SafeString& str, f32* values, u32 n) {
auto it = str.tokenBegin(" ");
const auto end = str.tokenEnd(" ");
u32 i = 0;
while (end != it) {
sead::FixedSafeString<256> part;
it.getAndForward(&part);
f32 value;
if (!sead::StringUtil::tryParseF32(&value, part))
value = 0.0;
values[i++] = value;
if (i == n)
break;
}
}
namespace {
template <typename T>
void writeToBuffer(u8* buffer, u32* written, const T& value) {
static_assert(std::is_trivially_copyable<T>());
std::memcpy(buffer + *written, &value, sizeof(value));
*written += u32(sizeof(value));
}
} // namespace
template <typename T>
void Manager::doSyncArray(const sead::PtrArray<FlagBase>& array, u8* buffer,
const char* description) {
KingEditor::instance()->log(getName(), "[ArrayStart]");
u32 offset = 0;
const auto flush = [&] {
KingEditor::instance()->log(getName(), description, buffer, offset);
offset = 0;
};
for (FlagBase& flag : array) {
u32 written = 0;
writeToBuffer(buffer + offset, &written, flag.getHash());
if constexpr (std::is_same<bool, T>()) {
writeToBuffer(buffer + offset, &written, static_cast<Flag<T>&>(flag).getValue());
} else {
writeToBuffer(buffer + offset, &written, static_cast<Flag<T>&>(flag).getValueRef());
}
offset += written;
if (offset >= ComBufferSize - written)
flush();
}
if (offset != 0)
flush();
KingEditor::instance()->log(getName(), "[ArrayEnd]");
}
template <int N>
void Manager::doSyncArrayStr(const sead::PtrArray<FlagBase>& array, u8* buffer,
const char* description, u32 n) {
KingEditor::instance()->log(getName(), "[ArrayStart]");
u32 offset = 0;
const auto flush = [&] {
KingEditor::instance()->log(getName(), description, buffer, offset);
offset = 0;
};
for (FlagBase& flag : array) {
const auto& flag_ = static_cast<const Flag<sead::FixedSafeString<N>>&>(flag);
u8* entry = buffer + offset;
const u32 hash = flag.getHash();
std::memcpy(entry, &hash, sizeof(hash));
const auto len = flag_.getValueRef().calcLength();
sead::MemUtil::copy(entry + sizeof(hash), flag_.getValueRef().cstr(), len);
sead::MemUtil::fillZero(entry + u32(sizeof(hash) + len), n - len);
offset += u32(sizeof(hash) + n);
if (offset >= ComBufferSize - sizeof(hash) - n)
flush();
}
if (offset != 0)
flush();
KingEditor::instance()->log(getName(), "[ArrayEnd]");
}
template <typename T>
void Manager::doSyncArrayVec(const sead::PtrArray<FlagBase>& array, u8* buffer,
const char* description, u32 n) {
KingEditor::instance()->log(getName(), "[ArrayStart]");
u32 offset = 0;
const auto flush = [&] {
KingEditor::instance()->log(getName(), description, buffer, offset);
offset = 0;
};
for (FlagBase& flag : array) {
const auto& flag_ = static_cast<const Flag<T>&>(flag);
u32 written = 0;
writeToBuffer(buffer + offset, &written, flag.getHash());
for (u32 i = 0; i != n; ++i)
writeToBuffer(buffer + offset, &written, flag_.getValueRef().e[i]);
offset += written;
/// @bug "n" should be "sizeof(f32) * n" instead.
if (offset >= ComBufferSize - sizeof(u32) - n)
flush();
}
if (offset != 0)
flush();
KingEditor::instance()->log(getName(), "[ArrayEnd]");
}
template <typename T>
void Manager::doSyncArray(const sead::PtrArray<sead::PtrArray<FlagBase>>& array, u8* buffer,
const char* description) {
KingEditor::instance()->log(getName(), "[ArrayStart]");
for (auto& flags : array) {
u32 written = [&] {
u32 offset = 0;
auto it = flags.begin();
const auto end = flags.end();
writeToBuffer(buffer, &offset, flags[0]->getHash());
for (; it != end; ++it) {
writeToBuffer(buffer, &offset, static_cast<Flag<T>&>(*it).getValueRef());
if (offset >= ComBufferSize - sizeof(T))
break;
}
return offset;
}();
if (written != 0)
KingEditor::instance()->log(getName(), description, buffer, written);
}
KingEditor::instance()->log(getName(), "[ArrayEnd]");
}
template <int N>
void Manager::doSyncArrayStr(const sead::PtrArray<sead::PtrArray<FlagBase>>& array, u8* buffer,
const char* description, u32 n) {
KingEditor::instance()->log(getName(), "[ArrayStart]");
for (auto& flags : array) {
u32 written = [&] {
u32 offset = 0;
auto it = flags.begin();
const auto end = flags.end();
writeToBuffer(buffer, &offset, flags[0]->getHash());
for (; it != end; ++it) {
const auto& flag = static_cast<const Flag<sead::FixedSafeString<N>>&>(*it);
const auto len = flag.getValueRef().calcLength();
sead::MemUtil::copy(buffer + offset, flag.getValueRef().cstr(), len);
sead::MemUtil::fillZero(buffer + u32(offset + len), n - len);
offset += n;
if (offset >= u32(ComBufferSize) - n)
break;
}
return offset;
}();
if (written != 0)
KingEditor::instance()->log(getName(), description, buffer, written);
}
KingEditor::instance()->log(getName(), "[ArrayEnd]");
}
template <typename T>
static u32 syncOneVec(Manager*, u8* buffer, const sead::PtrArray<FlagBase>& flags, u32 n) {
u32 offset = 0;
auto it = flags.begin();
const auto end = flags.end();
writeToBuffer(buffer, &offset, flags[0]->getHash());
for (; it != end; ++it) {
for (u32 i = 0; i < n; ++i)
writeToBuffer(buffer, &offset, static_cast<const Flag<T>&>(*it).getValueRef().e[i]);
if (offset >= u32(ComBufferSize) - n)
break;
}
return offset;
}
template <typename T>
void Manager::doSyncArrayVec(const sead::PtrArray<sead::PtrArray<FlagBase>>& array, u8* buffer,
const char* description, u32 n) {
KingEditor::instance()->log(getName(), "[ArrayStart]");
for (auto& flags : array) {
u32 written = syncOneVec<T>(this, buffer, flags, n);
if (written != 0)
KingEditor::instance()->log(getName(), description, buffer, written);
}
KingEditor::instance()->log(getName(), "[ArrayEnd]");
}
} // namespace ksys::gdt