整理初版
This commit is contained in:
385
src/script/SqrReg_ActiveHook.hpp
Normal file
385
src/script/SqrReg_ActiveHook.hpp
Normal file
@@ -0,0 +1,385 @@
|
||||
#pragma once
|
||||
#include "frida-gum.h"
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include "squirrel.h"
|
||||
#include "sqstdaux.h"
|
||||
#include "sqstdblob.h"
|
||||
#include "sqstdio.h"
|
||||
#include "sqstdmath.h"
|
||||
#include "sqstdstring.h"
|
||||
#include "sqstdsystem.h"
|
||||
#include <mutex>
|
||||
#include <iostream>
|
||||
|
||||
extern HSQUIRRELVM v;
|
||||
extern std::recursive_mutex SqMtx;
|
||||
|
||||
#define CONTAINS_STRING(str, substr) (str == substr)
|
||||
|
||||
typedef struct {
|
||||
const SQChar* name;
|
||||
size_t offset;
|
||||
} CpuContextMember;
|
||||
|
||||
// HookFunc
|
||||
struct _ExampleListener
|
||||
{
|
||||
GObject parent;
|
||||
guint num_calls;
|
||||
std::vector<std::string> ArgumentCount;
|
||||
std::string RetType;
|
||||
HSQOBJECT CallBackOnEnter;
|
||||
HSQOBJECT CallBackOnLeave;
|
||||
SQUserPointer FuncAddress;
|
||||
};
|
||||
enum _ExampleHookId
|
||||
{
|
||||
EXAMPLE_HOOK_OPEN,
|
||||
EXAMPLE_HOOK_CLOSE
|
||||
};
|
||||
typedef struct _ExampleListener ExampleListener;
|
||||
typedef enum _ExampleHookId ExampleHookId;
|
||||
|
||||
static void example_listener_iface_init(gpointer g_iface, gpointer iface_data);
|
||||
|
||||
static GumInterceptor* interceptor;
|
||||
|
||||
static std::thread::id Zhuxianc = std::this_thread::get_id();
|
||||
|
||||
#define EXAMPLE_TYPE_LISTENER (example_listener_get_type())
|
||||
G_DECLARE_FINAL_TYPE(ExampleListener, example_listener, EXAMPLE, LISTENER, GObject)
|
||||
G_DEFINE_TYPE_EXTENDED(ExampleListener, example_listener, G_TYPE_OBJECT, 0, G_IMPLEMENT_INTERFACE(GUM_TYPE_INVOCATION_LISTENER, example_listener_iface_init))
|
||||
|
||||
// 自定义替换函数
|
||||
static void replacement_function(GumInvocationContext* context)
|
||||
{
|
||||
// 在这里执行你的逻辑
|
||||
// gum_print("自定义逻辑已执行!\n");
|
||||
// 跳过原函数,直接返回
|
||||
// 如果需要修改返回值,可以通过 context->cpu_context 修改寄存器
|
||||
}
|
||||
|
||||
static SQInteger L_HookFunc(HSQUIRRELVM v)
|
||||
{
|
||||
static bool InitFlag = false;
|
||||
if (!InitFlag)
|
||||
{
|
||||
InitFlag = true;
|
||||
|
||||
gum_init_embedded();
|
||||
|
||||
interceptor = gum_interceptor_obtain();
|
||||
}
|
||||
|
||||
GumInvocationListener* listener = (GumInvocationListener*)g_object_new(EXAMPLE_TYPE_LISTENER, NULL);
|
||||
// 得到函数地址
|
||||
SQUserPointer FuncAddress;
|
||||
sq_getuserpointer(v, 2, &FuncAddress);
|
||||
|
||||
// 遍历参数类型数组
|
||||
std::vector<std::string> ParameterType;
|
||||
sq_pushnull(v); // null iterator
|
||||
while (SQ_SUCCEEDED(sq_next(v, 3)))
|
||||
{
|
||||
const SQChar* path;
|
||||
sq_getstring(v, -1, &path);
|
||||
ParameterType.push_back(path);
|
||||
sq_pop(v, 2);
|
||||
}
|
||||
sq_pop(v, 1);
|
||||
|
||||
// 得到入口回调函数
|
||||
HSQOBJECT CallBackOnEnter;
|
||||
sq_getstackobj(v, 4, &CallBackOnEnter);
|
||||
// 必须增加一次引用一会记得删除 不然这个函数会被释放
|
||||
sq_addref(v, &CallBackOnEnter);
|
||||
|
||||
// 得到出口回调函数
|
||||
HSQOBJECT CallBackOnLeave;
|
||||
sq_getstackobj(v, 5, &CallBackOnLeave);
|
||||
// 必须增加一次引用一会记得删除 不然这个函数会被释放
|
||||
sq_addref(v, &CallBackOnLeave);
|
||||
|
||||
EXAMPLE_LISTENER(listener)->ArgumentCount = ParameterType;
|
||||
// EXAMPLE_LISTENER(listener)->RetType = std::string(RetBuf);
|
||||
EXAMPLE_LISTENER(listener)->CallBackOnEnter = CallBackOnEnter;
|
||||
EXAMPLE_LISTENER(listener)->CallBackOnLeave = CallBackOnLeave;
|
||||
EXAMPLE_LISTENER(listener)->FuncAddress = FuncAddress;
|
||||
|
||||
gum_interceptor_begin_transaction(interceptor);
|
||||
gum_interceptor_attach(interceptor, GSIZE_TO_POINTER(FuncAddress), listener, GSIZE_TO_POINTER(FuncAddress));
|
||||
gum_interceptor_end_transaction(interceptor);
|
||||
|
||||
sq_pushuserpointer(v, listener);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static SQInteger L_DeHookFunc(HSQUIRRELVM v)
|
||||
{
|
||||
// 得到函数地址
|
||||
SQUserPointer FuncAddress;
|
||||
sq_getuserpointer(v, 2, &FuncAddress);
|
||||
|
||||
GumInvocationListener* listener = (GumInvocationListener*)FuncAddress;
|
||||
gum_interceptor_detach(interceptor, listener);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void example_listener_on_enter(GumInvocationListener* listener, GumInvocationContext* ic)
|
||||
{
|
||||
|
||||
gpointer ReturnAddress = gum_invocation_context_get_return_address(ic);
|
||||
ExampleListener* self = EXAMPLE_LISTENER(listener);
|
||||
|
||||
// std::cout << "调用点: " << self->FuncAddress << std::endl;
|
||||
|
||||
std::lock_guard<std::recursive_mutex> lock(SqMtx);
|
||||
// 执行虚拟机Main函数
|
||||
SQInteger top = sq_gettop(v); // saves the stack size before the call
|
||||
|
||||
//传入返回地址
|
||||
sq_pushroottable(v);
|
||||
sq_pushstring(v, _SC("_Haker_SetNextReturnAddress"), -1);
|
||||
if (SQ_SUCCEEDED(sq_get(v, -2)))
|
||||
{
|
||||
sq_pushroottable(v);
|
||||
sq_pushuserpointer(v, ReturnAddress);
|
||||
sq_call(v, 2, SQFalse, SQTrue);
|
||||
}
|
||||
sq_settop(v, top);
|
||||
|
||||
//传入CPU上下文
|
||||
sq_pushroottable(v);
|
||||
sq_pushstring(v, _SC("_Haker_SetCpuContext"), -1);
|
||||
if (SQ_SUCCEEDED(sq_get(v, -2)))
|
||||
{
|
||||
sq_pushroottable(v);
|
||||
sq_newtable(v);
|
||||
struct TableEntry
|
||||
{
|
||||
const SQChar* key;
|
||||
SQUserPointer value;
|
||||
} entries[] = {
|
||||
{_SC("eip"), (SQUserPointer)ic->cpu_context->eip},
|
||||
{_SC("edi"), (SQUserPointer)ic->cpu_context->edi},
|
||||
{_SC("esi"), (SQUserPointer)ic->cpu_context->esi},
|
||||
{_SC("ebp"), (SQUserPointer)ic->cpu_context->ebp},
|
||||
{_SC("esp"), (SQUserPointer)ic->cpu_context->esp},
|
||||
{_SC("ebx"), (SQUserPointer)ic->cpu_context->ebx},
|
||||
{_SC("edx"), (SQUserPointer)ic->cpu_context->edx},
|
||||
{_SC("ecx"), (SQUserPointer)ic->cpu_context->ecx},
|
||||
{_SC("eax"), (SQUserPointer)ic->cpu_context->eax},
|
||||
};
|
||||
|
||||
for (const auto& entry : entries)
|
||||
{
|
||||
sq_pushstring(v, entry.key, -1);
|
||||
sq_pushuserpointer(v, entry.value);
|
||||
sq_newslot(v, -3, SQFalse);
|
||||
}
|
||||
sq_call(v, 2, SQFalse, SQTrue);
|
||||
}
|
||||
sq_settop(v, top);
|
||||
|
||||
|
||||
|
||||
sq_pushobject(v, self->CallBackOnEnter);
|
||||
sq_pushroottable(v);
|
||||
sq_newarray(v, 0);
|
||||
for (size_t i = 0; i < self->ArgumentCount.size() - 1; i++)
|
||||
{
|
||||
void* Abuf = gum_invocation_context_get_nth_argument(ic, i);
|
||||
|
||||
if (CONTAINS_STRING(self->ArgumentCount[i], "int"))
|
||||
sq_pushinteger(v, (int)Abuf);
|
||||
else if (CONTAINS_STRING(self->ArgumentCount[i], "float"))
|
||||
{
|
||||
SQFloat* a = reinterpret_cast<float*>(&Abuf);
|
||||
sq_pushfloat(v, *(SQFloat*)a);
|
||||
}
|
||||
else if (CONTAINS_STRING(self->ArgumentCount[i], "bool"))
|
||||
sq_pushbool(v, (bool)Abuf);
|
||||
else if (CONTAINS_STRING(self->ArgumentCount[i], "string"))
|
||||
sq_pushstring(v, (char*)Abuf, -1);
|
||||
else if (CONTAINS_STRING(self->ArgumentCount[i], "pointer"))
|
||||
sq_pushuserpointer(v, (void*)Abuf);
|
||||
else if (CONTAINS_STRING(self->ArgumentCount[i], "short"))
|
||||
sq_pushinteger(v, (int)Abuf);
|
||||
else if (CONTAINS_STRING(self->ArgumentCount[i], "char"))
|
||||
sq_pushinteger(v, (int)Abuf);
|
||||
else
|
||||
sq_pushuserpointer(v, (void*)Abuf);
|
||||
sq_arrayappend(v, -2);
|
||||
}
|
||||
sq_call(v, 2, SQTrue, SQTrue); // calls the function
|
||||
if (sq_gettype(v, -1) == OT_ARRAY)
|
||||
{
|
||||
sq_pushnull(v); // null iterator
|
||||
int Idx = 0;
|
||||
while (SQ_SUCCEEDED(sq_next(v, -2)))
|
||||
{
|
||||
if (CONTAINS_STRING(self->ArgumentCount[Idx], "int"))
|
||||
{
|
||||
SQInteger Abuf;
|
||||
sq_getinteger(v, -1, &Abuf);
|
||||
gum_invocation_context_replace_nth_argument(ic, Idx, (void*)Abuf);
|
||||
}
|
||||
else if (CONTAINS_STRING(self->ArgumentCount[Idx], "float"))
|
||||
{
|
||||
SQFloat Abuf;
|
||||
sq_getfloat(v, -1, &Abuf);
|
||||
gum_invocation_context_replace_nth_argument(ic, Idx, &Abuf);
|
||||
}
|
||||
else if (CONTAINS_STRING(self->ArgumentCount[Idx], "bool"))
|
||||
{
|
||||
SQBool Abuf;
|
||||
sq_getbool(v, -1, &Abuf);
|
||||
gum_invocation_context_replace_nth_argument(ic, Idx, (void*)Abuf);
|
||||
}
|
||||
else if (CONTAINS_STRING(self->ArgumentCount[Idx], "string"))
|
||||
{
|
||||
const SQChar* Abuf;
|
||||
sq_getstring(v, -1, &Abuf);
|
||||
gum_invocation_context_replace_nth_argument(ic, Idx, (void*)Abuf);
|
||||
}
|
||||
else if (CONTAINS_STRING(self->ArgumentCount[Idx], "pointer"))
|
||||
{
|
||||
SQUserPointer Abuf;
|
||||
sq_getuserpointer(v, -1, &Abuf);
|
||||
gum_invocation_context_replace_nth_argument(ic, Idx, (void*)Abuf);
|
||||
}
|
||||
else if (CONTAINS_STRING(self->ArgumentCount[Idx], "short"))
|
||||
{
|
||||
SQInteger Abuf;
|
||||
sq_getinteger(v, -1, &Abuf);
|
||||
gum_invocation_context_replace_nth_argument(ic, Idx, (void*)Abuf);
|
||||
}
|
||||
else if (CONTAINS_STRING(self->ArgumentCount[Idx], "char"))
|
||||
{
|
||||
SQInteger Abuf;
|
||||
sq_getinteger(v, -1, &Abuf);
|
||||
char CBUF = Abuf;
|
||||
gum_invocation_context_replace_nth_argument(ic, Idx, (void*)CBUF);
|
||||
}
|
||||
Idx++;
|
||||
sq_pop(v, 2);
|
||||
}
|
||||
sq_pop(v, 1);
|
||||
sq_settop(v, top); // restores the original stack size
|
||||
return;
|
||||
}
|
||||
sq_settop(v, top); // restores the original stack size
|
||||
return;
|
||||
}
|
||||
static void example_listener_on_leave(GumInvocationListener* listener, GumInvocationContext* ic)
|
||||
{
|
||||
ExampleListener* self = EXAMPLE_LISTENER(listener);
|
||||
|
||||
std::lock_guard<std::recursive_mutex> lock(SqMtx);
|
||||
// 执行虚拟机Main函数
|
||||
SQInteger top = sq_gettop(v); // saves the stack size before the call
|
||||
sq_pushobject(v, self->CallBackOnLeave);
|
||||
sq_pushroottable(v);
|
||||
sq_newarray(v, 0);
|
||||
for (size_t i = 0; i < self->ArgumentCount.size(); i++)
|
||||
{
|
||||
void* Abuf;
|
||||
|
||||
if (i == (self->ArgumentCount.size() - 1))
|
||||
Abuf = gum_invocation_context_get_return_value(ic);
|
||||
else
|
||||
Abuf = gum_invocation_context_get_nth_argument(ic, i);
|
||||
|
||||
if (CONTAINS_STRING(self->ArgumentCount[i], "int"))
|
||||
sq_pushinteger(v, (int)Abuf);
|
||||
else if (CONTAINS_STRING(self->ArgumentCount[i], "float"))
|
||||
{
|
||||
SQFloat* a = reinterpret_cast<float*>(&Abuf);
|
||||
sq_pushfloat(v, *(SQFloat*)a);
|
||||
}
|
||||
else if (CONTAINS_STRING(self->ArgumentCount[i], "bool"))
|
||||
sq_pushbool(v, (bool)Abuf);
|
||||
else if (CONTAINS_STRING(self->ArgumentCount[i], "string"))
|
||||
sq_pushstring(v, (char*)Abuf, -1);
|
||||
else if (CONTAINS_STRING(self->ArgumentCount[i], "pointer"))
|
||||
sq_pushuserpointer(v, (void*)Abuf);
|
||||
else if (CONTAINS_STRING(self->ArgumentCount[i], "short"))
|
||||
sq_pushinteger(v, (int)Abuf);
|
||||
else if (CONTAINS_STRING(self->ArgumentCount[i], "char"))
|
||||
sq_pushinteger(v, (int)Abuf);
|
||||
else
|
||||
sq_pushuserpointer(v, (void*)Abuf);
|
||||
sq_arrayappend(v, -2);
|
||||
}
|
||||
sq_call(v, 2, SQTrue, SQTrue); // calls the function
|
||||
if (sq_gettype(v, -1) != OT_NULL)
|
||||
{
|
||||
if (CONTAINS_STRING(self->ArgumentCount.back(), "int"))
|
||||
{
|
||||
SQInteger Abuf;
|
||||
sq_getinteger(v, -1, &Abuf);
|
||||
gum_invocation_context_replace_return_value(ic, (void*)Abuf);
|
||||
}
|
||||
else if (CONTAINS_STRING(self->ArgumentCount.back(), "float"))
|
||||
{
|
||||
SQFloat Abuf;
|
||||
sq_getfloat(v, -1, &Abuf);
|
||||
gum_invocation_context_replace_return_value(ic, &Abuf);
|
||||
}
|
||||
else if (CONTAINS_STRING(self->ArgumentCount.back(), "bool"))
|
||||
{
|
||||
SQBool Abuf;
|
||||
sq_getbool(v, -1, &Abuf);
|
||||
gum_invocation_context_replace_return_value(ic, (void*)Abuf);
|
||||
}
|
||||
else if (CONTAINS_STRING(self->ArgumentCount.back(), "string"))
|
||||
{
|
||||
const SQChar* Abuf;
|
||||
sq_getstring(v, -1, &Abuf);
|
||||
gum_invocation_context_replace_return_value(ic, (void*)Abuf);
|
||||
}
|
||||
else if (CONTAINS_STRING(self->ArgumentCount.back(), "pointer"))
|
||||
{
|
||||
SQUserPointer Abuf;
|
||||
sq_getuserpointer(v, -1, &Abuf);
|
||||
gum_invocation_context_replace_return_value(ic, (void*)Abuf);
|
||||
}
|
||||
else if (CONTAINS_STRING(self->ArgumentCount.back(), "short"))
|
||||
{
|
||||
SQInteger Abuf;
|
||||
sq_getinteger(v, -1, &Abuf);
|
||||
gum_invocation_context_replace_return_value(ic, (void*)Abuf);
|
||||
}
|
||||
else if (CONTAINS_STRING(self->ArgumentCount.back(), "char"))
|
||||
{
|
||||
SQInteger Abuf;
|
||||
sq_getinteger(v, -1, &Abuf);
|
||||
char CBUF = Abuf;
|
||||
gum_invocation_context_replace_return_value(ic, (void*)Abuf);
|
||||
}
|
||||
}
|
||||
sq_settop(v, top);
|
||||
}
|
||||
static void example_listener_class_init(ExampleListenerClass* klass)
|
||||
{
|
||||
(void)EXAMPLE_IS_LISTENER;
|
||||
(void)glib_autoptr_cleanup_ExampleListener;
|
||||
}
|
||||
static void example_listener_iface_init(gpointer g_iface, gpointer iface_data)
|
||||
{
|
||||
GumInvocationListenerInterface* iface = (GumInvocationListenerInterface*)g_iface;
|
||||
iface->on_enter = example_listener_on_enter;
|
||||
iface->on_leave = example_listener_on_leave;
|
||||
}
|
||||
static void example_listener_init(ExampleListener* self)
|
||||
{
|
||||
}
|
||||
|
||||
static void RegisterActiveHook(HSQUIRRELVM v)
|
||||
{
|
||||
register_World_func(v, L_HookFunc, _SC("Sq_HookFunc"));
|
||||
register_World_func(v, L_DeHookFunc, _SC("Sq_DeHookFunc"));
|
||||
}
|
||||
102
src/script/SqrReg_Asset.hpp
Normal file
102
src/script/SqrReg_Asset.hpp
Normal file
@@ -0,0 +1,102 @@
|
||||
#pragma once
|
||||
#include "PVF_IO.hpp"
|
||||
|
||||
static SQInteger Asset_LoadScript(HSQUIRRELVM v)
|
||||
{
|
||||
// 获得路径
|
||||
const SQChar *Path;
|
||||
sq_getstring(v, 2, &Path);
|
||||
|
||||
PVF_IO *pvf = new PVF_IO(Path);
|
||||
pvf->Init();
|
||||
sq_pushuserpointer(v, pvf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static SQInteger Asset_GetPvfFileSize(HSQUIRRELVM v)
|
||||
{
|
||||
// 获取PVF指针
|
||||
SQUserPointer Pvfbuf;
|
||||
// 获得路径
|
||||
const SQChar *Path;
|
||||
sq_getuserpointer(v, 2, &Pvfbuf);
|
||||
sq_getstring(v, 3, &Path);
|
||||
|
||||
PVF_IO *Pvf = (PVF_IO *)Pvfbuf;
|
||||
auto Info = Pvf->GetFileInfo(Path);
|
||||
if (Info)
|
||||
sq_pushinteger(v, Info->Length);
|
||||
else
|
||||
sq_pushnull(v);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static SQInteger Asset_GetPvfFile(HSQUIRRELVM v)
|
||||
{
|
||||
// 获取PVF指针
|
||||
SQUserPointer Pvfbuf, blobp;
|
||||
// 获得路径
|
||||
const SQChar *Path;
|
||||
sq_getuserpointer(v, 2, &Pvfbuf);
|
||||
sq_getstring(v, 3, &Path);
|
||||
sqstd_getblob(v, 4, &blobp);
|
||||
|
||||
PVF_IO *Pvf = (PVF_IO *)Pvfbuf;
|
||||
Pvf->LoadFileToBlob(v, Path, blobp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SQInteger Asset_GetPvfBinString(HSQUIRRELVM v)
|
||||
{
|
||||
// 获取PVF指针
|
||||
SQUserPointer Pvfbuf;
|
||||
// 获得Key
|
||||
SQInteger Key;
|
||||
sq_getuserpointer(v, 2, &Pvfbuf);
|
||||
sq_getinteger(v, 3, &Key);
|
||||
|
||||
PVF_IO *Pvf = (PVF_IO *)Pvfbuf;
|
||||
std::string value = Pvf->GetBinString(Key);
|
||||
|
||||
sq_pushstring(v, value.c_str(), value.length());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static SQInteger Asset_GetPvfLoadString(HSQUIRRELVM v)
|
||||
{
|
||||
// 获取PVF指针
|
||||
SQUserPointer Pvfbuf;
|
||||
// 获取类型
|
||||
const SQChar *Type;
|
||||
// 获得Key
|
||||
const SQChar *Key;
|
||||
sq_getuserpointer(v, 2, &Pvfbuf);
|
||||
sq_getstring(v, 3, &Type);
|
||||
sq_getstring(v, 4, &Key);
|
||||
|
||||
PVF_IO *Pvf = (PVF_IO *)Pvfbuf;
|
||||
|
||||
std::string value = Pvf->GetLoadString(Type, Key);
|
||||
value = value.c_str();
|
||||
|
||||
sq_pushstring(v, value.c_str(), value.length());
|
||||
return 1;
|
||||
}
|
||||
|
||||
void RegisterAssetNutApi(const SQChar *funcName, SQFUNCTION funcAddr, HSQUIRRELVM v)
|
||||
{
|
||||
sq_pushroottable(v);
|
||||
sq_pushstring(v, funcName, -1);
|
||||
sq_newclosure(v, funcAddr, 0);
|
||||
sq_newslot(v, -3, false);
|
||||
sq_poptop(v);
|
||||
}
|
||||
|
||||
void RegisterAsset(HSQUIRRELVM v)
|
||||
{
|
||||
RegisterAssetNutApi(_SC("Asset_LoadScript"), Asset_LoadScript, v);
|
||||
RegisterAssetNutApi(_SC("Asset_GetPvfFileSize"), Asset_GetPvfFileSize, v);
|
||||
RegisterAssetNutApi(_SC("Asset_GetPvfFile"), Asset_GetPvfFile, v);
|
||||
RegisterAssetNutApi(_SC("Asset_GetPvfBinString"), Asset_GetPvfBinString, v);
|
||||
RegisterAssetNutApi(_SC("Asset_GetPvfLoadString"), Asset_GetPvfLoadString, v);
|
||||
}
|
||||
52
src/script/SqrReg_Battle_Field.hpp
Normal file
52
src/script/SqrReg_Battle_Field.hpp
Normal file
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
#include "squirrel.h"
|
||||
#include "sqstdaux.h"
|
||||
#include "sqstdblob.h"
|
||||
#include "sqstdio.h"
|
||||
#include "sqstdmath.h"
|
||||
#include "sqstdstring.h"
|
||||
#include "sqstdsystem.h"
|
||||
#include <iostream>
|
||||
|
||||
template <typename R, typename A, typename... ARG>
|
||||
R CallBattleField(A call_addr, const ARG... arguments)
|
||||
{
|
||||
if (!call_addr)
|
||||
{
|
||||
return R();
|
||||
}
|
||||
const auto control = reinterpret_cast<R (*)(ARG...)>(call_addr);
|
||||
try
|
||||
{
|
||||
return control(arguments...);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
return R();
|
||||
}
|
||||
|
||||
// 获取副本对象
|
||||
static SQInteger BattleField_GetDgn(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQUserPointer B = CallBattleField<void *>(0x80FDCFC, P);
|
||||
sq_pushuserpointer(v, B);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static SQInteger register_BattleField_func(HSQUIRRELVM v, SQFUNCTION f, const char *fname)
|
||||
{
|
||||
sq_pushroottable(v);
|
||||
sq_pushstring(v, fname, -1);
|
||||
sq_newclosure(v, f, 0); // create a new function
|
||||
sq_newslot(v, -3, SQFalse);
|
||||
sq_pop(v, 1); // pops the root table
|
||||
}
|
||||
|
||||
static void RegisterBattleField(HSQUIRRELVM v)
|
||||
{
|
||||
// 获取副本对象
|
||||
register_BattleField_func(v, BattleField_GetDgn, _SC("Sq_BattleField_GetDgn"));
|
||||
}
|
||||
547
src/script/SqrReg_Dio.hpp
Normal file
547
src/script/SqrReg_Dio.hpp
Normal file
@@ -0,0 +1,547 @@
|
||||
#pragma once
|
||||
#include "squirrel.h"
|
||||
#include "sqstdaux.h"
|
||||
#include "sqstdblob.h"
|
||||
#include "sqstdio.h"
|
||||
#include "sqstdmath.h"
|
||||
#include "sqstdstring.h"
|
||||
#include "sqstdsystem.h"
|
||||
#include <asio.hpp>
|
||||
#include <asio/ssl.hpp>
|
||||
#include <asio/basic_socket_streambuf.hpp>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <unordered_map>
|
||||
#include <mutex>
|
||||
#include <memory> // 新增:用于 std::unique_ptr
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <stdint.h>
|
||||
|
||||
// 全局变量声明(需在cpp文件中定义)
|
||||
extern HSQUIRRELVM v;
|
||||
extern std::recursive_mutex SqMtx;
|
||||
|
||||
using tcp = asio::ip::tcp;
|
||||
|
||||
// ====================== 工具函数 ======================
|
||||
// 字符串转小写
|
||||
std::string to_lower(std::string s) {
|
||||
std::transform(s.begin(), s.end(), s.begin(),
|
||||
[](unsigned char c) { return std::tolower(c); });
|
||||
return s;
|
||||
}
|
||||
|
||||
// 修剪字符串两端空格
|
||||
std::string trim(std::string s) {
|
||||
s.erase(s.begin(), std::find_if(s.begin(), s.end(),
|
||||
[](unsigned char c) { return !std::isspace(c); }));
|
||||
s.erase(std::find_if(s.rbegin(), s.rend(),
|
||||
[](unsigned char c) { return !std::isspace(c); }).base(), s.end());
|
||||
return s;
|
||||
}
|
||||
|
||||
// 解析 URL,分离路径和查询参数
|
||||
void parse_url(const std::string& url, std::string& path, std::string& query) {
|
||||
size_t query_pos = url.find('?');
|
||||
if (query_pos == std::string::npos) {
|
||||
path = url;
|
||||
query = "";
|
||||
}
|
||||
else {
|
||||
path = url.substr(0, query_pos);
|
||||
query = url.substr(query_pos + 1);
|
||||
}
|
||||
}
|
||||
|
||||
// ====================== HTTP 头解析结构体 ======================
|
||||
struct HttpRequestHeader {
|
||||
std::string method; // GET/POST/PUT/DELETE 等
|
||||
std::string path; // 请求路径(如 /api/test)
|
||||
std::string version; // HTTP/1.1 / HTTP/1.0
|
||||
std::string query_string; // URL 查询参数(如 ?id=1&name=test)
|
||||
// 头部键值对(统一转小写,避免大小写问题)
|
||||
std::unordered_map<std::string, std::string> headers;
|
||||
|
||||
// 便捷获取头部值(兼容大小写)
|
||||
std::string get_header(const std::string& key) const {
|
||||
std::string lower_key = to_lower(key);
|
||||
auto it = headers.find(lower_key);
|
||||
return it != headers.end() ? it->second : "";
|
||||
}
|
||||
};
|
||||
|
||||
// ====================== HTTP 头解析函数 ======================
|
||||
HttpRequestHeader parse_http_header(const std::string& raw_header) {
|
||||
HttpRequestHeader result;
|
||||
std::istringstream iss(raw_header);
|
||||
std::string line;
|
||||
bool first_line_parsed = false;
|
||||
|
||||
// 第一步:解析请求首行(仅解析第一行,避免重复)
|
||||
while (std::getline(iss, line)) {
|
||||
// 移除行尾的 \r
|
||||
if (!line.empty() && line.back() == '\r') {
|
||||
line.pop_back();
|
||||
}
|
||||
line = trim(line);
|
||||
|
||||
// 跳过空行
|
||||
if (line.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 仅解析第一个非空行作为请求首行
|
||||
if (!first_line_parsed) {
|
||||
std::string url;
|
||||
std::istringstream line_iss(line);
|
||||
line_iss >> result.method >> url >> result.version;
|
||||
parse_url(url, result.path, result.query_string);
|
||||
std::transform(result.method.begin(), result.method.end(), result.method.begin(),
|
||||
[](unsigned char c) { return std::toupper(c); });
|
||||
first_line_parsed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 解析头部键值对
|
||||
size_t colon_pos = line.find(':');
|
||||
if (colon_pos == std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string key = trim(line.substr(0, colon_pos));
|
||||
std::string value = trim(line.substr(colon_pos + 1));
|
||||
result.headers[to_lower(key)] = value;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// ====================== 读取完整原始请求 ======================
|
||||
std::string read_full_raw_request(tcp::socket& socket, HttpRequestHeader& header_out) {
|
||||
asio::streambuf buf;
|
||||
std::string full_request;
|
||||
asio::error_code ec;
|
||||
|
||||
try {
|
||||
// 第一步:读取头部(直到 \r\n\r\n)
|
||||
size_t header_bytes = asio::read_until(socket, buf, "\r\n\r\n", ec);
|
||||
if (ec) {
|
||||
throw asio::system_error(ec);
|
||||
}
|
||||
|
||||
// 提取头部内容
|
||||
std::string header_str(asio::buffer_cast<const char*>(buf.data()), header_bytes);
|
||||
full_request = header_str;
|
||||
|
||||
// 安全清理头部末尾的 \r\n\r\n(核心修复:先判断是否找到)
|
||||
size_t end_header_pos = header_str.find("\r\n\r\n"); // 用 find 而非 find_last_of,精准匹配结束符
|
||||
if (end_header_pos != std::string::npos) {
|
||||
// 只保留头部内容,截断后面的空行
|
||||
header_str = header_str.substr(0, end_header_pos);
|
||||
}
|
||||
|
||||
// 解析头部
|
||||
header_out = parse_http_header(header_str);
|
||||
|
||||
// 第二步:读取请求体(严格按 Content-Length 读取)
|
||||
size_t content_len = 0;
|
||||
std::string cl_str = header_out.get_header("Content-Length");
|
||||
if (!cl_str.empty()) {
|
||||
try {
|
||||
content_len = std::stoul(cl_str);
|
||||
}
|
||||
catch (...) {
|
||||
content_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 清空缓冲区中已读取的头部数据
|
||||
buf.consume(header_bytes);
|
||||
|
||||
// 读取请求体(防越界)
|
||||
if (content_len > 0) {
|
||||
// 先检查剩余缓冲区是否足够,避免读取超限
|
||||
size_t buf_available = buf.size();
|
||||
if (buf_available < content_len) {
|
||||
// 读取剩余需要的字节
|
||||
asio::read(socket, buf, asio::transfer_exactly(content_len - buf_available), ec);
|
||||
if (ec && ec != asio::error::eof) {
|
||||
throw asio::system_error(ec);
|
||||
}
|
||||
}
|
||||
|
||||
// 提取请求体(防缓冲区数据不足)
|
||||
size_t actual_read = std::min(buf.size(), content_len);
|
||||
std::string body_str(asio::buffer_cast<const char*>(buf.data()), actual_read);
|
||||
full_request += body_str;
|
||||
|
||||
// 清理缓冲区
|
||||
buf.consume(actual_read);
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
throw;
|
||||
}
|
||||
|
||||
return full_request;
|
||||
}
|
||||
|
||||
// ====================== 将 HttpRequestHeader 转为 Squirrel Table ======================
|
||||
void push_http_header_to_squirrel(HSQUIRRELVM v, const HttpRequestHeader& header) {
|
||||
// 1. 创建空 Table
|
||||
sq_newtable(v);
|
||||
|
||||
// 2. 设置基础字段(method/path/version/query_string)
|
||||
// method
|
||||
sq_pushstring(v, _SC("method"), -1);
|
||||
sq_pushstring(v, header.method.c_str(), -1);
|
||||
sq_rawset(v, -3);
|
||||
|
||||
// path
|
||||
sq_pushstring(v, _SC("path"), -1);
|
||||
sq_pushstring(v, header.path.c_str(), -1);
|
||||
sq_rawset(v, -3);
|
||||
|
||||
// version
|
||||
sq_pushstring(v, _SC("version"), -1);
|
||||
sq_pushstring(v, header.version.c_str(), -1);
|
||||
sq_rawset(v, -3);
|
||||
|
||||
// query_string
|
||||
sq_pushstring(v, _SC("query_string"), -1);
|
||||
sq_pushstring(v, header.query_string.c_str(), -1);
|
||||
sq_rawset(v, -3);
|
||||
|
||||
// 3. 创建 headers 子 Table
|
||||
sq_pushstring(v, _SC("headers"), -1);
|
||||
sq_newtable(v);
|
||||
// 遍历头部键值对,写入子 Table
|
||||
for (const auto& pair : header.headers) {
|
||||
sq_pushstring(v, pair.first.c_str(), -1); // 键(小写)
|
||||
sq_pushstring(v, pair.second.c_str(), -1); // 值
|
||||
sq_rawset(v, -3);
|
||||
}
|
||||
// 将 headers 子 Table 写入主 Table
|
||||
sq_rawset(v, -3);
|
||||
}
|
||||
|
||||
// ====================== 处理客户端请求 ======================
|
||||
void handle_client(tcp::socket* socket, HSQOBJECT HttpServerObject) {
|
||||
if (!socket || !socket->is_open()) {
|
||||
std::cerr << "无效的 socket 连接" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 读取完整请求并解析头部
|
||||
HttpRequestHeader header;
|
||||
std::string full_request = read_full_raw_request(*socket, header);
|
||||
|
||||
// 加锁操作 Squirrel VM(lock_guard 自动管理锁生命周期)
|
||||
std::lock_guard<std::recursive_mutex> lock(SqMtx);
|
||||
|
||||
// 执行 Squirrel 的 Event 函数
|
||||
SQInteger top = sq_gettop(v); // 保存栈状态
|
||||
sq_pushobject(v, HttpServerObject);
|
||||
sq_pushstring(v, _SC("Event"), -1);
|
||||
|
||||
if (SQ_SUCCEEDED(sq_get(v, -2))) {
|
||||
// 压入函数参数:
|
||||
// 参数1:HttpServerObject(this)
|
||||
sq_pushobject(v, HttpServerObject);
|
||||
// 参数2:socket 指针(userpointer)
|
||||
sq_pushuserpointer(v, socket);
|
||||
// 参数3:解析后的 header table
|
||||
push_http_header_to_squirrel(v, header);
|
||||
// 参数4:完整原始请求字符串
|
||||
size_t body_start_pos = full_request.find("\r\n\r\n");
|
||||
std::string request_body = (body_start_pos != std::string::npos) ? full_request.substr(body_start_pos + 4) : "";
|
||||
sq_pushstring(v, request_body.c_str(), request_body.size());
|
||||
|
||||
// 调用函数:参数数量=4,无返回值,开启错误捕获
|
||||
sq_call(v, 4, SQFalse, SQTrue);
|
||||
}
|
||||
|
||||
sq_settop(v, top); // 恢复栈状态
|
||||
|
||||
}
|
||||
catch (const asio::system_error& e) {
|
||||
std::cerr << "网络错误: " << e.what() << " (错误码: " << e.code() << ")" << std::endl;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << "处理请求错误: " << e.what() << std::endl;
|
||||
}
|
||||
catch (...) {
|
||||
std::cerr << "未知错误" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// ====================== 服务器上下文(支持多实例) ======================
|
||||
struct HttpServerCtx {
|
||||
uint64_t server_id; // 唯一服务器ID(多实例核心)
|
||||
std::atomic<bool> running{ true }; // 退出标志(atomic不可拷贝)
|
||||
HSQUIRRELVM vm; // Squirrel VM
|
||||
HSQOBJECT http_server_obj; // 保存的对象
|
||||
asio::io_context* io_context = nullptr; // IO上下文(用于停止)
|
||||
std::string host; // 记录主机(调试用)
|
||||
std::string port; // 记录端口(调试用)
|
||||
|
||||
// 禁用拷贝构造和赋值(显式声明,避免误拷贝)
|
||||
HttpServerCtx(const HttpServerCtx&) = delete;
|
||||
HttpServerCtx& operator=(const HttpServerCtx&) = delete;
|
||||
|
||||
// 允许移动构造(用于unique_ptr)
|
||||
HttpServerCtx(HttpServerCtx&&) = default;
|
||||
HttpServerCtx& operator=(HttpServerCtx&&) = default;
|
||||
|
||||
// 构造函数
|
||||
HttpServerCtx() = default;
|
||||
HttpServerCtx(uint64_t id, HSQUIRRELVM vm_ptr, HSQOBJECT obj, const std::string& h, const std::string& p)
|
||||
: server_id(id), vm(vm_ptr), http_server_obj(obj), host(h), port(p) {
|
||||
}
|
||||
};
|
||||
|
||||
// ====================== 全局服务器管理(核心修复:用unique_ptr存储,避免拷贝) ======================
|
||||
static std::unordered_map<uint64_t, std::unique_ptr<HttpServerCtx>> g_server_ctxs;
|
||||
static std::atomic<uint64_t> g_next_server_id{ 1 }; // 自增唯一ID(atomic不可拷贝,直接用)
|
||||
static std::mutex g_server_mutex; // 保护全局容器
|
||||
|
||||
// ====================== 服务器主函数 ======================
|
||||
void start_server(uint64_t server_id, const std::string& host, const std::string& port) {
|
||||
// 查找上下文(加锁)
|
||||
std::unique_lock<std::mutex> lock(g_server_mutex);
|
||||
auto it = g_server_ctxs.find(server_id);
|
||||
if (it == g_server_ctxs.end()) {
|
||||
std::cerr << "服务器上下文不存在 (ID: " << server_id << ")" << std::endl;
|
||||
return;
|
||||
}
|
||||
HttpServerCtx* ctx = it->second.get(); // 获取指针,不拷贝
|
||||
lock.unlock(); // 手动解锁
|
||||
|
||||
asio::io_context io_context;
|
||||
ctx->io_context = &io_context; // 关联IO上下文
|
||||
|
||||
try {
|
||||
tcp::acceptor acceptor(io_context, tcp::endpoint(asio::ip::make_address(host), std::stoi(port)));
|
||||
std::cout << "Server [" << server_id << "] listening on " << host << ":" << port << std::endl;
|
||||
|
||||
// 循环监听(支持退出)
|
||||
while (ctx->running.load(std::memory_order_relaxed)) { // 原子操作读取
|
||||
tcp::socket* socket = new tcp::socket(io_context);
|
||||
try {
|
||||
acceptor.accept(*socket);
|
||||
// 启动客户端处理线程
|
||||
std::thread(handle_client, std::move(socket), ctx->http_server_obj).detach();
|
||||
}
|
||||
catch (const asio::system_error& e) {
|
||||
delete socket; // 中断时释放Socket
|
||||
if (e.code() != asio::error::operation_aborted && ctx->running.load(std::memory_order_relaxed)) {
|
||||
std::cerr << "Server [" << server_id << "] Accept error: " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << "Server [" << server_id << "] error: " << e.what() << std::endl;
|
||||
}
|
||||
|
||||
// 停止IO上下文
|
||||
io_context.stop();
|
||||
std::cout << "Server [" << server_id << "] stopped" << std::endl;
|
||||
}
|
||||
|
||||
// ====================== Squirrel 绑定函数 - 创建HTTP客户端 ======================
|
||||
static SQInteger CreateHttp(HSQUIRRELVM v) {
|
||||
const SQChar* Host;
|
||||
sq_getstring(v, 2, &Host);
|
||||
const SQChar* Service;
|
||||
sq_getstring(v, 3, &Service);
|
||||
const SQChar* Content;
|
||||
sq_getstring(v, 4, &Content);
|
||||
|
||||
try {
|
||||
asio::io_context ioContext;
|
||||
asio::ip::tcp::resolver resolver(ioContext);
|
||||
auto endpoints = resolver.resolve(Host, Service);
|
||||
asio::ip::tcp::socket socket(ioContext);
|
||||
asio::connect(socket, endpoints);
|
||||
|
||||
// 发送HTTP请求
|
||||
std::string request = Content;
|
||||
asio::write(socket, asio::buffer(request));
|
||||
|
||||
// 读取响应
|
||||
asio::streambuf response;
|
||||
asio::error_code error;
|
||||
while (asio::read(socket, response, asio::transfer_at_least(1), error)) {}
|
||||
|
||||
if (error && error != asio::error::eof) {
|
||||
throw asio::system_error(error);
|
||||
}
|
||||
|
||||
// 将响应内容返回
|
||||
std::istream responseStream(&response);
|
||||
std::ostringstream oss;
|
||||
oss << responseStream.rdbuf();
|
||||
sq_pushstring(v, oss.str().c_str(), -1);
|
||||
return 1;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
return sq_throwerror(v, e.what());
|
||||
}
|
||||
catch (...) {
|
||||
return sq_throwerror(v, _SC("Unknown error occurred"));
|
||||
}
|
||||
}
|
||||
|
||||
// ====================== Squirrel 绑定函数 - 创建HTTP服务器(核心修复:避免拷贝atomic) ======================
|
||||
static SQInteger CreateHttpServer(HSQUIRRELVM v) {
|
||||
const SQChar* host = nullptr;
|
||||
const SQChar* port = nullptr;
|
||||
HSQOBJECT HttpServerObject;
|
||||
|
||||
// 1. 参数校验
|
||||
if (SQ_FAILED(sq_getstring(v, 2, &host)) ||
|
||||
SQ_FAILED(sq_getstring(v, 3, &port)) ||
|
||||
SQ_FAILED(sq_getstackobj(v, 4, &HttpServerObject))) {
|
||||
sq_pushstring(v, _SC("param error: need (host:str, port:str, obj:HSQOBJECT)"), -1);
|
||||
return SQ_ERROR;
|
||||
}
|
||||
|
||||
// 2. 生成唯一服务器ID
|
||||
uint64_t server_id = g_next_server_id.fetch_add(1, std::memory_order_relaxed);
|
||||
|
||||
try {
|
||||
// 3. 动态创建上下文(避免拷贝)
|
||||
auto ctx_ptr = std::unique_ptr<HttpServerCtx>(new HttpServerCtx(server_id, v, HttpServerObject, std::string(host), std::string(port)));
|
||||
sq_addref(v, &ctx_ptr->http_server_obj); // 增加引用
|
||||
|
||||
// 4. 加锁存入全局(移动语义,不拷贝)
|
||||
std::lock_guard<std::mutex> lock(g_server_mutex);
|
||||
g_server_ctxs[server_id] = std::move(ctx_ptr); // 移动unique_ptr,不拷贝atomic
|
||||
|
||||
// 5. 启动服务器线程
|
||||
std::thread server_thread(start_server, server_id, std::string(host), std::string(port));
|
||||
server_thread.detach();
|
||||
|
||||
// 6. 返回唯一ID给Squirrel
|
||||
sq_pushinteger(v, static_cast<SQInteger>(server_id));
|
||||
return 1;
|
||||
}
|
||||
catch (...) {
|
||||
// 异常清理
|
||||
sq_release(v, &HttpServerObject); // 直接释放传入的对象
|
||||
std::lock_guard<std::mutex> lock(g_server_mutex);
|
||||
g_server_ctxs.erase(server_id);
|
||||
sq_pushbool(v, false);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// ====================== Squirrel 绑定函数 - 停止HTTP服务器 ======================
|
||||
static SQInteger StopHttpServer(HSQUIRRELVM v) {
|
||||
SQInteger server_id_int;
|
||||
if (SQ_FAILED(sq_getinteger(v, 2, &server_id_int)) || server_id_int <= 0) {
|
||||
sq_pushstring(v, _SC("invalid server ID"), -1);
|
||||
return SQ_ERROR;
|
||||
}
|
||||
uint64_t server_id = static_cast<uint64_t>(server_id_int);
|
||||
|
||||
std::lock_guard<std::mutex> lock(g_server_mutex);
|
||||
auto it = g_server_ctxs.find(server_id);
|
||||
if (it == g_server_ctxs.end()) {
|
||||
// 修正:拼接错误信息中的 server ID
|
||||
std::string err_msg = "server instance not found (ID: " + std::to_string(server_id) + ")";
|
||||
sq_pushstring(v, err_msg.c_str(), -1);
|
||||
return SQ_ERROR;
|
||||
}
|
||||
HttpServerCtx* ctx = it->second.get();
|
||||
|
||||
// 1. 标记停止(原子操作)
|
||||
ctx->running.store(false, std::memory_order_relaxed);
|
||||
|
||||
// 2. 强制停止 IO 上下文(中断所有异步操作)
|
||||
if (ctx->io_context) {
|
||||
ctx->io_context->stop();
|
||||
}
|
||||
|
||||
// 3. 释放 Squirrel 引用
|
||||
sq_release(ctx->vm, &ctx->http_server_obj);
|
||||
|
||||
// 4. 移除上下文(unique_ptr 自动析构)
|
||||
g_server_ctxs.erase(it);
|
||||
|
||||
sq_pushbool(v, true);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ====================== Squirrel 绑定函数 - 发送HTTP响应 ======================
|
||||
static SQInteger HttpServerResponse_Write(HSQUIRRELVM v) {
|
||||
SQUserPointer P;
|
||||
if (SQ_FAILED(sq_getuserpointer(v, 2, &P))) {
|
||||
return sq_throwerror(v, _SC("invalid socket pointer"));
|
||||
}
|
||||
tcp::socket* socket = static_cast<tcp::socket*>(P);
|
||||
|
||||
const SQChar* Content;
|
||||
if (SQ_FAILED(sq_getstring(v, 3, &Content))) {
|
||||
return sq_throwerror(v, _SC("invalid response content"));
|
||||
}
|
||||
|
||||
try {
|
||||
if (socket && socket->is_open()) {
|
||||
std::string response = Content;
|
||||
asio::write(*socket, asio::buffer(response));
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
// 清理资源
|
||||
if (socket) {
|
||||
asio::error_code ec;
|
||||
socket->close(ec);
|
||||
delete socket;
|
||||
}
|
||||
return sq_throwerror(v, e.what());
|
||||
}
|
||||
catch (...) {
|
||||
if (socket) {
|
||||
asio::error_code ec;
|
||||
socket->close(ec);
|
||||
delete socket;
|
||||
}
|
||||
return sq_throwerror(v, _SC("Unknown error occurred"));
|
||||
}
|
||||
|
||||
// 最后清理socket
|
||||
if (socket) {
|
||||
asio::error_code ec;
|
||||
socket->close(ec);
|
||||
delete socket;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ====================== 辅助函数 - 注册Squirrel函数 ======================
|
||||
static SQInteger register_Dio_func(HSQUIRRELVM v, SQFUNCTION f, const char* fname) {
|
||||
sq_pushroottable(v);
|
||||
sq_pushstring(v, fname, -1);
|
||||
sq_newclosure(v, f, 0);
|
||||
sq_newslot(v, -3, SQFalse);
|
||||
sq_pop(v, 1); // 弹出根表
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ====================== 注册所有Dio函数 ======================
|
||||
static void RegisterDio(HSQUIRRELVM v) {
|
||||
// 创建HTTP客户端
|
||||
register_Dio_func(v, CreateHttp, _SC("Sq_CreateHttp"));
|
||||
// HTTP服务器相关
|
||||
register_Dio_func(v, CreateHttpServer, _SC("Sq_CreateHttpServer"));
|
||||
register_Dio_func(v, StopHttpServer, _SC("Sq_StopHttpServer"));
|
||||
// 发送HTTP响应
|
||||
register_Dio_func(v, HttpServerResponse_Write, _SC("Sq_HttpServerResponse_Write"));
|
||||
}
|
||||
52
src/script/SqrReg_Dungeon.hpp
Normal file
52
src/script/SqrReg_Dungeon.hpp
Normal file
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
#include "squirrel.h"
|
||||
#include "sqstdaux.h"
|
||||
#include "sqstdblob.h"
|
||||
#include "sqstdio.h"
|
||||
#include "sqstdmath.h"
|
||||
#include "sqstdstring.h"
|
||||
#include "sqstdsystem.h"
|
||||
#include <iostream>
|
||||
|
||||
template <typename R, typename A, typename... ARG>
|
||||
R CallDungeon(A call_addr, const ARG... arguments)
|
||||
{
|
||||
if (!call_addr)
|
||||
{
|
||||
return R();
|
||||
}
|
||||
const auto control = reinterpret_cast<R (*)(ARG...)>(call_addr);
|
||||
try
|
||||
{
|
||||
return control(arguments...);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
return R();
|
||||
}
|
||||
|
||||
// 获取副本编号
|
||||
static SQInteger Dungeon_GetIdex(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger Idx = CallDungeon<int>(0x80FDCF0, P);
|
||||
sq_pushinteger(v, Idx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static SQInteger register_Dungeon_func(HSQUIRRELVM v, SQFUNCTION f, const char *fname)
|
||||
{
|
||||
sq_pushroottable(v);
|
||||
sq_pushstring(v, fname, -1);
|
||||
sq_newclosure(v, f, 0); // create a new function
|
||||
sq_newslot(v, -3, SQFalse);
|
||||
sq_pop(v, 1); // pops the root table
|
||||
}
|
||||
|
||||
static void RegisterDungeon(HSQUIRRELVM v)
|
||||
{
|
||||
// 获取编号
|
||||
register_Dungeon_func(v, Dungeon_GetIdex, _SC("Sq_Dungeon_GetIdex"));
|
||||
}
|
||||
1209
src/script/SqrReg_Game.hpp
Normal file
1209
src/script/SqrReg_Game.hpp
Normal file
File diff suppressed because it is too large
Load Diff
163
src/script/SqrReg_GameManager.hpp
Normal file
163
src/script/SqrReg_GameManager.hpp
Normal file
@@ -0,0 +1,163 @@
|
||||
#pragma once
|
||||
#include "squirrel.h"
|
||||
#include "sqstdaux.h"
|
||||
#include "sqstdblob.h"
|
||||
#include "sqstdio.h"
|
||||
#include "sqstdmath.h"
|
||||
#include "sqstdstring.h"
|
||||
#include "sqstdsystem.h"
|
||||
#include <iostream>
|
||||
#include "frida-gum.h"
|
||||
|
||||
typedef void *(*__GetGameManagerVoid)();
|
||||
static SQInteger GameManager_GameManager(HSQUIRRELVM v)
|
||||
{
|
||||
void *GameManager = ((__GetGameManagerVoid)0x080CC18E)();
|
||||
sq_pushuserpointer(v, GameManager);
|
||||
return 1;
|
||||
}
|
||||
typedef void *(*__GameManagerByThis)(void *GameManager);
|
||||
static SQInteger GameManager_GetParty(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
void *CParty = ((__GameManagerByThis)0x08294E10)(P);
|
||||
if (CParty)
|
||||
sq_pushuserpointer(v, CParty);
|
||||
else
|
||||
sq_pushinteger(v, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
typedef int (*cdeclCall2P)(int *a1, int a2);
|
||||
static cdeclCall2P SkillSlot__get_skillslot_buf = (cdeclCall2P)0x086067DE;
|
||||
static cdeclCall2P SkillSlot__gcheckComboSkillInsertQuickSlot = (cdeclCall2P)0x08608D58;
|
||||
#define RDWORD(addr, offset) (*(DWORD *)((char *)(addr) + (offset)))
|
||||
int __attribute__((cdecl)) hookCSkill__reform_ui_group_no(int *thisP, int *skillClassP, bool isTpSkill, int a4)
|
||||
{
|
||||
int p = (int)skillClassP;
|
||||
if (RDWORD(skillClassP, -0x60) == 197)
|
||||
{
|
||||
// cout << " fix skill197 class to 4!" << endl;
|
||||
*skillClassP = 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __attribute__((cdecl)) hookSkillSlot__get_skillslot_group(int *thisP, int slot)
|
||||
{
|
||||
// DWORD retAddr = (DWORD)gum_invocation_context_get_return_address(NULL);
|
||||
// cout<< retAddr << " get_skillslot_group:" << slot << endl;
|
||||
if (slot < 8 || slot >= 198)
|
||||
return -1;
|
||||
else if (slot >= 160)
|
||||
return 4;
|
||||
else if (slot >= 122)
|
||||
return 3;
|
||||
else if (slot >= 84)
|
||||
return 2;
|
||||
else if (slot >= 46)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __attribute__((cdecl)) hookSkillSlot__get_skillslot_no(int *thisP, int skillId, int group, int slot, char is_active_skill)
|
||||
{
|
||||
if (!thisP || !*thisP)
|
||||
return -1;
|
||||
BYTE *buf = (BYTE *)SkillSlot__get_skillslot_buf(thisP, slot);
|
||||
if (!buf)
|
||||
return -1;
|
||||
if (is_active_skill && SkillSlot__gcheckComboSkillInsertQuickSlot(thisP, skillId))
|
||||
{
|
||||
int end = skillId ? 7 : 5;
|
||||
for (int i = 0; i <= end; ++i)
|
||||
{
|
||||
if (buf[2 * i] == skillId)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
for (int i = 198; i <= 203; ++i)
|
||||
{
|
||||
if (buf[2 * i] == skillId)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
int pos = 8 + group * 38;
|
||||
for (int i = 0; i < 38; ++i)
|
||||
{
|
||||
if (buf[2 * (i + pos)] == skillId)
|
||||
{
|
||||
return i + pos;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int __attribute__((cdecl)) hookSkillSlot__get_skillslot_no2(int *thisP, BYTE *buf, int skillId, int group, char is_active_skill)
|
||||
{
|
||||
if (!thisP || !*thisP || !buf)
|
||||
return -1;
|
||||
if (is_active_skill)
|
||||
{
|
||||
int end = skillId ? 7 : 5;
|
||||
for (int i = 0; i <= end; ++i)
|
||||
{
|
||||
if (buf[2 * i] == skillId)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
for (int i = 198; i <= 203; ++i)
|
||||
{
|
||||
if (buf[2 * i] == skillId)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
int pos = 8 + group * 38;
|
||||
for (int i = 0; i < 38; ++i)
|
||||
{
|
||||
if (buf[2 * (i + pos)] == skillId)
|
||||
{
|
||||
return i + pos;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static SQInteger GameManager_FixA4Skill(HSQUIRRELVM vm)
|
||||
{
|
||||
GumInterceptor *v = gum_interceptor_obtain();
|
||||
gum_interceptor_begin_transaction(v);
|
||||
gum_interceptor_replace_fast(v, (gpointer)0x083507E8, (gpointer)hookCSkill__reform_ui_group_no, NULL);
|
||||
gum_interceptor_replace_fast(v, (gpointer)0x086049FC, (gpointer)hookSkillSlot__get_skillslot_group, NULL);
|
||||
gum_interceptor_replace_fast(v, (gpointer)0x08604A86, (gpointer)hookSkillSlot__get_skillslot_no, NULL);
|
||||
gum_interceptor_replace_fast(v, (gpointer)0x08607DBA, (gpointer)hookSkillSlot__get_skillslot_no2, NULL);
|
||||
gum_interceptor_end_transaction(v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SQInteger register_GameManager_func(HSQUIRRELVM v, SQFUNCTION f, const char *fname)
|
||||
{
|
||||
sq_pushroottable(v);
|
||||
sq_pushstring(v, fname, -1);
|
||||
sq_newclosure(v, f, 0); // create a new function
|
||||
sq_newslot(v, -3, SQFalse);
|
||||
sq_pop(v, 1); // pops the root table
|
||||
}
|
||||
|
||||
static void RegisterGameManager(HSQUIRRELVM v)
|
||||
{
|
||||
// 获得GameManager对象
|
||||
register_GameManager_func(v, GameManager_GameManager, _SC("Sq_GameManager_GameManager"));
|
||||
// 获得队伍对象
|
||||
register_GameManager_func(v, GameManager_GetParty, _SC("Sq_GameManager_GetParty"));
|
||||
// 修复A4技能
|
||||
register_GameManager_func(v, GameManager_FixA4Skill, _SC("Sq_FixA4Skill"));
|
||||
}
|
||||
114
src/script/SqrReg_Inven.hpp
Normal file
114
src/script/SqrReg_Inven.hpp
Normal file
@@ -0,0 +1,114 @@
|
||||
#pragma once
|
||||
#include "squirrel.h"
|
||||
#include "sqstdaux.h"
|
||||
#include "sqstdblob.h"
|
||||
#include "sqstdio.h"
|
||||
#include "sqstdmath.h"
|
||||
#include "sqstdstring.h"
|
||||
#include "sqstdsystem.h"
|
||||
#include <iostream>
|
||||
|
||||
template <typename R, typename A, typename... ARG>
|
||||
R CallInven(A call_addr, const ARG... arguments)
|
||||
{
|
||||
if (!call_addr)
|
||||
{
|
||||
return R();
|
||||
}
|
||||
const auto control = reinterpret_cast<R (*)(ARG...)>(call_addr);
|
||||
try
|
||||
{
|
||||
return control(arguments...);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
return R();
|
||||
}
|
||||
|
||||
// 获取背包
|
||||
static SQInteger Inven_GetInven(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
void *InvenP = CallInven<void *>(0x80DA28E, P);
|
||||
sq_pushuserpointer(v, InvenP);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 获取背包中的项目
|
||||
static SQInteger Inven_GetItem(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger Type, Slot;
|
||||
sq_getinteger(v, 3, &Type);
|
||||
sq_getinteger(v, 4, &Slot);
|
||||
|
||||
void *ItemP = CallInven<void *>(0x84FC1DE, P, Type, Slot);
|
||||
sq_pushuserpointer(v, ItemP);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 删除背包中的项目
|
||||
static SQInteger Inven_RemoveItem(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
|
||||
CallInven<void *>(0x080CB7D8, P);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 删除背包中的指定数量的项目
|
||||
static SQInteger Inven_RemoveItemFormCount(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger Type, Slot, Count, Ps, Log;
|
||||
sq_getinteger(v, 3, &Type);
|
||||
sq_getinteger(v, 4, &Slot);
|
||||
sq_getinteger(v, 5, &Count);
|
||||
sq_getinteger(v, 6, &Ps);
|
||||
sq_getinteger(v, 7, &Log);
|
||||
|
||||
SQInteger Ret = CallInven<int>(0x850400C, P, Type, Slot, Count, Ps, Log);
|
||||
sq_pushinteger(v, Ret);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 根据Id获取背包中的物品槽位
|
||||
static SQInteger Inven_GetItemById(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger Idx;
|
||||
sq_getinteger(v, 3, &Idx);
|
||||
|
||||
SQInteger Slot = CallInven<int>(0x08505172, P, Idx);
|
||||
sq_pushinteger(v, Slot);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static SQInteger register_Inven_func(HSQUIRRELVM v, SQFUNCTION f, const char *fname)
|
||||
{
|
||||
sq_pushroottable(v);
|
||||
sq_pushstring(v, fname, -1);
|
||||
sq_newclosure(v, f, 0); // create a new function
|
||||
sq_newslot(v, -3, SQFalse);
|
||||
sq_pop(v, 1); // pops the root table
|
||||
}
|
||||
|
||||
static void RegisterInven(HSQUIRRELVM v)
|
||||
{
|
||||
// 获取背包
|
||||
register_Inven_func(v, Inven_GetInven, "Sq_Inven_GetInven");
|
||||
// 获取背包中的道具
|
||||
register_Inven_func(v, Inven_GetItem, "Sq_Inven_GetItem");
|
||||
// 删除背包中的项目
|
||||
register_Inven_func(v, Inven_RemoveItem, "Sq_Inven_RemoveItem");
|
||||
// 根据Id获取背包中的物品槽位
|
||||
register_Inven_func(v, Inven_RemoveItemFormCount, "Sq_Inven_RemoveItemFormCount");
|
||||
// 根据Id获取背包中的物品槽位
|
||||
register_Inven_func(v, Inven_GetItemById, "Sq_Inven_GetItemById");
|
||||
}
|
||||
209
src/script/SqrReg_Memory.hpp
Normal file
209
src/script/SqrReg_Memory.hpp
Normal file
@@ -0,0 +1,209 @@
|
||||
#pragma once
|
||||
#include "squirrel.h"
|
||||
#include "sqstdaux.h"
|
||||
#include "sqstdblob.h"
|
||||
#include "sqstdio.h"
|
||||
#include "sqstdmath.h"
|
||||
#include "sqstdstring.h"
|
||||
#include "sqstdsystem.h"
|
||||
#include "CConnectPool.h"
|
||||
#include "inline_hook.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <functional>
|
||||
#include <list>
|
||||
#include <ffi.h>
|
||||
#include <keystone/keystone.h>
|
||||
|
||||
static SQInteger _file_releasehook(SQUserPointer p, SQInteger SQ_UNUSED_ARG(size))
|
||||
{
|
||||
free((void*)p);
|
||||
return 0;
|
||||
}
|
||||
// 注册析构函数
|
||||
static SQInteger Register_Destruction(HSQUIRRELVM v)
|
||||
{
|
||||
// 析构函数测试
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
|
||||
sq_setinstanceup(v, 3, P);
|
||||
sq_setreleasehook(v, 3, _file_releasehook);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SQInteger PointerOperation(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer Address;
|
||||
sq_getuserpointer(v, 2, &Address);
|
||||
SQInteger Offset;
|
||||
sq_getinteger(v, 3, &Offset);
|
||||
|
||||
const SQChar* TypecharBuf;
|
||||
sq_getstring(v, 4, &TypecharBuf);
|
||||
std::string Type(TypecharBuf);
|
||||
|
||||
if (Type == "+")
|
||||
{
|
||||
sq_pushuserpointer(v, (void*)(Address + Offset));
|
||||
}
|
||||
else if (Type == "-")
|
||||
{
|
||||
sq_pushuserpointer(v, (void*)(Address - Offset));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static SQInteger PointerOperationPointer(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer Address;
|
||||
sq_getuserpointer(v, 2, &Address);
|
||||
SQUserPointer Address2;
|
||||
sq_getuserpointer(v, 3, &Address2);
|
||||
|
||||
const SQChar* TypecharBuf;
|
||||
sq_getstring(v, 4, &TypecharBuf);
|
||||
std::string Type(TypecharBuf);
|
||||
|
||||
if (Type == "+")
|
||||
{
|
||||
sq_pushuserpointer(v, (void*)((int)Address + (int)Address2));
|
||||
}
|
||||
else if (Type == "-")
|
||||
{
|
||||
sq_pushuserpointer(v, (void*)((int)Address - (int)Address2));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 写字节数组
|
||||
static SQInteger Memory_WriteByteArr(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
char* Address = (char*)P;
|
||||
|
||||
size_t Idx = 0;
|
||||
sq_pushnull(v); // null iterator
|
||||
while (SQ_SUCCEEDED(sq_next(v, 3)))
|
||||
{
|
||||
SQInteger Buf;
|
||||
sq_getinteger(v, -1, &Buf);
|
||||
CMem::WriteUChar((Address + Idx), Buf);
|
||||
// 这里-1是值,-2是键
|
||||
sq_pop(v, 2); // 在下一次迭代之前弹出键和值
|
||||
Idx++;
|
||||
}
|
||||
sq_pop(v, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SQInteger Memory_WriteBlob(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
|
||||
SQUserPointer blob_data;
|
||||
SQInteger blob_len = sqstd_getblobsize(v, 3);
|
||||
sqstd_getblob(v, 3, &blob_data);
|
||||
|
||||
CMem::WriteBytes(P, blob_data, blob_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 读内存字符串
|
||||
static SQInteger Memory_ReadString(HSQUIRRELVM v)
|
||||
{
|
||||
// 内存地址
|
||||
SQUserPointer Address;
|
||||
// 获取地址
|
||||
sq_getuserpointer(v, 2, &Address);
|
||||
if (sq_gettop(v) == 3)
|
||||
{
|
||||
SQInteger Length;
|
||||
sq_getinteger(v, 3, &Length);
|
||||
sq_pushstring(v, (char*)(Address), Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
sq_pushstring(v, (char*)(Address), -1);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 将汇编代码字符串转为字节码
|
||||
static SQInteger Asmjit_Compile(HSQUIRRELVM v)
|
||||
{
|
||||
const SQChar* CharBuf;
|
||||
sq_getstring(v, 2, &CharBuf);
|
||||
std::string AsmCode(CharBuf);
|
||||
SQUserPointer Address = 0;
|
||||
if (sq_gettop(v) == 3)
|
||||
{
|
||||
sq_getuserpointer(v, 3, &Address);
|
||||
}
|
||||
|
||||
ks_engine* ks;
|
||||
ks_err err;
|
||||
size_t count;
|
||||
unsigned char* encode;
|
||||
size_t size;
|
||||
// 打开Keystone引擎,使用x86-64架构和Intel语法
|
||||
if (ks_open(KS_ARCH_X86, KS_MODE_32, &ks) != KS_ERR_OK)
|
||||
{
|
||||
// fprintf(stderr, "Failed to open Keystone\n");
|
||||
return -1;
|
||||
}
|
||||
// 可选:设置语法为Intel(默认已经是Intel,可省略)
|
||||
ks_option(ks, KS_OPT_SYNTAX, KS_OPT_SYNTAX_INTEL);
|
||||
// 汇编指令
|
||||
if (ks_asm(ks, AsmCode.c_str(), (uint64_t)Address, &encode, &size, &count) != KS_ERR_OK)
|
||||
{
|
||||
// fprintf(stderr, "Assembly error: %s\n", ks_strerror(ks_errno(ks)));
|
||||
ks_close(ks);
|
||||
return -1;
|
||||
}
|
||||
// 创建Squirrel数组
|
||||
sq_newarray(v, 0);
|
||||
// 将每个字节压入数组
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
sq_pushinteger(v, encode[i]); // 压入字节值
|
||||
sq_arrayappend(v, -2); // 添加到数组(-2是数组位置)
|
||||
}
|
||||
// 释放资源
|
||||
ks_free(encode);
|
||||
ks_close(ks);
|
||||
|
||||
return 1; // 返回1表示有返回值
|
||||
}
|
||||
|
||||
static SQInteger register_Memory_func(HSQUIRRELVM v, SQFUNCTION f, const char* fname)
|
||||
{
|
||||
sq_pushroottable(v);
|
||||
sq_pushstring(v, fname, -1);
|
||||
sq_newclosure(v, f, 0); // create a new function
|
||||
sq_newslot(v, -3, SQFalse);
|
||||
sq_pop(v, 1); // pops the root table
|
||||
}
|
||||
|
||||
static void RegisterMemory(HSQUIRRELVM v)
|
||||
{
|
||||
// 析构函数
|
||||
register_Memory_func(v, Register_Destruction, "Register_Destruction");
|
||||
// 运算
|
||||
register_Memory_func(v, PointerOperation, "Sq_PointerOperation");
|
||||
register_Memory_func(v, PointerOperationPointer, "Sq_PointerOperationPointer");
|
||||
// 写字节
|
||||
register_Memory_func(v, Memory_WriteByteArr, "Sq_Memory_WriteByteArr");
|
||||
// 读字符串
|
||||
register_Memory_func(v, Memory_ReadString, "Sq_Memory_ReadString");
|
||||
// 将汇编代码字符串转为字节码
|
||||
register_Memory_func(v, Asmjit_Compile, "Sq_Asmjit_Compile");
|
||||
// 写
|
||||
register_Memory_func(v, Memory_WriteBlob, "Sq_Memory_WriteBlob");
|
||||
}
|
||||
139
src/script/SqrReg_Packet.hpp
Normal file
139
src/script/SqrReg_Packet.hpp
Normal file
@@ -0,0 +1,139 @@
|
||||
#pragma once
|
||||
#include "squirrel.h"
|
||||
#include "sqstdaux.h"
|
||||
#include "sqstdblob.h"
|
||||
#include "sqstdio.h"
|
||||
#include "sqstdmath.h"
|
||||
#include "sqstdstring.h"
|
||||
#include "sqstdsystem.h"
|
||||
#include "import.h"
|
||||
#include "inline_hook.h"
|
||||
#include "Singleton.h"
|
||||
#include "./sdk/sdk_class.h"
|
||||
#include "utils.h"
|
||||
#include "GameDataManager.h"
|
||||
#include "PacketBuf.h"
|
||||
#include "User.h"
|
||||
#include <iostream>
|
||||
|
||||
static SQInteger Packet_New(HSQUIRRELVM v)
|
||||
{
|
||||
InterfacePacketBuf *Pck = (InterfacePacketBuf *)PacketGuard::NewPacketGuard();
|
||||
sq_pushuserpointer(v, Pck);
|
||||
return 1;
|
||||
}
|
||||
static SQInteger Packet_Put_header(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer Buf;
|
||||
sq_getuserpointer(v, 2, &Buf);
|
||||
InterfacePacketBuf *Pck = (InterfacePacketBuf *)Buf;
|
||||
SQInteger Header1;
|
||||
sq_getinteger(v, 3, &Header1);
|
||||
SQInteger Header2;
|
||||
sq_getinteger(v, 4, &Header2);
|
||||
Pck->put_header(Header1, Header2);
|
||||
return 0;
|
||||
}
|
||||
static SQInteger Packet_Put_byte(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer Buf;
|
||||
sq_getuserpointer(v, 2, &Buf);
|
||||
InterfacePacketBuf *Pck = (InterfacePacketBuf *)Buf;
|
||||
SQInteger Byte;
|
||||
sq_getinteger(v, 3, &Byte);
|
||||
Pck->put_byte(Byte);
|
||||
return 0;
|
||||
}
|
||||
static SQInteger Packet_Put_short(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer Buf;
|
||||
sq_getuserpointer(v, 2, &Buf);
|
||||
InterfacePacketBuf *Pck = (InterfacePacketBuf *)Buf;
|
||||
SQInteger Short;
|
||||
sq_getinteger(v, 3, &Short);
|
||||
Pck->put_short(Short);
|
||||
return 0;
|
||||
}
|
||||
static SQInteger Packet_Put_int(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer Buf;
|
||||
sq_getuserpointer(v, 2, &Buf);
|
||||
InterfacePacketBuf *Pck = (InterfacePacketBuf *)Buf;
|
||||
SQInteger Int;
|
||||
sq_getinteger(v, 3, &Int);
|
||||
Pck->put_int(Int);
|
||||
return 0;
|
||||
}
|
||||
static SQInteger Packet_Put_binary(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer Buf;
|
||||
sq_getuserpointer(v, 2, &Buf);
|
||||
InterfacePacketBuf *Pck = (InterfacePacketBuf *)Buf;
|
||||
const SQChar *Str;
|
||||
sq_getstring(v, 3, &Str);
|
||||
Pck->put_str((char *)Str, strlen(Str));
|
||||
return 0;
|
||||
}
|
||||
static SQInteger Packet_Put_binaryex(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer Buf;
|
||||
sq_getuserpointer(v, 2, &Buf);
|
||||
InterfacePacketBuf *Pck = (InterfacePacketBuf *)Buf;
|
||||
SQUserPointer Str;
|
||||
sq_getuserpointer(v, 3, &Str);
|
||||
SQInteger Len;
|
||||
sq_getinteger(v, 4, &Len);
|
||||
Pck->put_binary((char *)Str, Len);
|
||||
return 0;
|
||||
}
|
||||
static SQInteger Packet_Finalize(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer Buf;
|
||||
sq_getuserpointer(v, 2, &Buf);
|
||||
InterfacePacketBuf *Pck = (InterfacePacketBuf *)Buf;
|
||||
SQBool B;
|
||||
sq_getbool(v, 3, &B);
|
||||
Pck->finalize(B);
|
||||
return 0;
|
||||
}
|
||||
static SQInteger Packet_Send(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer userbuf;
|
||||
sq_getuserpointer(v, 2, &userbuf);
|
||||
CUser *user = (CUser *)userbuf;
|
||||
SQUserPointer Buf;
|
||||
sq_getuserpointer(v, 3, &Buf);
|
||||
user->Send((PacketGuard *)Buf);
|
||||
return 0;
|
||||
}
|
||||
static SQInteger Packet_Delete(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer Buf;
|
||||
sq_getuserpointer(v, 2, &Buf);
|
||||
InterfacePacketBuf *Pck = (InterfacePacketBuf *)Buf;
|
||||
InterfacePacketBuf::DelPacketBuf(Pck);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SQInteger register_Packet_func(HSQUIRRELVM v, SQFUNCTION f, const char *fname)
|
||||
{
|
||||
sq_pushroottable(v);
|
||||
sq_pushstring(v, fname, -1);
|
||||
sq_newclosure(v, f, 0); // create a new function
|
||||
sq_newslot(v, -3, SQFalse);
|
||||
sq_pop(v, 1); // pops the root table
|
||||
}
|
||||
|
||||
static void RegisterPacket(HSQUIRRELVM v)
|
||||
{
|
||||
register_Packet_func(v, Packet_New, _SC("Sq_Packet_New"));
|
||||
register_Packet_func(v, Packet_Put_header, _SC("Sq_Packet_Put_header"));
|
||||
register_Packet_func(v, Packet_Put_byte, _SC("Sq_Packet_Put_byte"));
|
||||
register_Packet_func(v, Packet_Put_short, _SC("Sq_Packet_Put_short"));
|
||||
register_Packet_func(v, Packet_Put_int, _SC("Sq_Packet_Put_int"));
|
||||
register_Packet_func(v, Packet_Put_binary, _SC("Sq_Packet_Put_binary"));
|
||||
register_Packet_func(v, Packet_Put_binaryex, _SC("Sq_Packet_Put_binaryex"));
|
||||
register_Packet_func(v, Packet_Finalize, _SC("Sq_Packet_Finalize"));
|
||||
register_Packet_func(v, Packet_Send, _SC("Sq_Packet_Send"));
|
||||
register_Packet_func(v, Packet_Delete, _SC("Sq_Packet_Delete"));
|
||||
}
|
||||
95
src/script/SqrReg_Party.hpp
Normal file
95
src/script/SqrReg_Party.hpp
Normal file
@@ -0,0 +1,95 @@
|
||||
#pragma once
|
||||
#include "squirrel.h"
|
||||
#include "sqstdaux.h"
|
||||
#include "sqstdblob.h"
|
||||
#include "sqstdio.h"
|
||||
#include "sqstdmath.h"
|
||||
#include "sqstdstring.h"
|
||||
#include "sqstdsystem.h"
|
||||
#include <iostream>
|
||||
|
||||
template <typename R, typename A, typename... ARG>
|
||||
R CallParty(A call_addr, const ARG... arguments)
|
||||
{
|
||||
if (!call_addr)
|
||||
{
|
||||
return R();
|
||||
}
|
||||
const auto control = reinterpret_cast<R (*)(ARG...)>(call_addr);
|
||||
try
|
||||
{
|
||||
return control(arguments...);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
return R();
|
||||
}
|
||||
typedef int (*__CreateParty)(void *CParty, void *CUser);
|
||||
static SQInteger Party_CreateParty(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQUserPointer User;
|
||||
sq_getuserpointer(v, 3, &User);
|
||||
((__CreateParty)0x0859B1BE)(P, User);
|
||||
return 0;
|
||||
}
|
||||
typedef int (*__SetPartyInfoUI)(void *CParty, int code);
|
||||
static SQInteger Party_SetPartyInfoUI(HSQUIRRELVM v) // 设置队伍信息UI可以不写 创出来空的 要写的话要搞个指针 写入很多参数
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
((__SetPartyInfoUI)0x0859B234)(P, 0x44d672e);
|
||||
return 0;
|
||||
}
|
||||
typedef int (*__JoinParty)(void *CParty, void *CUser);
|
||||
static SQInteger Party_JoinParty(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQUserPointer User;
|
||||
sq_getuserpointer(v, 3, &User);
|
||||
((__JoinParty)0x0859B2B6)(P, User);
|
||||
return 0;
|
||||
}
|
||||
typedef int (*__SendPartyIpInfo)(void *CParty);
|
||||
static SQInteger Party_SendPartyIpInfo(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
((__SendPartyIpInfo)0x0859CEA2)(P);
|
||||
return 0;
|
||||
}
|
||||
// 获取战斗对象
|
||||
static SQInteger Party_GetBattle_Field(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
|
||||
sq_pushuserpointer(v, P + 2852);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static SQInteger register_Party_func(HSQUIRRELVM v, SQFUNCTION f, const char *fname)
|
||||
{
|
||||
sq_pushroottable(v);
|
||||
sq_pushstring(v, fname, -1);
|
||||
sq_newclosure(v, f, 0); // create a new function
|
||||
sq_newslot(v, -3, SQFalse);
|
||||
sq_pop(v, 1); // pops the root table
|
||||
}
|
||||
|
||||
static void RegisterParty(HSQUIRRELVM v)
|
||||
{
|
||||
// 创建队伍
|
||||
register_Party_func(v, Party_CreateParty, _SC("Sq_Party_CreateParty"));
|
||||
// 设置队伍信息UI
|
||||
register_Party_func(v, Party_SetPartyInfoUI, _SC("Sq_Party_SetPartyInfoUI"));
|
||||
// 让玩家加入队伍
|
||||
register_Party_func(v, Party_JoinParty, _SC("Sq_Party_JoinParty"));
|
||||
// 广播队伍玩家IP
|
||||
register_Party_func(v, Party_SendPartyIpInfo, _SC("Sq_Party_SendPartyIpInfo"));
|
||||
// 获取副本编号
|
||||
register_Party_func(v, Party_GetBattle_Field, _SC("Sq_Party_GetBattle_Field"));
|
||||
}
|
||||
247
src/script/SqrReg_RSA.hpp
Normal file
247
src/script/SqrReg_RSA.hpp
Normal file
@@ -0,0 +1,247 @@
|
||||
#pragma once
|
||||
#include "squirrel.h"
|
||||
#include "sqstdaux.h"
|
||||
#include "sqstdblob.h"
|
||||
#include "sqstdio.h"
|
||||
#include "sqstdmath.h"
|
||||
#include "sqstdstring.h"
|
||||
#include "sqstdsystem.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
|
||||
// 错误信息打印函数
|
||||
void print_openssl_error() {
|
||||
char err_buf[256];
|
||||
ERR_error_string_n(ERR_get_error(), err_buf, sizeof(err_buf));
|
||||
std::cerr << "OpenSSL 错误: " << err_buf << std::endl;
|
||||
}
|
||||
|
||||
// 生成 RSA 密钥对并保存到文件
|
||||
// 生成 RSA 密钥对(公钥:X.509/PKCS#8 格式,私钥:PKCS#1 格式)
|
||||
bool generate_rsa_key(const std::string& pub_key_path,
|
||||
const std::string& pri_key_path,
|
||||
int key_bits = 2048) {
|
||||
// 1. 创建 RSA 对象并生成密钥对
|
||||
RSA* rsa = RSA_new();
|
||||
BIGNUM* bn = BN_new();
|
||||
if (!rsa || !bn) {
|
||||
std::cerr << "创建 RSA/BIGNUM 失败" << std::endl;
|
||||
RSA_free(rsa);
|
||||
BN_free(bn);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 设置公钥指数(65537)
|
||||
if (BN_set_word(bn, RSA_F4) != 1) {
|
||||
std::cerr << "设置 BIGNUM 失败" << std::endl;
|
||||
print_openssl_error();
|
||||
RSA_free(rsa);
|
||||
BN_free(bn);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 生成 RSA 密钥对
|
||||
if (RSA_generate_key_ex(rsa, key_bits, bn, nullptr) != 1) {
|
||||
std::cerr << "生成 RSA 密钥对失败" << std::endl;
|
||||
print_openssl_error();
|
||||
RSA_free(rsa);
|
||||
BN_free(bn);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. 封装 RSA 到 EVP_PKEY(用于生成 X.509/PKCS#8 公钥)
|
||||
EVP_PKEY* evp_key = EVP_PKEY_new();
|
||||
if (!evp_key || EVP_PKEY_assign_RSA(evp_key, rsa) != 1) {
|
||||
std::cerr << "封装 EVP_PKEY 失败" << std::endl;
|
||||
print_openssl_error();
|
||||
EVP_PKEY_free(evp_key);
|
||||
RSA_free(rsa);
|
||||
BN_free(bn);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3. 保存 X.509/PKCS#8 格式公钥(-----BEGIN PUBLIC KEY-----)
|
||||
FILE* pub_file = fopen(pub_key_path.c_str(), "w");
|
||||
if (!pub_file) {
|
||||
std::cerr << "打开公钥文件失败: " << pub_key_path << std::endl;
|
||||
EVP_PKEY_free(evp_key);
|
||||
BN_free(bn);
|
||||
return false;
|
||||
}
|
||||
if (PEM_write_PUBKEY(pub_file, evp_key) != 1) {
|
||||
std::cerr << "写入 X.509 公钥失败" << std::endl;
|
||||
print_openssl_error();
|
||||
fclose(pub_file);
|
||||
EVP_PKEY_free(evp_key);
|
||||
BN_free(bn);
|
||||
return false;
|
||||
}
|
||||
fclose(pub_file);
|
||||
|
||||
// 4. 保存 PKCS#1 格式私钥(-----BEGIN RSA PRIVATE KEY-----)
|
||||
FILE* pri_file = fopen(pri_key_path.c_str(), "w");
|
||||
if (!pri_file) {
|
||||
std::cerr << "打开私钥文件失败: " << pri_key_path << std::endl;
|
||||
EVP_PKEY_free(evp_key);
|
||||
BN_free(bn);
|
||||
return false;
|
||||
}
|
||||
if (PEM_write_RSAPrivateKey(pri_file, rsa, nullptr, nullptr, 0, nullptr, nullptr) != 1) {
|
||||
std::cerr << "写入私钥失败" << std::endl;
|
||||
print_openssl_error();
|
||||
fclose(pri_file);
|
||||
EVP_PKEY_free(evp_key);
|
||||
BN_free(bn);
|
||||
return false;
|
||||
}
|
||||
fclose(pri_file);
|
||||
|
||||
// 5. 释放资源(EVP_PKEY_free 会自动释放内部的 RSA 对象)
|
||||
EVP_PKEY_free(evp_key);
|
||||
BN_free(bn);
|
||||
|
||||
std::cout << "RSA 密钥生成成功!" << std::endl;
|
||||
std::cout << "公钥(X.509/PKCS#8 格式): " << pub_key_path << std::endl;
|
||||
std::cout << "私钥(PKCS#1 格式): " << pri_key_path << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static SQInteger Rsa_GenerateKey(HSQUIRRELVM v)
|
||||
{
|
||||
// 初始化 OpenSSL 错误处理
|
||||
ERR_load_crypto_strings();
|
||||
OpenSSL_add_all_algorithms();
|
||||
|
||||
// 生成 2048 位 RSA 密钥对(推荐使用 2048/4096 位)
|
||||
bool ret = generate_rsa_key("public.pem", "private.pem", 2048);
|
||||
|
||||
// 清理 OpenSSL 资源
|
||||
EVP_cleanup();
|
||||
ERR_free_strings();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// 从文件加载私钥(PKCS#1 格式)
|
||||
RSA* load_rsa_private_key(const std::string& pri_key_path) {
|
||||
FILE* pri_file = fopen(pri_key_path.c_str(), "r");
|
||||
if (!pri_file) {
|
||||
std::cerr << "打开私钥文件失败: " << pri_key_path << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 加载 PKCS#1 格式私钥
|
||||
RSA* rsa = PEM_read_RSAPrivateKey(pri_file, nullptr, nullptr, nullptr);
|
||||
fclose(pri_file);
|
||||
|
||||
if (!rsa) {
|
||||
std::cerr << "加载私钥失败" << std::endl;
|
||||
print_openssl_error();
|
||||
}
|
||||
return rsa;
|
||||
}
|
||||
|
||||
// 新增:十六进制字符串转字节数组(核心补全)
|
||||
bool hex_string_to_bytes(const std::string& hex_str, std::vector<unsigned char>& bytes) {
|
||||
bytes.clear();
|
||||
// 检查长度是否为偶数(十六进制字符串必须2字符=1字节)
|
||||
if (hex_str.length() % 2 != 0) {
|
||||
std::cerr << "十六进制字符串长度为奇数,无效" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < hex_str.length(); i += 2) {
|
||||
std::string byte_str = hex_str.substr(i, 2);
|
||||
// 十六进制转字节(处理0-9/a-f/A-F)
|
||||
unsigned char byte = static_cast<unsigned char>(strtol(byte_str.c_str(), nullptr, 16));
|
||||
bytes.push_back(byte);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool rsa_private_encrypt(const std::vector<unsigned char>& plaintext_bytes, RSA* rsa_pri, std::string& ciphertext) {
|
||||
if (!rsa_pri || plaintext_bytes.empty()) return false;
|
||||
|
||||
int rsa_len = RSA_size(rsa_pri);
|
||||
unsigned char* enc_buf = new unsigned char[rsa_len];
|
||||
|
||||
// 加密字节数组(而非字符串的ASCII)
|
||||
int enc_len = RSA_private_encrypt(
|
||||
plaintext_bytes.size(), // 明文长度(字节数)
|
||||
plaintext_bytes.data(), // 明文字节数组
|
||||
enc_buf, // 加密结果缓冲区
|
||||
rsa_pri, // RSA私钥
|
||||
RSA_PKCS1_PADDING // 填充方式(和Java一致)
|
||||
);
|
||||
|
||||
if (enc_len > 0) {
|
||||
ciphertext = std::string((char*)enc_buf, enc_len);
|
||||
} else {
|
||||
std::cerr << "私钥加密失败(2048位RSA最多加密245字节)" << std::endl;
|
||||
print_openssl_error();
|
||||
}
|
||||
|
||||
delete[] enc_buf;
|
||||
return enc_len > 0;
|
||||
}
|
||||
|
||||
|
||||
static SQInteger Rsa_Private_Encrypt(HSQUIRRELVM v)
|
||||
{
|
||||
const SQChar* hex_str;
|
||||
sq_getstring(v, 2, &hex_str); // 获取Squirrel传入的十六进制字符串
|
||||
|
||||
// 1. 加载RSA私钥
|
||||
RSA* rsa_pri = load_rsa_private_key("privatekey.pem");
|
||||
if (!rsa_pri) {
|
||||
sq_pushnull(v);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 2. 核心:十六进制字符串转字节数组(对齐Java的toByteArray)
|
||||
std::vector<unsigned char> plaintext_bytes;
|
||||
if (!hex_string_to_bytes(std::string(hex_str), plaintext_bytes)) {
|
||||
RSA_free(rsa_pri);
|
||||
sq_pushnull(v);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 3. 加密字节数组
|
||||
std::string ciphertext;
|
||||
bool success = rsa_private_encrypt(plaintext_bytes, rsa_pri, ciphertext);
|
||||
|
||||
// 4. 返回加密后的字节串(Squirrel中以字符串形式承载二进制数据)
|
||||
if (success) {
|
||||
sq_pushstring(v, ciphertext.c_str(), ciphertext.length());
|
||||
} else {
|
||||
sq_pushnull(v);
|
||||
}
|
||||
|
||||
// 释放资源
|
||||
RSA_free(rsa_pri);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ====================== 辅助函数 - 注册Squirrel函数 ======================
|
||||
static SQInteger register_Rsa_func(HSQUIRRELVM v, SQFUNCTION f, const char* fname) {
|
||||
sq_pushroottable(v);
|
||||
sq_pushstring(v, fname, -1);
|
||||
sq_newclosure(v, f, 0);
|
||||
sq_newslot(v, -3, SQFalse);
|
||||
sq_pop(v, 1); // 弹出根表
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ====================== 注册所有Dio函数 ======================
|
||||
static void RegisterRsa(HSQUIRRELVM v) {
|
||||
|
||||
register_Rsa_func(v, Rsa_GenerateKey, _SC("Sq_Rsa_GenerateKey"));
|
||||
//使用私钥签名
|
||||
register_Rsa_func(v, Rsa_Private_Encrypt, _SC("Sq_Rsa_Private_Encrypt"));
|
||||
}
|
||||
543
src/script/SqrReg_User.hpp
Normal file
543
src/script/SqrReg_User.hpp
Normal file
@@ -0,0 +1,543 @@
|
||||
#pragma once
|
||||
#include "squirrel.h"
|
||||
#include "sqstdaux.h"
|
||||
#include "sqstdblob.h"
|
||||
#include "sqstdio.h"
|
||||
#include "sqstdmath.h"
|
||||
#include "sqstdstring.h"
|
||||
#include "sqstdsystem.h"
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
template <typename R, typename A, typename... ARG>
|
||||
R CallUser(A call_addr, const ARG... arguments)
|
||||
{
|
||||
if (!call_addr)
|
||||
{
|
||||
return R();
|
||||
}
|
||||
const auto control = reinterpret_cast<R (*)(ARG...)>(call_addr);
|
||||
try
|
||||
{
|
||||
return control(arguments...);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
return R();
|
||||
}
|
||||
|
||||
typedef int (*__GetUserByThis)(void *CUser);
|
||||
typedef int (*__GetUserArea)(void *CUser, bool a);
|
||||
typedef int (*__SetUserByInt)(void *CUser, int Value);
|
||||
static SQInteger CUser_GetPosX(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger X = int(((__GetUserByThis)0x0813492c)((void *)P));
|
||||
sq_pushinteger(v, X);
|
||||
return 1;
|
||||
}
|
||||
static SQInteger CUser_GetPosY(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger Y = int(((__GetUserByThis)0x0813493c)((void *)P));
|
||||
sq_pushinteger(v, Y);
|
||||
return 1;
|
||||
}
|
||||
static SQInteger CUser_Direction(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger Ret = int(((__GetUserByThis)0x0813494c)((void *)P));
|
||||
sq_pushinteger(v, Ret);
|
||||
return 1;
|
||||
}
|
||||
static SQInteger CUser_GetVill(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger Vill = int(((__GetUserByThis)0x08645564)((void *)P));
|
||||
sq_pushinteger(v, Vill);
|
||||
return 1;
|
||||
}
|
||||
static SQInteger CUser_GetArea(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
SQInteger Type = 0;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
if (sq_gettop(v) == 3)
|
||||
{
|
||||
sq_getinteger(v, 3, &Type);
|
||||
}
|
||||
SQInteger Area = int(((__GetUserArea)0x086813BE)((void *)P, Type));
|
||||
sq_pushinteger(v, Area);
|
||||
return 1;
|
||||
}
|
||||
static SQInteger CUser_GetState(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger State = int(((__GetUserByThis)0x080DA38C)((void *)P));
|
||||
sq_pushinteger(v, State);
|
||||
return 1;
|
||||
}
|
||||
static SQInteger CUser_GetCharacCount(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger Count = int(((__GetUserByThis)0x082300E8)((void *)P));
|
||||
sq_pushinteger(v, Count);
|
||||
return 1;
|
||||
}
|
||||
static SQInteger CUser_GetUniqueId(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger UID = int(((__GetUserByThis)0x080DA37C)((void *)P));
|
||||
sq_pushinteger(v, UID);
|
||||
return 1;
|
||||
}
|
||||
static SQInteger CUser_GetAccId(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger UID = int(((__GetUserByThis)0x080DA36E)((void *)P));
|
||||
sq_pushinteger(v, UID);
|
||||
return 1;
|
||||
}
|
||||
static SQInteger CUser_GetCharacNo(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger CID = int(((__GetUserByThis)0x080CBC4E)((void *)P));
|
||||
sq_pushinteger(v, CID);
|
||||
return 1;
|
||||
}
|
||||
static SQInteger CUser_GetCharacJob(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger Ret = int(((__GetUserByThis)0x080FDF20)((void *)P));
|
||||
sq_pushinteger(v, Ret);
|
||||
return 1;
|
||||
}
|
||||
static SQInteger CUser_GetCharacName(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger Ret = int(((__GetUserByThis)0x08101028)((void *)P));
|
||||
sq_pushstring(v, _SC((char *)Ret), -1);
|
||||
return 1;
|
||||
}
|
||||
static SQInteger CUser_GetCharacLevel(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger Ret = int(((__GetUserByThis)0x080DA2B8)((void *)P));
|
||||
sq_pushinteger(v, Ret);
|
||||
return 1;
|
||||
}
|
||||
static SQInteger CUser_SetCharacLevel(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger Value;
|
||||
sq_getinteger(v, 3, &Value);
|
||||
char *a = new char[4];
|
||||
CallUser<int>(0x822FC8E, a, P, Value);
|
||||
return 0;
|
||||
}
|
||||
static SQInteger CUser_GetCharacGrowType(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger Ret = int(((__GetUserByThis)0x0815741C)((void *)P));
|
||||
sq_pushinteger(v, Ret);
|
||||
return 1;
|
||||
}
|
||||
static SQInteger CUser_GetCharacSecondGrowType(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger Ret = int(((__GetUserByThis)0x0822F23C)((void *)P));
|
||||
sq_pushinteger(v, Ret);
|
||||
return 1;
|
||||
}
|
||||
static SQInteger CUser_GetFatigue(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger Ret = int(((__GetUserByThis)0x08657766)((void *)P));
|
||||
sq_pushinteger(v, Ret);
|
||||
return 1;
|
||||
}
|
||||
static SQInteger CUser_GetMaxFatigue(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger Ret = int(((__GetUserByThis)0x08657804)((void *)P));
|
||||
sq_pushinteger(v, Ret);
|
||||
return 1;
|
||||
}
|
||||
typedef int (*__CUser_DisConnSig)(void *CUser, int type, int is, int err);
|
||||
static SQInteger CUser_DisConnSig(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
SQInteger Src;
|
||||
SQInteger P2;
|
||||
SQInteger P3;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
sq_getinteger(v, 3, &Src);
|
||||
sq_getinteger(v, 4, &P2);
|
||||
sq_getinteger(v, 5, &P3);
|
||||
SQInteger Ret = int(((__CUser_DisConnSig)0x086489F4)((void *)P, Src, P2, P3));
|
||||
sq_pushinteger(v, Ret);
|
||||
return 1;
|
||||
}
|
||||
typedef void *(*__GetUserParty)(void *CUser);
|
||||
static SQInteger CUser_GetParty(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQUserPointer Ret = (((__GetUserParty)0x0865514C)((void *)P));
|
||||
sq_pushuserpointer(v, Ret);
|
||||
return 1;
|
||||
}
|
||||
static SQInteger CUser_CheckInBossTower(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger Ret = int(((__GetUserByThis)0x082a67e2)((void *)P));
|
||||
sq_pushinteger(v, Ret);
|
||||
return 1;
|
||||
}
|
||||
static SQInteger CUser_CheckInBlueMarble(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger Ret = int(((__GetUserByThis)0x080da32a)((void *)P));
|
||||
sq_pushinteger(v, Ret);
|
||||
return 1;
|
||||
}
|
||||
static SQInteger CUser_IsGmMode(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger Ret = int(((__GetUserByThis)0x0814589c)((void *)P));
|
||||
sq_pushinteger(v, Ret);
|
||||
return 1;
|
||||
}
|
||||
static SQInteger CUser_GetVisibleValues(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger Ret = int(((__GetUserByThis)0x0868BDE4)((void *)P));
|
||||
sq_pushinteger(v, Ret);
|
||||
return 1;
|
||||
}
|
||||
static SQInteger CUser_GetCurCharacLastPlayTick(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger Ret = int(((__GetUserByThis)0x082A66AA)((void *)P));
|
||||
sq_pushinteger(v, Ret);
|
||||
return 1;
|
||||
}
|
||||
typedef int (*__GiveUserItem)(void *CUser, int a2, int a3, int a4, int *a5, int a6);
|
||||
typedef int (*__UserSendUpdateItemList)(void *CUser, int a2, int a3, int a4);
|
||||
static SQInteger CUser_GiveUserItem(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger ItemId, ItemCount;
|
||||
sq_getinteger(v, 3, &ItemId);
|
||||
sq_getinteger(v, 4, &ItemCount);
|
||||
int *ItemSpace = (int *)malloc(4);
|
||||
int Slot = int(((__GiveUserItem)0x0867B6D4)((void *)P, ItemId, ItemCount, 6, ItemSpace, 0));
|
||||
if (Slot >= 0)
|
||||
{
|
||||
sq_newarray(v, 0);
|
||||
sq_pushinteger(v, *ItemSpace);
|
||||
sq_arrayappend(v, -2);
|
||||
sq_pushinteger(v, Slot);
|
||||
sq_arrayappend(v, -2);
|
||||
}
|
||||
else
|
||||
sq_pushnull(v);
|
||||
return 1;
|
||||
}
|
||||
// 通知客户端更新道具信息
|
||||
static SQInteger CUser_SendUpdateItemList(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger Type, ItemSpace, Slot;
|
||||
sq_getinteger(v, 3, &Type);
|
||||
sq_getinteger(v, 4, &ItemSpace);
|
||||
sq_getinteger(v, 5, &Slot);
|
||||
|
||||
CallUser<int>(0x867C65A, P, Type, ItemSpace, Slot);
|
||||
return 0;
|
||||
}
|
||||
// 通知客户端更新背包栏
|
||||
static SQInteger CUser_SendItemSpace(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger itemSpace;
|
||||
sq_getinteger(v, 3, &itemSpace);
|
||||
|
||||
// std::cout << *(int *)P << std::endl;
|
||||
CallUser<int>(0x865DB6C, P, itemSpace);
|
||||
return 0;
|
||||
}
|
||||
// 发送邮件
|
||||
static SQInteger CUser_SendMail(HSQUIRRELVM v)
|
||||
{
|
||||
SQInteger Cid;
|
||||
sq_getinteger(v, 2, &Cid);
|
||||
|
||||
std::vector<std::pair<int, int>> List;
|
||||
List.clear();
|
||||
|
||||
int ItemListLen = 0;
|
||||
sq_pushnull(v); // null iterator
|
||||
while (SQ_SUCCEEDED(sq_next(v, 3)))
|
||||
{
|
||||
SQInteger Index, Count;
|
||||
sq_getinteger(v, -1, &Count);
|
||||
sq_getinteger(v, -2, &Index);
|
||||
std::pair<int, int> pair1 = std::make_pair(Index, Count);
|
||||
List.push_back(pair1);
|
||||
// 这里-1是值,-2是键
|
||||
sq_pop(v, 2); // 在下一次迭代之前弹出键和值
|
||||
ItemListLen++;
|
||||
}
|
||||
sq_pop(v, 1);
|
||||
|
||||
void *addition_slots = malloc(1000);
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
CallUser<void>(0x80CB854, addition_slots + (i * 61));
|
||||
}
|
||||
CallUser<int>(0x8556A14, List, addition_slots, 10);
|
||||
|
||||
SQInteger Gold;
|
||||
sq_getinteger(v, 4, &Gold);
|
||||
const SQChar *Title;
|
||||
const SQChar *Text;
|
||||
sq_getstring(v, 5, &Title);
|
||||
sq_getstring(v, 6, &Text);
|
||||
int TextLen = strlen(Text);
|
||||
|
||||
CallUser<int>(0x8556B68, Title, addition_slots, ItemListLen, Gold, Cid, Text, TextLen, 0, 99, 1);
|
||||
return 0;
|
||||
}
|
||||
// 发送邮件
|
||||
static SQInteger CUser_ChangeGrowType(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger Base, Ex;
|
||||
sq_getinteger(v, 3, &Base);
|
||||
sq_getinteger(v, 4, &Ex);
|
||||
|
||||
CallUser<int>(0x867B048, P, Base, Ex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 发送消息包
|
||||
static SQInteger CUser_SendNotiPacket(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger Type1, Type2, Type3;
|
||||
sq_getinteger(v, 3, &Type1);
|
||||
sq_getinteger(v, 4, &Type2);
|
||||
sq_getinteger(v, 5, &Type3);
|
||||
CallUser<int>(0x867BA5C, P, Type1, Type2, Type3);
|
||||
return 0;
|
||||
}
|
||||
// 获取技能树
|
||||
static SQInteger CUser_GetSkillW(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
void *S = CallUser<void *>(0x822F140, P);
|
||||
sq_pushuserpointer(v, S);
|
||||
return 1;
|
||||
}
|
||||
// 重置技能
|
||||
static SQInteger CUser_InitSkillW(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger GrowType, IsAwa;
|
||||
sq_getinteger(v, 3, &GrowType);
|
||||
sq_getinteger(v, 4, &IsAwa);
|
||||
CallUser<int>(0x8608120, P, GrowType, IsAwa);
|
||||
return 0;
|
||||
}
|
||||
// 改变GM完成任务模式
|
||||
static SQInteger CUser_ChangeGmQuestFlag(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger Type;
|
||||
sq_getinteger(v, 3, &Type);
|
||||
|
||||
CallUser<int>(0x822FC8E, P, Type);
|
||||
return 0;
|
||||
}
|
||||
// 任务相关操作
|
||||
static SQInteger CUser_QuestAction(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger Type, QuestId, Reward, Flag;
|
||||
sq_getinteger(v, 3, &Type);
|
||||
sq_getinteger(v, 4, &QuestId);
|
||||
sq_getinteger(v, 5, &Reward);
|
||||
sq_getinteger(v, 6, &Flag);
|
||||
|
||||
CallUser<int>(0x0866DA8A, P, Type, QuestId, Reward, Flag);
|
||||
return 0;
|
||||
}
|
||||
// 刷新上次任务完成时间
|
||||
static SQInteger CUser_RefreshLastQuestTime(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
|
||||
*(int *)((void *)P + 0x79644) = 0;
|
||||
return 0;
|
||||
}
|
||||
// 充值点券
|
||||
static SQInteger CUser_RechargeCoupons(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer User;
|
||||
sq_getuserpointer(v, 2, &User);
|
||||
SQInteger Amount;
|
||||
sq_getinteger(v, 3, &Amount);
|
||||
CallUser<int>(0x80FFCA4, *(uintptr_t *)0x941F734, User, 5, Amount, (void *)0x8C7FA20, (void *)0x8C7FA20, "Gm", (void *)0, (void *)0, (void *)0);
|
||||
|
||||
CallUser<int>(0x8100790, *(uintptr_t *)0x941F734, User);
|
||||
return 0;
|
||||
}
|
||||
// 充值代币券
|
||||
static SQInteger CUser_RechargeCouponsPoint(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer User;
|
||||
sq_getuserpointer(v, 2, &User);
|
||||
SQInteger Amount;
|
||||
sq_getinteger(v, 3, &Amount);
|
||||
CallUser<int>(0x80FFFC0, *(uintptr_t *)0x941F734, User, Amount, 4, (void *)0, (void *)0);
|
||||
|
||||
CallUser<int>(0x8100790, *(uintptr_t *)0x941F734, User);
|
||||
return 0;
|
||||
}
|
||||
// 充值金币
|
||||
static SQInteger CUser_RechargeMoney(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer User;
|
||||
sq_getuserpointer(v, 2, &User);
|
||||
SQInteger Amount;
|
||||
sq_getinteger(v, 3, &Amount);
|
||||
CallUser<int>(0x84FF29C, User, Amount, 0, 0, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SQInteger register_User_func(HSQUIRRELVM v, SQFUNCTION f, const char *fname)
|
||||
{
|
||||
sq_pushroottable(v);
|
||||
sq_pushstring(v, fname, -1);
|
||||
sq_newclosure(v, f, 0); // create a new function
|
||||
sq_newslot(v, -3, SQFalse);
|
||||
sq_pop(v, 1); // pops the root table
|
||||
}
|
||||
|
||||
static void RegisterUser(HSQUIRRELVM v)
|
||||
{
|
||||
// 获取X坐标
|
||||
register_User_func(v, CUser_GetPosX, "Sq_CUser_GetPosX");
|
||||
// 获取Y坐标
|
||||
register_User_func(v, CUser_GetPosY, "Sq_CUser_GetPosY");
|
||||
// 获取朝向
|
||||
register_User_func(v, CUser_Direction, "Sq_CUser_Direction");
|
||||
// 获取城镇编号
|
||||
register_User_func(v, CUser_GetVill, "Sq_CUser_GetTownIndex");
|
||||
// 获取区域编号
|
||||
register_User_func(v, CUser_GetArea, "Sq_CUser_GetAreaIndex");
|
||||
// 获取账号状态
|
||||
register_User_func(v, CUser_GetState, "Sq_CUser_GetState");
|
||||
// 获取角色数量
|
||||
register_User_func(v, CUser_GetCharacCount, "Sq_CUser_GetCharacCount");
|
||||
// 获取UID
|
||||
register_User_func(v, CUser_GetAccId, "Sq_CUser_GetAccId");
|
||||
// 获取UniqueId
|
||||
register_User_func(v, CUser_GetUniqueId, "Sq_CUser_GetUniqueId");
|
||||
// 获取CID
|
||||
register_User_func(v, CUser_GetCharacNo, "Sq_CUser_GetCharacNo");
|
||||
// 获取角色职业
|
||||
register_User_func(v, CUser_GetCharacJob, "Sq_CUser_GetCharacJob");
|
||||
// 获取角色名称
|
||||
register_User_func(v, CUser_GetCharacName, "Sq_CUser_GetCharacName");
|
||||
// 获取角色等级
|
||||
register_User_func(v, CUser_GetCharacLevel, "Sq_CUser_GetCharacLevel");
|
||||
// 设置角色等级
|
||||
register_User_func(v, CUser_SetCharacLevel, "Sq_CUser_SetCharacLevel");
|
||||
// 获取角色转职职业
|
||||
register_User_func(v, CUser_GetCharacGrowType, "Sq_CUser_GetCharacGrowType");
|
||||
// 获取角色觉醒职业
|
||||
register_User_func(v, CUser_GetCharacSecondGrowType, "Sq_CUser_GetCharacSecondGrowType");
|
||||
// 获取已用疲劳值
|
||||
register_User_func(v, CUser_GetFatigue, "Sq_CUser_GetFatigue");
|
||||
// 获取最大疲劳值
|
||||
register_User_func(v, CUser_GetMaxFatigue, "Sq_CUser_GetMaxFatigue");
|
||||
// 踢人
|
||||
register_User_func(v, CUser_DisConnSig, "Sq_CUser_DisConnSig");
|
||||
// 获取当前小队/副本
|
||||
register_User_func(v, CUser_GetParty, "Sq_CUser_GetParty");
|
||||
// 获是否在领主塔
|
||||
register_User_func(v, CUser_CheckInBossTower, "Sq_CUser_CheckInBossTower");
|
||||
// 获取是否在龙之路
|
||||
register_User_func(v, CUser_CheckInBlueMarble, "Sq_CUser_CheckInBlueMarble");
|
||||
// 是否开启GM权限
|
||||
register_User_func(v, CUser_IsGmMode, "Sq_CUser_IsGmMode");
|
||||
// 获取可见Values
|
||||
register_User_func(v, CUser_GetVisibleValues, "Sq_CUser_GetVisibleValues");
|
||||
// 获取账号上次退出游戏的时间
|
||||
register_User_func(v, CUser_GetCurCharacLastPlayTick, "Sq_CUser_GetCurCharacLastPlayTick");
|
||||
// 发送道具
|
||||
register_User_func(v, CUser_GiveUserItem, "Sq_CUser_GiveUserItem");
|
||||
// 通知客户端更新背包
|
||||
register_User_func(v, CUser_SendItemSpace, "Sq_CUser_SendItemSpace");
|
||||
// 通知客户端道具更新
|
||||
register_User_func(v, CUser_SendUpdateItemList, "Sq_CUser_SendUpdateItemList");
|
||||
// 发送GM邮件
|
||||
register_User_func(v, CUser_SendMail, "Sq_CUser_SendMail");
|
||||
// 更改职业
|
||||
register_User_func(v, CUser_ChangeGrowType, "Sq_CUser_ChangeGrowType");
|
||||
// 发送消息包
|
||||
register_User_func(v, CUser_SendNotiPacket, "Sq_CUser_SendNotiPacket");
|
||||
// 获取技能树
|
||||
register_User_func(v, CUser_GetSkillW, "Sq_CUser_GetSkillW");
|
||||
// 重置技能树
|
||||
register_User_func(v, CUser_InitSkillW, "Sq_CUser_InitSkillW");
|
||||
// 改变GM完成任务模式
|
||||
register_User_func(v, CUser_ChangeGmQuestFlag, "Sq_CUser_ChangeGmQuestFlag");
|
||||
// 任务相关操作
|
||||
register_User_func(v, CUser_QuestAction, "Sq_CUser_QuestAction");
|
||||
// 刷新上次任务完成时间
|
||||
register_User_func(v, CUser_RefreshLastQuestTime, "Sq_CUser_RefreshLastQuestTime");
|
||||
// 充值点券
|
||||
register_User_func(v, CUser_RechargeCoupons, "Sq_CUser_RechargeCoupons");
|
||||
// 充值代币券
|
||||
register_User_func(v, CUser_RechargeCouponsPoint, "Sq_CUser_RechargeCouponsPoint");
|
||||
// 充值金币
|
||||
register_User_func(v, CUser_RechargeMoney, "Sq_CUser_RechargeMoney");
|
||||
}
|
||||
177
src/script/SqrReg_World.hpp
Normal file
177
src/script/SqrReg_World.hpp
Normal file
@@ -0,0 +1,177 @@
|
||||
#pragma once
|
||||
#include "squirrel.h"
|
||||
#include "sqstdaux.h"
|
||||
#include "sqstdblob.h"
|
||||
#include "sqstdio.h"
|
||||
#include "sqstdmath.h"
|
||||
#include "sqstdstring.h"
|
||||
#include "sqstdsystem.h"
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
|
||||
typedef void *(*__G_GameWorld)();
|
||||
static SQInteger Get_GameWorld(HSQUIRRELVM v)
|
||||
{
|
||||
void *World = ((__G_GameWorld)0x080DA3A7)();
|
||||
sq_pushuserpointer(v, World);
|
||||
return 1;
|
||||
}
|
||||
typedef int (*__GetSessionByUid)(void *World, int Uid);
|
||||
static SQInteger GameWorld_GetSessionByUid(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger Uid;
|
||||
sq_getinteger(v, 3, &Uid);
|
||||
|
||||
SQInteger Session = ((__GetSessionByUid)0x086C4C24)((void *)P, Uid);
|
||||
sq_pushinteger(v, Session);
|
||||
return 1;
|
||||
}
|
||||
typedef void *(*__GetUserBySession)(void *World, int Session);
|
||||
static SQInteger GameWorld_GetUserBySession(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger Session;
|
||||
sq_getinteger(v, 3, &Session);
|
||||
|
||||
void *User = ((__GetUserBySession)0x086C4B9C)((void *)P, Session);
|
||||
sq_pushuserpointer(v, User);
|
||||
return 1;
|
||||
}
|
||||
typedef void *(*__GetUserByUid)(void *World, int Uid);
|
||||
static SQInteger GameWorld_GetUserByUid(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQInteger Uid;
|
||||
sq_getinteger(v, 3, &Uid);
|
||||
|
||||
void *User = ((__GetUserByUid)0x086C4D40)((void *)P, Uid);
|
||||
sq_pushuserpointer(v, User);
|
||||
return 1;
|
||||
}
|
||||
typedef void *(*__GetUserByName)(void *World, char *Name);
|
||||
static SQInteger GameWorld_GetUserByName(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
const SQChar *Name;
|
||||
sq_getstring(v, 3, &Name);
|
||||
|
||||
void *User = ((__GetUserByName)0x086C9464)((void *)P, (char *)Name);
|
||||
sq_pushuserpointer(v, User);
|
||||
return 1;
|
||||
}
|
||||
typedef int (*__GetUserCount)(void *World);
|
||||
static SQInteger GameWorld_GetUserCount(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
|
||||
SQInteger Count = ((__GetUserCount)0x086C4550)((void *)P);
|
||||
sq_pushinteger(v, Count);
|
||||
return 1;
|
||||
}
|
||||
typedef void (*__SendAll)(void *World, void *Pack);
|
||||
static SQInteger GameWorld_SendAll(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQUserPointer Pck;
|
||||
sq_getuserpointer(v, 3, &Pck);
|
||||
|
||||
((__SendAll)0x086C8C14)((void *)P, (void *)Pck);
|
||||
return 0;
|
||||
}
|
||||
typedef void (*__SendPartyInfoToAll)(void *World, void *CParty, int code);
|
||||
static SQInteger GameWorld_SendPartyInfoToAll(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer World;
|
||||
sq_getuserpointer(v, 2, &World);
|
||||
SQUserPointer CParty;
|
||||
sq_getuserpointer(v, 3, &CParty);
|
||||
|
||||
((__SendPartyInfoToAll)0x086C878A)((void *)World, (void *)CParty, 0);
|
||||
return 0;
|
||||
}
|
||||
// typedef std::map<int, std::string> (*__GetUserIdList)(&std::vector<unsigned short> a1, int a2);
|
||||
// static SQInteger GetUserIdList(HSQUIRRELVM v)
|
||||
// {
|
||||
// SQInteger a1, a2;
|
||||
// sq_getinteger(v, 2, &a1);
|
||||
// sq_getinteger(v, 3, &a2);
|
||||
// std::vector<unsigned short> Qs;
|
||||
// std::map<int, std::string> Ret = ((__GetUserIdList)0x086C305E)(&Qs, a2);
|
||||
|
||||
// std::cout << Qs.size() << std::endl;
|
||||
// std::cout << Ret.size() << std::endl;
|
||||
// return 0;
|
||||
// }
|
||||
typedef void *(*__WorldMoveArea)(void *World, void *User, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int a10, int a11);
|
||||
static SQInteger GameWorld_MoveArea(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQUserPointer Player;
|
||||
sq_getuserpointer(v, 3, &Player);
|
||||
SQInteger TownIndex, AreaIndex, Xpos, Ypos;
|
||||
sq_getinteger(v, 4, &TownIndex);
|
||||
sq_getinteger(v, 5, &AreaIndex);
|
||||
sq_getinteger(v, 6, &Xpos);
|
||||
sq_getinteger(v, 7, &Ypos);
|
||||
|
||||
((__WorldMoveArea)0x86C5A84)((void *)P, (void *)Player, TownIndex, AreaIndex, Xpos, Ypos, 0, 0, 0, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
typedef void *(*__SendDungeonInOut)(void *World, void *User, int a3, bool a4);
|
||||
static SQInteger GameWorld_SendDungeonInOut(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer P;
|
||||
sq_getuserpointer(v, 2, &P);
|
||||
SQUserPointer Player;
|
||||
sq_getuserpointer(v, 3, &Player);
|
||||
SQInteger Index;
|
||||
SQBool Model;
|
||||
sq_getinteger(v, 4, &Index);
|
||||
sq_getbool(v, 5, &Model);
|
||||
|
||||
((__SendDungeonInOut)0x86C8FC8)((void *)P, (void *)Player, Index, Model);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SQInteger register_World_func(HSQUIRRELVM v, SQFUNCTION f, const char *fname)
|
||||
{
|
||||
sq_pushroottable(v);
|
||||
sq_pushstring(v, fname, -1);
|
||||
sq_newclosure(v, f, 0); // create a new function
|
||||
sq_newslot(v, -3, SQFalse);
|
||||
sq_pop(v, 1); // pops the root table
|
||||
}
|
||||
|
||||
static void RegisterWorld(HSQUIRRELVM v)
|
||||
{
|
||||
// 获取游戏世界
|
||||
register_World_func(v, Get_GameWorld, _SC("Sq_Get_GameWorld"));
|
||||
// 根据UID获取Session
|
||||
register_World_func(v, GameWorld_GetSessionByUid, _SC("Sq_GameWorld_GetSessionByUid"));
|
||||
// 根据Session获取玩家
|
||||
register_World_func(v, GameWorld_GetUserBySession, _SC("Sq_GameWorld_GetUserBySession"));
|
||||
// 根据UID获取玩家
|
||||
register_World_func(v, GameWorld_GetUserByUid, _SC("Sq_GameWorld_GetUserByUid"));
|
||||
// 根据名字获取玩家
|
||||
register_World_func(v, GameWorld_GetUserByName, _SC("Sq_GameWorld_GetUserByName"));
|
||||
// 获取玩家数量
|
||||
register_World_func(v, GameWorld_GetUserCount, _SC("Sq_GameWorld_GetUserCount"));
|
||||
// 给所有玩家发包
|
||||
register_World_func(v, GameWorld_SendAll, _SC("Sq_GameWorld_SendAll"));
|
||||
// 指定玩家移动
|
||||
register_World_func(v, GameWorld_MoveArea, _SC("Sq_GameWorld_MoveArea"));
|
||||
// 给所有玩家发送队伍包
|
||||
register_World_func(v, GameWorld_SendPartyInfoToAll, _SC("Sq_GameWorld_SendPartyInfoToAll"));
|
||||
// 副本开启或关闭消息
|
||||
register_World_func(v, GameWorld_SendDungeonInOut, _SC("Sq_GameWorld_SendDungeonInOut"));
|
||||
|
||||
// register_World_func(v, GetUserIdList, _SC("Sq_GetUserIdList"));
|
||||
}
|
||||
498
src/script/SqrReqScript.hpp
Normal file
498
src/script/SqrReqScript.hpp
Normal file
@@ -0,0 +1,498 @@
|
||||
#pragma once
|
||||
#include "BASE64.hpp"
|
||||
#include "Version.h"
|
||||
#include <asio.hpp>
|
||||
#include <asio/basic_socket_streambuf.hpp>
|
||||
#include <asio/ssl.hpp>
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <zlib.h>
|
||||
|
||||
|
||||
using namespace asio;
|
||||
using asio::ip::tcp;
|
||||
|
||||
// 单个字符解密
|
||||
static char CutcodeChar(char c, int key, int key2) {
|
||||
char a = (((c - 1) ^ key) ^ key2) - key;
|
||||
return a;
|
||||
}
|
||||
|
||||
// 解密
|
||||
void Cutecode(char *pstr, int *pkey, int len, int keyLength) {
|
||||
if (len == -1)
|
||||
len = strlen(pstr);
|
||||
for (int i = 0; i < len; i++) {
|
||||
*(pstr + i) = CutcodeChar(*(pstr + i), pkey[i % keyLength],
|
||||
pkey[(i + 18) % keyLength]);
|
||||
}
|
||||
}
|
||||
|
||||
// 加密函数
|
||||
static std::string r_encryptDecrypt(const std::string &input,
|
||||
const std::string &key) {
|
||||
std::string output = input;
|
||||
for (size_t i = 0; i < input.size(); i++) {
|
||||
output[i] = input[i] ^ key[i % key.size()]; // 使用异或运算进行加密
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
static std::string ReqScriptUrl(const std::vector<std::string> &domains) {
|
||||
for (const auto &domain : domains) {
|
||||
try {
|
||||
asio::io_context io_context;
|
||||
asio::ssl::context ctx(asio::ssl::context::tlsv12_client);
|
||||
ctx.set_verify_mode(asio::ssl::verify_none);
|
||||
// 启用 TLS 1.0/1.1/1.2/1.3 支持
|
||||
ctx.set_options(asio::ssl::context::default_workarounds |
|
||||
asio::ssl::context::no_sslv2 |
|
||||
asio::ssl::context::no_sslv3 |
|
||||
asio::ssl::context::single_dh_use);
|
||||
|
||||
asio::ssl::stream<asio::ip::tcp::socket> socket(io_context, ctx);
|
||||
|
||||
// 设置 SNI
|
||||
if (!SSL_set_tlsext_host_name(socket.native_handle(), domain.c_str())) {
|
||||
asio::error_code ec{static_cast<int>(::ERR_get_error()),
|
||||
asio::error::get_ssl_category()};
|
||||
throw asio::system_error{ec};
|
||||
}
|
||||
|
||||
asio::ip::tcp::resolver resolver(io_context);
|
||||
auto endpoints = resolver.resolve(domain, "https");
|
||||
|
||||
// 连接超时设置
|
||||
bool connect_timeout = false;
|
||||
asio::steady_timer connect_timer(io_context);
|
||||
connect_timer.expires_from_now(std::chrono::seconds(10));
|
||||
connect_timer.async_wait([&](const asio::error_code &ec) {
|
||||
if (!ec) {
|
||||
connect_timeout = true;
|
||||
socket.lowest_layer().close();
|
||||
}
|
||||
});
|
||||
|
||||
asio::error_code connect_ec;
|
||||
asio::async_connect(socket.lowest_layer(), endpoints,
|
||||
[&](asio::error_code ec, asio::ip::tcp::endpoint) {
|
||||
connect_ec = ec;
|
||||
connect_timer.cancel();
|
||||
});
|
||||
|
||||
io_context.run();
|
||||
io_context.reset();
|
||||
|
||||
if (connect_timeout) {
|
||||
throw std::runtime_error("连接超时");
|
||||
}
|
||||
|
||||
if (connect_ec) {
|
||||
throw std::system_error(connect_ec);
|
||||
}
|
||||
|
||||
// SSL握手超时设置
|
||||
bool handshake_timeout = false;
|
||||
asio::steady_timer handshake_timer(io_context);
|
||||
handshake_timer.expires_from_now(std::chrono::seconds(10));
|
||||
handshake_timer.async_wait([&](const asio::error_code &ec) {
|
||||
if (!ec) {
|
||||
handshake_timeout = true;
|
||||
socket.lowest_layer().close();
|
||||
}
|
||||
});
|
||||
|
||||
asio::error_code handshake_ec;
|
||||
socket.async_handshake(asio::ssl::stream_base::client,
|
||||
[&](asio::error_code ec) {
|
||||
handshake_ec = ec;
|
||||
handshake_timer.cancel();
|
||||
});
|
||||
|
||||
io_context.run();
|
||||
io_context.reset();
|
||||
|
||||
if (handshake_timeout) {
|
||||
throw std::runtime_error("SSL握手超时");
|
||||
}
|
||||
|
||||
if (handshake_ec) {
|
||||
throw std::system_error(handshake_ec);
|
||||
}
|
||||
std::string request = "POST /script/getservicenew HTTP/1.1\r\n";
|
||||
request += "Host: " + domain + "\r\n";
|
||||
request += "ve: " + std::string(DPS_SCRIPT_VERSION) + "\r\n";
|
||||
request += "Content-Length: 0\r\n";
|
||||
request += "Content-Type: application/x-www-form-urlencoded\r\n";
|
||||
request += "Connection: close\r\n";
|
||||
request += "\r\n";
|
||||
|
||||
asio::write(socket, asio::buffer(request));
|
||||
|
||||
// 响应超时设置
|
||||
bool response_timeout = false;
|
||||
asio::steady_timer response_timer(io_context);
|
||||
response_timer.expires_from_now(std::chrono::seconds(10));
|
||||
response_timer.async_wait([&](const asio::error_code &ec) {
|
||||
if (!ec) {
|
||||
response_timeout = true;
|
||||
socket.lowest_layer().close();
|
||||
}
|
||||
});
|
||||
|
||||
asio::streambuf response;
|
||||
asio::error_code read_ec;
|
||||
asio::async_read(socket, response, [&](asio::error_code ec, std::size_t) {
|
||||
read_ec = ec;
|
||||
response_timer.cancel();
|
||||
});
|
||||
|
||||
io_context.run();
|
||||
|
||||
if (response_timeout) {
|
||||
throw std::runtime_error("响应超时");
|
||||
}
|
||||
|
||||
if (read_ec && read_ec != asio::error::eof) {
|
||||
throw std::system_error(read_ec);
|
||||
}
|
||||
|
||||
// 解析响应头部
|
||||
std::istream response_stream(&response);
|
||||
std::string http_version;
|
||||
unsigned int status_code;
|
||||
std::string status_message;
|
||||
|
||||
response_stream >> http_version >> status_code;
|
||||
std::getline(response_stream, status_message); // 读取状态行剩余部分
|
||||
response_stream.ignore(); // 跳过状态行后的换行符
|
||||
|
||||
// 读取并解析头部字段
|
||||
std::string header_line;
|
||||
std::map<std::string, std::string> headers;
|
||||
while (std::getline(response_stream, header_line) &&
|
||||
header_line != "\r") {
|
||||
// 去掉行末的\r
|
||||
if (!header_line.empty() &&
|
||||
header_line[header_line.size() - 1] == '\r') {
|
||||
header_line.resize(header_line.size() - 1);
|
||||
}
|
||||
|
||||
// 分割头部字段
|
||||
size_t colon_pos = header_line.find(':');
|
||||
if (colon_pos != std::string::npos) {
|
||||
std::string key = header_line.substr(0, colon_pos);
|
||||
std::string value = header_line.substr(colon_pos + 1);
|
||||
|
||||
// 去除值前面的空格
|
||||
size_t start = value.find_first_not_of(" \t");
|
||||
if (start != std::string::npos) {
|
||||
value = value.substr(start);
|
||||
}
|
||||
|
||||
headers[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
if (status_code == 200) {
|
||||
// 读取响应体(根据Content-Length)
|
||||
size_t content_length = 0;
|
||||
auto cl_it = headers.find("Content-Length");
|
||||
if (cl_it != headers.end()) {
|
||||
content_length = std::stoul(cl_it->second);
|
||||
}
|
||||
|
||||
// 计算剩余需要读取的字节数
|
||||
size_t bytes_read = response.size();
|
||||
size_t bytes_to_read =
|
||||
content_length > bytes_read ? content_length - bytes_read : 0;
|
||||
|
||||
if (bytes_to_read > 0) {
|
||||
// 继续读取剩余数据
|
||||
response_timer.expires_from_now(std::chrono::seconds(10));
|
||||
response_timer.async_wait([&](const asio::error_code &ec) {
|
||||
if (!ec) {
|
||||
response_timeout = true;
|
||||
socket.lowest_layer().close();
|
||||
}
|
||||
});
|
||||
|
||||
asio::error_code read_body_ec;
|
||||
asio::async_read(socket, response,
|
||||
asio::transfer_exactly(bytes_to_read),
|
||||
[&](asio::error_code ec, std::size_t) {
|
||||
read_body_ec = ec;
|
||||
response_timer.cancel();
|
||||
});
|
||||
|
||||
io_context.run();
|
||||
|
||||
if (response_timeout) {
|
||||
throw std::runtime_error("读取响应体超时");
|
||||
}
|
||||
|
||||
if (read_body_ec && read_body_ec != asio::error::eof) {
|
||||
throw std::system_error(read_body_ec);
|
||||
}
|
||||
}
|
||||
|
||||
// 提取响应体字符串
|
||||
std::istreambuf_iterator<char> eos;
|
||||
std::string response_body(
|
||||
std::istreambuf_iterator<char>(response_stream), eos);
|
||||
return response_body;
|
||||
} else {
|
||||
std::cerr << "错误的请求 " << domain
|
||||
<< " failed with status code: " << status_code << std::endl;
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
std::cerr << "错误的连接 " << domain << ": " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
static std::string make_request(const std::string &host,
|
||||
const std::string &port,
|
||||
const std::string &path) {
|
||||
asio::io_context io_context;
|
||||
tcp::resolver resolver(io_context);
|
||||
tcp::resolver::results_type endpoints = resolver.resolve(host, port);
|
||||
|
||||
tcp::socket socket(io_context);
|
||||
asio::connect(socket, endpoints);
|
||||
|
||||
// Form the request. We specify the "Connection: close" header so that the
|
||||
// server will close the socket after transmitting the response. This
|
||||
// will allow us to treat all data up until the EOF as the content.
|
||||
std::string request = "GET " + path + " HTTP/1.1\r\n";
|
||||
request += "Host: " + host + "\r\n";
|
||||
request += "Connection: close\r\n\r\n";
|
||||
|
||||
// Send the request.
|
||||
asio::write(socket, asio::buffer(request));
|
||||
|
||||
// Read the response status line. The response streambuf will automatically
|
||||
// grow to accommodate the entire line. The growth may be limited by passing
|
||||
// a maximum size to the streambuf constructor.
|
||||
asio::streambuf response;
|
||||
asio::read_until(socket, response, "\r\n");
|
||||
|
||||
// Check that response is OK.
|
||||
std::istream response_stream(&response);
|
||||
std::string http_version;
|
||||
response_stream >> http_version;
|
||||
unsigned int status_code;
|
||||
response_stream >> status_code;
|
||||
std::string status_message;
|
||||
std::getline(response_stream, status_message);
|
||||
if (!response_stream || http_version.substr(0, 5) != "HTTP/") {
|
||||
throw std::runtime_error("Invalid response");
|
||||
}
|
||||
if (status_code != 200) {
|
||||
throw std::runtime_error("Response returned with status code " +
|
||||
std::to_string(status_code));
|
||||
}
|
||||
|
||||
// Read the response headers, which are terminated by a blank line.
|
||||
asio::read_until(socket, response, "\r\n\r\n");
|
||||
|
||||
// Process the response headers.
|
||||
std::string header;
|
||||
while (std::getline(response_stream, header) && header != "\r") {
|
||||
// std::cout << header << "\n";
|
||||
}
|
||||
// std::cout << "\n";
|
||||
|
||||
// Write whatever content we already have to output.
|
||||
std::ostringstream response_body;
|
||||
if (response.size() > 0) {
|
||||
response_body << &response;
|
||||
}
|
||||
|
||||
// Read until EOF, writing data to output as we go.
|
||||
asio::error_code error;
|
||||
while (asio::read(socket, response, asio::transfer_at_least(1), error)) {
|
||||
response_body << &response;
|
||||
}
|
||||
if (error != asio::error::eof) {
|
||||
throw asio::system_error(error);
|
||||
}
|
||||
|
||||
return response_body.str();
|
||||
}
|
||||
|
||||
static std::string ReqScript(std::string url) {
|
||||
std::vector<std::string> UrlData;
|
||||
Tool::Split(url, UrlData, ",");
|
||||
try {
|
||||
std::string host = UrlData[0];
|
||||
std::string port = UrlData[1];
|
||||
std::string path = "/" + UrlData[2];
|
||||
|
||||
std::string response = make_request(host, port, path);
|
||||
// std::cout << "Response body:\n"
|
||||
// << response << "\n";
|
||||
|
||||
return response;
|
||||
} catch (std::exception &e) {
|
||||
// std::cerr << "Exception: " << e.what() << "\n";
|
||||
return "null";
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<unsigned char> base64_decode(const std::string &encoded) {
|
||||
BIO *bio, *b64;
|
||||
std::vector<unsigned char> result(encoded.size());
|
||||
|
||||
b64 = BIO_new(BIO_f_base64());
|
||||
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
|
||||
|
||||
bio = BIO_new_mem_buf(encoded.c_str(), encoded.size());
|
||||
bio = BIO_push(b64, bio);
|
||||
|
||||
int len = BIO_read(bio, result.data(), encoded.size());
|
||||
result.resize(len);
|
||||
|
||||
BIO_free_all(bio);
|
||||
return result;
|
||||
}
|
||||
|
||||
// zlib解压函数
|
||||
static std::string gzip_decompress(std::vector<unsigned char> compressed) {
|
||||
z_stream zs;
|
||||
memset(&zs, 0, sizeof(zs));
|
||||
|
||||
if (inflateInit2(&zs, 16 + MAX_WBITS) != Z_OK) {
|
||||
// throw std::runtime_error("inflateInit failed");
|
||||
return "null";
|
||||
}
|
||||
|
||||
zs.next_in = (Bytef *)compressed.data();
|
||||
zs.avail_in = compressed.size();
|
||||
|
||||
int ret;
|
||||
char outbuffer[32768];
|
||||
std::string outstring;
|
||||
|
||||
do {
|
||||
zs.next_out = reinterpret_cast<Bytef *>(outbuffer);
|
||||
zs.avail_out = sizeof(outbuffer);
|
||||
|
||||
ret = inflate(&zs, 0);
|
||||
|
||||
if (outstring.size() < zs.total_out) {
|
||||
outstring.append(outbuffer, zs.total_out - outstring.size());
|
||||
}
|
||||
|
||||
} while (ret == Z_OK);
|
||||
|
||||
inflateEnd(&zs);
|
||||
|
||||
if (ret != Z_STREAM_END) {
|
||||
// throw std::runtime_error("Exception during zlib decompression: (" +
|
||||
// std::to_string(ret) + ") " + zs.msg);
|
||||
return "null";
|
||||
}
|
||||
|
||||
return outstring;
|
||||
}
|
||||
|
||||
static std::string rsaDecrypt(std::vector<unsigned char> encryptedData,
|
||||
const std::string &publicKeyStr) {
|
||||
RSA *rsa = RSA_new();
|
||||
BIO *bio = BIO_new_mem_buf(const_cast<char *>(publicKeyStr.c_str()), -1);
|
||||
PEM_read_bio_RSA_PUBKEY(bio, &rsa, NULL, NULL);
|
||||
|
||||
int rsaSize = RSA_size(rsa);
|
||||
std::string decryptedData(rsaSize, 0);
|
||||
|
||||
int decryptedSize =
|
||||
RSA_public_decrypt(encryptedData.size(), encryptedData.data(),
|
||||
reinterpret_cast<unsigned char *>(&decryptedData[0]),
|
||||
rsa, RSA_PKCS1_PADDING);
|
||||
|
||||
if (decryptedSize == -1) {
|
||||
std::cerr << "Error decrypting data" << std::endl;
|
||||
return "";
|
||||
}
|
||||
|
||||
RSA_free(rsa);
|
||||
BIO_free(bio);
|
||||
|
||||
decryptedData.resize(decryptedSize);
|
||||
return decryptedData;
|
||||
}
|
||||
|
||||
static void ReqSquirrelScript(HSQUIRRELVM v) {
|
||||
std::vector<std::string> domains = {"dps.senzo.online"};
|
||||
std::string StrBuf = ReqScriptUrl(domains);
|
||||
std::vector<unsigned char> compressed = base64_decode(StrBuf);
|
||||
std::string original_data = gzip_decompress(compressed);
|
||||
nlohmann::json Jso = nlohmann::json::parse(original_data);
|
||||
|
||||
std::string Key = Jso["key"].dump();
|
||||
|
||||
Key = Key.substr(1, Key.length() - 2);
|
||||
std::string Script = Jso["getBaseScriptStr"].dump();
|
||||
Script = Script.substr(1, Script.length() - 2);
|
||||
|
||||
std::string pub = R"(-----BEGIN PUBLIC KEY-----
|
||||
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDafyp7gGautPZZ3I3IlYLf8Qyw
|
||||
xGigvg0rkmXPaP34C6sHi//GLuYjwM6AUJTtbfo0pCNmLqBbCiiuzkBXEqM+GeS2
|
||||
+7zhu1yeEXv+i9iySFPbYydy851uVip7oqsbNM4iGYpS5ERND9XYuhSGUFI5p9ik
|
||||
Nsvz+z7r4iT2rd8vrwIDAQAB
|
||||
-----END PUBLIC KEY-----)";
|
||||
|
||||
std::string KeyString = rsaDecrypt(base64_decode(Key), pub);
|
||||
std::vector<std::string> BaseDataBuffer;
|
||||
Tool::Split(Script, BaseDataBuffer, "$$$$$");
|
||||
size_t Ds = BaseDataBuffer.size();
|
||||
|
||||
int RealKey[20] = {0};
|
||||
// 转换字符串到数组
|
||||
for (size_t i = 0; i < KeyString.length() && i < 20; ++i) {
|
||||
RealKey[i] = KeyString[i] - '0'; // 将字符转换为对应的数字
|
||||
}
|
||||
|
||||
std::vector<std::string> BaseData;
|
||||
|
||||
for (size_t i = 0; i < (Ds - 1); i++) {
|
||||
std::string str = BaseDataBuffer[i];
|
||||
|
||||
if (i % 2 != 0) {
|
||||
// 得到有多少个逗号
|
||||
std::vector<std::string> Data;
|
||||
Tool::Split(str, Data, ", ");
|
||||
size_t DDs = Data.size();
|
||||
char *nutstr = new char[DDs + 1];
|
||||
for (size_t s = 0; s < DDs; s++) {
|
||||
nutstr[s] = char(atoi(Data[s].c_str()));
|
||||
}
|
||||
Cutecode(nutstr, RealKey, DDs, 20); // 解密
|
||||
nutstr[DDs] = '\0';
|
||||
|
||||
std::string RealStr(nutstr, DDs + 1);
|
||||
delete[] nutstr;
|
||||
BaseData.push_back(RealStr);
|
||||
} else {
|
||||
BaseData.push_back(str);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < BaseData.size(); i += 2) {
|
||||
std::string Path = BaseData[i];
|
||||
std::string Script = BaseData[i + 1];
|
||||
|
||||
// std::cout << Path << std::endl;
|
||||
if (SQ_SUCCEEDED(sq_compilebuffer(v, (SQChar *)(Script.c_str()),
|
||||
Script.length(), (SQChar *)(Path.c_str()),
|
||||
true))) {
|
||||
sq_pushroottable(v);
|
||||
sq_call(v, 1, 1, 1);
|
||||
sq_pop(v, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
501
src/script/l_squirrel.cpp
Normal file
501
src/script/l_squirrel.cpp
Normal file
@@ -0,0 +1,501 @@
|
||||
#include "l_squirrel.h"
|
||||
#include "l_squirrel_register.hpp"
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||
#include <spdlog/sinks/basic_file_sink.h>
|
||||
#include <iostream>
|
||||
#include <ctime>
|
||||
#include <sstream>
|
||||
#include <chrono>
|
||||
#include "SqrReqScript.hpp"
|
||||
#include "Dio.hpp"
|
||||
#include <sys/wait.h>
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#define WEBSCRIPT true;
|
||||
|
||||
using asio::ip::tcp;
|
||||
|
||||
static char szGamePathA[256];
|
||||
void setupLogger()
|
||||
{
|
||||
getConfigPath(szGamePathA, sizeof(szGamePathA));
|
||||
std::string Path = std::string(szGamePathA);
|
||||
std::string log_filename = "log/dps_log/" + Path.substr(Path.find("cfg") + 4) + "/log_";
|
||||
char time_buffer[100];
|
||||
std::time_t now = std::time(nullptr);
|
||||
std::tm* local_time = std::localtime(&now);
|
||||
strftime(time_buffer, sizeof(time_buffer), "%Y-%m-%d_%H-%M-%S", local_time);
|
||||
log_filename += std::string(time_buffer) + ".txt";
|
||||
|
||||
auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
|
||||
console_sink->set_level(spdlog::level::info);
|
||||
console_sink->set_pattern("[multi_sink_example] [%^%l%$] %v");
|
||||
|
||||
auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(log_filename, true);
|
||||
file_sink->set_level(spdlog::level::info);
|
||||
file_sink->set_pattern("[%Y-%m-%d %H:%M:%S] [%^%l%$] %v");
|
||||
|
||||
auto logger = std::make_shared<spdlog::logger>("logger", spdlog::sinks_init_list{ console_sink, file_sink });
|
||||
logger->set_level(spdlog::level::info);
|
||||
logger->flush_on(spdlog::level::info);
|
||||
|
||||
// logger->info("欢迎使用Dps插件");
|
||||
|
||||
spdlog::register_logger(logger);
|
||||
spdlog::set_default_logger(logger);
|
||||
}
|
||||
|
||||
// 虚拟机对象
|
||||
HSQUIRRELVM v;
|
||||
// Lock
|
||||
std::recursive_mutex SqMtx;
|
||||
|
||||
static void printfunc(HSQUIRRELVM v, const SQChar* s, ...)
|
||||
{
|
||||
va_list vl;
|
||||
va_start(vl, s);
|
||||
char buf[1024];
|
||||
vsnprintf(buf, sizeof(buf), s, vl);
|
||||
va_end(vl);
|
||||
|
||||
spdlog::info(buf);
|
||||
}
|
||||
|
||||
static void errorfunc(HSQUIRRELVM v, const SQChar* s, ...)
|
||||
{
|
||||
va_list vl;
|
||||
va_start(vl, s);
|
||||
char buf[1024];
|
||||
vsnprintf(buf, sizeof(buf), s, vl);
|
||||
va_end(vl);
|
||||
|
||||
spdlog::error(buf);
|
||||
}
|
||||
|
||||
// 加密函数
|
||||
static std::string encryptDecrypt(const std::string& input, const std::string& key)
|
||||
{
|
||||
std::string output = input;
|
||||
for (size_t i = 0; i < input.size(); i++)
|
||||
{
|
||||
output[i] = input[i] ^ key[i % key.size()]; // 使用异或运算进行加密
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
// 判断是否处理加密
|
||||
static std::string IsencryptDecrypt(const std::string& input, const std::string& FileName)
|
||||
{
|
||||
if (FileName.find(".nut") != std::string::npos)
|
||||
return input;
|
||||
else
|
||||
return encryptDecrypt(input, "Rindro-Aurora");
|
||||
}
|
||||
|
||||
static void ReloadingScript(HSQUIRRELVM v, std::string FilePath)
|
||||
{
|
||||
// 爬取出所有的脚本文件
|
||||
std::vector<std::string> vec = Tool::GetListFilesR(FilePath);
|
||||
std::vector<std::pair<std::string, std::string>> SquirrelFilePath;
|
||||
// std::map<std::string, std::string>SquirrelFilePath;
|
||||
|
||||
for (auto it = vec.cbegin(); it != vec.cend(); ++it)
|
||||
{
|
||||
std::string FileName = FilePath + *it;
|
||||
// std::cout << FileName << std::endl;
|
||||
if (FileName.find(".nut") == std::string::npos && FileName.find(".sut") == std::string::npos)
|
||||
continue;
|
||||
std::fstream F;
|
||||
F.open((FileName).c_str(), std::ios::in);
|
||||
std::stringstream ContentStringStream;
|
||||
ContentStringStream << F.rdbuf();
|
||||
std::string ContentString(ContentStringStream.str());
|
||||
F.close();
|
||||
std::string RealContentString = IsencryptDecrypt(ContentString, FileName);
|
||||
SquirrelFilePath.push_back({ FileName, RealContentString });
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> SquirrelLastFilePath;
|
||||
|
||||
for (auto it = SquirrelFilePath.begin(); it != SquirrelFilePath.end(); it++)
|
||||
{
|
||||
std::string Sourcename = it->first;
|
||||
std::string ContentString = it->second;
|
||||
if (SQ_SUCCEEDED(sq_compilebuffer(v, (SQChar*)(ContentString.c_str()), ContentString.length(), (SQChar*)(Sourcename.c_str()), true)))
|
||||
{
|
||||
sq_pushroottable(v);
|
||||
sq_call(v, 1, 1, 1);
|
||||
sq_pop(v, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
SquirrelLastFilePath[Sourcename] = ContentString;
|
||||
}
|
||||
}
|
||||
|
||||
while (SquirrelLastFilePath.size() > 0)
|
||||
{
|
||||
std::map<std::string, std::string> FailMapBuffer;
|
||||
for (auto it = SquirrelLastFilePath.begin(); it != SquirrelLastFilePath.end(); it++)
|
||||
{
|
||||
std::string Sourcename = it->first;
|
||||
std::string ContentString = it->second;
|
||||
|
||||
if (SQ_SUCCEEDED(sq_compilebuffer(v, (SQChar*)(ContentString.c_str()), ContentString.length(), (SQChar*)(Sourcename.c_str()), true)))
|
||||
{
|
||||
sq_pushroottable(v);
|
||||
if (SQ_FAILED(sq_call(v, 1, 1, 1)))
|
||||
{
|
||||
FailMapBuffer[Sourcename] = ContentString;
|
||||
};
|
||||
sq_pop(v, 1);
|
||||
};
|
||||
}
|
||||
|
||||
SquirrelLastFilePath.clear();
|
||||
if (FailMapBuffer.size() > 0)
|
||||
{
|
||||
for (auto it = FailMapBuffer.begin(); it != FailMapBuffer.end(); it++)
|
||||
{
|
||||
std::string Sourcename = it->first;
|
||||
std::string ContentString = it->second;
|
||||
SquirrelLastFilePath[Sourcename] = ContentString;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 十六进制字符串转字节数组(完整实现)
|
||||
std::vector<unsigned char> hex_to_bytes(const std::string& hex_str) {
|
||||
std::vector<unsigned char> bytes;
|
||||
// 检查Hex字符串长度是否为偶数
|
||||
if (hex_str.size() % 2 != 0) {
|
||||
throw std::invalid_argument("Hex string length must be even");
|
||||
}
|
||||
// 逐字节转换
|
||||
for (size_t i = 0; i < hex_str.size(); i += 2) {
|
||||
std::string byte_str = hex_str.substr(i, 2);
|
||||
char* end_ptr;
|
||||
unsigned long byte_val = strtol(byte_str.c_str(), &end_ptr, 16);
|
||||
// 验证转换有效性
|
||||
if (*end_ptr != '\0' || byte_val > 0xFF) {
|
||||
throw std::invalid_argument("Invalid hex character: " + byte_str);
|
||||
}
|
||||
bytes.push_back(static_cast<unsigned char>(byte_val));
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
// 移除PKCS5Padding填充
|
||||
std::string unpad_pkcs5(const std::string& data) {
|
||||
if (data.empty()) return "";
|
||||
unsigned char pad_len = data.back();
|
||||
// 验证填充合法性:填充长度需≤块大小,且所有填充字节一致
|
||||
if (pad_len > AES_BLOCK_SIZE || pad_len == 0) return data;
|
||||
for (size_t i = data.size() - pad_len; i < data.size(); ++i) {
|
||||
if (static_cast<unsigned char>(data[i]) != pad_len) {
|
||||
return data; // 填充非法,返回原数据
|
||||
}
|
||||
}
|
||||
return data.substr(0, data.size() - pad_len);
|
||||
}
|
||||
|
||||
// AES-ECB解密(输入:二进制数据;密钥:固定字节数组)
|
||||
std::string aes_ecb_decrypt(const std::vector<unsigned char>& encrypted_data) {
|
||||
// 用户提供的密钥(16字节,AES-128)
|
||||
const signed char keyBytes[] = { 92, -2, -65, 10, 118, 103, -68, 72, -23, 124, -103, -39, 0, -128, 31, -107 };
|
||||
const int key_len = sizeof(keyBytes);
|
||||
|
||||
// 初始化AES解密密钥
|
||||
AES_KEY aes_key;
|
||||
if (AES_set_decrypt_key(reinterpret_cast<const unsigned char*>(keyBytes),
|
||||
key_len * 8, // 16*8=128位
|
||||
&aes_key) != 0) {
|
||||
throw std::runtime_error("Invalid AES key");
|
||||
}
|
||||
|
||||
// ECB模式分块解密(AES块大小16字节)
|
||||
size_t data_len = encrypted_data.size();
|
||||
std::vector<unsigned char> decrypt_buf(data_len);
|
||||
for (size_t i = 0; i < data_len; i += AES_BLOCK_SIZE) {
|
||||
// 最后一块不足16字节时补0(ECB要求块对齐,实际加密数据应为块大小整数倍)
|
||||
unsigned char block[AES_BLOCK_SIZE] = { 0 };
|
||||
memcpy(block, encrypted_data.data() + i,
|
||||
std::min(static_cast<size_t>(AES_BLOCK_SIZE), data_len - i));
|
||||
|
||||
AES_ecb_encrypt(block, decrypt_buf.data() + i, &aes_key, AES_DECRYPT);
|
||||
}
|
||||
|
||||
// 移除PKCS5填充并返回字符串
|
||||
return unpad_pkcs5(std::string(reinterpret_cast<char*>(decrypt_buf.data()), data_len));
|
||||
}
|
||||
|
||||
static void LoadScript(HSQUIRRELVM v, bool Flag) {
|
||||
|
||||
std::ifstream f("/dp_s/_DPS_/FileConfig.json");
|
||||
nlohmann::json Jso = nlohmann::json::parse(f);
|
||||
f.close();
|
||||
|
||||
//加载基础脚本
|
||||
for (const auto& elem : Jso["BaseScript"]) {
|
||||
if (elem.is_string()) {
|
||||
std::string line = elem.get<std::string>();
|
||||
std::string file_path = "/dp_s/_DPS_/_Core/" + line;
|
||||
|
||||
// 以二进制模式打开加密文件
|
||||
std::ifstream F(file_path, std::ios::binary | std::ios::in);
|
||||
if (!F.is_open()) {
|
||||
spdlog::error("无法打开脚本文件: {}", file_path);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 直接读取二进制数据到vector<unsigned char>
|
||||
std::vector<unsigned char> encrypted_data(
|
||||
(std::istreambuf_iterator<char>(F)),
|
||||
std::istreambuf_iterator<char>()
|
||||
);
|
||||
F.close();
|
||||
|
||||
std::string ContentString;
|
||||
//外网解密版本
|
||||
if (!Flag) {
|
||||
try {
|
||||
// 直接解密二进制数据
|
||||
ContentString = aes_ecb_decrypt(encrypted_data);
|
||||
if (ContentString.empty()) {
|
||||
spdlog::warn("解密结果为空: {}", file_path);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
catch (const std::runtime_error& e) {
|
||||
spdlog::error("AES解密失败 {}: {}", file_path, e.what());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
//本地不解密版本
|
||||
else {
|
||||
ContentString = std::string(reinterpret_cast<const char*>(encrypted_data.data()), encrypted_data.size());
|
||||
}
|
||||
|
||||
|
||||
if (SQ_SUCCEEDED(sq_compilebuffer(v, (SQChar*)(ContentString.c_str()), ContentString.length(), (SQChar*)(line.c_str()), true)))
|
||||
{
|
||||
sq_pushroottable(v);
|
||||
sq_call(v, 1, SQTrue, SQFalse);
|
||||
sq_pop(v, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
//加载项目脚本
|
||||
for (const auto& elem : Jso["ProjectScript"]) {
|
||||
for (const auto& path : elem["Script"]) {
|
||||
if (path.is_string()) {
|
||||
std::string line = path.get<std::string>();
|
||||
std::string ContentString = "";
|
||||
std::fstream F;
|
||||
F.open(("/dp_s/_DPS_/_BuiltProject/" + line).c_str(), std::ios::in);
|
||||
if (F.is_open()) {
|
||||
std::stringstream ContentStringStream;
|
||||
ContentStringStream << F.rdbuf();
|
||||
ContentString = (ContentStringStream.str());
|
||||
F.close();
|
||||
}
|
||||
if (SQ_SUCCEEDED(sq_compilebuffer(v, (SQChar*)(ContentString.c_str()), ContentString.length(), (SQChar*)(line.c_str()), true)))
|
||||
{
|
||||
sq_pushroottable(v);
|
||||
sq_call(v, 1, SQTrue, SQFalse);
|
||||
sq_pop(v, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static SQInteger SqReloadScript(HSQUIRRELVM v)
|
||||
{
|
||||
|
||||
if ((access("/dp_s/lib/db.ini", F_OK) != -1))
|
||||
{
|
||||
LoadScript(v, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
LoadScript(v, false);
|
||||
//读取网络单发脚本
|
||||
ReqSquirrelScript(v);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static std::string GetLocalScriptVersion() {
|
||||
std::ifstream file("/dp_s/_DPS_/version"); // 打开文件
|
||||
if (!file.is_open()) { // 检查文件是否成功打开
|
||||
return "-1";
|
||||
}
|
||||
std::string content((std::istreambuf_iterator<char>(file)),
|
||||
std::istreambuf_iterator<char>());
|
||||
content.pop_back();
|
||||
return content;
|
||||
}
|
||||
|
||||
static std::string GetRemoteScriptVersion() {
|
||||
|
||||
try {
|
||||
asio::io_context io_context;
|
||||
HttpsClient client(io_context);
|
||||
// 配置GET请求
|
||||
std::map<std::string, std::string> headers = {
|
||||
{"User-Agent", "AsioHttpsClient/Sync"},
|
||||
{"Accept", "application/json"},
|
||||
{"Content-Type", "application/json"} // POST必须的头
|
||||
};
|
||||
client.setRequest("dps.senzo.online", "/script/getBaseUpdateTime", "POST", "", headers);
|
||||
|
||||
// 同步发送请求(阻塞等待结果)
|
||||
HttpsClient::SyncResponse res = client.sendRequestSync();
|
||||
|
||||
// 处理结果
|
||||
if (res.error.empty()) {
|
||||
spdlog::info("获取到服务器最新脚本,版本为:{}", res.response);
|
||||
return res.response;
|
||||
}
|
||||
else {
|
||||
spdlog::info("请求服务器最新脚本失败,使用本地缓存脚本! 错误原因: {}", res.error);
|
||||
return "error";
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
spdlog::info("请求服务器最新脚本失败,使用本地缓存脚本! 错误原因: {}", e.what());
|
||||
return "error";
|
||||
}
|
||||
}
|
||||
|
||||
int executeCommand(const std::string& cmd) {
|
||||
pid_t pid = fork();
|
||||
if (pid == -1) return -1;
|
||||
|
||||
if (pid == 0) { // 子进程
|
||||
// 清除LD_PRELOAD
|
||||
unsetenv("LD_PRELOAD");
|
||||
// 执行命令(需拆分命令和参数)
|
||||
execl("/bin/sh", "sh", "-c", cmd.c_str(), nullptr);
|
||||
exit(1); // 若exec失败
|
||||
}
|
||||
|
||||
// 父进程等待子进程结束
|
||||
int status;
|
||||
waitpid(pid, &status, 0);
|
||||
return WEXITSTATUS(status);
|
||||
}
|
||||
|
||||
static void DownLoadScript(std::string RemoteVersion) {
|
||||
try {
|
||||
asio::io_context io_context;
|
||||
HttpsClient client(io_context);
|
||||
|
||||
// 设置下载请求
|
||||
client.setRequest("dps.senzo.online", "/script/getBaseSutZip", "GET");
|
||||
|
||||
// 下载文件
|
||||
HttpsClient::FileDownloadResult result = client.downloadFileSync("/dp_s/_DPS_/cache.tar.gz");
|
||||
|
||||
if (!result.error.empty()) {
|
||||
spdlog::info("下载服务器最新脚本失败,使用本地缓存脚本! 错误原因: {}", result.error);
|
||||
}
|
||||
else {
|
||||
spdlog::info("服务器最新脚本下载完成! 正在解压...");
|
||||
std::string command = "rm -rf \"" + std::string("/dp_s/_DPS_/_Core") + "\"";
|
||||
int Res1 = executeCommand(command.c_str());
|
||||
|
||||
std::string tarPath = "/dp_s/_DPS_/cache.tar.gz";
|
||||
std::string destDir = "/dp_s/_DPS_";
|
||||
std::string tarCmd = " tar -xzf \"" + tarPath + "\" -C \"" + destDir + "\"";
|
||||
int Res2 = executeCommand(tarCmd.c_str());
|
||||
|
||||
if (Res2 == 0) {
|
||||
spdlog::info("解压成功!");
|
||||
}
|
||||
else {
|
||||
spdlog::info("在解压过程中发生了一个预期之外的错误,请联系开发者!");
|
||||
}
|
||||
|
||||
std::ofstream file("/dp_s/_DPS_/version", std::ios::out);
|
||||
if (!file.is_open()) {
|
||||
spdlog::info("发生了一个预期之外的错误,请联系开发者!");
|
||||
}
|
||||
file << RemoteVersion << std::endl;
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
spdlog::info("下载服务器最新脚本失败,使用本地缓存脚本! 错误原因: {}", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void InitSquirrel()
|
||||
{
|
||||
v = sq_open(8192); // 创建虚拟机,其栈的初始大小为1024
|
||||
|
||||
sq_pushroottable(v);
|
||||
sqstd_register_bloblib(v);
|
||||
sqstd_register_iolib(v);
|
||||
sqstd_register_systemlib(v);
|
||||
sqstd_register_mathlib(v);
|
||||
sqstd_register_stringlib(v);
|
||||
// sqstd_register_dio(v);
|
||||
|
||||
sqstd_seterrorhandlers(v);
|
||||
|
||||
// 初始化日志器
|
||||
setupLogger();
|
||||
sq_setprintfunc(v, printfunc, errorfunc); // sets the print function
|
||||
|
||||
// 获取根表(全局作用域)
|
||||
sq_pushroottable(v);
|
||||
|
||||
// 将DP_S_VERSION添加到全局表
|
||||
sq_pushstring(v, "DP_S_VERSION", -1); // 键
|
||||
sq_pushfloat(v, 25.332); // 值
|
||||
sq_newslot(v, -3, SQFalse); // 在根表中创建slot
|
||||
|
||||
// 弹出根表,恢复堆栈
|
||||
sq_pop(v, 1);
|
||||
|
||||
// 注册全局NutApi
|
||||
GlobaRegisterSquirrel(v);
|
||||
|
||||
//非本地模式
|
||||
if ((access("/dp_s/lib/db.ini", F_OK) == -1)) {
|
||||
//获取本地脚本版本
|
||||
std::string LocalVersion = GetLocalScriptVersion();
|
||||
if (LocalVersion == "-1") {
|
||||
spdlog::info("本地未检测到DP-S核心脚本,正在尝试联网获取最新脚本...");
|
||||
}
|
||||
else {
|
||||
spdlog::info("本地DP-S核心脚本版本为{},正在检测是否有可用更新...", LocalVersion);
|
||||
}
|
||||
|
||||
//获取服务器最新脚本版本
|
||||
std::string RemoteVersion = GetRemoteScriptVersion();
|
||||
if (RemoteVersion != "error") {
|
||||
if (RemoteVersion != LocalVersion) {
|
||||
spdlog::info("正在下载服务器最新脚本...");
|
||||
//下载最新脚本
|
||||
DownLoadScript(RemoteVersion);
|
||||
}
|
||||
else {
|
||||
spdlog::info("当前服务器脚本已是最新版本无需更新.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SqReloadScript(v);
|
||||
// sq_pushroottable(v);
|
||||
// sq_pushstring(v, "sq_ReloadScript", -1);
|
||||
// sq_newclosure(v, SqReloadScript, 0); // create a new function
|
||||
// sq_newslot(v, -3, SQFalse);
|
||||
// sq_pop(v, 1); // pops the root table
|
||||
}
|
||||
31
src/script/l_squirrel.h
Normal file
31
src/script/l_squirrel.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
#ifndef l_squirrel
|
||||
#define l_squirrel
|
||||
// #define SQUNICODE
|
||||
#define NO_COMPILER
|
||||
|
||||
#include "squirrel.h"
|
||||
#include "sqstdaux.h"
|
||||
#include "sqstdblob.h"
|
||||
#include "sqstdio.h"
|
||||
#include "sqstdmath.h"
|
||||
#include "sqstdstring.h"
|
||||
#include "sqstdsystem.h"
|
||||
#include "Tool.h"
|
||||
#include <map>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <stdarg.h>
|
||||
#include <mutex>
|
||||
|
||||
#ifdef SQUNICODE
|
||||
#define scvprintf vfwprintf
|
||||
#define scfprintf fwprintf
|
||||
#else
|
||||
#define scvprintf vfprintf
|
||||
#define scfprintf fprintf
|
||||
#endif
|
||||
|
||||
void InitSquirrel();
|
||||
#endif
|
||||
42
src/script/l_squirrel_register.hpp
Normal file
42
src/script/l_squirrel_register.hpp
Normal file
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
#include "squirrel.h"
|
||||
#include "sqstdaux.h"
|
||||
#include "sqstdblob.h"
|
||||
#include "sqstdio.h"
|
||||
#include "sqstdmath.h"
|
||||
#include "sqstdstring.h"
|
||||
#include "sqstdsystem.h"
|
||||
#include "SqrReg_User.hpp" //用户类
|
||||
#include "SqrReg_Packet.hpp" //发包类
|
||||
#include "SqrReg_World.hpp" //世界类
|
||||
#include "SqrReg_Game.hpp" //游戏类
|
||||
#include "SqrReg_GameManager.hpp" //游戏管理器类
|
||||
#include "SqrReg_Party.hpp" //队伍类
|
||||
#include "SqrReg_Inven.hpp" //背包类
|
||||
#include "SqrReg_Battle_Field.hpp" //战斗对象类
|
||||
#include "SqrReg_Dungeon.hpp" //副本类
|
||||
#include "SqrReg_Memory.hpp" //内存类
|
||||
#include "SqrReg_ActiveHook.hpp" //动态HOOK
|
||||
#include "SqrReg_Dio.hpp" //网络类
|
||||
#include "SqrReg_Asset.hpp" //资源类
|
||||
#include "SqrReg_RSA.hpp" //RSA类
|
||||
#include <iostream>
|
||||
#include <stdarg.h>
|
||||
|
||||
static void GlobaRegisterSquirrel(HSQUIRRELVM v)
|
||||
{
|
||||
RegisterBattleField(v); // 战斗对象类
|
||||
RegisterDungeon(v); // 副本类
|
||||
RegisterInven(v); // 背包类
|
||||
RegisterGameManager(v); // 游戏管理器类
|
||||
RegisterParty(v); // 队伍类
|
||||
RegisterGame(v); // 游戏类
|
||||
RegisterWorld(v); // 世界类
|
||||
RegisterPacket(v); // 发包类
|
||||
RegisterUser(v); // 用户类
|
||||
RegisterMemory(v); // 内存类
|
||||
RegisterActiveHook(v); // 动态HOOK
|
||||
RegisterDio(v); // 网络类
|
||||
RegisterAsset(v); // 资源类
|
||||
RegisterRsa(v); // RSA类
|
||||
}
|
||||
Reference in New Issue
Block a user