Skip to content

Commit

Permalink
add vm35
Browse files Browse the repository at this point in the history
  • Loading branch information
ate47 committed Jan 8, 2025
1 parent a87a62b commit 0bfc5d5
Show file tree
Hide file tree
Showing 4 changed files with 290 additions and 5 deletions.
23 changes: 18 additions & 5 deletions src/acts/tools/gsc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -976,6 +976,9 @@ const char* GetFLocName(GSCExportReader& reader, GSCOBJHandler& handler, uint32_
void* maxPtr{};
for (size_t i = 0; i < handler.GetExportsCount(); i++) {
void* ptr = exportTable + reader.SizeOf() * i;
if (handler.GetExportsOffset() + reader.SizeOf() * (i + 1) > handler.GetFileSize()) {
throw std::runtime_error("Invalid export size");
}
reader.SetHandle(ptr);

uint32_t addr = reader.GetAddress();
Expand Down Expand Up @@ -1643,13 +1646,18 @@ int GscInfoHandleData(byte* data, size_t size, std::filesystem::path fsPath, Gsc

asmout << std::hex << "String addr:" << str->string << ", count:" << std::dec << (int)str->num_address << ", type:" << (int)str->type << ", loc:0x" << std::hex << (str_location - reinterpret_cast<uintptr_t>(scriptfile->Ptr())) << std::endl;

if (str->string >= scriptfile->GetFileSize()) {
asmout << "bad string location : 0x" << std::hex << str->string << "/0x" << scriptfile->GetFileSize() << "\n";
break;
}

char* encryptedString = scriptfile->Ptr<char>(str->string);

size_t len{ std::strlen(encryptedString) };
byte type{ (byte)(*reinterpret_cast<byte*>(encryptedString)) };

if (str->string + len > scriptfile->GetFileSize()) {
asmout << "bad string location : 0x" << std::hex << str->string << "/0x" << scriptfile->GetFileSize() << "\n";
asmout << "bad string location + len : 0x" << std::hex << str->string << "/0x" << scriptfile->GetFileSize() << "\n";
break;
}

Expand Down Expand Up @@ -3649,10 +3657,15 @@ int tool::gsc::gscinfo(Process& proc, int argc, const char* argv[]) {
LOG_ERROR("Can't read file data for {}", path.string());
continue;
}

auto lret = GscInfoHandleData((byte*)bufferAlign, size, pathRel, gdctx);
if (lret != tool::OK) {
ret = lret;
try {
auto lret = GscInfoHandleData((byte*)bufferAlign, size, pathRel, gdctx);
if (lret != tool::OK) {
ret = lret;
}
}
catch (std::runtime_error& e) {
LOG_ERROR("Exception when reading {}: {}", path.string(), e.what());
ret = tool::BASIC_ERROR;
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/acts/tools/gsc_opcodes_load.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ namespace tool::gsc::opcode {
VMI_T71B = 0x1B000a0d43534780,
VMI_T7 = 0x1C000a0d43534780,
VMI_T831 = 0x31000a0d43534780,
VMI_T835 = 0x35000a0d43534780,
VMI_T8 = 0x36000a0d43534780,
VMI_T937 = 0x37000a0d43534780,
VMI_T9 = 0x38000a0d43534780,
Expand Down
222 changes: 222 additions & 0 deletions src/acts/tools/gsc_vm/vm_t8.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <tools/gsc_vm.hpp>
#include <tools/gsc.hpp>
#include <tools/gsc_opcodes.hpp>
#include <decryptutils.hpp>


// Call of Duty: Black Ops 4 (T8)
Expand Down Expand Up @@ -254,6 +255,226 @@ namespace {
}
};

class T835GSCOBJHandler : public GSCOBJHandler {
public:
T835GSCOBJHandler(byte* file, size_t fileSize) : GSCOBJHandler(file, fileSize, GOHF_GLOBAL | GOHF_INLINE_FUNC_PTR | GOHF_SUPPORT_EV_HANDLER | GOHF_SUPPORT_VAR_VA | GOHF_SUPPORT_VAR_REF | GOHF_FOREACH_TYPE_T8 | GOHF_SUPPORT_GET_API_SCRIPT | GOHF_SWITCH_TYPE_T89) {}

void DumpHeaderInternal(std::ostream& asmout, const GscInfoOption& opt) override {
auto* data = Ptr<T8GSCOBJ>();
asmout
<< "// fixups ... " << std::dec << std::setw(3) << data->fixup_count << " (offset: 0x" << std::hex << data->fixup_offset << ")\n";

if (opt.m_test_header) {
asmout
<< "// ukn0c .... " << std::dec << data->pad << " / 0x" << std::hex << data->pad << "\n"
<< "// ukn34 .... " << std::dec << data->ukn34 << " / 0x" << std::hex << data->ukn34 << "\n"
<< "// ukn50 .... " << std::dec << data->ukn50 << " / 0x" << std::hex << data->ukn50 << "\n"
<< "// ukn5a .... " << std::dec << (int)data->ukn5a << " / 0x" << std::hex << (int)data->ukn5a << "\n"
;
}
}
void DumpExperimental(std::ostream& asmout, const GscInfoOption& opt, T8GSCOBJContext& ctx) override {
}

uint64_t GetName() override {
return Ptr<T8GSCOBJ>()->name;
}
uint16_t GetExportsCount() override {
return Ptr<T8GSCOBJ>()->exports_count;
}
uint32_t GetExportsOffset() override {
return Ptr<T8GSCOBJ>()->export_table_offset;
}
uint16_t GetIncludesCount() override {
return Ptr<T8GSCOBJ>()->include_count;
}
uint32_t GetIncludesOffset() override {
return Ptr<T8GSCOBJ>()->include_offset;
}
uint16_t GetImportsCount() override {
return Ptr<T8GSCOBJ>()->imports_count;
}
uint32_t GetImportsOffset() override {
return Ptr<T8GSCOBJ>()->imports_offset;
}
uint16_t GetGVarsCount() override {
return Ptr<T8GSCOBJ>()->globalvar_count;
}
uint32_t GetGVarsOffset() override {
return Ptr<T8GSCOBJ>()->globalvar_offset;
}
uint16_t GetStringsCount() override {
return Ptr<T8GSCOBJ>()->string_count;
}
uint32_t GetStringsOffset() override {
return Ptr<T8GSCOBJ>()->string_offset;
}
uint16_t GetDevStringsCount() override {
return Ptr<T8GSCOBJ>()->devblock_string_count;
}
uint32_t GetDevStringsOffset() override {
return Ptr<T8GSCOBJ>()->devblock_string_offset;
}
uint32_t GetFileSize() override {
return Ptr<T8GSCOBJ>()->script_size;
}
size_t GetHeaderSize() override {
return sizeof(T8GSCOBJ);
}
char* DecryptString(char* str) override {
return acts::decryptutils::DecryptString(str);
}
std::pair<const char*, size_t> GetStringHeader(size_t len) override {
static thread_local byte str[2]{ 0x9f, 0xFF };
str[1] = (byte)(len + 1);
return { reinterpret_cast<const char*>(&str[0]), sizeof(str) };
}
bool IsValidHeader(size_t size) override {
return size >= sizeof(T8GSCOBJ) && Ref<uint64_t>() == 0x35000a0d43534780;
}
uint16_t GetAnimTreeSingleCount() override {
return 0;
};
uint32_t GetAnimTreeSingleOffset() override {
return 0;
};
uint16_t GetAnimTreeDoubleCount() override {
return 0;
};
uint32_t GetAnimTreeDoubleOffset() override {
return 0;
};

void SetName(uint64_t name) override {
Ptr<T8GSCOBJ>()->name = name;
}
void SetHeader() override {
Ref<uint64_t>() = 0x35000a0d43534780;
}
void SetExportsCount(uint16_t val) override {
Ptr<T8GSCOBJ>()->exports_count = val;
}
void SetExportsOffset(uint32_t val) override {
Ptr<T8GSCOBJ>()->export_table_offset = val;
}
void SetIncludesCount(uint16_t val) override {
Ptr<T8GSCOBJ>()->include_count = val;
}
void SetIncludesOffset(uint32_t val) override {
Ptr<T8GSCOBJ>()->include_offset = val;
}
void SetImportsCount(uint16_t val) override {
Ptr<T8GSCOBJ>()->imports_count = val;
}
void SetImportsOffset(uint32_t val) override {
Ptr<T8GSCOBJ>()->imports_offset = val;
}
void SetStringsCount(uint16_t val) override {
Ptr<T8GSCOBJ>()->string_count = val;
}
void SetStringsOffset(uint32_t val) override {
Ptr<T8GSCOBJ>()->string_offset = val;
}
void SetDevStringsCount(uint16_t val) override {
Ptr<T8GSCOBJ>()->devblock_string_count = val;
}
void SetDevStringsOffset(uint32_t val) override {
Ptr<T8GSCOBJ>()->devblock_string_offset = val;
}
void SetGVarsCount(uint16_t val) override {
Ptr<T8GSCOBJ>()->globalvar_count = val;
}
void SetGVarsOffset(uint32_t val) override {
Ptr<T8GSCOBJ>()->globalvar_offset = val;
}
void SetFileSize(uint32_t val) override {
Ptr<T8GSCOBJ>()->script_size = val;
}
void SetCSEGOffset(uint32_t val) override {
Ptr<T8GSCOBJ>()->cseg_offset = val;
}
void SetCSEGSize(uint32_t val) override {
Ptr<T8GSCOBJ>()->cseg_size = val;
}
uint32_t GetCSEGOffset() override {
return Ptr<T8GSCOBJ>()->cseg_offset;
}
uint32_t GetCSEGSize() override {
return Ptr<T8GSCOBJ>()->cseg_size;
}
void SetAnimTreeSingleCount(uint16_t val) override {}
void SetAnimTreeSingleOffset(uint32_t val) override {}
void SetAnimTreeDoubleCount(uint16_t val) override {}
void SetAnimTreeDoubleOffset(uint32_t val) override {}
size_t GetImportSize() override {
return sizeof(tool::gsc::T8GSCImport);
}
size_t GetExportSize() override {
return sizeof(tool::gsc::T8GSCExport);
}
size_t GetStringSize() override {
return sizeof(tool::gsc::T8GSCString);
}
size_t GetGVarSize() override {
return sizeof(tool::gsc::T8GSCGlobalVar);
}
size_t GetAnimTreeSingleSize() override {
return 0;
}
size_t GetAnimTreeDoubleSize() override {
return 0;
}
void WriteExport(byte* data, const tool::gsc::IW23GSCExport& item) override {
auto& imp = *reinterpret_cast<tool::gsc::T8GSCExport*>(data);
imp.name = (uint32_t)item.name;
imp.name_space = (uint32_t)item.name_space;
imp.callback_event = (uint32_t)item.file_name_space;
imp.checksum = (uint32_t)item.checksum;
imp.flags = item.flags;
imp.address = item.address;
imp.param_count = item.param_count;
}
void WriteImport(byte* data, const tool::gsc::IW23GSCImport& item) override {
auto& imp = *reinterpret_cast<tool::gsc::T8GSCImport*>(data);
imp.name = (uint32_t)item.name;
imp.import_namespace = (uint32_t)item.name_space;
imp.flags = item.flags;
imp.num_address = item.num_address;
imp.param_count = item.param_count;
}
void WriteGVar(byte* data, const tool::gsc::T8GSCGlobalVar& item) override {
*reinterpret_cast<tool::gsc::T8GSCGlobalVar*>(data) = item;
}
void WriteString(byte* data, const tool::gsc::T8GSCString& item) override {
*reinterpret_cast<tool::gsc::T8GSCString*>(data) = item;
}
void WriteAnimTreeSingle(byte* data, const tool::gsc::GSC_USEANIMTREE_ITEM& item) override { }
void WriteAnimTreeDouble(byte* data, const tool::gsc::GSC_ANIMTREE_ITEM& item) override { }
int64_t GetDefaultChecksum(bool client) override {
// todo: check client
constexpr int32_t t = 0x636e9d38;
return t;
}
void SetChecksum(uint64_t val) override {
Ptr<T8GSCOBJ>()->crc = (uint32_t)val;
}
uint32_t GetChecksum() override {
return Ptr<T8GSCOBJ>()->crc;
}
const char* GetDefaultName(bool client) override {
if (client) {
return "";
}
return "scripts/core_common/clientids_shared.gsc";
}
bool IsVTableImportFlags(byte flags) override {
return flags == CLASS_VTABLE;
}
byte GetVTableImportFlags() override {
return CLASS_VTABLE;
}
};

/*****************************************************************************************************************************/

class T831GSCOBJHandler : public GSCOBJHandler {
Expand Down Expand Up @@ -480,4 +701,5 @@ namespace {

}
REGISTER_GSC_VM(VMI_T8, T8GSCOBJHandler);
REGISTER_GSC_VM(VMI_T835, T835GSCOBJHandler);
REGISTER_GSC_VM(VMI_T831, T831GSCOBJHandler);
49 changes: 49 additions & 0 deletions src/acts/tools/gsc_vm/vm_t8_opcodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,55 @@ namespace {
/*30c570*/vt831->RegisterOpCode(PLATFORM_PLAYSTATION, OPCODE_Undefined, 0xe6, 0xf5, 0x170, 0x193, 0x520, 0x5c7, 0x660, 0x6c4, 0x775, 0xaed, 0xaef, 0xb40, 0xb60, 0xd81, 0xd83, 0xd8b);
/*30cad0*/vt831->RegisterOpCode(PLATFORM_PLAYSTATION, OPCODE_Undefined, 0x2ab, 0x44e, 0x4e6, 0x522, 0x6ca, 0x71f, 0x7b1, 0x7ba, 0x8c6, 0x8d5, 0x909, 0x975, 0x981, 0x982, 0xac9, 0xcdf, 0xd43, 0xdc1, 0xe16, 0xe1e, 0xe3a, 0xead);

VmInfo* vt835 = RegisterVM(VMI_T835, "Call of Duty: Black ops 4 (35)", "t8", "bo4_35", VmFlags::VMF_OPCODE_U16 | VmFlags::VMF_ALIGN | VmFlags::VMF_INV_ADD_TO_OBJECT | VmFlags::VMF_CLIENT_VM);
vt831->RegisterVmName("t8_31", "blackops4_35");
vt835->AddPlatform(PLATFORM_PC);
vt835->SetMaxOpCode(0xFFF);
vt835->RegisterVMGlobalVariable("level");
vt835->RegisterVMGlobalVariable("game");
vt835->RegisterVMGlobalVariable("classes");
vt835->RegisterVMGlobalVariable("mission");
vt835->RegisterVMGlobalVariable("anim");
vt835->RegisterVMGlobalVariable("world");
vt835->RegisterVMGlobalVariable("sharedstructs");
vt835->RegisterVMGlobalVariable("memory");
vt835->RegisterVMOperatorFunction("profilestart", "profilestart()", OPCODE_ProfileStart, VPFD_NONE, 0, 0);
vt835->RegisterVMOperatorFunction("profilestop", "profilestop()", OPCODE_ProfileStop, VPFD_NONE, 0, 0);
vt835->RegisterVMOperatorFunction("isdefined", "isdefined(object) -> bool", OPCODE_IsDefined, VPFD_RETURN_VALUE, 1, 1);
vt835->RegisterVMOperatorFunction("notify", "<caller> notify(event, param*)", OPCODE_Notify, VPFD_SELF_PARAM | VPFD_USE_PRE_SCRIPT_CALL, 1);
vt835->RegisterVMOperatorFunction("endon", "<caller> endon(event+)", OPCODE_EndOn, VPFD_SELF_PARAM | VPFD_USE_COUNT, 1);
vt835->RegisterVMOperatorFunction("endoncallback", "<caller> endoncallback(func, event+)", OPCODE_EndOnCallback, VPFD_SELF_PARAM | VPFD_USE_COUNT, 2);
vt835->RegisterVMOperatorFunction("vectorscale", "vectorscale(vector, factor) -> vector", OPCODE_VectorScale, VPFD_RETURN_VALUE, 2, 2);
vt835->RegisterVMOperatorFunction("waittill", "<caller> waittill(event) -> struct", OPCODE_WaitTill, VPFD_SELF_PARAM | VPFD_USE_COUNT | VPFD_RETURN_VALUE, 1);
vt835->RegisterVMOperatorFunction("waittillmatch", "<caller> waittillmatch(event, match) -> struct", OPCODE_WaitTillMatch, VPFD_SELF_PARAM | VPFD_USE_COUNT | VPFD_RETURN_VALUE, 2);
vt835->RegisterVMOperatorFunction("waittillmatchtimeout", "<caller> waittillmatchtimeout(event, match, timeout) -> struct", OPCODE_WaitTillMatchTimeout, VPFD_SELF_PARAM | VPFD_USE_COUNT | VPFD_RETURN_VALUE, 3);
vt835->RegisterVMOperatorFunction("waittilltimeout", "<caller> waittilltimeout(event, timeout) -> struct", OPCODE_WaittillTimeout, VPFD_SELF_PARAM | VPFD_USE_COUNT | VPFD_RETURN_VALUE, 2);
vt835->RegisterVMOperatorFunction("wait", "wait(time)", OPCODE_Wait, VPFD_NONE, 1, 1);
vt835->RegisterVMOperatorFunction("waitframe", "waitframe(frames)", OPCODE_WaitFrame, VPFD_NONE, 1, 1);
vt835->RegisterVMOperatorFunction("waittillframeend", "waittillframeend()", OPCODE_WaitTillFrameEnd, VPFD_NONE, 0, 0);
vt835->RegisterVMHashOPCode('#', OPCODE_GetHash, 8, [](const char* str) { return hash::Hash64(str); });
vt835->RegisterVMHashOPCode('&', OPCODE_GetHash, 8, [](const char* str) { return hash::HashT89Scr(str); });
vt835->RegisterDevCall("assert", "assertmsg", "errormsg", "throw", "println");
vt835->RegisterDatatype("functionptr", "scriptfunctionptr", "codefunctionptr", "string", "array", "weapon", "int", "float", "vec", "class", "struct", "hash");
vt835->RegisterDatatypeRenamed("function", "functionptr");
vt835->RegisterOpCode(PLATFORM_PC, OPCODE_Abort, 0x0);
vt835->RegisterOpCode(PLATFORM_PC, OPCODE_Nop, 0x1);
vt835->RegisterOpCode(PLATFORM_PC, OPCODE_Breakpoint, 0x2);
vt835->RegisterOpCode(PLATFORM_PC, OPCODE_AutoBreakpoint, 0x3);
vt835->RegisterOpCode(PLATFORM_PC, OPCODE_ErrorBreakpoint, 0x4);
vt835->RegisterOpCode(PLATFORM_PC, OPCODE_WatchBreakpoint, 0x5);
vt835->RegisterOpCode(PLATFORM_PC, OPCODE_NotifyBreakpoint, 0x6);
vt835->RegisterOpCode(PLATFORM_PC, OPCODE_ThreadEndBreakpoint, 0x7);
vt835->RegisterOpCode(PLATFORM_PC, OPCODE_EvalLocalVariableCachedDebug, 0x8);
vt835->RegisterOpCode(PLATFORM_PC, OPCODE_EvalLocalVariableRefCachedDebug, 0x9);
vt835->RegisterOpCode(PLATFORM_PC, OPCODE_PushVar, 0xa);
vt835->RegisterOpCode(PLATFORM_PC, OPCODE_PushEntityVar, 0xb);
vt835->RegisterOpCode(PLATFORM_PC, OPCODE_ClearParams, 0xc);
vt835->RegisterOpCode(PLATFORM_PC, OPCODE_CheckClearParams, 0xd);
vt835->RegisterOpCode(PLATFORM_PC, OPCODE_PreScriptCall, 0xe);
vt835->RegisterOpCode(PLATFORM_PC, OPCODE_CallBuiltinFunction, 0xf);
vt835->RegisterOpCode(PLATFORM_PC, OPCODE_CallBuiltinMethod, 0x10);
vt835->RegisterOpCode(PLATFORM_PC, OPCODE_End, 0x11);
}


Expand Down

0 comments on commit 0bfc5d5

Please sign in to comment.