mirror of
https://github.com/Jacobwasbeast/LegacyWeaveLoader.git
synced 2026-07-02 09:04:22 +00:00
feat(api/runtime): java-style assets and localization sync
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
#include "MainMenuOverlay.h"
|
||||
#include "ModStrings.h"
|
||||
#include "ModAtlas.h"
|
||||
#include "NativeExports.h"
|
||||
#include "CustomPickaxeRegistry.h"
|
||||
#include "CustomToolMaterialRegistry.h"
|
||||
#include "CustomBlockRegistry.h"
|
||||
@@ -17,7 +18,9 @@
|
||||
#include <cstring>
|
||||
#include <cwchar>
|
||||
#include <cwctype>
|
||||
#include <cctype>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
@@ -110,6 +113,10 @@ namespace GameHooks
|
||||
static InventoryRemoveResource_fn s_inventoryRemoveResource = nullptr;
|
||||
static void* s_inventoryVtable = nullptr;
|
||||
static ItemInstanceHurtAndBreak_fn s_itemInstanceHurtAndBreak = nullptr;
|
||||
static std::string s_modsPath;
|
||||
static std::unordered_map<std::string, std::string> s_modAssetRoots;
|
||||
static bool s_modAssetsIndexed = false;
|
||||
static std::mutex s_modAssetsMutex;
|
||||
// Verified from compiled Player::inventory accesses in this game build.
|
||||
static constexpr ptrdiff_t kPlayerInventoryOffset = 0x340;
|
||||
static constexpr ptrdiff_t kLevelIsClientSideOffset = 0x268;
|
||||
@@ -334,6 +341,150 @@ namespace GameHooks
|
||||
return path.compare(pathLen - suffLen, suffLen, suffix) == 0;
|
||||
}
|
||||
|
||||
static std::string ToLowerAscii(const std::string& value)
|
||||
{
|
||||
std::string out;
|
||||
out.reserve(value.size());
|
||||
for (char ch : value)
|
||||
out.push_back((char)tolower((unsigned char)ch));
|
||||
return out;
|
||||
}
|
||||
|
||||
static std::string WStringToLowerAscii(const std::wstring& value)
|
||||
{
|
||||
std::string out;
|
||||
out.reserve(value.size());
|
||||
for (wchar_t ch : value)
|
||||
{
|
||||
if (ch > 0x7F)
|
||||
return std::string();
|
||||
out.push_back((char)tolower((unsigned char)ch));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
static void BuildModAssetIndexLocked()
|
||||
{
|
||||
s_modAssetRoots.clear();
|
||||
s_modAssetsIndexed = true;
|
||||
if (s_modsPath.empty())
|
||||
return;
|
||||
|
||||
WIN32_FIND_DATAA fd;
|
||||
std::string search = s_modsPath + "\\*";
|
||||
HANDLE h = FindFirstFileA(search.c_str(), &fd);
|
||||
if (h == INVALID_HANDLE_VALUE)
|
||||
return;
|
||||
|
||||
do
|
||||
{
|
||||
if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) continue;
|
||||
if (fd.cFileName[0] == '.') continue;
|
||||
|
||||
std::string modFolder = fd.cFileName;
|
||||
std::string assetsPath = s_modsPath + "\\" + modFolder + "\\assets";
|
||||
DWORD attr = GetFileAttributesA(assetsPath.c_str());
|
||||
if (attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY))
|
||||
continue;
|
||||
|
||||
WIN32_FIND_DATAA nsfd;
|
||||
std::string nsSearch = assetsPath + "\\*";
|
||||
HANDLE hNs = FindFirstFileA(nsSearch.c_str(), &nsfd);
|
||||
if (hNs == INVALID_HANDLE_VALUE)
|
||||
continue;
|
||||
do
|
||||
{
|
||||
if (!(nsfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) continue;
|
||||
if (nsfd.cFileName[0] == '.') continue;
|
||||
|
||||
std::string nsName = ToLowerAscii(nsfd.cFileName);
|
||||
if (nsName.empty())
|
||||
continue;
|
||||
|
||||
if (s_modAssetRoots.find(nsName) == s_modAssetRoots.end())
|
||||
{
|
||||
s_modAssetRoots.emplace(nsName, assetsPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogUtil::Log("[WeaveLoader] ModAssets: duplicate namespace '%s' (folder=%s) ignored",
|
||||
nsName.c_str(), modFolder.c_str());
|
||||
}
|
||||
} while (FindNextFileA(hNs, &nsfd));
|
||||
FindClose(hNs);
|
||||
} while (FindNextFileA(h, &fd));
|
||||
FindClose(h);
|
||||
}
|
||||
|
||||
static void EnsureModAssetIndex()
|
||||
{
|
||||
if (s_modAssetsIndexed)
|
||||
return;
|
||||
std::lock_guard<std::mutex> guard(s_modAssetsMutex);
|
||||
if (!s_modAssetsIndexed)
|
||||
BuildModAssetIndexLocked();
|
||||
}
|
||||
|
||||
static bool FileExistsW(const std::wstring& path)
|
||||
{
|
||||
DWORD attr = GetFileAttributesW(path.c_str());
|
||||
return (attr != INVALID_FILE_ATTRIBUTES) && !(attr & FILE_ATTRIBUTE_DIRECTORY);
|
||||
}
|
||||
|
||||
static bool TryResolveModAssetPath(const std::wstring& requestPath, std::wstring& outPath)
|
||||
{
|
||||
if (s_modsPath.empty())
|
||||
return false;
|
||||
|
||||
std::wstring lower = NormalizeLowerPath(requestPath);
|
||||
if (lower.find(L"://") != std::wstring::npos)
|
||||
return false;
|
||||
|
||||
const std::wstring kAssets = L"/assets/";
|
||||
size_t assetsPos = lower.find(kAssets);
|
||||
if (assetsPos == std::wstring::npos)
|
||||
return false;
|
||||
|
||||
size_t nsStart = assetsPos + kAssets.size();
|
||||
if (nsStart >= lower.size())
|
||||
return false;
|
||||
size_t nsEnd = lower.find(L'/', nsStart);
|
||||
if (nsEnd == std::wstring::npos || nsEnd <= nsStart)
|
||||
return false;
|
||||
|
||||
std::wstring ns = lower.substr(nsStart, nsEnd - nsStart);
|
||||
if (ns.empty())
|
||||
return false;
|
||||
|
||||
size_t relStart = nsEnd + 1;
|
||||
if (relStart >= lower.size())
|
||||
return false;
|
||||
std::wstring rel = lower.substr(relStart);
|
||||
|
||||
std::string nsKey = WStringToLowerAscii(ns);
|
||||
if (nsKey.empty())
|
||||
return false;
|
||||
|
||||
EnsureModAssetIndex();
|
||||
auto it = s_modAssetRoots.find(nsKey);
|
||||
if (it == s_modAssetRoots.end())
|
||||
return false;
|
||||
|
||||
std::wstring rootW(it->second.begin(), it->second.end());
|
||||
std::wstring relW = ns + L"/" + rel;
|
||||
for (wchar_t& ch : relW)
|
||||
{
|
||||
if (ch == L'/')
|
||||
ch = L'\\';
|
||||
}
|
||||
std::wstring fullPath = rootW + L"\\" + relW;
|
||||
if (!FileExistsW(fullPath))
|
||||
return false;
|
||||
|
||||
outPath = fullPath;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int DetectAtlasTypeFromResource(void* resourcePtr)
|
||||
{
|
||||
if (!resourcePtr)
|
||||
@@ -2284,6 +2435,14 @@ namespace GameHooks
|
||||
}
|
||||
}
|
||||
|
||||
std::wstring modAssetPath;
|
||||
if (TryResolveModAssetPath(*path, modAssetPath))
|
||||
{
|
||||
LogUtil::Log("[WeaveLoader] getResourceAsStream: redirecting %ls -> %ls",
|
||||
path->c_str(), modAssetPath.c_str());
|
||||
return Original_GetResourceAsStream(&modAssetPath);
|
||||
}
|
||||
|
||||
return Original_GetResourceAsStream(fileName);
|
||||
}
|
||||
|
||||
@@ -2372,6 +2531,13 @@ namespace GameHooks
|
||||
}
|
||||
modsPath = base + "mods";
|
||||
atlas_done:
|
||||
s_modsPath = modsPath;
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(s_modAssetsMutex);
|
||||
s_modAssetsIndexed = false;
|
||||
s_modAssetRoots.clear();
|
||||
}
|
||||
NativeExports::SetModsPath(modsPath);
|
||||
ModAtlas::SetBasePaths(modsPath, gameResPath);
|
||||
ModAtlas::EnsureAtlasesBuilt();
|
||||
|
||||
|
||||
@@ -679,6 +679,10 @@ bool HookManager::Install(const SymbolResolver& symbols)
|
||||
symbols.pServerLevelAddToTickNextTick ? symbols.pServerLevelAddToTickNextTick
|
||||
: symbols.pLevelAddToTickNextTick,
|
||||
symbols.pLevelGetTile);
|
||||
NativeExports::SetLocalizationSymbols(
|
||||
symbols.pMinecraftApp,
|
||||
symbols.pGetMinecraftLanguage,
|
||||
symbols.pGetMinecraftLocale);
|
||||
|
||||
if (symbols.pTexturesBindTextureResource)
|
||||
{
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
@@ -113,12 +114,64 @@ namespace ModAtlas
|
||||
return r;
|
||||
}
|
||||
|
||||
static bool HasPngExtension(const std::string& name)
|
||||
{
|
||||
if (name.size() < 4) return false;
|
||||
char a = (char)tolower((unsigned char)name[name.size() - 4]);
|
||||
char b = (char)tolower((unsigned char)name[name.size() - 3]);
|
||||
char c = (char)tolower((unsigned char)name[name.size() - 2]);
|
||||
char d = (char)tolower((unsigned char)name[name.size() - 1]);
|
||||
return a == '.' && b == 'p' && c == 'n' && d == 'g';
|
||||
}
|
||||
|
||||
static void ScanPngTree(const std::string& dir,
|
||||
const std::string& baseDir,
|
||||
const std::string& iconPrefix,
|
||||
std::vector<std::pair<std::string, std::string>>& out,
|
||||
std::unordered_set<std::string>& seen)
|
||||
{
|
||||
WIN32_FIND_DATAA fd;
|
||||
std::string search = dir + "\\*";
|
||||
HANDLE h = FindFirstFileA(search.c_str(), &fd);
|
||||
if (h == INVALID_HANDLE_VALUE) return;
|
||||
do
|
||||
{
|
||||
if (fd.cFileName[0] == '.') continue;
|
||||
std::string fullPath = dir + "\\" + fd.cFileName;
|
||||
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
{
|
||||
ScanPngTree(fullPath, baseDir, iconPrefix, out, seen);
|
||||
continue;
|
||||
}
|
||||
if (!HasPngExtension(fd.cFileName)) continue;
|
||||
|
||||
if (fullPath.size() <= baseDir.size()) continue;
|
||||
std::string rel = fullPath.substr(baseDir.size());
|
||||
if (!rel.empty() && (rel[0] == '\\' || rel[0] == '/'))
|
||||
rel.erase(0, 1);
|
||||
for (char& ch : rel)
|
||||
{
|
||||
if (ch == '\\') ch = '/';
|
||||
}
|
||||
if (rel.size() < 4) continue;
|
||||
rel.resize(rel.size() - 4);
|
||||
rel = ToLower(rel);
|
||||
|
||||
std::string iconName = iconPrefix + rel;
|
||||
if (seen.insert(iconName).second)
|
||||
out.push_back({ iconName, fullPath });
|
||||
} while (FindNextFileA(h, &fd));
|
||||
FindClose(h);
|
||||
}
|
||||
|
||||
static void FindModTextures(const std::string& modsPath,
|
||||
std::vector<std::pair<std::string, std::string>>& blocks,
|
||||
std::vector<std::pair<std::string, std::string>>& items)
|
||||
{
|
||||
blocks.clear();
|
||||
items.clear();
|
||||
std::unordered_set<std::string> seenBlocks;
|
||||
std::unordered_set<std::string> seenItems;
|
||||
|
||||
WIN32_FIND_DATAA fd;
|
||||
std::string search = modsPath + "\\*";
|
||||
@@ -134,34 +187,31 @@ namespace ModAtlas
|
||||
std::string assetsPath = modFolder + "\\assets";
|
||||
if (GetFileAttributesA(assetsPath.c_str()) != INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
std::string modId = ToLower(fd.cFileName);
|
||||
size_t pos = modId.find('-');
|
||||
while (pos != std::string::npos) { modId.erase(pos, 1); pos = modId.find('-'); }
|
||||
|
||||
std::string blocksPath = assetsPath + "\\blocks";
|
||||
std::string itemsPath = assetsPath + "\\items";
|
||||
|
||||
auto scanDir = [&](const std::string& dir, std::vector<std::pair<std::string, std::string>>& out, const std::string& prefix)
|
||||
// Java-style assets: assets/<namespace>/textures/block|item/*.png
|
||||
WIN32_FIND_DATAA nsfd;
|
||||
std::string nsSearch = assetsPath + "\\*";
|
||||
HANDLE hNs = FindFirstFileA(nsSearch.c_str(), &nsfd);
|
||||
if (hNs != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
std::string search2 = dir + "\\*.png";
|
||||
HANDLE h2 = FindFirstFileA(search2.c_str(), &fd);
|
||||
if (h2 == INVALID_HANDLE_VALUE) return;
|
||||
do
|
||||
{
|
||||
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue;
|
||||
std::string name = fd.cFileName;
|
||||
name.resize(name.size() - 4);
|
||||
std::string iconName = modId + ":" + name;
|
||||
std::string fullPath = dir + "\\" + fd.cFileName;
|
||||
out.push_back({ iconName, fullPath });
|
||||
} while (FindNextFileA(h2, &fd));
|
||||
FindClose(h2);
|
||||
};
|
||||
if (!(nsfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) continue;
|
||||
if (nsfd.cFileName[0] == '.') continue;
|
||||
|
||||
if (GetFileAttributesA(blocksPath.c_str()) == FILE_ATTRIBUTE_DIRECTORY)
|
||||
scanDir(blocksPath, blocks, "blocks");
|
||||
if (GetFileAttributesA(itemsPath.c_str()) == FILE_ATTRIBUTE_DIRECTORY)
|
||||
scanDir(itemsPath, items, "items");
|
||||
std::string nsFolder = nsfd.cFileName;
|
||||
std::string nsName = ToLower(nsFolder);
|
||||
std::string nsPath = assetsPath + "\\" + nsFolder;
|
||||
std::string texturesPath = nsPath + "\\textures";
|
||||
std::string blocksPath = texturesPath + "\\block";
|
||||
std::string itemsPath = texturesPath + "\\item";
|
||||
|
||||
if (GetFileAttributesA(blocksPath.c_str()) == FILE_ATTRIBUTE_DIRECTORY)
|
||||
ScanPngTree(blocksPath, blocksPath, nsName + ":block/", blocks, seenBlocks);
|
||||
if (GetFileAttributesA(itemsPath.c_str()) == FILE_ATTRIBUTE_DIRECTORY)
|
||||
ScanPngTree(itemsPath, itemsPath, nsName + ":item/", items, seenItems);
|
||||
} while (FindNextFileA(hNs, &nsfd));
|
||||
FindClose(hNs);
|
||||
}
|
||||
}
|
||||
} while (FindNextFileA(h, &fd));
|
||||
FindClose(h);
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
|
||||
/// <summary>
|
||||
/// Builds merged terrain.png and items.png atlases from mod assets.
|
||||
/// Scans mods/*/assets/blocks/*.png and items/*.png, stitches into copies of the
|
||||
/// Scans Java-style assets under mods/*/assets/<namespace>/textures/block|item/*.png,
|
||||
/// then stitches into copies of the
|
||||
/// vanilla atlases stored in mods/ModLoader/generated/. A CreateFileW hook redirects
|
||||
/// the game's file opens to the merged copies so vanilla files are never modified.
|
||||
/// </summary>
|
||||
|
||||
@@ -26,6 +26,13 @@ namespace
|
||||
LevelSetTileAndData_fn s_levelSetTileAndData = nullptr;
|
||||
LevelAddToTickNextTick_fn s_levelAddToTickNextTick = nullptr;
|
||||
LevelGetTile_fn s_levelGetTile = nullptr;
|
||||
|
||||
using GetMinecraftLanguage_fn = unsigned char (__fastcall *)(void* thisPtr, int pad);
|
||||
void* s_minecraftApp = nullptr;
|
||||
GetMinecraftLanguage_fn s_getMinecraftLanguage = nullptr;
|
||||
GetMinecraftLanguage_fn s_getMinecraftLocale = nullptr;
|
||||
bool s_loggedMissingLanguage = false;
|
||||
std::string s_modsPath;
|
||||
}
|
||||
|
||||
void NativeExports::SetLevelInteropSymbols(void* hasNeighborSignal, void* setTileAndData, void* addToTickNextTick, void* getTile)
|
||||
@@ -36,6 +43,52 @@ void NativeExports::SetLevelInteropSymbols(void* hasNeighborSignal, void* setTil
|
||||
s_levelGetTile = reinterpret_cast<LevelGetTile_fn>(getTile);
|
||||
}
|
||||
|
||||
void NativeExports::SetLocalizationSymbols(void* appPtr, void* getLanguage, void* getLocale)
|
||||
{
|
||||
s_minecraftApp = appPtr;
|
||||
s_getMinecraftLanguage = reinterpret_cast<GetMinecraftLanguage_fn>(getLanguage);
|
||||
s_getMinecraftLocale = reinterpret_cast<GetMinecraftLanguage_fn>(getLocale);
|
||||
}
|
||||
|
||||
void NativeExports::SetModsPath(const std::string& modsPath)
|
||||
{
|
||||
s_modsPath = modsPath;
|
||||
}
|
||||
|
||||
static std::string ResolveDefaultModsPath()
|
||||
{
|
||||
HMODULE hMod = nullptr;
|
||||
std::string modsPath;
|
||||
if (GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCSTR)&ResolveDefaultModsPath, &hMod) && hMod)
|
||||
{
|
||||
char dllPath[MAX_PATH] = { 0 };
|
||||
if (GetModuleFileNameA(hMod, dllPath, MAX_PATH))
|
||||
{
|
||||
std::string dllDir(dllPath);
|
||||
size_t dllPos = dllDir.find_last_of("\\/");
|
||||
if (dllPos != std::string::npos)
|
||||
{
|
||||
dllDir.resize(dllPos + 1);
|
||||
modsPath = dllDir + "mods";
|
||||
return modsPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char exePath[MAX_PATH] = { 0 };
|
||||
if (GetModuleFileNameA(nullptr, exePath, MAX_PATH))
|
||||
{
|
||||
std::string exeDir(exePath);
|
||||
size_t exePos = exeDir.find_last_of("\\/");
|
||||
if (exePos != std::string::npos)
|
||||
{
|
||||
exeDir.resize(exePos + 1);
|
||||
modsPath = exeDir + "mods";
|
||||
}
|
||||
}
|
||||
return modsPath;
|
||||
}
|
||||
|
||||
static std::wstring Utf8ToWide(const char* utf8)
|
||||
{
|
||||
if (!utf8 || !utf8[0]) return std::wstring();
|
||||
@@ -512,6 +565,34 @@ void native_register_string(int descriptionId, const char* displayName)
|
||||
ModStrings::Register(descriptionId, wName.c_str());
|
||||
}
|
||||
|
||||
int native_get_minecraft_language()
|
||||
{
|
||||
if (!s_minecraftApp || !s_getMinecraftLanguage)
|
||||
{
|
||||
if (!s_loggedMissingLanguage)
|
||||
{
|
||||
s_loggedMissingLanguage = true;
|
||||
LogUtil::Log("[WeaveLoader] native_get_minecraft_language: symbols unavailable");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return (int)s_getMinecraftLanguage(s_minecraftApp, 0);
|
||||
}
|
||||
|
||||
int native_get_minecraft_locale()
|
||||
{
|
||||
if (!s_minecraftApp || !s_getMinecraftLocale)
|
||||
return -1;
|
||||
return (int)s_getMinecraftLocale(s_minecraftApp, 0);
|
||||
}
|
||||
|
||||
const char* native_get_mods_path()
|
||||
{
|
||||
if (s_modsPath.empty())
|
||||
s_modsPath = ResolveDefaultModsPath();
|
||||
return s_modsPath.c_str();
|
||||
}
|
||||
|
||||
int native_register_entity(
|
||||
const char* namespacedId,
|
||||
float width,
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace NativeExports
|
||||
{
|
||||
void SetLevelInteropSymbols(void* hasNeighborSignal, void* setTileAndData, void* addToTickNextTick, void* getTile);
|
||||
void SetLocalizationSymbols(void* appPtr, void* getLanguage, void* getLocale);
|
||||
void SetModsPath(const std::string& modsPath);
|
||||
}
|
||||
|
||||
/// Exported C functions callable from C# via P/Invoke.
|
||||
@@ -119,6 +123,9 @@ extern "C"
|
||||
|
||||
__declspec(dllexport) int native_allocate_description_id();
|
||||
__declspec(dllexport) void native_register_string(int descriptionId, const char* displayName);
|
||||
__declspec(dllexport) int native_get_minecraft_language();
|
||||
__declspec(dllexport) int native_get_minecraft_locale();
|
||||
__declspec(dllexport) const char* native_get_mods_path();
|
||||
|
||||
__declspec(dllexport) int native_register_entity(
|
||||
const char* namespacedId,
|
||||
|
||||
@@ -125,6 +125,8 @@ static const char* SYM_BUFFEREDIMAGE_CTOR_FILE = "??0BufferedImage@@QEAA@AEBV?$b
|
||||
static const char* SYM_BUFFEREDIMAGE_CTOR_DLC = "??0BufferedImage@@QEAA@PEAVDLCPack@@AEBV?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@_N@Z";
|
||||
static const char* SYM_TEXTUREMANAGER_CREATETEXTURE = "?createTexture@TextureManager@@QEAAPEAVTexture@@AEBV?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@HHHHHHH_NPEAVBufferedImage@@@Z";
|
||||
static const char* SYM_TEXTURE_TRANSFERFROMIMAGE = "?transferFromImage@Texture@@QEAAXPEAVBufferedImage@@@Z";
|
||||
static const char* SYM_GET_MINECRAFT_LANGUAGE = "?GetMinecraftLanguage@CMinecraftApp@@QEAAEH@Z";
|
||||
static const char* SYM_GET_MINECRAFT_LOCALE = "?GetMinecraftLocale@CMinecraftApp@@QEAAEH@Z";
|
||||
static const char* SYM_ABSTRACT_TEXPACK_GETIMAGE = "?getImageResource@AbstractTexturePack@@UEAAPEAVBufferedImage@@AEBV?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@_N10@Z";
|
||||
static const char* SYM_DLC_TEXPACK_GETIMAGE = "?getImageResource@DLCTexturePack@@UEAAPEAVBufferedImage@@AEBV?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@_N10@Z";
|
||||
static const char* SYM_MINECRAFT_SETLEVEL = "?setLevel@Minecraft@@QEAAXPEAVMultiPlayerLevel@@HV?$shared_ptr@VPlayer@@@std@@_N2@Z";
|
||||
@@ -330,6 +332,15 @@ bool SymbolResolver::ResolveGameFunctions()
|
||||
pTextureAtlasLocationBlocks = Resolve(SYM_TEXATLAS_BLOCKS);
|
||||
pTextureAtlasLocationItems = Resolve(SYM_TEXATLAS_ITEMS);
|
||||
pTileTiles = Resolve(SYM_TILE_TILES);
|
||||
pMinecraftApp = Resolve("?app@@3VCMinecraftApp@@A");
|
||||
if (!pMinecraftApp)
|
||||
pMinecraftApp = ResolveExactProcName(m_moduleBase, "app");
|
||||
pGetMinecraftLanguage = Resolve(SYM_GET_MINECRAFT_LANGUAGE);
|
||||
if (!pGetMinecraftLanguage)
|
||||
pGetMinecraftLanguage = ResolveExactProcName(m_moduleBase, "CMinecraftApp::GetMinecraftLanguage");
|
||||
pGetMinecraftLocale = Resolve(SYM_GET_MINECRAFT_LOCALE);
|
||||
if (!pGetMinecraftLocale)
|
||||
pGetMinecraftLocale = ResolveExactProcName(m_moduleBase, "CMinecraftApp::GetMinecraftLocale");
|
||||
pLevelHasNeighborSignal = Resolve(SYM_LEVEL_HASNEIGHBORSIGNAL);
|
||||
pLevelSetTileAndData = Resolve(SYM_LEVEL_SETTILEANDDATA);
|
||||
pLevelAddToTickNextTick = Resolve(SYM_LEVEL_ADDTOTICKNEXTTICK);
|
||||
@@ -462,6 +473,9 @@ bool SymbolResolver::ResolveGameFunctions()
|
||||
logSym("TextureAtlas::LOCATION_BLOCKS", pTextureAtlasLocationBlocks);
|
||||
logSym("TextureAtlas::LOCATION_ITEMS", pTextureAtlasLocationItems);
|
||||
logSym("Tile::tiles", pTileTiles);
|
||||
logSym("app (CMinecraftApp)", pMinecraftApp);
|
||||
logSym("CMinecraftApp::GetMinecraftLanguage", pGetMinecraftLanguage);
|
||||
logSym("CMinecraftApp::GetMinecraftLocale", pGetMinecraftLocale);
|
||||
logSym("Level::hasNeighborSignal", pLevelHasNeighborSignal);
|
||||
logSym("Level::setTileAndData", pLevelSetTileAndData);
|
||||
logSym("Level::addToTickNextTick", pLevelAddToTickNextTick);
|
||||
|
||||
@@ -100,6 +100,9 @@ public:
|
||||
void* pTextureAtlasLocationBlocks = nullptr; // TextureAtlas::LOCATION_BLOCKS
|
||||
void* pTextureAtlasLocationItems = nullptr; // TextureAtlas::LOCATION_ITEMS
|
||||
void* pTileTiles = nullptr; // Tile::tiles (Tile*[]) for tile id lookup
|
||||
void* pMinecraftApp = nullptr; // global CMinecraftApp app
|
||||
void* pGetMinecraftLanguage = nullptr; // CMinecraftApp::GetMinecraftLanguage(int)
|
||||
void* pGetMinecraftLocale = nullptr; // CMinecraftApp::GetMinecraftLocale(int)
|
||||
void* pLevelHasNeighborSignal = nullptr; // Level::hasNeighborSignal(int,int,int)
|
||||
void* pLevelSetTileAndData = nullptr; // Level::setTileAndData(int,int,int,int,int,int)
|
||||
void* pLevelAddToTickNextTick = nullptr; // Level::addToTickNextTick(int,int,int,int,int)
|
||||
|
||||
@@ -662,7 +662,7 @@ namespace WorldIdRemap
|
||||
1.0f,
|
||||
1.0f,
|
||||
1,
|
||||
L"weaveloader.api:missing_block",
|
||||
L"weaveloader.api:block/missing_block",
|
||||
0.0f,
|
||||
15,
|
||||
kMissingBlockDescriptionId);
|
||||
@@ -676,7 +676,7 @@ namespace WorldIdRemap
|
||||
missingItemId,
|
||||
64,
|
||||
0,
|
||||
L"weaveloader.api:missing_item",
|
||||
L"weaveloader.api:item/missing_item",
|
||||
kMissingItemDescriptionId);
|
||||
IdRegistry::Instance().SetMissingFallback(IdRegistry::Type::Item, missingItemId);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user