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: 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,
0x41e2d0prints NDLanguage0xa39with0x998(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,+0x452cisn'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
- Give a level 45+ character a council rank:
race boss 4 <name>(any rank 1–8). - Put a grade-9 item of their race in the bag (Accretia: Voice of Empire Core
iuafd45; the mastery limit must be met). - Try to equip it. The client refuses with the Consul message, and the server logs nothing.
- 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):
checkEquipGates0x140820f60,raceBossStateBits0x140904900,raceBossRankOf0x140904140,setRaceBossRankCache0x140903f80,(*client).stateHigh0x1408ba9e0,broadcastState0x140928100. - Client: the equip check
0x41ddc0, the class-grade gate0x41e160and its message0x41e2d0,+0x452c(0x41e290read,0x44f090write), the state update0x44dee0.