gsc: fix loading & restore error messages (#519)

This commit is contained in:
Edo 2022-11-03 14:13:36 +00:00 committed by GitHub
parent 2bd643533c
commit 795b3129b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 290 additions and 91 deletions

View File

@ -65,30 +65,13 @@ namespace filesystem
game::FS_Startup(gamename);
}
std::vector<std::filesystem::path> get_paths(const std::filesystem::path& path)
{
std::vector<std::filesystem::path> paths{};
const auto code = game::SEH_GetCurrentLanguageName();
paths.push_back(path);
paths.push_back(path / code);
return paths;
}
bool can_insert_path(const std::filesystem::path& path)
{
for (const auto& path_ : get_search_paths_internal())
const auto& paths = get_search_paths_internal();
return std::ranges::none_of(paths.cbegin(), paths.cend(), [path](const auto& elem)
{
if (path_ == path)
{
return false;
}
}
return true;
return elem == path;
});
}
}
@ -190,14 +173,10 @@ namespace filesystem
return;
}
const auto paths = get_paths(path);
for (const auto& path_ : paths)
if (can_insert_path(path))
{
if (can_insert_path(path_))
{
console::info("[FS] Registering path '%s'\n", path_.generic_string().data());
get_search_paths_internal().push_front(path_);
}
console::info("[FS] Registering path '%s'\n", path.generic_string().data());
get_search_paths_internal().push_front(path);
}
}
@ -208,21 +187,17 @@ namespace filesystem
return;
}
const auto paths = get_paths(path);
for (const auto& path_ : paths)
auto& search_paths = get_search_paths_internal();
for (auto i = search_paths.begin(); i != search_paths.end();)
{
auto& search_paths = get_search_paths_internal();
for (auto i = search_paths.begin(); i != search_paths.end();)
if (*i == path)
{
if (*i == path_)
{
console::info("[FS] Unregistering path '%s'\n", path_.generic_string().data());
i = search_paths.erase(i);
}
else
{
++i;
}
console::info("[FS] Unregistering path '%s'\n", path.generic_string().data());
i = search_paths.erase(i);
}
else
{
++i;
}
}
}

View File

@ -10,6 +10,8 @@
#include <utils/hook.hpp>
#include <utils/string.hpp>
using namespace utils::string;
namespace gsc
{
namespace
@ -20,6 +22,38 @@ namespace gsc
std::string unknown_function_error;
// Array count confirmed at 0x1409BE0D0
std::array<const char*, 27> var_typename =
{
"undefined",
"object",
"string",
"localized string",
"vector",
"float",
"int",
"codepos",
"precodepos",
"function",
"builtin function",
"builtin method",
"stack",
"animation",
"pre animation",
"thread",
"thread",
"thread",
"thread",
"struct",
"removed entity",
"entity",
"array",
"removed thread",
"<free>",
"thread list",
"endon list",
};
void scr_emit_function_stub(unsigned int filename, unsigned int thread_name, char* code_pos)
{
current_filename = filename;
@ -82,6 +116,23 @@ namespace gsc
return res;
}
unsigned int scr_get_object(unsigned int index)
{
if (index < game::scr_VmPub->outparamcount)
{
auto* value = game::scr_VmPub->top - index;
if (value->type == game::VAR_POINTER)
{
return value->u.pointerValue;
}
scr_error(va("Type %s is not an object", var_typename[value->type]));
}
scr_error(va("Parameter %u does not exist", index + 1));
return 0;
}
unsigned int scr_get_const_string(unsigned int index)
{
if (index < game::scr_VmPub->outparamcount)
@ -89,16 +140,146 @@ namespace gsc
auto* value = game::scr_VmPub->top - index;
if (game::Scr_CastString(value))
{
assert(value->type == game::SCRIPT_STRING);
assert(value->type == game::VAR_STRING);
return value->u.stringValue;
}
game::Scr_ErrorInternal();
}
scr_error(utils::string::va("Parameter %u does not exist", index + 1));
scr_error(va("Parameter %u does not exist", index + 1));
return 0;
}
unsigned int scr_get_const_istring(unsigned int index)
{
if (index < game::scr_VmPub->outparamcount)
{
auto* value = game::scr_VmPub->top - index;
if (value->type == game::VAR_ISTRING)
{
return value->u.stringValue;
}
scr_error(va("Type %s is not a localized string", var_typename[value->type]));
}
scr_error(va("Parameter %u does not exist", index + 1));
return 0;
}
void scr_validate_localized_string_ref(int parm_index, const char* token, int token_len)
{
assert(token);
assert(token_len >= 0);
if (token_len < 2)
{
return;
}
for (auto char_iter = 0; char_iter < token_len; ++char_iter)
{
if (!std::isalnum(static_cast<unsigned char>(token[char_iter])) && token[char_iter] != '_')
{
scr_error(va("Illegal localized string reference: %s must contain only alpha-numeric characters and underscores", token));
}
}
}
void scr_get_vector(unsigned int index, float* vector_value)
{
if (index < game::scr_VmPub->outparamcount)
{
auto* value = game::scr_VmPub->top - index;
if (value->type == game::VAR_VECTOR)
{
std::memcpy(vector_value, value->u.vectorValue, sizeof(std::float_t[3]));
return;
}
scr_error(va("Type %s is not a vector", var_typename[value->type]));
}
scr_error(va("Parameter %u does not exist", index + 1));
}
int scr_get_int(unsigned int index)
{
if (index < game::scr_VmPub->outparamcount)
{
auto* value = game::scr_VmPub->top - index;
if (value->type == game::VAR_INTEGER)
{
return value->u.intValue;
}
scr_error(va("Type %s is not an int", var_typename[value->type]));
}
scr_error(va("Parameter %u does not exist", index + 1));
return 0;
}
float scr_get_float(unsigned int index)
{
if (index < game::scr_VmPub->outparamcount)
{
auto* value = game::scr_VmPub->top - index;
if (value->type == game::VAR_FLOAT)
{
return value->u.floatValue;
}
if (value->type == game::VAR_INTEGER)
{
return static_cast<float>(value->u.intValue);
}
scr_error(va("Type %s is not a float", var_typename[value->type]));
}
scr_error(va("Parameter %u does not exist", index + 1));
return 0.0f;
}
int scr_get_pointer_type(unsigned int index)
{
if (index < game::scr_VmPub->outparamcount)
{
if ((game::scr_VmPub->top - index)->type == game::VAR_POINTER)
{
return static_cast<int>(game::GetObjectType((game::scr_VmPub->top - index)->u.uintValue));
}
scr_error(va("Type %s is not an object", var_typename[(game::scr_VmPub->top - index)->type]));
}
scr_error(va("Parameter %u does not exist", index + 1));
return 0;
}
int scr_get_type(unsigned int index)
{
if (index < game::scr_VmPub->outparamcount)
{
return (game::scr_VmPub->top - index)->type;
}
scr_error(va("Parameter %u does not exist", index + 1));
return 0;
}
const char* scr_get_type_name(unsigned int index)
{
if (index < game::scr_VmPub->outparamcount)
{
return var_typename[(game::scr_VmPub->top - index)->type];
}
scr_error(va("Parameter %u does not exist", index + 1));
return nullptr;
}
}
std::optional<std::pair<std::string, std::string>> find_function(const char* pos)
@ -134,8 +315,18 @@ namespace gsc
utils::hook::call(0x1403ED8E8, compile_error_stub); // LinkFile
utils::hook::call(0x1403ED9DB, find_variable_stub); // Scr_EmitFunction
// Restore basic error messages to scr functions
// Restore basic error messages for commonly used scr functions
utils::hook::jump(0x1403F8990, scr_get_object);
utils::hook::jump(0x1403F8510, scr_get_const_string);
utils::hook::jump(0x1403F82F0, scr_get_const_istring);
utils::hook::jump(0x140327870, scr_validate_localized_string_ref);
utils::hook::jump(0x1403F8EC0, scr_get_vector);
utils::hook::jump(0x1403F88D0, scr_get_int);
utils::hook::jump(0x1403F8820, scr_get_float);
utils::hook::jump(0x1403F8BA0, scr_get_pointer_type);
utils::hook::jump(0x1403F8D70, scr_get_type);
utils::hook::jump(0x1403F8DE0, scr_get_type_name);
}
void pre_destroy() override

View File

@ -275,7 +275,7 @@ namespace gsc
override_function("assert", &assert_cmd);
override_function("assertex", &assert_ex_cmd);
override_function("assertmsg", &assert_ex_cmd);
override_function("assertmsg", &assert_msg_cmd);
add_function("executecommand", []
{

View File

@ -242,6 +242,11 @@ namespace gsc
{
utils::hook::invoke<void>(0x140323F20);
if (game::VirtualLobby_Loaded())
{
return;
}
clear();
fastfiles::enum_assets(game::ASSET_TYPE_RAWFILE, [](const game::XAssetHeader header)
@ -276,11 +281,14 @@ namespace gsc
void g_load_structs_stub()
{
for (auto& function_handle : main_handles)
if (!game::VirtualLobby_Loaded())
{
console::info("Executing '%s::main'\n", function_handle.first.data());
const auto thread = game::Scr_ExecThread(function_handle.second, 0);
game::RemoveRefToObject(thread);
for (auto& function_handle : main_handles)
{
console::info("Executing '%s::main'\n", function_handle.first.data());
const auto thread = game::Scr_ExecThread(function_handle.second, 0);
game::RemoveRefToObject(thread);
}
}
utils::hook::invoke<void>(0x1403380D0);
@ -290,6 +298,11 @@ namespace gsc
{
utils::hook::invoke<void>(0x140325B90);
if (game::VirtualLobby_Loaded())
{
return;
}
for (auto& function_handle : init_handles)
{
console::info("Executing '%s::init'\n", function_handle.first.data());

View File

@ -245,7 +245,7 @@ namespace notifies
std::vector<sol::lua_value> args;
const auto top = game::scr_function_stack->top;
for (auto* value = top; value->type != game::SCRIPT_END; --value)
for (auto* value = top; value->type != game::VAR_PRECODEPOS; --value)
{
args.push_back(scripting::lua::convert(state, *value));
}

View File

@ -52,7 +52,7 @@ namespace scripting
e.name = string;
e.entity = notify_list_owner_id;
for (auto* value = top; value->type != game::SCRIPT_END; --value)
for (auto* value = top; value->type != game::VAR_PRECODEPOS; --value)
{
e.arguments.emplace_back(*value);
}

View File

@ -90,7 +90,7 @@ namespace scripting
{
if (this->entity_id_)
{
game::AddRefToValue(game::SCRIPT_OBJECT, {static_cast<int>(this->entity_id_)});
game::AddRefToValue(game::VAR_POINTER, {static_cast<int>(this->entity_id_)});
}
}
@ -98,7 +98,7 @@ namespace scripting
{
if (this->entity_id_)
{
game::RemoveRefToValue(game::SCRIPT_OBJECT, {static_cast<int>(this->entity_id_)});
game::RemoveRefToValue(game::VAR_POINTER, {static_cast<int>(this->entity_id_)});
}
}

View File

@ -30,7 +30,7 @@ namespace scripting
const auto field_str = game::SL_GetString(field.data(), 0);
const auto _ = gsl::finally([field_str]()
{
game::RemoveRefToValue(game::SCRIPT_STRING, {static_cast<int>(field_str)});
game::RemoveRefToValue(game::VAR_STRING, {static_cast<int>(field_str)});
});
const auto offset = game::FindVariable(class_id, field_str);

View File

@ -31,7 +31,7 @@ namespace scripting::lua
{
const auto var = game::scr_VarGlob->childVariableValue[i];
if (var.type == game::SCRIPT_NONE)
if (var.type == game::VAR_UNDEFINED)
{
current = var.nextSibling;
continue;
@ -125,7 +125,7 @@ namespace scripting::lua
notifies::set_lua_hook(index, function);
game::VariableValue func;
func.type = game::SCRIPT_FUNCTION;
func.type = game::VAR_FUNCTION;
func.u.codePosValue = index;
return func;
@ -208,7 +208,7 @@ namespace scripting::lua
game::VariableValue result{};
result.u = variable.u.u;
result.type = (game::scriptType_e)variable.type;
result.type = variable.type;
return convert(s, result);
};

View File

@ -56,7 +56,7 @@ namespace scripting::safe_execution
*game::g_script_error_level += 1;
if (game::_setjmp(&game::g_script_error[*game::g_script_error_level]))
{
value->type = game::SCRIPT_NONE;
value->type = game::VAR_UNDEFINED;
value->u.intValue = 0;
*game::g_script_error_level -= 1;
return false;

View File

@ -17,7 +17,7 @@ namespace scripting
script_value::script_value(const int value)
{
game::VariableValue variable{};
variable.type = game::SCRIPT_INTEGER;
variable.type = game::VAR_INTEGER;
variable.u.intValue = value;
this->value_ = variable;
@ -26,7 +26,7 @@ namespace scripting
script_value::script_value(const unsigned int value)
{
game::VariableValue variable{};
variable.type = game::SCRIPT_INTEGER;
variable.type = game::VAR_INTEGER;
variable.u.uintValue = value;
this->value_ = variable;
@ -40,7 +40,7 @@ namespace scripting
script_value::script_value(const float value)
{
game::VariableValue variable{};
variable.type = game::SCRIPT_FLOAT;
variable.type = game::VAR_FLOAT;
variable.u.floatValue = value;
this->value_ = variable;
@ -54,7 +54,7 @@ namespace scripting
script_value::script_value(const char* value)
{
game::VariableValue variable{};
variable.type = game::SCRIPT_STRING;
variable.type = game::VAR_STRING;
variable.u.stringValue = game::SL_GetString(value, 0);
const auto _ = gsl::finally([&variable]()
@ -73,7 +73,7 @@ namespace scripting
script_value::script_value(const entity& value)
{
game::VariableValue variable{};
variable.type = game::SCRIPT_OBJECT;
variable.type = game::VAR_POINTER;
variable.u.pointerValue = value.get_entity_id();
this->value_ = variable;
@ -82,7 +82,7 @@ namespace scripting
script_value::script_value(const vector& value)
{
game::VariableValue variable{};
variable.type = game::SCRIPT_VECTOR;
variable.type = game::VAR_VECTOR;
variable.u.vectorValue = game::Scr_AllocVector(value);
const auto _ = gsl::finally([&variable]()
@ -100,7 +100,7 @@ namespace scripting
template <>
bool script_value::is<int>() const
{
return this->get_raw().type == game::SCRIPT_INTEGER;
return this->get_raw().type == game::VAR_INTEGER;
}
template <>
@ -140,7 +140,7 @@ namespace scripting
template <>
bool script_value::is<float>() const
{
return this->get_raw().type == game::SCRIPT_FLOAT;
return this->get_raw().type == game::VAR_FLOAT;
}
template <>
@ -158,7 +158,7 @@ namespace scripting
template <>
double script_value::get() const
{
return static_cast<double>(this->get_raw().u.floatValue);
return this->get_raw().u.floatValue;
}
/***************************************************************
@ -168,7 +168,7 @@ namespace scripting
template <>
bool script_value::is<const char*>() const
{
return this->get_raw().type == game::SCRIPT_STRING;
return this->get_raw().type == game::VAR_STRING;
}
template <>
@ -196,7 +196,7 @@ namespace scripting
template <>
bool script_value::is<std::vector<script_value>>() const
{
if (this->get_raw().type != game::SCRIPT_OBJECT)
if (this->get_raw().type != game::VAR_POINTER)
{
return false;
}
@ -204,7 +204,7 @@ namespace scripting
const auto id = this->get_raw().u.uintValue;
const auto type = game::scr_VarGlob->objectVariableValue[id].w.type;
return type == game::SCRIPT_ARRAY;
return type == game::VAR_ARRAY;
}
/***************************************************************
@ -214,7 +214,7 @@ namespace scripting
template <>
bool script_value::is<std::map<std::string, script_value>>() const
{
if (this->get_raw().type != game::SCRIPT_OBJECT)
if (this->get_raw().type != game::VAR_POINTER)
{
return false;
}
@ -222,7 +222,7 @@ namespace scripting
const auto id = this->get_raw().u.uintValue;
const auto type = game::scr_VarGlob->objectVariableValue[id].w.type;
return type == game::SCRIPT_STRUCT;
return type == game::VAR_OBJECT;
}
/***************************************************************
@ -232,7 +232,7 @@ namespace scripting
template <>
bool script_value::is<std::function<void()>>() const
{
return this->get_raw().type == game::SCRIPT_FUNCTION;
return this->get_raw().type == game::VAR_FUNCTION;
}
/***************************************************************
@ -242,7 +242,7 @@ namespace scripting
template <>
bool script_value::is<entity>() const
{
return this->get_raw().type == game::SCRIPT_OBJECT;
return this->get_raw().type == game::VAR_POINTER;
}
template <>
@ -258,7 +258,7 @@ namespace scripting
template <>
bool script_value::is<vector>() const
{
return this->get_raw().type == game::SCRIPT_VECTOR;
return this->get_raw().type == game::VAR_VECTOR;
}
template <>

View File

@ -35,7 +35,7 @@ namespace scripting
{
this->release();
this->value_ = other.value_;
other.value_.type = game::SCRIPT_NONE;
other.value_.type = game::VAR_UNDEFINED;
}
return *this;
@ -59,10 +59,10 @@ namespace scripting
void variable_value::release()
{
if (this->value_.type != game::SCRIPT_NONE)
if (this->value_.type != game::VAR_UNDEFINED)
{
game::RemoveRefToValue(this->value_.type, this->value_.u);
this->value_.type = game::SCRIPT_NONE;
this->value_.type = game::VAR_UNDEFINED;
}
}
}

View File

@ -22,6 +22,6 @@ namespace scripting
void assign(const game::VariableValue& value);
void release();
game::VariableValue value_{{0}, game::SCRIPT_NONE};
game::VariableValue value_{{0}, game::VAR_UNDEFINED};
};
}

View File

@ -25,19 +25,39 @@ namespace game
typedef void(*BuiltinMethod)(scr_entref_t);
typedef void(*BuiltinFunction)();
enum scriptType_e
enum
{
SCRIPT_NONE = 0,
SCRIPT_OBJECT = 1,
SCRIPT_STRING = 2,
SCRIPT_ISTRING = 3,
SCRIPT_VECTOR = 4,
SCRIPT_FLOAT = 5,
SCRIPT_INTEGER = 6,
SCRIPT_END = 8,
SCRIPT_FUNCTION = 9,
SCRIPT_STRUCT = 19,
SCRIPT_ARRAY = 22
VAR_UNDEFINED = 0x0,
VAR_BEGIN_REF = 0x1,
VAR_POINTER = 0x1,
VAR_STRING = 0x2,
VAR_ISTRING = 0x3,
VAR_VECTOR = 0x4,
VAR_END_REF = 0x5,
VAR_FLOAT = 0x5,
VAR_INTEGER = 0x6,
VAR_CODEPOS = 0x7,
VAR_PRECODEPOS = 0x8,
VAR_FUNCTION = 0x9,
VAR_BUILTIN_FUNCTION = 0xA,
VAR_BUILTIN_METHOD = 0xB,
VAR_STACK = 0xC,
VAR_ANIMATION = 0xD,
VAR_PRE_ANIMATION = 0xE,
VAR_THREAD = 0xF,
VAR_NOTIFY_THREAD = 0x10,
VAR_TIME_THREAD = 0x11,
VAR_CHILD_THREAD = 0x12,
VAR_OBJECT = 0x13,
VAR_DEAD_ENTITY = 0x14,
VAR_ENTITY = 0x15,
VAR_ARRAY = 0x16,
VAR_DEAD_THREAD = 0x17,
VAR_COUNT = 0x18,
VAR_FREE = 0x18,
VAR_THREAD_LIST = 0x19,
VAR_ENDON_LIST = 0x1A,
VAR_TOTAL_COUNT = 0x1B,
};
struct VariableStackBuffer