Script struct & function support + refactor function list

This commit is contained in:
Federico Cecchetto 2021-08-29 22:53:20 +02:00
parent c114cfc81e
commit 7568a91be9
12 changed files with 1948 additions and 1762 deletions

View File

@ -103,6 +103,25 @@ namespace scripting
return call_function(name, arguments);
}
script_value exec_ent_thread(const entity& entity, const char* pos, const std::vector<script_value>& arguments)
{
const auto id = entity.get_entity_id();
stack_isolation _;
for (auto i = arguments.rbegin(); i != arguments.rend(); ++i)
{
scripting::push_value(*i);
}
game::AddRefToObject(id);
const auto local_id = game::AllocThread(id);
const auto result = game::VM_Execute(local_id, pos, (unsigned int)arguments.size());
game::RemoveRefToObject(result);
return get_return_value();
}
static std::unordered_map<unsigned int, std::unordered_map<std::string, script_value>> custom_fields;
script_value get_custom_field(const entity& entity, const std::string& field)

View File

@ -21,6 +21,8 @@ namespace scripting
return call<script_value>(name, arguments).as<T>();
}
script_value exec_ent_thread(const entity& entity, const char* pos, const std::vector<script_value>& arguments);
void clear_entity_fields(const entity& entity);
void clear_custom_fields();

File diff suppressed because it is too large Load Diff

View File

@ -71,6 +71,18 @@ namespace scripting
}
}
unsigned int find_token_id(const std::string& name)
{
const auto result = token_map.find(name);
if (result != token_map.end())
{
return result->second;
}
return 0;
}
script_function find_function(const std::string& name, const bool prefer_global)
{
const auto index = find_function_index(name, prefer_global);

View File

@ -5,8 +5,10 @@ namespace scripting
{
extern std::unordered_map<std::string, unsigned> method_map;
extern std::unordered_map<std::string, unsigned> function_map;
extern std::unordered_map<std::string, unsigned> token_map;
using script_function = void(*)(game::scr_entref_t);
unsigned int find_token_id(const std::string& name);
script_function find_function(const std::string& name, const bool prefer_global);
}

View File

@ -300,6 +300,18 @@ namespace scripting::lua
return convert(s, entity.get(field));
};
entity_type["struct"] = sol::property([](const entity& entity, const sol::this_state s)
{
const auto id = entity.get_entity_id();
return scripting::lua::entity_to_struct(s, id);
});
entity_type["getstruct"] = [](const entity& entity, const sol::this_state s)
{
const auto id = entity.get_entity_id();
return scripting::lua::entity_to_struct(s, id);
};
struct game
{
};

View File

@ -1,5 +1,7 @@
#include <stdinc.hpp>
#include "value_conversion.hpp"
#include "../functions.hpp"
#include "../execution.hpp"
namespace scripting::lua
{
@ -18,7 +20,7 @@ namespace scripting::lua
std::unordered_map<std::string, array_value> values;
const auto offset = 40960 * (id & 3);
const auto offset = 0xA000 * (id & 3);
auto current = game::scr_VarGlob->objectVariableChildren[id].firstChild;
auto idx = 1;
@ -137,6 +139,89 @@ namespace scripting::lua
return script_value(variable);
}
sol::lua_value convert_function(lua_State* state, const char* pos)
{
return [pos](const entity& entity, const sol::this_state s, sol::variadic_args va)
{
std::vector<script_value> arguments{};
for (auto arg : va)
{
arguments.push_back(convert({s, arg}));
}
return convert(s, scripting::exec_ent_thread(entity, pos, arguments));
};
}
}
sol::lua_value entity_to_struct(lua_State* state, unsigned int parent_id)
{
auto table = sol::table::create(state);
auto metatable = sol::table::create(state);
const auto offset = 0xA000 * (parent_id & 3);
metatable[sol::meta_function::new_index] = [offset, parent_id](const sol::table t, const sol::this_state s,
const sol::lua_value& field, const sol::lua_value& value)
{
const auto id = field.is<std::string>()
? scripting::find_token_id(field.as<std::string>())
: field.as<int>();
if (!id)
{
return;
}
const auto variable_id = game::FindVariable(parent_id, id);
if (!variable_id)
{
return;
}
const auto variable = &game::scr_VarGlob->childVariableValue[variable_id + offset];
const auto new_variable = convert({ s, value }).get_raw();
game::AddRefToValue(new_variable.type, new_variable.u);
game::RemoveRefToValue(variable->type, variable->u.u);
variable->type = (char)new_variable.type;
variable->u.u = new_variable.u;
};
metatable[sol::meta_function::index] = [offset, parent_id](const sol::table t, const sol::this_state s,
const sol::lua_value& field)
{
const auto id = field.is<std::string>()
? scripting::find_token_id(field.as<std::string>())
: field.as<int>();
if (!id)
{
return sol::lua_value{s, sol::lua_nil};
}
const auto variable_id = game::FindVariable(parent_id, id);
if (!variable_id)
{
return sol::lua_value{s, sol::lua_nil};
}
const auto variable = game::scr_VarGlob->childVariableValue[variable_id + offset];
game::VariableValue result{};
result.u = variable.u.u;
result.type = (game::scriptType_e)variable.type;
return convert(s, result);
};
table[sol::metatable_key] = metatable;
return {state, table};
}
script_value convert(const sol::lua_value& value)
@ -206,11 +291,21 @@ namespace scripting::lua
return {state, value.as<std::string>()};
}
if (value.is<std::map<std::string, script_value>>())
{
return entity_to_struct(state, value.get_raw().u.uintValue);
}
if (value.is<std::vector<script_value>>())
{
return entity_to_array(state, value.get_raw().u.uintValue);
}
if (value.is<std::function<void()>>())
{
return convert_function(state, value.get_raw().u.codePosValue);
}
if (value.is<entity>())
{
return {state, value.as<entity>()};

View File

@ -4,6 +4,8 @@
namespace scripting::lua
{
sol::lua_value entity_to_struct(lua_State* state, unsigned int parent_id);
script_value convert(const sol::lua_value& value);
sol::lua_value convert(lua_State* state, const script_value& value);
}

View File

@ -2,7 +2,6 @@
#include "script_value.hpp"
#include "entity.hpp"
namespace scripting
{
/***************************************************************
@ -207,6 +206,34 @@ namespace scripting
return type == game::SCRIPT_ARRAY;
}
/***************************************************************
* Struct
**************************************************************/
template <>
bool script_value::is<std::map<std::string, script_value>>() const
{
if (this->get_raw().type != game::SCRIPT_OBJECT)
{
return false;
}
const auto id = this->get_raw().u.uintValue;
const auto type = game::scr_VarGlob->objectVariableValue[id].w.type;
return type == game::SCRIPT_STRUCT;
}
/***************************************************************
* Function
**************************************************************/
template <>
bool script_value::is<std::function<void()>>() const
{
return this->get_raw().type == game::SCRIPT_FUNCTION;
}
/***************************************************************
* Entity
**************************************************************/

View File

@ -611,7 +611,9 @@ namespace game
SCRIPT_FLOAT = 5,
SCRIPT_INTEGER = 6,
SCRIPT_END = 8,
SCRIPT_ARRAY = 22
SCRIPT_FUNCTION = 9,
SCRIPT_STRUCT = 19,
SCRIPT_ARRAY = 22,
};
struct VariableStackBuffer

View File

@ -7,7 +7,10 @@ namespace game
// Functions
WEAK symbol<void(int type, VariableUnion u)> AddRefToValue{0x5C0EB0};
WEAK symbol<void(unsigned int id)> AddRefToObject{0x5C0EA0};
WEAK symbol<unsigned int(unsigned int id)> AllocThread{0x5C1200};
WEAK symbol<void(int type, VariableUnion u)> RemoveRefToValue{0x5C29B0};
WEAK symbol<void(unsigned int id)> RemoveRefToObject{0x5C28A0};
WEAK symbol<void(int localClientNum, const char* text)> Cbuf_AddText{0x59A050};
@ -44,6 +47,7 @@ namespace game
WEAK symbol<bool()> CL_IsCgameInitialized{0x3CA0C0};
WEAK symbol<unsigned int (unsigned int parentId, unsigned int name)> FindVariable{0x5C1D50};
WEAK symbol<unsigned int(int entnum, unsigned int classnum)> FindEntityId{0x5C1C50};
WEAK symbol<void(VariableValue* result, unsigned int classnum, int entnum, int offset)> GetEntityFieldValue{0x5C6100};
@ -69,6 +73,8 @@ namespace game
WEAK symbol<int(unsigned int classnum, int entnum, int offset)> Scr_SetObjectField{0x512190};
WEAK symbol<void(unsigned int id, scr_string_t stringValue, unsigned int paramcount)> Scr_NotifyId{0x5C8240};
WEAK symbol<unsigned int(unsigned int localId, const char* pos, unsigned int paramcount)> VM_Execute{0x5C8DB0};
WEAK symbol<void(float x, float y, float width, float height, float s0, float t0, float s1, float t1,
float* color, Material* material)> R_AddCmdDrawStretchPic{0x3C9710};
WEAK symbol<void(const char* text, int maxChars, Font_s* font, float x, float y, float xScale, float yScale,

View File

@ -23,6 +23,7 @@
#include <csetjmp>
#include <deque>
#include <optional>
#include <map>
#ifdef max
#undef max