Old School Ops

RF455-082 RF 4.55 v0.3.1: race council members can't equip council armour (the server never sends the seat state bits)

Game server RF Online: Dragonborn v0.3.1 low · filed by cybercyber
New

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 race council's armour (m_nClassGradeLim 9: Voice of Empire Core, Bellato Union's Shout, Representative of Decem at level 45, the level 50–70 race sets and the <ArchonOnly> uniforms) can't be worn by any council member (race ranks 1–8). The client refuses it before sending anything. Only the Race Leader (rank 0) can wear it.

The client allows grade-9 gear only when the character has a council seat, and it learns the seat from state bits 0x21–0x28. The server sends bit 16 (Race Leader) or bit 17 (council) but never a seat bit.

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.
  • Item data: read from the bundled db\gamedata_rf455.db.
  • The refusal: seen in game (a level 45 Accretia at rank 4 with a Voice of Empire Core); the server log has no equip line for it.

1. The items (read, gamedata_rf455.db)

m_nClassGradeLim is 0 on most item rows. It is 8 on 12 rows of each armour table (<GuildMasterOnly> uniforms, i?????c45) and 9 on 66 rows of each (helmetitem, upperitem, loweritem, gauntletitem, shoeitem), plus one weapon. Example, upperitem 827:

iuafd45  Voice of Empire Core  m_strCivil 00001  m_nLevelLim 45  m_nClassGradeLim 9  m_nExpertID1 2  m_nExpertLim1 33

2. The server doesn't check the grade (read)

(*Server).checkEquipGates (0x140820f60) checks the race (civil), the level, the two mastery pairs and the two-hand rule. It never reads the class-grade limit. When the test character equipped other items, the log had "equipped" lines, but there was none for this item, so the client never sent the request.

3. The client's gate (read)

The client's equip check (0x41ddc0) runs its gates in order and ends with the class-grade gate 0x41e160:

  • The item's grade is the record's +0xd4 (0x420d50).
  • Grade 9 passes only when 0x41e290() (the character's +0x452c) is greater than 1:
41e1a3: mov  ecx, [0x1028ac0]        ; own avatar
41e1a9: call 0x41e290                ; mov eax, [ecx+0x452c]
...
41e1dd: cmp  dword [ebp-0x10], 1
41e1e1: jle  0x41e1f2                ; -> refused
41e1e3: cmp  dword [ebp-0xc], 9      ; grade 9
41e1e7: jne  0x41e1f2
41e1e9: mov  eax, 1                  ; allowed
  • On a refusal, 0x41e2d0 prints NDLanguage 0xa39 with 0x998 (the "Consul" label) for grade 9.

4. Where +0x452c comes from (read)

+0x452c is written only by 0x44f090(v), from the state-flag update 0x44dee0 (64-bit state, tested through the shift helper 0x878370):

  • bit 16 → title level 3 and +0x452c = 10 (the Race Leader);
  • bit 17 → title level 2, then the first of bits 0x21…0x28 that is set gives +0x452c = 2…9. With none of them set, +0x452c isn't written;
  • bit 42 (without 16 or 17) → 1; none of these bits → 0.

So a council member needs bit 17 and one seat bit. Rank k = bit 0x20 + k (value k + 1) is our reading of the pattern. The client only needs any one of them for grade 9.

5. What the server sends (read)

raceBossStateBits (0x140904900) gives the low word's rank bits:

14090492b: test  cl, cl                ; rank == 0 ?
14090492d: mov   ecx, 0
140904932: mov   edx, 0x10000
140904937: cmove ecx, edx              ; rank 0 -> bit 16
14090493a: test  al, al
14090493c: je    0x14090494a
140904940: cmp   al, 9
140904942: jae   0x14090494a
140904944: or    ecx, 0x20000          ; ranks 1-8 -> bit 17
14090494a: mov   eax, ecx

The high word comes from (*client).stateHigh (0x1408ba9e0), which sets only 0x400000. Its callers are broadcastState, onPlayerDeath, handleRevival, actResurrect, updatePartyFlag and broadcastPartyState. Nothing in the gameserver package sets bits 0x21–0x28. The only other high bit i found is bts rcx, 0x2a in guildLifeStateWord.

Expected

A council member (ranks 1–8) can wear the council armour, like the Race Leader.

Suggested fix

Set the seat bit with bit 17: for rank k in 1–8, set bit k of the high state word (bit 0x20 + k overall), for example in stateHigh or wherever the 64-bit state is put together. Don't set bit 0x20 for rank 0: the client reads it as another flag (0x44ed68, the +0x80d marker).

Optionally, check m_nClassGradeLim in checkEquipGates too. Today a modified client could equip council gear without a rank.

How to reproduce in game

  1. Give a level 45+ character a council rank: race boss 4 <name> (any rank 1–8).
  2. Put a grade-9 item of their race in the bag (Accretia: Voice of Empire Core iuafd45; the mastery limit must be met).
  3. Try to equip it. The client refuses with the Consul message, and the server logs nothing.
  4. The same item can be equipped at rank 0 (race boss 0 <name>).

What i do locally (not a fix)

A server byte patch rewrites the tail of stateHigh (0x1408baa66) more compactly and adds a small routine in its int3 tail (0x1408baacf). The routine reads the rank cache [client+0x48] (byte 0 = rank) and sets bit rank of the high word, then clears bit 0, so rank 0 adds nothing. Not yet tested in game.

Where to look

  • Server (v0.3.1): checkEquipGates 0x140820f60, raceBossStateBits 0x140904900, raceBossRankOf 0x140904140, setRaceBossRankCache 0x140903f80, (*client).stateHigh 0x1408ba9e0, broadcastState 0x140928100.
  • Client: the equip check 0x41ddc0, the class-grade gate 0x41e160 and its message 0x41e2d0, +0x452c (0x41e290 read, 0x44f090 write), the state update 0x44dee0.
Reported on version 0.3.1

Replies

Nobody has replied yet.

Sign in to comment.

Top xp sources

How xp works
Loading…

Open the full search page