From 9923503a09ffb07f8c4c2180ccc06b028f88aadc Mon Sep 17 00:00:00 2001 From: qaate47 Date: Mon, 4 Nov 2024 22:14:54 +0100 Subject: [PATCH] better vararg decomp/comp t10, remove hash.cpp --- src/acts/compiler/gsc_compiler.cpp | 16 +++ src/acts/hashutils.cpp | 3 + src/acts/hashutils.hpp | 4 +- src/acts/tools/gsc.cpp | 66 ++++++++++++- src/acts/tools/gsc.hpp | 15 ++- src/acts/tools/gsc_opcodes.cpp | 18 +++- src/acts/tools/gsc_opcodes.hpp | 1 + src/acts/tools/gsc_vm/vm_jup_opcodes.cpp | 4 +- src/acts/tools/gsc_vm/vm_t10.cpp | 10 +- src/acts/tools/gsc_vm/vm_t10_opcodes.cpp | 8 +- src/shared/hash.cpp | 38 ------- src/shared/hash.hpp | 120 ++++++++++++++++------- test/gsc-compiler/acts_cer_test.gsc | 5 +- test/gsc-compiler/acts_cer_test2.gsc | 6 ++ 14 files changed, 215 insertions(+), 99 deletions(-) delete mode 100644 src/shared/hash.cpp create mode 100644 test/gsc-compiler/acts_cer_test2.gsc diff --git a/src/acts/compiler/gsc_compiler.cpp b/src/acts/compiler/gsc_compiler.cpp index d503876..16739b4 100644 --- a/src/acts/compiler/gsc_compiler.cpp +++ b/src/acts/compiler/gsc_compiler.cpp @@ -5616,6 +5616,22 @@ namespace acts::compiler { return nullptr; } + if (obj.gscHandler->HasFlag(tool::gsc::GOHF_VAR_VA_COUNT)) { + std::string paramIdfCount = "varargcount"; + if (exp.m_params == 256) { + obj.info.PrintLineMessage(alogs::LVL_ERROR, param, std::format("Can't register param '{}': too many params", paramIdfCount)); + return nullptr; + } + exp.m_params++; + + auto [err, vardef] = exp.RegisterVar(paramIdfCount, false); + if (err) { + obj.info.PrintLineMessage(alogs::LVL_ERROR, param, err); + return nullptr; + } + } + + continue; } diff --git a/src/acts/hashutils.cpp b/src/acts/hashutils.cpp index c8df85f..301e1f7 100644 --- a/src/acts/hashutils.cpp +++ b/src/acts/hashutils.cpp @@ -191,6 +191,7 @@ namespace hashutils { Add("system", true, iw, true); Add("scripts/core_common/system_shared.csc", true, iw, true); Add("scripts/core_common/system_shared.gsc", true, iw, true); + Add("scripts/common/system.gsc", true, iw, true); Add("register", true, iw, true); Add("__init__system__", true, iw, true); Add("__init__", true, iw, true); @@ -198,7 +199,9 @@ namespace hashutils { Add("main", true, iw, true); Add("init", true, iw, true); // it seems all the varargs are called "vararg", but a flag is also describing, so idk + // in t10 the vararg param is followed by varargcount Add("vararg", true, iw, true); + Add("varargcount", true, iw, true); // basic letter char buff[2] = { 0, 0 }; diff --git a/src/acts/hashutils.hpp b/src/acts/hashutils.hpp index c8fe954..2b9d85a 100644 --- a/src/acts/hashutils.hpp +++ b/src/acts/hashutils.hpp @@ -3,8 +3,8 @@ #include namespace hashutils { - constexpr uint64_t MASK62 = 0xFFFFFFFFFFFFFFFull; - constexpr uint64_t MASK63 = 0x7FFFFFFFFFFFFFFFull; + constexpr uint64_t MASK62 = hash::MASK62; + constexpr uint64_t MASK63 = hash::MASK63; constexpr auto DEFAULT_HASH_FILE = "strings.txt"; /* diff --git a/src/acts/tools/gsc.cpp b/src/acts/tools/gsc.cpp index ad21eb2..ee03a37 100644 --- a/src/acts/tools/gsc.cpp +++ b/src/acts/tools/gsc.cpp @@ -22,6 +22,13 @@ enum DumpVTableAnswer : int { GscInfoOption::GscInfoOption() { // set default formatter m_formatter = &tool::gsc::formatter::GetFromName(); +} + +bool tool::gsc::GscDecompilerGlobalContext::WarningType(GscDecompilerGlobalContextWarn warn) { + core::async::opt_lock_guard lg{ asyncMtx }; + if ((warningOpt & warn)) return false; + warningOpt |= warn; + return true; } bool GscInfoOption::Compute(const char** args, INT startIndex, INT endIndex) { @@ -111,6 +118,9 @@ bool GscInfoOption::Compute(const char** args, INT startIndex, INT endIndex) { else if (!_strcmpi("--vtable", arg)) { m_vtable = true; } + else if (!_strcmpi("--debug-hashes", arg)) { + m_debugHashes = true; + } else if (!_strcmpi("--vtable-dump", arg)) { if (i + 1 == endIndex) { LOG_ERROR("Missing value for param: {}!", arg); @@ -355,6 +365,7 @@ void GscInfoOption::PrintHelp() { LOG_DEBUG("--ignore-dbg-plt : ignore debug platform info"); LOG_DEBUG("-A --sync [mode] : Sync mode: async or sync"); LOG_DEBUG("--vtable : Do not hide and decompile vtable functions"); + LOG_DEBUG("--debug-hashes : Debug hash alogrithm"); LOG_DEBUG("-i --ignore[t + ] : ignore step : "); LOG_DEBUG(" a : all, d: devblocks, s : switch, e : foreach, w : while, i : if, f : for, r : return"); LOG_DEBUG(" R : bool return, c: class members, D: devblocks inline, S : special patterns"); @@ -1182,6 +1193,16 @@ int GscInfoHandleData(byte* data, size_t size, const char* path, GscDecompilerGl char asmfnamebuff[1000]; + const char* extractedName{ hashutils::ExtractPtr(scriptfile->GetName()) }; + + if (opt.m_debugHashes && extractedName) { + uint64_t hashPath{ vmInfo->HashPath(extractedName) }; + + if (hashPath != scriptfile->GetName() && gdctx.WarningType(GDGCW_BAD_HASH_PATH)) { + LOG_WARNING("Invalid hash algorithm for extracted name 0x{:x} != 0x{:x} for {}", scriptfile->GetName(), hashPath, extractedName); + } + } + if (opt.m_outputDir) { const char* name = opt.m_noPath ? nullptr : hashutils::ExtractPtr(scriptfile->GetName()); @@ -1462,6 +1483,17 @@ int GscInfoHandleData(byte* data, size_t size, const char* path, GscDecompilerGl for (size_t i = 0; i < scriptfile->GetIncludesCount(); i++) { asmout << "#using " << hashutils::ExtractTmpScript(includes[i]) << ";\n"; + + if (opt.m_debugHashes) { + const char* incExt{ hashutils::ExtractPtr(includes[i]) }; + if (incExt) { + uint64_t hashPath{ vmInfo->HashPath(incExt) }; + + if (hashPath != includes[i] && gdctx.WarningType(GDGCW_BAD_HASH_PATH_INCLUDE)) { + LOG_WARNING("Invalid hash alogithm for extracted include 0x{:x} != 0x{:x} for {}", includes[i], hashPath, incExt); + } + } + } } if (scriptfile->GetIncludesCount()) { asmout << "\n"; @@ -1717,6 +1749,31 @@ int GscInfoHandleData(byte* data, size_t size, const char* path, GscDecompilerGl auto& asmctx = r.first->second; + + if (opt.m_debugHashes) { + uint64_t name{ exp->GetName() }; + const char* namePtr{ hashutils::ExtractPtr(name) }; + if (namePtr) { + uint64_t hashScr{ vmInfo->HashField(namePtr) }; + + if (hashScr != name && gdctx.WarningType(GDGCW_BAD_HASH_FIELD)) { + LOG_WARNING("Invalid hash algorithm for extracted field 0x{:x} != 0x{:x} for {}", name, hashScr, namePtr); + } + } + uint64_t fileNameSpace{ exp->GetFileNamespace() }; + if (fileNameSpace) { + + const char* fnsPtr{ hashutils::ExtractPtr(fileNameSpace) }; + if (fnsPtr) { + uint64_t hashFSScr{ vmInfo->HashFilePath(fnsPtr) }; + + if (hashFSScr != fileNameSpace && gdctx.WarningType(GDGCW_BAD_HASH_FILE)) { + LOG_WARNING("Invalid hash algorithm for extracted field 0x{:x} != 0x{:x} for {}", fileNameSpace, hashFSScr, fnsPtr); + } + } + } + } + DumpFunctionHeader(*exp, output, *scriptfile, ctx, asmctx); if (asmctx.m_opt.m_formatter->flags & tool::gsc::formatter::FFL_NEWLINE_AFTER_BLOCK_START) { @@ -3072,13 +3129,16 @@ void tool::gsc::DumpFunctionHeader(GSCExportReader& exp, std::ostream& asmout, G } for (size_t i = 0; i < exp.GetParamCount(); i++) { + // -1 to avoid the object, -1 because we are in reverse order + const auto& lvar = ctx.m_localvars[ctx.m_localvars.size() - i - 2]; + + if ((lvar.flags & T8GSCLocalVarFlag::IW_VARIADIC_COUNT) && !lvar.defaultValueNode) { + continue; // ignore if the varargcount is used + } if (i) { asmout << ", "; } - // -1 to avoid the object, -1 because we are in reverse order - const auto& lvar = ctx.m_localvars[ctx.m_localvars.size() - i - 2]; - if (lvar.flags & T8GSCLocalVarFlag::VARIADIC) { asmout << "..."; } diff --git a/src/acts/tools/gsc.hpp b/src/acts/tools/gsc.hpp index 15e9c45..0d81c0c 100644 --- a/src/acts/tools/gsc.hpp +++ b/src/acts/tools/gsc.hpp @@ -46,6 +46,7 @@ namespace tool::gsc { GOHF_STRING_NAMES = 0x2000, GOHF_NOTIFY_CRC_STRING = 0x4000, GOHF_FILENAMESPACE = 0x8000, + GOHF_VAR_VA_COUNT = 0x10000, }; static_assert( ((GOHF_FOREACH_TYPE_T8 | GOHF_FOREACH_TYPE_T9 | GOHF_FOREACH_TYPE_JUP | GOHF_FOREACH_TYPE_T7 @@ -95,6 +96,7 @@ namespace tool::gsc { bool m_ignoreDebugPlatform{}; bool m_sync{ true }; bool m_vtable{}; + bool m_debugHashes{}; const char* vtable_dump{}; uint32_t m_stepskip{}; opcode::Platform m_platform{ opcode::Platform::PLATFORM_PC }; @@ -267,7 +269,8 @@ namespace tool::gsc { enum T8GSCLocalVarFlag : uint8_t { ARRAY_REF = 0x01, VARIADIC = 0x02, - T9_VAR_REF = 0x04 // T9 + T9_VAR_REF = 0x04, // T9 + IW_VARIADIC_COUNT = 0x80, // Special value }; class OPCodeInfo { @@ -733,9 +736,17 @@ namespace tool::gsc { std::unordered_set m_vtableMethods{}; std::unordered_map m_vtable{}; }; + enum GscDecompilerGlobalContextWarn : uint64_t { + GDGCW_BAD_HASH_PATH = 1, + GDGCW_BAD_HASH_FIELD = 1 << 1, + GDGCW_BAD_HASH_FILE = 1 << 2, + GDGCW_BAD_HASH_PATH_INCLUDE = 1 << 3, + }; + struct GscDecompilerGlobalContext { std::mutex* asyncMtx{}; GscInfoOption opt{}; + uint64_t warningOpt{}; std::unordered_map debugObjects{}; size_t decompiledFiles{}; std::unordered_map>> vtables{}; @@ -745,6 +756,8 @@ namespace tool::gsc { delete d; } } + + bool WarningType(GscDecompilerGlobalContextWarn warn); }; // Result context for T8GSCOBJ::PatchCode class T8GSCOBJContext { diff --git a/src/acts/tools/gsc_opcodes.cpp b/src/acts/tools/gsc_opcodes.cpp index d2d91de..0107df1 100644 --- a/src/acts/tools/gsc_opcodes.cpp +++ b/src/acts/tools/gsc_opcodes.cpp @@ -263,7 +263,7 @@ uint64_t VmInfo::HashPath(const char* value) const { if (hash::TryHashPattern(value, t)) { return t; } - if (HasFlag(VmFlags::VMF_HASH_CER) || HasFlag(VmFlags::VMF_HASH_CER_SP) || HasFlag(VmFlags::VMF_HASH_IW)) { + if (HasFlag(VmFlags::VMF_HASH_PATH_IW)) { return hash::HashIWRes(value); } return hash::Hash64(value); @@ -798,6 +798,7 @@ class OPCodeInfoSafeCreateLocalVariables : public OPCodeInfo { context.m_localvars.insert(context.m_localvars.begin(), { hash::HashT89Scr(""), 0 }); } + bool lastVa{}; for (size_t i = 0; i < count; i++) { context.WritePadding(out); uint64_t varName; @@ -817,7 +818,7 @@ class OPCodeInfoSafeCreateLocalVariables : public OPCodeInfo { context.m_bcl += 4; } auto& bytecode = context.m_bcl; - + byte flags; if (objctx.m_vmInfo->flags & VmFlags::VMF_NO_PARAM_FLAGS) { flags = 0; @@ -826,13 +827,24 @@ class OPCodeInfoSafeCreateLocalVariables : public OPCodeInfo { flags = *(bytecode++); } + byte flagsGen{ flags }; + + if (lastVa) { + out << "(va count)"; + flagsGen |= T8GSCLocalVarFlag::IW_VARIADIC_COUNT; + lastVa = false; + } + // the variables are in reversed order - context.m_localvars.insert(context.m_localvars.begin(), { varName, flags }); + context.m_localvars.insert(context.m_localvars.begin(), { varName, flagsGen }); out << hashutils::ExtractTmp("var", varName); if (flags & T8GSCLocalVarFlag::VARIADIC) { out << "..."; + if (context.m_gscReader.HasFlag(tool::gsc::GOHF_VAR_VA_COUNT)) { + lastVa = true; + } } else if (flags & T8GSCLocalVarFlag::ARRAY_REF) { out << "&"; diff --git a/src/acts/tools/gsc_opcodes.hpp b/src/acts/tools/gsc_opcodes.hpp index df128e6..468396b 100644 --- a/src/acts/tools/gsc_opcodes.hpp +++ b/src/acts/tools/gsc_opcodes.hpp @@ -26,6 +26,7 @@ namespace tool::gsc::opcode { VMF_CRC_DUMP = 1 << 17, VMF_EXPORT_CRC32 = 1 << 18, VMF_HASH_CER_SP = 1 << 19, + VMF_HASH_PATH_IW = 1 << 20, }; enum VmOperatorFunctionData : uint64_t { VPFD_NONE = 0, diff --git a/src/acts/tools/gsc_vm/vm_jup_opcodes.cpp b/src/acts/tools/gsc_vm/vm_jup_opcodes.cpp index a96185f..95078f3 100644 --- a/src/acts/tools/gsc_vm/vm_jup_opcodes.cpp +++ b/src/acts/tools/gsc_vm/vm_jup_opcodes.cpp @@ -7,7 +7,7 @@ namespace { using namespace tool::gsc::opcode; void OpCode() { - VmInfo* v8a = RegisterVM(VMI_JUP_8A, "Call of Duty: Modern Warfare III", "jup", "mwiiia", VmFlags::VMF_FOREACH_IW | VmFlags::VMF_HASH64 | VmFlags::VMF_NO_PARAM_FLAGS | VmFlags::VMF_FULL_FILE_NAMESPACE | VmFlags::VMF_HASH_IW | VmFlags::VMF_CALL_NO_PARAMS | VmFlags::VMF_IW_CALLS); + VmInfo* v8a = RegisterVM(VMI_JUP_8A, "Call of Duty: Modern Warfare III", "jup", "mwiiia", VmFlags::VMF_FOREACH_IW | VmFlags::VMF_HASH64 | VmFlags::VMF_NO_PARAM_FLAGS | VmFlags::VMF_FULL_FILE_NAMESPACE | VmFlags::VMF_HASH_IW | VmFlags::VMF_HASH_PATH_IW | VmFlags::VMF_CALL_NO_PARAMS | VmFlags::VMF_IW_CALLS); v8a->RegisterVmName("jupa", "s5a", "mwiiia", "modernwarfareiiia", "mw23a"); v8a->AddPlatform(PLATFORM_PC); v8a->RegisterSameCodePlatform(PLATFORM_PC, PLATFORM_PLAYSTATION); @@ -34,7 +34,7 @@ namespace { v8a->RegisterOpCode(PLATFORM_PC, OPCODE_SafeCreateLocalVariables, 0x98); v8a->RegisterOpCode(PLATFORM_PC, OPCODE_IW_RegisterVariable, 0x2B, 0xA4); - VmInfo* v8b = RegisterVM(VMI_JUP_8B, "Call of Duty: Modern Warfare III (8B)", "jup8b", "mwiii", VmFlags::VMF_CRC_DUMP | VmFlags::VMF_FOREACH_IW | VmFlags::VMF_HASH64 | VmFlags::VMF_NO_PARAM_FLAGS | VmFlags::VMF_FULL_FILE_NAMESPACE | VmFlags::VMF_HASH_IW | VmFlags::VMF_CALL_NO_PARAMS | VmFlags::VMF_IW_CALLS); + VmInfo* v8b = RegisterVM(VMI_JUP_8B, "Call of Duty: Modern Warfare III (8B)", "jup8b", "mwiii", VmFlags::VMF_CRC_DUMP | VmFlags::VMF_FOREACH_IW | VmFlags::VMF_HASH64 | VmFlags::VMF_NO_PARAM_FLAGS | VmFlags::VMF_FULL_FILE_NAMESPACE | VmFlags::VMF_HASH_IW | VmFlags::VMF_HASH_PATH_IW | VmFlags::VMF_CALL_NO_PARAMS | VmFlags::VMF_IW_CALLS); v8b->RegisterVmName("jup", "s5", "mwiii", "modernwarfareiii", "mw23"); v8b->AddPlatform(PLATFORM_PC); v8b->RegisterVMGlobalVariable("level", OPCODE_IW_GetLevel); diff --git a/src/acts/tools/gsc_vm/vm_t10.cpp b/src/acts/tools/gsc_vm/vm_t10.cpp index 7435349..65f5b29 100644 --- a/src/acts/tools/gsc_vm/vm_t10.cpp +++ b/src/acts/tools/gsc_vm/vm_t10.cpp @@ -12,7 +12,7 @@ namespace { class T1006GSCOBJHandler : public GSCOBJHandler { public: - T1006GSCOBJHandler(byte* file, size_t fileSize) : GSCOBJHandler(file, fileSize, GOHF_ANIMTREE | GOHF_ANIMTREE_DOUBLE | GOHF_FOREACH_TYPE_JUP | GOHF_NOTIFY_CRC_STRING | GOHF_SUPPORT_EV_HANDLER | GOHF_SUPPORT_VAR_VA) {} + T1006GSCOBJHandler(byte* file, size_t fileSize) : GSCOBJHandler(file, fileSize, GOHF_ANIMTREE | GOHF_ANIMTREE_DOUBLE | GOHF_FOREACH_TYPE_JUP | GOHF_NOTIFY_CRC_STRING | GOHF_SUPPORT_EV_HANDLER | GOHF_SUPPORT_VAR_VA | GOHF_VAR_VA_COUNT) {} void DumpHeader(std::ostream& asmout, const GscInfoOption& opt) override { GscObj24* data = Ptr(); @@ -342,7 +342,7 @@ namespace { class T1007GSCOBJHandler : public GSCOBJHandler { public: - T1007GSCOBJHandler(byte* file, size_t fileSize) : GSCOBJHandler(file, fileSize, GOHF_ANIMTREE | GOHF_ANIMTREE_DOUBLE | GOHF_FOREACH_TYPE_JUP | GOHF_NOTIFY_CRC_STRING | GOHF_SUPPORT_EV_HANDLER | GOHF_SUPPORT_VAR_VA) {} + T1007GSCOBJHandler(byte* file, size_t fileSize) : GSCOBJHandler(file, fileSize, GOHF_ANIMTREE | GOHF_ANIMTREE_DOUBLE | GOHF_FOREACH_TYPE_JUP | GOHF_NOTIFY_CRC_STRING | GOHF_SUPPORT_EV_HANDLER | GOHF_SUPPORT_VAR_VA | GOHF_VAR_VA_COUNT) {} void DumpHeader(std::ostream& asmout, const GscInfoOption& opt) override { GscObj24* data = Ptr(); @@ -671,7 +671,7 @@ namespace { class T100CGSCOBJHandler : public GSCOBJHandler { public: - T100CGSCOBJHandler(byte* file, size_t fileSize) : GSCOBJHandler(file, fileSize, GOHF_ANIMTREE | GOHF_ANIMTREE_DOUBLE | GOHF_FOREACH_TYPE_JUP | GOHF_NOTIFY_CRC_STRING | GOHF_SUPPORT_EV_HANDLER | GOHF_SUPPORT_VAR_VA) {} + T100CGSCOBJHandler(byte* file, size_t fileSize) : GSCOBJHandler(file, fileSize, GOHF_ANIMTREE | GOHF_ANIMTREE_DOUBLE | GOHF_FOREACH_TYPE_JUP | GOHF_NOTIFY_CRC_STRING | GOHF_SUPPORT_EV_HANDLER | GOHF_SUPPORT_VAR_VA | GOHF_VAR_VA_COUNT) {} void DumpHeader(std::ostream& asmout, const GscInfoOption& opt) override { GscObj24* data = Ptr(); @@ -997,12 +997,12 @@ namespace { }; - + /*****************************************************************************************************************************/ class T100BGSCOBJHandler : public GSCOBJHandler { public: - T100BGSCOBJHandler(byte* file, size_t fileSize) : GSCOBJHandler(file, fileSize, GOHF_ANIMTREE | GOHF_ANIMTREE_DOUBLE | GOHF_FOREACH_TYPE_JUP | GOHF_NOTIFY_CRC_STRING | GOHF_SUPPORT_EV_HANDLER | GOHF_SUPPORT_VAR_VA) {} + T100BGSCOBJHandler(byte* file, size_t fileSize) : GSCOBJHandler(file, fileSize, GOHF_ANIMTREE | GOHF_ANIMTREE_DOUBLE | GOHF_FOREACH_TYPE_JUP | GOHF_NOTIFY_CRC_STRING | GOHF_SUPPORT_EV_HANDLER | GOHF_SUPPORT_VAR_VA | GOHF_VAR_VA_COUNT) {} void DumpHeader(std::ostream& asmout, const GscInfoOption& opt) override { GscObj24* data = Ptr(); diff --git a/src/acts/tools/gsc_vm/vm_t10_opcodes.cpp b/src/acts/tools/gsc_vm/vm_t10_opcodes.cpp index 56f0e8a..b00d4f8 100644 --- a/src/acts/tools/gsc_vm/vm_t10_opcodes.cpp +++ b/src/acts/tools/gsc_vm/vm_t10_opcodes.cpp @@ -7,7 +7,7 @@ namespace { using namespace tool::gsc::opcode; void OpCode() { - VmInfo* t106 = RegisterVM(VMI_T10_06, "Call of Duty: Black Ops 6 (06)", "t10_6", "bo6_6", VmFlags::VMF_EXPORT_NOCHECKSUM | VmFlags::VMF_CRC_DUMP | VmFlags::VMF_FOREACH_IW | VmFlags::VMF_HASH64 | VmFlags::VMF_FULL_FILE_NAMESPACE | VmFlags::VMF_HASH_CER | VmFlags::VMF_CALL_NO_PARAMS); // VmFlags::VMF_IW_CALLS | VmFlags::VMF_NO_PARAM_FLAGS + VmInfo* t106 = RegisterVM(VMI_T10_06, "Call of Duty: Black Ops 6 (06)", "t10_6", "bo6_6", VmFlags::VMF_EXPORT_NOCHECKSUM | VmFlags::VMF_CRC_DUMP | VmFlags::VMF_FOREACH_IW | VmFlags::VMF_HASH64 | VmFlags::VMF_FULL_FILE_NAMESPACE | VmFlags::VMF_HASH_CER | VmFlags::VMF_HASH_PATH_IW | VmFlags::VMF_CALL_NO_PARAMS); // VmFlags::VMF_IW_CALLS | VmFlags::VMF_NO_PARAM_FLAGS t106->RegisterVmName("cer6", "t10_6", "blackops6_6"); t106->AddPlatform(PLATFORM_PC); t106->RegisterVMGlobalVariable("level", OPCODE_IW_GetLevel); @@ -149,7 +149,7 @@ namespace { t106->RegisterOpCode(PLATFORM_PC, OPCODE_IW_GetAnimationTree, 0xa0); - VmInfo* t107 = RegisterVM(VMI_T10_07, "Call of Duty: Black Ops 6 (07)", "t10", "bo6_7", VmFlags::VMF_CRC_DUMP | VmFlags::VMF_FOREACH_IW | VmFlags::VMF_EXPORT_NOCHECKSUM | VmFlags::VMF_HASH64 | VmFlags::VMF_FULL_FILE_NAMESPACE | VmFlags::VMF_HASH_CER | VmFlags::VMF_CALL_NO_PARAMS); // VmFlags::VMF_IW_CALLS | VmFlags::VMF_NO_PARAM_FLAGS + VmInfo* t107 = RegisterVM(VMI_T10_07, "Call of Duty: Black Ops 6 (07)", "t10", "bo6_7", VmFlags::VMF_CRC_DUMP | VmFlags::VMF_FOREACH_IW | VmFlags::VMF_EXPORT_NOCHECKSUM | VmFlags::VMF_HASH64 | VmFlags::VMF_FULL_FILE_NAMESPACE | VmFlags::VMF_HASH_CER | VmFlags::VMF_HASH_PATH_IW | VmFlags::VMF_CALL_NO_PARAMS); // VmFlags::VMF_IW_CALLS | VmFlags::VMF_NO_PARAM_FLAGS t107->RegisterVmName("cer7", "t10_7", "blackops6_7"); t107->AddPlatform(PLATFORM_PC); t107->RegisterVMGlobalVariable("level", OPCODE_IW_GetLevel); @@ -183,7 +183,7 @@ namespace { t107->RegisterOpCode(PLATFORM_PC, OPCODE_SafeCreateLocalVariables, 0x5a); t107->RegisterOpCode(PLATFORM_PC, OPCODE_IW_RegisterMultipleVariables, 0x53); - VmInfo* t10b = RegisterVM(VMI_T10_0B, "Call of Duty: Black Ops 6 (0B)", "t10", "bo6_b", VmFlags::VMF_CRC_DUMP | VmFlags::VMF_FOREACH_IW | VmFlags::VMF_EXPORT_CRC32 | VmFlags::VMF_HASH64 | VmFlags::VMF_FULL_FILE_NAMESPACE | VmFlags::VMF_HASH_CER_SP | VmFlags::VMF_CALL_NO_PARAMS); // VmFlags::VMF_IW_CALLS | VmFlags::VMF_NO_PARAM_FLAGS + VmInfo* t10b = RegisterVM(VMI_T10_0B, "Call of Duty: Black Ops 6 (0B)", "t10", "bo6_b", VmFlags::VMF_CRC_DUMP | VmFlags::VMF_FOREACH_IW | VmFlags::VMF_EXPORT_CRC32 | VmFlags::VMF_HASH64 | VmFlags::VMF_FULL_FILE_NAMESPACE | VmFlags::VMF_HASH_CER_SP | VmFlags::VMF_HASH_PATH_IW | VmFlags::VMF_CALL_NO_PARAMS); // VmFlags::VMF_IW_CALLS | VmFlags::VMF_NO_PARAM_FLAGS t10b->RegisterVmName("cerb", "t10_b", "blackops6_b", "t10sp", "bo6sp"); t10b->AddPlatform(PLATFORM_PC); t10b->RegisterVMGlobalVariable("level", OPCODE_IW_GetLevel); @@ -211,7 +211,7 @@ namespace { t10b->RegisterOpCode(PLATFORM_PC, OPCODE_SafeCreateLocalVariables, 0x20); t10b->RegisterOpCode(PLATFORM_PC, OPCODE_IW_RegisterMultipleVariables, 0x93); - VmInfo* t10c = RegisterVM(VMI_T10_0C, "Call of Duty: Black Ops 6", "t10", "bo6", VmFlags::VMF_CRC_DUMP | VmFlags::VMF_FOREACH_IW | VmFlags::VMF_EXPORT_CRC32 | VmFlags::VMF_HASH64 | VmFlags::VMF_FULL_FILE_NAMESPACE | VmFlags::VMF_HASH_CER | VmFlags::VMF_CALL_NO_PARAMS); // VmFlags::VMF_IW_CALLS | VmFlags::VMF_NO_PARAM_FLAGS + VmInfo* t10c = RegisterVM(VMI_T10_0C, "Call of Duty: Black Ops 6", "t10", "bo6", VmFlags::VMF_CRC_DUMP | VmFlags::VMF_FOREACH_IW | VmFlags::VMF_EXPORT_CRC32 | VmFlags::VMF_HASH64 | VmFlags::VMF_FULL_FILE_NAMESPACE | VmFlags::VMF_HASH_CER | VmFlags::VMF_HASH_PATH_IW | VmFlags::VMF_CALL_NO_PARAMS); // VmFlags::VMF_IW_CALLS | VmFlags::VMF_NO_PARAM_FLAGS t10c->RegisterVmName("cer", "t10", "blackops6"); t10c->AddPlatform(PLATFORM_PC); t10c->RegisterVMGlobalVariable("level", OPCODE_IW_GetLevel); diff --git a/src/shared/hash.cpp b/src/shared/hash.cpp deleted file mode 100644 index e1551c3..0000000 --- a/src/shared/hash.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include - -namespace hash { - - bool TryHashPattern(const char* str, uint64_t& outVal) { - std::string_view v{ str }; - - if (!v.rfind("var_", 0)) { - outVal = std::strtoull(&str[4], nullptr, 16); - return true; - } - if (!v.rfind("event_", 0)) { - outVal = std::strtoull(&str[6], nullptr, 16); - return true; - } - if (!v.rfind("function_", 0)) { - outVal = std::strtoull(&str[9], nullptr, 16); - return true; - } - if (!v.rfind("namespace_", 0)) { - outVal = std::strtoull(&str[10], nullptr, 16); - return true; - } - if (!v.rfind("script_", 0)) { - outVal = std::strtoull(&str[7], nullptr, 16); - return true; - } - if (!v.rfind("hash_", 0)) { - outVal = std::strtoull(&str[5], nullptr, 16); - return true; - } - if (!v.rfind("file_", 0)) { - outVal = std::strtoull(&str[5], nullptr, 16); - return true; - } - return false; - } -} \ No newline at end of file diff --git a/src/shared/hash.hpp b/src/shared/hash.hpp index a40d39b..9f35424 100644 --- a/src/shared/hash.hpp +++ b/src/shared/hash.hpp @@ -1,6 +1,8 @@ #pragma once namespace hash { + constexpr uint64_t MASK62 = 0xFFFFFFFFFFFFFFFull; + constexpr uint64_t MASK63 = 0x7FFFFFFFFFFFFFFFull; /* * Compute the hash32 on a string (canon id) * @param str String to compute @@ -54,61 +56,110 @@ namespace hash { return Hash64A(str, start, iv) & 0x7FFFFFFFFFFFFFFF; } - bool TryHashPattern(const char* str, uint64_t& outVal); - inline uint64_t HashPattern(const char* str) { - uint64_t out; - if (TryHashPattern(str, out)) { - return out; + constexpr bool TryHashPattern(const char* str, uint64_t& outVal) { + std::string_view v{ str }; + + if (!str || !*str) { + outVal = 0; + return true; } - return 0; - } + if (!v.rfind("var_", 0)) { + outVal = std::strtoull(&str[4], nullptr, 16); + return true; + } + if (!v.rfind("event_", 0)) { + outVal = std::strtoull(&str[6], nullptr, 16); + return true; + } + if (!v.rfind("function_", 0)) { + outVal = std::strtoull(&str[9], nullptr, 16); + return true; + } + if (!v.rfind("namespace_", 0)) { + outVal = std::strtoull(&str[10], nullptr, 16); + return true; + } + if (!v.rfind("script_", 0)) { + outVal = std::strtoull(&str[7], nullptr, 16); + return true; + } + if (!v.rfind("hash_", 0)) { + outVal = std::strtoull(&str[5], nullptr, 16); + return true; + } + if (!v.rfind("file_", 0)) { + outVal = std::strtoull(&str[5], nullptr, 16); + return true; + } + return false; + } - inline uint64_t HashPattern(const wchar_t* str) { + constexpr bool TryHashPattern(const wchar_t* str, uint64_t& outVal) { std::wstring_view v{ str }; + if (!str || !*str) { + outVal = 0; + return true; + } + if (!v.rfind(L"var_", 0)) { - return std::wcstoull(&str[4], nullptr, 16); + outVal = std::wcstoull(&str[4], nullptr, 16); + return true; } if (!v.rfind(L"event_", 0)) { - return std::wcstoull(&str[6], nullptr, 16); + outVal = std::wcstoull(&str[6], nullptr, 16); + return true; } if (!v.rfind(L"function_", 0)) { - return std::wcstoull(&str[9], nullptr, 16); + outVal = std::wcstoull(&str[9], nullptr, 16); + return true; } if (!v.rfind(L"namespace_", 0)) { - return std::wcstoull(&str[10], nullptr, 16); + outVal = std::wcstoull(&str[10], nullptr, 16); + return true; } if (!v.rfind(L"script_", 0)) { - return std::wcstoull(&str[7], nullptr, 16); + outVal = std::wcstoull(&str[7], nullptr, 16); + return true; } if (!v.rfind(L"hash_", 0)) { - return std::wcstoull(&str[5], nullptr, 16); + outVal = std::wcstoull(&str[5], nullptr, 16); + return true; } if (!v.rfind(L"file_", 0)) { - return std::wcstoull(&str[5], nullptr, 16); + outVal = std::wcstoull(&str[5], nullptr, 16); + return true; + } + return false; + } + + constexpr uint64_t HashPattern(const char* str) { + uint64_t out; + if (TryHashPattern(str, out)) { + return out; } return 0; } - /* - * Compute the hash32 on a string (canon id), but allow pattern like "function_123456" - * @param str String to compute - * @return Hashed value - */ - inline uint32_t HashT89ScrPattern(const char* str) { - uint32_t p = (uint32_t) HashPattern(str); - return p ? p : HashT89Scr(str); + constexpr uint64_t HashPattern(const wchar_t* str) { + uint64_t out; + if (TryHashPattern(str, out)) { + return out; + } + return 0; } + /* * Compute the hash64 on a string (fnva1), but allow pattern like "hash_123456", path are unformatted * @param str String to compute * @return Hashed value */ - inline uint64_t Hash64Pattern(const char* str, uint64_t start = 0xcbf29ce484222325LL, uint64_t iv = 0x100000001b3) { - uint64_t p = HashPattern(str); - return p ? p : Hash64(str, start, iv); + constexpr uint64_t Hash64Pattern(const char* str, uint64_t start = 0xcbf29ce484222325LL, uint64_t iv = 0x100000001b3) { + uint64_t out; + if (TryHashPattern(str, out)) return out; + return Hash64(str, start, iv); } /* @@ -153,23 +204,16 @@ namespace hash { return hash & 0x7FFFFFFFFFFFFFFF; } - /* - * Compute the hash32 on a string (canon id), but allow pattern like "function_123456" - * @param str String to compute - * @return Hashed value - */ - inline uint32_t HashT89ScrPattern(const wchar_t* str) { - uint32_t p = (uint32_t)HashPattern(str); - return p ? p : HashT89Scr(str); - } + /* * Compute the hash64 on a string (fnva1), but allow pattern like "hash_123456", path are unformatted * @param str String to compute * @return Hashed value */ - inline uint64_t Hash64Pattern(const wchar_t* str, uint64_t start = 0xcbf29ce484222325LL, uint64_t iv = 0x100000001b3) { - uint64_t p = HashPattern(str); - return p ? p : Hash64(str, start, iv); + constexpr uint64_t Hash64Pattern(const wchar_t* str, uint64_t start = 0xcbf29ce484222325LL, uint64_t iv = 0x100000001b3) { + uint64_t out; + if (TryHashPattern(str, out)) return out; + return Hash64(str, start, iv); } constexpr uint64_t HashSecure(const char* pattern, uint64_t start, const char* str, uint64_t iv) { if (!str || !*str) { diff --git a/test/gsc-compiler/acts_cer_test.gsc b/test/gsc-compiler/acts_cer_test.gsc index f13b9e4..72b5409 100644 --- a/test/gsc-compiler/acts_cer_test.gsc +++ b/test/gsc-compiler/acts_cer_test.gsc @@ -41,9 +41,9 @@ function autoexec test_ev() { level.players[0] thread [[ f ]](); } -function test2(..., params) { +function test2(...) { // todo: find name of params - return self iprintln(flat_args(vararg, params)); + return self iprintln(flat_args(vararg, varargcount)); } function test() { @@ -55,7 +55,6 @@ function test() { self iprintln("hello: " + v1 + v2 + v3); } - code_loc: i++; diff --git a/test/gsc-compiler/acts_cer_test2.gsc b/test/gsc-compiler/acts_cer_test2.gsc new file mode 100644 index 0000000..9b64b4f --- /dev/null +++ b/test/gsc-compiler/acts_cer_test2.gsc @@ -0,0 +1,6 @@ + + +function test2(...) { + // todo: find name of params + return self iprintln(flat_args(vararg, varargcount)); +}