Prepare scripting environment
This commit is contained in:
parent
e78dcdf21b
commit
508cc5d51e
@ -13,13 +13,61 @@ namespace game
|
||||
|
||||
MSG_ReadData_t MSG_ReadData;
|
||||
|
||||
RemoveRefToValue_t RemoveRefToValue;
|
||||
|
||||
Sys_ShowConsole_t Sys_ShowConsole;
|
||||
|
||||
VM_Notify_t VM_Notify;
|
||||
|
||||
int* cmd_args;
|
||||
int* cmd_argc;
|
||||
const char*** cmd_argv;
|
||||
}
|
||||
|
||||
short* scrVarGlob;
|
||||
char** scrMemTreePub;
|
||||
|
||||
void AddRefToValue(VariableValue* value)
|
||||
{
|
||||
if (value->type == SCRIPT_OBJECT)
|
||||
{
|
||||
++scrVarGlob[4 * value->u.entityId];
|
||||
}
|
||||
else if (value->type == SCRIPT_STRING)
|
||||
{
|
||||
static const auto size = is_sp() ? 16 : 12;
|
||||
const auto ref_count = reinterpret_cast<unsigned volatile *>(*scrMemTreePub + size * value
|
||||
->u.stringValue);
|
||||
InterlockedIncrement(ref_count);
|
||||
}
|
||||
else if (value->type == SCRIPT_VECTOR)
|
||||
{
|
||||
if (!*PBYTE(value->u.vectorValue - 1))
|
||||
{
|
||||
++*PWORD(value->u.vectorValue - 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scr_entref_t Scr_GetEntityIdRef(const unsigned int id)
|
||||
{
|
||||
static auto class_array = reinterpret_cast<DWORD*>(SELECT_VALUE(0x19AFC84, 0x1E72184, 0x1D3C804));
|
||||
static auto ent_array = reinterpret_cast<WORD*>(SELECT_VALUE(0x19AFC82, 0x1E72182, 0x1D3C802));
|
||||
|
||||
scr_entref_t result{};
|
||||
result.raw.classnum = static_cast<unsigned short>(class_array[2 * id]) >> 8;
|
||||
result.raw.entnum = ent_array[4 * id];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const char* SL_ConvertToString(unsigned int stringValue)
|
||||
{
|
||||
if (!stringValue) return nullptr;
|
||||
|
||||
static const auto size = is_sp() ? 16 : 12;
|
||||
return *scrMemTreePub + size * stringValue + 4;
|
||||
}
|
||||
}
|
||||
|
||||
launcher::mode mode = launcher::mode::none;
|
||||
|
||||
@ -50,10 +98,17 @@ namespace game
|
||||
|
||||
native::MSG_ReadData = native::MSG_ReadData_t(SELECT_VALUE(0, 0x5592A0, 0));
|
||||
|
||||
native::RemoveRefToValue = native::RemoveRefToValue_t(SELECT_VALUE(0x477EA0, 0x565730, 0x4E8A40));
|
||||
|
||||
native::Sys_ShowConsole = native::Sys_ShowConsole_t(SELECT_VALUE(0x470AF0, 0x5CF590, 0));
|
||||
|
||||
native::VM_Notify = native::VM_Notify_t(SELECT_VALUE(0x610200, 0x569720, 0x4EF450));
|
||||
|
||||
native::cmd_args = reinterpret_cast<int*>(SELECT_VALUE(0x1750750, 0x1C978D0, 0x1B455F8));
|
||||
native::cmd_argc = reinterpret_cast<int*>(SELECT_VALUE(0x1750794, 0x1C97914, 0x1B4563C));
|
||||
native::cmd_argv = reinterpret_cast<const char***>(SELECT_VALUE(0x17507B4, 0x1C97934, 0x1B4565C));
|
||||
|
||||
native::scrVarGlob = reinterpret_cast<short*>(SELECT_VALUE(0x19AFC80, 0x1E72180, 0x1D3C800));
|
||||
native::scrMemTreePub = reinterpret_cast<char**>(SELECT_VALUE(0x196FB00, 0x1E32000, 0x1C152A4));
|
||||
}
|
||||
}
|
||||
|
@ -18,15 +18,30 @@ namespace game
|
||||
typedef void (*DB_LoadXAssets_t)(XZoneInfo* zoneInfo, unsigned int zoneCount, int sync);
|
||||
extern DB_LoadXAssets_t DB_LoadXAssets;
|
||||
|
||||
typedef void(*MSG_ReadData_t)(msg_t *msg, void *data, int len);
|
||||
typedef void (*MSG_ReadData_t)(msg_t* msg, void* data, int len);
|
||||
extern MSG_ReadData_t MSG_ReadData;
|
||||
|
||||
typedef void (*RemoveRefToValue_t)(scriptType_e type, VariableUnion u);
|
||||
extern RemoveRefToValue_t RemoveRefToValue;
|
||||
|
||||
typedef void (*Sys_ShowConsole_t)();
|
||||
extern Sys_ShowConsole_t Sys_ShowConsole;
|
||||
|
||||
typedef void (*VM_Notify_t)(unsigned int notifyListOwnerId, unsigned int stringValue, VariableValue* top);
|
||||
extern VM_Notify_t VM_Notify;
|
||||
|
||||
extern int* cmd_args;
|
||||
extern int* cmd_argc;
|
||||
extern const char*** cmd_argv;
|
||||
|
||||
extern short* scrVarGlob;
|
||||
extern char** scrMemTreePub;
|
||||
|
||||
void AddRefToValue(VariableValue* value);
|
||||
|
||||
scr_entref_t Scr_GetEntityIdRef(unsigned int id);
|
||||
|
||||
const char* SL_ConvertToString(unsigned int stringValue);
|
||||
}
|
||||
|
||||
bool is_mp();
|
||||
|
@ -399,5 +399,56 @@ namespace game
|
||||
int allocFlags;
|
||||
int freeFlags;
|
||||
};
|
||||
|
||||
struct scr_entref_raw
|
||||
{
|
||||
unsigned __int16 entnum;
|
||||
unsigned __int16 classnum;
|
||||
};
|
||||
|
||||
union scr_entref_t
|
||||
{
|
||||
unsigned int val;
|
||||
scr_entref_raw raw;
|
||||
};
|
||||
|
||||
enum scriptType_e
|
||||
{
|
||||
SCRIPT_NONE = 0,
|
||||
SCRIPT_OBJECT = 1,
|
||||
SCRIPT_STRING = 2,
|
||||
SCRIPT_VECTOR = 4,
|
||||
SCRIPT_FLOAT = 5,
|
||||
SCRIPT_INTEGER = 6,
|
||||
SCRIPT_END = 8, // Custom
|
||||
};
|
||||
|
||||
struct VariableStackBuffer
|
||||
{
|
||||
const char* pos;
|
||||
unsigned __int16 size;
|
||||
unsigned __int16 bufLen;
|
||||
unsigned __int16 localId;
|
||||
char time;
|
||||
char buf[1];
|
||||
};
|
||||
|
||||
union VariableUnion
|
||||
{
|
||||
int intValue;
|
||||
float floatValue;
|
||||
unsigned int stringValue;
|
||||
const float* vectorValue;
|
||||
const char* codePosValue;
|
||||
unsigned int pointerValue;
|
||||
VariableStackBuffer* stackValue;
|
||||
unsigned int entityId;
|
||||
};
|
||||
|
||||
struct VariableValue
|
||||
{
|
||||
VariableUnion u;
|
||||
scriptType_e type;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
37
src/module/notification.cpp
Normal file
37
src/module/notification.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/module_loader.hpp"
|
||||
#include "notification.hpp"
|
||||
#include "utils/hook.hpp"
|
||||
|
||||
void notification::post_load()
|
||||
{
|
||||
utils::hook(SELECT_VALUE(0x6109F3, 0x56B637, 0x4EDFF7), vm_notify_stub, HOOK_CALL).install()->quick();
|
||||
utils::hook(SELECT_VALUE(0x6128BE, 0x56D541, 0x4EFAF9), vm_notify_stub, HOOK_CALL).install()->quick();
|
||||
|
||||
if (game::is_sp())
|
||||
{
|
||||
utils::hook(0x610970, vm_notify_stub, HOOK_JUMP).install()->quick();
|
||||
}
|
||||
}
|
||||
|
||||
void notification::vm_notify_stub(const unsigned int notify_id, const unsigned short type,
|
||||
game::native::VariableValue* stack)
|
||||
{
|
||||
event e;
|
||||
e.name = game::native::SL_ConvertToString(type);
|
||||
e.entity = game::native::Scr_GetEntityIdRef(notify_id);
|
||||
|
||||
for (auto value = stack; value->type != game::native::SCRIPT_END; --value)
|
||||
{
|
||||
e.arguments.emplace_back(*value);
|
||||
}
|
||||
|
||||
if(!e.arguments.empty())
|
||||
{
|
||||
printf("");
|
||||
}
|
||||
|
||||
game::native::VM_Notify(notify_id, type, stack);
|
||||
}
|
||||
|
||||
REGISTER_MODULE(notification)
|
20
src/module/notification.hpp
Normal file
20
src/module/notification.hpp
Normal file
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
#include "loader/module_loader.hpp"
|
||||
#include "scripting.hpp"
|
||||
|
||||
class notification final : public module
|
||||
{
|
||||
public:
|
||||
class event final
|
||||
{
|
||||
public:
|
||||
std::string name;
|
||||
game::native::scr_entref_t entity;
|
||||
std::vector<scripting::variable> arguments;
|
||||
};
|
||||
|
||||
void post_load() override;
|
||||
|
||||
private:
|
||||
static void vm_notify_stub(unsigned int notify_id, unsigned short type, game::native::VariableValue* stack);
|
||||
};
|
@ -1,26 +1,101 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/module_loader.hpp"
|
||||
#include "game/game.hpp"
|
||||
#include "scripting.hpp"
|
||||
|
||||
class scripting final : public module
|
||||
utils::hook scripting::start_hook_;
|
||||
utils::hook scripting::stop_hook_;
|
||||
|
||||
std::mutex scripting::mutex_;
|
||||
std::vector<std::function<void()>> scripting::start_callbacks_;
|
||||
std::vector<std::function<void()>> scripting::stop_callbacks_;
|
||||
|
||||
scripting::variable::variable(game::native::VariableValue value) : value_(value)
|
||||
{
|
||||
public:
|
||||
void post_load() override
|
||||
{
|
||||
this->chai_.add(chaiscript::fun(&function), "function");
|
||||
game::native::AddRefToValue(&value);
|
||||
}
|
||||
|
||||
double d = this->chai_.eval<double>("function(3, 4.75);");
|
||||
printf("Result: %f", d);
|
||||
scripting::variable::~variable()
|
||||
{
|
||||
game::native::RemoveRefToValue(this->value_.type, this->value_.u);
|
||||
}
|
||||
|
||||
scripting::variable::operator game::native::VariableValue() const
|
||||
{
|
||||
return this->value_;
|
||||
}
|
||||
|
||||
void scripting::post_load()
|
||||
{
|
||||
start_hook_.initialize(SELECT_VALUE(0x50C575, 0x50D4F2, 0x48A026), []()
|
||||
{
|
||||
start_execution();
|
||||
static_cast<void(*)()>(start_hook_.get_original())();
|
||||
}, HOOK_CALL)->install()->quick();
|
||||
|
||||
stop_hook_.initialize(SELECT_VALUE(0x528B04, 0x569E46, 0x4F03FA), []()
|
||||
{
|
||||
stop_execution();
|
||||
static_cast<void(*)()>(stop_hook_.get_original())();
|
||||
}, HOOK_CALL)->install()->quick();
|
||||
|
||||
on_start([this]()
|
||||
{
|
||||
this->chai_ = std::make_unique<chaiscript::ChaiScript>();
|
||||
});
|
||||
|
||||
on_stop([this]()
|
||||
{
|
||||
this->chai_ = {};
|
||||
});
|
||||
}
|
||||
|
||||
void scripting::pre_destroy()
|
||||
{
|
||||
this->chai_ = {};
|
||||
start_callbacks_.clear();
|
||||
stop_callbacks_.clear();
|
||||
}
|
||||
|
||||
void scripting::on_start(const std::function<void()>& callback)
|
||||
{
|
||||
std::lock_guard _(mutex_);
|
||||
start_callbacks_.push_back(callback);
|
||||
}
|
||||
|
||||
void scripting::on_stop(const std::function<void()>& callback)
|
||||
{
|
||||
std::lock_guard _(mutex_);
|
||||
stop_callbacks_.push_back(callback);
|
||||
}
|
||||
|
||||
void scripting::start_execution()
|
||||
{
|
||||
std::vector<std::function<void()>> copy;
|
||||
|
||||
{
|
||||
std::lock_guard _(mutex_);
|
||||
copy = start_callbacks_;
|
||||
}
|
||||
|
||||
private:
|
||||
chaiscript::ChaiScript chai_;
|
||||
|
||||
static double function(int i, double j)
|
||||
for (const auto& callback : copy)
|
||||
{
|
||||
return i * j;
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
void scripting::stop_execution()
|
||||
{
|
||||
std::vector<std::function<void()>> copy;
|
||||
|
||||
{
|
||||
std::lock_guard _(mutex_);
|
||||
copy = stop_callbacks_;
|
||||
}
|
||||
|
||||
};
|
||||
for (const auto& callback : copy)
|
||||
{
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
REGISTER_MODULE(scripting)
|
||||
|
39
src/module/scripting.hpp
Normal file
39
src/module/scripting.hpp
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
#include "loader/module_loader.hpp"
|
||||
#include "game/game.hpp"
|
||||
#include "utils/hook.hpp"
|
||||
|
||||
class scripting final : public module
|
||||
{
|
||||
public:
|
||||
class variable final
|
||||
{
|
||||
public:
|
||||
variable(game::native::VariableValue value);
|
||||
~variable();
|
||||
|
||||
operator game::native::VariableValue() const;
|
||||
|
||||
private:
|
||||
game::native::VariableValue value_;
|
||||
};
|
||||
|
||||
void post_load() override;
|
||||
void pre_destroy() override;
|
||||
|
||||
static void on_start(const std::function<void()>& callback);
|
||||
static void on_stop(const std::function<void()>& callback);
|
||||
|
||||
private:
|
||||
std::unique_ptr<chaiscript::ChaiScript> chai_;
|
||||
|
||||
static utils::hook start_hook_;
|
||||
static utils::hook stop_hook_;
|
||||
|
||||
static std::mutex mutex_;
|
||||
static std::vector<std::function<void()>> start_callbacks_;
|
||||
static std::vector<std::function<void()>> stop_callbacks_;
|
||||
|
||||
static void start_execution();
|
||||
static void stop_execution();
|
||||
};
|
@ -156,6 +156,11 @@ namespace utils
|
||||
return this->place_;
|
||||
}
|
||||
|
||||
void* hook::get_original() const
|
||||
{
|
||||
return this->original_;
|
||||
}
|
||||
|
||||
void hook::nop(void* place, const size_t length)
|
||||
{
|
||||
DWORD old_protect;
|
||||
|
@ -80,6 +80,7 @@ namespace utils
|
||||
hook* uninstall(bool unprotect = true);
|
||||
|
||||
void* get_address() const;
|
||||
void* get_original() const;
|
||||
void quick();
|
||||
|
||||
static bool iat(nt::module module, const std::string& target_module, const std::string& process, void* stub);
|
||||
|
Loading…
Reference in New Issue
Block a user