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;
});
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)
{
const auto variable = value.get_raw();
const auto& variable = value.get_raw();
if (value.is<int>())
{
@ -131,28 +131,24 @@ namespace json
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)
{
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)
{
// const auto function = scripting::find_function(variable.u.codePosValue);
return utils::string::va("[codepos]");
return "[codepos]";
}
if (variable.type == game::SCRIPT_END)
{
// const auto function = scripting::find_function(variable.u.codePosValue);
return utils::string::va("[precodepos]");
return "[precodepos]";
}
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<const char*, std::pair<std::string, std::string>> script_function_table_rev;
std::unordered_map<unsigned int, std::string> canonical_string_table;
namespace
{
utils::hook::detour g_shutdown_game_hook;
utils::hook::detour sl_get_canonical_string_hook;
std::vector<std::function<void()>> shutdown_callbacks;
void g_shutdown_game_stub(const int free_scripts)
{
if (free_scripts)
{
canonical_string_table.clear();
}
for (const auto& callback : shutdown_callbacks)
{
callback();
@ -37,6 +45,18 @@ namespace scripting
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)
@ -50,6 +70,7 @@ namespace scripting
void post_unpack() override
{
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::BuiltinFunctionDef> function_map;
extern std::unordered_map<unsigned int, std::string> canonical_string_table;
using script_function = void(*)(game::scr_entref_t);
void on_shutdown(const std::function<void()>& callback);

View File

@ -2,46 +2,145 @@
#include "object.hpp"
#include "execution.hpp"
#include "../../component/scripting.hpp"
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)
: id_(id)
, parent_id_(parent_id)
{
/*if (!this->id_)
if (!this->id_)
{
return;
}
const auto value = game::scr_VarGlob->childVariableValue[this->id_];
game::VariableValue variable;
variable.u = value.u.u;
variable.type = (game::scriptType_e)value.type;
this->value_ = variable;*/
}
void object_value::operator=(const script_value& /*value*/)
{
/*if (!this->id_)
{
return;
}
const auto value = _value.get_raw();
const auto variable = &game::scr_VarGlob->childVariableValue[this->id_];
game::VariableValue variable_{};
variable_.type = variable->type;
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;
}
game::AddRefToValue(game::SCRIPTINSTANCE_SERVER, &value);
game::RemoveRefToValue(game::SCRIPTINSTANCE_SERVER, variable->type, variable->u.u);
this->value_ = variable_;
}
variable->type = gsl::narrow_cast<char>(value.type);
variable->u.u = value.u;
void object_value::operator=(const script_value& value)
{
if (!this->id_)
{
return;
}
this->value_ = value;*/
const auto& value_0 = value.get_raw();
game::VariableValue previous{};
if (game::environment::is_sp())
{
const auto variable = &game::scr_VarGlob->variableList_sp[this->id_ + 0x6000];
previous.type = variable->w.type & 0x1F;
previous.u = variable->u.u;
variable->w.type |= value_0.type;
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;
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)
@ -121,25 +220,7 @@ namespace scripting
std::vector<std::string> object::get_keys() const
{
std::vector<std::string> result;
/*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;
return SELECT_VALUE(get_keys_sp, get_keys_mp)(this->id_);
}
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);
if (!variable_id)
@ -167,18 +248,27 @@ namespace scripting
return {};
}
const auto value = game::scr_VarGlob->childVariableValue[variable_id];
game::VariableValue variable;
variable.u = value.u.u;
variable.type = (game::scriptType_e)value.type;
game::VariableValue variable_{};
return variable;*/
return {};
if (game::environment::is_sp())
{
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;
}
void object::set(const std::string& /*key*/, const script_value& /*value*/) const
return variable_;
}
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);
if (!variable_id)
@ -186,16 +276,29 @@ namespace scripting
return;
}
const auto variable = &game::scr_VarGlob->childVariableValue[variable_id];
game::VariableValue variable_{};
variable_.type = variable->type;
variable_.u = variable->u.u;
game::VariableValue previous{};
game::AddRefToValue(game::SCRIPTINSTANCE_SERVER, &value);
game::RemoveRefToValue(game::SCRIPTINSTANCE_SERVER, variable_.type, variable_.u);
if (game::environment::is_sp())
{
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->u.u = value.u;*/
variable->w.type |= value_.type;
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
@ -205,7 +308,7 @@ namespace scripting
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);
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<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<gentity_s*(scriptInstance_t inst, int index)> Scr_GetEntity{0x0, 0x0};