]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - protocol.c
Add cvar snd_cdautopause: optional CD track pause during game pause
[xonotic/darkplaces.git] / protocol.c
index c212757163f7636203fd108f12d4307e3f771a14..837ad97bed27445f804927f334b6b94440882747 100644 (file)
-
 #include "quakedef.h"
 
-void ClearStateToDefault(entity_state_t *s)
+// this is 88 bytes (must match entity_state_t in protocol.h)
+entity_state_t defaultstate =
+{
+       // ! means this is not sent to client
+       0,//double time; // ! time this state was built (used on client for interpolation)
+       {0,0,0},//float netcenter[3]; // ! for network prioritization, this is the center of the bounding box (which may differ from the origin)
+       {0,0,0},//float origin[3];
+       {0,0,0},//float angles[3];
+       0,//int effects;
+       0,//unsigned int customizeentityforclient; // !
+       0,//unsigned short number; // entity number this state is for
+       0,//unsigned short modelindex;
+       0,//unsigned short frame;
+       0,//unsigned short tagentity;
+       0,//unsigned short specialvisibilityradius; // ! larger if it has effects/light
+       0,//unsigned short viewmodelforclient; // !
+       0,//unsigned short exteriormodelforclient; // ! not shown if first person viewing from this entity, shown in all other cases
+       0,//unsigned short nodrawtoclient; // !
+       0,//unsigned short drawonlytoclient; // !
+       0,//unsigned short traileffectnum;
+       {0,0,0,0},//unsigned short light[4]; // color*256 (0.00 to 255.996), and radius*1
+       ACTIVE_NOT,//unsigned char active; // true if a valid state
+       0,//unsigned char lightstyle;
+       0,//unsigned char lightpflags;
+       0,//unsigned char colormap;
+       0,//unsigned char skin; // also chooses cubemap for rtlights if lightpflags & LIGHTPFLAGS_FULLDYNAMIC
+       255,//unsigned char alpha;
+       16,//unsigned char scale;
+       0,//unsigned char glowsize;
+       254,//unsigned char glowcolor;
+       0,//unsigned char flags;
+       0,//unsigned char internaleffects; // INTEF_FLAG1QW and so on
+       0,//unsigned char tagindex;
+       {32, 32, 32},//unsigned char colormod[3];
+       {32, 32, 32},//unsigned char glowmod[3];
+};
+
+// LadyHavoc: I own protocol ranges 96, 97, 3500-3599
+
+struct protocolversioninfo_s
 {
-       s->time = 0;
-       VectorClear(s->origin);
-       VectorClear(s->angles);
-       s->effects = 0;
-       s->modelindex = 0;
-       s->frame = 0;
-       s->colormap = 0;
-       s->skin = 0;
-       s->alpha = 255;
-       s->scale = 16;
-       s->glowsize = 0;
-       s->glowcolor = 254;
-       s->flags = 0;
-       s->active = 0;
+       int number;
+       protocolversion_t version;
+       const char *name;
 }
+protocolversioninfo[] =
+{
+       { 3505, PROTOCOL_DARKPLACES8 , "DP8"},
+       { 3504, PROTOCOL_DARKPLACES7 , "DP7"},
+       { 3503, PROTOCOL_DARKPLACES6 , "DP6"},
+       { 3502, PROTOCOL_DARKPLACES5 , "DP5"},
+       { 3501, PROTOCOL_DARKPLACES4 , "DP4"},
+       { 3500, PROTOCOL_DARKPLACES3 , "DP3"},
+       {   97, PROTOCOL_DARKPLACES2 , "DP2"},
+       {   96, PROTOCOL_DARKPLACES1 , "DP1"},
+       {   15, PROTOCOL_QUAKEDP     , "QUAKEDP"},
+       {   15, PROTOCOL_QUAKE       , "QUAKE"},
+       {   28, PROTOCOL_QUAKEWORLD  , "QW"},
+       {  250, PROTOCOL_NEHAHRAMOVIE, "NEHAHRAMOVIE"},
+       {10000, PROTOCOL_NEHAHRABJP  , "NEHAHRABJP"},
+       {10001, PROTOCOL_NEHAHRABJP2 , "NEHAHRABJP2"},
+       {10002, PROTOCOL_NEHAHRABJP3 , "NEHAHRABJP3"},
+       {    0, PROTOCOL_UNKNOWN     , NULL}
+};
 
-// (server) clears the database to contain no frames (thus delta compression compresses against nothing)
-void EntityFrame_ClearDatabase(entity_database_t *d)
+protocolversion_t Protocol_EnumForName(const char *s)
 {
-       memset(d, 0, sizeof(*d));
-       d->ackframe = -1;
+       int i;
+       for (i = 0;protocolversioninfo[i].name;i++)
+               if (!strcasecmp(s, protocolversioninfo[i].name))
+                       return protocolversioninfo[i].version;
+       return PROTOCOL_UNKNOWN;
 }
 
-// (server) acknowledge a frame as recieved by client (removes old frames from database, will use this new frame for delta compression)
-void EntityFrame_AckFrame(entity_database_t *d, int frame)
+const char *Protocol_NameForEnum(protocolversion_t p)
 {
+       int i;
+       for (i = 0;protocolversioninfo[i].name;i++)
+               if (protocolversioninfo[i].version == p)
+                       return protocolversioninfo[i].name;
+       return "UNKNOWN";
 }
 
-// (server) clears frame, to prepare for adding entities
-void EntityFrame_Clear(entity_frame_t *f)
+protocolversion_t Protocol_EnumForNumber(int n)
 {
-       memset(f, 0, sizeof(*f));
+       int i;
+       for (i = 0;protocolversioninfo[i].name;i++)
+               if (protocolversioninfo[i].number == n)
+                       return protocolversioninfo[i].version;
+       return PROTOCOL_UNKNOWN;
 }
 
-// (server) allocates an entity slot in frame, returns NULL if full
-entity_state_t *EntityFrame_NewEntity(entity_frame_t *f, int number)
+int Protocol_NumberForEnum(protocolversion_t p)
 {
-       entity_state_t *e;
-       if (f->numentities >= MAX_ENTITY_DATABASE)
-               return NULL;
-       e = &f->entitydata[f->numentities++];
-       e->active = true;
-       e->number = number;
-       return e;
+       int i;
+       for (i = 0;protocolversioninfo[i].name;i++)
+               if (protocolversioninfo[i].version == p)
+                       return protocolversioninfo[i].number;
+       return 0;
 }
 
-// (server) writes a frame to network stream
-void EntityFrame_Write(entity_database_t *d, entity_frame_t *f, int deltaframe, int newframe, sizebuf_t *msg)
+void Protocol_Names(char *buffer, size_t buffersize)
 {
+       int i;
+       if (buffersize < 1)
+               return;
+       buffer[0] = 0;
+       for (i = 0;protocolversioninfo[i].name;i++)
+       {
+               if (i > 0)
+                       strlcat(buffer, " ", buffersize);
+               strlcat(buffer, protocolversioninfo[i].name, buffersize);
+       }
 }
 
-// (client) reads a frame from network stream
-void EntityFrame_Read(entity_database_t *d, entity_frame_t *f)
+void Protocol_UpdateClientStats(const int *stats)
 {
+       int i;
+       // update the stats array and set deltabits for any changed stats
+       for (i = 0;i < MAX_CL_STATS;i++)
+       {
+               if (host_client->stats[i] != stats[i])
+               {
+                       host_client->statsdeltabits[i >> 3] |= 1 << (i & 7);
+                       host_client->stats[i] = stats[i];
+               }
+       }
 }
 
-// (client) fetchs an entity from the database, read with _Read, fills in structs for current and previous state
-void EntityFrame_FetchEntity(entity_database_t *d, entity_state_t *previous, entity_state_t *current)
+// only a few stats are within the 32 stat limit of Quake, and most of them
+// are sent every frame in svc_clientdata messages, so we only send the
+// remaining ones here
+static const int sendquakestats[] =
+{
+// quake did not send these secrets/monsters stats in this way, but doing so
+// allows a mod to increase STAT_TOTALMONSTERS during the game, and ensures
+// that STAT_SECRETS and STAT_MONSTERS are always correct (even if a client
+// didn't receive an svc_foundsecret or svc_killedmonster), which may be most
+// valuable if randomly seeking around in a demo
+STAT_TOTALSECRETS, // never changes during game
+STAT_TOTALMONSTERS, // changes in some mods
+STAT_SECRETS, // this makes svc_foundsecret unnecessary
+STAT_MONSTERS, // this makes svc_killedmonster unnecessary
+STAT_VIEWHEIGHT, // sent just for FTEQW clients
+STAT_VIEWZOOM, // this rarely changes
+-1,
+};
+
+void Protocol_WriteStatsReliable(void)
 {
+       int i, j;
+       if (!host_client->netconnection)
+               return;
+       // detect changes in stats and write reliable messages
+       // this only deals with 32 stats because the older protocols which use
+       // this function can only cope with 32 stats,
+       // they also do not support svc_updatestatubyte which was introduced in
+       // DP6 protocol (except for QW)
+       for (j = 0;sendquakestats[j] >= 0;j++)
+       {
+               i = sendquakestats[j];
+               // check if this bit is set
+               if (host_client->statsdeltabits[i >> 3] & (1 << (i & 7)))
+               {
+                       host_client->statsdeltabits[i >> 3] -= (1 << (i & 7));
+                       // send the stat as a byte if possible
+                       if (sv.protocol == PROTOCOL_QUAKEWORLD)
+                       {
+                               if (host_client->stats[i] >= 0 && host_client->stats[i] < 256)
+                               {
+                                       MSG_WriteByte(&host_client->netconnection->message, qw_svc_updatestat);
+                                       MSG_WriteByte(&host_client->netconnection->message, i);
+                                       MSG_WriteByte(&host_client->netconnection->message, host_client->stats[i]);
+                               }
+                               else
+                               {
+                                       MSG_WriteByte(&host_client->netconnection->message, qw_svc_updatestatlong);
+                                       MSG_WriteByte(&host_client->netconnection->message, i);
+                                       MSG_WriteLong(&host_client->netconnection->message, host_client->stats[i]);
+                               }
+                       }
+                       else
+                       {
+                               // this could make use of svc_updatestatubyte in DP6 and later
+                               // protocols but those protocols do not use this function
+                               MSG_WriteByte(&host_client->netconnection->message, svc_updatestat);
+                               MSG_WriteByte(&host_client->netconnection->message, i);
+                               MSG_WriteLong(&host_client->netconnection->message, host_client->stats[i]);
+                       }
+               }
+       }
 }