1044 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			1044 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C++
		
	
	
	
| #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 "croncpp.h"
 | ||
| #include "l_socket.h"
 | ||
| #include <openssl/md5.h>
 | ||
| #include <opencc/opencc.h>
 | ||
| #include <iostream>
 | ||
| #include <functional>
 | ||
| #include <list>
 | ||
| #include <ffi.h>
 | ||
| #include <iconv.h>
 | ||
| #include "nlohmann/json.hpp"
 | ||
| 
 | ||
| #define CONTAINS_STRING(str, substr) (str == substr)
 | ||
| 
 | ||
| template <typename R, typename A, typename... ARG>
 | ||
| R CallGameT(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();
 | ||
| }
 | ||
| template <typename R>
 | ||
| R CallGameRT(void *call_addr, va_list arguments, std::vector<std::string> Type)
 | ||
| {
 | ||
|     if (!call_addr)
 | ||
|     {
 | ||
|         return R();
 | ||
|     }
 | ||
|     try
 | ||
|     {
 | ||
|         // 使用汇编语言将va_list中的值一个一个push进去
 | ||
|         R result;
 | ||
|         va_list args;
 | ||
|         va_copy(args, arguments);
 | ||
| 
 | ||
|         asm volatile(
 | ||
|             "pushl %0"
 | ||
|             :
 | ||
|             : "g"(va_arg(args, int))
 | ||
|             : "memory");
 | ||
| 
 | ||
|         va_end(args);
 | ||
| 
 | ||
|         asm volatile(
 | ||
|             "call *%1"
 | ||
|             : "=a"(result)
 | ||
|             : "r"(call_addr)
 | ||
|             : "memory");
 | ||
| 
 | ||
|         return result;
 | ||
|     }
 | ||
|     catch (...)
 | ||
|     {
 | ||
|     }
 | ||
|     return R();
 | ||
| }
 | ||
| 
 | ||
| static char szGamePath[256];
 | ||
| static int getargs(char ***argv)
 | ||
| {
 | ||
|     size_t buflen = 1024, readlen = 0, maxlen = buflen;
 | ||
|     int fd = open("/proc/self/cmdline", O_RDONLY);
 | ||
|     if (fd == -1)
 | ||
|         return 0;
 | ||
|     char *buf = (char *)malloc(buflen);
 | ||
|     while (1)
 | ||
|     {
 | ||
|         ssize_t n = read(fd, buf + readlen, buflen - readlen);
 | ||
|         if (n == -1)
 | ||
|         {
 | ||
|             free(buf);
 | ||
|             close(fd);
 | ||
|             return 0;
 | ||
|         }
 | ||
|         readlen += n;
 | ||
|         if (!n || readlen < buflen)
 | ||
|             break;
 | ||
|         maxlen += buflen;
 | ||
|         buf = (char *)realloc(buf, maxlen);
 | ||
|     }
 | ||
|     close(fd);
 | ||
|     int argc = 0;
 | ||
|     char *cp = buf;
 | ||
|     do
 | ||
|     {
 | ||
|         while (*cp != '\0')
 | ||
|             cp++;
 | ||
|         argc++;
 | ||
|     } while (++cp < buf + readlen);
 | ||
|     *argv = (char **)malloc(argc * sizeof(char *));
 | ||
|     argc = 0;
 | ||
|     cp = buf;
 | ||
|     do
 | ||
|     {
 | ||
|         (*argv)[argc] = (char *)malloc(strlen(cp) + 1);
 | ||
|         strcpy((*argv)[argc], cp);
 | ||
|         argc++;
 | ||
|         while (*cp != '\0')
 | ||
|             cp++;
 | ||
|     } while (++cp < buf + readlen);
 | ||
|     free(buf);
 | ||
|     return argc;
 | ||
| }
 | ||
| static int getConfigPath(char *pPath, size_t nSize)
 | ||
| {
 | ||
|     if (readlink("/proc/self/exe", pPath, nSize) <= 0)
 | ||
|         return -1;
 | ||
|     char **argv = NULL;
 | ||
|     int argc = getargs(&argv);
 | ||
|     if (!argv || argc < 2)
 | ||
|     {
 | ||
|         if (argv)
 | ||
|         {
 | ||
|             for (int i = 0; i < argc; i++)
 | ||
|             {
 | ||
|                 if (argv[i])
 | ||
|                     free(argv[i]);
 | ||
|             }
 | ||
|             free(argv);
 | ||
|         }
 | ||
|         return -1;
 | ||
|     }
 | ||
|     *strrchr(pPath, '/') = '\0';
 | ||
|     sprintf(pPath, "%s/cfg/%s.cfg", pPath, argv[1]);
 | ||
|     for (int i = 0; i < argc; i++)
 | ||
|     {
 | ||
|         if (argv[i])
 | ||
|             free(argv[i]);
 | ||
|     }
 | ||
|     free(argv);
 | ||
|     return 0;
 | ||
| }
 | ||
| static SQInteger Game_GetConfig(HSQUIRRELVM v)
 | ||
| {
 | ||
|     sq_pushstring(v, szGamePath, -1);
 | ||
|     return 1;
 | ||
| }
 | ||
| 
 | ||
| // 加密函数
 | ||
| static std::string Buf_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 Buf_IsencryptDecrypt(const std::string &input, const std::string &FileName)
 | ||
| {
 | ||
|     if (FileName.find(".nut") != std::string::npos)
 | ||
|         return input;
 | ||
|     else
 | ||
|         return Buf_encryptDecrypt(input, "Lenheart-asdhfjiaednkljanslk");
 | ||
| }
 | ||
| 
 | ||
| // 执行脚本
 | ||
| static SQInteger RunScript(HSQUIRRELVM v)
 | ||
| {
 | ||
|     const SQChar *Path;
 | ||
|     sq_getstring(v, 2, &Path);
 | ||
|     std::string RealPath(Path);
 | ||
|     RealPath = "/dp_s/" + RealPath;
 | ||
| 
 | ||
|     std::fstream F;
 | ||
|     F.open(RealPath, std::ios::in);
 | ||
|     std::stringstream ContentStringStream;
 | ||
|     ContentStringStream << F.rdbuf();
 | ||
|     std::string ContentString(ContentStringStream.str());
 | ||
|     F.close();
 | ||
| 
 | ||
|     std::string RealContentString = Buf_IsencryptDecrypt(ContentString, RealPath);
 | ||
| 
 | ||
|     if (SQ_SUCCEEDED(sq_compilebuffer(v, (SQChar *)(RealContentString.c_str()), RealContentString.length(), (SQChar *)(RealPath.c_str()), true)))
 | ||
|     {
 | ||
|         sq_pushroottable(v);
 | ||
|         sq_call(v, 1, 1, 1);
 | ||
|         sq_pop(v, 1);
 | ||
|     }
 | ||
| 
 | ||
|     return 0;
 | ||
| }
 | ||
| // 指针转int
 | ||
| static SQInteger L_Ptr2Int(HSQUIRRELVM v)
 | ||
| {
 | ||
|     SQUserPointer P;
 | ||
|     sq_getuserpointer(v, 2, &P);
 | ||
|     sq_pushinteger(v, (int)P);
 | ||
|     return 1;
 | ||
| }
 | ||
| // int转指针
 | ||
| static SQInteger L_Int2Ptr(HSQUIRRELVM v)
 | ||
| {
 | ||
|     SQInteger Address;
 | ||
|     sq_getinteger(v, 2, &Address);
 | ||
|     sq_pushuserpointer(v, (void *)Address);
 | ||
|     return 1;
 | ||
| }
 | ||
| 
 | ||
| // 写内存
 | ||
| static SQInteger L_WriteAddress(HSQUIRRELVM v)
 | ||
| {
 | ||
|     // 内存地址 int型
 | ||
|     SQUserPointer Address;
 | ||
|     // 内存偏移 int型
 | ||
|     SQInteger Offset;
 | ||
|     // 获取参数个数
 | ||
|     int ParameterNum = sq_gettop(v);
 | ||
|     // 2个参数时
 | ||
|     if (ParameterNum == 4)
 | ||
|     {
 | ||
|         // 获取地址
 | ||
|         sq_getuserpointer(v, 2, &Address);
 | ||
|         // 获取偏移
 | ||
|         sq_getinteger(v, 3, &Offset);
 | ||
|         // 获取修改的值
 | ||
|         SQInteger WriteValue;
 | ||
|         sq_getinteger(v, 4, &WriteValue);
 | ||
| 
 | ||
|         *(int *)((void *)Address + Offset) = WriteValue;
 | ||
|         sq_pushbool(v, true);
 | ||
|         return 1;
 | ||
|     }
 | ||
|     if (ParameterNum == 5)
 | ||
|     {
 | ||
|     }
 | ||
|     else
 | ||
|     {
 | ||
|         sq_pushbool(v, false);
 | ||
|         return 1;
 | ||
|     }
 | ||
|     return 0;
 | ||
| }
 | ||
| // 读内存
 | ||
| static SQInteger L_ReadAddress(HSQUIRRELVM v)
 | ||
| {
 | ||
|     // 内存地址 int型
 | ||
|     SQUserPointer Address;
 | ||
|     // 获取地址
 | ||
|     sq_getuserpointer(v, 2, &Address);
 | ||
|     sq_pushinteger(v, *(int *)Address);
 | ||
|     return 1;
 | ||
| }
 | ||
| // 读内存
 | ||
| static SQInteger L_ReadPoint(HSQUIRRELVM v)
 | ||
| {
 | ||
|     // 内存地址 int型
 | ||
|     SQUserPointer Address;
 | ||
|     // 获取地址
 | ||
|     sq_getuserpointer(v, 2, &Address);
 | ||
|     int *ptr = reinterpret_cast<int *>(Address);
 | ||
|     int value = *ptr;
 | ||
|     sq_pushuserpointer(v, (void *)(value));
 | ||
|     return 1;
 | ||
| }
 | ||
| // 读内存字符串
 | ||
| static SQInteger L_ReadAddressString(HSQUIRRELVM v)
 | ||
| {
 | ||
|     // 内存地址 int型
 | ||
|     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 L_ReadByteArr(HSQUIRRELVM v)
 | ||
| {
 | ||
|     SQUserPointer P;
 | ||
|     sq_getuserpointer(v, 2, &P);
 | ||
|     SQInteger Count;
 | ||
|     sq_getinteger(v, 3, &Count);
 | ||
| 
 | ||
|     char *Address = (char *)P;
 | ||
|     sq_newarray(v, 0);
 | ||
|     for (size_t i = 0; i < Count; i++)
 | ||
|     {
 | ||
|         sq_pushinteger(v, (int)(Address[i]));
 | ||
|         sq_arrayappend(v, -2);
 | ||
|     }
 | ||
|     return 1;
 | ||
| }
 | ||
| // 指针转Blob
 | ||
| static SQInteger L_Point2Blob(HSQUIRRELVM v)
 | ||
| {
 | ||
|     SQUserPointer P;
 | ||
|     sq_getuserpointer(v, 2, &P);
 | ||
|     SQInteger Count;
 | ||
|     sq_getinteger(v, 3, &Count);
 | ||
| 
 | ||
|     char *Address = (char *)P;
 | ||
|     SQUserPointer Blobobj = sqstd_createblob(v, Count);
 | ||
|     memcpy(Blobobj, P, Count);
 | ||
| 
 | ||
|     return 1;
 | ||
| }
 | ||
| // 写字节数组
 | ||
| static SQInteger L_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;
 | ||
| }
 | ||
| // 写Blob到指定地址
 | ||
| static SQInteger L_WriteBlobToAddress(HSQUIRRELVM v)
 | ||
| {
 | ||
|     SQUserPointer P;
 | ||
|     sq_getuserpointer(v, 2, &P);
 | ||
|     SQUserPointer Blobobj;
 | ||
|     // sq_getuserpointer(v, 3, &P);
 | ||
|     sqstd_getblob(v, 3, &Blobobj);
 | ||
|     int Size = sqstd_getblobsize(v, 3);
 | ||
| 
 | ||
|     memcpy(P, Blobobj, Size);
 | ||
|     return 0;
 | ||
| }
 | ||
| // 通过ID从Pvf中查询名称
 | ||
| static SQInteger L_GetNameByIdFromPvf(HSQUIRRELVM v)
 | ||
| {
 | ||
|     SQInteger Idx;
 | ||
|     sq_getinteger(v, 2, &Idx);
 | ||
| 
 | ||
|     void *Ret = CallGameT<void *>(0x835FA32, CallGameT<void *>(0x80CC19B), (unsigned int)Idx);
 | ||
|     if (Ret)
 | ||
|     {
 | ||
|         const char *Name = CallGameT<const char *>(0x811ed82, Ret);
 | ||
|         sq_pushstring(v, Name, -1);
 | ||
|     }
 | ||
|     else
 | ||
|     {
 | ||
|         sq_pushnull(v);
 | ||
|     }
 | ||
|     return 1;
 | ||
| }
 | ||
| // 通过ID从Pvf中查询Data
 | ||
| static SQInteger L_GetDataByIdFromPvf(HSQUIRRELVM v)
 | ||
| {
 | ||
|     SQInteger Idx;
 | ||
|     sq_getinteger(v, 2, &Idx);
 | ||
| 
 | ||
|     void *Ret = CallGameT<void *>(0x835FA32, CallGameT<void *>(0x80CC19B), (unsigned int)Idx);
 | ||
|     if (Ret)
 | ||
|     {
 | ||
|         sq_pushuserpointer(v, Ret);
 | ||
|     }
 | ||
|     else
 | ||
|     {
 | ||
|         sq_pushnull(v);
 | ||
|     }
 | ||
|     return 1;
 | ||
| }
 | ||
| 
 | ||
| // 创建数据库连接池
 | ||
| static SQInteger L_CreatCConnectPool(HSQUIRRELVM v)
 | ||
| {
 | ||
|     SQInteger MinConnectCount, MaxConnectCount, Port;
 | ||
|     const SQChar *Host;
 | ||
|     const SQChar *Account;
 | ||
|     const SQChar *Passwd;
 | ||
| 
 | ||
|     sq_getinteger(v, 2, &MinConnectCount);
 | ||
|     sq_getinteger(v, 3, &MaxConnectCount);
 | ||
|     sq_getstring(v, 4, &Host);
 | ||
|     sq_getinteger(v, 5, &Port);
 | ||
|     sq_getstring(v, 6, &Account);
 | ||
|     sq_getstring(v, 7, &Passwd);
 | ||
| 
 | ||
|     // 初始化数据库
 | ||
|     CConnectPool::CreatePool(MinConnectCount, MaxConnectCount, Host, Port, Account, Passwd);
 | ||
|     return 0;
 | ||
| }
 | ||
| // 阻塞线程的数据库操作 无返回值
 | ||
| static SQInteger L_MysqlExecNoRet(HSQUIRRELVM v)
 | ||
| {
 | ||
|     const SQChar *Sql;
 | ||
|     sq_getstring(v, 2, &Sql);
 | ||
| 
 | ||
|     MYSQL *MysqlObject = CConnectPool::GetConnect();
 | ||
|     mysql_query(MysqlObject, Sql);
 | ||
|     CConnectPool::PutConnect(MysqlObject);
 | ||
|     return 0;
 | ||
| }
 | ||
| 
 | ||
| struct CreateSocketInfo
 | ||
| {
 | ||
|     std::string Ip;
 | ||
|     std::string Port;
 | ||
| };
 | ||
| 
 | ||
| static void *SocketThread_function(void *arg)
 | ||
| {
 | ||
|     CreateSocketInfo *Info = (CreateSocketInfo *)arg;
 | ||
|     l_socket::getInstance().Init(Info->Ip, Info->Port);
 | ||
|     delete Info;
 | ||
|     // 在这里编写线程的具体操作
 | ||
| 
 | ||
|     pthread_exit(NULL);
 | ||
| }
 | ||
| 
 | ||
| // 创建Socket连接
 | ||
| static SQInteger L_CreatSocketConnect(HSQUIRRELVM v)
 | ||
| {
 | ||
|     const SQChar *Host;
 | ||
|     const SQChar *Port;
 | ||
|     sq_getstring(v, 2, &Host);
 | ||
|     sq_getstring(v, 3, &Port);
 | ||
|     CreateSocketInfo *Info = new CreateSocketInfo();
 | ||
|     Info->Ip = Host;
 | ||
|     Info->Port = Port;
 | ||
| 
 | ||
|     pthread_t SocketThread;
 | ||
|     // 创建线程1
 | ||
|     if (pthread_create(&SocketThread, NULL, SocketThread_function, Info) != 0)
 | ||
|     {
 | ||
|         std::cerr << "Error creating thread 1" << std::endl;
 | ||
|     }
 | ||
|     return 0;
 | ||
| }
 | ||
| 
 | ||
| static SQInteger register_Game_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 Aprintfunc(const SQChar *s, ...)
 | ||
| {
 | ||
|     fflush(stdout);
 | ||
|     va_list vl;
 | ||
|     va_start(vl, s);
 | ||
|     scvprintf(stdout, s, vl);
 | ||
|     va_end(vl);
 | ||
|     printf("\n");
 | ||
|     fflush(stdout);
 | ||
| }
 | ||
| 
 | ||
| // CallFunc
 | ||
| static SQInteger L_CallFunc(HSQUIRRELVM v)
 | ||
| {
 | ||
|     // 得到参数个数
 | ||
|     SQInteger Count = sq_gettop(v);
 | ||
|     // 得到函数地址
 | ||
|     SQUserPointer FuncAddress;
 | ||
|     sq_getuserpointer(v, 2, &FuncAddress);
 | ||
|     // 得到返回值类型
 | ||
|     const SQChar *RetType;
 | ||
|     sq_getstring(v, 3, &RetType);
 | ||
| 
 | ||
|     std::vector<std::string> ParameterType;
 | ||
|     // 遍历参数类型数组
 | ||
|     sq_pushnull(v); // null iterator
 | ||
|     while (SQ_SUCCEEDED(sq_next(v, 4)))
 | ||
|     {
 | ||
|         const SQChar *path;
 | ||
|         sq_getstring(v, -1, &path);
 | ||
|         ParameterType.push_back(path);
 | ||
|         sq_pop(v, 2);
 | ||
|     }
 | ||
|     sq_pop(v, 1);
 | ||
| 
 | ||
|     // 头部信息个数
 | ||
|     int HeaderCount = 4;
 | ||
| 
 | ||
|     // 计算valist内存
 | ||
|     int AdrSize = 0;
 | ||
|     for (std::string Type : ParameterType)
 | ||
|     {
 | ||
|         if (CONTAINS_STRING(Type, "int"))
 | ||
|             AdrSize += sizeof(int);
 | ||
|         else if (CONTAINS_STRING(Type, "bool"))
 | ||
|             AdrSize += sizeof(bool);
 | ||
|         else if (CONTAINS_STRING(Type, "string"))
 | ||
|             AdrSize += sizeof(char *);
 | ||
|         else if (CONTAINS_STRING(Type, "float"))
 | ||
|             AdrSize += sizeof(float);
 | ||
|         else if (CONTAINS_STRING(Type, "pointer"))
 | ||
|             AdrSize += sizeof(void *);
 | ||
|         else if (CONTAINS_STRING(Type, "short"))
 | ||
|             AdrSize += sizeof(short);
 | ||
|         else if (CONTAINS_STRING(Type, "char"))
 | ||
|             AdrSize += sizeof(char);
 | ||
|     }
 | ||
| 
 | ||
|     char *m = (char *)malloc(AdrSize);
 | ||
|     void *bm = m;
 | ||
|     // 定义函数签名
 | ||
|     ffi_cif cif;
 | ||
|     ffi_type **args = (ffi_type **)malloc(ParameterType.size() * sizeof(ffi_type *)); // 动态分配参数类型数组
 | ||
|     void **values = (void **)malloc(ParameterType.size() * sizeof(void *));           // 动态分配参数值数组
 | ||
|     ffi_arg result;
 | ||
| 
 | ||
|     int CFlag = 0;
 | ||
|     for (int i = (HeaderCount + 1); i < (Count + 1); i++)
 | ||
|     {
 | ||
|         if (CONTAINS_STRING(ParameterType[0], "int"))
 | ||
|         {
 | ||
|             sq_getinteger(v, i, (SQInteger *)m);
 | ||
|             args[CFlag] = &ffi_type_sint;
 | ||
|             values[CFlag] = m;
 | ||
|             m += sizeof(int);
 | ||
|         }
 | ||
|         else if (CONTAINS_STRING(ParameterType[0], "float"))
 | ||
|         {
 | ||
|             sq_getfloat(v, i, (SQFloat *)m);
 | ||
|             args[CFlag] = &ffi_type_float;
 | ||
|             values[CFlag] = m;
 | ||
|             m += sizeof(float);
 | ||
|         }
 | ||
|         else if (CONTAINS_STRING(ParameterType[0], "bool"))
 | ||
|         {
 | ||
|             sq_getbool(v, i, (SQBool *)m);
 | ||
|             args[CFlag] = &ffi_type_sint8;
 | ||
|             values[CFlag] = m;
 | ||
|             m += sizeof(bool);
 | ||
|         }
 | ||
|         else if (CONTAINS_STRING(ParameterType[0], "string"))
 | ||
|         {
 | ||
| 
 | ||
|             sq_getstring(v, i, (const SQChar **)m);
 | ||
|             args[CFlag] = &ffi_type_pointer;
 | ||
|             values[CFlag] = m;
 | ||
|             m += sizeof(void *);
 | ||
|         }
 | ||
|         else if (CONTAINS_STRING(ParameterType[0], "pointer"))
 | ||
|         {
 | ||
|             sq_getuserpointer(v, i, (SQUserPointer *)m);
 | ||
|             args[CFlag] = &ffi_type_pointer;
 | ||
|             values[CFlag] = m;
 | ||
|             m += sizeof(void *);
 | ||
|         }
 | ||
|         else if (CONTAINS_STRING(ParameterType[0], "short"))
 | ||
|         {
 | ||
|             sq_getinteger(v, i, (SQInteger *)m);
 | ||
|             args[CFlag] = &ffi_type_sint16;
 | ||
|             values[CFlag] = m;
 | ||
|             m += sizeof(short);
 | ||
|         }
 | ||
|         else if (CONTAINS_STRING(ParameterType[0], "char"))
 | ||
|         {
 | ||
|             sq_getinteger(v, i, (SQInteger *)m);
 | ||
|             args[CFlag] = &ffi_type_schar;
 | ||
|             values[CFlag] = m;
 | ||
|             m += sizeof(char);
 | ||
|         }
 | ||
| 
 | ||
|         ParameterType.erase(ParameterType.begin());
 | ||
|         CFlag++;
 | ||
|     }
 | ||
| 
 | ||
|     ffi_type *RetTypeFlag = &ffi_type_void;
 | ||
| 
 | ||
|     std::string RetTypeString = RetType;
 | ||
|     if (CONTAINS_STRING(RetTypeString, "int"))
 | ||
|         RetTypeFlag = &ffi_type_sint;
 | ||
|     else if (CONTAINS_STRING(RetTypeString, "float"))
 | ||
|         RetTypeFlag = &ffi_type_float;
 | ||
|     else if (CONTAINS_STRING(RetTypeString, "bool"))
 | ||
|         RetTypeFlag = &ffi_type_sint8;
 | ||
|     else if (CONTAINS_STRING(RetTypeString, "string"))
 | ||
|         RetTypeFlag = &ffi_type_pointer;
 | ||
|     else if (CONTAINS_STRING(RetTypeString, "pointer"))
 | ||
|         RetTypeFlag = &ffi_type_pointer;
 | ||
|     else if (CONTAINS_STRING(RetTypeString, "short"))
 | ||
|         RetTypeFlag = &ffi_type_sint16;
 | ||
|     else if (CONTAINS_STRING(RetTypeString, "char"))
 | ||
|         RetTypeFlag = &ffi_type_schar;
 | ||
| 
 | ||
|     if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, CFlag, RetTypeFlag, args) == FFI_OK)
 | ||
|     {
 | ||
|         // 动态调用函数
 | ||
|         ffi_call(&cif, FFI_FN(FuncAddress), &result, values);
 | ||
|     }
 | ||
| 
 | ||
|     free(args);
 | ||
|     free(values);
 | ||
|     free(bm);
 | ||
| 
 | ||
|     if (CONTAINS_STRING(RetTypeString, "int"))
 | ||
|         sq_pushinteger(v, (int)result);
 | ||
|     else if (CONTAINS_STRING(RetTypeString, "float"))
 | ||
|         sq_pushfloat(v, (float)result);
 | ||
|     else if (CONTAINS_STRING(RetTypeString, "bool"))
 | ||
|         sq_pushbool(v, (bool)result);
 | ||
|     else if (CONTAINS_STRING(RetTypeString, "string"))
 | ||
|         sq_pushstring(v, (char *)result, -1);
 | ||
|     else if (CONTAINS_STRING(RetTypeString, "pointer"))
 | ||
|         sq_pushuserpointer(v, (void *)result);
 | ||
|     else if (CONTAINS_STRING(RetTypeString, "short"))
 | ||
|         sq_pushinteger(v, (int)result);
 | ||
|     else if (CONTAINS_STRING(RetTypeString, "char"))
 | ||
|         sq_pushinteger(v, (int)result);
 | ||
|     else
 | ||
|         return 0;
 | ||
|     return 1;
 | ||
| }
 | ||
| 
 | ||
| static SQInteger L_S_Ptr(HSQUIRRELVM v)
 | ||
| {
 | ||
|     const SQChar *str;
 | ||
|     sq_getstring(v, 2, &str);
 | ||
|     unsigned long long addr = std::stoull(str, 0, 16);
 | ||
|     void *ptr = reinterpret_cast<void *>(addr);
 | ||
|     sq_pushuserpointer(v, ptr);
 | ||
|     return 1;
 | ||
| }
 | ||
| static SQInteger L_Str_Ptr(HSQUIRRELVM v)
 | ||
| {
 | ||
|     const SQChar *str;
 | ||
|     sq_getstring(v, 2, &str);
 | ||
|     sq_pushuserpointer(v, (void *)str);
 | ||
|     return 1;
 | ||
| }
 | ||
| static SQInteger L_Ptr_Operation_A2S(HSQUIRRELVM v)
 | ||
| {
 | ||
|     // 内存地址 int型
 | ||
|     SQUserPointer Address;
 | ||
|     // 获取地址
 | ||
|     sq_getuserpointer(v, 2, &Address);
 | ||
|     SQInteger Offset;
 | ||
|     sq_getinteger(v, 3, &Offset);
 | ||
|     sq_pushuserpointer(v, (void *)(Address + Offset));
 | ||
|     return 1;
 | ||
| }
 | ||
| 
 | ||
| static SQInteger New_Point(HSQUIRRELVM v)
 | ||
| {
 | ||
|     SQInteger Len;
 | ||
|     sq_getinteger(v, 2, &Len);
 | ||
|     void *P = malloc(Len);
 | ||
|     sq_pushuserpointer(v, P);
 | ||
|     return 1;
 | ||
| }
 | ||
| static SQInteger Delete_Point(HSQUIRRELVM v)
 | ||
| {
 | ||
|     SQUserPointer P;
 | ||
|     sq_getuserpointer(v, 2, &P);
 | ||
|     free(P);
 | ||
|     return 0;
 | ||
| }
 | ||
| 
 | ||
| static SQInteger Sq_getExportByName(HSQUIRRELVM v)
 | ||
| {
 | ||
|     const SQChar *MoudleName;
 | ||
|     const SQChar *FuncName;
 | ||
| 
 | ||
|     sq_getstring(v, 2, &MoudleName);
 | ||
|     sq_getstring(v, 3, &FuncName);
 | ||
| 
 | ||
|     void *handle = dlopen(nullptr, RTLD_LAZY);
 | ||
|     if (!handle)
 | ||
|         return 0;
 | ||
| 
 | ||
|     void *targetFunctionPtr = dlsym(handle, FuncName);
 | ||
|     if (!targetFunctionPtr)
 | ||
|         return 0;
 | ||
| 
 | ||
|     sq_pushuserpointer(v, targetFunctionPtr);
 | ||
|     return 1;
 | ||
| }
 | ||
| 
 | ||
| static SQInteger OutPutTable(HSQUIRRELVM v)
 | ||
| {
 | ||
|     const SQChar *Str;
 | ||
|     sq_getstring(v, 2, &Str);
 | ||
| 
 | ||
|     nlohmann::json ex1 = nlohmann::json::parse(Str);
 | ||
| 
 | ||
|     std::cout << std::setw(4) << ex1 << std::endl;
 | ||
|     return 0;
 | ||
| }
 | ||
| 
 | ||
| const std::string base64_chars =
 | ||
|     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 | ||
|     "abcdefghijklmnopqrstuvwxyz"
 | ||
|     "0123456789+/";
 | ||
| 
 | ||
| std::string base64_encode(const std::string &in)
 | ||
| {
 | ||
|     std::string out;
 | ||
|     int val = 0;
 | ||
|     int valb = -6;
 | ||
|     for (unsigned char c : in)
 | ||
|     {
 | ||
|         val = (val << 8) + c;
 | ||
|         valb += 8;
 | ||
|         while (valb >= 0)
 | ||
|         {
 | ||
|             out.push_back(base64_chars[(val >> valb) & 0x3F]);
 | ||
|             valb -= 6;
 | ||
|         }
 | ||
|     }
 | ||
|     if (valb > -6)
 | ||
|     {
 | ||
|         out.push_back(base64_chars[((val << 8) >> (valb + 8)) & 0x3F]);
 | ||
|     }
 | ||
|     while (out.size() % 4)
 | ||
|     {
 | ||
|         out.push_back('=');
 | ||
|     }
 | ||
|     return out;
 | ||
| }
 | ||
| std::string calculateMD5(const std::string &filePath)
 | ||
| {
 | ||
|     std::ifstream file(filePath, std::ios::binary | std::ios::ate);
 | ||
|     if (!file)
 | ||
|     {
 | ||
|         return "";
 | ||
|     }
 | ||
|     std::streampos size = file.tellg();
 | ||
|     file.seekg(0, std::ios::beg);
 | ||
| 
 | ||
|     unsigned char buffer[16];
 | ||
|     MD5_CTX md5Context;
 | ||
|     MD5_Init(&md5Context);
 | ||
| 
 | ||
|     while (file.read(reinterpret_cast<char *>(buffer), sizeof(buffer)))
 | ||
|     {
 | ||
|         MD5_Update(&md5Context, buffer, file.gcount());
 | ||
|     }
 | ||
| 
 | ||
|     MD5_Final(buffer, &md5Context);
 | ||
| 
 | ||
|     file.close();
 | ||
|     return base64_encode((char *)buffer);
 | ||
| }
 | ||
| 
 | ||
| void processDirectory(const std::string &directoryPath, std::unordered_map<std::string, std::string> &fileMD5Map)
 | ||
| {
 | ||
|     DIR *dir;
 | ||
|     struct dirent *entry;
 | ||
| 
 | ||
|     if ((dir = opendir(directoryPath.c_str())) != nullptr)
 | ||
|     {
 | ||
|         while ((entry = readdir(dir)) != nullptr)
 | ||
|         {
 | ||
|             if (entry->d_type == DT_REG)
 | ||
|             {
 | ||
|                 std::string filePath = directoryPath + "/" + entry->d_name;
 | ||
|                 std::string currentMD5 = calculateMD5(filePath);
 | ||
| 
 | ||
|                 if (fileMD5Map.find(filePath) != fileMD5Map.end())
 | ||
|                 {
 | ||
|                     if (fileMD5Map[filePath] != currentMD5)
 | ||
|                     {
 | ||
|                         fileMD5Map[filePath] = currentMD5;
 | ||
|                         std::lock_guard<std::recursive_mutex> lock(SqMtx);
 | ||
|                         // 执行虚拟机Main函数
 | ||
|                         SQInteger top = sq_gettop(v); // saves the stack size before the call
 | ||
|                         sq_pushroottable(v);          // pushes the global table
 | ||
|                         sq_pushstring(v, _SC("_Reload_List_Write_"), -1);
 | ||
|                         if (SQ_SUCCEEDED(sq_get(v, -2)))
 | ||
|                         {                        // gets the field 'foo' from the global table
 | ||
|                             sq_pushroottable(v); // push the 'this' (in this case is the global table)
 | ||
|                             sq_pushstring(v, filePath.c_str(), -1);
 | ||
|                             sq_call(v, 2, SQFalse, SQTrue); // calls the function
 | ||
|                         }
 | ||
|                         sq_settop(v, top); // restores the original stack size
 | ||
| 
 | ||
|                         // // 文件有变动,写入文件路径
 | ||
|                         // std::ofstream outputFile("/dp_s/auto_reload.dat", std::ios_base::app);
 | ||
|                         // if (outputFile.is_open())
 | ||
|                         // {
 | ||
|                         //     std::string ins = "dofile(\"" + filePath + "\");";
 | ||
|                         //     outputFile << ins << std::endl;
 | ||
|                         //     outputFile.close();
 | ||
|                         // }
 | ||
|                         // else
 | ||
|                         // {
 | ||
|                         //     std::cerr << "无法创建输出文件。" << std::endl;
 | ||
|                         // }
 | ||
|                     }
 | ||
|                 }
 | ||
|                 else
 | ||
|                 {
 | ||
|                     fileMD5Map[filePath] = currentMD5;
 | ||
|                 }
 | ||
|             }
 | ||
|             else if (entry->d_type == DT_DIR && std::string(entry->d_name) != "." && std::string(entry->d_name) != "..")
 | ||
|             {
 | ||
|                 processDirectory(directoryPath + "/" + entry->d_name, fileMD5Map);
 | ||
|             }
 | ||
|         }
 | ||
|         closedir(dir);
 | ||
|     }
 | ||
|     else
 | ||
|     {
 | ||
|         std::cerr << "无法打开目录:" << directoryPath << std::endl;
 | ||
|     }
 | ||
| }
 | ||
| struct AutoReloadSt
 | ||
| {
 | ||
|     std::string Path;
 | ||
| };
 | ||
| static void *continuousMonitoring(void *arg)
 | ||
| {
 | ||
|     AutoReloadSt *Info = (AutoReloadSt *)arg;
 | ||
|     std::unordered_map<std::string, std::string> fileMD5Map;
 | ||
|     while (true)
 | ||
|     {
 | ||
|         processDirectory(Info->Path, fileMD5Map);
 | ||
|         usleep(1000); // 每隔 1 秒检查一次
 | ||
|     }
 | ||
| }
 | ||
| static SQInteger AutoReload(HSQUIRRELVM v)
 | ||
| {
 | ||
|     const SQChar *Str;
 | ||
|     sq_getstring(v, 2, &Str);
 | ||
| 
 | ||
|     AutoReloadSt *Info = new AutoReloadSt();
 | ||
|     Info->Path = std::string(Str);
 | ||
|     // 开启DP-S 自动热重载
 | ||
|     // std::string targetDirectory = (char *)Str;
 | ||
|     // std::thread monitorThread(continuousMonitoring, targetDirectory);
 | ||
|     // monitorThread.join();
 | ||
| 
 | ||
|     pthread_t MonitoringThread;
 | ||
|     // 创建线程1
 | ||
|     if (pthread_create(&MonitoringThread, NULL, continuousMonitoring, Info) != 0)
 | ||
|     {
 | ||
|         std::cerr << "Error creating thread 1" << std::endl;
 | ||
|     }
 | ||
| 
 | ||
|     return 0;
 | ||
| }
 | ||
| 
 | ||
| static SQInteger L_Sq_Cron_Next(HSQUIRRELVM v)
 | ||
| {
 | ||
|     const SQChar *Str;
 | ||
|     sq_getstring(v, 2, &Str);
 | ||
|     SQInteger Date;
 | ||
|     sq_getinteger(v, 3, &Date);
 | ||
| 
 | ||
|     auto cron = cron::make_cron(Str);
 | ||
|     std::time_t next = cron::cron_next(cron, Date);
 | ||
|     sq_pushinteger(v, next);
 | ||
| 
 | ||
|     return 1;
 | ||
| }
 | ||
| 
 | ||
| static SQInteger _stream_myreadstring(HSQUIRRELVM v)
 | ||
| {
 | ||
|     SQStream *self = NULL;
 | ||
|     if (SQ_FAILED(sq_getinstanceup(v, 1, (SQUserPointer *)&self, (SQUserPointer)((SQUnsignedInteger)SQSTD_STREAM_TYPE_TAG), SQFalse)))
 | ||
|         return sq_throwerror(v, _SC("invalid type tag"));
 | ||
|     if (!self || !self->IsValid())
 | ||
|         return sq_throwerror(v, _SC("the stream is invalid"));
 | ||
| 
 | ||
|     SQInteger Count;
 | ||
|     sq_getinteger(v, 2, &Count);
 | ||
|     char *Str = new char[Count + 1];
 | ||
|     self->Read(Str, Count);
 | ||
|     std::string Sstr(Str, Count);
 | ||
|     delete[] Str;
 | ||
|     sq_pushstring(v, Sstr.c_str(), -1);
 | ||
|     return 1;
 | ||
| }
 | ||
| 
 | ||
| static SQInteger _CrcDecode(HSQUIRRELVM v)
 | ||
| {
 | ||
|     SQInteger Buffer[4];
 | ||
| 
 | ||
|     sq_pushnull(v); // null iterator
 | ||
|     int Idx = 0;
 | ||
|     while (SQ_SUCCEEDED(sq_next(v, -2)))
 | ||
|     {
 | ||
|         sq_getinteger(v, -1, &Buffer[Idx]);
 | ||
|         Idx++;
 | ||
|         sq_pop(v, 2);
 | ||
|     }
 | ||
|     sq_pop(v, 1);
 | ||
| 
 | ||
|     SQInteger crc32;
 | ||
|     sq_getinteger(v, 3, &crc32);
 | ||
| 
 | ||
|     int64 num = 2175242257;
 | ||
|     int64 anInt = ((Buffer[0]) << 0) | ((Buffer[1]) << 8) | ((Buffer[2]) << 16) | ((Buffer[3]) << 24);
 | ||
|     int64 val = (anInt ^ num ^ crc32);
 | ||
|     int64 jiemi = (val >> 6) | ((val << (32 - 6)) & 0xFFFFFFFF);
 | ||
| 
 | ||
|     sq_newarray(v, 0);
 | ||
|     for (size_t i = 0; i < 4; i++)
 | ||
|     {
 | ||
|         sq_pushinteger(v, (jiemi >> (i * 8)) & 0xFF);
 | ||
|         sq_arrayappend(v, -2);
 | ||
|     }
 | ||
|     return 1;
 | ||
| }
 | ||
| 
 | ||
| static SQInteger L_Conversion(HSQUIRRELVM v)
 | ||
| {
 | ||
|     const SQChar *Str;
 | ||
|     sq_getstring(v, 2, &Str);
 | ||
|     SQInteger Type;
 | ||
|     sq_getinteger(v, 3, &Type);
 | ||
| 
 | ||
|     std::string traditionalStr = std::string(Str);
 | ||
| 
 | ||
|     opencc_t ot;
 | ||
|     if (Type == 0)
 | ||
|         ot = opencc_open(OPENCC_DEFAULT_CONFIG_TRAD_TO_SIMP);
 | ||
|     else if (Type == 1)
 | ||
|         ot = opencc_open(OPENCC_DEFAULT_CONFIG_SIMP_TO_TRAD);
 | ||
| 
 | ||
|     char *NewStr = opencc_convert_utf8(ot, traditionalStr.c_str(), traditionalStr.length());
 | ||
|     std::string RetStr(NewStr);
 | ||
|     sq_pushstring(v, RetStr.c_str(), -1);
 | ||
|     opencc_convert_utf8_free(NewStr);
 | ||
|     opencc_close(ot);
 | ||
| 
 | ||
|     return 1;
 | ||
| }
 | ||
| 
 | ||
| static SQInteger L_GetTimestampString(HSQUIRRELVM v)
 | ||
| {
 | ||
|     auto now = std::chrono::system_clock::now();
 | ||
|     auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);
 | ||
|     auto value = now_ms.time_since_epoch();
 | ||
|     long long milliseconds = value.count();
 | ||
| 
 | ||
|     std::ostringstream oss;
 | ||
|     oss << milliseconds;
 | ||
| 
 | ||
|     sq_pushstring(v, oss.str().c_str(), -1);
 | ||
|     return 1;
 | ||
| }
 | ||
| 
 | ||
| static void RegisterGame(HSQUIRRELVM v)
 | ||
| {
 | ||
|     getConfigPath(szGamePath, sizeof(szGamePath));
 | ||
| 
 | ||
|     // 获取字符串时间戳
 | ||
|     register_World_func(v, L_GetTimestampString, _SC("Sq_GetTimestampString"));
 | ||
| 
 | ||
|     // 简繁转换
 | ||
|     register_World_func(v, L_Conversion, _SC("Sq_Conversion"));
 | ||
| 
 | ||
|     // 获取下一个cron
 | ||
|     register_World_func(v, L_Sq_Cron_Next, _SC("Sq_Cron_Next"));
 | ||
|     // 自身封装读取流
 | ||
|     register_World_func(v, _stream_myreadstring, _SC("stream_myreadstring"));
 | ||
|     register_World_func(v, _CrcDecode, _SC("Sq_CrcDecode"));
 | ||
| 
 | ||
|     // int 和指针相互转换
 | ||
|     register_World_func(v, RunScript, _SC("sq_RunScript"));
 | ||
| 
 | ||
|     register_World_func(v, L_Ptr2Int, _SC("Sq_Ptr2Int"));
 | ||
|     register_World_func(v, L_Int2Ptr, _SC("Sq_Int2Ptr"));
 | ||
|     register_World_func(v, L_S_Ptr, _SC("S_Ptr"));
 | ||
|     register_World_func(v, L_Str_Ptr, _SC("Str_Ptr"));
 | ||
| 
 | ||
|     // 指针运算
 | ||
|     register_World_func(v, L_Ptr_Operation_A2S, _SC("Ptr_Operation_A2S"));
 | ||
| 
 | ||
|     // new一个指针
 | ||
|     register_World_func(v, New_Point, _SC("Sq_New_Point"));
 | ||
|     // 销毁一个指针
 | ||
|     register_World_func(v, Delete_Point, _SC("Sq_Delete_Point"));
 | ||
| 
 | ||
|     // 获取频道配置
 | ||
|     register_World_func(v, Game_GetConfig, _SC("Sq_Game_GetConfig"));
 | ||
|     // 写地址int
 | ||
|     register_World_func(v, L_WriteAddress, _SC("Sq_WriteAddress"));
 | ||
|     // 读地址int
 | ||
|     register_World_func(v, L_ReadAddress, _SC("Sq_ReadAddress"));
 | ||
|     // 读地址Point
 | ||
|     register_World_func(v, L_ReadPoint, _SC("Sq_ReadPoint"));
 | ||
|     // 读地址字符串
 | ||
|     register_World_func(v, L_ReadAddressString, _SC("Sq_ReadAddressString"));
 | ||
|     // 读取Byte
 | ||
|     register_World_func(v, L_ReadByteArr, _SC("Sq_ReadByteArr"));
 | ||
|     // 写入Byte
 | ||
|     register_World_func(v, L_WriteByteArr, _SC("Sq_WriteByteArr"));
 | ||
|     // 通过指针转Blob
 | ||
|     register_World_func(v, L_Point2Blob, _SC("Sq_Point2Blob"));
 | ||
|     // 写Blob到指定地址
 | ||
|     register_World_func(v, L_WriteBlobToAddress, _SC("Sq_WriteBlobToAddress"));
 | ||
|     // 通过ID从Pvf中查询名称
 | ||
|     register_World_func(v, L_GetNameByIdFromPvf, _SC("Sq_GetNameByIdFromPvf"));
 | ||
|     // 通过ID从Pvf中查询Data
 | ||
|     register_World_func(v, L_GetDataByIdFromPvf, _SC("Sq_GetDataByIdFromPvf"));
 | ||
|     // 创建数据库连接池
 | ||
|     register_World_func(v, L_CreatCConnectPool, _SC("Sq_CreatCConnectPool"));
 | ||
|     // 阻塞线程的数据库操作 无返回值
 | ||
|     register_World_func(v, L_MysqlExecNoRet, _SC("Sq_MysqlExecNoRet"));
 | ||
|     // 创建Socket连接
 | ||
|     register_World_func(v, L_CreatSocketConnect, _SC("Sq_CreatSocketConnect"));
 | ||
|     // 动态调用Call
 | ||
|     register_World_func(v, L_CallFunc, _SC("Sq_CallFunc"));
 | ||
|     // 获取模块函数地址
 | ||
|     register_World_func(v, Sq_getExportByName, _SC("Sq_getExportByName"));
 | ||
|     // 打印表
 | ||
|     register_World_func(v, OutPutTable, _SC("Sq_OutPutTable"));
 | ||
|     // 开启自动热重载
 | ||
|     register_World_func(v, AutoReload, _SC("Sq_AutoReload"));
 | ||
| }
 |