#include "import.h"
#include "l_squirrel.h"
#include "l_socket.h"
#include "controller.h"
#include "CConnectPool.h"
extern HSQUIRRELVM v;
extern std::recursive_mutex SqMtx;
#define MY_VERSION ("BuildTime： " __DATE__ " " __TIME__)

int n_sleep_time = 10000;
int bGMMode = 0, bFairPVP = 0, bPickupRout = 0;

// SUBHOOK_INIT(PacketGuard, 0x0858DD4C);
SUBHOOK_INIT(GetVectorUserCharacInfo, 0x081A0BB8);
SUBHOOK_INIT(doDispatch, 0x08594922);
SUBHOOK_INIT(addServerHackCnt, 0x080F8C7E);
SUBHOOK_INIT(put_header, 0x080CB8FC);
SUBHOOK_INIT(IsRoutingItem, 0x08150F18);
SUBHOOK_INIT(setCharacInfoDetail, 0x0864AC1A);
SUBHOOK_INIT(IsGameMasterMode, 0x0811EDEE);
SUBHOOK_INIT(isGMUser, 0x0814589C);
SUBHOOK_INIT(GetPvPTeamCount, 0x08568CE0);
SUBHOOK_INIT(isGM, 0x08109346);
SUBHOOK_INIT(isGM1, 0x0829948C);
SUBHOOK_INIT(set_add_info, 0x080CB884);
SUBHOOK_INIT(get_dispatcher, 0x085948E2);
SUBHOOK_INIT(dispatch_template, 0x081258B6);
SUBHOOK_INIT(isSocketAvatar, 0x082F9228);
SUBHOOK_INIT(reach_game_world, 0x086C4E50);
SUBHOOK_INIT(Inter_LoadEtc_dispatch_sig, 0x084C0264);

SUBHOOK_INIT(Inter_LoadGeolocation_dispatch_sig, 0x0816088A);

SUBHOOK_INIT(Leninsert_user, 0x086C25A6);
SUBHOOK_INIT(LenGameWorld_move_position, 0x086C5706);
SUBHOOK_INIT(LenGetTimerMess, 0x08630ECC);
SUBHOOK_INIT(Lengetareauseridlist, 0x086C305E);
SUBHOOK_INIT(ReqDBSendNewSystemMultiMail, 0x08556B68);
SUBHOOK_INIT(AddItem, 0x0867B6D4);
SUBHOOK_INIT(InterSelectMobileAuthReward, 0x0816132A);
SUBHOOK_INIT(CreateSkill, 0x084024E6);
SUBHOOK_INIT(CreateEquip, 0x084023AC);
SUBHOOK_INIT(History_Log, 0x854F990);
SUBHOOK_INIT(UseGlod, 0x84FF54C);
SUBHOOK_INIT(BossDieCheckSend, 0x81CDA62);
SUBHOOK_INIT(Giveup_Game, 0x81C40B4);
SUBHOOK_INIT(CUserWorkPerFiveMin, 0x8652F0C);
SUBHOOK_INIT(TimerDispatcher_dispatch, 0x8632A18);
SUBHOOK_INIT(SetUserMaxLevel, 0x0868fec8);

//_setCharacInfoDetail

template <typename R, typename A, typename... ARG>
R CallMain(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();
}

int checkGame(const char *pName)
{
	char path[256];
	char *path_end;

	memset(path, 0, sizeof(path));
	if (readlink("/proc/self/exe", path, sizeof(path)) <= 0)
		return -1;
	path_end = strrchr(path, '/');
	if (!path_end || strlen(path_end) < 9)
		return -1;
	return strcmp(pName, ++path_end);
}

int open_main_module_file()
{
	char path[256];
	memset(path, 0, sizeof(path));
	if (readlink("/proc/self/exe", path, sizeof(path)) <= 0)
		return -1;
	return open(path, O_RDONLY);
}

int GetProfileString(const char *profile, const char *section, const char *key, char **val)
{
	int hFile = open(profile, O_RDONLY);
	if (hFile == -1)
		return -1;
	struct stat st;
	fstat(hFile, &st);
	void *pFileData = mmap(0, st.st_size, PROT_READ, MAP_SHARED, hFile, 0);
	if (!pFileData)
	{
		close(hFile);
		return -1;
	}
	unsigned char readSection = 0, readKey = 1, readValue = 0, got = 0, notes = 0;
	char *cur = (char *)pFileData, *end = (char *)pFileData + st.st_size;
	char *sectionbuf = (char *)malloc(1024), *keybuf = (char *)malloc(1024), *valuebuf = (char *)malloc(1024);
	memset(sectionbuf, 0, 1024);
	memset(keybuf, 0, 1024);
	memset(valuebuf, 0, 1024);
	int i = 0;
	do
	{
		if (notes && *cur != '\n')
			continue;
		switch (*cur)
		{
		case '#':
			notes = 1;
			break;
		case ' ':
		case '\t':
			// jump space
			break;
		case '\n':
			// new line
			if (readValue)
			{
				valuebuf[i] = '\0';
				if (!strcmp(section, sectionbuf) && !strcmp(key, keybuf))
				{
					*val = (char *)malloc(i + 1);
					memset(*val, 0, i + 1);
					strcpy(*val, valuebuf);
					got = 1;
				}
				// printf("value:%s\n", valuebuf);
			}
			notes = 0, readSection = 0, readKey = 1, readValue = 0, i = 0;
			break;
		case '[':
			// section begin
			readSection = 1;
			readKey = 0;
			readValue = 0;
			i = 0;
			break;
		case ']':
			// section end
			if (readSection)
			{
				sectionbuf[i] = '\0';
				// printf("section:%s\n", sectionbuf);
				readSection = 0;
			}
			break;
		case '=':
			if (readKey)
			{
				keybuf[i] = '\0';
				// printf("key:%s\n", keybuf);
				readSection = 0;
				readKey = 0;
				readValue = 1;
				i = 0;
			}
			break;
		default:
			if (readSection)
			{
				sectionbuf[i++] = *cur;
			}
			else if (readKey)
			{
				keybuf[i++] = *cur;
			}
			else if (readValue)
			{
				valuebuf[i++] = *cur;
			}
			break;
		}
	} while (++cur != end && !got);
	free(sectionbuf);
	free(keybuf);
	free(valuebuf);
	munmap(pFileData, st.st_size);
	return 0;
}

int GetProfileInt(const char *profile, const char *section, const char *key)
{
	int ival = 0;
	char *pValue = NULL;
	if (GetProfileString(profile, section, key, &pValue) || !pValue)
		return 0;
	ival = atoi(pValue);
	free(pValue);
	return ival;
}

Elf32_Shdr *get_section_by_type(Elf32_Ehdr *pHeader, Elf32_Shdr *pSectionHeaderTable, Elf32_Word sh_type)
{
	Elf32_Half i = 0;
	do
	{
		if (pSectionHeaderTable[i].sh_type == sh_type)
		{
			return &pSectionHeaderTable[i];
		}
	} while (++i < pHeader->e_shnum);
	return NULL;
}

Elf32_Shdr *get_section_by_index(Elf32_Ehdr *pHeader, Elf32_Shdr *pSectionHeaderTable, Elf32_Half i)
{
	if (i < pHeader->e_shnum)
	{
		return &pSectionHeaderTable[i];
	}
	return NULL;
}

Elf32_Shdr *get_section_by_name(Elf32_Ehdr *pHeader, Elf32_Shdr *pSectionHeaderTable, const char *pSymStrTbl, const char *pName)
{
	Elf32_Half i = 0;
	do
	{
		if (!strcmp(pName, &pSymStrTbl[pSectionHeaderTable[i].sh_name]))
		{
			return &pSectionHeaderTable[i];
		}
	} while (++i < pHeader->e_shnum);
	return NULL;
}

int get_symbol_index_by_name(Elf32_Sym *pSymbolTbl, int nSymbols, const char *pSymStrTbl, const char *pName)
{
	int i = 0;
	do
	{
		if (ELF32_ST_TYPE(pSymbolTbl[i].st_info) == STT_FUNC && !strcmp(pName, &pSymStrTbl[pSymbolTbl[i].st_name]))
		{
			return i;
		}
	} while (++i < nSymbols);
	return 0;
}

void *replaceIAT(const char *pName, void *pAddr)
{
	void *pOrgAddr = NULL;

	int hFile = open_main_module_file();
	if (hFile != -1)
	{
		struct stat st;
		fstat(hFile, &st);
		void *pFileData = mmap(0, st.st_size, PROT_READ, MAP_SHARED, hFile, 0);
		if (pFileData)
		{
			Elf32_Ehdr *pHeader = (Elf32_Ehdr *)pFileData;
			Elf32_Shdr *pSectionHeaderTable = (Elf32_Shdr *)((char *)pHeader + pHeader->e_shoff);
			Elf32_Shdr *pSymSection = get_section_by_type(pHeader, pSectionHeaderTable, SHT_DYNSYM);
			Elf32_Shdr *pSymStrSection = get_section_by_index(pHeader, pSectionHeaderTable, pSymSection->sh_link);
			Elf32_Sym *pSymbolTbl = (Elf32_Sym *)((char *)pHeader + pSymSection->sh_offset);
			const char *pSymStrTbl = (const char *)((char *)pHeader + pSymStrSection->sh_offset);
			unsigned int iSymbol = get_symbol_index_by_name(pSymbolTbl, pSymSection->sh_size / sizeof(Elf32_Sym), pSymStrTbl, pName);
			Elf32_Shdr *pStrSection = get_section_by_index(pHeader, pSectionHeaderTable, pHeader->e_shstrndx);
			const char *pStrTbl = (const char *)((char *)pHeader + pStrSection->sh_offset);
			Elf32_Shdr *pRelPltSection = get_section_by_name(pHeader, pSectionHeaderTable, pStrTbl, ".rel.plt");
			Elf32_Shdr *pRelDynSection = get_section_by_name(pHeader, pSectionHeaderTable, pStrTbl, ".rel.dyn");
			Elf32_Rel *pRelPlt = (Elf32_Rel *)(0x8047000 + pRelPltSection->sh_offset);
			Elf32_Rel *pRelDyn = (Elf32_Rel *)(0x8047000 + pRelDynSection->sh_offset);
			int nRelPlt = pRelPltSection->sh_size / sizeof(Elf32_Rel);
			int nRelDyn = pRelDynSection->sh_size / sizeof(Elf32_Rel);
			for (int i = 0; i < nRelPlt; i++)
			{
				if (ELF32_R_SYM(pRelPlt[i].r_info) == iSymbol && pRelPlt[i].r_offset)
				{
					pOrgAddr = *(void **)pRelPlt[i].r_offset;
					*(void **)pRelPlt[i].r_offset = pAddr;
					break;
				}
			}
			if (!pOrgAddr)
			{
				for (int i = 0; i < nRelDyn; i++)
				{
					if (ELF32_R_SYM(pRelDyn[i].r_info) == iSymbol && pRelDyn[i].r_offset)
					{
						void **jmpAddr = (void **)pRelDyn[i].r_offset;
						// printf("jmpaddr::::::::::::::::::::%X\n", pRelDyn[i].r_offset);
						pOrgAddr = (void *)((char *)(*jmpAddr) + (int)jmpAddr + sizeof(void *));
						CMem::WriteBytes(pOrgAddr, &pAddr, sizeof(pAddr));
						break;
					}
				}
			}
			munmap(pFileData, st.st_size);
		}
		close(hFile);
	}
	return pOrgAddr;
}

int my_select(int __nfds, fd_set *__restrict __readfds,
			  fd_set *__restrict __writefds,
			  fd_set *__restrict __exceptfds,
			  struct timeval *__restrict __timeout)
{
	if (!__nfds && !__readfds && !__writefds && !__exceptfds)
	{
		if (!__timeout->tv_sec && __timeout->tv_usec >= 0 && __timeout->tv_usec <= 1000)
		{
			__timeout->tv_usec = n_sleep_time;
		}
	}
	return select(__nfds, __readfds, __writefds, __exceptfds, __timeout);
}

int my_usleep(__useconds_t __useconds)
{
	if (__useconds >= 0 && __useconds <= 1000)
	{
		__useconds = n_sleep_time;
	}
	return usleep(__useconds);
}

/*void* my_malloc (size_t __size)
{
	if (__size > 100 * 1024 * 1024)
	{
		char path[256];
		memset(path, 0, sizeof(path));
		readlink("/proc/self/exe", path, sizeof(path));
		printf("**********************************[%s][malloc]: %.2f\n", path, (double)__size / 1024 / 1024);
		print_backtrace(2);
	}
	return malloc(__size);
}*/

int _doDispatch(void *pPacketDispatcher, void *pUser, int a3, int a4, void *src, int a6, int a7, int a8) // 收包处理
{
	void *pAction = *get_dispatcher(pPacketDispatcher, a4);
	if (pAction)
	{
		// printf("Recv() cs:%d cmd:%d len:%d callback:%p\t%p\t%p\t%p\t%p\t%p\n", a3, a4, a6, *((void **)pAction), (void *)*((unsigned int *)pAction + 12), (void *)*((unsigned int *)pAction + 16), (void *)*((unsigned int *)pAction + 20), (void *)*((unsigned int *)pAction + 24), (void *)*((unsigned int *)pAction + 28));
	}
	else
	{
		// printf("Recv() cs:%d cmd:%d len:%d\n", a3, a4, a6);
	}
	return doDispatch(pPacketDispatcher, pUser, a3, a4, src, a6, a7, a8);
}

int _dispatch_template(void *pInst, void *pUser, void *pPacketBuf)
{
	char *buf = (char *)(*((unsigned int *)pPacketBuf + 5));
	// printf("Recv() cs:%d cmd:%d len:%d callback:%p|%p|%p|%p|%p\n"
	//	, buf[0]
	//	, *((unsigned short*)&buf[1])
	//	, *((unsigned int*)&buf[3])
	//	, *((void**)*((unsigned int*)pInst + 12))
	//	, *((void**)*((unsigned int*)pInst + 16))
	//	, *((void**)*((unsigned int*)pInst + 20))
	//	, *((void**)*((unsigned int*)pInst + 24))
	//	, *((void**)*((unsigned int*)pInst + 28))
	//);
	return dispatch_template(pInst, pUser, pPacketBuf);
}

int _addServerHackCnt(void *pCHackAnalyzer, void *pCUserCharacInfo, int HackType, int Cnt, int a5, int a6)
{
	// printf("addServerHackCnt() HackType:%d \n", HackType);
	// char pack_buf[0xC];
	// PacketGuard(pack_buf);
	return addServerHackCnt(pCHackAnalyzer, pCUserCharacInfo, HackType, Cnt, a5, a6);
}

int _put_header(void *pInterfacePacketBuf, int Type, int Cmd)
{

	return put_header(pInterfacePacketBuf, Type, Cmd);
}

int _IsRoutingItem(void *pItem)
{
	// 拾取掷点
	return bPickupRout && (*((unsigned int *)pItem + 14) == 4 || *((unsigned char *)pItem + 189));
}

int _setCharacInfoDetail(void *pUser, int a2, int a3, void *pCHARAC_DATA)
{
	// 下线位置
	unsigned char curArea = *((unsigned char *)pCHARAC_DATA + 34);
	int ret = setCharacInfoDetail(pUser, a2, a3, pCHARAC_DATA);
	if (curArea == 12 || curArea == 13)
	{
		*((char *)GetVectorUserCharacInfo((char *)pUser + 497384, a2) + 34) = 11;
	}
	return ret;
}

int _IsGameMasterMode(void *pUser)
{
	// gm
	return bGMMode || *((unsigned char *)pUser + 463320) != 0;
}

int _isGMUser(void *pUser)
{
	// gm
	// printf("%s\n", __FUNCTION__);
	return bGMMode || (*((unsigned char *)pUser + 463320) != 0);
}

int _isGM(void *pGMAccounts, unsigned int a2)
{
	// gm
	// printf("%s\n", __FUNCTION__);
	return bGMMode || isGM(pGMAccounts, a2);
}

int _isGM1(void *pGM_Manager)
{
	// gm
	// printf("%s\n", __FUNCTION__);
	return bGMMode || isGM1(pGM_Manager);
}

int _GetPvPTeamCount(void *pDataManager)
{
	if (bFairPVP)
		return 10;
	return *((unsigned int *)pDataManager + 11540);
}

// void *_set_add_info(void *pInven_Item, int a2)
// {
// 	if ((unsigned int)__builtin_return_address(0) == 0x0820156C)
// 	{
// 		char *_esp = NULL;
// 		__asm__ __volatile__("movl %%esp, %[a1];" : [a1] "=m"(_esp));
// 		if (_esp)
// 		{
// 			for (int i = 0; i < 200; i++)
// 			{
// 				if (897 == *((unsigned int *)&_esp[i]))
// 				{
// 					// printf("Get !!! %X\n", i);
// 					a2 = GetProfileInt(szGamePath, "", "val");
// 				}
// 			}
// 		}
// 		// printf("====================_set_add_info======================%d\n", a2);
// 	}
// 	return set_add_info(pInven_Item, a2);
// }

int _isSocketAvatar(void *pAvatarItemMgr1, void *pAvatarItemMgr2)
{
	return 1;
}

int _reach_game_world(void *pThis, void *a2)
{
	std::lock_guard<std::recursive_mutex> lock(SqMtx);

	SQInteger top = sq_gettop(v); // saves the stack size before the call
	sq_pushroottable(v);		  // pushes the global table
	sq_pushstring(v, _SC("Cb_reach_game_world"), -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_pushuserpointer(v, a2);
		sq_call(v, 2, SQFalse, SQTrue); // calls the function
	}
	sq_settop(v, top); // restores the original stack size

	return reach_game_world(pThis, a2);
}

int _Inter_LoadEtc_dispatch_sig(void *pThis, void *pUser, char *a3)
{
	int result = Inter_LoadEtc_dispatch_sig(pThis, pUser, a3);
	YLOG("_Inter_LoadEtc_dispatch_sig begin");

	// typedef double(__cdecl* FN_sqrt)(_In_ double _X);

	CUserCharacInfo_getCurCharacNo getCurCharacNo = (CUserCharacInfo_getCurCharacNo)(0x080CBC4E);
	int CurCharacNo = getCurCharacNo(pUser);
	YLOG("CurCharacNo :%d", CurCharacNo);

	CUserCharacInfo_getCurCharacName getCurCharacName = (CUserCharacInfo_getCurCharacName)0x8101028;

	char *name = getCurCharacName(pUser);
	YLOG("CurCharacName :%s", name);

	YLOG("_Inter_LoadEtc_dispatch_sig end");
	return result;
}

void _Leninsert_user(void *Area, void *CUser)
{
	// *(int *)(Area + 0x68) = 1; // 让这个区域的所有玩家互相看不见123
	// *(int *)(Area + 26) = 1;
	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("Cb_insert_user"), -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_pushuserpointer(v, Area);
		sq_pushuserpointer(v, CUser);
		sq_call(v, 3, SQFalse, SQTrue); // calls the function
	}
	sq_settop(v, top); // restores the original stack size
	Leninsert_user(Area, CUser);
}
void _LenGameWorld_move_position(void *GameWorld, void *CUser, int a3, int a4, int a5, short a6)
{
	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("Cb_GameWorld_move_position"), -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_pushuserpointer(v, CUser);
		sq_pushinteger(v, a3);
		sq_pushinteger(v, a4);
		sq_pushinteger(v, a5);
		sq_pushinteger(v, a6);
		sq_call(v, 6, SQFalse, SQTrue); // calls the function
	}
	sq_settop(v, top); // restores the original stack size
	LenGameWorld_move_position(GameWorld, CUser, a3, a4, a5, a6);
}

int _LenGetTimerMess(void *TimerQueue, void *TimerEntry)
{
	if (l_socket::getInstance().InitState)
		l_socket::getInstance().Logic();
	return LenGetTimerMess(TimerQueue, TimerEntry);
}

int _UseGlod(void *CUser, int a1, int a3, int a4)
{
	return UseGlod(CUser, a1, a3, a4);
}

void PrintAuroraTag()
{
	printf("\n");

	// YLOG("**********************************************************");
	// YLOG("  DNF_Server Plugin S%s                                  ", MY_VERSION);
	// YLOG("                                   By:Rindro-Aurora     ");
	// YLOG("                                 	PowerBy:Vance		 ");
	// YLOG("**********************************************************");
	// YLOG("DP_S插件已加载*************************************凌众-极光");
	// YLOG("DP_S插件已加载*************************************凌众-极光");
	// YLOG("DP_S插件已加载*************************************凌众-极光");
	// YLOG("DP_S插件已加载*************************************凌众-极光");
	// YLOG("DP_S插件已加载*************************************凌众-极光");
	// YLOG("DP_S插件已加载*************************************凌众-极光");
}

int _Inter_LoadGeolocation_dispatch_sig(void *pThis, void *pUser, char *a3)
{
	PrintAuroraTag();
	// 请求脚本
	// ReqScript();
	// 初始化松鼠
	InitSquirrel();

	int Ret = Inter_LoadGeolocation_dispatch_sig(pThis, pUser, a3);

	void *handle = dlopen("/home/neople/game/frida.so", RTLD_LAZY);
	if (!handle)
	{
		std::cerr << "无法加载库: " << dlerror() << '\n';
	}
	return Ret;
}

int _ReqDBSendNewSystemMultiMail(char *src, int a2, unsigned int a3, int a4, int a5, char *a6, int a7, int a8, int a9, char a10)
{
	int Ret = ReqDBSendNewSystemMultiMail(src, a2, a3, a4, a5, a6, a7, a8, a9, a10);
	std::cout << 111 << std::endl;
	return Ret;
}

int _AddItem(void *CUser, int a2, int a3, int a4, int *a5, int a6)
{
	int Ret = AddItem(CUser, a2, a3, a4, a5, a6);
	std::cout << 111 << std::endl;
	return Ret;
}

int _InterSelectMobileAuthReward(void *InterSelect, void *CUser, char *a3)
{
	int Ret = InterSelectMobileAuthReward(InterSelect, CUser, a3);
	std::cout << 111 << std::endl;
	return Ret;
}

bool _CreateSkill(int a1, int a2)
{
	char *Str = (char *)(a2 + 121);
	char *Str1 = (char *)(a2 + 529);
	std::cout << "Str: " << Str << std::endl;
	std::cout << "Str1: " << Str1 << std::endl;

	bool Ret = CreateSkill(a1, a2);
	return Ret;
}

// 贪玩需求
bool _CreateEquip(void *a1, unsigned int a2, void *a3)
{
	char *Str = (char *)(a3);
	for (int i = 0; i < (30 * 11); i++)
	{
		Str[i] = 0x0;
	}

	bool Ret = CreateEquip(a1, a2, a3);
	return Ret;
}

int _History_Log(int a1, char *format, ...)
{
	char Buffer[256];

	va_list args;
	va_start(args, format);
	vsprintf(Buffer, format, args);
	va_end(args);

	std::vector<std::string> Data;
	Tool::Split(Buffer, Data, ",");
	// std::cout << Buffer << 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);		  // pushes the global table
	sq_pushstring(v, _SC("Cb_History_Log"), -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_newarray(v, 0);
		for (std::string Str : Data)
		{
			sq_pushstring(v, Str.c_str(), -1);
			sq_arrayappend(v, -2);
		}
		sq_call(v, 2, SQFalse, SQTrue); // calls the function
	}
	sq_settop(v, top); // restores the original stack size

	// 调用原始函数
	va_start(args, format);
	int result = History_Log(a1, format, args);
	va_end(args);
	return result;
}

// BOSS死亡HOOK
void _BossDieCheckSend(void *a1, void *a2, void *a3)
{
	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("Cb_BossDie"), -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_pushuserpointer(v, a2);
		sq_call(v, 2, SQFalse, SQTrue); // calls the function
	}
	sq_settop(v, top); // restores the original stack size
	BossDieCheckSend(a1, a2, a3);
}

void _Giveup_Game(void *CParty, void *CUser, bool a3, bool a4, bool a5)
{
	// 放弃副本
	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("Cb_giveup_dgn"), -1);
	if (SQ_SUCCEEDED(sq_get(v, -2)))
	{						 // gets the fie123oo' from the global table
		sq_pushroottable(v); // push the 'this' (in this case is the global table)
		sq_pushuserpointer(v, CUser);
		sq_call(v, 2, SQFalse, SQTrue); // calls the function
	}
	sq_settop(v, top); // restores the original stack size
	Giveup_Game(CParty, CUser, a3, a4, a5);
}

void _CUserWorkPerFiveMin(void *CUser)
{
	// 用户每五分钟执行
	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("Cb_user_workperfivemin"), -1);
	if (SQ_SUCCEEDED(sq_get(v, -2)))
	{						 // gets the fie123oo' from the global table
		sq_pushroottable(v); // push the 'this' (in this case is the global table)
		sq_pushuserpointer(v, CUser);
		sq_call(v, 2, SQFalse, SQTrue); // calls the function
	}
	sq_settop(v, top); // restores the original stack size
	CUserWorkPerFiveMin(CUser);
}

void *_SetUserMaxLevel(void *CUser, int level)
{
	// 用户每五分钟执行
	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("Cb_user_setusermaxlevel"), -1);
	if (SQ_SUCCEEDED(sq_get(v, -2)))
	{						 // gets the fie123oo' from the global table
		sq_pushroottable(v); // push the 'this' (in this case is the global table)
		sq_pushuserpointer(v, CUser);
		sq_pushinteger(v, level);
		sq_call(v, 3, SQFalse, SQTrue); // calls the function
	}
	sq_settop(v, top); // restores the original stack size
	return CUser;
}

int _TimerDispatcher_dispatch(void *A, void *B)
{
	int ret = TimerDispatcher_dispatch(A, B);
	// void *a1 = malloc(100);
	// void *mutexobj = CallMain<void *>(0x810544C, a1, (char *)CallMain<void *>(0x80F647C) + 16);

	if (v)
	{
		// 用户每五分钟执行
		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("Cb_timer_dispatch"), -1);
		if (SQ_SUCCEEDED(sq_get(v, -2)))
		{									// gets the fie123oo' from the global table
			sq_pushroottable(v);			// push the 'this' (in this case is the global table)
			sq_call(v, 1, SQFalse, SQTrue); // calls the function
		}
		sq_settop(v, top); // restores the original stack size
	}

	// CallMain<int>(0x8105468, mutexobj);
	return ret;
}

void Lenheart()
{

	if (!checkGame("df_game_r"))
	{

		int a = 1;
		void *buf = malloc(4);
		CMem::WriteBytes(buf, &a, 4);
		unsigned int nMaxGrade = 85;
		bGMMode = 1;

		// max_level = nMaxGrade;

		// ServerParameterScript::setDungeonOpen

		// CodeHook::WriteUChar(MAIN_OFFSET(0x22069B), 0x01);
		// ServerParameterScript::isDungeonOpen
		// CMem::WriteUChar(MAIN_OFFSET(0x220894), 0x01);
		// // Init DataManager
		// CMem::WriteUChar(MAIN_OFFSET(0x258E80), 0xEB);
		// // Init Level Exp
		// CMem::WriteUChar(MAIN_OFFSET(0x314ECB), 0xEB);
		// // Init Mob Reward
		// CMem::WriteUChar(MAIN_OFFSET(0x314FCB), 0xEB);
		// // CDataManager::GetSpAtLevelUp
		// CMem::WriteUChar(MAIN_OFFSET(0x318CC8), 0xE6);
		// // fixbug
		// CMem::WriteUChar(MAIN_OFFSET(0x31C128), 0x7E);
		// CMem::WriteUChar(MAIN_OFFSET(0x31C129), 0x06);

		// CMem::WriteUChar(MAIN_OFFSET(0x547005), nMaxGrade);
		// CMem::WriteUChar(MAIN_OFFSET(0x61AF55), nMaxGrade);
		// CMem::WriteUChar(MAIN_OFFSET(0x61B0F3), nMaxGrade);
		// CMem::WriteUChar(MAIN_OFFSET(0x61DD28), nMaxGrade - 1);
		// CMem::WriteUChar(MAIN_OFFSET(0x61E86A), nMaxGrade);
		// CMem::WriteUChar(MAIN_OFFSET(0x61EE9C), nMaxGrade - 1);
		// CMem::WriteUChar(MAIN_OFFSET(0x6224A8), nMaxGrade - 1);
		// CMem::WriteUChar(MAIN_OFFSET(0x622929), nMaxGrade);
		// CMem::WriteUChar(MAIN_OFFSET(0x641D4B), nMaxGrade - 1);
		// CMem::WriteUChar(MAIN_OFFSET(0x647ECE), nMaxGrade);
		// CMem::WriteUChar(MAIN_OFFSET(0x647EDA), nMaxGrade);
		// CMem::WriteUChar(MAIN_OFFSET(0x647F82), nMaxGrade);
		// CMem::WriteUChar(MAIN_OFFSET(0x647F88), nMaxGrade);
		// CMem::WriteUChar(MAIN_OFFSET(0x66521D), nMaxGrade);
		// CMem::WriteUChar(MAIN_OFFSET(0x665223), nMaxGrade);
		// SUBHOOK_SETUP(addServerHackCnt);
		// SUBHOOK_SETUP(put_header);
		// SUBHOOK_SETUP(IsCurCharacVisible);
		// SUBHOOK_SETUP(IsRoutingItem);
		// SUBHOOK_SETUP(setCharacInfoDetail);
		// SUBHOOK_SETUP(IsGameMasterMode);
		// SUBHOOK_SETUP(isGMUser);
		// SUBHOOK_SETUP(isGM);
		// SUBHOOK_SETUP(isGM1);
		// SUBHOOK_SETUP(GetPvPTeamCount);
		// SUBHOOK_SETUP(set_add_info);
		SUBHOOK_SETUP(reach_game_world);
		SUBHOOK_SETUP(Leninsert_user);
		SUBHOOK_SETUP(LenGetTimerMess);
		SUBHOOK_SETUP(LenGameWorld_move_position);
		// SUBHOOK_SETUP(Lengetareauseridlist);
		// SUBHOOK_SETUP(Inter_LoadEtc_dispatch_sig);
		// SUBHOOK_SETUP(send_area_users);
		SUBHOOK_SETUP(Inter_LoadGeolocation_dispatch_sig);
		SUBHOOK_SETUP(History_Log);
		// 发送邮件HOOK
		// SUBHOOK_SETUP(ReqDBSendNewSystemMultiMail);
		// 发送道具
		// SUBHOOK_SETUP(AddItem);
		// 账号首角色送成长契约
		// SUBHOOK_SETUP(InterSelectMobileAuthReward);
		// 创建角色创建技能
		// SUBHOOK_SETUP(CreateSkill);
		// 创建角色创建装备
		SUBHOOK_SETUP(CreateEquip);
		// 使用金币
		// SUBHOOK_SETUP(UseGlod);
		// BOSS死亡
		SUBHOOK_SETUP(BossDieCheckSend);
		// 放弃副本
		SUBHOOK_SETUP(Giveup_Game);
		// 用户每五分钟执行
		SUBHOOK_SETUP(CUserWorkPerFiveMin);
		// 每帧执行
		// SUBHOOK_SETUP(TimerDispatcher_dispatch);
		// 设置角色等级
		// SUBHOOK_SETUP(SetUserMaxLevel);

		// SUBHOOK_SETUP(doDispatch); // 收包注册

		// CMem::HookJmp(0x86c2994, (int)insert_user_send_to_all);

		Controller::Get()
			->init();
		// SUBHOOK_SETUP(isSocketAvatar);
		// if (nMaxGrade > 70)
		// {
		// 	// 以下需要扩充类大小, 修改偏移
		// 	CMem::WriteUInt(MAIN_OFFSET(0x87162 + 3), 0xB678 + nMaxGrade * 4 + nMaxGrade * 12);
		// 	// CDataManager::set_reward_sp
		// 	CMem::WriteUInt(MAIN_OFFSET(0x318C26 + 2), 10836 + 840);
		// 	CMem::WriteUChar(MAIN_OFFSET(0x318C3B), nMaxGrade);
		// 	CMem::WriteUInt(MAIN_OFFSET(0x318C68 + 2), 10836 + 840);
		// 	CMem::WriteUChar(MAIN_OFFSET(0x318C79), nMaxGrade);
		// 	// CDataManager::GetSpAtLevelUp
		// 	CMem::WriteUChar(MAIN_OFFSET(0x318CC4), nMaxGrade);
		// 	CMem::WriteUInt(MAIN_OFFSET(0x318CD4 + 2), 10836 + 840);
		// }
		// CMem::WriteUChar(MAIN_OFFSET(0x61B8F6), nMaxGrade);
		// CMem::WriteUChar(MAIN_OFFSET(0x622659), nMaxGrade);
		// CMem::WriteUChar(MAIN_OFFSET(0x622941), nMaxGrade);
		// CMem::WriteUChar(MAIN_OFFSET(0x622941), nMaxGrade);
	}
}

void __attribute__((constructor)) lenheart_init(void)
{
	Lenheart();
}
