Add notification support

This commit is contained in:
momo5502 2019-01-19 00:57:19 +01:00
parent e3d47528f6
commit a1f1f99a45
4 changed files with 194 additions and 10 deletions

View File

@ -15,8 +15,12 @@ namespace game
MSG_ReadData_t MSG_ReadData;
MT_AllocIndex_t MT_AllocIndex;
RemoveRefToValue_t RemoveRefToValue;
Scr_NotifyId_t Scr_NotifyId;
SL_GetStringOfSize_t SL_GetStringOfSize;
Sys_ShowConsole_t Sys_ShowConsole;
@ -29,6 +33,7 @@ namespace game
short* scrVarGlob;
char** scrMemTreePub;
char* scrMemTreeGlob;
unsigned int* scr_numParam;
unsigned int* scr_numArgs;
@ -65,6 +70,24 @@ namespace game
}
}
void* MT_Alloc(const int numBytes, const int type)
{
return scrMemTreeGlob + 12 * size_t(MT_AllocIndex(numBytes, type));
}
const float* Scr_AllocVector(const float *v)
{
const auto mem = static_cast<DWORD*>(MT_Alloc(16, 2));
*mem = 0;
const auto array = reinterpret_cast<float*>(mem + 1);
array[0] = v[0];
array[1] = v[1];
array[2] = v[2];
return array;
}
void Scr_ClearOutParams()
{
const auto num_params = *scr_numParam;
@ -109,7 +132,7 @@ namespace game
return *scrMemTreePub + size * stringValue + 4;
}
unsigned int SL_GetString(const char *str, const unsigned int user)
unsigned int SL_GetString(const char* str, const unsigned int user)
{
return SL_GetStringOfSize(str, user, strlen(str) + 1, 7);
}
@ -146,8 +169,12 @@ namespace game
native::MSG_ReadData = native::MSG_ReadData_t(SELECT_VALUE(0, 0x5592A0, 0));
native::MT_AllocIndex = native::MT_AllocIndex_t(SELECT_VALUE(0x4B9610, 0x562080, 0x4E6C30));
native::RemoveRefToValue = native::RemoveRefToValue_t(SELECT_VALUE(0x477EA0, 0x565730, 0x4E8A40));
native::Scr_NotifyId = native::Scr_NotifyId_t(SELECT_VALUE(0x610980, 0x56B5E0, 0x4EFAA0));
native::SL_GetStringOfSize = native::SL_GetStringOfSize_t(SELECT_VALUE(0x4E13F0, 0x564650, 0x4E7490));
native::Sys_ShowConsole = native::Sys_ShowConsole_t(SELECT_VALUE(0x470AF0, 0x5CF590, 0));
@ -160,14 +187,20 @@ namespace game
native::scrVarGlob = reinterpret_cast<short*>(SELECT_VALUE(0x19AFC80, 0x1E72180, 0x1D3C800));
native::scrMemTreePub = reinterpret_cast<char**>(SELECT_VALUE(0x196FB00, 0x1E32000, 0x1C152A4));
native::scrMemTreeGlob = reinterpret_cast<char*>(SELECT_VALUE(0x186DA00, 0x1D6FF00, 0x1C16600));
native::scr_numParam = reinterpret_cast<unsigned int*>(SELECT_VALUE(0x1BF2598, 0x20B4A98, 0x1F5B098));
native::scr_numArgs = reinterpret_cast<unsigned int*>(SELECT_VALUE(0x1BF2594, 0x20B4A94, 0x1F5B094));
native::scr_stackPtr = reinterpret_cast<native::VariableValue**>(SELECT_VALUE(0x1BF2590, 0x20B4A90, 0x1F5B090));
native::scr_stackEndPtr = reinterpret_cast<native::VariableValue**>(SELECT_VALUE(0x1BF2584, 0x20B4A84, 0x1F5B084));
native::scr_stackEndPtr = reinterpret_cast<native::VariableValue**>( SELECT_VALUE(0x1BF2584, 0x20B4A84,
0x1F5B084
));
native::scr_instanceFunctions = reinterpret_cast<native::scr_call_t*>(SELECT_VALUE(0x184CDB0, 0x1D4F258, 0x1BF59C8));
native::scr_globalFunctions = reinterpret_cast<native::scr_call_t*>(SELECT_VALUE(0x186C68C, 0x1D6EB34, 0x1C152A4));
native::scr_instanceFunctions = reinterpret_cast<native::scr_call_t*>( SELECT_VALUE(0x184CDB0, 0x1D4F258,
0x1BF59C8));
native::scr_globalFunctions = reinterpret_cast<native::scr_call_t*>( SELECT_VALUE(0x186C68C, 0x1D6EB34,
0x1C152A4
));
native::g_script_error_level = reinterpret_cast<int*>(SELECT_VALUE(0x1BEFCFC, 0x20B21FC, 0x1F5B058));
native::g_script_error = reinterpret_cast<jmp_buf*>(SELECT_VALUE(0x1BF1D18, 0x20B4218, 0x1F5A818));

View File

@ -12,7 +12,7 @@ namespace game
typedef void (*Cmd_AddCommand_t)(const char* cmdName, void (*function)(), cmd_function_t* allocedCmd);
extern Cmd_AddCommand_t Cmd_AddCommand;
typedef void (*Com_Error_t)(int code, const char *fmt, ...);
typedef void (*Com_Error_t)(int code, const char* fmt, ...);
extern Com_Error_t Com_Error;
typedef void (*Conbuf_AppendText_t)(const char* message);
@ -24,10 +24,16 @@ namespace game
typedef void (*MSG_ReadData_t)(msg_t* msg, void* data, int len);
extern MSG_ReadData_t MSG_ReadData;
typedef void* (*MT_AllocIndex_t)(int numBytes, int type);
extern MT_AllocIndex_t MT_AllocIndex;
typedef void (*RemoveRefToValue_t)(scriptType_e type, VariableUnion u);
extern RemoveRefToValue_t RemoveRefToValue;
typedef unsigned int (*SL_GetStringOfSize_t)(const char *str, unsigned int user, unsigned int len, int type);
typedef void (*Scr_NotifyId_t)(unsigned int id, unsigned int stringValue, unsigned int paramcount);
extern Scr_NotifyId_t Scr_NotifyId;
typedef unsigned int (*SL_GetStringOfSize_t)(const char* str, unsigned int user, unsigned int len, int type);
extern SL_GetStringOfSize_t SL_GetStringOfSize;
typedef void (*Sys_ShowConsole_t)();
@ -42,6 +48,7 @@ namespace game
extern short* scrVarGlob;
extern char** scrMemTreePub;
extern char* scrMemTreeGlob;
extern unsigned int* scr_numParam;
extern unsigned int* scr_numArgs;
@ -58,12 +65,15 @@ namespace game
void AddRefToValue(VariableValue* value);
void* MT_Alloc(int numBytes, int type);
const float* Scr_AllocVector(const float* v);
void Scr_ClearOutParams();
scr_entref_t Scr_GetEntityIdRef(unsigned int id);
scr_call_t Scr_GetFunc(unsigned int index);
const char* SL_ConvertToString(unsigned int stringValue);
unsigned int SL_GetString(const char *str, unsigned int user);
unsigned int SL_GetString(const char* str, unsigned int user);
}
bool is_mp();

View File

@ -70,6 +70,11 @@ chaiscript::Boxed_Value scripting::entity::call(const std::string& function,
return this->environment_->call(function, this->get_entity_id(), arguments);
}
void scripting::entity::notify(const std::string& event, const std::vector<chaiscript::Boxed_Value>& arguments) const
{
this->environment_->notify(event, this->get_entity_id(), arguments);
}
scripting::variable::variable(game::native::VariableValue value) : value_(value)
{
game::native::AddRefToValue(&value);
@ -187,12 +192,71 @@ void scripting::initialize_entity()
this->chai_->add(chaiscript::user_type<entity>(), "entity");
this->chai_->add(chaiscript::constructor<entity()>(), "entity");
this->chai_->add(chaiscript::constructor<entity(const entity&)>(), "entity");
this->chai_->add(chaiscript::fun(&entity::on_notify), "onNotify");
this->chai_->add(chaiscript::fun([](const entity& ent, const std::string& event,
const std::function<void(const std::vector<chaiscript::Boxed_Value>&)>&
callback)
{
return ent.on_notify(event, callback, false);
}), "onNotify");
this->chai_->add(chaiscript::fun([](entity& lhs, const entity& rhs) -> entity&
{
return lhs = rhs;
}), "=");
this->chai_->add(chaiscript::fun(&entity::notify), "vectorNotify");
this->chai_->add(chaiscript::fun([](const entity& ent, const std::string& event)
{
return ent.notify(event, {});
}), "notify");
this->chai_->add(chaiscript::fun(
[](const entity& ent, const std::string& event,
const chaiscript::Boxed_Value& a1)
{
return ent.notify(event, {a1});
}), "notify");
this->chai_->add(chaiscript::fun(
[](const entity& ent, const std::string& event,
const chaiscript::Boxed_Value& a1,
const chaiscript::Boxed_Value& a2)
{
return ent.notify(event, {a1, a2});
}), "notify");
this->chai_->add(chaiscript::fun(
[](const entity& ent, const std::string& event,
const chaiscript::Boxed_Value& a1,
const chaiscript::Boxed_Value& a2,
const chaiscript::Boxed_Value& a3)
{
return ent.notify(event, {a1, a2, a3});
}), "notify");
this->chai_->add(chaiscript::fun(
[](const entity& ent, const std::string& event,
const chaiscript::Boxed_Value& a1,
const chaiscript::Boxed_Value& a2,
const chaiscript::Boxed_Value& a3,
const chaiscript::Boxed_Value& a4)
{
return ent.notify(event, {a1, a2, a3, a4});
}), "notify");
this->chai_->add(chaiscript::fun(
[](const entity& ent, const std::string& event,
const chaiscript::Boxed_Value& a1,
const chaiscript::Boxed_Value& a2,
const chaiscript::Boxed_Value& a3,
const chaiscript::Boxed_Value& a4,
const chaiscript::Boxed_Value& a5)
{
return ent.notify(event, {a1, a2, a3, a4, a5});
}), "notify");
this->chai_->add(chaiscript::fun(&entity::call), "vectorCall");
this->chai_->add(chaiscript::fun([](const entity& ent, const std::string& function)
{
@ -284,6 +348,15 @@ chaiscript::Boxed_Value scripting::make_boxed(const game::native::VariableValue
{
return chaiscript::var(entity(this, value.u.entityId));
}
else if (value.type == game::native::SCRIPT_VECTOR)
{
std::vector<float> values;
values.push_back(value.u.vectorValue[0]);
values.push_back(value.u.vectorValue[1]);
values.push_back(value.u.vectorValue[2]);
return chaiscript::var(values);
}
return {};
}
@ -338,6 +411,39 @@ void scripting::stop_execution()
}
}
void scripting::notify(const std::string& event, const unsigned int entity_id,
std::vector<chaiscript::Boxed_Value> arguments)
{
const auto old_args = *game::native::scr_numArgs;
const auto old_params = *game::native::scr_numParam;
const auto old_stack_ptr = *game::native::scr_stackPtr;
const auto old_stack_end_ptr = *game::native::scr_stackEndPtr;
game::native::VariableValue stack[512];
*game::native::scr_stackPtr = stack;
*game::native::scr_stackEndPtr = &stack[ARRAYSIZE(stack) - 1];
*game::native::scr_numArgs = 0;
*game::native::scr_numParam = 0;
const auto cleanup = gsl::finally([=]()
{
game::native::Scr_ClearOutParams();
*game::native::scr_numArgs = old_args;
*game::native::scr_numParam = old_params;
*game::native::scr_stackPtr = old_stack_ptr;
*game::native::scr_stackEndPtr = old_stack_end_ptr;
});
std::reverse(arguments.begin(), arguments.end());
for (const auto& argument : arguments)
{
this->push_param(argument);
}
const auto event_id = game::native::SL_GetString(event.data(), 0);
game::native::Scr_NotifyId(entity_id, event_id, *game::native::scr_numArgs);
}
chaiscript::Boxed_Value scripting::call(const std::string& function, const unsigned int entity_id,
std::vector<chaiscript::Boxed_Value> arguments)
{
@ -379,9 +485,6 @@ chaiscript::Boxed_Value scripting::call(const std::string& function, const unsig
this->push_param(argument);
}
*game::native::scr_numParam = *game::native::scr_numArgs;
*game::native::scr_numArgs = 0;
if (!call_safe(function_ptr, entity))
{
throw std::runtime_error("Error executing function '" + function + "'");
@ -477,6 +580,41 @@ void scripting::push_param(const chaiscript::Boxed_Value& value) const
value_ptr->type = game::native::SCRIPT_STRING;
value_ptr->u.stringValue = game::native::SL_GetString(real_value.data(), 0);
}
else if (value.get_type_info() == typeid(std::vector<chaiscript::Boxed_Value>))
{
float values[3];
const auto real_value = this->chai_->boxed_cast<std::vector<chaiscript::Boxed_Value>>(value);
if (real_value.size() != 3)
{
throw std::runtime_error("Invalid vector length. Size must be exactly 3");
}
const auto unbox_float = [&real_value, this](size_t index) -> float
{
const auto value = real_value[index];
if (value.get_type_info() == typeid(float))
{
return this->chai_->boxed_cast<float>(value);
}
else if (value.get_type_info() == typeid(double))
{
return float(this->chai_->boxed_cast<double>(value));
}
else if (value.get_type_info() == typeid(int))
{
return float(this->chai_->boxed_cast<int>(value));
}
throw std::runtime_error("Vector element at index " + std::to_string(index) + " is not a number");
};
values[0] = unbox_float(0);
values[1] = unbox_float(1);
values[2] = unbox_float(2);
value_ptr->type = game::native::SCRIPT_VECTOR;
value_ptr->u.vectorValue = game::native::Scr_AllocVector(values);
}
else
{
throw std::runtime_error("Unable to unbox value of type '" + value.get_type_info().bare_name() + "'");

View File

@ -23,6 +23,7 @@ public:
game::native::scr_entref_t get_entity_reference() const;
chaiscript::Boxed_Value call(const std::string& function, const std::vector<chaiscript::Boxed_Value>& arguments) const;
void notify(const std::string& event, const std::vector<chaiscript::Boxed_Value>& arguments) const;
private:
scripting* environment_;
@ -81,6 +82,8 @@ private:
static void start_execution();
static void stop_execution();
void notify(const std::string& event, unsigned int entity_id, std::vector<chaiscript::Boxed_Value> arguments);
void push_param(const chaiscript::Boxed_Value& value) const;
chaiscript::Boxed_Value get_return_value();
chaiscript::Boxed_Value call(const std::string& function, unsigned int entity_id, std::vector<chaiscript::Boxed_Value> arguments);