Skip to content

Instantly share code, notes, and snippets.

View gist:86c0c8644853ecc1bf7fa000b3ee4873
# Name
ffence - Emit write barriers
# Synopsis
```
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <fcntl.h>
View gist:a99438772511ecfc0542f3377796bb9e
The protocol is implemented on top of QUIC.
First, the server and client recognise protocol compatibility through ALPN. The protocol is actually a potentially limitless family of mutually incompatible protocols, and has ALPNs of the form "laminar/<game name>/<game ID>", where game name is a string that is 32 bytes or less for the name of the game and perhaps if room permits, a name for the version, and game ID is a 32-byte bytestring that is randomly generated each version that make a change to the network format or game mechanics (even if backwards compatible).
Once compatibility is confirmed and the server and client establish a connection, they can handshake and negotiate extensions. Two QUIC extensions are recommended in particular:
Setting QUIC transport parameter 0x000B (accepts_datagrams) to 1 enables DATAGRAM frame types, which correspond to frame type numbers 0x1C and 0x1D. They are described in detail at https://datatracker.ietf.org/doc/draft-pauly-quic-datagram/ .
Setting QUIC transport par
View gist:1a7d7350bebdbdfe0244915921b46d6a
The protocol is implemented on top of QUIC.
First, the server and client recognise protocol compatibility through ALPN. The protocol is actually a potentially limitless family of mutually incompatible protocols, and has ALPNs of the form "laminar/<game name>/<game ID>/<minor version>", where game name is a string that is 16 bytes or less for the name of the game, game ID is a 64-character base64 string that is randomly generated each major version, and minor version is a 64-bit number in hexadecimal that is set to 0x0000000000000000 for the first release of a major version and then incremented each minor version which modifies the protocol.
Once compatibility is confirmed and the server and client establish a connection, a few extensions are automatically enabled (others may be negotiated and then enabled):
- Type 0x1C and 0x1D are DATAGRAM, and follow the syntax and semantics described in detail at https://datatracker.ietf.org/doc/draft-pauly-quic-datagram/ .
- Type 0x4C20 is EXPIRED_STREAM_DAT
View gist:e8c86a0043029bc558cf03737010b8cd
Double-precision floating point numbers have 9007199254740990 different valid NaN payloads, and single-precision floating points have 16777214, both way more than the vast majority of programs will ever need for floating-point purposes. Let's pack our own data into that.
In a double-precision floating-point number, there are 52 mantissa bits, and one sign bit. When the exponent has all bits set, the value as a whole is interpreted as an overflow value if all zeroes, and a NaN otherwise, giving (2^52 - 1)*2 different valid NaN values. Similarly, single-precision floating-point has 21 mantissa bits, for (2^21-1)*2 different valid NaN values. For the room allotted for them, NaN payloads are insignificant in the scheme of things: the IEEE 754 standard mandates NaN behavior that makes their payloads essentially opaque to type-safe code, most programming languages and libraries only give one or two different NaN payloads, most encodings which accept floating point NaNs disregard the payload, and there is not stan
View gist:eee00bc212b989b21500473cabcfb111
Double-precision floating point numbers have 9007199254740990 different valid NaN payloads, and single-precision floating points have 16777214, both way more than the vast majority of programs will ever need for floating-point purposes. Let's pack our own data into that.
In a double-precision floating-point number, there are 52 mantissa bits, and one sign bit. When the exponent has all bits set, the value as a whole is interpreted as an overflow value if all zeroes, and a NaN otherwise, giving (2^52 - 1)*2 different valid NaN values. Similarly, single-precision floating-point has 21 mantissa bits, for (2^21-1)*2 different valid NaN values. For the room allotted for them, NaN payloads are insignificant in the scheme of things: the IEEE standard mandates NaN behavior that makes their payloads essentially opaque to type-safe code, most programming languages and libraries only give one or two different NaN payloads, most encodings which accept floating point NaNs disregard the payload, and there is not standard
View gist:0ce90e910d2b3d244f010cb2c59c5ac3
Double-precision floating point numbers have 9007199254740990 different valid NaN payloads, and single-precision floating points have 16777214, both way more than the vast majority of programs will ever need for floating-point purposes. Let's pack our own data into that.
In a double-precision floating-point number, there are 52 mantissa bits, and one sign bit. When the exponent has all bits set, the value as a whole is interpreted as an overflow value if all zeroes, and a NaN otherwise, giving (2^52 - 1)*2 different valid NaN values. Similarly, single-precision floating-point has 21 mantissa bits, for (2^21-1)*2 different valid NaN values. For the room allotted for them, NaN payloads are insignificant in the scheme of things: the IEEE standard mandates NaN behavior that makes their payloads essentially opaque to type-safe code, most programming languages and libraries only give one or two different NaN payloads, most encodings which accept floating point NaNs disregard the payload, and there is not standard
View gist:426cadba8a988f4459c0c3165ddc40f2
Problem:
Some operations would like to work on past or potential future versions of a component storage. For instance, many fast multiplayer games try to extrapolate component states from the known past to the present while the packets carrying the actual current state are still in transit. Or a discrete event simulation system wants to avoid component order artefacts by not modifying components until the changes to all the components involved in an interaction are determined. Or an AI should be able to simulate possible outcomes of its actions.
The normal fast way to do things like this is to mutate the associated structures in place to the states they had, have, or will have, as needed by the system operating on it, but this is tricky to get right, and can easily break if implementation details such as the order of systems changes. It coflates the different states that the storages had at different times together into one, and allows for multiple unrelated systems that do not work together to mutate the
View gist:9a37e7e15817ca76b6d96a5c54cdaf20
The protocol is implemented as a QUIC extension.
First, the server and client must agree on implementing the Amethyst protocol extension, and check that in fact they agree on the precise game. This is done by setting transport parameter 0xCCCC to the value 1. This value may be set higher in future versions.
Once this check passes, a few new frame types are enabled:
- Type 0x4C00 is GUID_TRANSMISSION. Every frame of this type is a fixed 128-bit frame whose only contents are a game version GUID.
- Type 0x4C01 is GUID_ACK. It has no payload, and only serves to acknowledge GUID_TRANSMISSION frames.
- Type 0x4C02 is EXPIRED_STREAM_DATA, and follows the syntax and semantics described in detailed at https://datatracker.ietf.org/doc/draft-lubashev-quic-partial-reliability/ .
Then, the server and client must double-check that they are in fact compatible. The solution to this, as with many other problems involving multiple mutually incompatible but similar protocols, is a GUID. For the first ver
View gist:7c1b61a387ab970ed63d1445aef6ef46
The protocol is implemented as a QUIC extension.
First, the server and client must agree on implementing the Amethyst protocol extension, and check that in fact they agree on the precise game. This is done by setting transport parameter 0xCCCC to the value 1. This value may be set higher in future versions.
Once this check passes, a few new frame types are enabled:
- Type 0x4C00 is GUID_TRANSMISSION. Every frame of this type is a fixed 128-bit frame whose only contents are a game version GUID.
- Type 0x4C01 is NEW_CHANNEL_ID. It is described in more detail later.
- Type 0x4C02 is EXPIRED_STREAM_DATA, and follows the syntax and semantics described in detailed at https://datatracker.ietf.org/doc/draft-lubashev-quic-partial-reliability/ .
Then, the server and client must double-check that they are in fact compatible. The solution to this, as with many other problems involving multiple mutually incompatible but similar protocols, is a GUID. For the first version of the game, the end develo
View gist:55466ff21a2e7184e6499211086ea725
Mostly based on QUIC.
Long Header:
0.......1.......2.......3.......4.......5.......6.......7.......
[Flags ][ Magic number "Jet" ][ Connection ID ]
[ Connection ID ][ Version Number ]
[ Packet Number ][ Payload... ]
Flags: Most significant bit set to 1 to signify long header, the other 7 are used to specify long packet type.
Magic number "Jet": This field is unused in QUIC, so I'm using it for magic numbering. Set it to the ASCII representation of "Jet".
Connection ID: Unique identifier of a connection session.