mirror of
https://github.com/ytsodacan/Faucet.git
synced 2026-07-28 00:13:11 +00:00
idrk
This commit is contained in:
parent
6c101a6b1b
commit
40aea3e780
|
|
@ -4,6 +4,7 @@
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <vector>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <gdiplus.h>
|
#include <gdiplus.h>
|
||||||
|
|
@ -14,30 +15,28 @@ static HWND g_SplashWnd = NULL;
|
||||||
static HWND g_StatusWnd = NULL;
|
static HWND g_StatusWnd = NULL;
|
||||||
static HWND g_CountWnd = NULL;
|
static HWND g_CountWnd = NULL;
|
||||||
static HWND g_FailWnd = NULL;
|
static HWND g_FailWnd = NULL;
|
||||||
static int g_TotalModsFound = 0;
|
static int g_TotalMods = 0;
|
||||||
static int g_ModsLoadedCount = 0;
|
static int g_LoadedMods = 0;
|
||||||
static int g_ModsFailedCount = 0;
|
static int g_FailedMods = 0;
|
||||||
|
|
||||||
static ULONG_PTR g_gdiplusToken;
|
static ULONG_PTR g_gdiplusToken;
|
||||||
|
|
||||||
LRESULT CALLBACK SplashWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
|
LRESULT CALLBACK SplashWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
|
||||||
switch (msg) {
|
if (msg == WM_PAINT) {
|
||||||
case WM_PAINT: {
|
|
||||||
PAINTSTRUCT ps;
|
PAINTSTRUCT ps;
|
||||||
HDC hdc = BeginPaint(hwnd, &ps);
|
HDC hdc = BeginPaint(hwnd, &ps);
|
||||||
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
|
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
|
||||||
EndPaint(hwnd, &ps);
|
EndPaint(hwnd, &ps);
|
||||||
} return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return DefWindowProc(hwnd, msg, wParam, lParam);
|
return DefWindowProc(hwnd, msg, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateSplash() {
|
void CreateSplash() {
|
||||||
|
|
||||||
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
|
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
|
||||||
Gdiplus::GdiplusStartup(&g_gdiplusToken, &gdiplusStartupInput, NULL);
|
Gdiplus::GdiplusStartup(&g_gdiplusToken, &gdiplusStartupInput, NULL);
|
||||||
|
|
||||||
WNDCLASSW wc = { 0 };
|
WNDCLASSW wc = {};
|
||||||
wc.lpfnWndProc = SplashWndProc;
|
wc.lpfnWndProc = SplashWndProc;
|
||||||
wc.hInstance = GetModuleHandle(NULL);
|
wc.hInstance = GetModuleHandle(NULL);
|
||||||
wc.lpszClassName = L"ModLoaderSplash";
|
wc.lpszClassName = L"ModLoaderSplash";
|
||||||
|
|
@ -45,74 +44,70 @@ void CreateSplash() {
|
||||||
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||||
RegisterClassW(&wc);
|
RegisterClassW(&wc);
|
||||||
|
|
||||||
int w = 600;
|
const int w = 600, h = 400;
|
||||||
int h = 400;
|
const int x = (GetSystemMetrics(SM_CXSCREEN) - w) / 2;
|
||||||
int x = (GetSystemMetrics(SM_CXSCREEN) - w) / 2;
|
const int y = (GetSystemMetrics(SM_CYSCREEN) - h) / 2;
|
||||||
int y = (GetSystemMetrics(SM_CYSCREEN) - h) / 2;
|
|
||||||
|
|
||||||
g_SplashWnd = CreateWindowExW(WS_EX_TOPMOST, wc.lpszClassName, L"Faucet",
|
g_SplashWnd = CreateWindowExW(WS_EX_TOPMOST, wc.lpszClassName, L"Faucet",
|
||||||
WS_POPUP | WS_BORDER | WS_VISIBLE, x, y, w, h, NULL, NULL, wc.hInstance, NULL);
|
WS_POPUP | WS_BORDER | WS_VISIBLE, x, y, w, h, NULL, NULL, wc.hInstance, NULL);
|
||||||
|
|
||||||
CreateWindowW(L"STATIC", L"FAUCET", WS_CHILD | WS_VISIBLE | SS_CENTER,
|
CreateWindowW(L"STATIC", L"FAUCET",
|
||||||
|
WS_CHILD | WS_VISIBLE | SS_CENTER,
|
||||||
0, 20, w, 40, g_SplashWnd, NULL, wc.hInstance, NULL);
|
0, 20, w, 40, g_SplashWnd, NULL, wc.hInstance, NULL);
|
||||||
|
|
||||||
HWND hLogo = CreateWindowW(L"STATIC", NULL,
|
HWND hLogo = CreateWindowW(L"STATIC", NULL,
|
||||||
WS_CHILD | WS_VISIBLE | SS_BITMAP | SS_CENTERIMAGE,
|
WS_CHILD | WS_VISIBLE | SS_BITMAP | SS_CENTERIMAGE,
|
||||||
100, 70, 400, 150,
|
100, 70, 400, 150, g_SplashWnd, NULL, wc.hInstance, NULL);
|
||||||
g_SplashWnd, NULL, wc.hInstance, NULL);
|
|
||||||
|
|
||||||
wchar_t buffer[MAX_PATH];
|
wchar_t buffer[MAX_PATH];
|
||||||
GetModuleFileNameW(NULL, buffer, MAX_PATH);
|
GetModuleFileNameW(NULL, buffer, MAX_PATH);
|
||||||
std::wstring exePath = buffer;
|
std::wstring exeDir = std::wstring(buffer);
|
||||||
std::wstring exeDir = exePath.substr(0, exePath.find_last_of(L"\\/"));
|
exeDir = exeDir.substr(0, exeDir.find_last_of(L"\\/"));
|
||||||
std::wstring fullPath = exeDir + L"\\Common\\Media\\Faucet.png";
|
std::wstring imagePath = exeDir + L"\\Common\\Media\\Faucet.png";
|
||||||
|
|
||||||
DWORD dwAttrib = GetFileAttributesW(fullPath.c_str());
|
Gdiplus::Bitmap* bitmap = Gdiplus::Bitmap::FromFile(imagePath.c_str());
|
||||||
if (dwAttrib == INVALID_FILE_ATTRIBUTES) {
|
|
||||||
std::wstring errorMsg = L"Image not found at:\n" + fullPath;
|
|
||||||
MessageBoxW(g_SplashWnd, errorMsg.c_str(), L"File Error", MB_ICONERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
Gdiplus::Bitmap* bitmap = Gdiplus::Bitmap::FromFile(fullPath.c_str());
|
|
||||||
if (bitmap && bitmap->GetLastStatus() == Gdiplus::Ok) {
|
if (bitmap && bitmap->GetLastStatus() == Gdiplus::Ok) {
|
||||||
HBITMAP hBmp = NULL;
|
HBITMAP hBmp = NULL;
|
||||||
Gdiplus::Status status = bitmap->GetHBITMAP(Gdiplus::Color(255, 255, 255, 255), &hBmp);
|
if (bitmap->GetHBITMAP(Gdiplus::Color(255, 255, 255, 255), &hBmp) == Gdiplus::Ok && hBmp) {
|
||||||
|
HBITMAP hOld = (HBITMAP)SendMessage(hLogo, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBmp);
|
||||||
if (status == Gdiplus::Ok && hBmp != NULL) {
|
if (hOld) DeleteObject(hOld);
|
||||||
SendMessage(hLogo, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBmp);
|
|
||||||
}
|
}
|
||||||
delete bitmap;
|
|
||||||
}
|
}
|
||||||
|
delete bitmap;
|
||||||
|
|
||||||
g_StatusWnd = CreateWindowW(L"STATIC", L"Preparing...", WS_CHILD | WS_VISIBLE | SS_CENTER,
|
g_StatusWnd = CreateWindowW(L"STATIC", L"Preparing...",
|
||||||
|
WS_CHILD | WS_VISIBLE | SS_CENTER,
|
||||||
10, 240, 580, 40, g_SplashWnd, NULL, wc.hInstance, NULL);
|
10, 240, 580, 40, g_SplashWnd, NULL, wc.hInstance, NULL);
|
||||||
|
|
||||||
g_CountWnd = CreateWindowW(L"STATIC", L"0/0 MODS LOADED", WS_CHILD | WS_VISIBLE | SS_LEFT,
|
g_CountWnd = CreateWindowW(L"STATIC", L"0/0 MODS LOADED",
|
||||||
|
WS_CHILD | WS_VISIBLE | SS_LEFT,
|
||||||
20, 350, 200, 20, g_SplashWnd, NULL, wc.hInstance, NULL);
|
20, 350, 200, 20, g_SplashWnd, NULL, wc.hInstance, NULL);
|
||||||
|
|
||||||
g_FailWnd = CreateWindowW(L"STATIC", L"", WS_CHILD | WS_VISIBLE | SS_RIGHT,
|
g_FailWnd = CreateWindowW(L"STATIC", L"",
|
||||||
|
WS_CHILD | WS_VISIBLE | SS_RIGHT,
|
||||||
380, 350, 200, 20, g_SplashWnd, NULL, wc.hInstance, NULL);
|
380, 350, 200, 20, g_SplashWnd, NULL, wc.hInstance, NULL);
|
||||||
|
|
||||||
UpdateWindow(g_SplashWnd);
|
UpdateWindow(g_SplashWnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateSplashStatus(const std::wstring& text) {
|
void UpdateSplashStatus(const std::wstring& text) {
|
||||||
if (g_StatusWnd) {
|
if (!g_StatusWnd) return;
|
||||||
SendMessageW(g_StatusWnd, WM_SETTEXT, 0, (LPARAM)text.c_str());
|
|
||||||
|
|
||||||
std::wstring countText = std::to_wstring(g_ModsLoadedCount) + L"/" + std::to_wstring(g_TotalModsFound) + L" MODS LOADED";
|
SendMessageW(g_StatusWnd, WM_SETTEXT, 0, (LPARAM)text.c_str());
|
||||||
SendMessageW(g_CountWnd, WM_SETTEXT, 0, (LPARAM)countText.c_str());
|
|
||||||
|
|
||||||
if (g_ModsFailedCount > 0) {
|
std::wstring countText = std::to_wstring(g_LoadedMods) + L"/"
|
||||||
std::wstring failText = std::to_wstring(g_ModsFailedCount) + L" HAVE FAILED TO LOAD";
|
+ std::to_wstring(g_TotalMods) + L" MODS LOADED";
|
||||||
SendMessageW(g_FailWnd, WM_SETTEXT, 0, (LPARAM)failText.c_str());
|
SendMessageW(g_CountWnd, WM_SETTEXT, 0, (LPARAM)countText.c_str());
|
||||||
}
|
|
||||||
|
|
||||||
MSG msg;
|
if (g_FailedMods > 0) {
|
||||||
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
std::wstring failText = std::to_wstring(g_FailedMods) + L" FAILED TO LOAD";
|
||||||
TranslateMessage(&msg);
|
SendMessageW(g_FailWnd, WM_SETTEXT, 0, (LPARAM)failText.c_str());
|
||||||
DispatchMessage(&msg);
|
}
|
||||||
}
|
|
||||||
|
MSG msg;
|
||||||
|
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||||
|
TranslateMessage(&msg);
|
||||||
|
DispatchMessage(&msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -127,15 +122,19 @@ void ModLoader::Initialize() {
|
||||||
|
|
||||||
auto startTime = std::chrono::steady_clock::now();
|
auto startTime = std::chrono::steady_clock::now();
|
||||||
CreateSplash();
|
CreateSplash();
|
||||||
|
|
||||||
OpenLogFile();
|
OpenLogFile();
|
||||||
Log(L"Faucet ModLoader initializing");
|
|
||||||
|
Log("=== Faucet ModLoader starting ===");
|
||||||
|
|
||||||
std::wstring modsDir = GetModsDirectory();
|
std::wstring modsDir = GetModsDirectory();
|
||||||
ScanAndLoadMods(modsDir);
|
ScanAndLoadMods(modsDir);
|
||||||
|
|
||||||
auto endTime = std::chrono::steady_clock::now();
|
auto endTime = std::chrono::steady_clock::now();
|
||||||
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime).count();
|
long long elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime).count();
|
||||||
|
|
||||||
|
Log("Initialization complete — " + std::to_string(g_LoadedMods) + " loaded, "
|
||||||
|
+ std::to_string(g_FailedMods) + " failed, "
|
||||||
|
+ std::to_string(elapsed) + "ms total");
|
||||||
|
|
||||||
if (elapsed < 1000) {
|
if (elapsed < 1000) {
|
||||||
UpdateSplashStatus(L"Finalizing...");
|
UpdateSplashStatus(L"Finalizing...");
|
||||||
|
|
@ -144,8 +143,8 @@ void ModLoader::Initialize() {
|
||||||
|
|
||||||
if (g_SplashWnd) {
|
if (g_SplashWnd) {
|
||||||
DestroyWindow(g_SplashWnd);
|
DestroyWindow(g_SplashWnd);
|
||||||
|
g_SplashWnd = NULL;
|
||||||
UnregisterClassW(L"ModLoaderSplash", GetModuleHandle(NULL));
|
UnregisterClassW(L"ModLoaderSplash", GetModuleHandle(NULL));
|
||||||
|
|
||||||
Gdiplus::GdiplusShutdown(g_gdiplusToken);
|
Gdiplus::GdiplusShutdown(g_gdiplusToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -153,39 +152,42 @@ void ModLoader::Initialize() {
|
||||||
void ModLoader::NotifyInit() {
|
void ModLoader::NotifyInit() {
|
||||||
for (auto& mod : m_mods) {
|
for (auto& mod : m_mods) {
|
||||||
if (!mod.healthy) continue;
|
if (!mod.healthy) continue;
|
||||||
const char* id = mod.instance->GetInfo()->id;
|
|
||||||
try {
|
try {
|
||||||
if (!mod.instance->OnInit()) {
|
if (!mod.instance->OnInit()) {
|
||||||
|
Log("OnInit() returned false for: " + std::string(mod.instance->GetInfo()->id));
|
||||||
mod.healthy = false;
|
mod.healthy = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
|
Log("OnInit() threw for: " + std::string(mod.instance->GetInfo()->id));
|
||||||
mod.healthy = false;
|
mod.healthy = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModLoader::OnLevelLoad() {
|
void ModLoader::OnLevelLoad() {
|
||||||
Log(L"Level has loaded");
|
Log("Level loaded");
|
||||||
for (auto& mod : m_mods) {
|
for (auto& mod : m_mods) {
|
||||||
if (!mod.healthy) continue;
|
if (!mod.healthy) continue;
|
||||||
try {
|
try {
|
||||||
mod.instance->OnLevelLoad();
|
mod.instance->OnLevelLoad();
|
||||||
}
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
|
Log("OnLevelLoad() threw for: " + std::string(mod.instance->GetInfo()->id));
|
||||||
mod.healthy = false;
|
mod.healthy = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModLoader::OnLevelUnload() {
|
void ModLoader::OnLevelUnload() {
|
||||||
Log(L"Level has unloaded");
|
Log("Level unloaded");
|
||||||
for (auto& mod : m_mods) {
|
for (auto& mod : m_mods) {
|
||||||
if (!mod.healthy) continue;
|
if (!mod.healthy) continue;
|
||||||
try {
|
try {
|
||||||
mod.instance->OnLevelUnload();
|
mod.instance->OnLevelUnload();
|
||||||
}
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
|
Log("OnLevelUnload() threw for: " + std::string(mod.instance->GetInfo()->id));
|
||||||
mod.healthy = false;
|
mod.healthy = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -194,26 +196,29 @@ void ModLoader::OnLevelUnload() {
|
||||||
void ModLoader::NotifyUpdate(float deltaTime) {
|
void ModLoader::NotifyUpdate(float deltaTime) {
|
||||||
for (auto& mod : m_mods) {
|
for (auto& mod : m_mods) {
|
||||||
if (!mod.healthy) continue;
|
if (!mod.healthy) continue;
|
||||||
if (mod.instance == nullptr) {
|
if (!mod.instance) {
|
||||||
mod.healthy = false;
|
mod.healthy = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (!mod.instance->OnUpdate(deltaTime)) {
|
if (!mod.instance->OnUpdate(deltaTime)) {
|
||||||
|
Log("OnUpdate() returned false for: " + std::string(mod.instance->GetInfo()->id));
|
||||||
mod.healthy = false;
|
mod.healthy = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
|
Log("OnUpdate() threw for: " + std::string(mod.instance->GetInfo()->id));
|
||||||
mod.healthy = false;
|
mod.healthy = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModLoader::Shutdown() {
|
void ModLoader::Shutdown() {
|
||||||
for (int i = static_cast<int>(m_mods.size()) - 1; i >= 0; --i) {
|
Log("Shutting down ModLoader");
|
||||||
|
for (int i = static_cast<int>(m_mods.size()) - 1; i >= 0; --i)
|
||||||
UnloadOneMod(m_mods[i]);
|
UnloadOneMod(m_mods[i]);
|
||||||
}
|
|
||||||
m_mods.clear();
|
m_mods.clear();
|
||||||
|
|
||||||
if (m_logFile != INVALID_HANDLE_VALUE) {
|
if (m_logFile != INVALID_HANDLE_VALUE) {
|
||||||
CloseHandle(m_logFile);
|
CloseHandle(m_logFile);
|
||||||
m_logFile = INVALID_HANDLE_VALUE;
|
m_logFile = INVALID_HANDLE_VALUE;
|
||||||
|
|
@ -223,9 +228,8 @@ void ModLoader::Shutdown() {
|
||||||
IMod* ModLoader::FindMod(const std::string& id) const {
|
IMod* ModLoader::FindMod(const std::string& id) const {
|
||||||
for (const auto& mod : m_mods) {
|
for (const auto& mod : m_mods) {
|
||||||
if (mod.healthy && mod.instance &&
|
if (mod.healthy && mod.instance &&
|
||||||
std::string(mod.instance->GetInfo()->id) == id) {
|
std::string(mod.instance->GetInfo()->id) == id)
|
||||||
return mod.instance;
|
return mod.instance;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
@ -234,34 +238,51 @@ void ModLoader::ScanAndLoadMods(const std::wstring& modsDir) {
|
||||||
DWORD dwAttrib = GetFileAttributesW(modsDir.c_str());
|
DWORD dwAttrib = GetFileAttributesW(modsDir.c_str());
|
||||||
if (dwAttrib == INVALID_FILE_ATTRIBUTES || !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) {
|
if (dwAttrib == INVALID_FILE_ATTRIBUTES || !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) {
|
||||||
CreateDirectoryW(modsDir.c_str(), NULL);
|
CreateDirectoryW(modsDir.c_str(), NULL);
|
||||||
|
Log("Mods directory not found — created it");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::wstring> dllPaths;
|
||||||
std::wstring searchPath = modsDir + L"\\*.dll";
|
std::wstring searchPath = modsDir + L"\\*.dll";
|
||||||
WIN32_FIND_DATAW fd;
|
WIN32_FIND_DATAW fd;
|
||||||
HANDLE hFind = FindFirstFileW(searchPath.c_str(), &fd);
|
HANDLE hFind = FindFirstFileW(searchPath.c_str(), &fd);
|
||||||
|
|
||||||
if (hFind != INVALID_HANDLE_VALUE) {
|
if (hFind != INVALID_HANDLE_VALUE) {
|
||||||
do {
|
do {
|
||||||
if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
|
if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
||||||
std::wstring fullPath = modsDir + L"\\" + fd.cFileName;
|
dllPaths.push_back(modsDir + L"\\" + fd.cFileName);
|
||||||
UpdateSplashStatus(L"Loading: " + std::wstring(fd.cFileName));
|
|
||||||
LoadOneMod(fullPath);
|
|
||||||
}
|
|
||||||
} while (FindNextFileW(hFind, &fd));
|
} while (FindNextFileW(hFind, &fd));
|
||||||
FindClose(hFind);
|
FindClose(hFind);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_TotalMods = static_cast<int>(dllPaths.size());
|
||||||
|
Log("Found " + std::to_string(g_TotalMods) + " mod(s) to load");
|
||||||
|
|
||||||
|
for (const auto& path : dllPaths) {
|
||||||
|
std::wstring filename = path.substr(path.find_last_of(L"\\/") + 1);
|
||||||
|
UpdateSplashStatus(L"Loading: " + filename);
|
||||||
|
LoadOneMod(path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModLoader::LoadOneMod(const std::wstring& dllPath) {
|
bool ModLoader::LoadOneMod(const std::wstring& dllPath) {
|
||||||
|
std::string narrowPath(dllPath.begin(), dllPath.end());
|
||||||
|
std::string filename = narrowPath.substr(narrowPath.find_last_of("\\/") + 1);
|
||||||
|
|
||||||
|
auto t0 = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
HMODULE hMod = LoadLibraryW(dllPath.c_str());
|
HMODULE hMod = LoadLibraryW(dllPath.c_str());
|
||||||
if (!hMod) return false;
|
if (!hMod) {
|
||||||
|
Log("FAIL [" + filename + "] LoadLibrary failed (error " + std::to_string(GetLastError()) + ")");
|
||||||
|
++g_FailedMods;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
using CreateModFn = IMod * (*)();
|
using CreateModFn = IMod * (*)();
|
||||||
auto createFn = reinterpret_cast<CreateModFn>(GetProcAddress(hMod, "CreateMod"));
|
auto createFn = reinterpret_cast<CreateModFn>(GetProcAddress(hMod, "CreateMod"));
|
||||||
|
|
||||||
if (!createFn) {
|
if (!createFn) {
|
||||||
|
Log("FAIL [" + filename + "] missing CreateMod export");
|
||||||
FreeLibrary(hMod);
|
FreeLibrary(hMod);
|
||||||
|
++g_FailedMods;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -270,37 +291,67 @@ bool ModLoader::LoadOneMod(const std::wstring& dllPath) {
|
||||||
instance = createFn();
|
instance = createFn();
|
||||||
}
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
|
Log("FAIL [" + filename + "] CreateMod() threw");
|
||||||
FreeLibrary(hMod);
|
FreeLibrary(hMod);
|
||||||
|
++g_FailedMods;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!instance) {
|
if (!instance) {
|
||||||
|
Log("FAIL [" + filename + "] CreateMod() returned null");
|
||||||
FreeLibrary(hMod);
|
FreeLibrary(hMod);
|
||||||
|
++g_FailedMods;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ModInfo* info = instance->GetInfo();
|
||||||
|
std::string modId = info ? info->id : "(unknown)";
|
||||||
|
std::string modVer = info
|
||||||
|
? std::to_string(info->version.major) + "."
|
||||||
|
+ std::to_string(info->version.minor) + "."
|
||||||
|
+ std::to_string(info->version.patch)
|
||||||
|
: "(unknown)";
|
||||||
|
|
||||||
LoadedMod record;
|
LoadedMod record;
|
||||||
record.module = hMod;
|
record.module = hMod;
|
||||||
record.instance = instance;
|
record.instance = instance;
|
||||||
record.path = std::string(dllPath.begin(), dllPath.end());
|
record.path = narrowPath;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!instance->OnLoad()) {
|
if (!instance->OnLoad()) {
|
||||||
|
Log("WARN [" + modId + " " + modVer + "] OnLoad() returned false — marking unhealthy");
|
||||||
record.healthy = false;
|
record.healthy = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
|
Log("FAIL [" + modId + " " + modVer + "] OnLoad() threw — marking unhealthy");
|
||||||
record.healthy = false;
|
record.healthy = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||||
|
std::chrono::steady_clock::now() - t0).count();
|
||||||
|
|
||||||
|
if (record.healthy) {
|
||||||
|
Log("OK [" + modId + " " + modVer + "] loaded in " + std::to_string(elapsed) + "ms");
|
||||||
|
++g_LoadedMods;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
++g_FailedMods;
|
||||||
|
}
|
||||||
|
|
||||||
m_mods.push_back(std::move(record));
|
m_mods.push_back(std::move(record));
|
||||||
return true;
|
return record.healthy;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModLoader::UnloadOneMod(LoadedMod& mod) {
|
void ModLoader::UnloadOneMod(LoadedMod& mod) {
|
||||||
if (!mod.instance) return;
|
if (!mod.instance) return;
|
||||||
|
|
||||||
|
if (mod.instance->GetInfo())
|
||||||
|
Log("Unloading: " + std::string(mod.instance->GetInfo()->id));
|
||||||
|
|
||||||
delete mod.instance;
|
delete mod.instance;
|
||||||
mod.instance = nullptr;
|
mod.instance = nullptr;
|
||||||
|
|
||||||
if (mod.module) {
|
if (mod.module) {
|
||||||
FreeLibrary(mod.module);
|
FreeLibrary(mod.module);
|
||||||
mod.module = nullptr;
|
mod.module = nullptr;
|
||||||
|
|
@ -308,30 +359,38 @@ void ModLoader::UnloadOneMod(LoadedMod& mod) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModLoader::OpenLogFile() {
|
void ModLoader::OpenLogFile() {
|
||||||
std::wstring dir = GetModsDirectory();
|
std::wstring logPath = GetModsDirectory() + L"\\modloader.log";
|
||||||
std::wstring logPath = dir + L"\\modloader.log";
|
CreateDirectoryW(GetModsDirectory().c_str(), NULL);
|
||||||
CreateDirectoryW(dir.c_str(), NULL);
|
|
||||||
m_logFile = CreateFileW(logPath.c_str(), GENERIC_WRITE, FILE_SHARE_READ,
|
m_logFile = CreateFileW(logPath.c_str(), GENERIC_WRITE, FILE_SHARE_READ,
|
||||||
nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||||
|
|
||||||
|
if (m_logFile != INVALID_HANDLE_VALUE) {
|
||||||
|
BYTE bom[3] = { 0xEF, 0xBB, 0xBF };
|
||||||
|
DWORD written;
|
||||||
|
WriteFile(m_logFile, bom, 3, &written, nullptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModLoader::Log(const std::wstring& msg) {
|
void ModLoader::Log(const std::string& msg) {
|
||||||
auto now = std::chrono::system_clock::now();
|
auto now = std::chrono::system_clock::now();
|
||||||
std::time_t t = std::chrono::system_clock::to_time_t(now);
|
std::time_t t = std::chrono::system_clock::to_time_t(now);
|
||||||
struct tm buf;
|
struct tm buf;
|
||||||
localtime_s(&buf, &t);
|
localtime_s(&buf, &t);
|
||||||
char ts[16];
|
char ts[16];
|
||||||
std::strftime(ts, sizeof(ts), "[%H:%M:%S] ", &buf);
|
std::strftime(ts, sizeof(ts), "[%H:%M:%S] ", &buf);
|
||||||
std::wstring line = std::wstring(ts, ts + strlen(ts)) + msg + L"\r\n";
|
|
||||||
|
std::string line = std::string(ts) + msg + "\r\n";
|
||||||
|
|
||||||
if (m_logFile != INVALID_HANDLE_VALUE) {
|
if (m_logFile != INVALID_HANDLE_VALUE) {
|
||||||
DWORD written;
|
DWORD written;
|
||||||
WriteFile(m_logFile, line.c_str(), static_cast<DWORD>(line.size() * sizeof(wchar_t)), &written, nullptr);
|
WriteFile(m_logFile, line.c_str(), static_cast<DWORD>(line.size()), &written, nullptr);
|
||||||
}
|
}
|
||||||
OutputDebugStringW(line.c_str());
|
|
||||||
|
OutputDebugStringA(line.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModLoader::Log(const std::string& msg) {
|
void ModLoader::Log(const std::wstring& msg) {
|
||||||
Log(std::wstring(msg.begin(), msg.end()));
|
Log(std::string(msg.begin(), msg.end()));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::wstring ModLoader::GetModsDirectory() const {
|
std::wstring ModLoader::GetModsDirectory() const {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,37 @@
|
||||||
SDK.cpp
|
ModLoader.cpp
|
||||||
|
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\include\xutility(4813,18): warning C4244: '=': conversion from 'const wchar_t' to 'char', possible loss of data
|
||||||
|
(compiling source file '/ModLoader.cpp')
|
||||||
|
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\include\xutility(4813,18):
|
||||||
|
the template instantiation context (the oldest one first) is
|
||||||
|
S:\GitHub\Faucet\Minecraft.Client\ModLoader.cpp(285,30):
|
||||||
|
see reference to function template instantiation 'std::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string<std::_String_const_iterator<std::_String_val<std::_Simple_types<_Elem>>>,0>(_Iter,_Iter,const _Alloc &)' being compiled
|
||||||
|
with
|
||||||
|
[
|
||||||
|
_Elem=wchar_t,
|
||||||
|
_Iter=std::_String_const_iterator<std::_String_val<std::_Simple_types<wchar_t>>>,
|
||||||
|
_Alloc=std::allocator<char>
|
||||||
|
]
|
||||||
|
S:\GitHub\Faucet\Minecraft.Client\ModLoader.cpp(285,17):
|
||||||
|
see the first reference to 'std::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string' in 'ModLoader::LoadOneMod'
|
||||||
|
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\include\xstring(812,17):
|
||||||
|
see reference to function template instantiation 'void std::basic_string<char,std::char_traits<char>,std::allocator<char>>::_Construct_from_iter<const wchar_t*,const wchar_t*,_Size_type>(_Iter,const _Sent,_Size)' being compiled
|
||||||
|
with
|
||||||
|
[
|
||||||
|
_Size_type=unsigned __int64,
|
||||||
|
_Iter=const wchar_t *,
|
||||||
|
_Sent=const wchar_t *,
|
||||||
|
_Size=unsigned __int64
|
||||||
|
]
|
||||||
|
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\include\xstring(968,18):
|
||||||
|
see reference to function template instantiation '_OutIt *std::_Copy_n_unchecked4<const wchar_t*,_Size,char*>(_InIt,_SizeTy,_OutIt)' being compiled
|
||||||
|
with
|
||||||
|
[
|
||||||
|
_OutIt=char *,
|
||||||
|
_Size=unsigned __int64,
|
||||||
|
_InIt=const wchar_t *,
|
||||||
|
_SizeTy=unsigned __int64
|
||||||
|
]
|
||||||
|
|
||||||
Microsoft (R) Incremental Linker Version 14.44.35222.0
|
Microsoft (R) Incremental Linker Version 14.44.35222.0
|
||||||
Copyright (C) Microsoft Corporation. All rights reserved.
|
Copyright (C) Microsoft Corporation. All rights reserved.
|
||||||
"/OUT:S:\GitHub\Faucet\x64\Debug\Faucet.exe" /INCREMENTAL "/ILK:x64\Debug\Faucet.ilk" d3d11.lib ..\Minecraft.World\x64_Debug\Minecraft.World.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib XInput9_1_0.lib ..\Minecraft.Client\Windows64\Miles\Lib\mss64.lib wsock32.lib /MANIFEST "/MANIFESTUAC:level='asInvoker' uiAccess='false'" /manifest:embed /DEBUG "/PDB:S:\GitHub\Faucet\x64\Debug\Minecraft.Client.pdb" /TLBID:1 /DYNAMICBASE /NXCOMPAT "/IMPLIB:S:\GitHub\Faucet\x64\Debug\Faucet.lib" /MACHINE:X64 x64\Debug\MinecraftWindows.res
|
"/OUT:S:\GitHub\Faucet\x64\Debug\Faucet.exe" /INCREMENTAL "/ILK:x64\Debug\Faucet.ilk" d3d11.lib ..\Minecraft.World\x64_Debug\Minecraft.World.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib XInput9_1_0.lib ..\Minecraft.Client\Windows64\Miles\Lib\mss64.lib wsock32.lib /MANIFEST "/MANIFESTUAC:level='asInvoker' uiAccess='false'" /manifest:embed /DEBUG "/PDB:S:\GitHub\Faucet\x64\Debug\Minecraft.Client.pdb" /TLBID:1 /DYNAMICBASE /NXCOMPAT "/IMPLIB:S:\GitHub\Faucet\x64\Debug\Faucet.lib" /MACHINE:X64 x64\Debug\MinecraftWindows.res
|
||||||
|
|
@ -506,40 +539,6 @@
|
||||||
Windows64\Iggy\lib\iggy_w64.lib
|
Windows64\Iggy\lib\iggy_w64.lib
|
||||||
Windows64\Miles\lib\mss64.lib
|
Windows64\Miles\lib\mss64.lib
|
||||||
x64\Debug\iob_shim.obj
|
x64\Debug\iob_shim.obj
|
||||||
4J_Input_d.lib(4J_Input.obj) : warning LNK4099: PDB 'vc110.pdb' was not found with '4J_Input_d.lib(4J_Input.obj)' or at 'S:\GitHub\Faucet\x64\Debug\vc110.pdb'; linking object as if no debug info
|
|
||||||
4J_Input_d.lib(INP_Keyboard.obj) : warning LNK4099: PDB 'vc110.pdb' was not found with '4J_Input_d.lib(INP_Keyboard.obj)' or at 'S:\GitHub\Faucet\x64\Debug\vc110.pdb'; linking object as if no debug info
|
|
||||||
4J_Input_d.lib(INP_Main.obj) : warning LNK4099: PDB 'vc110.pdb' was not found with '4J_Input_d.lib(INP_Main.obj)' or at 'S:\GitHub\Faucet\x64\Debug\vc110.pdb'; linking object as if no debug info
|
|
||||||
4J_Input_d.lib(stdafx.obj) : warning LNK4099: PDB 'vc110.pdb' was not found with '4J_Input_d.lib(stdafx.obj)' or at 'S:\GitHub\Faucet\x64\Debug\vc110.pdb'; linking object as if no debug info
|
|
||||||
4J_Input_d.lib(LinkedList.obj) : warning LNK4099: PDB 'vc110.pdb' was not found with '4J_Input_d.lib(LinkedList.obj)' or at 'S:\GitHub\Faucet\x64\Debug\vc110.pdb'; linking object as if no debug info
|
|
||||||
4J_Input_d.lib(INP_ForceFeedback.obj) : warning LNK4099: PDB 'vc110.pdb' was not found with '4J_Input_d.lib(INP_ForceFeedback.obj)' or at 'S:\GitHub\Faucet\x64\Debug\vc110.pdb'; linking object as if no debug info
|
|
||||||
4J_Render_PC_d.lib(4J_Render.obj) : warning LNK4099: PDB 'vc110.pdb' was not found with '4J_Render_PC_d.lib(4J_Render.obj)' or at 'S:\GitHub\Faucet\x64\Debug\vc110.pdb'; linking object as if no debug info
|
|
||||||
4J_Render_PC_d.lib(RendererMatrix.obj) : warning LNK4099: PDB 'vc110.pdb' was not found with '4J_Render_PC_d.lib(RendererMatrix.obj)' or at 'S:\GitHub\Faucet\x64\Debug\vc110.pdb'; linking object as if no debug info
|
|
||||||
4J_Render_PC_d.lib(RendererCore.obj) : warning LNK4099: PDB 'vc110.pdb' was not found with '4J_Render_PC_d.lib(RendererCore.obj)' or at 'S:\GitHub\Faucet\x64\Debug\vc110.pdb'; linking object as if no debug info
|
|
||||||
4J_Render_PC_d.lib(RendererVertex.obj) : warning LNK4099: PDB 'vc110.pdb' was not found with '4J_Render_PC_d.lib(RendererVertex.obj)' or at 'S:\GitHub\Faucet\x64\Debug\vc110.pdb'; linking object as if no debug info
|
|
||||||
4J_Render_PC_d.lib(RendererCBuff.obj) : warning LNK4099: PDB 'vc110.pdb' was not found with '4J_Render_PC_d.lib(RendererCBuff.obj)' or at 'S:\GitHub\Faucet\x64\Debug\vc110.pdb'; linking object as if no debug info
|
|
||||||
4J_Render_PC_d.lib(RendererTexture.obj) : warning LNK4099: PDB 'vc110.pdb' was not found with '4J_Render_PC_d.lib(RendererTexture.obj)' or at 'S:\GitHub\Faucet\x64\Debug\vc110.pdb'; linking object as if no debug info
|
|
||||||
4J_Render_PC_d.lib(RendererState.obj) : warning LNK4099: PDB 'vc110.pdb' was not found with '4J_Render_PC_d.lib(RendererState.obj)' or at 'S:\GitHub\Faucet\x64\Debug\vc110.pdb'; linking object as if no debug info
|
|
||||||
4J_Render_PC_d.lib(stdafx.obj) : warning LNK4099: PDB 'vc110.pdb' was not found with '4J_Render_PC_d.lib(stdafx.obj)' or at 'S:\GitHub\Faucet\x64\Debug\vc110.pdb'; linking object as if no debug info
|
|
||||||
4J_Render_PC_d.lib(pngread.obj) : warning LNK4099: PDB 'vc110.pdb' was not found with '4J_Render_PC_d.lib(pngread.obj)' or at 'S:\GitHub\Faucet\x64\Debug\vc110.pdb'; linking object as if no debug info
|
|
||||||
4J_Render_PC_d.lib(pngwrite.obj) : warning LNK4099: PDB 'vc110.pdb' was not found with '4J_Render_PC_d.lib(pngwrite.obj)' or at 'S:\GitHub\Faucet\x64\Debug\vc110.pdb'; linking object as if no debug info
|
|
||||||
4J_Render_PC_d.lib(png.obj) : warning LNK4099: PDB 'vc110.pdb' was not found with '4J_Render_PC_d.lib(png.obj)' or at 'S:\GitHub\Faucet\x64\Debug\vc110.pdb'; linking object as if no debug info
|
|
||||||
4J_Render_PC_d.lib(pngrtran.obj) : warning LNK4099: PDB 'vc110.pdb' was not found with '4J_Render_PC_d.lib(pngrtran.obj)' or at 'S:\GitHub\Faucet\x64\Debug\vc110.pdb'; linking object as if no debug info
|
|
||||||
4J_Render_PC_d.lib(pngtrans.obj) : warning LNK4099: PDB 'vc110.pdb' was not found with '4J_Render_PC_d.lib(pngtrans.obj)' or at 'S:\GitHub\Faucet\x64\Debug\vc110.pdb'; linking object as if no debug info
|
|
||||||
4J_Render_PC_d.lib(pngrio.obj) : warning LNK4099: PDB 'vc110.pdb' was not found with '4J_Render_PC_d.lib(pngrio.obj)' or at 'S:\GitHub\Faucet\x64\Debug\vc110.pdb'; linking object as if no debug info
|
|
||||||
4J_Render_PC_d.lib(pngmem.obj) : warning LNK4099: PDB 'vc110.pdb' was not found with '4J_Render_PC_d.lib(pngmem.obj)' or at 'S:\GitHub\Faucet\x64\Debug\vc110.pdb'; linking object as if no debug info
|
|
||||||
4J_Render_PC_d.lib(pngerror.obj) : warning LNK4099: PDB 'vc110.pdb' was not found with '4J_Render_PC_d.lib(pngerror.obj)' or at 'S:\GitHub\Faucet\x64\Debug\vc110.pdb'; linking object as if no debug info
|
|
||||||
4J_Render_PC_d.lib(pngset.obj) : warning LNK4099: PDB 'vc110.pdb' was not found with '4J_Render_PC_d.lib(pngset.obj)' or at 'S:\GitHub\Faucet\x64\Debug\vc110.pdb'; linking object as if no debug info
|
|
||||||
4J_Render_PC_d.lib(pngget.obj) : warning LNK4099: PDB 'vc110.pdb' was not found with '4J_Render_PC_d.lib(pngget.obj)' or at 'S:\GitHub\Faucet\x64\Debug\vc110.pdb'; linking object as if no debug info
|
|
||||||
4J_Render_PC_d.lib(pngrutil.obj) : warning LNK4099: PDB 'vc110.pdb' was not found with '4J_Render_PC_d.lib(pngrutil.obj)' or at 'S:\GitHub\Faucet\x64\Debug\vc110.pdb'; linking object as if no debug info
|
|
||||||
4J_Render_PC_d.lib(pngwutil.obj) : warning LNK4099: PDB 'vc110.pdb' was not found with '4J_Render_PC_d.lib(pngwutil.obj)' or at 'S:\GitHub\Faucet\x64\Debug\vc110.pdb'; linking object as if no debug info
|
|
||||||
4J_Render_PC_d.lib(pngwio.obj) : warning LNK4099: PDB 'vc110.pdb' was not found with '4J_Render_PC_d.lib(pngwio.obj)' or at 'S:\GitHub\Faucet\x64\Debug\vc110.pdb'; linking object as if no debug info
|
|
||||||
4J_Render_PC_d.lib(pngwtran.obj) : warning LNK4099: PDB 'vc110.pdb' was not found with '4J_Render_PC_d.lib(pngwtran.obj)' or at 'S:\GitHub\Faucet\x64\Debug\vc110.pdb'; linking object as if no debug info
|
|
||||||
4J_Storage_d.lib(4J_Storage.obj) : warning LNK4099: PDB 'vc110.pdb' was not found with '4J_Storage_d.lib(4J_Storage.obj)' or at 'S:\GitHub\Faucet\x64\Debug\vc110.pdb'; linking object as if no debug info
|
|
||||||
4J_Storage_d.lib(STO_SaveGame.obj) : warning LNK4099: PDB 'vc110.pdb' was not found with '4J_Storage_d.lib(STO_SaveGame.obj)' or at 'S:\GitHub\Faucet\x64\Debug\vc110.pdb'; linking object as if no debug info
|
|
||||||
4J_Storage_d.lib(STO_DLC.obj) : warning LNK4099: PDB 'vc110.pdb' was not found with '4J_Storage_d.lib(STO_DLC.obj)' or at 'S:\GitHub\Faucet\x64\Debug\vc110.pdb'; linking object as if no debug info
|
|
||||||
4J_Storage_d.lib(STO_Main.obj) : warning LNK4099: PDB 'vc110.pdb' was not found with '4J_Storage_d.lib(STO_Main.obj)' or at 'S:\GitHub\Faucet\x64\Debug\vc110.pdb'; linking object as if no debug info
|
|
||||||
4J_Storage_d.lib(stdafx.obj) : warning LNK4099: PDB 'vc110.pdb' was not found with '4J_Storage_d.lib(stdafx.obj)' or at 'S:\GitHub\Faucet\x64\Debug\vc110.pdb'; linking object as if no debug info
|
|
||||||
Creating library S:\GitHub\Faucet\x64\Debug\Faucet.lib and object S:\GitHub\Faucet\x64\Debug\Faucet.exp
|
|
||||||
Minecraft.Client.vcxproj -> S:\GitHub\Faucet\x64\Debug\Faucet.exe
|
Minecraft.Client.vcxproj -> S:\GitHub\Faucet\x64\Debug\Faucet.exe
|
||||||
Run post-build script
|
Run post-build script
|
||||||
Post-build script started. Output Directory: S:\GitHub\Faucet\x64\Debug\/, Project Directory: S:\GitHub\Faucet\Minecraft.Client\/
|
Post-build script started. Output Directory: S:\GitHub\Faucet\x64\Debug\/, Project Directory: S:\GitHub\Faucet\Minecraft.Client\/
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in a new issue