Open khanghugo opened 1 year ago
Sorry for the delayed reply! Thanks for the kind words. ❤️ I'm really glad you've found the documentation helpful.
Unfortunately I have to admit that the fundamentals behind delta compression or even the bit packing/unpacking underlying it are still pretty opaque to me. I adapted hlviewer's implementation, mostly just to get something working with fp-ts
ADTs. I think that project is much more readable as a reference for the decoding side:
I'll take a stab at generalizing what I do know (or what I think I know, at least 😄), but I've only had to decode them relying on the hlviewer implementation. Encoding from within a client or just trying to write the structures to file might be a little more nuanced.
Individual delta encoders look like they're defined in <mod>/delta.lst
, along with their fields.
Not 100% sure on what the header implies:
// none == no conditional encode routine
// gamedll routine_name : before transmitting data, invoke the named function from the game .dll to reset fields as needed
// clientdll routine_name : same as above, except the routine is called via the client.dll
My guess is that a client would need these to know how to encode the deltas.
DT_*
): describes the type of the value.SVC_*
messages from server.Big guesses to follow here...
<mod>/delta.lst
.SVC_DELTADESCRIPTION
messages.SVC_DELTADESCRIPTION
message for each of the <mod>/delta.lst
deltas.delta_description_t
deltas.SVC_*
messages are received and will decode them according to the metadata in the description.SVC_*
messages containing specific deltas.SVC_*
messages can contain 1 or more delta structures.Message | When | |
---|---|---|
SVC_CLIENTDATA |
Every frame. Has client data, weapon data from the previous frame. | Message structure: SVC_CLIENTDATA. |
SVC_EVENT |
When some specific game events happen; can be queued / dropped. | Message structure: SVC_EVENT. |
SVC_EVENT_RELIABLE |
When some specific game events happen, but can't be queued / dropped. | Message structure: SVC_EVENT_RELIABLE. |
SVC_SPAWNBASELINE |
When entity spawns for the first time? | Message structure: SVC_SPAWNBASELINE. |
SVC_PACKETENTITIES |
Initial entity state? | Message structure: SVC_PACKETENTITIES. |
SVC_DELTAPACKETENTITIES |
Every frame? Same as SVC_PACKETENTITIES but this compares to a previous frame somehow. |
Message structure: SVC_DELTAPACKETENTITIES. |
"Reliable" terminology harkens back to Quake netcode stuff I believe: https://fabiensanglard.net/quakeSource/quakeSourceNetWork.php.
There is bitwise magic afoot here, so I've never had a great understanding about this.
hlviewer is an excellent reference: https://github.com/skyrim/hlviewer.js/blob/master/src/BitReader.ts#L10-L48.
Roughly I believe it works like:
x
amount of bits in a byte.n
number of those bits to read a value.x - n
bits left in the byte to store more data.If a message is finished writing, usually it will fill up to the next byte boundary.
Hey, thanks for the detailed reply. Since then I have found some (enough) details to understand the delta. Good enough to implement my own, and also a delta writer.
https://github.com/khanghugo/demosuperimpose-goldsrc/blob/master/src/netmsg_doer/utils.rs
Great work on this.
I am trying to write my own demo writer but now I am working through delta. I hope you won't mind writing documentation on it since apparently you are the best at writing docs for GoldSrc demo as of now.
Regardless, I am still plowing through it by reading your delta decoding snippet along with this and this.