Finish scripting::object + add some functions

This commit is contained in:
Federico Cecchetto 2022-06-15 18:38:30 +02:00
parent 7f553cba0e
commit 6165f07275
6 changed files with 220 additions and 69 deletions

View File

@ -305,6 +305,35 @@ namespace gsc
return count; return count;
}); });
gsc::function::add("toint", [](const std::string& str, const scripting::variadic_args& va)
{
auto radix = 10;
if (va.size() > 0)
{
radix = va[0];
}
return static_cast<int>(std::strtoull(str.data(), nullptr, radix));
});
gsc::function::add("os::date", [](const scripting::variadic_args& va)
{
std::string format = "%Y-%m-%dT%H:%M:%S%z";
if (va.size() > 0)
{
format = va[0].as<std::string>();
}
tm ltime{};
char timestamp[MAX_PATH] = {0};
const auto time = _time64(nullptr);
_localtime64_s(&ltime, &time);
std::strftime(timestamp, sizeof(timestamp) - 1, format.data(), &ltime);
return std::string(timestamp);
});
} }
}; };
} }

View File

@ -94,7 +94,7 @@ namespace json
nlohmann::json gsc_to_json(scripting::script_value value, bool print_id) nlohmann::json gsc_to_json(scripting::script_value value, bool print_id)
{ {
const auto variable = value.get_raw(); const auto& variable = value.get_raw();
if (value.is<int>()) if (value.is<int>())
{ {
@ -131,28 +131,24 @@ namespace json
return object_to_json(variable.u.uintValue, print_id); return object_to_json(variable.u.uintValue, print_id);
} }
if (value.is<scripting::function>())
{
const auto function = value.as<scripting::function>();
return utils::string::va("[[ %s ]]", function.get_name().data());
}
if (variable.type == game::SCRIPT_NONE) if (variable.type == game::SCRIPT_NONE)
{ {
return {}; return {};
} }
// TODO: scripting component, gsc is way different in BO1 than BO2 :/ if (value.is<scripting::function>())
{
return "[function]";
}
if (variable.type == game::SCRIPT_CODEPOS) if (variable.type == game::SCRIPT_CODEPOS)
{ {
// const auto function = scripting::find_function(variable.u.codePosValue); return "[codepos]";
return utils::string::va("[codepos]");
} }
if (variable.type == game::SCRIPT_END) if (variable.type == game::SCRIPT_END)
{ {
// const auto function = scripting::find_function(variable.u.codePosValue); return "[precodepos]";
return utils::string::va("[precodepos]");
} }
return utils::string::va("[%s]", value.type_name().data()); return utils::string::va("[%s]", value.type_name().data());

View File

@ -23,13 +23,21 @@ namespace scripting
std::unordered_map<std::string, std::vector<std::pair<std::string, const char*>>> script_function_table_sort; std::unordered_map<std::string, std::vector<std::pair<std::string, const char*>>> script_function_table_sort;
std::unordered_map<const char*, std::pair<std::string, std::string>> script_function_table_rev; std::unordered_map<const char*, std::pair<std::string, std::string>> script_function_table_rev;
std::unordered_map<unsigned int, std::string> canonical_string_table;
namespace namespace
{ {
utils::hook::detour g_shutdown_game_hook; utils::hook::detour g_shutdown_game_hook;
utils::hook::detour sl_get_canonical_string_hook;
std::vector<std::function<void()>> shutdown_callbacks; std::vector<std::function<void()>> shutdown_callbacks;
void g_shutdown_game_stub(const int free_scripts) void g_shutdown_game_stub(const int free_scripts)
{ {
if (free_scripts)
{
canonical_string_table.clear();
}
for (const auto& callback : shutdown_callbacks) for (const auto& callback : shutdown_callbacks)
{ {
callback(); callback();
@ -37,6 +45,18 @@ namespace scripting
return g_shutdown_game_hook.invoke<void>(free_scripts); return g_shutdown_game_hook.invoke<void>(free_scripts);
} }
unsigned int sl_transfer_canonical_string_stub(game::scriptInstance_t inst, unsigned int string_value)
{
const auto result = sl_get_canonical_string_hook.invoke<unsigned int>(inst, string_value);
const auto str = game::SL_ConvertToString(string_value, inst);
if (str)
{
canonical_string_table[result] = game::SL_ConvertToString(string_value, inst);
}
return result;
}
} }
void on_shutdown(const std::function<void()>& callback) void on_shutdown(const std::function<void()>& callback)
@ -50,6 +70,7 @@ namespace scripting
void post_unpack() override void post_unpack() override
{ {
g_shutdown_game_hook.create(SELECT_VALUE(0x607700, 0x540950), g_shutdown_game_stub); g_shutdown_game_hook.create(SELECT_VALUE(0x607700, 0x540950), g_shutdown_game_stub);
sl_get_canonical_string_hook.create(SELECT_VALUE(0x5F3F40, 0x622530), sl_transfer_canonical_string_stub);
} }
}; };
} }

View File

@ -11,6 +11,8 @@ namespace scripting
extern std::unordered_map<std::string, game::BuiltinMethodDef> method_map; extern std::unordered_map<std::string, game::BuiltinMethodDef> method_map;
extern std::unordered_map<std::string, game::BuiltinFunctionDef> function_map; extern std::unordered_map<std::string, game::BuiltinFunctionDef> function_map;
extern std::unordered_map<unsigned int, std::string> canonical_string_table;
using script_function = void(*)(game::scr_entref_t); using script_function = void(*)(game::scr_entref_t);
void on_shutdown(const std::function<void()>& callback); void on_shutdown(const std::function<void()>& callback);

View File

@ -2,46 +2,145 @@
#include "object.hpp" #include "object.hpp"
#include "execution.hpp" #include "execution.hpp"
#include "../../component/scripting.hpp"
namespace scripting namespace scripting
{ {
namespace
{
std::string get_string(unsigned int canonical_string)
{
if (canonical_string_table.find(canonical_string) != canonical_string_table.end())
{
return canonical_string_table[canonical_string];
}
return "";
}
unsigned int get_canonical_string(const std::string& str)
{
for (const auto& value : canonical_string_table)
{
if (value.second == str)
{
return value.first;
}
}
return game::SL_GetCanonicalString(game::SCRIPTINSTANCE_SERVER, str.data());
}
std::vector<std::string> get_keys_sp(unsigned int id)
{
std::vector<std::string> result;
auto current = game::scr_VarGlob->variableList_sp[id + 1].nextSibling;
while (current)
{
const auto var = &game::scr_VarGlob->variableList_sp[current + 0x6000];
const auto key_value = get_string(var->w.status >> 8);
result.push_back(key_value);
const auto next_sibling = game::scr_VarGlob->variableList_sp[current + 0x6000].nextSibling;
if (!next_sibling)
{
break;
}
current = static_cast<unsigned __int16>(game::scr_VarGlob->variableList_sp[next_sibling + 0x6000].id);
}
return result;
}
std::vector<std::string> get_keys_mp(unsigned int id)
{
std::vector<std::string> result;
auto current = game::scr_VarGlob->variableList_mp[id + 1].nextSibling;
while (current)
{
const auto var = &game::scr_VarGlob->variableList_mp[current + 0x8000];
const auto key_value = get_string(var->w.status >> 8);
result.push_back(key_value);
const auto next_sibling = game::scr_VarGlob->variableList_mp[current + 0x8000].nextSibling;
if (!next_sibling)
{
break;
}
current = game::scr_VarGlob->variableList_mp[next_sibling + 0x8000].hash.id;
}
return result;
}
}
object_value::object_value(unsigned int parent_id, unsigned int id) object_value::object_value(unsigned int parent_id, unsigned int id)
: id_(id) : id_(id)
, parent_id_(parent_id) , parent_id_(parent_id)
{ {
/*if (!this->id_) if (!this->id_)
{ {
return; return;
} }
const auto value = game::scr_VarGlob->childVariableValue[this->id_]; game::VariableValue variable_{};
game::VariableValue variable;
variable.u = value.u.u;
variable.type = (game::scriptType_e)value.type;
this->value_ = variable;*/ if (game::environment::is_sp())
{
const auto variable = &game::scr_VarGlob->variableList_sp[this->id_ + 0x6000];
variable_.type = variable->w.type & 0x1F;
variable_.u = variable->u.u;
}
else
{
const auto variable = &game::scr_VarGlob->variableList_mp[this->id_ + 0x8000];
variable_.type = variable->w.type & 0x1F;
variable_.u = variable->u.u;
}
this->value_ = variable_;
} }
void object_value::operator=(const script_value& /*value*/) void object_value::operator=(const script_value& value)
{ {
/*if (!this->id_) if (!this->id_)
{ {
return; return;
} }
const auto value = _value.get_raw(); const auto& value_0 = value.get_raw();
const auto variable = &game::scr_VarGlob->childVariableValue[this->id_]; game::VariableValue previous{};
game::VariableValue variable_{};
variable_.type = variable->type;
variable_.u = variable->u.u;
game::AddRefToValue(game::SCRIPTINSTANCE_SERVER, &value); if (game::environment::is_sp())
game::RemoveRefToValue(game::SCRIPTINSTANCE_SERVER, variable->type, variable->u.u); {
const auto variable = &game::scr_VarGlob->variableList_sp[this->id_ + 0x6000];
previous.type = variable->w.type & 0x1F;
previous.u = variable->u.u;
variable->type = gsl::narrow_cast<char>(value.type); variable->w.type |= value_0.type;
variable->u.u = value.u; variable->u.u = value_0.u;
}
else
{
const auto variable = &game::scr_VarGlob->variableList_mp[this->id_ + 0x8000];
previous.type = variable->w.type & 0x1F;
previous.u = variable->u.u;
this->value_ = value;*/ variable->w.type |= value_0.type;
variable->u.u = value_0.u;
}
game::AddRefToValue(game::SCRIPTINSTANCE_SERVER, &value_0);
game::RemoveRefToValue(game::SCRIPTINSTANCE_SERVER, previous.type, previous.u);
this->value_ = value_0;
} }
object::object(const unsigned int id) object::object(const unsigned int id)
@ -121,25 +220,7 @@ namespace scripting
std::vector<std::string> object::get_keys() const std::vector<std::string> object::get_keys() const
{ {
std::vector<std::string> result; return SELECT_VALUE(get_keys_sp, get_keys_mp)(this->id_);
/*auto current = game::scr_VarGlob->objectVariableChildren[this->id_].firstChild;
while (current)
{
const auto var = game::scr_VarGlob->childVariableValue[current];
const auto string_id = (unsigned __int8)var.name_lo + (var.k.keys.name_hi << 8);
if (string_id < 0x34BC)
{
const auto string = reinterpret_cast<const char**>(SELECT_VALUE(0x2DACC28, 0x2D7CF28))[string_id];
result.push_back(string);
}
current = var.nextSibling;
}*/
return result;
} }
unsigned int object::size() const unsigned int object::size() const
@ -157,9 +238,9 @@ namespace scripting
}*/ }*/
} }
script_value object::get(const std::string& /*key*/) const script_value object::get(const std::string& key) const
{ {
/*const auto string_value = game::SL_GetCanonicalString(key.data(), 0); const auto string_value = get_canonical_string(key);
const auto variable_id = game::FindVariable(game::SCRIPTINSTANCE_SERVER, this->id_, string_value); const auto variable_id = game::FindVariable(game::SCRIPTINSTANCE_SERVER, this->id_, string_value);
if (!variable_id) if (!variable_id)
@ -167,18 +248,27 @@ namespace scripting
return {}; return {};
} }
const auto value = game::scr_VarGlob->childVariableValue[variable_id]; game::VariableValue variable_{};
game::VariableValue variable;
variable.u = value.u.u;
variable.type = (game::scriptType_e)value.type;
return variable;*/ if (game::environment::is_sp())
return {}; {
const auto variable = &game::scr_VarGlob->variableList_sp[variable_id + 0x6000];
variable_.type = variable->w.type & 0x1F;
variable_.u = variable->u.u;
}
else
{
const auto variable = &game::scr_VarGlob->variableList_mp[variable_id + 0x8000];
variable_.type = variable->w.type & 0x1F;
variable_.u = variable->u.u;
}
return variable_;
} }
void object::set(const std::string& /*key*/, const script_value& /*value*/) const void object::set(const std::string& key, const script_value& value) const
{ {
/*const auto value = value_.get_raw(); const auto& value_ = value.get_raw();
const auto variable_id = this->get_value_id(key); const auto variable_id = this->get_value_id(key);
if (!variable_id) if (!variable_id)
@ -186,16 +276,29 @@ namespace scripting
return; return;
} }
const auto variable = &game::scr_VarGlob->childVariableValue[variable_id]; game::VariableValue previous{};
game::VariableValue variable_{};
variable_.type = variable->type;
variable_.u = variable->u.u;
game::AddRefToValue(game::SCRIPTINSTANCE_SERVER, &value); if (game::environment::is_sp())
game::RemoveRefToValue(game::SCRIPTINSTANCE_SERVER, variable_.type, variable_.u); {
const auto variable = &game::scr_VarGlob->variableList_sp[variable_id + 0x6000];
previous.type = variable->w.type & 0x1F;
previous.u = variable->u.u;
variable->type = gsl::narrow_cast<char>(value.type); variable->w.type |= value_.type;
variable->u.u = value.u;*/ variable->u.u = value_.u;
}
else
{
const auto variable = &game::scr_VarGlob->variableList_mp[variable_id + 0x8000];
previous.type = variable->w.type & 0x1F;
previous.u = variable->u.u;
variable->w.type |= value_.type;
variable->u.u = value_.u;
}
game::AddRefToValue(game::SCRIPTINSTANCE_SERVER, &value_);
game::RemoveRefToValue(game::SCRIPTINSTANCE_SERVER, previous.type, previous.u);
} }
unsigned int object::get_entity_id() const unsigned int object::get_entity_id() const
@ -205,7 +308,7 @@ namespace scripting
unsigned int object::get_value_id(const std::string& key) const unsigned int object::get_value_id(const std::string& key) const
{ {
const auto string_value = game::SL_GetCanonicalString(key.data(), 0); const auto string_value = get_canonical_string(key);
const auto variable_id = game::FindVariable(game::SCRIPTINSTANCE_SERVER, this->id_, string_value); const auto variable_id = game::FindVariable(game::SCRIPTINSTANCE_SERVER, this->id_, string_value);
if (!variable_id) if (!variable_id)

View File

@ -75,7 +75,7 @@ namespace game
WEAK symbol<unsigned int(const char* str, unsigned int user, scriptInstance_t inst)> SL_GetString{0x463130, 0x4B1770}; WEAK symbol<unsigned int(const char* str, unsigned int user, scriptInstance_t inst)> SL_GetString{0x463130, 0x4B1770};
WEAK symbol<const char*(unsigned int stringValue, scriptInstance_t inst)> SL_ConvertToString{0x687530, 0x624C70}; WEAK symbol<const char*(unsigned int stringValue, scriptInstance_t inst)> SL_ConvertToString{0x687530, 0x624C70};
WEAK symbol<unsigned int(const char* str, bool is_static)> SL_GetCanonicalString{0x0, 0x0}; WEAK symbol<unsigned int(scriptInstance_t inst, const char* str)> SL_GetCanonicalString{0x4FB120, 0x68D860};
WEAK symbol<int(scriptInstance_t inst)> Scr_GetNumParam{0x0, 0x0}; WEAK symbol<int(scriptInstance_t inst)> Scr_GetNumParam{0x0, 0x0};
WEAK symbol<gentity_s*(scriptInstance_t inst, int index)> Scr_GetEntity{0x0, 0x0}; WEAK symbol<gentity_s*(scriptInstance_t inst, int index)> Scr_GetEntity{0x0, 0x0};