Fix script leaks + increase memory

This commit is contained in:
fed 2022-11-11 21:15:26 +01:00
parent e62fc74d98
commit 15fdab136f
6 changed files with 123 additions and 55 deletions

View File

@ -106,11 +106,6 @@ namespace gsc
public: public:
void post_unpack() override void post_unpack() override
{ {
if (game::environment::is_sp())
{
return;
}
scr_emit_function_hook.create(SELECT_VALUE(0x3BD680_b, 0x504660_b), &scr_emit_function_stub); scr_emit_function_hook.create(SELECT_VALUE(0x3BD680_b, 0x504660_b), &scr_emit_function_stub);
utils::hook::call(SELECT_VALUE(0x3BD626_b, 0x504606_b), unknown_function_stub); // CompileError (LinkFile) utils::hook::call(SELECT_VALUE(0x3BD626_b, 0x504606_b), unknown_function_stub); // CompileError (LinkFile)

View File

@ -348,11 +348,6 @@ namespace gsc
utils::hook::inject(SELECT_VALUE(0x3BDC36_b, 0x504C66_b) + 3, &meth_table); utils::hook::inject(SELECT_VALUE(0x3BDC36_b, 0x504C66_b) + 3, &meth_table);
utils::hook::set<uint32_t>(SELECT_VALUE(0x3BDC3F_b, 0x504C6F_b), sizeof(meth_table)); utils::hook::set<uint32_t>(SELECT_VALUE(0x3BDC3F_b, 0x504C6F_b), sizeof(meth_table));
if (game::environment::is_sp())
{
return;
}
developer_script = dvars::register_bool("developer_script", false, 0, "Enable developer script comments"); developer_script = dvars::register_bool("developer_script", false, 0, "Enable developer script comments");
utils::hook::nop(SELECT_VALUE(0x3CB723_b, 0x512783_b), 8); utils::hook::nop(SELECT_VALUE(0x3CB723_b, 0x512783_b), 8);
@ -466,36 +461,39 @@ namespace gsc
return scripting::script_value{}; return scripting::script_value{};
}); });
function::add("say", [](const function_args& args)
{
const auto message = args[0].as<std::string>();
game::SV_GameSendServerCommand(-1, game::SV_CMD_CAN_IGNORE, utils::string::va("%c \"%s\"", 84, message.data()));
return scripting::script_value{};
});
function::add("typeof", typeof); function::add("typeof", typeof);
function::add("type", typeof); function::add("type", typeof);
method::add("tell", [](const game::scr_entref_t ent, const function_args& args) if (!game::environment::is_sp())
{ {
if (ent.classnum != 0) function::add("say", [](const function_args& args)
{ {
throw std::runtime_error("Invalid entity"); const auto message = args[0].as<std::string>();
} game::SV_GameSendServerCommand(-1, game::SV_CMD_CAN_IGNORE, utils::string::va("%c \"%s\"", 84, message.data()));
const auto client = ent.entnum; return scripting::script_value{};
});
if (game::mp::g_entities[client].client == nullptr) method::add("tell", [](const game::scr_entref_t ent, const function_args& args)
{ {
throw std::runtime_error("Not a player entity"); if (ent.classnum != 0)
} {
throw std::runtime_error("Invalid entity");
}
const auto message = args[0].as<std::string>(); const auto client = ent.entnum;
game::SV_GameSendServerCommand(client, game::SV_CMD_CAN_IGNORE, utils::string::va("%c \"%s\"", 84, message.data()));
return scripting::script_value{}; if (game::mp::g_entities[client].client == nullptr)
}); {
throw std::runtime_error("Not a player entity");
}
const auto message = args[0].as<std::string>();
game::SV_GameSendServerCommand(client, game::SV_CMD_CAN_IGNORE, utils::string::va("%c \"%s\"", 84, message.data()));
return scripting::script_value{};
});
}
} }
}; };
} }

View File

@ -39,13 +39,48 @@ namespace gsc
std::unordered_map<std::string, std::uint32_t> main_handles; std::unordered_map<std::string, std::uint32_t> main_handles;
std::unordered_map<std::string, std::uint32_t> init_handles; std::unordered_map<std::string, std::uint32_t> init_handles;
utils::memory::allocator scriptfile_allocator;
std::unordered_map<std::string, game::ScriptFile*> loaded_scripts; std::unordered_map<std::string, game::ScriptFile*> loaded_scripts;
struct
{
char* buf = nullptr;
char* pos = nullptr;
unsigned int size = 0x1000000;
} script_memory;
char* allocate_buffer(size_t size)
{
if (script_memory.buf == nullptr)
{
script_memory.buf = game::PMem_AllocFromSource_NoDebug(script_memory.size, 4, 1, game::PMEM_SOURCE_SCRIPT);
script_memory.pos = script_memory.buf;
}
if (script_memory.pos + size > script_memory.buf + script_memory.size)
{
game::Com_Error(game::ERR_FATAL, "Out of custom script memory");
}
const auto pos = script_memory.pos;
script_memory.pos += size;
return pos;
}
void free_script_memory()
{
game::PMem_PopFromSource_NoDebug(script_memory.buf, script_memory.size, 4, 1, game::PMEM_SOURCE_SCRIPT);
script_memory.buf = nullptr;
script_memory.pos = nullptr;
}
void clear() void clear()
{ {
main_handles.clear(); main_handles.clear();
init_handles.clear(); init_handles.clear();
loaded_scripts.clear(); loaded_scripts.clear();
scriptfile_allocator.clear();
free_script_memory();
} }
bool read_script_file(const std::string& name, std::string* data) bool read_script_file(const std::string& name, std::string* data)
@ -75,14 +110,13 @@ namespace gsc
return false; return false;
} }
char* allocate_buffer(size_t size)
{
// PMem_AllocFromSource_NoDebug
return utils::hook::invoke<char*>(SELECT_VALUE(0x41FB50_b, 0x5A4DC0_b), size, 4, 1, 5);
}
game::ScriptFile* load_custom_script(const char* file_name, const std::string& real_name) game::ScriptFile* load_custom_script(const char* file_name, const std::string& real_name)
{ {
if (game::VirtualLobby_Loaded())
{
return nullptr;
}
if (const auto itr = loaded_scripts.find(real_name); itr != loaded_scripts.end()) if (const auto itr = loaded_scripts.find(real_name); itr != loaded_scripts.end())
{ {
return itr->second; return itr->second;
@ -134,7 +168,7 @@ namespace gsc
return nullptr; return nullptr;
} }
const auto script_file_ptr = reinterpret_cast<game::ScriptFile*>(allocate_buffer(sizeof(game::ScriptFile))); const auto script_file_ptr = scriptfile_allocator.allocate<game::ScriptFile>();
script_file_ptr->name = file_name; script_file_ptr->name = file_name;
const auto stack = assembler->output_stack(); const auto stack = assembler->output_stack();
@ -143,15 +177,12 @@ namespace gsc
const auto script = assembler->output_script(); const auto script = assembler->output_script();
script_file_ptr->bytecodeLen = static_cast<int>(script.size()); script_file_ptr->bytecodeLen = static_cast<int>(script.size());
const auto script_size = script.size(); script_file_ptr->buffer = game::Hunk_AllocateTempMemoryHigh(stack.size() + 1);
const auto buffer_size = script_size + stack.size() + 2; std::memcpy(script_file_ptr->buffer, stack.data(), stack.size());
const auto buffer = allocate_buffer(buffer_size); script_file_ptr->bytecode = allocate_buffer(script.size() + 1);
std::memcpy(buffer, script.data(), script_size); std::memcpy(script_file_ptr->bytecode, script.data(), script.size());
std::memcpy(&buffer[script_size], stack.data(), stack.size());
script_file_ptr->bytecode = &buffer[0];
script_file_ptr->buffer = reinterpret_cast<char*>(&buffer[script.size()]);
script_file_ptr->compressedLen = 0; script_file_ptr->compressedLen = 0;
loaded_scripts[real_name] = script_file_ptr; loaded_scripts[real_name] = script_file_ptr;
@ -254,8 +285,6 @@ namespace gsc
{ {
utils::hook::invoke<void>(SELECT_VALUE(0x2B9DA0_b, 0x18BC00_b), a1, a2); utils::hook::invoke<void>(SELECT_VALUE(0x2B9DA0_b, 0x18BC00_b), a1, a2);
clear();
if (game::VirtualLobby_Loaded()) if (game::VirtualLobby_Loaded())
{ {
return; return;
@ -286,6 +315,27 @@ namespace gsc
utils::hook::invoke<void>(SELECT_VALUE(0x1F1E00_b, 0x396080_b), rawfile, buf, size); utils::hook::invoke<void>(SELECT_VALUE(0x1F1E00_b, 0x396080_b), rawfile, buf, size);
} }
void pmem_init_stub()
{
utils::hook::invoke<void>(SELECT_VALUE(0x420260_b, 0x5A5590_b));
const auto type_0 = &game::g_scriptmem[0];
const auto type_1 = &game::g_scriptmem[1];
const auto size_0 = 0x100000; // default size
const auto size_1 = 0x100000 + script_memory.size;
const auto block = reinterpret_cast<char*>(VirtualAlloc(NULL, size_0 + size_1, MEM_RESERVE, PAGE_READWRITE));
type_0->buf = block;
type_0->size = size_0;
type_1->buf = block + size_0;
type_1->size = size_1;
utils::hook::set<uint32_t>(SELECT_VALUE(0x420252_b, 0x5A5582_b), size_0 + size_1);
}
} }
void load_main_handles() void load_main_handles()
@ -329,11 +379,6 @@ namespace gsc
public: public:
void post_unpack() override void post_unpack() override
{ {
if (game::environment::is_sp())
{
return;
}
// allow custom scripts to include other custom scripts // allow custom scripts to include other custom scripts
xsk::gsc::h1::resolver::init([](const auto& include_name) xsk::gsc::h1::resolver::init([](const auto& include_name)
{ {
@ -369,6 +414,9 @@ namespace gsc
// loads scripts with an uncompressed stack // loads scripts with an uncompressed stack
utils::hook::call(SELECT_VALUE(0x3C7280_b, 0x50E3C0_b), db_get_raw_buffer_stub); utils::hook::call(SELECT_VALUE(0x3C7280_b, 0x50E3C0_b), db_get_raw_buffer_stub);
// Increase script memory
utils::hook::call(SELECT_VALUE(0x38639C_b, 0x15C4D6_b), pmem_init_stub);
scripting::on_shutdown([](int free_scripts) scripting::on_shutdown([](int free_scripts)
{ {
if (free_scripts) if (free_scripts)

View File

@ -343,8 +343,6 @@ namespace party
const auto path = get_usermap_file_path(mapname, ext); const auto path = get_usermap_file_path(mapname, ext);
const auto hash = get_file_hash(path); const auto hash = get_file_hash(path);
console::debug("%s %s %s != %s\n", ext.data(), key.data(), hash.data(), source_hash.data());
if ((!source_hash.empty() && hash != source_hash) || (source_hash.empty() && !opt)) if ((!source_hash.empty() && hash != source_hash) || (source_hash.empty() && !opt))
{ {
command::execute("disconnect"); command::execute("disconnect");
@ -423,8 +421,6 @@ namespace party
} }
} }
console::debug("%i %s\n", is_usermap, buffer.data());
net_out_of_band_print_hook.invoke<void>(sock, addr, buffer.data()); net_out_of_band_print_hook.invoke<void>(sock, addr, buffer.data());
} }
} }

View File

@ -1599,6 +1599,28 @@ namespace game
int ingame_cursor_visible; int ingame_cursor_visible;
}; };
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,
};
struct physical_memory
{
char __pad0[0x10];
char* buf;
char __pad1[0x8];
int unk1;
size_t size;
char __pad2[0x500];
};
static_assert(sizeof(physical_memory) == 0x530);
namespace mp namespace mp
{ {
struct cachedSnapshot_t struct cachedSnapshot_t

View File

@ -117,6 +117,8 @@ namespace game
WEAK symbol<int(const char* buf, int max, char** infos)> GameInfo_ParseArenas{0x0, 0x4DE0B0}; WEAK symbol<int(const char* buf, int max, char** infos)> GameInfo_ParseArenas{0x0, 0x4DE0B0};
WEAK symbol<char*(const size_t size)> Hunk_AllocateTempMemoryHigh{0x415DB0, 0x59DEC0};
WEAK symbol<char*(char* string)> I_CleanStr{0x4293E0, 0x5AF2E0}; WEAK symbol<char*(char* string)> I_CleanStr{0x4293E0, 0x5AF2E0};
WEAK symbol<const char*(int, int, int)> Key_KeynumToString{0x1AC410, 0x199990}; WEAK symbol<const char*(int, int, int)> Key_KeynumToString{0x1AC410, 0x199990};
@ -155,6 +157,11 @@ namespace game
WEAK symbol<char* (GfxImage* image, uint32_t width, uint32_t height, uint32_t depth, uint32_t mipCount, WEAK symbol<char* (GfxImage* image, uint32_t width, uint32_t height, uint32_t depth, uint32_t mipCount,
uint32_t imageFlags, DXGI_FORMAT imageFormat, const char* name, const D3D11_SUBRESOURCE_DATA* initData)> Image_Setup{0x560740, 0x683890}; uint32_t imageFlags, DXGI_FORMAT imageFormat, const char* name, const D3D11_SUBRESOURCE_DATA* initData)> Image_Setup{0x560740, 0x683890};
WEAK symbol<char*(const size_t size, unsigned int alignment,
unsigned int type, PMem_Source source)> PMem_AllocFromSource_NoDebug{0x41FB50, 0x5A4DC0};
WEAK symbol<void(char* buf, const size_t size, unsigned int alignment,
unsigned int type, PMem_Source source)> PMem_PopFromSource_NoDebug{0x4203D0, 0x5A5700};
WEAK symbol<unsigned int(unsigned int localId, const char* pos, WEAK symbol<unsigned int(unsigned int localId, const char* pos,
unsigned int paramcount)> VM_Execute{0x3C9E50, 0x510EB0}; unsigned int paramcount)> VM_Execute{0x3C9E50, 0x510EB0};
@ -299,6 +306,8 @@ namespace game
WEAK symbol<scrVmPub_t> scr_VmPub{0xC3F4E20, 0xB7AE3C0}; WEAK symbol<scrVmPub_t> scr_VmPub{0xC3F4E20, 0xB7AE3C0};
WEAK symbol<function_stack_t> scr_function_stack{0xC4015C0, 0xB7B8940}; WEAK symbol<function_stack_t> scr_function_stack{0xC4015C0, 0xB7B8940};
WEAK symbol<physical_memory> g_scriptmem{0xD5F3140, 0xC92EC40};
WEAK symbol<GfxDrawMethod_s> gfxDrawMethod{0xF7530B0, 0xE9213F0}; WEAK symbol<GfxDrawMethod_s> gfxDrawMethod{0xF7530B0, 0xE9213F0};
WEAK symbol<int> dvarCount{0xC90E550, 0x2999C34}; WEAK symbol<int> dvarCount{0xC90E550, 0x2999C34};