update gsc

yoink some from h2-mod
This commit is contained in:
quaK 2024-07-10 20:34:26 +03:00
parent e4eecf66c5
commit 483aad7425
5 changed files with 110 additions and 97 deletions

View File

@ -56,7 +56,7 @@ 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
"while processing function '{}' in script '{}':\nunknown script '{}'", pos.function, pos.file, scripting::current_file
);
}
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)
{
const auto function_stack = game::scr_function_stack;
const auto pos = frame == game::scr_VmPub->function_frame ? function_stack->pos : frame->fs.pos;
const auto function = find_function(pos);
const auto pos = frame == game::scr_VmPub->function_frame ? game::scr_function_stack->pos : frame->fs.pos;
const auto script_info = 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];
assert(script);
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;
if (pos_map.contains(position_fixup))
{
auto position_fixup = position + i;
if (pos_map.contains(position_fixup))
{
position = position_fixup;
break;
}
position = position_fixup;
break;
}
}
if (pos_map.contains(position))
{
const auto& info = pos_map.at(position);
if (pos_map.contains(position))
{
const auto& info = pos_map.at(position);
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);
}
else
{
goto NO_DEVMAP;
}
console::warn("\tat function \"%s\" in file \"%s.gsc\" (line %d, col %d)\n",
function.data(), file.data(), info.line, info.column);
}
else
{
NO_DEVMAP:
console::warn("\tat function \"%s\" in file \"%s.gsc\"\n", function.value().first.data(), file_name.data());
goto NO_DEVMAP;
}
}
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");
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))
|| (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;
gsc_error_msg = {};
print_callstack(opcode_id);
print_callstack();
console::warn("**********************************************\n");
}
@ -428,16 +423,21 @@ namespace gsc
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)
{
const auto first_function = file.second.begin();
for (auto i = file.second.begin(); i != file.second.end() && std::next(i) != file.second.end(); ++i)
{
const auto next = std::next(i);
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 };
}
}
}

View File

@ -2,7 +2,13 @@
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);
}

View File

@ -311,17 +311,6 @@ namespace gsc
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)
{
print(args);
@ -375,9 +364,14 @@ namespace gsc
const auto what = args[0].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;

View File

@ -20,8 +20,7 @@
namespace gsc
{
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, code_pos_map> source_pos_map;
std::unordered_map<std::string, loaded_script_t> loaded_scripts;
namespace
{
@ -106,40 +105,44 @@ namespace gsc
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 offset = 0;
auto count = *reinterpret_cast<const int*>(data + offset);
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)
const auto read_32 = [&]()
{
auto pos = *reinterpret_cast<const uint32_t*>(data + offset);
offset += sizeof(uint32_t);
const auto val = *reinterpret_cast<const std::uint32_t*>(data);
data += sizeof(std::uint32_t);
return val;
};
auto line = *reinterpret_cast<const uint16_t*>(data + offset);
offset += sizeof(uint16_t);
const auto read_16 = [&]()
{
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);
offset += sizeof(uint16_t);
std::map<std::uint32_t, col_line_t> pos_map;
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)
{
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())
@ -177,13 +180,7 @@ namespace gsc
data.assign(source_buffer.begin(), source_buffer.end());
const auto assembly_ptr = compiler.compile(real_name, data);
const auto output_script = 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& [bytecode, stack, devmap] = assembler.assemble(*assembly_ptr);
const auto script_file_ptr = static_cast<game::ScriptFile*>(scriptfile_allocator.allocate(sizeof(game::ScriptFile)));
script_file_ptr->name = file_name;
@ -202,7 +199,10 @@ namespace gsc
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());
@ -459,6 +459,15 @@ namespace gsc
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
{
public:

View File

@ -3,16 +3,20 @@
namespace gsc
{
extern std::unique_ptr<xsk::gsc::iw7::context> gsc_ctx;
extern std::unordered_map<std::string, game::ScriptFile*> loaded_scripts;
struct col_line_t
{
std::uint16_t line;
std::uint16_t column;
};
struct source_pos_info
{
xsk::u16 line;
xsk::u16 column;
};
using code_pos_map = std::map<uint32_t, source_pos_info>;
extern std::unordered_map<std::string, code_pos_map> source_pos_map;
struct loaded_script_t
{
game::ScriptFile* ptr;
std::map<std::uint32_t, col_line_t> devmap;
};
extern std::unique_ptr<xsk::gsc::iw7::context> gsc_ctx;
game::ScriptFile* find_script(game::XAssetType type, const char* name, int allow_create_default);
loaded_script_t* get_loaded_script(const std::string& name);
}