Fitzquake Protocol

From Quake Wiki

Fitzquake Protocol
Version: 666
Base: Netquake Protocol
Clients: Fitzquake 0.85+

DirectQ 1.7.666+

Servers: Fitzquake 0.85+

DirectQ 1.7.666+

The Fitzquake Protocol is derived from the Netquake Protocol and was introduced in Fitzquake version 0.85. Currently only Fitzquake and DirectQ support it.

Overview of Features[edit]

The Fitzquake protocol adds support for increased limits such as model and sound precaches, model frames, edicts, and player armor and ammo stats. It also supports entity and weaponmodel alpha, and adds timing hints for model interpolation.

Model index > 255[edit]

Quake normally sends model indexes as a single byte. Fitzquake can send a second byte when the index exceeds 255. This works for both entity models and player's weapon models.

Entity frame index > 255[edit]

Quake normally sends entity frame indexes as a single byte. Fitzquake can send a second byte when the index exceeds 255.

Sound index > 255[edit]

Quake normally sends sound indexes as a single byte. Fitzquake can send a second byte when the index exceeds 255.

Edicts > 8192[edit]

Normally any edict beyond the first 8192 can't play a sound effect, because only 13 bits are devoted to the edict number in a sound message. Fitzquake can send a full 2-byte edict number in the sound message, so that up to 65535 edicts can play sounds.

Player ammo and armor > 255[edit]

Player ammo and armor is normally sent as a single byte. Fitzquake can send a second byte so that the client can recieve ammo/armor values up to 65535.

High-precision aiming[edit]

Client angles are sent as shorts instead of bytes, for more precise aiming (especially noticable when zoomed in.)

Entity alpha[edit]

Entity alpha is stored on the server as a .alpha field, and can be hard-coded in the bsp file or set dynamically by QuakeC. The server will support hard-coded values from the bsp even if the progs.dat was not compiled with the .alpha field.

Entities with alpha "0" will have a default alpha value, and generally be fully visible. To explicitly set an entity to invisible, set the alpha to "-1". Values between "1" and "0" will interpreted normally. Note that a map entity with no alpha field specified will get the value "0" at load time, and therefore be default.

Water surfaces on entities that have default alpha will obey r_wateralpha, but water surfaces on entities that have a specified alpha value will ignore r_wateralpha and use the entity alpha.

Weapon model alpha[edit]

Player weapon model alpha is transmitted seperately from the client entity alpha, but for now the Fitzquake server uses the client entity's .alpha field for both. There is currently no way for QuakeC to set the weapon alpha specifically.

Interpolation timing hints[edit]

For entities that don't animate at exactly 10Hz, such as crucified zombies, this hint tells the client what interval to use when lerping to the new frame. This interval is taken from the entity's .nextthink value, subtracted from the current server time. It is only sent to clients when it does not equal 0.1.

Client Messages[edit]

The following client messages have changed:

clc_move[edit]

Client angles are always sent to the server as shorts instead of bytes. The angles are encoded and decoded as follows:

void MSG_WriteAngle16 (sizebuf_t *sb, float f)
{
    MSG_WriteShort (sb, Q_rint(f * 65536.0 / 360.0) & 65535);
}

float MSG_ReadAngle16 (void)
{
    return MSG_ReadShort() * (360.0 / 65536);
}

You may need to define Q_rint in your mathlib.h; the definition is:

#define Q_rint(x) ((x) > 0 ? (int)((x) + 0.5) : (int)((x) - 0.5))

Server Messages[edit]

The following server messages have been added, or their behavior has changed:

entity update[edit]

The existing update flags field can have 5 new flags.

  • U_EXTEND1 - another byte of flags will follow the first two.
  • U_ALPHA - entity has alpha different than its baseline. Alpha is encoded as a single byte, with a 0 representing "default" alpha, and values 1-255 representing the range 0.0-1.0. Use the ENTALPHA_ macros (below) to convert correctly between floats and bytes. This byte is sent immediately after the U_ANGLE3 angle, if present.
  • U_FRAME2 - entity frame is >255, so a second byte will be sent. It is sent immediately after the U_ALPHA byte, if present.
  • U_MODEL2 - entity modelindex is >255, so a second byte will be sent. It is sent immediately after the U_FRAME2 byte, if present.
  • U_LERPFINISH - nextthink interval (ent->v.nextthink - sv.time) is not exactly 0.1 seconds, so the actual interval will be sent as a byte. Intervals of 0.0-1.0 seconds map to values 0-255. Anything >1 is clamped. It is sent immediately after the U_MODEL2 byte, if present.

svc_clientdata[edit]

The existing flags field can have 11 new flags:

  • SU_EXTEND1 - a third byte of flags follows the first two.
  • SU_WEAPON2 - weapon model index is >255, so a second byte will be sent. It is sent immediately after the STAT_ACTIVEWEAPON byte.
  • SU_ARMOR2 - armor value is >255, so a second byte will be sent. It is sent immediately after the SU_WEAPON2 byte, if present.
  • SU_AMMO2 - current ammo value is >255, so a second byte will be sent. It is sent immediately after the SU_ARMOR2 byte, if present.
  • SU_SHELLS2 - shell ammo value is >255, so a second byte will be sent. It is sent immediately after the SU_AMMO2 byte, if present.
  • SU_NAILS2 - nail ammo value is >255, so a second byte will be sent. It is sent immediately after the SU_SHELLS2 byte, if present.
  • SU_ROCKETS2 - rocket ammo value is >255, so a second byte will be sent. It is sent immediately after the SU_NAILS2 byte, if present.
  • SU_CELLS2 - cell ammo value is >255, so a second byte will be sent. It is sent immediately after the SU_ROCKETS2 byte, if present.
  • SU_EXTEND2 - a fourth byte of flags follows the first three.
  • SU_WEAPONFRAME2 - weapon frame index is >255, so a second byte will be sent. It is sent immediately after the SU_CELLS2 byte, if present.
  • SU_WEAPONALPHA - weapon alpha is not default, so an alpha byte will be sent. It is encoded the same as U_ALPHA. It is sent immediately after the SU_WEAPONFRAME2 byte, if present.

svc_sound[edit]

The existing flags field can have 2 new flags.

  • SND_LARGEENTITY - the edict is 2 full bytes followed by a third byte for the channel, rather than packing them into a single short (13 bits for edict, 3 bit for channel.) This is used whenever the edict number is > 8191.
  • SND_LARGESOUND - the sound index is 2 bytes instead of 1. This is sent when the sound index is > 255.

svc_spawnbaseline2 (new)[edit]

This message is sent instead of svc_spawnbaseline if an entity has alpha, has a model index > 255, or has a frame index > 255. It is similar to svc_spawnbaseline except a new "flags" byte comes at the beginning of the message. This byte can have 3 flags:

  • B_LARGEMODEL - model index is sent as a short instead of a byte.
  • B_LARGEFRAME - frame index is sent as a short instead of a byte.
  • B_ALPHA - an alpha byte is added at the end of the message. Encoded the same as U_ALPHA.

svc_spawnstatic2 (new)[edit]

This message is sent instead of svc_spawnstatic if an entity has alpha, has a model index > 255, or has a frame index > 255. It is similar to svc_spawnstatic except a new "flags" byte comes at the beginning of the message. The flags are intepreted the same as svc_spawnbaseline2.

svc_spawnstaticsound2 (new)[edit]

This message is sent instead of svc_spawnstaticsound if sound index is > 255. It is the same as svc_spawnstaticsound except the sound index is 2 bytes.

Definitions[edit]

#define PROTOCOL_FITZQUAKE 666

//flags for entity update messages
#define U_EXTEND1       (1<<15) // another byte to follow
#define U_ALPHA         (1<<16) // 1 byte, uses ENTALPHA_ENCODE, not sent if equal to baseline
#define U_FRAME2        (1<<17) // 1 byte, this is .frame & 0xFF00 (second byte)
#define U_MODEL2        (1<<18) // 1 byte, this is .modelindex & 0xFF00 (second byte)
#define U_LERPFINISH    (1<<19) // 1 byte, 0.0-1.0 maps to 0-255, not sent if exactly 0.1, this is ent->v.nextthink - sv.time, used for lerping

//flags for client update messages
#define SU_EXTEND1      (1<<15) // another byte to follow
#define SU_WEAPON2      (1<<16) // 1 byte, this is .weaponmodel & 0xFF00 (second byte)
#define SU_ARMOR2       (1<<17) // 1 byte, this is .armorvalue & 0xFF00 (second byte)
#define SU_AMMO2        (1<<18) // 1 byte, this is .currentammo & 0xFF00 (second byte)
#define SU_SHELLS2      (1<<19) // 1 byte, this is .ammo_shells & 0xFF00 (second byte)
#define SU_NAILS2       (1<<20) // 1 byte, this is .ammo_nails & 0xFF00 (second byte)
#define SU_ROCKETS2     (1<<21) // 1 byte, this is .ammo_rockets & 0xFF00 (second byte)
#define SU_CELLS2       (1<<22) // 1 byte, this is .ammo_cells & 0xFF00 (second byte)
#define SU_EXTEND2      (1<<23) // another byte to follow
#define SU_WEAPONFRAME2 (1<<24) // 1 byte, this is .weaponframe & 0xFF00 (second byte)
#define SU_WEAPONALPHA  (1<<25) // 1 byte, this is alpha for weaponmodel, uses ENTALPHA_ENCODE, not sent if ENTALPHA_DEFAULT

//flags for sound messages
#define SND_LARGEENTITY (1<<3)  // a short + byte (instead of just a short)
#define SND_LARGESOUND  (1<<4)  // a short soundindex (instead of a byte)

//flags for entity baseline messages
#define B_LARGEMODEL    (1<<0)  // modelindex is short instead of byte
#define B_LARGEFRAME    (1<<1)  // frame is short instead of byte
#define B_ALPHA         (1<<2)  // 1 byte, uses ENTALPHA_ENCODE, not sent if ENTALPHA_DEFAULT

//new server messages
#define svc_spawnbaseline2      42  // support for large modelindex, large framenum, alpha, using flags
#define svc_spawnstatic2        43  // support for large modelindex, large framenum, alpha, using flags
#define svc_spawnstaticsound2   44  // [coord3] [short] samp [byte] vol [byte] aten

//alpha-related definitions and macros
#define ENTALPHA_DEFAULT    0   //entity's alpha is "default" (i.e. water obeys r_wateralpha) -- must be zero so zeroed out memory works
#define ENTALPHA_ZERO       1   //entity is invisible (lowest possible alpha)
#define ENTALPHA_ONE        255 //entity is fully opaque (highest possible alpha)
#define ENTALPHA_ENCODE(a)  (((a)==0)?ENTALPHA_DEFAULT:Q_rint(CLAMP(1,(a)*254.0f+1,255))) //server convert to byte to send to client
#define ENTALPHA_DECODE(a)  (((a)==ENTALPHA_DEFAULT)?1.0f:((float)(a)-1)/(254)) //client convert to float for rendering
#define ENTALPHA_TOSAVE(a)  (((a)==ENTALPHA_DEFAULT)?0.0f:(((a)==ENTALPHA_ZERO)?-1.0f:((float)(a)-1)/(254))) //server convert to float for savegame