Game: RF 4.55 (Dragonborn), server v0.3.1, Windows build (stock gameserver.exe, SHA-256 c10012f3…f699a).
Client: the supported Taiwan build, RF_Online.bin SHA-256 46528aac…2bbc558 (2025-07-16), Language=Taiwan.
Summary
The server saves an item on the hotkey bar (link board) as the item's storage place (location and slot), not
as the item. It saves that place only when the player edits the bar (0D/11). Equipping or unequipping moves the
item to another place. The client still knows the item by the same serial, so it sends no 0D/11. At the next login
the server sends whatever item now sits at the saved place. A player who swaps weapons or a shield by hotkey logs
back in to keys that hold the other weapon, or that are empty. Skill and force keys are not affected.
How each part is known:
- Server side: read in the stock v0.3.1
gameserver.exe (with a Go symbol disassembler). - Client side: read in
RF_Online.bin. - Data: our
gommo_rf455.db (read-only) and history.log, one player (Helios, serial 3162). - What the screen showed: reported by the player ("my hotkey bar is messed up after I log back in").
1. What is stored (read)
- 0D/11 is
u8 flag, u8 n, n × {u8 slot 0..49, u8 code, u16 idx}. For an item, code is 4 and idx is the client serial (from the log: f9 02 0d 04 5700 16 ff ffff). handleAlterLinkBoardSlot (0x1407c9d40) → (*AlterLinkBoardSlot).ApplyLinkBoard (0x140665020):- code 4 goes through the resolver from
itemLinkStorage (0x1407ca540), a map from client_index to the row's (location, slot); - the slot is stored as
0x4000 | location << 8 | slot in character_state.link_board (101 bytes: 50 × u16, then the flag).
- Only the slots named in the 0D/11 change. Among the handlers, the only caller of
ApplyLinkBoard and of itemLinkStorage is handleAlterLinkBoardSlot.
2. What is sent at login (read)
handleLinkBoardDownload (0x140871c60) runs compactItemSerials, then itemLinkSerial (0x1407ca8e0). That builds a map from location << 8 | slot to the row's current client_index.WireLinkBoard (0x1406652a0) sends 0x4000 | serial for whichever row sits at the stored place, or 0xFFFF when none does.
3. Equip moves the item without touching the board (read)
handleEquipPart (0x14081dca0) removes the bag row and grants a new row at (1, part). The previous part is returned into the bag (log strings "equip: remove inven fail", "grant equip failed", "return occupant").- From the DB, after the player equipped weapon 4933 from bag slot 78 at 23:04:47:
id loc slot client_index table item created_at
26689 1 6 87 6 4933 2026-10-11 23:04:47
26690 0 78 81 6 6841 2026-10-11 23:04:47 <- the weapon that was equipped before
- The board isn't touched, and the client's key still holds serial 87, so no 0D/11 is sent.
4. The saved board at logout (read, link_board updated 23:04:54)
| Key | Saved place | Sent back at the next login |
|---|
| bar 2, key 3 | (1,5), the shield slot | Nothing: the shield (125) has since been unequipped to (0,4) |
| bar 1, key 3 | (0,78) | Weapon 6841, whatever is in bag slot 78 now |
| bar 2, key 2 | (1,6) | Weapon 4933, whatever is equipped now |
| bar 2, key 4 | (0,71) | Weapon 7713 |
Each time the player swaps (the log has "equipped" / "unequipped" on slots 5 and 6 all session), these places hold
different items.
Expected
A hotkey keeps the item it was set to across a relog, wherever that item has moved since.
Suggested fix
Either of these:
- Store something stable for an item. The serial isn't stable:
compactItemSerials renumbers it each login. The row id isn't either, since equip re-inserts the row. A stable item id would work. - Rewrite the board when an item moves. In
handleEquipPart, handleOffPart, the embellish handlers, storage moves, and anything else that deletes and re-inserts an item row, replace the old 0x4000 | loc << 8 | slot with the new one in link_board. For a swap, replace both, the occupant's too.
How to reproduce in game
- Put two weapons (or a weapon and a shield) from the bag onto the hotkey bar.
- Equip one of them from the bar, then the other. Don't edit the bar again.
- Relog. The weapon keys now hold the other weapon or nothing, and the shield key is empty.
What i do locally (not a fix)
A client patch. When the client's bag sender (0x58b7b0) finds the bag changed, a small routine marks every item
entry in the link-board sender's snapshot (board 6 + 0x1308c) as changed. The link-board sender (0x58bb90, every
5 s and before leaving) then resends all the item keys, and the server re-resolves their current places. It costs
one extra 0D/11 and one link_board write after each bag change.
Where to look
- Server (v0.3.1):
handleAlterLinkBoardSlot 0x1407c9d40, itemLinkStorage 0x1407ca540, ApplyLinkBoard 0x140665020;handleLinkBoardDownload 0x140871c60, itemLinkSerial 0x1407ca8e0, WireLinkBoard 0x1406652a0;compactItemSerials 0x140883760, handleEquipPart 0x14081dca0, handleOffPart 0x14081f4a0.
- Client: the link-board sender
0x58bb90 (snapshot at board 6 + 0x1308c), the bag sender 0x58b7b0, and the flush 0x562d90.