complete gsc loading

This commit is contained in:
m 2023-12-29 11:42:02 -06:00
parent 29a0877f7a
commit a3df08538f
6 changed files with 154 additions and 65 deletions

View File

@ -79,14 +79,12 @@ namespace gsc
{
const auto& pos = function.value();
unknown_function_error = std::format(
"while processing function '{}' in script '{}':\nunknown script '{}' ({})",
pos.first, pos.second, scripting::current_file, scripting::current_file_id
"while processing function '{}' in script '{}':\nunknown script '{}'", pos.first, pos.second, scripting::current_file
);
}
else
{
unknown_function_error = std::format("unknown script '{}' ({})",
scripting::current_file, scripting::current_file_id);
unknown_function_error = std::format("unknown script '{}'", scripting::current_file);
}
}
@ -96,8 +94,7 @@ namespace gsc
const auto name = scripting::get_token(thread_name);
unknown_function_error = std::format(
"while processing script '{}':\nunknown function '{}::{}'",
scripting::current_file, filename, name
"while processing script '{}':\nunknown function '{}::{}'", scripting::current_file, filename, name
);
}

View File

@ -28,22 +28,23 @@ namespace gsc
std::unordered_map<std::string, std::uint32_t> init_handles;
utils::memory::allocator scriptfile_allocator;
std::unordered_map<const char*, game::ScriptFile*> loaded_scripts;
std::unordered_map<std::string, game::ScriptFile*> loaded_scripts;
char* script_mem_buf = nullptr;
std::uint64_t script_mem_buf_size = 0;
struct
{
char* buf = nullptr;
char* pos = nullptr;
const unsigned int size = 0x100000i64;
const std::uint64_t size = 0x100000i64;
} script_memory;
char* allocate_buffer(size_t size)
{
if (script_memory.buf == nullptr)
{
game::PMem_BeginAlloc("custom_gsc_script", 1);
script_memory.buf = game::PMem_AllocFromSource_NoDebug(script_memory.size, 4, 0, 1); // 3rd paramter unused because of 4th
game::PMem_EndAlloc("custom_gsc_script", 1);
script_memory.buf = script_mem_buf;
script_memory.pos = script_memory.buf;
}
@ -59,10 +60,13 @@ namespace gsc
void free_script_memory()
{
game::PMem_Free("custom_gsc_script", 1);
if (script_memory.buf != nullptr)
{
memset(script_memory.buf, 0, reinterpret_cast<size_t>(script_memory.pos) - reinterpret_cast<size_t>(script_memory.buf));
script_memory.buf = nullptr;
script_memory.pos = nullptr;
}
}
void clear()
{
@ -106,7 +110,7 @@ namespace gsc
return itr->second;
}
if (game::Com_FrontEndScene_IsActive())
if (game::Com_FrontEnd_IsInFrontEnd())
{
return nullptr;
}
@ -117,8 +121,10 @@ namespace gsc
return nullptr;
}
// TODO: check if needed in IW7
// filter out "GSC rawfiles" that were used for development usage and are not meant for us.
// each "GSC rawfile" has a ScriptFile counterpart to be used instead
/*
if (game::DB_XAssetExists(game::ASSET_TYPE_SCRIPTFILE, file_name) &&
!game::DB_IsXAssetDefault(game::ASSET_TYPE_SCRIPTFILE, file_name))
{
@ -129,6 +135,7 @@ namespace gsc
return game::DB_FindXAssetHeader(game::ASSET_TYPE_SCRIPTFILE, file_name, false).scriptfile;
}
}
*/
console::debug("Loading custom gsc '%s.gsc'", real_name.data());
@ -225,14 +232,8 @@ namespace gsc
return;
}
console::debug("load_script: getting handles for '%s'\n", name.data());
const auto main_token = gsc_ctx->token_id("main");
const auto init_token = gsc_ctx->token_id("init");
const auto main_handle = game::Scr_GetFunctionHandle(name.data(), main_token);
const auto init_handle = game::Scr_GetFunctionHandle(name.data(), init_token);
console::debug("main token: %u (%u), init token: %u (%u)\n", main_token, main_handle, init_token, init_handle);
const auto main_handle = game::Scr_GetFunctionHandle(name.data(), gsc_ctx->token_id("main"));
const auto init_handle = game::Scr_GetFunctionHandle(name.data(), gsc_ctx->token_id("init"));
if (main_handle)
{
@ -267,8 +268,6 @@ namespace gsc
const auto relative = path.lexically_relative(root_dir).generic_string();
const auto base_name = relative.substr(0, relative.size() - 4);
console::debug("load_script called on %s\n", base_name.data());
load_script(base_name);
}
}
@ -285,11 +284,12 @@ namespace gsc
void load_scripts_stub()
{
if (!game::Com_FrontEndScene_IsActive())
if (!game::Com_FrontEnd_IsInFrontEnd())
{
for (const auto& path : filesystem::get_search_paths())
{
load_scripts(path, "scripts/");
load_scripts(path, "userscripts/");
load_scripts(path, "userscripts/"s + game::Com_GameMode_GetActiveGameModeStr() + "/");
}
}
@ -354,7 +354,7 @@ namespace gsc
{
for (auto& function_handle : main_handles)
{
console::info("Executing '%s::main'\n", function_handle.first.data());
console::debug("Executing '%s::main'\n", function_handle.first.data());
game::RemoveRefToObject(game::Scr_ExecThread(function_handle.second, 0));
}
@ -366,17 +366,46 @@ namespace gsc
{
for (auto& function_handle : init_handles)
{
console::info("Executing '%s::init'\n", function_handle.first.data());
console::debug("Executing '%s::init'\n", function_handle.first.data());
game::RemoveRefToObject(game::Scr_ExecThread(function_handle.second, 0));
}
scr_load_level_hook.invoke<void>();
}
utils::hook::detour g_shutdown_game_hook;
void g_shutdown_game_stub(bool full_clear)
void g_shutdown_game_stub(int full_clear, int a2)
{
if (full_clear && a2)
{
clear();
g_shutdown_game_hook.invoke<void>(full_clear);
}
g_shutdown_game_hook.invoke<void>(full_clear, a2);
}
// donetsk developers will paste this in days
utils::hook::detour db_alloc_x_zone_memory_internal_hook;
void db_alloc_x_zone_memory_internal_stub(unsigned __int64* blockSize, const char* filename, game::XZoneMemory* zoneMem, unsigned int type)
{
bool patch = false; // ugly fix for script memory allocation
if (!_stricmp(filename, "code_post_gfx") && type == 2)
{
patch = true;
console::debug("patching memory for '%s'\n", filename);
}
if (patch)
{
blockSize[game::XFILE_BLOCK_SCRIPT] += script_memory.size;
}
db_alloc_x_zone_memory_internal_hook.invoke<void>(blockSize, filename, zoneMem, type);
if (patch)
{
blockSize[game::XFILE_BLOCK_SCRIPT] -= script_memory.size;
script_mem_buf = zoneMem->blocks[game::XFILE_BLOCK_SCRIPT].alloc + blockSize[game::XFILE_BLOCK_SCRIPT];
script_mem_buf_size = script_memory.size;
}
}
}
@ -403,6 +432,9 @@ namespace gsc
public:
void post_unpack() override
{
// Allocate script memory (PMem doesn't work)
db_alloc_x_zone_memory_internal_hook.create(0xA75450_b, db_alloc_x_zone_memory_internal_stub);
// Load our scripts with an uncompressed stack
utils::hook::call(0xC09DA7_b, db_get_raw_buffer_stub);
@ -422,10 +454,8 @@ namespace gsc
// execute init handle
scr_load_level_hook.create(0xB51B40_b, scr_load_level_stub);
/*
// clear memory (G_MainMP_ShutdownGameMemory)
g_shutdown_game_hook.create(0xC56C80_b, g_shutdown_game_stub);
*/
// clear memory (SV_GameMP_ShutdownGameVM)
g_shutdown_game_hook.create(0xBB36D86_b, g_shutdown_game_stub);
}
void pre_destroy() override

View File

@ -27,7 +27,6 @@ namespace scripting
utils::concurrency::container<shared_table_t> shared_table;
std::string current_file;
unsigned int current_file_id{};
namespace
{
@ -44,11 +43,8 @@ namespace scripting
utils::hook::detour sl_get_canonical_string_hook;
utils::hook::detour db_find_xasset_header_hook;
const char* current_script_file_name;
game::dvar_t* g_dump_scripts;
std::string current_script_file;
unsigned int current_file_id{};
std::vector<std::function<void(bool, bool)>> shutdown_callbacks;
@ -115,13 +111,12 @@ namespace scripting
void process_script_stub(const char* filename)
{
current_script_file_name = filename;
current_script_file = filename;
const auto file_id = atoi(filename);
if (file_id)
{
current_file_id = static_cast<std::uint16_t>(file_id);
current_file = scripting::get_token(current_file_id);
}
else
{
@ -135,10 +130,14 @@ namespace scripting
void add_function_sort(unsigned int id, const char* pos)
{
std::string filename = current_file;
if (current_file_id)
{
filename = scripting::get_token(current_file_id);
}
if (!script_function_table_sort.contains(filename))
{
const auto script = gsc::find_script(game::ASSET_TYPE_SCRIPTFILE, current_script_file_name, false);
const auto script = gsc::find_script(game::ASSET_TYPE_SCRIPTFILE, current_script_file.data(), false);
if (script)
{
const auto end = &script->bytecode[script->bytecodeLen];
@ -162,7 +161,15 @@ namespace scripting
{
add_function_sort(thread_name, code_pos);
if (current_file_id)
{
const auto name = get_token(current_file_id);
add_function(name, thread_name, code_pos);
}
else
{
add_function(current_file, thread_name, code_pos);
}
scr_set_thread_position_hook.invoke<void>(thread_name, code_pos);
}
@ -212,9 +219,6 @@ namespace scripting
scr_set_thread_position_hook.create(0xBFD190_b, scr_set_thread_position_stub);
process_script_hook.create(0xC09D20_b, process_script_stub);
sl_get_canonical_string_hook.create(game::SL_GetCanonicalString, sl_get_canonical_string_stub);
// clear memory (SV_GameMP_ShutdownGameVM)
g_shutdown_game_hook.create(0xB21CC0_b, g_shutdown_game_stub);
}
};
}

View File

@ -13,7 +13,6 @@ namespace scripting
extern utils::concurrency::container<shared_table_t> shared_table;
extern std::string current_file;
extern unsigned int current_file_id;
void on_shutdown(const std::function<void(bool, bool)>& callback);
std::optional<std::string> get_canonical_string(const unsigned int id);

View File

@ -3267,16 +3267,78 @@ namespace game
enum PMem_Source
{
PMEM_SOURCE_EXTERNAL = 0x0,
PMEM_SOURCE_DATABASE = 0x1,
PMEM_SOURCE_DEFAULT_LOW = 0x2,
PMEM_SOURCE_DEFAULT_HIGH = 0x3,
PMEM_SOURCE_MOVIE = 0x4,
PMEM_SOURCE_SCRIPT = 0x5,
PMEM_SOURCE_UNK5 = 0x5,
PMEM_SOURCE_UNK6 = 0x6,
PMEM_SOURCE_UNK7 = 0x7,
PMEM_SOURCE_UNK8 = 0x8,
PMEM_SOURCE_CUSTOMIZATION = 0x9,
PMEM_SOURCE_SCRIPT = 0x1,
};
enum PMem_Direction : __int32
{
PHYS_ALLOC_LOW = 0x0,
PHYS_ALLOC_HIGH = 0x1,
PHYS_ALLOC_COUNT = 0x2,
};
enum Mem_PageID
{
};
struct Mem_PageRange
{
Mem_PageID firstPageID;
Mem_PageID lastPageID;
};
struct PhysicalMemoryAllocation
{
const char* name;
char* prev_buffer;
char* next_buffer;
unsigned __int64 pos;
Mem_PageRange pageRange;
};
struct PhysicalMemoryPrim
{
const char* name;
unsigned int allocListCount;
char __pad0[4];
unsigned __int8* buf;
unsigned __int64 unk_pos;
int unk1;
char __pad2[4];
unsigned __int64 pos;
PhysicalMemoryAllocation allocList[32];
};
struct PhysicalMemory
{
PhysicalMemoryPrim prim[2];
};
struct XBlock
{
char* alloc;
unsigned __int64 size;
};
struct XZoneMemory
{
XBlock blocks[10];
char __pad0[200]; // unk size
};
enum XFileBlock
{
XFILE_BLOCK_TEMP_ADDITIONAL = 0x0,
XFILE_BLOCK_TEMP = 0x1,
XFILE_BLOCK_TEMP_PRELOAD = 0x2,
XFILE_BLOCK_CALLBACK = 0x3,
XFILE_BLOCK_RUNTIME = 0x4,
XFILE_BLOCK_RUNTIME_VIDEO = 0x5,
XFILE_BLOCK_CACHED_VIDEO = 0x6,
XFILE_BLOCK_PHYSICAL = 0x7,
XFILE_BLOCK_VIRTUAL = 0x8,
XFILE_BLOCK_SCRIPT = 0x9,
MAX_XFILE_COUNT = 0xA,
};
enum VariableType

View File

@ -276,9 +276,6 @@ namespace game
WEAK game::symbol<unsigned __int64> pmem_size{ 0x7686A28 };
WEAK game::symbol<unsigned char*> pmem_buffer{ 0x7686A20 };
/*
WEAK game::symbol<PhysicalMemory> g_mem{ 0xD5F26E0, 0xC92E1E0 };
WEAK game::symbol<PhysicalMemory> g_scriptmem{ 0xD5F3140, 0xC92EC40 };
WEAK game::symbol<PhysicalMemory> g_physmem{ 0xD5F3BA0, 0xC92F6A0 };
*/
WEAK game::symbol<PhysicalMemory> g_mem{ 0x7685560 };
WEAK game::symbol<PhysicalMemory> g_scriptmem{ 0x7685FC0 };
}