mirror of
https://github.com/ytsodacan/Faucet.git
synced 2026-04-23 07:28:07 +00:00
change loading menu to gdi aswell
This commit is contained in:
parent
ee8d07b6f7
commit
2cde10f835
|
|
@ -11,53 +11,154 @@
|
|||
|
||||
#pragma comment(lib, "gdiplus.lib")
|
||||
|
||||
static HWND g_SplashWnd = NULL;
|
||||
static HWND g_StatusWnd = NULL;
|
||||
static HWND g_CountWnd = NULL;
|
||||
static HWND g_FailWnd = NULL;
|
||||
static int g_TotalMods = 0;
|
||||
static int g_LoadedMods = 0;
|
||||
static int g_FailedMods = 0;
|
||||
// ---------------------------------------------------------------------------
|
||||
// Splash state
|
||||
// ---------------------------------------------------------------------------
|
||||
static HWND g_SplashWnd = NULL;
|
||||
static HBITMAP g_hLogoBmp = NULL;
|
||||
static int g_LogoW = 0;
|
||||
static int g_LogoH = 0;
|
||||
static int g_TotalMods = 0;
|
||||
static int g_LoadedMods = 0;
|
||||
static int g_FailedMods = 0;
|
||||
static std::wstring g_StatusText = L"Preparing...";
|
||||
static ULONG_PTR g_gdiplusToken;
|
||||
|
||||
static ULONG_PTR g_gdiplusToken;
|
||||
static HFONT g_hFontTitle = NULL;
|
||||
static HFONT g_hFontStatus = NULL;
|
||||
static HFONT g_hFontCount = NULL;
|
||||
|
||||
LRESULT CALLBACK SplashWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
|
||||
if (msg == WM_PAINT) {
|
||||
PAINTSTRUCT ps;
|
||||
HDC hdc = BeginPaint(hwnd, &ps);
|
||||
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
|
||||
EndPaint(hwnd, &ps);
|
||||
return 0;
|
||||
static const int SW = 600;
|
||||
static const int SH = 400;
|
||||
|
||||
#define SC_BG RGB(24, 24, 24)
|
||||
#define SC_WHITE RGB(255, 255, 255)
|
||||
#define SC_GREY RGB(160, 160, 160)
|
||||
#define SC_RED RGB(220, 60, 60)
|
||||
#define SC_ACCENT RGB(80, 140, 220)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Splash paint
|
||||
// ---------------------------------------------------------------------------
|
||||
static void PaintSplash(HWND hwnd)
|
||||
{
|
||||
PAINTSTRUCT ps;
|
||||
HDC hdc = BeginPaint(hwnd, &ps);
|
||||
|
||||
HDC mem = CreateCompatibleDC(hdc);
|
||||
HBITMAP bmp = CreateCompatibleBitmap(hdc, SW, SH);
|
||||
HBITMAP obmp = (HBITMAP)SelectObject(mem, bmp);
|
||||
|
||||
RECT rc = { 0, 0, SW, SH };
|
||||
HBRUSH bgBr = CreateSolidBrush(SC_BG);
|
||||
FillRect(mem, &rc, bgBr);
|
||||
DeleteObject(bgBr);
|
||||
|
||||
SetBkMode(mem, TRANSPARENT);
|
||||
|
||||
HFONT of = (HFONT)SelectObject(mem, g_hFontTitle);
|
||||
SetTextColor(mem, SC_WHITE);
|
||||
RECT titleR = { 0, 18, SW, 58 };
|
||||
DrawTextW(mem, L"FAUCET", -1, &titleR, DT_CENTER | DT_SINGLELINE | DT_VCENTER);
|
||||
|
||||
HPEN linePen = CreatePen(PS_SOLID, 1, SC_ACCENT);
|
||||
HPEN oldPen = (HPEN)SelectObject(mem, linePen);
|
||||
MoveToEx(mem, 40, 62, NULL);
|
||||
LineTo(mem, SW - 40, 62);
|
||||
SelectObject(mem, oldPen);
|
||||
DeleteObject(linePen);
|
||||
|
||||
if (g_hLogoBmp)
|
||||
{
|
||||
HDC logoDC = CreateCompatibleDC(mem);
|
||||
HBITMAP old = (HBITMAP)SelectObject(logoDC, g_hLogoBmp);
|
||||
int lx = (SW - g_LogoW) / 2;
|
||||
int ly = 74;
|
||||
BitBlt(mem, lx, ly, g_LogoW, g_LogoH, logoDC, 0, 0, SRCCOPY);
|
||||
SelectObject(logoDC, old);
|
||||
DeleteDC(logoDC);
|
||||
}
|
||||
|
||||
SelectObject(mem, g_hFontStatus);
|
||||
SetTextColor(mem, SC_GREY);
|
||||
RECT statR = { 20, 240, SW - 20, 282 };
|
||||
DrawTextW(mem, g_StatusText.c_str(), -1, &statR, DT_CENTER | DT_SINGLELINE | DT_VCENTER | DT_END_ELLIPSIS);
|
||||
|
||||
int barX = 20, barY = 292, barW = SW - 40, barH = 6;
|
||||
HBRUSH trackBr = CreateSolidBrush(RGB(50, 50, 50));
|
||||
RECT trackR = { barX, barY, barX + barW, barY + barH };
|
||||
FillRect(mem, &trackR, trackBr);
|
||||
DeleteObject(trackBr);
|
||||
|
||||
if (g_TotalMods > 0)
|
||||
{
|
||||
int fillW = (int)((float)g_LoadedMods / g_TotalMods * barW);
|
||||
HBRUSH fillBr = CreateSolidBrush(SC_ACCENT);
|
||||
RECT fillR = { barX, barY, barX + fillW, barY + barH };
|
||||
FillRect(mem, &fillR, fillBr);
|
||||
DeleteObject(fillBr);
|
||||
}
|
||||
|
||||
SelectObject(mem, g_hFontCount);
|
||||
|
||||
std::wstring countText = std::to_wstring(g_LoadedMods) + L"/" + std::to_wstring(g_TotalMods) + L" MODS LOADED";
|
||||
SetTextColor(mem, SC_GREY);
|
||||
RECT countR = { barX, barY + 14, barX + barW / 2, barY + 34 };
|
||||
DrawTextW(mem, countText.c_str(), -1, &countR, DT_LEFT | DT_SINGLELINE | DT_VCENTER);
|
||||
|
||||
if (g_FailedMods > 0)
|
||||
{
|
||||
std::wstring failText = std::to_wstring(g_FailedMods) + L" FAILED";
|
||||
SetTextColor(mem, SC_RED);
|
||||
RECT failR = { barX + barW / 2, barY + 14, barX + barW, barY + 34 };
|
||||
DrawTextW(mem, failText.c_str(), -1, &failR, DT_RIGHT | DT_SINGLELINE | DT_VCENTER);
|
||||
}
|
||||
|
||||
SelectObject(mem, of);
|
||||
|
||||
BitBlt(hdc, 0, 0, SW, SH, mem, 0, 0, SRCCOPY);
|
||||
SelectObject(mem, obmp);
|
||||
DeleteObject(bmp);
|
||||
DeleteDC(mem);
|
||||
|
||||
EndPaint(hwnd, &ps);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Splash window proc
|
||||
// ---------------------------------------------------------------------------
|
||||
LRESULT CALLBACK SplashWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (msg == WM_PAINT) { PaintSplash(hwnd); return 0; }
|
||||
if (msg == WM_ERASEBKGND) { return 1; }
|
||||
return DefWindowProc(hwnd, msg, wParam, lParam);
|
||||
}
|
||||
|
||||
void CreateSplash() {
|
||||
// ---------------------------------------------------------------------------
|
||||
// Splash creation
|
||||
// ---------------------------------------------------------------------------
|
||||
void CreateSplash()
|
||||
{
|
||||
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
|
||||
Gdiplus::GdiplusStartup(&g_gdiplusToken, &gdiplusStartupInput, NULL);
|
||||
|
||||
g_hFontTitle = CreateFontW(28, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Segoe UI");
|
||||
g_hFontStatus = CreateFontW(15, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Segoe UI");
|
||||
g_hFontCount = CreateFontW(13, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Segoe UI");
|
||||
|
||||
WNDCLASSW wc = {};
|
||||
wc.lpfnWndProc = SplashWndProc;
|
||||
wc.hInstance = GetModuleHandle(NULL);
|
||||
wc.lpszClassName = L"ModLoaderSplash";
|
||||
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
||||
wc.hbrBackground = NULL;
|
||||
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||
RegisterClassW(&wc);
|
||||
|
||||
const int w = 600, h = 400;
|
||||
const int x = (GetSystemMetrics(SM_CXSCREEN) - w) / 2;
|
||||
const int y = (GetSystemMetrics(SM_CYSCREEN) - h) / 2;
|
||||
const int x = (GetSystemMetrics(SM_CXSCREEN) - SW) / 2;
|
||||
const int y = (GetSystemMetrics(SM_CYSCREEN) - SH) / 2;
|
||||
|
||||
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);
|
||||
|
||||
CreateWindowW(L"STATIC", L"FAUCET",
|
||||
WS_CHILD | WS_VISIBLE | SS_CENTER,
|
||||
0, 20, w, 40, g_SplashWnd, NULL, wc.hInstance, NULL);
|
||||
|
||||
HWND hLogo = CreateWindowW(L"STATIC", NULL,
|
||||
WS_CHILD | WS_VISIBLE | SS_BITMAP | SS_CENTERIMAGE,
|
||||
100, 70, 400, 150, g_SplashWnd, NULL, wc.hInstance, NULL);
|
||||
WS_POPUP | WS_BORDER | WS_VISIBLE, x, y, SW, SH, NULL, NULL, wc.hInstance, NULL);
|
||||
|
||||
wchar_t buffer[MAX_PATH];
|
||||
GetModuleFileNameW(NULL, buffer, MAX_PATH);
|
||||
|
|
@ -66,57 +167,72 @@ void CreateSplash() {
|
|||
std::wstring imagePath = exeDir + L"\\Common\\Media\\Faucet.png";
|
||||
|
||||
Gdiplus::Bitmap* bitmap = Gdiplus::Bitmap::FromFile(imagePath.c_str());
|
||||
if (bitmap && bitmap->GetLastStatus() == Gdiplus::Ok) {
|
||||
HBITMAP hBmp = NULL;
|
||||
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 (hOld) DeleteObject(hOld);
|
||||
if (bitmap && bitmap->GetLastStatus() == Gdiplus::Ok)
|
||||
{
|
||||
g_LogoW = (int)bitmap->GetWidth();
|
||||
g_LogoH = (int)bitmap->GetHeight();
|
||||
|
||||
const int maxW = 400, maxH = 150;
|
||||
if (g_LogoW > maxW || g_LogoH > maxH)
|
||||
{
|
||||
float scale = min((float)maxW / g_LogoW, (float)maxH / g_LogoH);
|
||||
g_LogoW = (int)(g_LogoW * scale);
|
||||
g_LogoH = (int)(g_LogoH * scale);
|
||||
}
|
||||
|
||||
Gdiplus::Bitmap* scaled = new Gdiplus::Bitmap(g_LogoW, g_LogoH, PixelFormat32bppARGB);
|
||||
Gdiplus::Graphics g(scaled);
|
||||
g.SetInterpolationMode(Gdiplus::InterpolationModeHighQualityBicubic);
|
||||
g.DrawImage(bitmap, 0, 0, g_LogoW, g_LogoH);
|
||||
|
||||
HDC hdc = GetDC(g_SplashWnd);
|
||||
HDC memDC = CreateCompatibleDC(hdc);
|
||||
g_hLogoBmp = CreateCompatibleBitmap(hdc, g_LogoW, g_LogoH);
|
||||
HBITMAP old = (HBITMAP)SelectObject(memDC, g_hLogoBmp);
|
||||
Gdiplus::Graphics gdc(memDC);
|
||||
gdc.DrawImage(scaled, 0, 0, g_LogoW, g_LogoH);
|
||||
SelectObject(memDC, old);
|
||||
DeleteDC(memDC);
|
||||
ReleaseDC(g_SplashWnd, hdc);
|
||||
|
||||
delete scaled;
|
||||
}
|
||||
delete bitmap;
|
||||
|
||||
g_StatusWnd = CreateWindowW(L"STATIC", L"Preparing...",
|
||||
WS_CHILD | WS_VISIBLE | SS_CENTER,
|
||||
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,
|
||||
20, 350, 200, 20, g_SplashWnd, NULL, wc.hInstance, NULL);
|
||||
|
||||
g_FailWnd = CreateWindowW(L"STATIC", L"",
|
||||
WS_CHILD | WS_VISIBLE | SS_RIGHT,
|
||||
380, 350, 200, 20, g_SplashWnd, NULL, wc.hInstance, NULL);
|
||||
|
||||
UpdateWindow(g_SplashWnd);
|
||||
}
|
||||
|
||||
void UpdateSplashStatus(const std::wstring& text) {
|
||||
if (!g_StatusWnd) return;
|
||||
// ---------------------------------------------------------------------------
|
||||
// Splash update
|
||||
// ---------------------------------------------------------------------------
|
||||
void UpdateSplashStatus(const std::wstring& text)
|
||||
{
|
||||
if (!g_SplashWnd) return;
|
||||
|
||||
SendMessageW(g_StatusWnd, WM_SETTEXT, 0, (LPARAM)text.c_str());
|
||||
g_StatusText = text;
|
||||
|
||||
std::wstring countText = std::to_wstring(g_LoadedMods) + L"/"
|
||||
+ std::to_wstring(g_TotalMods) + L" MODS LOADED";
|
||||
SendMessageW(g_CountWnd, WM_SETTEXT, 0, (LPARAM)countText.c_str());
|
||||
|
||||
if (g_FailedMods > 0) {
|
||||
std::wstring failText = std::to_wstring(g_FailedMods) + L" FAILED TO LOAD";
|
||||
SendMessageW(g_FailWnd, WM_SETTEXT, 0, (LPARAM)failText.c_str());
|
||||
}
|
||||
InvalidateRect(g_SplashWnd, NULL, FALSE);
|
||||
UpdateWindow(g_SplashWnd);
|
||||
|
||||
MSG msg;
|
||||
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
|
||||
ModLoader& ModLoader::Get() {
|
||||
// ---------------------------------------------------------------------------
|
||||
// ModLoader
|
||||
// ---------------------------------------------------------------------------
|
||||
ModLoader& ModLoader::Get()
|
||||
{
|
||||
static ModLoader instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void ModLoader::Initialize() {
|
||||
void ModLoader::Initialize()
|
||||
{
|
||||
if (m_initialized) return;
|
||||
m_initialized = true;
|
||||
|
||||
|
|
@ -136,99 +252,121 @@ void ModLoader::Initialize() {
|
|||
+ std::to_string(g_FailedMods) + " failed, "
|
||||
+ std::to_string(elapsed) + "ms total");
|
||||
|
||||
if (elapsed < 1000) {
|
||||
if (elapsed < 1000)
|
||||
{
|
||||
UpdateSplashStatus(L"Finalizing...");
|
||||
Sleep(static_cast<DWORD>(1000 - elapsed));
|
||||
}
|
||||
|
||||
if (g_SplashWnd) {
|
||||
if (g_SplashWnd)
|
||||
{
|
||||
DestroyWindow(g_SplashWnd);
|
||||
g_SplashWnd = NULL;
|
||||
if (g_hLogoBmp) { DeleteObject(g_hLogoBmp); g_hLogoBmp = NULL; }
|
||||
if (g_hFontTitle) { DeleteObject(g_hFontTitle); g_hFontTitle = NULL; }
|
||||
if (g_hFontStatus) { DeleteObject(g_hFontStatus); g_hFontStatus = NULL; }
|
||||
if (g_hFontCount) { DeleteObject(g_hFontCount); g_hFontCount = NULL; }
|
||||
UnregisterClassW(L"ModLoaderSplash", GetModuleHandle(NULL));
|
||||
Gdiplus::GdiplusShutdown(g_gdiplusToken);
|
||||
}
|
||||
}
|
||||
|
||||
void ModLoader::NotifyInit() {
|
||||
for (auto& mod : m_mods) {
|
||||
// ---------------------------------------------------------------------------
|
||||
// Mod lifecycle
|
||||
// ---------------------------------------------------------------------------
|
||||
void ModLoader::NotifyInit()
|
||||
{
|
||||
for (auto& mod : m_mods)
|
||||
{
|
||||
if (!mod.healthy) continue;
|
||||
try {
|
||||
if (!mod.instance->OnInit()) {
|
||||
try
|
||||
{
|
||||
if (!mod.instance->OnInit())
|
||||
{
|
||||
Log("OnInit() returned false for: " + std::string(mod.instance->GetInfo()->id));
|
||||
mod.healthy = false;
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
catch (...)
|
||||
{
|
||||
Log("OnInit() threw for: " + std::string(mod.instance->GetInfo()->id));
|
||||
mod.healthy = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ModLoader::OnLevelLoad() {
|
||||
void ModLoader::OnLevelLoad()
|
||||
{
|
||||
if (m_levelLoaded) return;
|
||||
m_levelLoaded = true;
|
||||
Log(L"Level loaded");
|
||||
for (auto& mod : m_mods) {
|
||||
for (auto& mod : m_mods)
|
||||
{
|
||||
if (!mod.healthy) continue;
|
||||
try {
|
||||
mod.instance->OnLevelLoad();
|
||||
}
|
||||
catch (...) {
|
||||
mod.healthy = false;
|
||||
}
|
||||
try { mod.instance->OnLevelLoad(); }
|
||||
catch (...) { mod.healthy = false; }
|
||||
}
|
||||
}
|
||||
|
||||
void ModLoader::OnLevelUnload() {
|
||||
void ModLoader::OnLevelUnload()
|
||||
{
|
||||
if (!m_levelLoaded) return;
|
||||
m_levelLoaded = false;
|
||||
Log(L"Level unloaded");
|
||||
for (auto& mod : m_mods) {
|
||||
for (auto& mod : m_mods)
|
||||
{
|
||||
if (!mod.healthy) continue;
|
||||
try {
|
||||
mod.instance->OnLevelUnload();
|
||||
}
|
||||
catch (...) {
|
||||
mod.healthy = false;
|
||||
}
|
||||
try { mod.instance->OnLevelUnload(); }
|
||||
catch (...) { mod.healthy = false; }
|
||||
}
|
||||
}
|
||||
|
||||
void ModLoader::NotifyUpdate(float deltaTime) {
|
||||
for (auto& mod : m_mods) {
|
||||
void ModLoader::NotifyUpdate(float deltaTime)
|
||||
{
|
||||
for (auto& mod : m_mods)
|
||||
{
|
||||
if (!mod.healthy) continue;
|
||||
if (!mod.instance) {
|
||||
mod.healthy = false;
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
if (!mod.instance->OnUpdate(deltaTime)) {
|
||||
if (!mod.instance) { mod.healthy = false; continue; }
|
||||
try
|
||||
{
|
||||
if (!mod.instance->OnUpdate(deltaTime))
|
||||
{
|
||||
Log("OnUpdate() returned false for: " + std::string(mod.instance->GetInfo()->id));
|
||||
mod.healthy = false;
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
catch (...)
|
||||
{
|
||||
Log("OnUpdate() threw for: " + std::string(mod.instance->GetInfo()->id));
|
||||
mod.healthy = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ModLoader::Shutdown() {
|
||||
// ---------------------------------------------------------------------------
|
||||
// Shutdown
|
||||
// ---------------------------------------------------------------------------
|
||||
void ModLoader::Shutdown()
|
||||
{
|
||||
Log("Shutting down ModLoader");
|
||||
for (int i = static_cast<int>(m_mods.size()) - 1; i >= 0; --i)
|
||||
UnloadOneMod(m_mods[i]);
|
||||
m_mods.clear();
|
||||
|
||||
if (m_logFile != INVALID_HANDLE_VALUE) {
|
||||
if (m_logFile != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CloseHandle(m_logFile);
|
||||
m_logFile = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
IMod* ModLoader::FindMod(const std::string& id) const {
|
||||
for (const auto& mod : m_mods) {
|
||||
// ---------------------------------------------------------------------------
|
||||
// Mod lookup
|
||||
// ---------------------------------------------------------------------------
|
||||
IMod* ModLoader::FindMod(const std::string& id) const
|
||||
{
|
||||
for (const auto& mod : m_mods)
|
||||
{
|
||||
if (mod.healthy && mod.instance &&
|
||||
std::string(mod.instance->GetInfo()->id) == id)
|
||||
return mod.instance;
|
||||
|
|
@ -236,9 +374,14 @@ IMod* ModLoader::FindMod(const std::string& id) const {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void ModLoader::ScanAndLoadMods(const std::wstring& modsDir) {
|
||||
// ---------------------------------------------------------------------------
|
||||
// Scanning & loading
|
||||
// ---------------------------------------------------------------------------
|
||||
void ModLoader::ScanAndLoadMods(const std::wstring& modsDir)
|
||||
{
|
||||
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);
|
||||
Log("Mods directory not found — created it");
|
||||
return;
|
||||
|
|
@ -248,7 +391,8 @@ void ModLoader::ScanAndLoadMods(const std::wstring& modsDir) {
|
|||
std::wstring searchPath = modsDir + L"\\*.dll";
|
||||
WIN32_FIND_DATAW fd;
|
||||
HANDLE hFind = FindFirstFileW(searchPath.c_str(), &fd);
|
||||
if (hFind != INVALID_HANDLE_VALUE) {
|
||||
if (hFind != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
do {
|
||||
if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
||||
dllPaths.push_back(modsDir + L"\\" + fd.cFileName);
|
||||
|
|
@ -259,21 +403,24 @@ void ModLoader::ScanAndLoadMods(const std::wstring& modsDir) {
|
|||
g_TotalMods = static_cast<int>(dllPaths.size());
|
||||
Log("Found " + std::to_string(g_TotalMods) + " mod(s) to load");
|
||||
|
||||
for (const auto& path : dllPaths) {
|
||||
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());
|
||||
if (!hMod) {
|
||||
if (!hMod)
|
||||
{
|
||||
Log("FAIL [" + filename + "] LoadLibrary failed (error " + std::to_string(GetLastError()) + ")");
|
||||
++g_FailedMods;
|
||||
return false;
|
||||
|
|
@ -281,7 +428,8 @@ bool ModLoader::LoadOneMod(const std::wstring& dllPath) {
|
|||
|
||||
using CreateModFn = IMod * (*)();
|
||||
auto createFn = reinterpret_cast<CreateModFn>(GetProcAddress(hMod, "CreateMod"));
|
||||
if (!createFn) {
|
||||
if (!createFn)
|
||||
{
|
||||
Log("FAIL [" + filename + "] missing CreateMod export");
|
||||
FreeLibrary(hMod);
|
||||
++g_FailedMods;
|
||||
|
|
@ -289,17 +437,17 @@ bool ModLoader::LoadOneMod(const std::wstring& dllPath) {
|
|||
}
|
||||
|
||||
IMod* instance = nullptr;
|
||||
try {
|
||||
instance = createFn();
|
||||
}
|
||||
catch (...) {
|
||||
try { instance = createFn(); }
|
||||
catch (...)
|
||||
{
|
||||
Log("FAIL [" + filename + "] CreateMod() threw");
|
||||
FreeLibrary(hMod);
|
||||
++g_FailedMods;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!instance) {
|
||||
if (!instance)
|
||||
{
|
||||
Log("FAIL [" + filename + "] CreateMod() returned null");
|
||||
FreeLibrary(hMod);
|
||||
++g_FailedMods;
|
||||
|
|
@ -309,9 +457,7 @@ bool ModLoader::LoadOneMod(const std::wstring& dllPath) {
|
|||
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)
|
||||
? std::to_string(info->version.major) + "." + std::to_string(info->version.minor) + "." + std::to_string(info->version.patch)
|
||||
: "(unknown)";
|
||||
|
||||
LoadedMod record;
|
||||
|
|
@ -319,13 +465,16 @@ bool ModLoader::LoadOneMod(const std::wstring& dllPath) {
|
|||
record.instance = instance;
|
||||
record.path = narrowPath;
|
||||
|
||||
try {
|
||||
if (!instance->OnLoad()) {
|
||||
try
|
||||
{
|
||||
if (!instance->OnLoad())
|
||||
{
|
||||
Log("WARN [" + modId + " " + modVer + "] OnLoad() returned false — marking unhealthy");
|
||||
record.healthy = false;
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
catch (...)
|
||||
{
|
||||
Log("FAIL [" + modId + " " + modVer + "] OnLoad() threw — marking unhealthy");
|
||||
record.healthy = false;
|
||||
}
|
||||
|
|
@ -333,11 +482,13 @@ bool ModLoader::LoadOneMod(const std::wstring& dllPath) {
|
|||
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::steady_clock::now() - t0).count();
|
||||
|
||||
if (record.healthy) {
|
||||
if (record.healthy)
|
||||
{
|
||||
Log("OK [" + modId + " " + modVer + "] loaded in " + std::to_string(elapsed) + "ms");
|
||||
++g_LoadedMods;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
++g_FailedMods;
|
||||
}
|
||||
|
||||
|
|
@ -345,7 +496,8 @@ bool ModLoader::LoadOneMod(const std::wstring& dllPath) {
|
|||
return record.healthy;
|
||||
}
|
||||
|
||||
void ModLoader::UnloadOneMod(LoadedMod& mod) {
|
||||
void ModLoader::UnloadOneMod(LoadedMod& mod)
|
||||
{
|
||||
if (!mod.instance) return;
|
||||
|
||||
if (mod.instance->GetInfo())
|
||||
|
|
@ -354,22 +506,26 @@ void ModLoader::UnloadOneMod(LoadedMod& mod) {
|
|||
delete mod.instance;
|
||||
mod.instance = nullptr;
|
||||
|
||||
if (mod.module) {
|
||||
if (mod.module)
|
||||
{
|
||||
FreeLibrary(mod.module);
|
||||
mod.module = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void ModLoader::OpenLogFile() {
|
||||
// ---------------------------------------------------------------------------
|
||||
// Logging
|
||||
// ---------------------------------------------------------------------------
|
||||
void ModLoader::OpenLogFile()
|
||||
{
|
||||
std::wstring logPath = GetModsDirectory() + L"\\modloader.log";
|
||||
CreateDirectoryW(GetModsDirectory().c_str(), NULL);
|
||||
m_logFile = CreateFileW(logPath.c_str(), GENERIC_WRITE, FILE_SHARE_READ,
|
||||
nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void ModLoader::Log(const std::string& msg) {
|
||||
void ModLoader::Log(const std::string& msg)
|
||||
{
|
||||
auto now = std::chrono::system_clock::now();
|
||||
std::time_t t = std::chrono::system_clock::to_time_t(now);
|
||||
struct tm buf;
|
||||
|
|
@ -379,7 +535,8 @@ void ModLoader::Log(const std::string& msg) {
|
|||
|
||||
std::string line = std::string(ts) + msg + "\r\n";
|
||||
|
||||
if (m_logFile != INVALID_HANDLE_VALUE) {
|
||||
if (m_logFile != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DWORD written;
|
||||
WriteFile(m_logFile, line.c_str(), static_cast<DWORD>(line.size()), &written, nullptr);
|
||||
}
|
||||
|
|
@ -387,11 +544,16 @@ void ModLoader::Log(const std::string& msg) {
|
|||
OutputDebugStringA(line.c_str());
|
||||
}
|
||||
|
||||
void ModLoader::Log(const std::wstring& msg) {
|
||||
void ModLoader::Log(const std::wstring& msg)
|
||||
{
|
||||
Log(std::string(msg.begin(), msg.end()));
|
||||
}
|
||||
|
||||
std::wstring ModLoader::GetModsDirectory() const {
|
||||
// ---------------------------------------------------------------------------
|
||||
// Paths
|
||||
// ---------------------------------------------------------------------------
|
||||
std::wstring ModLoader::GetModsDirectory() const
|
||||
{
|
||||
wchar_t exePath[MAX_PATH] = {};
|
||||
GetModuleFileNameW(nullptr, exePath, MAX_PATH);
|
||||
std::wstring dir = exePath;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,37 @@
|
|||
UIScene_ModsMenu.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(416,27):
|
||||
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(416,27):
|
||||
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
|
||||
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
|
||||
|
|
@ -506,40 +539,6 @@
|
|||
Windows64\Iggy\lib\iggy_w64.lib
|
||||
Windows64\Miles\lib\mss64.lib
|
||||
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
|
||||
Run post-build script
|
||||
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.
|
|
@ -1,3 +1,3 @@
|
|||
[16:46:29] === Faucet ModLoader starting ===
|
||||
[16:46:29] Found 0 mod(s) to load
|
||||
[16:46:29] Initialization complete — 0 loaded, 0 failed, 116ms total
|
||||
[16:54:27] === Faucet ModLoader starting ===
|
||||
[16:54:27] Found 0 mod(s) to load
|
||||
[16:54:27] Initialization complete — 0 loaded, 0 failed, 169ms total
|
||||
|
|
|
|||
Loading…
Reference in a new issue