leevccc 发表于 2025-5-12 17:04:08

GMS083 拆分椅子img为多个小img的例子

原帖地址


这个例子是将原本的椅子数据从0301.img拆分为0301x.img 并让客户端正确加载,可以尽情的举一反三推导出其他的使用场景,我就不举例了。

客户端部分


//#include "Global.h"
#include <shlwapi.h>
#pragma comment(lib, "shlwapi.lib")

bool Hook_LoadLayer() {
    typedef int(__fastcall* _LoadLayer)(void* ecx, void* edx, wchar_t** bsUOL, int bLeft, void* l, int* pnRepeatStartIndex);
    static auto LoadLayer = reinterpret_cast<_LoadLayer>(0x00941417);

    _LoadLayer Hook = [](void* ecx, void* edx, wchar_t** bsUOL, int bLeft, void* l, int* pnRepeatStartIndex) -> int {
      if (StrStrW(*bsUOL, L"0301.img")) {
            wchar_t* wsUOL = StrStrW(*bsUOL, L".img/") + 5;
            wchar_t* wsEffect = StrStrW(wsUOL, L"/");

            unsigned int uLen = lstrlenW(wsUOL) - lstrlenW(wsEffect) + 1;
            wchar_t wsNewUOL;
            StrCpyNW(wsNewUOL, wsUOL, uLen);

            int nItemID = _wtoi(wsNewUOL);
            int nItemType = nItemID / 1000;

            wchar_t wsPath;
            wsprintfW(wsPath, L"Item/Install/%05d.img/%08d%ws", nItemType, nItemID, wsEffect);

            StrCpyW(*bsUOL, wsPath);
      }

      return LoadLayer(ecx, edx, bsUOL, bLeft, l, pnRepeatStartIndex);
    };

    return SetHook(true, reinterpret_cast<void**>(&LoadLayer), Hook);
}

bool Hook_GetObjectA() {
    typedef void* (__fastcall* _GetObjectA)(void* ecx, void* edx, void* result, wchar_t** bsUOL, void* vParam, void* vAux);
    static auto GetObjectA = reinterpret_cast<_GetObjectA>(0x00403A93);

    _GetObjectA Hook = [](void* ecx, void* edx, void* result, wchar_t** bsUOL, void* vParam, void* vAux) -> void* {
      if (StrStrW(*bsUOL, L"Item/")) {
            wchar_t* wsCategory = StrStrW(*bsUOL, L"/00");
            if (wsCategory) {
                wsCategory += 2;

                unsigned int uLen = lstrlenW(*bsUOL) - lstrlenW(wsCategory);
                wchar_t wsUOL;
                StrCpyNW(wsUOL, *bsUOL, uLen);
                StrCatW(wsUOL, wsCategory);
                StrCpyW(*bsUOL, wsUOL);
            }
      }
      return GetObjectA(ecx, edx, result, bsUOL, vParam, vAux);
      };

    return SetHook(true, reinterpret_cast<void**>(&GetObjectA), Hook);
}

DWORD dwGetItemProp = 0x005D371F;
void __declspec(naked) Hook_GetItemProp()
{
    __asm
    {
      cmp      esi, 3
      jne      _RET
      cmp      edi, 399
      je      _RET

      push    eax
      push    ecx
      push    edx

      xor edx, edx
      mov      eax, ebx
      mov      ecx, 1000
      div      ecx

      mov      edi, eax

      pop      edx
      pop      ecx
      pop      eax

      _RET :
      jmp    dword ptr
    }
}

void Hook_Install() {
    Hook_LoadLayer();
    Hook_GetObjectA();
    Hook(&dwGetItemProp, Hook_GetItemProp);
}


另外要修改 StringPool 中ID为2352的值

Item/%s/%04d.img
改为
Item/%s/%05d.img
因为img的文件名多了一个

然后你就可以把0301.img里的内容拆分到0301x.img中去了



服务端要修改的部分,应该是HeavenMS的端
修改src\server\MapleItemInformationProvider.java里的两个方法

private MapleData getItemData(int itemId) {
    MapleData ret = null;
    String idStr = String.format("%08d", itemId); // e.g. 03010001
    String baseImgName = idStr.substring(0, 4);   // e.g. 0301
    String splitImgPrefix = idStr.substring(0, 5); // e.g. 03010

    MapleDataDirectoryEntry root = itemData.getRoot();
    for (MapleDataDirectoryEntry topDir : root.getSubdirectories()) {
      for (MapleDataFileEntry iFile : topDir.getFiles()) {
            // First: Try original format (e.g. 0301.img)
            if (iFile.getName().equals(baseImgName + ".img")) {
                ret = itemData.getData(topDir.getName() + "/" + iFile.getName());
                if (ret != null) {
                  MapleData child = ret.getChildByPath(idStr);
                  if (child != null) {
                        return child;
                  }
                }
            }
            // Second: Try split format (e.g. 03010.img, 03011.img, etc.)
            else if (iFile.getName().startsWith(splitImgPrefix)) {
                ret = itemData.getData(topDir.getName() + "/" + iFile.getName());
                if (ret != null) {
                  MapleData child = ret.getChildByPath(idStr);
                  if (child != null) {
                        return child;
                  }
                  System.out.println(" Tried to load item " + itemId + " from " + iFile.getName());
                }
            }
      }
    }

    // Fallback: try equipData
    root = equipData.getRoot();
    for (MapleDataDirectoryEntry topDir : root.getSubdirectories()) {
      for (MapleDataFileEntry iFile : topDir.getFiles()) {
            if (iFile.getName().equals(idStr + ".img")) {
                return equipData.getData(topDir.getName() + "/" + iFile.getName());
            }
      }
    }

    return null;
}

public List<Integer> getItemIdsInRange(int minId, int maxId, boolean ignoreCashItem) {
    List<Integer> list = new ArrayList<>();

    for (int i = minId; i <= maxId; i++) {
      if (getItemData(i) != null && (!ignoreCashItem || !isCash(i))) {
            list.add(i);
      }
    }

    return list;
}

Magical-H 发表于 2025-5-13 22:08:23

沙发!顶起来支持!
页: [1]
查看完整版本: GMS083 拆分椅子img为多个小img的例子