Skip to content

lcmem Scanning

NNKtv28 edited this page Sep 28, 2026 · 2 revisions

The scan workflow

A first scan reads about 14 GB and takes about 90 seconds. Each refinement after that is almost instant, because it only re-reads addresses that are still candidates. Results persist between runs in .lcmem/session.npz.

python -m lcmem scan 60 --type f32      # while the value shows 60
# change it in game
python -m lcmem refine exact 90
python -m lcmem refine decreased        # narrow without knowing the number
python -m lcmem results

Unknown values

Use shell for tight loops: it keeps the snapshot in memory. It is also the only place where scan unknown works (for a value you cannot read on screen):

lcmem> type f32
lcmem> scan unknown 512
lcmem> refine decreased
lcmem> refine unchanged
lcmem> results

Sessions are pinned to a process ID. If you restart the game, lcmem tells you to rescan instead of writing to an address that now means something else.

Turning a hit into something durable

A bare address is useless after a restart. When a scan narrows to one candidate, find out what owns it:

python -m lcmem identify 0x1E99F58AA80      # -> CameraFX.CameraFXManager
python -m lcmem object   0x1E99F58AA80      # every field, named and decoded

Now you have a class and a field name instead of an address. Write a patch against that, or a Love Menu feature.

Finding by shape

find_class cannot always find a class by name. On this client, ChatChannelInfo's name is in the metadata heap but nothing points at it. Where that happens, find objects by their known field layout instead. It is faster (one sweep, not two) and more robust. See find_message_vtable in lc_patches/lc_flight/locate.py.

Clone this wiki locally