ksys/gdt: Add common flags

This commit is contained in:
Léo Lam 2020-11-05 13:46:20 +01:00
parent f2a8d32f29
commit d87fefe1fb
No known key found for this signature in database
GPG Key ID: 0DF30F9081000741
8 changed files with 11466 additions and 1 deletions

View File

@ -52351,7 +52351,8 @@
0x00000071008bf838,nullsub_2643,4, 0x00000071008bf838,nullsub_2643,4,
0x00000071008bf83c,sub_71008BF83C,8, 0x00000071008bf83c,sub_71008BF83C,8,
0x00000071008bf844,sub_71008BF844,92, 0x00000071008bf844,sub_71008BF844,92,
0x00000071008bf8a0,initGlobalGameDataFlagIndexes,148764, 0x00000071008bf8a0,_ZN4ksys3gdt11CommonFlags4initEv,4,_ZN4ksys3gdt15initCommonFlagsEv
0x00000071008bf8a4,initGlobalGameDataFlagIndexes,148760,_ZN4ksys3gdt16initCommonFlags_Ev
0x00000071008e3dbc,sub_71008E3DBC,12, 0x00000071008e3dbc,sub_71008E3DBC,12,
0x00000071008e3dc8,getStrBowPorchStockNum,12, 0x00000071008e3dc8,getStrBowPorchStockNum,12,
0x00000071008e3dd4,getStrCaptionPictSize,12, 0x00000071008e3dd4,getStrCaptionPictSize,12,

Can't render this file because it is too large.

View File

@ -1,7 +1,10 @@
target_sources(uking PRIVATE target_sources(uking PRIVATE
gdtCommonFlags.cpp
gdtCommonFlags.h
gdtFlag.cpp gdtFlag.cpp
gdtFlag.h gdtFlag.h
gdtFlagProxy.h gdtFlagProxy.h
gdtFlagUtils.h
gdtManager.cpp gdtManager.cpp
gdtManager.h gdtManager.h
gdtSaveMgr.cpp gdtSaveMgr.cpp

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,5 @@
#pragma once
#include "KingSystem/GameData/gdtManager.h"
namespace ksys::gdt {} // namespace ksys::gdt

View File

@ -22,6 +22,8 @@ namespace ksys::gdt {
enum class FlagHandle : u32 {}; enum class FlagHandle : u32 {};
constexpr FlagHandle InvalidHandle = FlagHandle(-1);
class TriggerParamRef { class TriggerParamRef {
public: public:
TriggerParamRef(TriggerParam** param_1, TriggerParam** param, bool check_permissions, TriggerParamRef(TriggerParam** param_1, TriggerParam** param, bool check_permissions,

View File

@ -0,0 +1,195 @@
#!/usr/bin/env python3
import argparse
from pathlib import Path
import typing as tp
import oead
def add_development_remnant_flags(flags: tp.Dict[str, str]):
_flags = {
"AoC_DragonFireChallengeRing_Advent": "bool_data",
"AoC_RandomSpawnTreasure_Contents": "string64_data",
"AoC_RandomSpawnTreasure_IsRandomized": "bool_data",
"AoC_TestProg_Imoto_Flag_00": "bool_data",
"AoC_TestProg_Imoto_TagCount_00": "s32_data",
"AocTestEx_Omosako_IsPastWorld": "bool_data",
"AocTestEx_Omosako_ReturnToMainField_Position": "vector3f_data",
"AocTestEx_Omosako_ReturnToMainField_Rotation": "f32_data",
"AocTestEx_Omosako_SandOfTime_Num": "s32_data",
"AocTestEx_Omosako_SandOfTime_Rate": "f32_data",
"Location_DarkDungeon01": "s32_data",
"Location_DarkDungeon02": "s32_data",
"Location_DarkDungeon03": "s32_data",
"Location_DarkDungeon04": "s32_data",
"SpurGear_revolve_01": "bool_data",
"SpurGear_revolve_02": "bool_data",
}
flags.update(_flags)
def load_flag_types(root: Path) -> tp.Dict[str, str]:
flag_types: tp.Dict[str, str] = dict()
add_development_remnant_flags(flag_types)
gdt_dir = root / "GameData"
for path in gdt_dir.glob("Flag/*.yml"):
flag_list = oead.byml.from_text(path.read_text(encoding="utf-8"))
keys = list(flag_list.keys())
assert len(keys) == 1
flag_type = keys[0]
for flag in flag_list[flag_type]:
flag_types[flag["DataName"]] = flag_type
return flag_types
def write_struct_chunk(f: tp.TextIO, flags: tp.Collection[str], i: int) -> None:
f.write(f"""\
struct CommonFlags{i} {{
""")
for name in flags:
f.write(f" FlagHandle flag_{name} = InvalidHandle;\n")
f.write(f"""\
u32 _pad = 0;
}};
[[gnu::visibility("hidden")]] extern CommonFlags{i} sCommonFlags{i};
""")
FLAGS_PER_CHUNK = 1023
def chunk_flag_iterator(flags: tp.Iterator[str]):
while True:
chunk = []
for i in range(FLAGS_PER_CHUNK):
try:
chunk.append(next(flags))
except StopIteration:
break
if not chunk:
return
yield chunk
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument("root", help="Path to the root of the GameROM source")
parser.add_argument("exe_flag_list", help="Path to a file containing a list of flags")
args = parser.parse_args()
src_root = Path(__file__).parent.parent
src_gdt = src_root / "src" / "KingSystem" / "GameData"
root = Path(args.root)
exe_flag_list = Path(args.exe_flag_list).read_text().splitlines()
flag_types = load_flag_types(root)
with (src_gdt / "gdtCommonFlags.h").open("w") as f:
f.write("""\
#pragma once
// DO NOT EDIT. This file is automatically generated.
#include "KingSystem/GameData/gdtManager.h"
namespace ksys::gdt {
// clang-format off
namespace detail {
""")
for i, chunk in enumerate(chunk_flag_iterator(iter(exe_flag_list))):
write_struct_chunk(f, chunk, i)
f.write("\n")
f.write("""\
} // namespace detail
void initCommonFlags();
""")
for i, name in enumerate(exe_flag_list):
chunk_idx: int = i // FLAGS_PER_CHUNK
f.write(f"inline FlagHandle& flag_{name}() {{ return detail::sCommonFlags{chunk_idx}.flag_{name}; }}\n")
pass
f.write("""\
// clang-format on
} // namespace ksys::gdt
""")
# Generate the implementation.
fn_names = {
"bool_data": "getBoolHandle",
"s32_data": "getS32Handle",
"f32_data": "getF32Handle",
"string_data": "getStrHandle",
"string64_data": "getStr64Handle",
"string256_data": "getStr256Handle",
"vector2f_data": "getVec2fHandle",
"vector3f_data": "getVec3fHandle",
"vector4f_data": "getVec4fHandle",
"bool_array_data": "getBoolArrayHandle",
"s32_array_data": "getS32ArrayHandle",
"f32_array_data": "getF32ArrayHandle",
"string_array_data": "getStrArrayHandle",
"string64_array_data": "getStr64ArrayHandle",
"string256_array_data": "getStr256ArrayHandle",
"vector2f_array_data": "getVec2fArrayHandle",
"vector3f_array_data": "getVec3fArrayHandle",
"vector4f_array_data": "getVec4fArrayHandle",
}
with (src_gdt / "gdtCommonFlags.cpp").open("w") as f:
f.write("""\
// DO NOT EDIT. This file is automatically generated.
#include "KingSystem/GameData/gdtCommonFlags.h"
namespace ksys::gdt {
namespace detail {
""")
for i in range(len(exe_flag_list) // FLAGS_PER_CHUNK + 1):
f.write(f"CommonFlags{i} sCommonFlags{i};\n")
f.write("""
} // namespace detail
void initCommonFlags_();
void initCommonFlags() {
initCommonFlags_();
}
void initCommonFlags_() {
auto* mgr = Manager::instance();
if (!mgr)
return;
// clang-format off
""")
for flag_name in exe_flag_list:
f.write(f" flag_{flag_name}() = mgr->{fn_names[flag_types[flag_name]]}(\"{flag_name}\");\n")
f.write("""\
// clang-format on
}
} // namespace ksys::gdt
""")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,31 @@
# This script needs to be compatible with Python 2.7 as it is executed in IDA.
import idaapi
import idautils
import idc
import os
# only valid in 1.5.0
LOAD_SAVEDATA_FUNCTION_START = 0x71008BF8A0
LOAD_SAVEDATA_FUNCTION_END = 0x71008E3DB8
CRC32_FUNCTION_EA = 0x7100B2170C
SAVEDATA_STRUCT = 0x710246F9E0
with open(os.path.dirname(os.path.realpath(__file__)) + "/../build/gdt_common_flags.txt", "w") as file:
struct_offset = 0
for ref in idautils.CodeRefsTo(idc.GetFunctionAttr(CRC32_FUNCTION_EA, idc.FUNCATTR_START), 1):
if not (LOAD_SAVEDATA_FUNCTION_START < ref < LOAD_SAVEDATA_FUNCTION_END):
continue
string_xref = idaapi.get_arg_addrs(ref)[0]
iterator = idautils.XrefsFrom(string_xref, 0)
next(iterator)
string_addr = next(iterator).to
string = idc.GetString(string_addr)
# For some reason the struct includes dummy members that should be skipped.
if idaapi.get_dword(SAVEDATA_STRUCT + struct_offset) == 0:
struct_offset += 4
file.write("%s\n" % string)
struct_offset += 4