X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=protocol.h;h=d594b03d2b49841335402b1a735ca76b95d74a97;hb=52b39606404e83bb166408f5e5eb6ea84bf027f8;hp=027871ee4fb25a87e220da964c17f1e231bdbaa7;hpb=8dcce44300385b12c46d494c06aadcfa35a8bc14;p=xonotic%2Fdarkplaces.git diff --git a/protocol.h b/protocol.h index 027871ee..d594b03d 100644 --- a/protocol.h +++ b/protocol.h @@ -8,7 +8,7 @@ of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. @@ -19,7 +19,17 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // protocol.h -- communications protocols -#define PROTOCOL_VERSION 15 +#ifndef PROTOCOL_H +#define PROTOCOL_H + +#define PROTOCOL_QUAKE 15 +#define PROTOCOL_NEHAHRAMOVIE 250 +#define PROTOCOL_DARKPLACES1 96 +#define PROTOCOL_DARKPLACES2 97 +// LordHavoc: I think the 96-99 range was going to run out too soon... +// so here I jump to 3500 +#define PROTOCOL_DARKPLACES3 3500 +#define PROTOCOL_DARKPLACES4 3501 // model effects #define EF_ROCKET 1 // leave a trail @@ -39,52 +49,58 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define EF_ADDITIVE 32 #define EF_BLUE 64 #define EF_RED 128 -#define EF_DELTA 8388608 // LordHavoc: entity is delta compressed to save network bandwidth +#define EF_DELTA 8388608 // LordHavoc: (obsolete) entity is delta compressed to save network bandwidth (no longer used) +#define EF_LOWPRECISION 4194304 // LordHavoc: entity is low precision (integer coordinates) to save network bandwidth // effects/model (can be used as model flags or entity effects) -#define EF_REFLECTIVE 256 // LordHavoc: shiny metal objects :) +#define EF_REFLECTIVE 256 // LordHavoc: shiny metal objects :) (not currently supported) #define EF_FULLBRIGHT 512 // LordHavoc: fullbright +#define EF_FLAME 1024 // LordHavoc: on fire +#define EF_STARDUST 2048 // LordHavoc: showering sparks +#define EF_NOSHADOW 4096 // LordHavoc: does not cast a shadow + +#define EF_STEP 0x80000000 // internal client use only - present on MOVETYPE_STEP entities, not QC accessible (too many bits) // if the high bit of the servercmd is set, the low bits are fast update flags: -#define U_MOREBITS (1<<0) -#define U_ORIGIN1 (1<<1) -#define U_ORIGIN2 (1<<2) -#define U_ORIGIN3 (1<<3) -#define U_ANGLE2 (1<<4) +#define U_MOREBITS (1<<0) +#define U_ORIGIN1 (1<<1) +#define U_ORIGIN2 (1<<2) +#define U_ORIGIN3 (1<<3) +#define U_ANGLE2 (1<<4) // LordHavoc: U_NOLERP was only ever used for monsters, so I renamed it U_STEP -#define U_STEP (1<<5) -#define U_FRAME (1<<6) +#define U_STEP (1<<5) +#define U_FRAME (1<<6) // just differentiates from other updates -#define U_SIGNAL (1<<7) +#define U_SIGNAL (1<<7) -// svc_update can pass all of the fast update bits, plus more -#define U_ANGLE1 (1<<8) -#define U_ANGLE3 (1<<9) -#define U_MODEL (1<<10) -#define U_COLORMAP (1<<11) -#define U_SKIN (1<<12) -#define U_EFFECTS (1<<13) -#define U_LONGENTITY (1<<14) +#define U_ANGLE1 (1<<8) +#define U_ANGLE3 (1<<9) +#define U_MODEL (1<<10) +#define U_COLORMAP (1<<11) +#define U_SKIN (1<<12) +#define U_EFFECTS (1<<13) +#define U_LONGENTITY (1<<14) // LordHavoc: protocol extension -#define U_EXTEND1 (1<<15) +#define U_EXTEND1 (1<<15) // LordHavoc: first extend byte -#define U_DELTA (1<<16) // no data, while this is set the entity is delta compressed (uses previous frame as a baseline, meaning only things that have changed from the previous frame are sent, except for the forced full update every half second) -#define U_ALPHA (1<<17) // 1 byte, 0.0-1.0 maps to 0-255, not sent if exactly 1, and the entity is not sent if <=0 unless it has effects (model effects are checked as well) -#define U_SCALE (1<<18) // 1 byte, scale / 16 positive, not sent if 1.0 -#define U_EFFECTS2 (1<<19) // 1 byte, this is .effects & 0xFF00 (second byte) -#define U_GLOWSIZE (1<<20) // 1 byte, encoding is float/8.0, signed (negative is darklight), not sent if 0 -#define U_GLOWCOLOR (1<<21) // 1 byte, palette index, default is 254 (white), this IS used for darklight (allowing colored darklight), however the particles from a darklight are always black, not sent if default value (even if glowsize or glowtrail is set) -#define U_COLORMOD (1<<22) // 1 byte, 3 bit red, 3 bit green, 2 bit blue, this lets you tint an object artifically, so you could make a red rocket, or a blue fiend... -#define U_EXTEND2 (1<<23) // another byte to follow +#define U_DELTA (1<<16) // no data, while this is set the entity is delta compressed (uses previous frame as a baseline, meaning only things that have changed from the previous frame are sent, except for the forced full update every half second) +#define U_ALPHA (1<<17) // 1 byte, 0.0-1.0 maps to 0-255, not sent if exactly 1, and the entity is not sent if <=0 unless it has effects (model effects are checked as well) +#define U_SCALE (1<<18) // 1 byte, scale / 16 positive, not sent if 1.0 +#define U_EFFECTS2 (1<<19) // 1 byte, this is .effects & 0xFF00 (second byte) +#define U_GLOWSIZE (1<<20) // 1 byte, encoding is float/8.0, signed (negative is darklight), not sent if 0 +#define U_GLOWCOLOR (1<<21) // 1 byte, palette index, default is 254 (white), this IS used for darklight (allowing colored darklight), however the particles from a darklight are always black, not sent if default value (even if glowsize or glowtrail is set) +// LordHavoc: colormod feature has been removed, because no one used it +#define U_COLORMOD (1<<22) // 1 byte, 3 bit red, 3 bit green, 2 bit blue, this lets you tint an object artifically, so you could make a red rocket, or a blue fiend... +#define U_EXTEND2 (1<<23) // another byte to follow // LordHavoc: second extend byte -#define U_GLOWTRAIL (1<<24) // leaves a trail of particles (of color .glowcolor, or black if it is a negative glowsize) -#define U_VIEWMODEL (1<<25) // attachs the model to the view (origin and angles become relative to it), only shown to owner, a more powerful alternative to .weaponmodel and such -#define U_FRAME2 (1<<26) // 1 byte, this is .frame & 0xFF00 (second byte) -#define U_UNUSED27 (1<<27) // future expansion -#define U_UNUSED28 (1<<28) // future expansion -#define U_UNUSED29 (1<<29) // future expansion -#define U_UNUSED30 (1<<30) // future expansion -#define U_EXTEND3 (1<<31) // another byte to follow, future expansion +#define U_GLOWTRAIL (1<<24) // leaves a trail of particles (of color .glowcolor, or black if it is a negative glowsize) +#define U_VIEWMODEL (1<<25) // attachs the model to the view (origin and angles become relative to it), only shown to owner, a more powerful alternative to .weaponmodel and such +#define U_FRAME2 (1<<26) // 1 byte, this is .frame & 0xFF00 (second byte) +#define U_MODEL2 (1<<27) // 1 byte, this is .modelindex & 0xFF00 (second byte) +#define U_EXTERIORMODEL (1<<28) // causes this model to not be drawn when using a first person view (third person will draw it, first person will not) +#define U_UNUSED29 (1<<29) // future expansion +#define U_UNUSED30 (1<<30) // future expansion +#define U_EXTEND3 (1<<31) // another byte to follow, future expansion #define SU_VIEWHEIGHT (1<<0) #define SU_IDEALPITCH (1<<1) @@ -101,11 +117,32 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define SU_WEAPONFRAME (1<<12) #define SU_ARMOR (1<<13) #define SU_WEAPON (1<<14) +#define SU_EXTEND1 (1<<15) +// first extend byte +#define SU_PUNCHVEC1 (1<<16) +#define SU_PUNCHVEC2 (1<<17) +#define SU_PUNCHVEC3 (1<<18) +#define SU_VIEWZOOM (1<<19) // byte factor (0 = 0.0 (not valid), 255 = 1.0) +#define SU_UNUSED20 (1<<20) +#define SU_UNUSED21 (1<<21) +#define SU_UNUSED22 (1<<22) +#define SU_EXTEND2 (1<<23) // another byte to follow, future expansion +// second extend byte +#define SU_UNUSED24 (1<<24) +#define SU_UNUSED25 (1<<25) +#define SU_UNUSED26 (1<<26) +#define SU_UNUSED27 (1<<27) +#define SU_UNUSED28 (1<<28) +#define SU_UNUSED29 (1<<29) +#define SU_UNUSED30 (1<<30) +#define SU_EXTEND3 (1<<31) // another byte to follow, future expansion // a sound with no channel is a local only sound #define SND_VOLUME (1<<0) // a byte #define SND_ATTENUATION (1<<1) // a byte #define SND_LOOPING (1<<2) // a long +#define SND_LARGEENTITY (1<<3) // a short and a byte (instead of a short) +#define SND_LARGESOUND (1<<4) // a short (instead of a byte) // defaults for clientinfo messages @@ -137,7 +174,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define svc_stufftext 9 // [string] stuffed into client's console buffer // the string should be \n terminated #define svc_setangle 10 // [angle3] set the view angle to this absolute value - + #define svc_serverinfo 11 // [long] version // [string] signon string // [string]..[0]model cache @@ -150,11 +187,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define svc_updatecolors 17 // [byte] [byte] #define svc_particle 18 // [vec3] #define svc_damage 19 - + #define svc_spawnstatic 20 // svc_spawnbinary 21 #define svc_spawnbaseline 22 - + #define svc_temp_entity 23 #define svc_setpause 24 // [byte] on / off @@ -175,12 +212,21 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define svc_cutscene 34 -#define svc_showlmp 35 // [string] slotname [string] lmpfilename [coord] x [coord] y +#define svc_showlmp 35 // [string] slotname [string] lmpfilename [short] x [short] y #define svc_hidelmp 36 // [string] slotname #define svc_skybox 37 // [string] skyname -#define svc_skyboxsize 50 // [coord] size (default is 4096) -#define svc_fog 51 // [byte] enable [float] density [byte] red [byte] green [byte] blue +// LordHavoc: my svc_ range, 50-59 +#define svc_cgame 50 // [short] length [bytes] data +#define svc_unusedlh1 51 +#define svc_effect 52 // [vector] org [byte] modelindex [byte] startframe [byte] framecount [byte] framerate +#define svc_effect2 53 // [vector] org [short] modelindex [short] startframe [byte] framecount [byte] framerate +#define svc_sound2 54 // short soundindex instead of byte +#define svc_spawnbaseline2 55 // short modelindex instead of byte +#define svc_spawnstatic2 56 // short modelindex instead of byte +#define svc_entities 57 // [int] deltaframe [int] thisframe [float vector] eye [variable length] entitydata +#define svc_unusedlh3 58 +#define svc_spawnstaticsound2 59 // [coord3] [short] samp [byte] vol [byte] aten // // client to server @@ -191,6 +237,17 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define clc_move 3 // [usercmd_t] #define clc_stringcmd 4 // [string] message +// LordHavoc: my clc_ range, 50-59 +#define clc_ackentities 50 // [int] framenumber +#define clc_unusedlh1 51 +#define clc_unusedlh2 52 +#define clc_unusedlh3 53 +#define clc_unusedlh4 54 +#define clc_unusedlh5 55 +#define clc_unusedlh6 56 +#define clc_unusedlh7 57 +#define clc_unusedlh8 58 +#define clc_unusedlh9 59 // // temp entity events @@ -209,9 +266,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define TE_TELEPORT 11 // [vector] origin #define TE_EXPLOSION2 12 // [vector] origin [byte] startcolor [byte] colorcount -// PGM 01/21/97 +// PGM 01/21/97 #define TE_BEAM 13 // [entity] entity [vector] start [vector] end -// PGM 01/21/97 +// PGM 01/21/97 // Nehahra effects used in the movie (TE_EXPLOSION3 also got written up in a QSG tutorial, hence it's not marked NEH) #define TE_EXPLOSION3 16 // [vector] origin [coord] red [coord] green [coord] blue @@ -230,3 +287,289 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define TE_SUPERSPIKEQUAD 59 // [vector] origin // LordHavoc: block2 - 70-80 #define TE_EXPLOSIONQUAD 70 // [vector] origin +#define TE_UNUSED1 71 // unused +#define TE_SMALLFLASH 72 // [vector] origin +#define TE_CUSTOMFLASH 73 // [vector] origin [byte] radius / 8 - 1 [byte] lifetime / 256 - 1 [byte] red [byte] green [byte] blue +#define TE_FLAMEJET 74 // [vector] origin [vector] velocity [byte] count +#define TE_PLASMABURN 75 // [vector] origin +// LordHavoc: Tei grabbed these codes +#define TE_TEI_G3 76 // [vector] start [vector] end [vector] angles +#define TE_TEI_SMOKE 77 // [vector] origin [vector] dir [byte] count +#define TE_TEI_BIGEXPLOSION 78 // [vector] origin +#define TE_TEI_PLASMAHIT 79 // [vector} origin [vector] dir [byte] count + + +// these are bits for the 'flags' field of the entity_state_t +#define RENDER_STEP 1 +#define RENDER_GLOWTRAIL 2 +#define RENDER_VIEWMODEL 4 +#define RENDER_EXTERIORMODEL 8 +#define RENDER_LOWPRECISION 16 // send as low precision coordinates to save bandwidth +#define RENDER_COLORMAPPED 32 +#define RENDER_SHADOW 64 // cast shadow + +typedef struct +{ + double time; // time this state was built + vec3_t origin; + vec3_t angles; + int number; // entity number this state is for + unsigned short active; // true if a valid state + unsigned short modelindex; + unsigned short frame; + unsigned short effects; + unsigned short tagentity; + unsigned short specialvisibilityradius; + unsigned short viewmodelforclient; + unsigned short exteriormodelforclient; + unsigned short nodrawtoclient; + unsigned short drawonlytoclient; + qbyte colormap; + qbyte skin; + qbyte alpha; + qbyte scale; + qbyte glowsize; + qbyte glowcolor; + qbyte flags; + qbyte tagindex; +} +entity_state_t; + +/* +PROTOCOL_DARKPLACES3 +server updates entities according to some (unmentioned) scheme. + +a frame consists of all visible entities, some of which are up to date, +often some are not up to date. + +these entities are stored in a range (firstentity/endentity) of structs in the +entitydata[] buffer. + +to make a commit the server performs these steps: +1. duplicate oldest frame in database (this is the baseline) as new frame, and + write frame numbers (oldest frame's number, new frame's number) and eye + location to network packet (eye location is obsolete and will be removed in + future revisions) +2. write an entity change to packet and modify new frame accordingly + (this repeats until packet is sufficiently full or new frame is complete) +3. write terminator (0xFFFF) to network packet + (FIXME: this terminator value conflicts with MAX_EDICTS 32768...) + +to read a commit the client performs these steps: +1. reads frame numbers from packet and duplicates baseline frame as new frame, + also reads eye location but does nothing with it (obsolete). +2. delete frames older than the baseline which was used +3. read entity changes from packet until terminator (0xFFFF) is encountered, + each change is applied to entity frame. +4. sends ack framenumber to server as part of input packet + +if server receives ack message in put packet it performs these steps: +1. remove all older frames from database. +*/ + +/* +PROTOCOL_DARKPLACES4 +a frame consists of some visible entities in a range (this is stored as start and end, note that end may be less than start if it wrapped). + +these entities are stored in a range (firstentity/endentity) of structs in the entitydata[] buffer. + +to make a commit the server performs these steps: +1. build an entity_frame_t using appropriate functions, containing (some of) the visible entities, this is passed to the Write function to send it. + +This documention is unfinished! +the Write function performs these steps: +1. check if entity frame is larger than MAX_ENTITYFRAME or is larger than available space in database, if so the baseline is defaults, otherwise it is the current baseline of the database. +2. write differences of an entity compared to selected baseline. +3. add entity to entity update in database. +4. if there are more entities to write and packet is not full, go back to step 2. +5. write terminator (0xFFFF) as entity number. +6. return. + + + + + +server updates entities in looping ranges, a frame consists of a range of visible entities (not always all visible entities), +*/ + +typedef struct +{ + double time; + int framenum; + int firstentity; // index into entitydata, modulo MAX_ENTITY_DATABASE + int endentity; // index into entitydata, firstentity + numentities +} +entity_frameinfo_t; + +#define MAX_ENTITY_HISTORY 64 +#define MAX_ENTITY_DATABASE (MAX_EDICTS * 2) + +typedef struct +{ + // note: these can be far out of range, modulo with MAX_ENTITY_DATABASE to get a valid range (which may wrap) + // start and end of used area, when adding a new update to database, store at endpos, and increment endpos + // when removing updates from database, nudge down frames array to only contain useful frames + // this logic should explain better: + // if (numframes >= MAX_ENTITY_HISTORY || (frames[numframes - 1].endentity - frames[0].firstentity) + entitiestoadd > MAX_ENTITY_DATABASE) + // flushdatabase(); + // note: if numframes == 0, insert at start (0 in entitydata) + // the only reason this system is used is to avoid copying memory when frames are removed + int numframes; + // server only: last acknowledged frame + int ackframe; + // the current state in the database + vec3_t eye; + // table of entities in the entityhistorydata + entity_frameinfo_t frames[MAX_ENTITY_HISTORY]; + // entities + entity_state_t entitydata[MAX_ENTITY_DATABASE]; +} +entity_database_t; + +// build entity data in this, to pass to entity read/write functions +typedef struct +{ + double time; + int framenum; + int numentities; + int firstentitynum; + int lastentitynum; + vec3_t eye; + entity_state_t entitydata[MAX_ENTITY_DATABASE]; +} +entity_frame_t; + +// LordHavoc: these are in approximately sorted order, according to cost and +// likelyhood of being used for numerous objects in a frame + +// note that the bytes are not written/read in this order, this is only the +// order of the bits to minimize overhead from extend bytes + +// enough to describe a nail, gib, shell casing, bullet hole, or rocket +#define E_ORIGIN1 (1<<0) +#define E_ORIGIN2 (1<<1) +#define E_ORIGIN3 (1<<2) +#define E_ANGLE1 (1<<3) +#define E_ANGLE2 (1<<4) +#define E_ANGLE3 (1<<5) +#define E_MODEL1 (1<<6) +#define E_EXTEND1 (1<<7) + +// enough to describe almost anything +#define E_FRAME1 (1<<8) +#define E_EFFECTS1 (1<<9) +#define E_ALPHA (1<<10) +#define E_SCALE (1<<11) +#define E_COLORMAP (1<<12) +#define E_SKIN (1<<13) +#define E_FLAGS (1<<14) +#define E_EXTEND2 (1<<15) + +// players, custom color glows, high model numbers +#define E_FRAME2 (1<<16) +#define E_MODEL2 (1<<17) +#define E_EFFECTS2 (1<<18) +#define E_GLOWSIZE (1<<19) +#define E_GLOWCOLOR (1<<20) +#define E_UNUSED1 (1<<21) +#define E_UNUSED2 (1<<22) +#define E_EXTEND3 (1<<23) + +#define E_SOUND1 (1<<24) +#define E_SOUNDVOL (1<<25) +#define E_SOUNDATTEN (1<<26) +#define E_TAGATTACHMENT (1<<27) +#define E_UNUSED5 (1<<28) +#define E_UNUSED6 (1<<29) +#define E_UNUSED7 (1<<30) +#define E_EXTEND4 (1<<31) + +// clears a state to baseline values +void ClearStateToDefault(entity_state_t *s); +// used by some of the DP protocols +void EntityState_Write(entity_state_t *ent, sizebuf_t *msg, entity_state_t *delta); + +// (server) clears the database to contain no frames (thus delta compression +// compresses against nothing) +void EntityFrame_ClearDatabase(entity_database_t *d); +// (server and client) removes frames older than 'frame' from database +void EntityFrame_AckFrame(entity_database_t *d, int frame); +// (server) clears frame, to prepare for adding entities +void EntityFrame_Clear(entity_frame_t *f, vec3_t eye, int framenum); +// (server) adds an entity to frame +void EntityFrame_AddEntity(entity_frame_t *f, entity_state_t *s); +// (server and client) reads a frame from the database +void EntityFrame_FetchFrame(entity_database_t *d, int framenum, entity_frame_t *f); +// (server and client) adds a entity_frame to the database, for future +// reference +void EntityFrame_AddFrame(entity_database_t *d, entity_frame_t *f); +// (server) writes a frame to network stream +void EntityFrame_Write(entity_database_t *d, entity_frame_t *f, sizebuf_t *msg); +// (client) reads a frame from network stream +void EntityFrame_Read(entity_database_t *d); +// (client) returns the frame number of the most recent frame recieved +int EntityFrame_MostRecentlyRecievedFrameNum(entity_database_t *d); + +typedef struct entity_database4_commit_s +{ + // frame number this commit represents + int framenum; + // number of entities in entity[] array + int numentities; + // maximum number of entities in entity[] array (dynamic resizing) + int maxentities; + entity_state_t *entity; +} +entity_database4_commit_t; + +typedef struct entity_database4_s +{ + // what mempool to use for allocations + mempool_t *mempool; + // reference frame + int referenceframenum; + // reference entities array is resized according to demand + int maxreferenceentities; + // array of states for entities, these are indexable by their entity number (yes there are gaps) + entity_state_t *referenceentity; + // commits waiting to be applied to the reference database when confirmed + // (commit[i]->numentities == 0 means it is empty) + entity_database4_commit_t commit[MAX_ENTITY_HISTORY]; + // (server only) the current commit being worked on + entity_database4_commit_t *currentcommit; + // (server only) if a commit won't fit entirely, continue where it left + // off next frame + int currententitynumber; + // (client only) most recently received frame number to be sent in next + // input update + int ackframenum; +} +entity_database4_t; + +// should-be-private functions that aren't +int EntityFrame4_SV_ChooseCommitToReplace(entity_database4_t *d); +entity_state_t *EntityFrame4_GetReferenceEntity(entity_database4_t *d, int number); +void EntityFrame4_AddCommitEntity(entity_database4_t *d, entity_state_t *s); + +// allocate a database +entity_database4_t *EntityFrame4_AllocDatabase(mempool_t *pool); +// free a database +void EntityFrame4_FreeDatabase(entity_database4_t *d); +// reset a database (resets compression but does not reallocate anything) +void EntityFrame4_ResetDatabase(entity_database4_t *d); +// updates database to account for a frame-received acknowledgment +void EntityFrame4_AckFrame(entity_database4_t *d, int framenum); + +// begin writing a frame +void EntityFrame4_SV_WriteFrame_Begin(entity_database4_t *d, sizebuf_t *msg, int framenum); +// write an entity in the frame +// returns false if full +int EntityFrame4_SV_WriteFrame_Entity(entity_database4_t *d, sizebuf_t *msg, int maxbytes, entity_state_t *s); +// end writing a frame +void EntityFrame4_SV_WriteFrame_End(entity_database4_t *d, sizebuf_t *msg); + +// reads a frame from the network stream +void EntityFrame4_CL_ReadFrame(entity_database4_t *d); + +#endif +