Rindro-Plugins/Register_System.hpp

152 lines
4.7 KiB
C++

#pragma once
#include "DNFTOOL.hpp"
#include "zlib.h"
#include <ctime>
#include <sstream>
#include <chrono>
#include "json.hpp"
using json = nlohmann::json;
// 定义互斥锁和需要重载的文件列表
static std::mutex reloadListMutex;
static std::vector<std::string> reloadFileList;
struct AutoReloadSt
{
std::string Path;
};
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 LenheartBase::CBASE64::encode((char*)buffer);
}
void processDirectory(const std::string& directoryPath, std::unordered_map<std::string, std::string>& fileMD5Map) {
std::string searchPath = directoryPath + "\\*";
WIN32_FIND_DATAA findData;
HANDLE hFind = FindFirstFileA(searchPath.c_str(), &findData);
if (hFind != INVALID_HANDLE_VALUE) {
do {
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
if (std::string(findData.cFileName) != "." && std::string(findData.cFileName) != "..") {
std::string subDirPath = directoryPath + "\\" + findData.cFileName;
processDirectory(subDirPath, fileMD5Map);
}
}
else {
std::string filePath = directoryPath + "\\" + findData.cFileName;
if (filePath.find(".nut") == std::string::npos)continue;
std::string currentMD5 = calculateMD5(filePath);
if (fileMD5Map.find(filePath) != fileMD5Map.end()) {
if (fileMD5Map[filePath] != currentMD5) {
fileMD5Map[filePath] = currentMD5;
// 加锁将需要重载的文件添加到列表中
std::lock_guard<std::mutex> lock(reloadListMutex);
reloadFileList.push_back(filePath);
}
}
else {
fileMD5Map[filePath] = currentMD5;
}
}
} while (FindNextFileA(hFind, &findData) != 0);
FindClose(hFind);
}
else {
std::cerr << "无法打开目录:" << directoryPath << std::endl;
}
}
static DWORD WINAPI AutoReloadThread(LPVOID lpParam)
{
AutoReloadSt* Info = static_cast<AutoReloadSt*>(lpParam);
std::string ReloadPath = Info->Path;
delete Info;
std::unordered_map<std::string, std::string> fileMD5Map;
while (true)
{
processDirectory(ReloadPath, fileMD5Map);
Sleep(10);
}
return 0;
}
static SQInteger AutoReload(HSQUIRRELVM v) {
const SQChar* value;
Sq_getstring((HSQUIRRELVM)v, 2, &value);
char* vOutPutText = DNFTOOL::SquirrelU2W(value);
std::string ReloadPath = vOutPutText;
delete[]vOutPutText;
//构造路径结构体传递
AutoReloadSt* Info = new AutoReloadSt();
Info->Path = ReloadPath;
DWORD threadID;
HANDLE Thand = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)AutoReloadThread, Info, 0, &threadID);
return 0;
}
static SQInteger ReloadLogic(HSQUIRRELVM v) {
// 加锁获取需要重载的文件列表
std::lock_guard<std::mutex> lock(reloadListMutex);
for (const auto& file : reloadFileList) {
std::string line = file;
std::string ContentString = "";
std::fstream F;
F.open((line).c_str(), std::ios::in);
if (F.is_open()) {
std::stringstream ContentStringStream;
ContentStringStream << F.rdbuf();
ContentString = (ContentStringStream.str());
F.close();
}
std::wstring filename = DNFTOOL::charTowchar_t((char*)line.c_str(), line.length());
std::wstring str = DNFTOOL::charTowchar_t((char*)ContentString.c_str(), ContentString.length());
if (sq_mycompilebuffer(v, str.c_str(), str.length(), filename.c_str(), true) >= 0) {
Sq_pushroottable(v);
Sq_call(v, 1, SQTrue, SQTrue);
Sq_pop(v, 1);
}
}
// 清空列表
reloadFileList.clear();
return 0;
}
static void RegisterNutApi_System(wchar_t* funcName, SQFUNCTION funcAddr)
{
HSQUIRRELVM v = *(HSQUIRRELVM*)0x1AF3544;
Sq_pushroottable(v);
Sq_pushstring(v, funcName, -1);
RealSqNewClosure(v, funcAddr, 0);
SQNewSlot(v, -3, SQFalse);
SQPopTop(v);
}
void R_Register_System() {
RegisterNutApi_System(L"Sq_AutoReload", AutoReload);//开启热重载
RegisterNutApi_System(L"Sq_ReloadLogic", ReloadLogic);//热重载逻辑(保持主线程加载)
}