update gsc
yoink some from h2-mod
This commit is contained in:
parent
e4eecf66c5
commit
483aad7425
@ -56,7 +56,7 @@ namespace gsc
|
|||||||
{
|
{
|
||||||
const auto& pos = function.value();
|
const auto& pos = function.value();
|
||||||
unknown_function_error = std::format(
|
unknown_function_error = std::format(
|
||||||
"while processing function '{}' in script '{}':\nunknown script '{}'", pos.first, pos.second, scripting::current_file
|
"while processing function '{}' in script '{}':\nunknown script '{}'", pos.function, pos.file, scripting::current_file
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -289,62 +289,58 @@ namespace gsc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_callstack(uint8_t opcode_id)
|
void print_callstack()
|
||||||
{
|
{
|
||||||
bool first = true;
|
|
||||||
|
|
||||||
for (auto frame = game::scr_VmPub->function_frame; frame != game::scr_VmPub->function_frame_start; --frame)
|
for (auto frame = game::scr_VmPub->function_frame; frame != game::scr_VmPub->function_frame_start; --frame)
|
||||||
{
|
{
|
||||||
const auto function_stack = game::scr_function_stack;
|
const auto pos = frame == game::scr_VmPub->function_frame ? game::scr_function_stack->pos : frame->fs.pos;
|
||||||
const auto pos = frame == game::scr_VmPub->function_frame ? function_stack->pos : frame->fs.pos;
|
const auto script_info = find_function(pos);
|
||||||
const auto function = find_function(pos);
|
|
||||||
|
|
||||||
if (function.has_value())
|
if (!script_info.has_value())
|
||||||
{
|
{
|
||||||
auto& file_name = function.value().second;
|
console::warn("\tat unknown location %p\n", pos);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (gsc::source_pos_map.contains(file_name))
|
const auto& function = script_info->function;
|
||||||
|
const auto& file = script_info->file;
|
||||||
|
const auto* loaded_script = gsc::get_loaded_script(file);
|
||||||
|
|
||||||
|
if (loaded_script)
|
||||||
|
{
|
||||||
|
const auto script = loaded_script->ptr;
|
||||||
|
assert(script);
|
||||||
|
|
||||||
|
const auto& pos_map = loaded_script->devmap;
|
||||||
|
|
||||||
|
auto position = static_cast<std::uint32_t>(pos - script->bytecode);
|
||||||
|
for (auto i = 0; i < 8; ++i)
|
||||||
{
|
{
|
||||||
const auto script = gsc::loaded_scripts[file_name];
|
auto position_fixup = position + i;
|
||||||
assert(script);
|
if (pos_map.contains(position_fixup))
|
||||||
|
|
||||||
const auto& pos_map = gsc::source_pos_map[file_name];
|
|
||||||
|
|
||||||
auto position = static_cast<std::uint32_t>(pos - script->bytecode);
|
|
||||||
for (auto i = 0; i < 8; ++i)
|
|
||||||
{
|
{
|
||||||
auto position_fixup = position + i;
|
position = position_fixup;
|
||||||
if (pos_map.contains(position_fixup))
|
break;
|
||||||
{
|
|
||||||
position = position_fixup;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (pos_map.contains(position))
|
if (pos_map.contains(position))
|
||||||
{
|
{
|
||||||
const auto& info = pos_map.at(position);
|
const auto& info = pos_map.at(position);
|
||||||
|
|
||||||
console::warn("\tat function \"%s\" in file \"%s.gsc\" (line %d, col %d)\n",
|
console::warn("\tat function \"%s\" in file \"%s.gsc\" (line %d, col %d)\n",
|
||||||
function.value().first.data(), file_name.data(), info.line, info.column);
|
function.data(), file.data(), info.line, info.column);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
goto NO_DEVMAP;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
NO_DEVMAP:
|
goto NO_DEVMAP;
|
||||||
console::warn("\tat function \"%s\" in file \"%s.gsc\"\n", function.value().first.data(), file_name.data());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
console::warn("\tat unknown location %p\n", pos);
|
NO_DEVMAP:
|
||||||
|
console::warn("\tat function \"%s\" in file \"%s.gsc\"\n", function.data(), file.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
first = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -360,9 +356,8 @@ namespace gsc
|
|||||||
console::warn("*********** script runtime error *************\n");
|
console::warn("*********** script runtime error *************\n");
|
||||||
|
|
||||||
const auto opcode_id = *reinterpret_cast<std::uint8_t*>(0x146B22940);
|
const auto opcode_id = *reinterpret_cast<std::uint8_t*>(0x146B22940);
|
||||||
const std::string error_str = gsc_error_msg.has_value()
|
|
||||||
? utils::string::va(": %s", gsc_error_msg.value().data())
|
const std::string error_str = gsc_error_msg.has_value() ? std::format(": {}", gsc_error_msg.value()) : std::string();
|
||||||
: "";
|
|
||||||
|
|
||||||
if ((opcode_id >= gsc_ctx->opcode_id(xsk::gsc::opcode::OP_CallBuiltin0) && opcode_id <= gsc_ctx->opcode_id(xsk::gsc::opcode::OP_CallBuiltin))
|
if ((opcode_id >= gsc_ctx->opcode_id(xsk::gsc::opcode::OP_CallBuiltin0) && opcode_id <= gsc_ctx->opcode_id(xsk::gsc::opcode::OP_CallBuiltin))
|
||||||
|| (opcode_id >= gsc_ctx->opcode_id(xsk::gsc::opcode::OP_CallBuiltinMethod0) && opcode_id <= gsc_ctx->opcode_id(xsk::gsc::opcode::OP_CallBuiltinMethod)))
|
|| (opcode_id >= gsc_ctx->opcode_id(xsk::gsc::opcode::OP_CallBuiltinMethod0) && opcode_id <= gsc_ctx->opcode_id(xsk::gsc::opcode::OP_CallBuiltinMethod)))
|
||||||
@ -385,7 +380,7 @@ namespace gsc
|
|||||||
force_error_print = false;
|
force_error_print = false;
|
||||||
gsc_error_msg = {};
|
gsc_error_msg = {};
|
||||||
|
|
||||||
print_callstack(opcode_id);
|
print_callstack();
|
||||||
console::warn("**********************************************\n");
|
console::warn("**********************************************\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -428,16 +423,21 @@ namespace gsc
|
|||||||
game::Scr_ErrorInternal();
|
game::Scr_ErrorInternal();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::pair<std::string, std::string>> find_function(const char* pos)
|
std::optional<script_info_t> find_function(const char* pos)
|
||||||
{
|
{
|
||||||
for (const auto& file : scripting::script_function_table_sort)
|
for (const auto& file : scripting::script_function_table_sort)
|
||||||
{
|
{
|
||||||
|
const auto first_function = file.second.begin();
|
||||||
for (auto i = file.second.begin(); i != file.second.end() && std::next(i) != file.second.end(); ++i)
|
for (auto i = file.second.begin(); i != file.second.end() && std::next(i) != file.second.end(); ++i)
|
||||||
{
|
{
|
||||||
const auto next = std::next(i);
|
const auto next = std::next(i);
|
||||||
if (pos >= i->second && pos < next->second)
|
if (pos >= i->second && pos < next->second)
|
||||||
{
|
{
|
||||||
return {std::make_pair(i->first, file.first)};
|
script_info_t info{};
|
||||||
|
info.function = i->first;
|
||||||
|
info.file = file.first;
|
||||||
|
info.script_start = first_function->second;
|
||||||
|
return { info };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,13 @@
|
|||||||
|
|
||||||
namespace gsc
|
namespace gsc
|
||||||
{
|
{
|
||||||
void scr_error(const char* error, const bool force_print = false);
|
struct script_info_t
|
||||||
|
{
|
||||||
|
const char* script_start;
|
||||||
|
std::string file;
|
||||||
|
std::string function;
|
||||||
|
};
|
||||||
|
|
||||||
std::optional<std::pair<std::string, std::string>> find_function(const char* pos);
|
void scr_error(const char* error, const bool force_print = false);
|
||||||
|
std::optional<script_info_t> find_function(const char* pos);
|
||||||
}
|
}
|
@ -311,17 +311,6 @@ namespace gsc
|
|||||||
|
|
||||||
utils::hook::jump(0x140C0D0A4, utils::hook::assemble(vm_execute_stub), true);
|
utils::hook::jump(0x140C0D0A4, utils::hook::assemble(vm_execute_stub), true);
|
||||||
|
|
||||||
/*
|
|
||||||
if (game::environment::is_dedi())
|
|
||||||
{
|
|
||||||
function::add("isusingmatchrulesdata", [](const function_args& args)
|
|
||||||
{
|
|
||||||
// return 0 so the game doesn't override the cfg
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
function::add("print", [](const function_args& args)
|
function::add("print", [](const function_args& args)
|
||||||
{
|
{
|
||||||
print(args);
|
print(args);
|
||||||
@ -375,9 +364,14 @@ namespace gsc
|
|||||||
const auto what = args[0].get_raw();
|
const auto what = args[0].get_raw();
|
||||||
const auto with = args[1].get_raw();
|
const auto with = args[1].get_raw();
|
||||||
|
|
||||||
if (what.type != game::VAR_FUNCTION || with.type != game::VAR_FUNCTION)
|
if (what.type != game::VAR_FUNCTION)
|
||||||
{
|
{
|
||||||
throw std::runtime_error("replacefunc: parameter 1 must be a function");
|
throw std::runtime_error("parameter 1 must be a function");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (with.type != game::VAR_FUNCTION)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("parameter 2 must be a function");
|
||||||
}
|
}
|
||||||
|
|
||||||
vm_execute_hooks[what.u.codePosValue] = with.u.codePosValue;
|
vm_execute_hooks[what.u.codePosValue] = with.u.codePosValue;
|
||||||
|
@ -20,8 +20,7 @@
|
|||||||
namespace gsc
|
namespace gsc
|
||||||
{
|
{
|
||||||
std::unique_ptr<xsk::gsc::iw7::context> gsc_ctx = std::make_unique<xsk::gsc::iw7::context>();
|
std::unique_ptr<xsk::gsc::iw7::context> gsc_ctx = std::make_unique<xsk::gsc::iw7::context>();
|
||||||
std::unordered_map<std::string, game::ScriptFile*> loaded_scripts;
|
std::unordered_map<std::string, loaded_script_t> loaded_scripts;
|
||||||
std::unordered_map<std::string, code_pos_map> source_pos_map;
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
@ -106,40 +105,44 @@ namespace gsc
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse_gsc_map(const std::string& name, const xsk::gsc::buffer& devmap)
|
std::map<std::uint32_t, col_line_t> parse_devmap(const xsk::gsc::buffer& devmap)
|
||||||
{
|
{
|
||||||
auto data = devmap.data;
|
auto data = devmap.data;
|
||||||
auto offset = 0;
|
|
||||||
|
|
||||||
auto count = *reinterpret_cast<const int*>(data + offset);
|
const auto read_32 = [&]()
|
||||||
offset += sizeof(uint32_t);
|
|
||||||
|
|
||||||
console::debug("parsing gscmap for \"%s\" (%d)\n", name.data(), count);
|
|
||||||
|
|
||||||
code_pos_map pos_map{};
|
|
||||||
|
|
||||||
for (auto i = 0; i < count; ++i)
|
|
||||||
{
|
{
|
||||||
auto pos = *reinterpret_cast<const uint32_t*>(data + offset);
|
const auto val = *reinterpret_cast<const std::uint32_t*>(data);
|
||||||
offset += sizeof(uint32_t);
|
data += sizeof(std::uint32_t);
|
||||||
|
return val;
|
||||||
|
};
|
||||||
|
|
||||||
auto line = *reinterpret_cast<const uint16_t*>(data + offset);
|
const auto read_16 = [&]()
|
||||||
offset += sizeof(uint16_t);
|
{
|
||||||
|
const auto val = *reinterpret_cast<const std::uint16_t*>(data);
|
||||||
|
data += sizeof(std::uint16_t);
|
||||||
|
return val;
|
||||||
|
};
|
||||||
|
|
||||||
auto column = *reinterpret_cast<const uint16_t*>(data + offset);
|
std::map<std::uint32_t, col_line_t> pos_map;
|
||||||
offset += sizeof(uint16_t);
|
|
||||||
|
|
||||||
pos_map[pos] = { line, column };
|
const auto devmap_count = read_32();
|
||||||
|
for (auto i = 0u; i < devmap_count; i++)
|
||||||
|
{
|
||||||
|
const auto script_pos = read_32();
|
||||||
|
const auto line = read_16();
|
||||||
|
const auto col = read_16();
|
||||||
|
|
||||||
|
pos_map[script_pos] = { line, col };
|
||||||
}
|
}
|
||||||
|
|
||||||
source_pos_map[name] = pos_map;
|
return pos_map;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 (const auto itr = loaded_scripts.find(file_name); itr != loaded_scripts.end())
|
if (const auto itr = loaded_scripts.find(file_name); itr != loaded_scripts.end())
|
||||||
{
|
{
|
||||||
return itr->second;
|
return itr->second.ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (game::Com_FrontEnd_IsInFrontEnd())
|
if (game::Com_FrontEnd_IsInFrontEnd())
|
||||||
@ -177,13 +180,7 @@ namespace gsc
|
|||||||
data.assign(source_buffer.begin(), source_buffer.end());
|
data.assign(source_buffer.begin(), source_buffer.end());
|
||||||
|
|
||||||
const auto assembly_ptr = compiler.compile(real_name, data);
|
const auto assembly_ptr = compiler.compile(real_name, data);
|
||||||
const auto output_script = assembler.assemble(*assembly_ptr);
|
const auto& [bytecode, stack, devmap] = assembler.assemble(*assembly_ptr);
|
||||||
|
|
||||||
const auto bytecode = std::get<0>(output_script);
|
|
||||||
const auto stack = std::get<1>(output_script);
|
|
||||||
const auto devmap = std::get<2>(output_script);
|
|
||||||
|
|
||||||
parse_gsc_map(real_name, devmap);
|
|
||||||
|
|
||||||
const auto script_file_ptr = static_cast<game::ScriptFile*>(scriptfile_allocator.allocate(sizeof(game::ScriptFile)));
|
const auto script_file_ptr = static_cast<game::ScriptFile*>(scriptfile_allocator.allocate(sizeof(game::ScriptFile)));
|
||||||
script_file_ptr->name = file_name;
|
script_file_ptr->name = file_name;
|
||||||
@ -202,7 +199,10 @@ namespace gsc
|
|||||||
|
|
||||||
script_file_ptr->compressedLen = 0;
|
script_file_ptr->compressedLen = 0;
|
||||||
|
|
||||||
loaded_scripts[file_name] = script_file_ptr;
|
loaded_script_t loaded_script{};
|
||||||
|
loaded_script.ptr = script_file_ptr;
|
||||||
|
loaded_script.devmap = parse_devmap(devmap);
|
||||||
|
loaded_scripts.insert(std::make_pair(file_name, loaded_script));
|
||||||
|
|
||||||
console::debug("Loaded custom gsc '%s.gsc'", real_name.data());
|
console::debug("Loaded custom gsc '%s.gsc'", real_name.data());
|
||||||
|
|
||||||
@ -459,6 +459,15 @@ namespace gsc
|
|||||||
return game::DB_FindXAssetHeader(type, name, allow_create_default).scriptfile;
|
return game::DB_FindXAssetHeader(type, name, allow_create_default).scriptfile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loaded_script_t* get_loaded_script(const std::string& name)
|
||||||
|
{
|
||||||
|
if (loaded_scripts.contains(name))
|
||||||
|
{
|
||||||
|
return &loaded_scripts[name];
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
class loading final : public component_interface
|
class loading final : public component_interface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -3,16 +3,20 @@
|
|||||||
|
|
||||||
namespace gsc
|
namespace gsc
|
||||||
{
|
{
|
||||||
extern std::unique_ptr<xsk::gsc::iw7::context> gsc_ctx;
|
struct col_line_t
|
||||||
extern std::unordered_map<std::string, game::ScriptFile*> loaded_scripts;
|
{
|
||||||
|
std::uint16_t line;
|
||||||
|
std::uint16_t column;
|
||||||
|
};
|
||||||
|
|
||||||
struct source_pos_info
|
struct loaded_script_t
|
||||||
{
|
{
|
||||||
xsk::u16 line;
|
game::ScriptFile* ptr;
|
||||||
xsk::u16 column;
|
std::map<std::uint32_t, col_line_t> devmap;
|
||||||
};
|
};
|
||||||
using code_pos_map = std::map<uint32_t, source_pos_info>;
|
|
||||||
extern std::unordered_map<std::string, code_pos_map> source_pos_map;
|
extern std::unique_ptr<xsk::gsc::iw7::context> gsc_ctx;
|
||||||
|
|
||||||
game::ScriptFile* find_script(game::XAssetType type, const char* name, int allow_create_default);
|
game::ScriptFile* find_script(game::XAssetType type, const char* name, int allow_create_default);
|
||||||
|
loaded_script_t* get_loaded_script(const std::string& name);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user