View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0025684 | Return of Reckoning | General | public | 2026-08-08 14:40 | 2026-08-08 17:34 |
| Reporter | reddozen | Assigned To | |||
| Priority | normal | Severity | crash | Reproducibility | always |
| Status | new | Resolution | open | ||
| Summary | 0025684: tome update packet corruption | ||||
| Description | From the %LOCALAPPDATA%\CrashDumps .dmp file crashed midfight during a fort. no lag or packetloss just bonked. Client crashed at packet decode: 00 0a length f8 opcode be bb 29 0f 7a 66 92 84 ae 47 payload Here's some psuedo code to illustrate the problem and fix // Busted af public void SendTok(ushort Entry, bool Print) { PacketOut Out = new PacketOut((byte)Opcodes.F_TOK_ENTRY_UPDATE); Out.WriteUInt32(1); Out.WriteUInt16((UInt16)Entry); // <-- This is wrong endianness Out.WriteByte(1); Out.WriteByte((byte)(Print ? 1 : 0)); Out.WriteByte(1); GetPlayer().SendPacket(Out); } // Corrected public void SendTok(ushort Entry, bool Announce, byte Popup = 0, bool Unlocked = true) { // Stop crashing me pls if (Entry >= 12000) { Log.Error("Big Sadness", "Refusing tome entry " + Entry + " as its above the max value of 12000"); return; } PacketOut Out = new PacketOut((byte)Opcodes.F_TOK_ENTRY_UPDATE); Out.WriteUInt16R(0); // 0 = single entry, 1 = bitmap mode Out.WriteUInt16R(1); // count. always 1 cuz not bitmap Out.WriteUInt16R(Entry); // <-- FIX LITTLE ENDIAN Out.WriteByte((byte)(Unlocked ? 1 : 0)); // 0 = relock the entry, 1 = unlock it Out.WriteByte((byte)(Announce ? 1 : 0)); // 0 = silent, 1 = recent list + combat log + some UI shit Out.WriteByte(Popup); // popup category: 0 = none, 1/2/3 does some UI shit. GetPlayer().SendPacket(Out); } // Your bug is probably somewhere in here. dunno why this would fire mid-fort outside zone travel public void SendAllToks() { byte[] Bits = new byte[1500]; // 1500 * 8 = 12000 entries foreach (KeyValuePair<ushort, Character_tok> Kp in _Toks) // Hey! Figure out your concurrency safety here! :) { ushort Entry = Kp.Value.TokEntry; if (Entry >= 12000) // Stop crashing me pls { Log.Error("Big Sadness", "Refusing tome entry " + Entry + " as its above the max value of 12000"); continue; } Bits[Entry >> 3] |= (byte)(1 << (Entry & 7)); } PacketOut Out = new PacketOut((byte)Opcodes.F_TOK_ENTRY_UPDATE); Out.WriteUInt16R(1); // 0 = single entry, 1 = bitmap mode Out.WriteUInt16R((ushort)Bits.Length); // bitmap count Out.WriteUInt16R(0); // base: the entry id that bit 0 of byte 0 maps to. Bug is probably somewhere in here Out.Write(Bits, 0, Bits.Length); GetPlayer().SendPacket(Out); } crashed at the 12000 assert | ||||
| Tags | No tags attached. | ||||
|
This is probably unrelated to the TOK system and more a case of the client trying to parse garbage data as a packet. The current backpressure implementation in the server netcode unfortunately can truncate packets if the client isn't receiving fast enough (fort and other low FPS situations usually trigger this since the client receive code doesn't appear to be async) and this result in a desync of the bytestream. The client then starts interpreting the next bytes as best it can, which is why you sometimes see random survey popups, huge amounts of gold or XP / renown being received, etc. It's entirely possible one of those interpretations looks like a TOK update and triggers this failure. If the TOK packet endianness was wrong then any time a TOK is unlocked would be broken or show garbage, and this isn't the case. |
|
|
That wasn't the case in this scenario as the ringbuffer from the crash dump wasn't showing garbled in the next frames, or would be insanely unlikely. On another note its entirely possible to increase the clientside netcode ringbuffer size so the buffer overruns can't occur like you're describing. You can do this easily in the LAA client. |
|