diff --git a/Minecraft.Server.FourKit/FourKitHost.cs b/Minecraft.Server.FourKit/FourKitHost.cs index 78b41b0ec..cd0751f33 100644 --- a/Minecraft.Server.FourKit/FourKitHost.cs +++ b/Minecraft.Server.FourKit/FourKitHost.cs @@ -558,7 +558,7 @@ public static class FourKitHost try { NativeBridge.SetWorldCallbacks(getTileId, setTile, setTileData, breakBlock, getHighestBlockY, getWorldInfo, setWorldTime, setWeather, createExplosion, strikeLightning, setSpawnLocation, dropItem); - ServerLog.Info("fourkit", "World native callbacks registered."); + //ServerLog.Info("fourkit", "World native callbacks registered."); } catch (Exception ex) { @@ -572,7 +572,7 @@ public static class FourKitHost try { NativeBridge.SetPlayerCallbacks(kickPlayer, banPlayer, banPlayerIp, getPlayerAddress); - ServerLog.Info("fourkit", "Player native callbacks registered."); + //ServerLog.Info("fourkit", "Player native callbacks registered."); } catch (Exception ex) { @@ -586,7 +586,7 @@ public static class FourKitHost try { NativeBridge.SetInventoryCallbacks(getPlayerInventory, setPlayerInventorySlot, getContainerContents, setContainerSlot, getContainerViewerEntityIds, closeContainer, openVirtualContainer); - ServerLog.Info("fourkit", "Inventory native callbacks registered."); + //ServerLog.Info("fourkit", "Inventory native callbacks registered."); } catch (Exception ex) { diff --git a/Minecraft.Server/CMakeLists.txt b/Minecraft.Server/CMakeLists.txt index eff55237b..1f339a055 100644 --- a/Minecraft.Server/CMakeLists.txt +++ b/Minecraft.Server/CMakeLists.txt @@ -103,5 +103,8 @@ add_custom_command(TARGET Minecraft.Server POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "${FOURKIT_RUNTIME_JSON}" "$" +# COMMAND ${CMAKE_COMMAND} -E copy_if_different +# "${CMAKE_SOURCE_DIR}/include/hostfxr.dll" +# "$" COMMENT "Copying Minecraft.Server.FourKit to Minecraft.Server" -) \ No newline at end of file +) diff --git a/Minecraft.Server/FourKitBridge.cpp b/Minecraft.Server/FourKitBridge.cpp index 6c3223062..d4d74917a 100644 --- a/Minecraft.Server/FourKitBridge.cpp +++ b/Minecraft.Server/FourKitBridge.cpp @@ -70,6 +70,13 @@ typedef int(__cdecl *hostfxr_get_runtime_delegate_fn)( typedef int(__cdecl *hostfxr_close_fn)(const hostfxr_handle host_context_handle); +struct hostfxr_initialize_parameters +{ + size_t size; + const wchar_t *host_path; + const wchar_t *dotnet_root; +}; + #define UNMANAGEDCALLERSONLY_METHOD ((const wchar_t *)-1) typedef int(__stdcall *load_assembly_and_get_function_pointer_fn)( @@ -91,6 +98,7 @@ namespace FourKitBridge static hostfxr_initialize_for_runtime_config_fn s_initFn = nullptr; static hostfxr_get_runtime_delegate_fn s_getDelegateFn = nullptr; static hostfxr_close_fn s_closeFn = nullptr; +static std::wstring s_dotnetRoot; typedef void(__stdcall *fn_initialize)(); typedef void(__stdcall *fn_fire_player_join)(int entityId, const char *nameUtf8, int nameByteLen, const char *uuidUtf8, int uuidByteLen); @@ -714,7 +722,6 @@ static int __cdecl NativeBanPlayerIp(int entityId, const char *reasonUtf8, int r return 0; } - // Disconnect all players on this IP PlayerList *list = MinecraftServer::getPlayerList(); if (list) { @@ -1046,13 +1053,97 @@ static void __cdecl NativeGetContainerViewerEntityIds(int entityId, int *outIds, *outCount = count; } +static std::wstring FindNet10SystemRoot() +{ + // overengineered + // trying to do a lot of safeguards here, setups can be all over the place + // fixes an issue aiden had + + std::vector candidates; + wchar_t envRoot[MAX_PATH] = {}; + DWORD len = GetEnvironmentVariableW(L"DOTNET_ROOT", envRoot, MAX_PATH); + if (len > 0 && len < MAX_PATH) + { + candidates.push_back(std::wstring(envRoot)); + } + candidates.push_back(L"C:\\Program Files\\dotnet"); + + for (const auto &root : candidates) + { + std::wstring fxrDir = root + L"\\host\\fxr"; + WIN32_FIND_DATAW fd; + HANDLE h = FindFirstFileW((fxrDir + L"\\*").c_str(), &fd); + if (h == INVALID_HANDLE_VALUE) + { + continue; + } + bool has10 = false; + do + { + if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && fd.cFileName[0] != L'.') + { + if (std::wstring(fd.cFileName).substr(0, 3) == L"10.") + { + has10 = true; + } + } + } while (!has10 && FindNextFileW(h, &fd)); + FindClose(h); + if (has10) + { + return root; + } + } + + return L"C:\\Program Files\\dotnet"; +} + +static bool TryLoadHostfxrFromPath(const std::wstring &path) +{ + HMODULE lib = LoadLibraryW(path.c_str()); + if (!lib) + { + return false; + } + + s_initFn = (hostfxr_initialize_for_runtime_config_fn)GetProcAddress(lib, "hostfxr_initialize_for_runtime_config"); + s_getDelegateFn = (hostfxr_get_runtime_delegate_fn)GetProcAddress(lib, "hostfxr_get_runtime_delegate"); + s_closeFn = (hostfxr_close_fn)GetProcAddress(lib, "hostfxr_close"); + + if (s_initFn && s_getDelegateFn && s_closeFn) + { + return true; + } + + s_initFn = nullptr; + s_getDelegateFn = nullptr; + s_closeFn = nullptr; + FreeLibrary(lib); + return false; +} + static bool LoadHostfxr() { // hardcoded for windows // no linux support yet so no need - wchar_t dotnetRoot[MAX_PATH] = {}; - DWORD len = GetEnvironmentVariableW(L"DOTNET_ROOT", dotnetRoot, MAX_PATH); + wchar_t exePath[MAX_PATH] = {}; + GetModuleFileNameW(NULL, exePath, MAX_PATH); + std::wstring exeDir(exePath); + size_t lastSlash = exeDir.find_last_of(L"\\/"); + if (lastSlash != std::wstring::npos) + { + exeDir = exeDir.substr(0, lastSlash); + } + + if (TryLoadHostfxrFromPath(exeDir + L"\\hostfxr.dll")) + { + s_dotnetRoot = FindNet10SystemRoot(); + return true; + } + + wchar_t dotnetRoot[MAX_PATH] = {}; + DWORD len = GetEnvironmentVariableW(L"DOTNET_ROOT", dotnetRoot, MAX_PATH); // sometimes this is set in windows if (len == 0 || len >= MAX_PATH) { wcscpy_s(dotnetRoot, L"C:\\Program Files\\dotnet"); @@ -1061,54 +1152,35 @@ static bool LoadHostfxr() std::wstring hostfxrDir = std::wstring(dotnetRoot) + L"\\host\\fxr"; WIN32_FIND_DATAW fd; - std::wstring searchPattern = hostfxrDir + L"\\*"; - HANDLE hFind = FindFirstFileW(searchPattern.c_str(), &fd); - if (hFind == INVALID_HANDLE_VALUE) + HANDLE hFind = FindFirstFileW((hostfxrDir + L"\\*").c_str(), &fd); + if (hFind != INVALID_HANDLE_VALUE) { - LogError("fourkit", "Cannot find hostfxr. Is .NET 10 runtime installed?"); - return false; - } - - std::wstring bestVersion; - do - { - if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && fd.cFileName[0] != L'.') + std::wstring bestVersion; + do { - std::wstring ver(fd.cFileName); - if (ver > bestVersion) + if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && fd.cFileName[0] != L'.') { - bestVersion = ver; + std::wstring ver(fd.cFileName); + if (ver.substr(0, 3) == L"10." && ver > bestVersion) + { + bestVersion = ver; + } + } + } while (FindNextFileW(hFind, &fd)); + FindClose(hFind); + + if (!bestVersion.empty()) + { + if (TryLoadHostfxrFromPath(hostfxrDir + L"\\" + bestVersion + L"\\hostfxr.dll")) + { + s_dotnetRoot = std::wstring(dotnetRoot); + return true; } } - } while (FindNextFileW(hFind, &fd)); - FindClose(hFind); - - if (bestVersion.empty()) - { - LogError("fourkit", "No hostfxr version found. Is .NET runtime installed?"); - return false; } - std::wstring hostfxrPath = hostfxrDir + L"\\" + bestVersion + L"\\hostfxr.dll"; - - HMODULE lib = LoadLibraryW(hostfxrPath.c_str()); - if (!lib) - { - LogError("fourkit", "Failed to load hostfxr.dll."); - return false; - } - - s_initFn = (hostfxr_initialize_for_runtime_config_fn)GetProcAddress(lib, "hostfxr_initialize_for_runtime_config"); - s_getDelegateFn = (hostfxr_get_runtime_delegate_fn)GetProcAddress(lib, "hostfxr_get_runtime_delegate"); - s_closeFn = (hostfxr_close_fn)GetProcAddress(lib, "hostfxr_close"); - - if (!s_initFn || !s_getDelegateFn || !s_closeFn) - { - LogError("fourkit", "Failed to resolve hostfxr exports."); - return false; - } - - return true; + LogError("fourkit", "hostfxr.dll not found. Install the .NET 10 x64 runtime (https://aka.ms/dotnet/download) or copy hostfxr.dll from C:\\Program Files\\dotnet\\host\\fxr\\10.x.x\\ next to the server executable."); + return false; } static bool GetManagedEntryPoint( @@ -1158,8 +1230,13 @@ void Initialize() std::wstring runtimeConfigPath = exeDir + L"\\Minecraft.Server.FourKit.runtimeconfig.json"; std::wstring assemblyPath = exeDir + L"\\Minecraft.Server.FourKit.dll"; + hostfxr_initialize_parameters initParams = {}; + initParams.size = sizeof(hostfxr_initialize_parameters); + initParams.host_path = exePath; + initParams.dotnet_root = s_dotnetRoot.c_str(); + hostfxr_handle ctx = nullptr; - int rc = s_initFn(runtimeConfigPath.c_str(), nullptr, &ctx); + int rc = s_initFn(runtimeConfigPath.c_str(), &initParams, &ctx); if (rc != 0 || ctx == nullptr) { char msg[256];