Old School Ops

RF455-044 # RF 4.55: monsters next to you blink out, or vanish until re-sent, when the monster position tick runs late

Game server RF Online: Dragonborn v0.2.0 normal · filed by cybercyber 13h ago
New

Game: RF 4.55 (Dragonborn), server v0.2.0, Windows build (gameserver.exe SHA-256 96452fbd…d70cec7). Client: the supported Taiwan build, RF_Online.bin SHA-256 46528aac…2bbc558 (8,430,808 bytes, 2025-07-16), Language=Taiwan

At a hunting spot, with other players online and moving, monsters right next to you (50–800 away, alive, sometimes the one you're fighting):

  1. blink out: they disappear for a while, then pop back in place;
  2. vanish: they disappear and stay gone until the server sends them again (they move, or you move and they come back into view).

It gets worse the more players are online and moving. With one player alone it almost never shows.

Cause

The client drops any monster it hasn't had a position tick (04/0A) for in 10 s. The server's tick for an idle monster is about 4.6 s apart when the server is quiet. When it's busy, the ticks stretch well past 10 s.

Client side (RF_Online.bin)
  • Recv_msg_04_0A (0x5c4810, body u8 0, u8 kind, u16 index, u32 serial) finds the character and stamps timeGetTime() as "last heard from" (0x7cf050, log string "Real Fix").
  • Check 1, hide: vtable +0x70 0x7cf0b0 reports the character stale when now - last >= 10000 ms (the cmp at 0x7cf0ef). 0x51ccd0 then treats it as out of range and stops drawing it, until the next tick. That's symptom 1.
  • Check 2, delete: for monsters, vtable +0x130 0x458750 is true when now - last > 10000 ms (the cmp at 0x45878c). 0x51ce1f then deletes the monster from the client's list. Only a fresh 03/10, 04/0B or 04/16 brings it back. That's symptom 2.

These limits are fine as long as every monster in view gets 04/0A at least every 10 s.

Server side (gameserver.exe v0.2.0)
  • The tick is counted in loop passes, not time.
    • (*Server).monsterKeepAlive (0x140885ac0) counts each monster's +0x1c0 down and sends protocol.MonsterPositionTick with broadcastNearScope at 0. It then resets it to 22 (0x140885b94).
    • It runs from monsterWanderLoop (0x14088a300): one 200 ms ticker for every monster on the server. Each pass does stepMonsterAI, regenMonsterHP and monsterKeepAlive per monster.
    • So the tick is every 23 passes, 4.6 s, but only if every pass fits in 200 ms. Go drops ticker ticks when a pass runs long, and the keep-alive stretches with it.
  • Passes run long because they wait on the world lock.
    • Per monster, several times a pass, the loop calls (*world).snapshotPlayers (0x140941ac0), through searchNearPlayer in stepMonsterAI and through broadcastNearScope.
    • That lock is held by (*world).monstersInScope (0x140940360) while it walks every monster on the server, to keep the ones on one map and layer.
  • monstersInScope runs for normal player activity:
    • updateMonsterVisibility (0x14093a020): every player's 04/02 position report (handlePosReport), and every move start, stop and re-entry. Also tickVisibleMonsters for every player every ~4.6 s, and resyncScope.
    • towerNearestMonster (0x1408fcce0): every finished guard tower, from towerLoop on its own 200 ms ticker.
    • aoeCandidates, animusAreaSplash, trapHasEnemyNear and detonateTrap: every area skill, animus splash and trap.

So the lock's load grows with (players moving + towers + area attacks) × (all monsters on the server).

Profiled with settings.cfg PROFILE_PORT:

  • monsterWanderLoop used about 4% CPU, but was blocked on the world lock for 19.5 s of a 20 s window.
  • The lock's held time was mostly monstersInScope under updateMonsterVisibility and under the tower search.
Measured (time between 04/0A for each monster near one observing player, 150 s at a hunting spot)
OnlineMedian90%MaxGaps ≥ 10 s
1 player alone5.2 s7–9 snone
~120 characters, walking (a position report every 250 ms while moving, as GoMMO's own scripted client does)37 s57 s68.6 s40 of 50

At the second load, over 20 minutes at one hunting spot, the client deleted 18 live monsters 50–840 away from the player, each at 10.0–10.5 s since its last tick.

Even alone, the longest gap (9 s) was 1 s short of the client's limit.

Sending 04/0A more often on the same counter doesn't help. I tried a reset of 3 instead of 22 (with the tower ticker slowed to 1 s at the same time): the gaps got worse (median 66.5 s, max 147 s), because each tick is one more broadcastNearScope through the same lock.

Reported on version 0.2.0

History

  • cybercyber filed it · 13h ago

Replies

Nobody has replied yet.

Sign in to comment.

Loading…
Open the full search page