Skip to content

Implementing Safer Map Connectivity Checks Using AreaCode.img from Map.wz #313

@v3921358

Description

@v3921358

I noticed that Map.wz contains an AreaCode.img file.
Through the BMS leak, I discovered that it is loaded during map initialization (CFieldMan::CFieldMan).
A function was created to handle connectivity checks:

CFieldMan::IsConnected(CFieldMan *this, unsigned int dwFrom, unsigned int dwTo)

The logic behind the check is as follows:

  1. Extract the prefix of both dwFrom and dwTo map codes by dividing them by 10,000,000.
  2. Use m_mAreaCode to look up the corresponding area category for each prefix.
  3. If the two maps belong to the same category, they are considered connected; otherwise, they are not.

This isConnected check is then used in:

  • CUser::OnPortalScrollUseRequest (likely for Return Scroll)
  • CUserCashItemImpl::IsMapTransferAvailable (likely for Teleport Rock)

Compared to the current check:

mapId / 100_000_000 == player.getMapId() / 100_000_000

which can be interpreted as (dwTo / 100,000,000 == dwFrom / 100,000,000)

this approach is safer ->

FieldMan.isConnected(player.getMapId(), mapId)

A rough Java equivalent would be:

import java.util.HashMap;
import java.util.Map;

public class FieldMan {

    private static final Map<Integer, Integer> areaCode = new HashMap<>();

    public static void loadAreaCode() {
        DataProvider dataProvider = DataProviderFactory.getDataProvider("Map.wz");
        if (dataProvider != null) {
            Data areaCodeImgData = dataProvider.getData("Map/AreaCode.img");
            if (areaCodeImgData != null) {
                for (Data areaCodeData : areaCodeImgData.getChildren()) {
                    areaCode.put(
                        Integer.parseInt(areaCodeData.getName()),
                        Integer.parseInt(String.valueOf(areaCodeData.getData()))
                    );
                }
            }
        }
    }

    public static boolean isConnected(int from, int to) {
        int fromKey = from / 10_000_000;
        int toKey = to / 10_000_000;
        Integer fromCategory = areaCode.get(fromKey);
        Integer toCategory = areaCode.get(toKey);
        if (fromCategory == null || toCategory == null) {
            return false;
        }
        return fromCategory.equals(toCategory);
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions