From: havoc Date: Tue, 14 Sep 2004 22:41:10 +0000 (+0000) Subject: PROTOCOL_DARKPLACES5 X-Git-Tag: xonotic-v0.1.0preview~5605 X-Git-Url: http://git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=commitdiff_plain;h=435b52972823fa8e8ceb9b67797ca3f886f6208a PROTOCOL_DARKPLACES5 git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@4499 d7cf8633-e32d-0410-b094-e92efae38249 --- diff --git a/cgamevm.c b/cgamevm.c index 31881975..277c7eb0 100644 --- a/cgamevm.c +++ b/cgamevm.c @@ -87,7 +87,7 @@ unsigned char CGVM_MSG_ReadByte(void) short CGVM_MSG_ReadShort(void) { - int num; + short num; num = CGVM_MSG_ReadByte() | (CGVM_MSG_ReadByte() << 8); return num; } diff --git a/cl_demo.c b/cl_demo.c index be9bf40d..2b7f060b 100644 --- a/cl_demo.c +++ b/cl_demo.c @@ -42,7 +42,6 @@ CL_NextDemo Called to play the next demo in the demo loop ===================== */ -extern void Call_MR_ToggleMenu_f (void); void CL_NextDemo (void) { char str[1024]; @@ -57,9 +56,6 @@ void CL_NextDemo (void) { Con_Print("No demos listed with startdemos\n"); cls.demonum = -1; - // put up menu instead of staring at console - if (key_dest != key_menu) - Call_MR_ToggleMenu_f(); return; } } diff --git a/cl_input.c b/cl_input.c index e3d964d8..f8593c2e 100644 --- a/cl_input.c +++ b/cl_input.c @@ -385,38 +385,33 @@ void CL_SendMove(usercmd_t *cmd) MSG_WriteFloat (&buf, cl.mtime[0]); // so server can get ping times - if (cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3) + if (cl.protocol == PROTOCOL_QUAKE) { for (i = 0;i < 3;i++) - MSG_WriteFloat (&buf, cl.viewangles[i]); + MSG_WriteAngle8i (&buf, cl.viewangles[i]); } - else if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5) + else if (cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3) { - for (i=0 ; i<3 ; i++) - MSG_WritePreciseAngle (&buf, cl.viewangles[i]); + for (i = 0;i < 3;i++) + MSG_WriteAngle32f (&buf, cl.viewangles[i]); } - else + else if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5) { - for (i=0 ; i<3 ; i++) - MSG_WriteAngle (&buf, cl.viewangles[i]); + for (i = 0;i < 3;i++) + MSG_WriteAngle16i (&buf, cl.viewangles[i]); } - MSG_WriteShort (&buf, forwardmove); - MSG_WriteShort (&buf, sidemove); - MSG_WriteShort (&buf, upmove); + MSG_WriteCoord16i (&buf, forwardmove); + MSG_WriteCoord16i (&buf, sidemove); + MSG_WriteCoord16i (&buf, upmove); forwardmove = sidemove = upmove = 0; // send button bits bits = 0; - if ( in_attack.state & 3 ) - bits |= 1; - in_attack.state &= ~2; - - if (in_jump.state & 3) - bits |= 2; - in_jump.state &= ~2; // LordHavoc: added 6 new buttons + if (in_attack.state & 3) bits |= 1;in_attack.state &= ~2; + if (in_jump.state & 3) bits |= 2;in_jump.state &= ~2; if (in_button3.state & 3) bits |= 4;in_button3.state &= ~2; if (in_button4.state & 3) bits |= 8;in_button4.state &= ~2; if (in_button5.state & 3) bits |= 16;in_button5.state &= ~2; @@ -432,14 +427,17 @@ void CL_SendMove(usercmd_t *cmd) if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3) { // LordHavoc: should we ack this on receipt instead? would waste net bandwidth though - i = EntityFrame_MostRecentlyRecievedFrameNum(&cl.entitydatabase); - if (i > 0) + if (cl.entitydatabase) { - MSG_WriteByte(&buf, clc_ackentities); - MSG_WriteLong(&buf, i); + i = EntityFrame_MostRecentlyRecievedFrameNum(cl.entitydatabase); + if (i > 0) + { + MSG_WriteByte(&buf, clc_ackentities); + MSG_WriteLong(&buf, i); + } } } - else + else if (cl.protocol == PROTOCOL_DARKPLACES4) { if (cl.entitydatabase4) { @@ -452,6 +450,16 @@ void CL_SendMove(usercmd_t *cmd) MSG_WriteLong(&buf, i); } } + else if (cl.protocol == PROTOCOL_DARKPLACES5) + { + i = cl.latestframenum; + if (cl_nodelta.integer) + i = -1; + if (developer_networkentities.integer >= 1) + Con_Printf("send clc_ackentities %i\n", i); + MSG_WriteByte(&buf, clc_ackentities); + MSG_WriteLong(&buf, i); + } // deliver the message if (cls.demoplayback) diff --git a/cl_main.c b/cl_main.c index 86a7e895..1006559d 100644 --- a/cl_main.c +++ b/cl_main.c @@ -145,9 +145,9 @@ void CL_ClearState(void) // LordHavoc: have to set up the baseline info for alpha and other stuff for (i = 0;i < cl_max_entities;i++) { - ClearStateToDefault(&cl_entities[i].state_baseline); - ClearStateToDefault(&cl_entities[i].state_previous); - ClearStateToDefault(&cl_entities[i].state_current); + cl_entities[i].state_baseline = defaultstate; + cl_entities[i].state_previous = defaultstate; + cl_entities[i].state_current = defaultstate; } CL_CGVM_Clear(); @@ -904,7 +904,7 @@ static void CL_RelinkNetworkEntities(void) ent = &cl.viewent; ent->state_previous = ent->state_current; - ClearStateToDefault(&ent->state_current); + ent->state_current = defaultstate; ent->state_current.time = cl.time; ent->state_current.number = -1; ent->state_current.active = true; diff --git a/cl_parse.c b/cl_parse.c index fae79068..e92bb5fb 100644 --- a/cl_parse.c +++ b/cl_parse.c @@ -150,7 +150,7 @@ void CL_ParseStartSoundPacket(int largesoundindex) if (ent >= MAX_EDICTS) Host_Error ("CL_ParseStartSoundPacket: ent = %i", ent); - MSG_ReadVector(pos); + MSG_ReadVector(pos, cl.protocol); S_StartSound (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0, attenuation); } @@ -312,7 +312,6 @@ Con_DPrintf("CL_SignonReply: %i\n", cls.signon); CL_ParseServerInfo ================== */ -qbyte entlife[MAX_EDICTS]; // FIXME: this is a lot of memory to be keeping around, this needs to be dynamically allocated and freed static char parse_model_precache[MAX_MODELS][MAX_QPATH]; static char parse_sound_precache[MAX_SOUNDS][MAX_QPATH]; @@ -449,8 +448,6 @@ void CL_ParseServerInfo (void) Matrix4x4_CreateFromQuakeEntity(&ent->render.matrix, 0, 0, 0, 0, 0, 0, 1); Matrix4x4_Invert_Simple(&ent->render.inversematrix, &ent->render.matrix); CL_BoundingBoxForEntity(&ent->render); - // clear entlife array - memset(entlife, 0, MAX_EDICTS); cl_num_entities = 1; @@ -498,6 +495,7 @@ void CL_ValidateState(entity_state_t *s) void CL_MoveLerpEntityStates(entity_t *ent) { float odelta[3], adelta[3]; + CL_ValidateState(&ent->state_current); VectorSubtract(ent->state_current.origin, ent->persistent.neworigin, odelta); VectorSubtract(ent->state_current.angles, ent->persistent.newangles, adelta); if (!ent->state_previous.active || cls.timedemo || DotProduct(odelta, odelta) > 1000*1000 || cl_nolerp.integer) @@ -539,168 +537,14 @@ void CL_MoveLerpEntityStates(entity_t *ent) } } -/* -================== -CL_ParseUpdate - -Parse an entity update message from the server -If an entities model or origin changes from frame to frame, it must be -relinked. Other attributes can change without relinking. -================== -*/ -void CL_ParseUpdate (int bits) -{ - int num; - entity_t *ent; - entity_state_t new; - - if (bits & U_MOREBITS) - bits |= (MSG_ReadByte()<<8); - if ((bits & U_EXTEND1) && cl.protocol != PROTOCOL_NEHAHRAMOVIE) - { - bits |= MSG_ReadByte() << 16; - if (bits & U_EXTEND2) - bits |= MSG_ReadByte() << 24; - } - - if (bits & U_LONGENTITY) - num = (unsigned) MSG_ReadShort (); - else - num = (unsigned) MSG_ReadByte (); - - if (num >= MAX_EDICTS) - Host_Error("CL_ParseUpdate: entity number (%i) >= MAX_EDICTS (%i)\n", num, MAX_EDICTS); - if (num < 1) - Host_Error("CL_ParseUpdate: invalid entity number (%i)\n", num); - - ent = cl_entities + num; - - // note: this inherits the 'active' state of the baseline chosen - // (state_baseline is always active, state_current may not be active if - // the entity was missing in the last frame) - if (bits & U_DELTA) - new = ent->state_current; - else - { - new = ent->state_baseline; - new.active = true; - } - - new.number = num; - new.time = cl.mtime[0]; - new.flags = 0; - if (bits & U_MODEL) new.modelindex = (new.modelindex & 0xFF00) | MSG_ReadByte(); - if (bits & U_FRAME) new.frame = (new.frame & 0xFF00) | MSG_ReadByte(); - if (bits & U_COLORMAP) new.colormap = MSG_ReadByte(); - if (bits & U_SKIN) new.skin = MSG_ReadByte(); - if (bits & U_EFFECTS) new.effects = (new.effects & 0xFF00) | MSG_ReadByte(); - if (bits & U_ORIGIN1) new.origin[0] = MSG_ReadCoord(); - if (bits & U_ANGLE1) new.angles[0] = MSG_ReadAngle(); - if (bits & U_ORIGIN2) new.origin[1] = MSG_ReadCoord(); - if (bits & U_ANGLE2) new.angles[1] = MSG_ReadAngle(); - if (bits & U_ORIGIN3) new.origin[2] = MSG_ReadCoord(); - if (bits & U_ANGLE3) new.angles[2] = MSG_ReadAngle(); - if (bits & U_STEP) new.flags |= RENDER_STEP; - if (bits & U_ALPHA) new.alpha = MSG_ReadByte(); - if (bits & U_SCALE) new.scale = MSG_ReadByte(); - if (bits & U_EFFECTS2) new.effects = (new.effects & 0x00FF) | (MSG_ReadByte() << 8); - if (bits & U_GLOWSIZE) new.glowsize = MSG_ReadByte(); - if (bits & U_GLOWCOLOR) new.glowcolor = MSG_ReadByte(); - // apparently the dpcrush demo uses this (unintended, and it uses white anyway) - if (bits & U_COLORMOD) MSG_ReadByte(); - if (bits & U_GLOWTRAIL) new.flags |= RENDER_GLOWTRAIL; - if (bits & U_FRAME2) new.frame = (new.frame & 0x00FF) | (MSG_ReadByte() << 8); - if (bits & U_MODEL2) new.modelindex = (new.modelindex & 0x00FF) | (MSG_ReadByte() << 8); - if (bits & U_VIEWMODEL) new.flags |= RENDER_VIEWMODEL; - if (bits & U_EXTERIORMODEL) new.flags |= RENDER_EXTERIORMODEL; - - // LordHavoc: to allow playback of the Nehahra movie - if (cl.protocol == PROTOCOL_NEHAHRAMOVIE && (bits & U_EXTEND1)) - { - // LordHavoc: evil format - int i = MSG_ReadFloat(); - int j = MSG_ReadFloat() * 255.0f; - if (i == 2) - { - i = MSG_ReadFloat(); - if (i) - new.effects |= EF_FULLBRIGHT; - } - if (j < 0) - new.alpha = 0; - else if (j == 0 || j >= 255) - new.alpha = 255; - else - new.alpha = j; - } - - if (new.active) - CL_ValidateState(&new); - - ent->state_previous = ent->state_current; - ent->state_current = new; - if (ent->state_current.active) - { - CL_MoveLerpEntityStates(ent); - cl_entities_active[ent->state_current.number] = true; - // mark as visible (no kill this frame) - entlife[ent->state_current.number] = 2; - } -} - -static entity_frame_t entityframe; -extern mempool_t *cl_entities_mempool; void CL_ReadEntityFrame(void) { if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3) - { - int i; - entity_t *ent; - EntityFrame_Read(&cl.entitydatabase); - EntityFrame_FetchFrame(&cl.entitydatabase, EntityFrame_MostRecentlyRecievedFrameNum(&cl.entitydatabase), &entityframe); - for (i = 0;i < entityframe.numentities;i++) - { - // copy the states - ent = &cl_entities[entityframe.entitydata[i].number]; - ent->state_previous = ent->state_current; - ent->state_current = entityframe.entitydata[i]; - CL_MoveLerpEntityStates(ent); - // the entity lives again... - entlife[ent->state_current.number] = 2; - cl_entities_active[ent->state_current.number] = true; - } - } - else - { - if (!cl.entitydatabase4) - cl.entitydatabase4 = EntityFrame4_AllocDatabase(cl_entities_mempool); - EntityFrame4_CL_ReadFrame(cl.entitydatabase4); - } -} - -void CL_EntityUpdateSetup(void) -{ -} - -void CL_EntityUpdateEnd(void) -{ - if (cl.protocol == PROTOCOL_QUAKE || cl.protocol == PROTOCOL_NEHAHRAMOVIE || cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3) - { - int i; - // disable entities that disappeared this frame - for (i = 1;i < MAX_EDICTS;i++) - { - // clear only the entities that were active last frame but not this - // frame, don't waste time clearing all entities (which would cause - // cache misses) - if (entlife[i]) - { - entlife[i]--; - if (!entlife[i]) - cl_entities[i].state_previous.active = cl_entities[i].state_current.active = 0; - } - } - } + EntityFrame_CL_ReadFrame(); + else if (cl.protocol == PROTOCOL_DARKPLACES4) + EntityFrame4_CL_ReadFrame(); + else if (cl.protocol == PROTOCOL_DARKPLACES5) + EntityFrame5_CL_ReadFrame(); } /* @@ -712,7 +556,8 @@ void CL_ParseBaseline (entity_t *ent, int large) { int i; - ClearStateToDefault(&ent->state_baseline); + ent->state_baseline = defaultstate; + // FIXME: set ent->state_baseline.number? ent->state_baseline.active = true; if (large) { @@ -728,8 +573,8 @@ void CL_ParseBaseline (entity_t *ent, int large) ent->state_baseline.skin = MSG_ReadByte(); for (i = 0;i < 3;i++) { - ent->state_baseline.origin[i] = MSG_ReadCoord (); - ent->state_baseline.angles[i] = MSG_ReadAngle (); + ent->state_baseline.origin[i] = MSG_ReadCoord(cl.protocol); + ent->state_baseline.angles[i] = MSG_ReadAngle8i(); } CL_ValidateState(&ent->state_baseline); ent->state_previous = ent->state_current = ent->state_baseline; @@ -764,46 +609,41 @@ void CL_ParseClientdata (int bits) cl.idealpitch = 0; VectorCopy (cl.mvelocity[0], cl.mvelocity[1]); - if (cl.protocol == PROTOCOL_DARKPLACES5) + for (i = 0;i < 3;i++) { - for (i = 0;i < 3;i++) + if (bits & (SU_PUNCH1<= MAX_EDICTS) { @@ -1037,7 +904,7 @@ void CL_ParseTempEntity(void) { case TE_WIZSPIKE: // spike hitting wall - MSG_ReadVector(pos); + MSG_ReadVector(pos, cl.protocol); CL_FindNonSolidLocation(pos, pos, 4); Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]); CL_AllocDlight(NULL, &tempmatrix, 100, 0.12f, 0.50f, 0.12f, 500, 0.2, 0, 0, false, 1); @@ -1047,7 +914,7 @@ void CL_ParseTempEntity(void) case TE_KNIGHTSPIKE: // spike hitting wall - MSG_ReadVector(pos); + MSG_ReadVector(pos, cl.protocol); CL_FindNonSolidLocation(pos, pos, 4); Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]); CL_AllocDlight(NULL, &tempmatrix, 100, 0.50f, 0.30f, 0.10f, 500, 0.2, 0, 0, false, 1); @@ -1057,7 +924,7 @@ void CL_ParseTempEntity(void) case TE_SPIKE: // spike hitting wall - MSG_ReadVector(pos); + MSG_ReadVector(pos, cl.protocol); CL_FindNonSolidLocation(pos, pos, 4); // LordHavoc: changed to spark shower CL_SparkShower(pos, vec3_origin, 15); @@ -1076,7 +943,7 @@ void CL_ParseTempEntity(void) break; case TE_SPIKEQUAD: // quad spike hitting wall - MSG_ReadVector(pos); + MSG_ReadVector(pos, cl.protocol); CL_FindNonSolidLocation(pos, pos, 4); // LordHavoc: changed to spark shower CL_SparkShower(pos, vec3_origin, 15); @@ -1098,7 +965,7 @@ void CL_ParseTempEntity(void) break; case TE_SUPERSPIKE: // super spike hitting wall - MSG_ReadVector(pos); + MSG_ReadVector(pos, cl.protocol); CL_FindNonSolidLocation(pos, pos, 4); // LordHavoc: changed to dust shower CL_SparkShower(pos, vec3_origin, 30); @@ -1117,7 +984,7 @@ void CL_ParseTempEntity(void) break; case TE_SUPERSPIKEQUAD: // quad super spike hitting wall - MSG_ReadVector(pos); + MSG_ReadVector(pos, cl.protocol); CL_FindNonSolidLocation(pos, pos, 4); // LordHavoc: changed to dust shower CL_SparkShower(pos, vec3_origin, 30); @@ -1139,7 +1006,7 @@ void CL_ParseTempEntity(void) // LordHavoc: added for improved blood splatters case TE_BLOOD: // blood puff - MSG_ReadVector(pos); + MSG_ReadVector(pos, cl.protocol); CL_FindNonSolidLocation(pos, pos, 4); dir[0] = MSG_ReadChar(); dir[1] = MSG_ReadChar(); @@ -1149,7 +1016,7 @@ void CL_ParseTempEntity(void) break; case TE_SPARK: // spark shower - MSG_ReadVector(pos); + MSG_ReadVector(pos, cl.protocol); CL_FindNonSolidLocation(pos, pos, 4); dir[0] = MSG_ReadChar(); dir[1] = MSG_ReadChar(); @@ -1158,7 +1025,7 @@ void CL_ParseTempEntity(void) CL_SparkShower(pos, dir, count); break; case TE_PLASMABURN: - MSG_ReadVector(pos); + MSG_ReadVector(pos, cl.protocol); CL_FindNonSolidLocation(pos, pos, 4); Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]); CL_AllocDlight(NULL, &tempmatrix, 200, 1, 1, 1, 1000, 0.2, 0, 0, true, 1); @@ -1167,47 +1034,47 @@ void CL_ParseTempEntity(void) // LordHavoc: added for improved gore case TE_BLOODSHOWER: // vaporized body - MSG_ReadVector(pos); // mins - MSG_ReadVector(pos2); // maxs - velspeed = MSG_ReadCoord(); // speed - count = MSG_ReadShort(); // number of particles + MSG_ReadVector(pos, cl.protocol); // mins + MSG_ReadVector(pos2, cl.protocol); // maxs + velspeed = MSG_ReadCoord(cl.protocol); // speed + count = (unsigned short) MSG_ReadShort(); // number of particles CL_BloodShower(pos, pos2, velspeed, count); break; case TE_PARTICLECUBE: // general purpose particle effect - MSG_ReadVector(pos); // mins - MSG_ReadVector(pos2); // maxs - MSG_ReadVector(dir); // dir - count = MSG_ReadShort(); // number of particles + MSG_ReadVector(pos, cl.protocol); // mins + MSG_ReadVector(pos2, cl.protocol); // maxs + MSG_ReadVector(dir, cl.protocol); // dir + count = (unsigned short) MSG_ReadShort(); // number of particles colorStart = MSG_ReadByte(); // color colorLength = MSG_ReadByte(); // gravity (1 or 0) - velspeed = MSG_ReadCoord(); // randomvel + velspeed = MSG_ReadCoord(cl.protocol); // randomvel CL_ParticleCube(pos, pos2, dir, count, colorStart, colorLength, velspeed); break; case TE_PARTICLERAIN: // general purpose particle effect - MSG_ReadVector(pos); // mins - MSG_ReadVector(pos2); // maxs - MSG_ReadVector(dir); // dir - count = MSG_ReadShort(); // number of particles + MSG_ReadVector(pos, cl.protocol); // mins + MSG_ReadVector(pos2, cl.protocol); // maxs + MSG_ReadVector(dir, cl.protocol); // dir + count = (unsigned short) MSG_ReadShort(); // number of particles colorStart = MSG_ReadByte(); // color CL_ParticleRain(pos, pos2, dir, count, colorStart, 0); break; case TE_PARTICLESNOW: // general purpose particle effect - MSG_ReadVector(pos); // mins - MSG_ReadVector(pos2); // maxs - MSG_ReadVector(dir); // dir - count = MSG_ReadShort(); // number of particles + MSG_ReadVector(pos, cl.protocol); // mins + MSG_ReadVector(pos2, cl.protocol); // maxs + MSG_ReadVector(dir, cl.protocol); // dir + count = (unsigned short) MSG_ReadShort(); // number of particles colorStart = MSG_ReadByte(); // color CL_ParticleRain(pos, pos2, dir, count, colorStart, 1); break; case TE_GUNSHOT: // bullet hitting wall - MSG_ReadVector(pos); + MSG_ReadVector(pos, cl.protocol); CL_FindNonSolidLocation(pos, pos, 4); // LordHavoc: changed to dust shower CL_SparkShower(pos, vec3_origin, 15); @@ -1215,7 +1082,7 @@ void CL_ParseTempEntity(void) case TE_GUNSHOTQUAD: // quad bullet hitting wall - MSG_ReadVector(pos); + MSG_ReadVector(pos, cl.protocol); CL_FindNonSolidLocation(pos, pos, 4); CL_SparkShower(pos, vec3_origin, 15); Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]); @@ -1224,7 +1091,7 @@ void CL_ParseTempEntity(void) case TE_EXPLOSION: // rocket explosion - MSG_ReadVector(pos); + MSG_ReadVector(pos, cl.protocol); CL_FindNonSolidLocation(pos, pos, 10); CL_ParticleExplosion(pos); // LordHavoc: boosted color from 1.0, 0.8, 0.4 to 1.25, 1.0, 0.5 @@ -1235,7 +1102,7 @@ void CL_ParseTempEntity(void) case TE_EXPLOSIONQUAD: // quad rocket explosion - MSG_ReadVector(pos); + MSG_ReadVector(pos, cl.protocol); CL_FindNonSolidLocation(pos, pos, 10); CL_ParticleExplosion(pos); Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]); @@ -1245,20 +1112,20 @@ void CL_ParseTempEntity(void) case TE_EXPLOSION3: // Nehahra movie colored lighting explosion - MSG_ReadVector(pos); + MSG_ReadVector(pos, cl.protocol); CL_FindNonSolidLocation(pos, pos, 10); CL_ParticleExplosion(pos); Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]); - color[0] = MSG_ReadCoord() * (2.0f / 1.0f); - color[1] = MSG_ReadCoord() * (2.0f / 1.0f); - color[2] = MSG_ReadCoord() * (2.0f / 1.0f); + color[0] = MSG_ReadCoord(cl.protocol) * (2.0f / 1.0f); + color[1] = MSG_ReadCoord(cl.protocol) * (2.0f / 1.0f); + color[2] = MSG_ReadCoord(cl.protocol) * (2.0f / 1.0f); CL_AllocDlight(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, 0, true, 1); S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1); break; case TE_EXPLOSIONRGB: // colored lighting explosion - MSG_ReadVector(pos); + MSG_ReadVector(pos, cl.protocol); CL_FindNonSolidLocation(pos, pos, 10); CL_ParticleExplosion(pos); color[0] = MSG_ReadByte() * (2.0f / 255.0f); @@ -1271,7 +1138,7 @@ void CL_ParseTempEntity(void) case TE_TAREXPLOSION: // tarbaby explosion - MSG_ReadVector(pos); + MSG_ReadVector(pos, cl.protocol); CL_FindNonSolidLocation(pos, pos, 10); CL_BlobExplosion(pos); @@ -1282,14 +1149,14 @@ void CL_ParseTempEntity(void) break; case TE_SMALLFLASH: - MSG_ReadVector(pos); + MSG_ReadVector(pos, cl.protocol); CL_FindNonSolidLocation(pos, pos, 10); Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]); CL_AllocDlight(NULL, &tempmatrix, 200, 2, 2, 2, 1000, 0.2, 0, 0, true, 1); break; case TE_CUSTOMFLASH: - MSG_ReadVector(pos); + MSG_ReadVector(pos, cl.protocol); CL_FindNonSolidLocation(pos, pos, 4); radius = MSG_ReadByte() * 8; velspeed = (MSG_ReadByte() + 1) * (1.0 / 256.0); @@ -1301,8 +1168,8 @@ void CL_ParseTempEntity(void) break; case TE_FLAMEJET: - MSG_ReadVector(pos); - MSG_ReadVector(dir); + MSG_ReadVector(pos, cl.protocol); + MSG_ReadVector(dir, cl.protocol); count = MSG_ReadByte(); CL_Flames(pos, dir, count); break; @@ -1343,12 +1210,12 @@ void CL_ParseTempEntity(void) break; case TE_LAVASPLASH: - MSG_ReadVector(pos); + MSG_ReadVector(pos, cl.protocol); CL_LavaSplash(pos); break; case TE_TELEPORT: - MSG_ReadVector(pos); + MSG_ReadVector(pos, cl.protocol); Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]); CL_AllocDlight(NULL, &tempmatrix, 500, 1.0f, 1.0f, 1.0f, 1500, 99.0f, 0, 0, true, 1); // CL_TeleportSplash(pos); @@ -1356,7 +1223,7 @@ void CL_ParseTempEntity(void) case TE_EXPLOSION2: // color mapped explosion - MSG_ReadVector(pos); + MSG_ReadVector(pos, cl.protocol); CL_FindNonSolidLocation(pos, pos, 10); colorStart = MSG_ReadByte(); colorLength = MSG_ReadByte(); @@ -1371,23 +1238,23 @@ void CL_ParseTempEntity(void) break; case TE_TEI_G3: - MSG_ReadVector(pos); - MSG_ReadVector(pos2); - MSG_ReadVector(dir); + MSG_ReadVector(pos, cl.protocol); + MSG_ReadVector(pos2, cl.protocol); + MSG_ReadVector(dir, cl.protocol); CL_BeamParticle(pos, pos2, 12, 1, 0.3, 0.1, 1, 1); CL_BeamParticle(pos, pos2, 5, 1, 0.9, 0.3, 1, 1); break; case TE_TEI_SMOKE: - MSG_ReadVector(pos); - MSG_ReadVector(dir); + MSG_ReadVector(pos, cl.protocol); + MSG_ReadVector(dir, cl.protocol); count = MSG_ReadByte(); CL_FindNonSolidLocation(pos, pos, 4); CL_Tei_Smoke(pos, dir, count); break; case TE_TEI_BIGEXPLOSION: - MSG_ReadVector(pos); + MSG_ReadVector(pos, cl.protocol); CL_FindNonSolidLocation(pos, pos, 10); CL_ParticleExplosion(pos); Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]); @@ -1396,8 +1263,8 @@ void CL_ParseTempEntity(void) break; case TE_TEI_PLASMAHIT: - MSG_ReadVector(pos); - MSG_ReadVector(dir); + MSG_ReadVector(pos, cl.protocol); + MSG_ReadVector(dir, cl.protocol); count = MSG_ReadByte(); CL_FindNonSolidLocation(pos, pos, 5); CL_Tei_PlasmaHit(pos, dir, count); @@ -1471,6 +1338,7 @@ void CL_ParseServerMessage(void) // if the high bit of the command byte is set, it is a fast update if (cmd & 128) { + entitiesupdated = true; // LordHavoc: fix for bizarre problem in MSVC that I do not understand (if I assign the string pointer directly it ends up storing a NULL pointer) temp = "entity"; cmdlogname[cmdindex] = temp; @@ -1481,7 +1349,7 @@ void CL_ParseServerMessage(void) cls.signon = SIGNONS; CL_SignonReply (); } - CL_ParseUpdate (cmd&127); + EntityFrameQuake_ReadEntity (cmd&127); continue; } @@ -1527,19 +1395,12 @@ void CL_ParseServerMessage(void) break; case svc_time: - if (!entitiesupdated) - { - // this is a new frame, we'll be seeing entities, - // so prepare for entity updates - CL_EntityUpdateSetup(); - entitiesupdated = true; - } cl.mtime[1] = cl.mtime[0]; cl.mtime[0] = MSG_ReadFloat (); break; case svc_clientdata: - i = MSG_ReadShort (); + i = (unsigned short) MSG_ReadShort (); CL_ParseClientdata (i); break; @@ -1583,7 +1444,12 @@ void CL_ParseServerMessage(void) case svc_setangle: for (i=0 ; i<3 ; i++) - cl.viewangles[i] = MSG_ReadAngle (); + { + if (cl.protocol == PROTOCOL_DARKPLACES5) + cl.viewangles[i] = MSG_ReadAngle16i (); + else + cl.viewangles[i] = MSG_ReadAngle8i (); + } break; case svc_setview: @@ -1613,7 +1479,7 @@ void CL_ParseServerMessage(void) break; case svc_stopsound: - i = MSG_ReadShort(); + i = (unsigned short) MSG_ReadShort(); S_StopSound(i>>3, i&7); break; @@ -1628,7 +1494,7 @@ void CL_ParseServerMessage(void) i = MSG_ReadByte (); if (i >= cl.maxclients) Host_Error ("CL_ParseServerMessage: svc_updatefrags >= cl.maxclients"); - cl.scores[i].frags = MSG_ReadShort (); + cl.scores[i].frags = (unsigned short) MSG_ReadShort (); break; case svc_updatecolors: @@ -1651,13 +1517,13 @@ void CL_ParseServerMessage(void) break; case svc_spawnbaseline: - i = MSG_ReadShort (); + i = (unsigned short) MSG_ReadShort (); if (i < 0 || i >= MAX_EDICTS) Host_Error ("CL_ParseServerMessage: svc_spawnbaseline: invalid entity number %i", i); CL_ParseBaseline (cl_entities + i, false); break; case svc_spawnbaseline2: - i = MSG_ReadShort (); + i = (unsigned short) MSG_ReadShort (); if (i < 0 || i >= MAX_EDICTS) Host_Error ("CL_ParseServerMessage: svc_spawnbaseline2: invalid entity number %i", i); CL_ParseBaseline (cl_entities + i, true); @@ -1750,12 +1616,12 @@ void CL_ParseServerMessage(void) if (gamemode == GAME_TENEBRAE) { // repeating particle effect - MSG_ReadCoord(); - MSG_ReadCoord(); - MSG_ReadCoord(); - MSG_ReadCoord(); - MSG_ReadCoord(); - MSG_ReadCoord(); + MSG_ReadCoord(cl.protocol); + MSG_ReadCoord(cl.protocol); + MSG_ReadCoord(cl.protocol); + MSG_ReadCoord(cl.protocol); + MSG_ReadCoord(cl.protocol); + MSG_ReadCoord(cl.protocol); MSG_ReadByte(); MSG_ReadLong(); MSG_ReadLong(); @@ -1768,9 +1634,9 @@ void CL_ParseServerMessage(void) if (gamemode == GAME_TENEBRAE) { // particle effect - MSG_ReadCoord(); - MSG_ReadCoord(); - MSG_ReadCoord(); + MSG_ReadCoord(cl.protocol); + MSG_ReadCoord(cl.protocol); + MSG_ReadCoord(cl.protocol); MSG_ReadByte(); MSG_ReadString(); } @@ -1803,7 +1669,7 @@ void CL_ParseServerMessage(void) } if (entitiesupdated) - CL_EntityUpdateEnd(); + EntityFrameQuake_ISeeDeadEntities(); parsingerror = false; } diff --git a/cl_particles.c b/cl_particles.c index 11ec5230..d5f9b93f 100644 --- a/cl_particles.c +++ b/cl_particles.c @@ -612,7 +612,7 @@ void CL_ParseParticleEffect (void) vec3_t org, dir; int i, count, msgcount, color; - MSG_ReadVector(org); + MSG_ReadVector(org, cl.protocol); for (i=0 ; i<3 ; i++) dir[i] = MSG_ReadChar () * (1.0/16); msgcount = MSG_ReadByte (); diff --git a/client.h b/client.h index 55af9a9a..38ef0b79 100644 --- a/client.h +++ b/client.h @@ -540,8 +540,10 @@ typedef struct int protocol; // entity database stuff - entity_database_t entitydatabase; - entity_database4_t *entitydatabase4; + // latest received entity frame number + int latestframenum; + entityframe_database_t *entitydatabase; + entityframe4_database_t *entitydatabase4; } client_state_t; @@ -599,6 +601,7 @@ extern int cl_num_static_entities; extern int cl_num_temp_entities; extern int cl_num_brushmodel_entities; +extern mempool_t *cl_entities_mempool; extern entity_t *cl_entities; extern qbyte *cl_entities_active; extern entity_t *cl_static_entities; @@ -652,6 +655,8 @@ void CL_InitInput (void); void CL_SendCmd (usercmd_t *cmd); void CL_SendMove (usercmd_t *cmd); +void CL_ValidateState(entity_state_t *s); +void CL_MoveLerpEntityStates(entity_t *ent); void CL_LerpUpdate(entity_t *e); void CL_ParseTEnt (void); void CL_RelinkBeams (void); diff --git a/common.c b/common.c index c20ad3f6..89d73de3 100644 --- a/common.c +++ b/common.c @@ -190,8 +190,15 @@ void MSG_WriteString (sizebuf_t *sb, const char *s) SZ_Write (sb, s, strlen(s)+1); } -// used by server (always latest PROTOCOL_DARKPLACES) -void MSG_WriteDPCoord (sizebuf_t *sb, float f) +void MSG_WriteCoord13i (sizebuf_t *sb, float f) +{ + if (f >= 0) + MSG_WriteShort (sb, (int)(f * 8.0f + 0.5f)); + else + MSG_WriteShort (sb, (int)(f * 8.0f - 0.5f)); +} + +void MSG_WriteCoord16i (sizebuf_t *sb, float f) { if (f >= 0) MSG_WriteShort (sb, (int)(f + 0.5f)); @@ -199,16 +206,32 @@ void MSG_WriteDPCoord (sizebuf_t *sb, float f) MSG_WriteShort (sb, (int)(f - 0.5f)); } -void MSG_WritePreciseAngle (sizebuf_t *sb, float f) +void MSG_WriteCoord32f (sizebuf_t *sb, float f) { - if (f >= 0) - MSG_WriteShort (sb, (int)(f*(65536.0f/360.0f) + 0.5f) & 65535); + MSG_WriteFloat (sb, f); +} + +void MSG_WriteCoord (sizebuf_t *sb, float f, int protocol) +{ + if (protocol == PROTOCOL_QUAKE) + MSG_WriteCoord13i (sb, f); + else if (protocol == PROTOCOL_DARKPLACES1 || protocol == PROTOCOL_DARKPLACES5) + MSG_WriteCoord32f (sb, f); + else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4) + MSG_WriteCoord16i (sb, f); else - MSG_WriteShort (sb, (int)(f*(65536.0f/360.0f) - 0.5f) & 65535); + Host_Error("MSG_WriteCoord: unknown protocol\n"); +} + +void MSG_WriteVector (sizebuf_t *sb, float *v, int protocol) +{ + MSG_WriteCoord (sb, v[0], protocol); + MSG_WriteCoord (sb, v[1], protocol); + MSG_WriteCoord (sb, v[2], protocol); } // LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem -void MSG_WriteAngle (sizebuf_t *sb, float f) +void MSG_WriteAngle8i (sizebuf_t *sb, float f) { if (f >= 0) MSG_WriteByte (sb, (int)(f*(256.0f/360.0f) + 0.5f) & 255); @@ -216,6 +239,20 @@ void MSG_WriteAngle (sizebuf_t *sb, float f) MSG_WriteByte (sb, (int)(f*(256.0f/360.0f) - 0.5f) & 255); } +void MSG_WriteAngle16i (sizebuf_t *sb, float f) +{ + if (f >= 0) + MSG_WriteShort (sb, (int)(f*(65536.0f/360.0f) + 0.5f) & 65535); + else + MSG_WriteShort (sb, (int)(f*(65536.0f/360.0f) - 0.5f) & 65535); +} + +void MSG_WriteAngle32f (sizebuf_t *sb, float f) +{ + MSG_WriteFloat (sb, f); +} + + // // reading functions // @@ -324,15 +361,54 @@ int MSG_ReadBytes (int numbytes, unsigned char *out) return l; } -// used by client -float MSG_ReadCoord (void) +float MSG_ReadCoord13i (void) { - if (cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5) - return (signed short) MSG_ReadLittleShort(); - else if (cl.protocol == PROTOCOL_DARKPLACES1) - return MSG_ReadLittleFloat(); - else - return MSG_ReadLittleShort() * (1.0f/8.0f); + return MSG_ReadLittleShort() * (1.0f/8.0f); +} + +float MSG_ReadCoord16i (void) +{ + return (signed short) MSG_ReadLittleShort(); +} + +float MSG_ReadCoord32f (void) +{ + return MSG_ReadLittleFloat(); +} + +float MSG_ReadCoord (int protocol) +{ + if (protocol == PROTOCOL_QUAKE) + return MSG_ReadCoord13i(); + else if (protocol == PROTOCOL_DARKPLACES1 || protocol == PROTOCOL_DARKPLACES5) + return MSG_ReadCoord32f(); + else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4) + return MSG_ReadCoord16i(); + Host_Error("MSG_ReadCoord: unknown protocol\n"); + return 0; +} + +void MSG_ReadVector (float *v, int protocol) +{ + v[0] = MSG_ReadCoord(protocol); + v[1] = MSG_ReadCoord(protocol); + v[2] = MSG_ReadCoord(protocol); +} + +// LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem +float MSG_ReadAngle8i (void) +{ + return MSG_ReadByte () * (360.0f/256.0f); +} + +float MSG_ReadAngle16i (void) +{ + return MSG_ReadShort () * (360.0f/65536.0f); +} + +float MSG_ReadAngle32f (void) +{ + return MSG_ReadFloat (); } diff --git a/common.h b/common.h index 48116bb4..b6272a80 100644 --- a/common.h +++ b/common.h @@ -115,10 +115,14 @@ void MSG_WriteShort (sizebuf_t *sb, int c); void MSG_WriteLong (sizebuf_t *sb, int c); void MSG_WriteFloat (sizebuf_t *sb, float f); void MSG_WriteString (sizebuf_t *sb, const char *s); -void MSG_WriteCoord (sizebuf_t *sb, float f); -void MSG_WriteAngle (sizebuf_t *sb, float f); -void MSG_WritePreciseAngle (sizebuf_t *sb, float f); -void MSG_WriteDPCoord (sizebuf_t *sb, float f); +void MSG_WriteAngle8i (sizebuf_t *sb, float f); +void MSG_WriteAngle16i (sizebuf_t *sb, float f); +void MSG_WriteAngle32f (sizebuf_t *sb, float f); +void MSG_WriteCoord13i (sizebuf_t *sb, float f); +void MSG_WriteCoord16i (sizebuf_t *sb, float f); +void MSG_WriteCoord32f (sizebuf_t *sb, float f); +void MSG_WriteCoord (sizebuf_t *sb, float f, int protocol); +void MSG_WriteVector (sizebuf_t *sb, float *v, int protocol); extern int msg_readcount; extern qboolean msg_badread; // set if a read goes beyond end of message @@ -139,12 +143,14 @@ int MSG_ReadBytes (int numbytes, unsigned char *out); #define MSG_ReadLong MSG_ReadLittleLong #define MSG_ReadFloat MSG_ReadLittleFloat -float MSG_ReadCoord (void); - -#define MSG_ReadAngle() (MSG_ReadByte() * (360.0f / 256.0f)) -#define MSG_ReadPreciseAngle() (MSG_ReadShort() * (360.0f / 65536.0f)) - -#define MSG_ReadVector(v) ((v)[0] = MSG_ReadCoord(), (v)[1] = MSG_ReadCoord(), (v)[2] = MSG_ReadCoord()) +float MSG_ReadAngle8i (void); +float MSG_ReadAngle16i (void); +float MSG_ReadAngle32f (void); +float MSG_ReadCoord13i (void); +float MSG_ReadCoord16i (void); +float MSG_ReadCoord32f (void); +float MSG_ReadCoord (int protocol); +void MSG_ReadVector (float *v, int protocol); //============================================================================ diff --git a/host.c b/host.c index b1ed19b0..ee924867 100644 --- a/host.c +++ b/host.c @@ -455,8 +455,12 @@ void SV_DropClient(qboolean crash) NetConn_Heartbeat(1); // free the client now + if (host_client->entitydatabase) + EntityFrame_FreeDatabase(host_client->entitydatabase); if (host_client->entitydatabase4) EntityFrame4_FreeDatabase(host_client->entitydatabase4); + if (host_client->entitydatabase5) + EntityFrame5_FreeDatabase(host_client->entitydatabase5); // clear the client struct (this sets active to false) memset(host_client, 0, sizeof(*host_client)); } diff --git a/host_cmd.c b/host_cmd.c index 7ded7c47..bdae5cf8 100644 --- a/host_cmd.c +++ b/host_cmd.c @@ -50,6 +50,7 @@ Host_Status_f */ void Host_Status_f (void) { + const char *protocolname; client_t *client; int seconds, minutes, hours = 0, j, players; void (*print) (const char *fmt, ...); @@ -71,6 +72,17 @@ void Host_Status_f (void) players++; print ("host: %s\n", Cvar_VariableString ("hostname")); print ("version: %s build %s\n", gamename, buildstring); + switch(sv.protocol) + { + case PROTOCOL_QUAKE: protocolname = sv.netquakecompatible ? "QUAKE" : "QUAKEDP";break; + case PROTOCOL_DARKPLACES1: protocolname = "PROTOCOL_DARKPLACES1";break; + case PROTOCOL_DARKPLACES2: protocolname = "PROTOCOL_DARKPLACES2";break; + case PROTOCOL_DARKPLACES3: protocolname = "PROTOCOL_DARKPLACES3";break; + case PROTOCOL_DARKPLACES4: protocolname = "PROTOCOL_DARKPLACES4";break; + case PROTOCOL_DARKPLACES5: protocolname = "PROTOCOL_DARKPLACES5";break; + default: protocolname = "PROTOCOL_UNKNOWN";break; + } + print ("protocol: %i (%s)\n", sv.protocol, protocolname); print ("map: %s\n", sv.name); print ("players: %i active (%i max)\n\n", players, svs.maxclients); for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++) @@ -943,10 +955,9 @@ void Host_Color_f(void) } cvar_t cl_rate = {CVAR_SAVE, "_cl_rate", "10000"}; -cvar_t sv_maxrate = {CVAR_SAVE | CVAR_NOTIFY, "sv_maxrate", "10000"}; void Host_Rate_f(void) { - int rate, maxrate; + int rate; if (Cmd_Argc() != 2) { @@ -965,12 +976,7 @@ void Host_Rate_f(void) return; } - maxrate = bound(NET_MINRATE, sv_maxrate.integer, NET_MAXRATE); - if (sv_maxrate.integer != maxrate) - Cvar_SetValueQuick(&sv_maxrate, maxrate); - - if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) != LHNETADDRESSTYPE_LOOP) - host_client->netconnection->rate = bound(NET_MINRATE, rate, maxrate); + host_client->netconnection->rate = rate; } /* @@ -1210,9 +1216,18 @@ void Host_Spawn_f (void) // and it won't happen if the game was just loaded, so you wind up // with a permanent head tilt MSG_WriteByte (&host_client->message, svc_setangle); - for (i=0 ; i < 2 ; i++) - MSG_WriteAngle (&host_client->message, sv_player->v->angles[i] ); - MSG_WriteAngle (&host_client->message, 0 ); + if (sv.protocol == PROTOCOL_DARKPLACES5) + { + MSG_WriteAngle16i (&host_client->message, sv_player->v->angles[0]); + MSG_WriteAngle16i (&host_client->message, sv_player->v->angles[1]); + MSG_WriteAngle16i (&host_client->message, 0); + } + else + { + MSG_WriteAngle8i (&host_client->message, sv_player->v->angles[0]); + MSG_WriteAngle8i (&host_client->message, sv_player->v->angles[1]); + MSG_WriteAngle8i (&host_client->message, 0); + } SV_WriteClientdataToMessage (sv_player, &host_client->message); @@ -1778,7 +1793,6 @@ void Host_InitCommands (void) Cmd_AddCommand ("color", Host_Color_f); Cvar_RegisterVariable (&cl_rate); Cmd_AddCommand ("rate", Host_Rate_f); - Cvar_RegisterVariable (&sv_maxrate); if (gamemode == GAME_NEHAHRA) { Cvar_RegisterVariable (&cl_pmodel); diff --git a/menu.c b/menu.c index c4de8c30..8a1105dc 100644 --- a/menu.c +++ b/menu.c @@ -3276,9 +3276,6 @@ int maxplayers; qboolean m_serverInfoMessage = false; double m_serverInfoMessageTime; -extern cvar_t sv_public; -extern cvar_t sv_maxrate; - void M_Menu_GameOptions_f (void) { key_dest = key_menu; diff --git a/model_brush.h b/model_brush.h index d3865d58..f04ab606 100644 --- a/model_brush.h +++ b/model_brush.h @@ -756,6 +756,7 @@ q3dpvs_t; #define CHECKPVSBIT(pvs,b) ((b) >= 0 ? ((pvs)[(b) >> 3] & (1 << ((b) & 7))) : false) #define SETPVSBIT(pvs,b) ((b) >= 0 ? ((pvs)[(b) >> 3] |= (1 << ((b) & 7))) : false) +#define CLEARPVSBIT(pvs,b) ((b) >= 0 ? ((pvs)[(b) >> 3] &= ~(1 << ((b) & 7))) : false) #endif diff --git a/netconn.c b/netconn.c index 12636d4c..591056c4 100755 --- a/netconn.c +++ b/netconn.c @@ -1119,21 +1119,16 @@ int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, qbyte *data, int length, if (clientnum < svs.maxclients) { // prepare the client struct - if ((client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_clients_mempool))) + if ((conn = NetConn_Open(mysocket, peeraddress))) { - if ((conn = NetConn_Open(mysocket, peeraddress))) - { - // allocated connection - LHNETADDRESS_ToString(peeraddress, conn->address, sizeof(conn->address), true); - if (developer.integer) - Con_Printf("Datagram_ParseConnectionless: sending \"accept\" to %s.\n", conn->address); - NetConn_WriteString(mysocket, "\377\377\377\377accept", peeraddress); - // now set up the client - SV_ConnectClient(clientnum, conn); - NetConn_Heartbeat(1); - } - else - EntityFrame4_FreeDatabase(client->entitydatabase4); + // allocated connection + LHNETADDRESS_ToString(peeraddress, conn->address, sizeof(conn->address), true); + if (developer.integer) + Con_Printf("Datagram_ParseConnectionless: sending \"accept\" to %s.\n", conn->address); + NetConn_WriteString(mysocket, "\377\377\377\377accept", peeraddress); + // now set up the client + SV_ConnectClient(clientnum, conn); + NetConn_Heartbeat(1); } } else diff --git a/pr_cmds.c b/pr_cmds.c index 3465c473..32fe4cf7 100644 --- a/pr_cmds.c +++ b/pr_cmds.c @@ -630,7 +630,7 @@ void PF_ambientsound (void) char *samp; float *pos; float vol, attenuation; - int i, soundnum, large; + int soundnum, large; pos = G_VECTOR (OFS_PARM0); samp = G_STRING(OFS_PARM1); @@ -659,8 +659,7 @@ void PF_ambientsound (void) else MSG_WriteByte (&sv.signon, svc_spawnstaticsound); - for (i=0 ; i<3 ; i++) - MSG_WriteDPCoord(&sv.signon, pos[i]); + MSG_WriteVector(&sv.signon, pos, sv.protocol); if (large) MSG_WriteShort (&sv.signon, soundnum); @@ -1352,6 +1351,7 @@ void PF_precache_sound (void) { char *s; int i; + int limit = (sv.protocol == PROTOCOL_QUAKE ? 256 : MAX_SOUNDS); if (sv.state != ss_loading) PF_ERROR("PF_Precache_*: Precache can only be done in spawn functions"); @@ -1360,7 +1360,7 @@ void PF_precache_sound (void) G_INT(OFS_RETURN) = G_INT(OFS_PARM0); PR_CheckEmptyString (s); - for (i=0 ; iv->skin); for (i=0 ; i<3 ; i++) { - MSG_WriteDPCoord(&sv.signon, ent->v->origin[i]); - MSG_WriteAngle(&sv.signon, ent->v->angles[i]); + MSG_WriteCoord(&sv.signon, ent->v->origin[i], sv.protocol); + MSG_WriteAngle8i(&sv.signon, ent->v->angles[i]); } // throw the entity away now @@ -2239,12 +2243,16 @@ effect(origin, modelname, startframe, framecount, framerate) */ void PF_effect (void) { + int i; char *s; s = G_STRING(OFS_PARM1); if (!s || !s[0]) PF_WARNING("effect: no model specified\n"); - SV_StartEffect(G_VECTOR(OFS_PARM0), SV_ModelIndex(s), G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4)); + i = SV_ModelIndex(s); + if (i < 0) + PF_WARNING("effect: model not precached\n"); + SV_StartEffect(G_VECTOR(OFS_PARM0), i, G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4)); } void PF_te_blood (void) @@ -2254,9 +2262,9 @@ void PF_te_blood (void) MSG_WriteByte(&sv.datagram, svc_temp_entity); MSG_WriteByte(&sv.datagram, TE_BLOOD); // origin - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol); // velocity MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127)); MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127)); @@ -2272,15 +2280,15 @@ void PF_te_bloodshower (void) MSG_WriteByte(&sv.datagram, svc_temp_entity); MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER); // min - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol); // max - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol); // speed - MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM2)); + MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM2), sv.protocol); // count MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535)); } @@ -2290,9 +2298,9 @@ void PF_te_explosionrgb (void) MSG_WriteByte(&sv.datagram, svc_temp_entity); MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB); // origin - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol); // color MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255)); MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255)); @@ -2306,17 +2314,17 @@ void PF_te_particlecube (void) MSG_WriteByte(&sv.datagram, svc_temp_entity); MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE); // min - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol); // max - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol); // velocity - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol); // count MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535)); // color @@ -2324,7 +2332,7 @@ void PF_te_particlecube (void) // gravity true/false MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0); // randomvel - MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM6)); + MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM6), sv.protocol); } void PF_te_particlerain (void) @@ -2334,17 +2342,17 @@ void PF_te_particlerain (void) MSG_WriteByte(&sv.datagram, svc_temp_entity); MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN); // min - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol); // max - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol); // velocity - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol); // count MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535)); // color @@ -2358,17 +2366,17 @@ void PF_te_particlesnow (void) MSG_WriteByte(&sv.datagram, svc_temp_entity); MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW); // min - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol); // max - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol); // velocity - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol); // count MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535)); // color @@ -2382,9 +2390,9 @@ void PF_te_spark (void) MSG_WriteByte(&sv.datagram, svc_temp_entity); MSG_WriteByte(&sv.datagram, TE_SPARK); // origin - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol); // velocity MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127)); MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127)); @@ -2398,9 +2406,9 @@ void PF_te_gunshotquad (void) MSG_WriteByte(&sv.datagram, svc_temp_entity); MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD); // origin - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol); } void PF_te_spikequad (void) @@ -2408,9 +2416,9 @@ void PF_te_spikequad (void) MSG_WriteByte(&sv.datagram, svc_temp_entity); MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD); // origin - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol); } void PF_te_superspikequad (void) @@ -2418,9 +2426,9 @@ void PF_te_superspikequad (void) MSG_WriteByte(&sv.datagram, svc_temp_entity); MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD); // origin - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol); } void PF_te_explosionquad (void) @@ -2428,9 +2436,9 @@ void PF_te_explosionquad (void) MSG_WriteByte(&sv.datagram, svc_temp_entity); MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD); // origin - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol); } void PF_te_smallflash (void) @@ -2438,9 +2446,9 @@ void PF_te_smallflash (void) MSG_WriteByte(&sv.datagram, svc_temp_entity); MSG_WriteByte(&sv.datagram, TE_SMALLFLASH); // origin - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol); } void PF_te_customflash (void) @@ -2450,9 +2458,9 @@ void PF_te_customflash (void) MSG_WriteByte(&sv.datagram, svc_temp_entity); MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH); // origin - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol); // radius MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255)); // lifetime @@ -2468,9 +2476,9 @@ void PF_te_gunshot (void) MSG_WriteByte(&sv.datagram, svc_temp_entity); MSG_WriteByte(&sv.datagram, TE_GUNSHOT); // origin - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol); } void PF_te_spike (void) @@ -2478,9 +2486,9 @@ void PF_te_spike (void) MSG_WriteByte(&sv.datagram, svc_temp_entity); MSG_WriteByte(&sv.datagram, TE_SPIKE); // origin - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol); } void PF_te_superspike (void) @@ -2488,9 +2496,9 @@ void PF_te_superspike (void) MSG_WriteByte(&sv.datagram, svc_temp_entity); MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE); // origin - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol); } void PF_te_explosion (void) @@ -2498,9 +2506,9 @@ void PF_te_explosion (void) MSG_WriteByte(&sv.datagram, svc_temp_entity); MSG_WriteByte(&sv.datagram, TE_EXPLOSION); // origin - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol); } void PF_te_tarexplosion (void) @@ -2508,9 +2516,9 @@ void PF_te_tarexplosion (void) MSG_WriteByte(&sv.datagram, svc_temp_entity); MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION); // origin - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol); } void PF_te_wizspike (void) @@ -2518,9 +2526,9 @@ void PF_te_wizspike (void) MSG_WriteByte(&sv.datagram, svc_temp_entity); MSG_WriteByte(&sv.datagram, TE_WIZSPIKE); // origin - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol); } void PF_te_knightspike (void) @@ -2528,9 +2536,9 @@ void PF_te_knightspike (void) MSG_WriteByte(&sv.datagram, svc_temp_entity); MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE); // origin - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol); } void PF_te_lavasplash (void) @@ -2538,9 +2546,9 @@ void PF_te_lavasplash (void) MSG_WriteByte(&sv.datagram, svc_temp_entity); MSG_WriteByte(&sv.datagram, TE_LAVASPLASH); // origin - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol); } void PF_te_teleport (void) @@ -2548,9 +2556,9 @@ void PF_te_teleport (void) MSG_WriteByte(&sv.datagram, svc_temp_entity); MSG_WriteByte(&sv.datagram, TE_TELEPORT); // origin - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol); } void PF_te_explosion2 (void) @@ -2558,9 +2566,9 @@ void PF_te_explosion2 (void) MSG_WriteByte(&sv.datagram, svc_temp_entity); MSG_WriteByte(&sv.datagram, TE_EXPLOSION2); // origin - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol); // color MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1)); MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM2)); @@ -2573,13 +2581,13 @@ void PF_te_lightning1 (void) // owner entity MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0)); // start - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol); // end - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol); } void PF_te_lightning2 (void) @@ -2589,13 +2597,13 @@ void PF_te_lightning2 (void) // owner entity MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0)); // start - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol); // end - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol); } void PF_te_lightning3 (void) @@ -2605,13 +2613,13 @@ void PF_te_lightning3 (void) // owner entity MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0)); // start - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol); // end - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol); } void PF_te_beam (void) @@ -2621,22 +2629,22 @@ void PF_te_beam (void) // owner entity MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0)); // start - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol); // end - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol); } void PF_te_plasmaburn (void) { MSG_WriteByte(&sv.datagram, svc_temp_entity); MSG_WriteByte(&sv.datagram, TE_PLASMABURN); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]); - MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol); } static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out) diff --git a/progs.h b/progs.h index 18d15884..b1578120 100644 --- a/progs.h +++ b/progs.h @@ -57,13 +57,9 @@ typedef struct edict_engineprivate_s // we should avoid extensive checking on entities already encountered int areagridmarknumber; - // old entity protocol, not used -#ifdef QUAKEENTITIES + // PROTOCOL_QUAKE // baseline values entity_state_t baseline; - // LordHavoc: previous frame - entity_state_t deltabaseline; -#endif // LordHavoc: gross hack to make floating items still work int suspendedinairflag; diff --git a/protocol.c b/protocol.c index 2d288522..72870b34 100644 --- a/protocol.c +++ b/protocol.c @@ -4,39 +4,277 @@ // this is 80 bytes entity_state_t defaultstate = { - // ! means this is sent to client - 0,//double time; // time this state was built (used on client for interpolation) - {0,0,0},//float origin[3]; // ! - {0,0,0},//float angles[3]; // ! - 0,//int number; // ! entity number this state is for - 0,//int effects; // ! - 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,0,0,0},//unsigned short light[4]; // ! color*256 (0.00 to 255.996), and radius*1 - 0,//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 tagindex; // ! + // ! means this is not sent to client + 0,//double time; // ! time this state was built (used on client for interpolation) + {0,0,0},//float origin[3]; + {0,0,0},//float angles[3]; + 0,//int number; // entity number this state is for + 0,//int effects; + 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,0,0,0},//unsigned short light[4]; // color*256 (0.00 to 255.996), and radius*1 + 0,//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 tagindex; + 255,//unsigned char colormod; // padding to a multiple of 8 bytes (to align the double time) - {0,0,0,0,0}//unsigned char unused[5]; + {0,0,0,0}//unsigned char unused[4]; // ! }; -void ClearStateToDefault(entity_state_t *s) +double entityframequake_mtime = 0; + +void EntityFrameQuake_ReadEntity(int bits) { - *s = defaultstate; + int num; + entity_t *ent; + entity_state_t s; + + entityframequake_mtime = cl.mtime[0]; + + if (bits & U_MOREBITS) + bits |= (MSG_ReadByte()<<8); + if ((bits & U_EXTEND1) && cl.protocol != PROTOCOL_NEHAHRAMOVIE) + { + bits |= MSG_ReadByte() << 16; + if (bits & U_EXTEND2) + bits |= MSG_ReadByte() << 24; + } + + if (bits & U_LONGENTITY) + num = (unsigned short) MSG_ReadShort (); + else + num = MSG_ReadByte (); + + if (num >= MAX_EDICTS) + Host_Error("EntityFrameQuake_ReadEntity: entity number (%i) >= MAX_EDICTS (%i)\n", num, MAX_EDICTS); + if (num < 1) + Host_Error("EntityFrameQuake_ReadEntity: invalid entity number (%i)\n", num); + + ent = cl_entities + num; + + // note: this inherits the 'active' state of the baseline chosen + // (state_baseline is always active, state_current may not be active if + // the entity was missing in the last frame) + if (bits & U_DELTA) + s = ent->state_current; + else + { + s = ent->state_baseline; + s.active = true; + } + + s.number = num; + s.time = cl.mtime[0]; + s.flags = 0; + if (bits & U_MODEL) s.modelindex = (s.modelindex & 0xFF00) | MSG_ReadByte(); + if (bits & U_FRAME) s.frame = (s.frame & 0xFF00) | MSG_ReadByte(); + if (bits & U_COLORMAP) s.colormap = MSG_ReadByte(); + if (bits & U_SKIN) s.skin = MSG_ReadByte(); + if (bits & U_EFFECTS) s.effects = (s.effects & 0xFF00) | MSG_ReadByte(); + if (bits & U_ORIGIN1) s.origin[0] = MSG_ReadCoord13i(); + if (bits & U_ANGLE1) s.angles[0] = MSG_ReadAngle8i(); + if (bits & U_ORIGIN2) s.origin[1] = MSG_ReadCoord13i(); + if (bits & U_ANGLE2) s.angles[1] = MSG_ReadAngle8i(); + if (bits & U_ORIGIN3) s.origin[2] = MSG_ReadCoord13i(); + if (bits & U_ANGLE3) s.angles[2] = MSG_ReadAngle8i(); + if (bits & U_STEP) s.flags |= RENDER_STEP; + if (bits & U_ALPHA) s.alpha = MSG_ReadByte(); + if (bits & U_SCALE) s.scale = MSG_ReadByte(); + if (bits & U_EFFECTS2) s.effects = (s.effects & 0x00FF) | (MSG_ReadByte() << 8); + if (bits & U_GLOWSIZE) s.glowsize = MSG_ReadByte(); + if (bits & U_GLOWCOLOR) s.glowcolor = MSG_ReadByte(); + if (bits & U_COLORMOD) s.colormod = MSG_ReadByte(); + if (bits & U_GLOWTRAIL) s.flags |= RENDER_GLOWTRAIL; + if (bits & U_FRAME2) s.frame = (s.frame & 0x00FF) | (MSG_ReadByte() << 8); + if (bits & U_MODEL2) s.modelindex = (s.modelindex & 0x00FF) | (MSG_ReadByte() << 8); + if (bits & U_VIEWMODEL) s.flags |= RENDER_VIEWMODEL; + if (bits & U_EXTERIORMODEL) s.flags |= RENDER_EXTERIORMODEL; + + // LordHavoc: to allow playback of the Nehahra movie + if (cl.protocol == PROTOCOL_NEHAHRAMOVIE && (bits & U_EXTEND1)) + { + // LordHavoc: evil format + int i = MSG_ReadFloat(); + int j = MSG_ReadFloat() * 255.0f; + if (i == 2) + { + i = MSG_ReadFloat(); + if (i) + s.effects |= EF_FULLBRIGHT; + } + if (j < 0) + s.alpha = 0; + else if (j == 0 || j >= 255) + s.alpha = 255; + else + s.alpha = j; + } + + ent->state_previous = ent->state_current; + ent->state_current = s; + if (ent->state_current.active) + { + CL_MoveLerpEntityStates(ent); + cl_entities_active[ent->state_current.number] = true; + } + + if (msg_badread) + Host_Error("EntityFrameQuake_ReadEntity: read error\n"); +} + +void EntityFrameQuake_ISeeDeadEntities(void) +{ + int i; + for (i = 0;i < cl_max_entities;i++) + { + if (cl_entities_active[i] && cl_entities[i].state_current.time != cl.mtime[0]) + { + cl_entities_active[i] = false; + cl_entities[i].state_current = defaultstate; + cl_entities[i].state_current.number = i; + } + } +} + +void EntityFrameQuake_WriteFrame(sizebuf_t *msg, int numstates, const entity_state_t *states) +{ + const entity_state_t *s; + entity_state_t baseline; + int i, bits; + sizebuf_t buf; + qbyte data[128]; + + // prepare the buffer + memset(&buf, 0, sizeof(buf)); + buf.data = data; + buf.maxsize = sizeof(data); + + for (i = 0, s = states;i < numstates;i++, s++) + { + // prepare the buffer + SZ_Clear(&buf); + +// send an update + bits = 0; + if (s->number >= 256) + bits |= U_LONGENTITY; + if (s->flags & RENDER_STEP) + bits |= U_STEP; + if (s->flags & RENDER_VIEWMODEL) + bits |= U_VIEWMODEL; + if (s->flags & RENDER_GLOWTRAIL) + bits |= U_GLOWTRAIL; + if (s->flags & RENDER_EXTERIORMODEL) + bits |= U_EXTERIORMODEL; + + // LordHavoc: old stuff, but rewritten to have more exact tolerances + baseline = sv.edicts[s->number].e->baseline; + if (baseline.origin[0] != s->origin[0]) + bits |= U_ORIGIN1; + if (baseline.origin[1] != s->origin[1]) + bits |= U_ORIGIN2; + if (baseline.origin[2] != s->origin[2]) + bits |= U_ORIGIN3; + if (baseline.angles[0] != s->angles[0]) + bits |= U_ANGLE1; + if (baseline.angles[1] != s->angles[1]) + bits |= U_ANGLE2; + if (baseline.angles[2] != s->angles[2]) + bits |= U_ANGLE3; + if (baseline.colormap != s->colormap) + bits |= U_COLORMAP; + if (baseline.skin != s->skin) + bits |= U_SKIN; + if (baseline.frame != s->frame) + { + bits |= U_FRAME; + if (s->frame & 0xFF00) + bits |= U_FRAME2; + } + if (baseline.effects != s->effects) + { + bits |= U_EFFECTS; + if (s->effects & 0xFF00) + bits |= U_EFFECTS2; + } + if (baseline.modelindex != s->modelindex) + { + bits |= U_MODEL; + if (s->modelindex & 0xFF00) + bits |= U_MODEL2; + } + if (baseline.alpha != s->alpha) + bits |= U_ALPHA; + if (baseline.scale != s->scale) + bits |= U_SCALE; + if (baseline.glowsize != s->glowsize) + bits |= U_GLOWSIZE; + if (baseline.glowcolor != s->glowcolor) + bits |= U_GLOWCOLOR; + + // if extensions are disabled, clear the relevant update flags + if (sv.netquakecompatible) + bits &= 0x7FFF; + + // write the message + if (bits >= 16777216) + bits |= U_EXTEND2; + if (bits >= 65536) + bits |= U_EXTEND1; + if (bits >= 256) + bits |= U_MOREBITS; + bits |= U_SIGNAL; + + MSG_WriteByte (&buf, bits); + if (bits & U_MOREBITS) MSG_WriteByte(&buf, bits>>8); + if (bits & U_EXTEND1) MSG_WriteByte(&buf, bits>>16); + if (bits & U_EXTEND2) MSG_WriteByte(&buf, bits>>24); + if (bits & U_LONGENTITY) MSG_WriteShort(&buf, s->number); + else MSG_WriteByte(&buf, s->number); + + if (bits & U_MODEL) MSG_WriteByte(&buf, s->modelindex); + if (bits & U_FRAME) MSG_WriteByte(&buf, s->frame); + if (bits & U_COLORMAP) MSG_WriteByte(&buf, s->colormap); + if (bits & U_SKIN) MSG_WriteByte(&buf, s->skin); + if (bits & U_EFFECTS) MSG_WriteByte(&buf, s->effects); + if (bits & U_ORIGIN1) MSG_WriteCoord13i(&buf, s->origin[0]); + if (bits & U_ANGLE1) MSG_WriteAngle8i(&buf, s->angles[0]); + if (bits & U_ORIGIN2) MSG_WriteCoord13i(&buf, s->origin[1]); + if (bits & U_ANGLE2) MSG_WriteAngle8i(&buf, s->angles[1]); + if (bits & U_ORIGIN3) MSG_WriteCoord13i(&buf, s->origin[2]); + if (bits & U_ANGLE3) MSG_WriteAngle8i(&buf, s->angles[2]); + if (bits & U_ALPHA) MSG_WriteByte(&buf, s->alpha); + if (bits & U_SCALE) MSG_WriteByte(&buf, s->scale); + if (bits & U_EFFECTS2) MSG_WriteByte(&buf, s->effects >> 8); + if (bits & U_GLOWSIZE) MSG_WriteByte(&buf, s->glowsize); + if (bits & U_GLOWCOLOR) MSG_WriteByte(&buf, s->glowcolor); + if (bits & U_COLORMOD) MSG_WriteByte(&buf, s->colormod); + if (bits & U_FRAME2) MSG_WriteByte(&buf, s->frame >> 8); + if (bits & U_MODEL2) MSG_WriteByte(&buf, s->modelindex >> 8); + + // if the commit is full, we're done this frame + if (msg->cursize + buf.cursize > msg->maxsize) + { + // next frame we will continue where we left off + break; + } + // write the message to the packet + SZ_Write(msg, buf.data, buf.cursize); + } } int EntityState_DeltaBits(const entity_state_t *o, const entity_state_t *n) @@ -120,40 +358,58 @@ void EntityState_WriteExtendBits(sizebuf_t *msg, unsigned int bits) } } -void EntityState_WriteFields(entity_state_t *ent, sizebuf_t *msg, unsigned int bits) +void EntityState_WriteFields(const entity_state_t *ent, sizebuf_t *msg, unsigned int bits) { - // LordHavoc: have to write flags first, as they can modify protocol - if (bits & E_FLAGS) - MSG_WriteByte(msg, ent->flags); - if (ent->flags & RENDER_LOWPRECISION) + if (sv.protocol == PROTOCOL_DARKPLACES2) { if (bits & E_ORIGIN1) - MSG_WriteShort(msg, ent->origin[0]); + MSG_WriteCoord16i(msg, ent->origin[0]); if (bits & E_ORIGIN2) - MSG_WriteShort(msg, ent->origin[1]); + MSG_WriteCoord16i(msg, ent->origin[1]); if (bits & E_ORIGIN3) - MSG_WriteShort(msg, ent->origin[2]); + MSG_WriteCoord16i(msg, ent->origin[2]); + } + else if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5) + { + // LordHavoc: have to write flags first, as they can modify protocol + if (bits & E_FLAGS) + MSG_WriteByte(msg, ent->flags); + if (ent->flags & RENDER_LOWPRECISION) + { + if (bits & E_ORIGIN1) + MSG_WriteCoord16i(msg, ent->origin[0]); + if (bits & E_ORIGIN2) + MSG_WriteCoord16i(msg, ent->origin[1]); + if (bits & E_ORIGIN3) + MSG_WriteCoord16i(msg, ent->origin[2]); + } + else + { + if (bits & E_ORIGIN1) + MSG_WriteCoord32f(msg, ent->origin[0]); + if (bits & E_ORIGIN2) + MSG_WriteCoord32f(msg, ent->origin[1]); + if (bits & E_ORIGIN3) + MSG_WriteCoord32f(msg, ent->origin[2]); + } + } + if (sv.protocol == PROTOCOL_DARKPLACES5 && !(ent->flags & RENDER_LOWPRECISION)) + { if (bits & E_ANGLE1) - MSG_WriteAngle(msg, ent->angles[0]); + MSG_WriteAngle16i(msg, ent->angles[0]); if (bits & E_ANGLE2) - MSG_WriteAngle(msg, ent->angles[1]); + MSG_WriteAngle16i(msg, ent->angles[1]); if (bits & E_ANGLE3) - MSG_WriteAngle(msg, ent->angles[2]); + MSG_WriteAngle16i(msg, ent->angles[2]); } else { - if (bits & E_ORIGIN1) - MSG_WriteFloat(msg, ent->origin[0]); - if (bits & E_ORIGIN2) - MSG_WriteFloat(msg, ent->origin[1]); - if (bits & E_ORIGIN3) - MSG_WriteFloat(msg, ent->origin[2]); if (bits & E_ANGLE1) - MSG_WritePreciseAngle(msg, ent->angles[0]); + MSG_WriteAngle8i(msg, ent->angles[0]); if (bits & E_ANGLE2) - MSG_WritePreciseAngle(msg, ent->angles[1]); + MSG_WriteAngle8i(msg, ent->angles[1]); if (bits & E_ANGLE3) - MSG_WritePreciseAngle(msg, ent->angles[2]); + MSG_WriteAngle8i(msg, ent->angles[2]); } if (bits & E_MODEL1) MSG_WriteByte(msg, ent->modelindex & 0xFF); @@ -179,6 +435,9 @@ void EntityState_WriteFields(entity_state_t *ent, sizebuf_t *msg, unsigned int b MSG_WriteByte(msg, ent->glowsize); if (bits & E_GLOWCOLOR) MSG_WriteByte(msg, ent->glowcolor); + if (sv.protocol == PROTOCOL_DARKPLACES2) + if (bits & E_FLAGS) + MSG_WriteByte(msg, ent->flags); if (bits & E_TAGATTACHMENT) { MSG_WriteShort(msg, ent->tagentity); @@ -197,7 +456,7 @@ void EntityState_WriteFields(entity_state_t *ent, sizebuf_t *msg, unsigned int b MSG_WriteByte(msg, ent->lightpflags); } -void EntityState_WriteUpdate(entity_state_t *ent, sizebuf_t *msg, entity_state_t *delta) +void EntityState_WriteUpdate(const entity_state_t *ent, sizebuf_t *msg, const entity_state_t *delta) { unsigned int bits; if (ent->active) @@ -244,52 +503,52 @@ void EntityState_ReadFields(entity_state_t *e, unsigned int bits) if (cl.protocol == PROTOCOL_DARKPLACES2) { if (bits & E_ORIGIN1) - e->origin[0] = (signed short) MSG_ReadShort(); + e->origin[0] = MSG_ReadCoord16i(); if (bits & E_ORIGIN2) - e->origin[1] = (signed short) MSG_ReadShort(); + e->origin[1] = MSG_ReadCoord16i(); if (bits & E_ORIGIN3) - e->origin[2] = (signed short) MSG_ReadShort(); + e->origin[2] = MSG_ReadCoord16i(); } - else + else if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES3 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5) { if (bits & E_FLAGS) e->flags = MSG_ReadByte(); - if (e->flags & RENDER_LOWPRECISION || cl.protocol == PROTOCOL_DARKPLACES2) + if (e->flags & RENDER_LOWPRECISION) { if (bits & E_ORIGIN1) - e->origin[0] = (signed short) MSG_ReadShort(); + e->origin[0] = MSG_ReadCoord16i(); if (bits & E_ORIGIN2) - e->origin[1] = (signed short) MSG_ReadShort(); + e->origin[1] = MSG_ReadCoord16i(); if (bits & E_ORIGIN3) - e->origin[2] = (signed short) MSG_ReadShort(); + e->origin[2] = MSG_ReadCoord16i(); } else { if (bits & E_ORIGIN1) - e->origin[0] = MSG_ReadFloat(); + e->origin[0] = MSG_ReadCoord32f(); if (bits & E_ORIGIN2) - e->origin[1] = MSG_ReadFloat(); + e->origin[1] = MSG_ReadCoord32f(); if (bits & E_ORIGIN3) - e->origin[2] = MSG_ReadFloat(); + e->origin[2] = MSG_ReadCoord32f(); } } if (cl.protocol == PROTOCOL_DARKPLACES5 && !(e->flags & RENDER_LOWPRECISION)) { if (bits & E_ANGLE1) - e->angles[0] = MSG_ReadPreciseAngle(); + e->angles[0] = MSG_ReadAngle16i(); if (bits & E_ANGLE2) - e->angles[1] = MSG_ReadPreciseAngle(); + e->angles[1] = MSG_ReadAngle16i(); if (bits & E_ANGLE3) - e->angles[2] = MSG_ReadPreciseAngle(); + e->angles[2] = MSG_ReadAngle16i(); } else { if (bits & E_ANGLE1) - e->angles[0] = MSG_ReadAngle(); + e->angles[0] = MSG_ReadAngle8i(); if (bits & E_ANGLE2) - e->angles[1] = MSG_ReadAngle(); + e->angles[1] = MSG_ReadAngle8i(); if (bits & E_ANGLE3) - e->angles[2] = MSG_ReadAngle(); + e->angles[2] = MSG_ReadAngle8i(); } if (bits & E_MODEL1) e->modelindex = (e->modelindex & 0xFF00) | (unsigned int) MSG_ReadByte(); @@ -320,15 +579,15 @@ void EntityState_ReadFields(entity_state_t *e, unsigned int bits) e->flags = MSG_ReadByte(); if (bits & E_TAGATTACHMENT) { - e->tagentity = MSG_ReadShort(); + e->tagentity = (unsigned short) MSG_ReadShort(); e->tagindex = MSG_ReadByte(); } if (bits & E_LIGHT) { - e->light[0] = MSG_ReadShort(); - e->light[1] = MSG_ReadShort(); - e->light[2] = MSG_ReadShort(); - e->light[3] = MSG_ReadShort(); + e->light[0] = (unsigned short) MSG_ReadShort(); + e->light[1] = (unsigned short) MSG_ReadShort(); + e->light[2] = (unsigned short) MSG_ReadShort(); + e->light[3] = (unsigned short) MSG_ReadShort(); } if (bits & E_LIGHTSTYLE) e->lightstyle = MSG_ReadByte(); @@ -385,18 +644,30 @@ void EntityState_ReadFields(entity_state_t *e, unsigned int bits) } } +// (client and server) allocates a new empty database +entityframe_database_t *EntityFrame_AllocDatabase(mempool_t *mempool) +{ + return Mem_Alloc(mempool, sizeof(entityframe_database_t)); +} + +// (client and server) frees the database +void EntityFrame_FreeDatabase(entityframe_database_t *d) +{ + Mem_Free(d); +} + // (server) clears the database to contain no frames (thus delta compression compresses against nothing) -void EntityFrame_ClearDatabase(entity_database_t *d) +void EntityFrame_ClearDatabase(entityframe_database_t *d) { memset(d, 0, sizeof(*d)); } // (server and client) removes frames older than 'frame' from database -void EntityFrame_AckFrame(entity_database_t *d, int frame) +void EntityFrame_AckFrame(entityframe_database_t *d, int frame) { int i; - if (d->ackframe < frame) - d->ackframe = frame; + if (d->ackframenum < frame) + d->ackframenum = frame; for (i = 0;i < d->numframes && d->frames[i].framenum < frame;i++); // ignore outdated frame acks (out of order packets) if (i == 0) @@ -414,27 +685,13 @@ void EntityFrame_Clear(entity_frame_t *f, vec3_t eye, int framenum) f->framenum = framenum; f->numentities = 0; if (eye == NULL) - { VectorClear(f->eye); - } else - { VectorCopy(eye, f->eye); - } -} - -// (server) adds an entity to frame -void EntityFrame_AddEntity(entity_frame_t *f, entity_state_t *s) -{ - if (f->numentities < MAX_ENTITY_DATABASE) - { - f->entitydata[f->numentities] = *s; - f->entitydata[f->numentities++].active = true; - } } // (server and client) reads a frame from the database -void EntityFrame_FetchFrame(entity_database_t *d, int framenum, entity_frame_t *f) +void EntityFrame_FetchFrame(entityframe_database_t *d, int framenum, entity_frame_t *f) { int i, n; EntityFrame_Clear(f, NULL, -1); @@ -454,18 +711,18 @@ void EntityFrame_FetchFrame(entity_database_t *d, int framenum, entity_frame_t * } // (server and client) adds a entity_frame to the database, for future reference -void EntityFrame_AddFrame(entity_database_t *d, entity_frame_t *f) +void EntityFrame_AddFrame(entityframe_database_t *d, vec3_t eye, int framenum, int numentities, const entity_state_t *entitydata) { int n, e; entity_frameinfo_t *info; - VectorCopy(f->eye, d->eye); + VectorCopy(eye, d->eye); // figure out how many entity slots are used already if (d->numframes) { n = d->frames[d->numframes - 1].endentity - d->frames[0].firstentity; - if (n + f->numentities > MAX_ENTITY_DATABASE || d->numframes >= MAX_ENTITY_HISTORY) + if (n + numentities > MAX_ENTITY_DATABASE || d->numframes >= MAX_ENTITY_HISTORY) { // ran out of room, dump database EntityFrame_ClearDatabase(d); @@ -473,14 +730,14 @@ void EntityFrame_AddFrame(entity_database_t *d, entity_frame_t *f) } info = &d->frames[d->numframes]; - info->framenum = f->framenum; + info->framenum = framenum; e = -1000; // make sure we check the newly added frame as well, but we haven't incremented numframes yet for (n = 0;n <= d->numframes;n++) { if (e >= d->frames[n].framenum) { - if (e == f->framenum) + if (e == framenum) Con_Print("EntityFrame_AddFrame: tried to add out of sequence frame to database\n"); else Con_Print("EntityFrame_AddFrame: out of sequence frames in database\n"); @@ -493,40 +750,54 @@ void EntityFrame_AddFrame(entity_database_t *d, entity_frame_t *f) info->firstentity = d->frames[d->numframes - 1].endentity; else info->firstentity = 0; - info->endentity = info->firstentity + f->numentities; + info->endentity = info->firstentity + numentities; d->numframes++; n = info->firstentity % MAX_ENTITY_DATABASE; e = MAX_ENTITY_DATABASE - n; - if (e > f->numentities) - e = f->numentities; - memcpy(d->entitydata + n, f->entitydata, sizeof(entity_state_t) * e); - if (f->numentities > e) - memcpy(d->entitydata, f->entitydata + e, sizeof(entity_state_t) * (f->numentities - e)); + if (e > numentities) + e = numentities; + memcpy(d->entitydata + n, entitydata, sizeof(entity_state_t) * e); + if (numentities > e) + memcpy(d->entitydata, entitydata + e, sizeof(entity_state_t) * (numentities - e)); } // (server) writes a frame to network stream static entity_frame_t deltaframe; // FIXME? -void EntityFrame_Write(entity_database_t *d, entity_frame_t *f, sizebuf_t *msg) +void EntityFrame_WriteFrame(sizebuf_t *msg, entityframe_database_t *d, int numstates, const entity_state_t *states, int viewentnum) { int i, onum, number; entity_frame_t *o = &deltaframe; - entity_state_t *ent, *delta; + const entity_state_t *ent, *delta; + vec3_t eye; + + d->latestframenum++; + + VectorClear(eye); + for (i = 0;i < numstates;i++) + { + if (states[i].number == viewentnum) + { + VectorSet(eye, states[i].origin[0], states[i].origin[1], states[i].origin[2] + 22); + break; + } + } - EntityFrame_AddFrame(d, f); + EntityFrame_AddFrame(d, eye, d->latestframenum, numstates, states); + + EntityFrame_FetchFrame(d, d->ackframenum > 0 ? d->ackframenum : -1, o); - EntityFrame_FetchFrame(d, d->ackframe > 0 ? d->ackframe : -1, o); MSG_WriteByte (msg, svc_entities); MSG_WriteLong (msg, o->framenum); - MSG_WriteLong (msg, f->framenum); - MSG_WriteFloat (msg, f->eye[0]); - MSG_WriteFloat (msg, f->eye[1]); - MSG_WriteFloat (msg, f->eye[2]); + MSG_WriteLong (msg, d->latestframenum); + MSG_WriteFloat (msg, eye[0]); + MSG_WriteFloat (msg, eye[1]); + MSG_WriteFloat (msg, eye[2]); onum = 0; - for (i = 0;i < f->numentities;i++) + for (i = 0;i < numstates;i++) { - ent = f->entitydata + i; + ent = states + i; number = ent->number; for (;onum < o->numentities && o->entitydata[onum].number < number;onum++) { @@ -557,11 +828,16 @@ void EntityFrame_Write(entity_database_t *d, entity_frame_t *f, sizebuf_t *msg) // (client) reads a frame from network stream static entity_frame_t framedata; // FIXME? -void EntityFrame_Read(entity_database_t *d) +void EntityFrame_CL_ReadFrame(void) { - int number, removed; + int i, number, removed; entity_frame_t *f = &framedata, *delta = &deltaframe; entity_state_t *e, *old, *oldend; + entity_t *ent; + entityframe_database_t *d; + if (!cl.entitydatabase) + cl.entitydatabase = EntityFrame_AllocDatabase(cl_entities_mempool); + d = cl.entitydatabase; EntityFrame_Clear(f, NULL, -1); @@ -577,7 +853,7 @@ void EntityFrame_Read(entity_database_t *d) old = delta->entitydata; oldend = old + delta->numentities; // read entities until we hit the magic 0xFFFF end tag - while ((number = (unsigned short) MSG_ReadShort()) != 0xFFFF) + while ((number = (unsigned short) MSG_ReadShort()) != 0xFFFF && !msg_badread) { if (msg_badread) Host_Error("EntityFrame_Read: read error\n"); @@ -634,12 +910,42 @@ void EntityFrame_Read(entity_database_t *d) f->entitydata[f->numentities] = *old++; f->entitydata[f->numentities++].time = cl.mtime[0]; } - EntityFrame_AddFrame(d, f); + EntityFrame_AddFrame(d, f->eye, f->framenum, f->numentities, f->entitydata); + + memset(cl_entities_active, 0, cl_max_entities * sizeof(qbyte)); + number = 1; + for (i = 0;i < f->numentities;i++) + { + for (;number < f->entitydata[i].number;number++) + { + if (cl_entities_active[number]) + { + cl_entities_active[number] = false; + cl_entities[number].state_current.active = false; + } + } + // update the entity + ent = &cl_entities[number]; + ent->state_previous = ent->state_current; + ent->state_current = f->entitydata[i]; + CL_MoveLerpEntityStates(ent); + // the entity lives again... + cl_entities_active[number] = true; + number++; + } + for (;number < cl_max_entities;number++) + { + if (cl_entities_active[number]) + { + cl_entities_active[number] = false; + cl_entities[number].state_current.active = false; + } + } } // (client) returns the frame number of the most recent frame recieved -int EntityFrame_MostRecentlyRecievedFrameNum(entity_database_t *d) +int EntityFrame_MostRecentlyRecievedFrameNum(entityframe_database_t *d) { if (d->numframes) return d->frames[d->numframes - 1].framenum; @@ -652,7 +958,7 @@ int EntityFrame_MostRecentlyRecievedFrameNum(entity_database_t *d) -entity_state_t *EntityFrame4_GetReferenceEntity(entity_database4_t *d, int number) +entity_state_t *EntityFrame4_GetReferenceEntity(entityframe4_database_t *d, int number) { if (d->maxreferenceentities <= number) { @@ -675,7 +981,7 @@ entity_state_t *EntityFrame4_GetReferenceEntity(entity_database4_t *d, int numbe return d->referenceentity + number; } -void EntityFrame4_AddCommitEntity(entity_database4_t *d, entity_state_t *s) +void EntityFrame4_AddCommitEntity(entityframe4_database_t *d, const entity_state_t *s) { // resize commit's entity list if full if (d->currentcommit->maxentities <= d->currentcommit->numentities) @@ -692,9 +998,9 @@ void EntityFrame4_AddCommitEntity(entity_database4_t *d, entity_state_t *s) d->currentcommit->entity[d->currentcommit->numentities++] = *s; } -entity_database4_t *EntityFrame4_AllocDatabase(mempool_t *pool) +entityframe4_database_t *EntityFrame4_AllocDatabase(mempool_t *pool) { - entity_database4_t *d; + entityframe4_database_t *d; d = Mem_Alloc(pool, sizeof(*d)); d->mempool = pool; EntityFrame4_ResetDatabase(d); @@ -702,7 +1008,7 @@ entity_database4_t *EntityFrame4_AllocDatabase(mempool_t *pool) return d; } -void EntityFrame4_FreeDatabase(entity_database4_t *d) +void EntityFrame4_FreeDatabase(entityframe4_database_t *d) { int i; for (i = 0;i < MAX_ENTITY_HISTORY;i++) @@ -713,7 +1019,7 @@ void EntityFrame4_FreeDatabase(entity_database4_t *d) Mem_Free(d); } -void EntityFrame4_ResetDatabase(entity_database4_t *d) +void EntityFrame4_ResetDatabase(entityframe4_database_t *d) { int i; d->ackframenum = -1; @@ -724,7 +1030,7 @@ void EntityFrame4_ResetDatabase(entity_database4_t *d) d->referenceentity[i] = defaultstate; } -int EntityFrame4_AckFrame(entity_database4_t *d, int framenum) +int EntityFrame4_AckFrame(entityframe4_database_t *d, int framenum) { int i, j, found; entity_database4_commit_t *commit; @@ -783,43 +1089,20 @@ int EntityFrame4_AckFrame(entity_database4_t *d, int framenum) return found; } -int EntityFrame4_SV_WriteFrame_Entity(entity_database4_t *d, sizebuf_t *msg, int maxbytes, entity_state_t *s) -{ - qbyte data[128]; - sizebuf_t buf; - entity_state_t *e; - // prepare the buffer - memset(&buf, 0, sizeof(buf)); - buf.data = data; - buf.maxsize = sizeof(data); - // make the update message - e = EntityFrame4_GetReferenceEntity(d, s->number); - EntityState_WriteUpdate(s, &buf, e); - // if the message is empty, skip out now - if (!buf.cursize) - return true; - // if the commit is full, we're done - if (msg->cursize + buf.cursize + 2 >= min(msg->maxsize, maxbytes)) - return false; - // add the entity to the commit - EntityFrame4_AddCommitEntity(d, s); - // write the message to the packet - SZ_Write(msg, buf.data, buf.cursize); - // carry on - return true; -} - -extern void CL_MoveLerpEntityStates(entity_t *ent); -void EntityFrame4_CL_ReadFrame(entity_database4_t *d) +void EntityFrame4_CL_ReadFrame(void) { int i, n, cnumber, referenceframenum, framenum, enumber, done, stopnumber, skip = false; entity_state_t *s; + entityframe4_database_t *d; + if (!cl.entitydatabase4) + cl.entitydatabase4 = EntityFrame4_AllocDatabase(cl_entities_mempool); + d = cl.entitydatabase4; // read the number of the frame this refers to referenceframenum = MSG_ReadLong(); // read the number of this frame framenum = MSG_ReadLong(); // read the start number - enumber = MSG_ReadShort(); + enumber = (unsigned short) MSG_ReadShort(); if (developer_networkentities.integer >= 1) { Con_Printf("recv svc_entities num:%i ref:%i database: ref:%i commits:", framenum, referenceframenum, d->referenceframenum); @@ -931,77 +1214,198 @@ void EntityFrame4_CL_ReadFrame(entity_database4_t *d) EntityFrame4_ResetDatabase(d); } +void EntityFrame4_WriteFrame(sizebuf_t *msg, entityframe4_database_t *d, int numstates, const entity_state_t *states) +{ + const entity_state_t *e, *s; + entity_state_t inactiveentitystate; + int i, n, startnumber; + sizebuf_t buf; + qbyte data[128]; + // if there isn't enough space to accomplish anything, skip it + if (msg->cursize + 24 > msg->maxsize) + return; + // prepare the buffer + memset(&buf, 0, sizeof(buf)); + buf.data = data; + buf.maxsize = sizeof(data); + for (i = 0;i < MAX_ENTITY_HISTORY;i++) + if (!d->commit[i].numentities) + break; + // if commit buffer full, just don't bother writing an update this frame + if (i == MAX_ENTITY_HISTORY) + return; + d->currentcommit = d->commit + i; -/* -int EntityState5_PriorityForChangedBits(int changedbits) -{ - if (changedbits & E5_ISACTIVE) - return 2; - else if (changedbits & (E5_FLAGS | E5_ATTACHMENT | E5_MODEL | E5_SKIN | E5_EXTERIORFORENTITY | E5_COLORMAP | E5_LIGHT | E5_GLOW | E5_EFFECTS | E5_ORIGIN | E5_ANGLES | E5_FRAME | E5_ALPHA | E5_SCALE)) - return 1; - else - return 0; -} + // this state's number gets played around with later + inactiveentitystate = defaultstate; -void EntityState5_WriteUpdate(int number, entitystate_t *s, int changedbits, sizebuf_t *msg) -{ - bits = 0; - if (!s->active) - MSG_WriteShort(msg, number | 0x8000); + d->currentcommit->numentities = 0; + d->currentcommit->framenum = ++d->latestframenumber; + MSG_WriteByte(msg, svc_entities); + MSG_WriteLong(msg, d->referenceframenum); + MSG_WriteLong(msg, d->currentcommit->framenum); + if (developer_networkentities.integer >= 1) + { + Con_Printf("send svc_entities num:%i ref:%i (database: ref:%i commits:", d->currentcommit->framenum, d->referenceframenum, d->referenceframenum); + for (i = 0;i < MAX_ENTITY_HISTORY;i++) + if (d->commit[i].numentities) + Con_Printf(" %i", d->commit[i].framenum); + Con_Print(")\n"); + } + if (d->currententitynumber >= sv.max_edicts) + startnumber = 1; else + startnumber = bound(1, d->currententitynumber, sv.max_edicts - 1); + MSG_WriteShort(msg, startnumber); + // reset currententitynumber so if the loop does not break it we will + // start at beginning next frame (if it does break, it will set it) + d->currententitynumber = 1; + for (i = 0, n = startnumber;n < sv.max_edicts;n++) { - bits |= E5_ISACTIVE; - if (changedbits & E5_ORIGIN) + // find the old state to delta from + e = EntityFrame4_GetReferenceEntity(d, n); + // prepare the buffer + SZ_Clear(&buf); + // entity exists, build an update (if empty there is no change) + // find the state in the list + for (;i < numstates && states[i].number < n;i++); + // make the message + s = states + i; + if (s->number == n) { - bits |= E5_ORIGIN; - if (s->origin[0] < -4096 || s->origin[0] >= 4096 || s->origin[1] < -4096 || s->origin[1] >= 4096 || s->origin[2] < -4096 || s->origin[2] >= 4096) - bits |= E5_ORIGIN32; + // build the update + EntityState_WriteUpdate(s, &buf, e); } - if (changedbits & E5_ANGLES) + else { - bits |= E5_ANGLES; - if (!(s->flags & RENDERFLAGS_LOWPRECISION)) - bits |= E5_ANGLES16; + inactiveentitystate.number = n; + s = &inactiveentitystate; + if (e->active) + { + // entity used to exist but doesn't anymore, send remove + MSG_WriteShort(&buf, n | 0x8000); + } } - if (changedbits & E5_MODEL) + // if the commit is full, we're done this frame + if (msg->cursize + buf.cursize > msg->maxsize - 4) { - bits |= E5_MODEL; - if (s->modelindex >= 256) - bits |= E5_MODEL16; + // next frame we will continue where we left off + break; } - if (changedbits & E5_FRAME) + // add the entity to the commit + EntityFrame4_AddCommitEntity(d, s); + // if the message is empty, skip out now + if (buf.cursize) { - bits |= E5_FRAME; - if (s->frame >= 256) - bits |= E5_FRAME16; + // write the message to the packet + SZ_Write(msg, buf.data, buf.cursize); } - if (changedbits & E5_SKIN) - bits |= E5_SKIN; - if (changedbits & E5_EFFECTS) + } + d->currententitynumber = n; + + // remove world message (invalid, and thus a good terminator) + MSG_WriteShort(msg, 0x8000); + // write the number of the end entity + MSG_WriteShort(msg, d->currententitynumber); + // just to be sure + d->currentcommit = NULL; +} + + + + +#define E5_PROTOCOL_PRIORITYLEVELS 32 + +entityframe5_database_t *EntityFrame5_AllocDatabase(mempool_t *pool) +{ + entityframe5_database_t *d; + d = Mem_Alloc(pool, sizeof(*d)); + EntityFrame5_ResetDatabase(d); + return d; +} + +void EntityFrame5_FreeDatabase(entityframe5_database_t *d) +{ + Mem_Free(d); +} + +void EntityFrame5_ResetDatabase(entityframe5_database_t *d) +{ + int i; + memset(d, 0, sizeof(*d)); + d->latestframenum = 0; + d->ackframenum = -1; + for (i = 0;i < MAX_EDICTS;i++) + d->states[i] = defaultstate; +} + + +int EntityState5_Priority(entityframe5_database_t *d, entity_state_t *view, entity_state_t *s, int changedbits, int age) +{ + int lowprecision, limit, priority; + double distance; + if (!changedbits) + return 0; + if (!s->active/* && changedbits & E5_FULLUPDATE*/) + return E5_PROTOCOL_PRIORITYLEVELS - 1; + // check whole attachment chain to judge relevance to player + lowprecision = false; + for (limit = 0;limit < 256;limit++) + { + if (s == view) + return E5_PROTOCOL_PRIORITYLEVELS - 1; + if (s->flags & RENDER_VIEWMODEL) + return E5_PROTOCOL_PRIORITYLEVELS - 1; + if (s->flags & RENDER_LOWPRECISION) + lowprecision = true; + if (!s->tagentity) { - bits |= E5_EFFECTS; - if (s->modelindex >= 256) - bits |= E5_MODEL16; + if (VectorCompare(s->origin, view->origin)) + return E5_PROTOCOL_PRIORITYLEVELS - 1; + break; + } + s = d->states + s->tagentity; + } + if (limit >= 256) + Con_Printf("Protocol: Runaway loop recursing tagentity links on entity %i\n", s->number); + // it's not a viewmodel for this client + distance = VectorDistance(view->origin, s->origin); + priority = (E5_PROTOCOL_PRIORITYLEVELS / 2) + age - (int)(distance * (E5_PROTOCOL_PRIORITYLEVELS / 16384.0f)); + if (lowprecision) + priority -= (E5_PROTOCOL_PRIORITYLEVELS / 4); + //if (changedbits & E5_FULLUPDATE) + // priority += 4; + //if (changedbits & (E5_ATTACHMENT | E5_MODEL | E5_FLAGS | E5_COLORMAP)) + // priority += 4; + return (int) bound(1, priority, E5_PROTOCOL_PRIORITYLEVELS - 1); +} + +void EntityState5_WriteUpdate(int number, const entity_state_t *s, int changedbits, sizebuf_t *msg) +{ + unsigned int bits = 0; + if (!s->active) + MSG_WriteShort(msg, number | 0x8000); + else + { + bits = changedbits; + if ((bits & E5_ORIGIN) && (s->origin[0] < -4096 || s->origin[0] >= 4096 || s->origin[1] < -4096 || s->origin[1] >= 4096 || s->origin[2] < -4096 || s->origin[2] >= 4096)) + bits |= E5_ORIGIN32; + if ((bits & E5_ANGLES) && !(s->flags & RENDER_LOWPRECISION)) + bits |= E5_ANGLES16; + if ((bits & E5_MODEL) && s->modelindex >= 256) + bits |= E5_MODEL16; + if ((bits & E5_FRAME) && s->frame >= 256) + bits |= E5_FRAME16; + if (bits & E5_EFFECTS) + { + if (s->effects >= 65536) + bits |= E5_EFFECTS32; + else if (s->effects >= 256) + bits |= E5_EFFECTS16; } - if (changedbits & E5_FLAGS) - bits |= E5_FLAGS; - if (changedbits & E5_ALPHA) - bits |= E5_ALPHA; - if (changedbits & E5_SCALE) - bits |= E5_SCALE; - if (changedbits & E5_ATTACHMENT) - bits |= E5_ATTACHMENT; - if (changedbits & E5_EXTERIORFORENTITY) - bits |= E5_EXTERIORFORENTITY; - if (changedbits & E5_LIGHT) - bits |= E5_LIGHT; - if (changedbits & E5_COLORMAP) - bits |= E5_COLORMAP; - if (changedbits & E5_GLOW) - bits |= E5_GLOW; if (bits >= 256) bits |= E5_EXTEND1; if (bits >= 65536) @@ -1022,30 +1426,30 @@ void EntityState5_WriteUpdate(int number, entitystate_t *s, int changedbits, siz { if (bits & E5_ORIGIN32) { - MSG_WriteFloat(msg, s->origin[0]); - MSG_WriteFloat(msg, s->origin[1]); - MSG_WriteFloat(msg, s->origin[2]); + MSG_WriteCoord32f(msg, s->origin[0]); + MSG_WriteCoord32f(msg, s->origin[1]); + MSG_WriteCoord32f(msg, s->origin[2]); } else { - MSG_WriteShort(msg, (int)floor(s->origin[0] * 8 + 0.5f)); - MSG_WriteShort(msg, (int)floor(s->origin[1] * 8 + 0.5f)); - MSG_WriteShort(msg, (int)floor(s->origin[2] * 8 + 0.5f)); + MSG_WriteCoord13i(msg, s->origin[0]); + MSG_WriteCoord13i(msg, s->origin[1]); + MSG_WriteCoord13i(msg, s->origin[2]); } } if (bits & E5_ANGLES) { if (bits & E5_ANGLES16) { - MSG_WriteShort(msg, (int)floor(s->angles[0] * (65536.0f / 360.0f) + 0.5f)); - MSG_WriteShort(msg, (int)floor(s->angles[1] * (65536.0f / 360.0f) + 0.5f)); - MSG_WriteShort(msg, (int)floor(s->angles[2] * (65536.0f / 360.0f) + 0.5f)); + MSG_WriteAngle16i(msg, s->angles[0]); + MSG_WriteAngle16i(msg, s->angles[1]); + MSG_WriteAngle16i(msg, s->angles[2]); } else { - MSG_WriteByte(msg, (int)floor(s->angles[0] * (256.0f / 360.0f) + 0.5f)); - MSG_WriteByte(msg, (int)floor(s->angles[1] * (256.0f / 360.0f) + 0.5f)); - MSG_WriteByte(msg, (int)floor(s->angles[2] * (256.0f / 360.0f) + 0.5f)); + MSG_WriteAngle8i(msg, s->angles[0]); + MSG_WriteAngle8i(msg, s->angles[1]); + MSG_WriteAngle8i(msg, s->angles[2]); } } if (bits & E5_MODEL) @@ -1063,7 +1467,7 @@ void EntityState5_WriteUpdate(int number, entitystate_t *s, int changedbits, siz MSG_WriteByte(msg, s->frame); } if (bits & E5_SKIN) - MSG_WriteByte(msg, s->flags); + MSG_WriteByte(msg, s->skin); if (bits & E5_EFFECTS) { if (bits & E5_EFFECTS32) @@ -1074,25 +1478,25 @@ void EntityState5_WriteUpdate(int number, entitystate_t *s, int changedbits, siz MSG_WriteByte(msg, s->effects); } if (bits & E5_ALPHA) - MSG_WriteByte(msg, s->flags); + MSG_WriteByte(msg, s->alpha); if (bits & E5_SCALE) - MSG_WriteByte(msg, s->flags); + MSG_WriteByte(msg, s->scale); + if (bits & E5_COLORMAP) + MSG_WriteByte(msg, s->colormap); if (bits & E5_ATTACHMENT) { MSG_WriteShort(msg, s->tagentity); MSG_WriteByte(msg, s->tagindex); } - if (bits & E5_EXTERIORFORENTITY) - MSG_WriteShort(msg, s->tagentity); if (bits & E5_LIGHT) { MSG_WriteShort(msg, s->light[0]); MSG_WriteShort(msg, s->light[1]); MSG_WriteShort(msg, s->light[2]); MSG_WriteShort(msg, s->light[3]); + MSG_WriteByte(msg, s->lightstyle); + MSG_WriteByte(msg, s->lightpflags); } - if (bits & E5_COLORMAP) - MSG_WriteByte(msg, s->colormap); if (bits & E5_GLOW) { MSG_WriteByte(msg, s->glowsize); @@ -1101,30 +1505,201 @@ void EntityState5_WriteUpdate(int number, entitystate_t *s, int changedbits, siz } } -int EntityFrame5_ReadUpdate(void) +void EntityState5_ReadUpdate(entity_state_t *s) { - number = MSG_ReadShort(); - e = cl_entities + (number & 0x7FFF); - e->state_previous = e->state_current; - if (number & 0x8000) + int bits; + bits = MSG_ReadByte(); + if (bits & E5_EXTEND1) { - if (number == 0x8000) + bits |= MSG_ReadByte() << 8; + if (bits & E5_EXTEND2) { - // end of entity list - return false; + bits |= MSG_ReadByte() << 16; + if (bits & E5_EXTEND3) + bits |= MSG_ReadByte() << 24; } - // remove - number &= 0x7FFF; - e->state_current = defaultstate; - e->state_current.number = number; - return true; } - else + if (bits & E5_FULLUPDATE) + { + *s = defaultstate; + s->active = true; + } + if (bits & E5_FLAGS) + s->flags = MSG_ReadByte(); + if (bits & E5_ORIGIN) + { + if (bits & E5_ORIGIN32) + { + s->origin[0] = MSG_ReadCoord32f(); + s->origin[1] = MSG_ReadCoord32f(); + s->origin[2] = MSG_ReadCoord32f(); + } + else + { + s->origin[0] = MSG_ReadCoord13i(); + s->origin[1] = MSG_ReadCoord13i(); + s->origin[2] = MSG_ReadCoord13i(); + } + } + if (bits & E5_ANGLES) + { + if (bits & E5_ANGLES16) + { + s->angles[0] = MSG_ReadAngle16i(); + s->angles[1] = MSG_ReadAngle16i(); + s->angles[2] = MSG_ReadAngle16i(); + } + else + { + s->angles[0] = MSG_ReadAngle8i(); + s->angles[1] = MSG_ReadAngle8i(); + s->angles[2] = MSG_ReadAngle8i(); + } + } + if (bits & E5_MODEL) + { + if (bits & E5_MODEL16) + s->modelindex = (unsigned short) MSG_ReadShort(); + else + s->modelindex = MSG_ReadByte(); + } + if (bits & E5_FRAME) { + if (bits & E5_FRAME16) + s->frame = (unsigned short) MSG_ReadShort(); + else + s->frame = MSG_ReadByte(); + } + if (bits & E5_SKIN) + s->skin = MSG_ReadByte(); + if (bits & E5_EFFECTS) + { + if (bits & E5_EFFECTS32) + s->effects = (unsigned int) MSG_ReadLong(); + else if (bits & E5_EFFECTS16) + s->effects = (unsigned short) MSG_ReadShort(); + else + s->effects = MSG_ReadByte(); + } + if (bits & E5_ALPHA) + s->alpha = MSG_ReadByte(); + if (bits & E5_SCALE) + s->alpha = MSG_ReadByte(); + if (bits & E5_COLORMAP) + s->colormap = MSG_ReadByte(); + if (bits & E5_ATTACHMENT) + { + s->tagentity = (unsigned short) MSG_ReadShort(); + s->tagindex = MSG_ReadByte(); + } + if (bits & E5_LIGHT) + { + s->light[0] = (unsigned short) MSG_ReadShort(); + s->light[1] = (unsigned short) MSG_ReadShort(); + s->light[2] = (unsigned short) MSG_ReadShort(); + s->light[3] = (unsigned short) MSG_ReadShort(); + s->lightstyle = MSG_ReadByte(); + s->lightpflags = MSG_ReadByte(); + } + if (bits & E5_GLOW) + { + s->glowsize = MSG_ReadByte(); + s->glowcolor = MSG_ReadByte(); + } + + + if (developer_networkentities.integer >= 2) + { + Con_Printf("ReadFields e%i", s->number); + + if (bits & E5_ORIGIN) + Con_Printf(" E5_ORIGIN %f %f %f", s->origin[0], s->origin[1], s->origin[2]); + if (bits & E5_ANGLES) + Con_Printf(" E5_ANGLES %f %f %f", s->angles[0], s->angles[1], s->angles[2]); + if (bits & E5_MODEL) + Con_Printf(" E5_MODEL %i", s->modelindex); + if (bits & E5_FRAME) + Con_Printf(" E5_FRAME %i", s->frame); + if (bits & E5_SKIN) + Con_Printf(" E5_SKIN %i", s->skin); + if (bits & E5_EFFECTS) + Con_Printf(" E5_EFFECTS %i", s->effects); + if (bits & E5_FLAGS) + { + Con_Printf(" E5_FLAGS %i (", s->flags); + if (s->flags & RENDER_STEP) + Con_Print(" STEP"); + if (s->flags & RENDER_GLOWTRAIL) + Con_Print(" GLOWTRAIL"); + if (s->flags & RENDER_VIEWMODEL) + Con_Print(" VIEWMODEL"); + if (s->flags & RENDER_EXTERIORMODEL) + Con_Print(" EXTERIORMODEL"); + if (s->flags & RENDER_LOWPRECISION) + Con_Print(" LOWPRECISION"); + if (s->flags & RENDER_COLORMAPPED) + Con_Print(" COLORMAPPED"); + if (s->flags & RENDER_SHADOW) + Con_Print(" SHADOW"); + if (s->flags & RENDER_LIGHT) + Con_Print(" LIGHT"); + Con_Print(")"); + } + if (bits & E5_ALPHA) + Con_Printf(" E5_ALPHA %f", s->alpha / 255.0f); + if (bits & E5_SCALE) + Con_Printf(" E5_SCALE %f", s->scale / 16.0f); + if (bits & E5_COLORMAP) + Con_Printf(" E5_COLORMAP %i", s->colormap); + if (bits & E5_ATTACHMENT) + Con_Printf(" E5_ATTACHMENT e%i:%i", s->tagentity, s->tagindex); + if (bits & E5_LIGHT) + Con_Printf(" E5_LIGHT %i:%i:%i:%i %i:%i", s->light[0], s->light[1], s->light[2], s->light[3], s->lightstyle, s->lightpflags); + if (bits & E5_GLOW) + Con_Printf(" E5_GLOW %i:%i", s->glowsize * 4, s->glowcolor); + Con_Print("\n"); } } -int cl_entityframe5_lastreceivedframenum; +int EntityState5_DeltaBits(const entity_state_t *o, const entity_state_t *n) +{ + unsigned int bits = 0; + if (n->active) + { + if (!o->active) + bits |= E5_FULLUPDATE; + if (!VectorCompare(o->origin, n->origin)) + bits |= E5_ORIGIN; + if (!VectorCompare(o->angles, n->angles)) + bits |= E5_ANGLES; + if (o->modelindex != n->modelindex) + bits |= E5_MODEL; + if (o->frame != n->frame) + bits |= E5_FRAME; + if (o->skin != n->skin) + bits |= E5_SKIN; + if (o->effects != n->effects) + bits |= E5_EFFECTS; + if (o->flags != n->flags) + bits |= E5_FLAGS; + if (o->alpha != n->alpha) + bits |= E5_ALPHA; + if (o->scale != n->scale) + bits |= E5_SCALE; + if (o->colormap != n->colormap) + bits |= E5_COLORMAP; + if (o->tagentity != n->tagentity || o->tagindex != n->tagindex) + bits |= E5_ATTACHMENT; + if (o->light[0] != n->light[0] || o->light[1] != n->light[1] || o->light[2] != n->light[2] || o->light[3] != n->light[3] || o->lightstyle != n->lightstyle || o->lightpflags != n->lightpflags) + bits |= E5_LIGHT; + if (o->glowsize != n->glowsize || o->glowcolor != n->glowcolor) + bits |= E5_GLOW; + } + else + if (o->active) + bits |= E5_FULLUPDATE; + return bits; +} void EntityFrame5_CL_ReadFrame(void) { @@ -1132,10 +1707,10 @@ void EntityFrame5_CL_ReadFrame(void) entity_t *ent; entity_state_t *s; // read the number of this frame to echo back in next input packet - cl_entityframe5_lastreceivedframenum = MSG_ReadLong(); + cl.latestframenum = MSG_ReadLong(); // read entity numbers until we find a 0x8000 // (which would be remove world entity, but is actually a terminator) - while ((n = MSG_ReadShort()) != 0x8000) + while ((n = (unsigned short)MSG_ReadShort()) != 0x8000 && !msg_badread) { // get the entity number and look it up enumber = n & 0x7FFF; @@ -1152,8 +1727,7 @@ void EntityFrame5_CL_ReadFrame(void) else { // update entity - s->active = true; - EntityState_ReadFields(s, EntityState_ReadExtendBits()); + EntityState5_ReadUpdate(s); } // set the cl_entities_active flag cl_entities_active[enumber] = s->active; @@ -1175,43 +1749,14 @@ void EntityFrame5_CL_ReadFrame(void) } } -#define ENTITYFRAME5_MAXPACKETLOGS 64 -#define ENTITYFRAME5_MAXSTATES 128 - -typedef struct entityframe5_state_s -{ - unsigned short entitynumber; - qbyte active; - qbyte activedirtybit; - int dirtybits; -} -entityframe5_state_t; - -typedef struct entityframe5_packetlog_s -{ - int packetnumber; - int numstates; - entityframe5_state_t states[ENTITYFRAME5_MAXSTATES]; -} -entityframe5_packetlog_t; - -typedef struct entityframe5_s -{ - int ackedframenum; - entityframe5_packetlog_t packetlog[ENTITYFRAME5_MAXPACKETLOGS]; - qbyte activedirtybits[(MAX_EDICTS + 7) / 8]; - int dirtybits[MAX_EDICTS]; -} -entityframe5_t; - -void EntityFrame5_AckFrame(entityframe5_t *d, int framenum) +void EntityFrame5_AckFrame(entityframe5_database_t *d, int framenum, int viewentnum) { - int i, j, k, l, dirtybits, activedirtybit; - entityframe5_state_t *s, *s2; + int i, j, k, l, bits; + entityframe5_changestate_t *s, *s2; entityframe5_packetlog_t *p, *p2; - if (framenum >= d->ackedframenum) + if (framenum <= d->ackframenum) return; - d->ackedframenum = framenum; + d->ackframenum = framenum; // scan for packets made obsolete by this ack for (i = 0, p = d->packetlog;i < ENTITYFRAME5_MAXPACKETLOGS;i++, p++) { @@ -1225,37 +1770,36 @@ void EntityFrame5_AckFrame(entityframe5_t *d, int framenum) // already obsolete due to a later update. if (p->packetnumber < framenum) { - // packet was lost - merge dirtybits into the main array so they + // packet was lost - merge deltabits into the main array so they // will be re-sent, but only if there is no newer update of that // bit in the logs (as those will arrive before this update) for (j = 0, s = p->states;j < p->numstates;j++, s++) { - activedirtybit = s->activedirtybit; - dirtybits = s->dirtybits; - // check for any newer updates to this entity - for (k = 0, p2 = d->packetlog;k < ENTITYFRAME5_MAXPACKETLOGS;k++, p2++) + // check for any newer updates to this entity and mask off any + // overlapping bits (we don't need to send something again if + // it has already been sent more recently) + bits = s->bits & ~d->deltabits[s->number]; + for (k = 0, p2 = d->packetlog;k < ENTITYFRAME5_MAXPACKETLOGS && bits;k++, p2++) { if (p2->packetnumber > framenum) { for (l = 0, s2 = p2->states;l < p2->numstates;l++, p2++) { - if (s2->entitynumber == s->entitynumber) + if (s2->number == s->number) { - activedirtybit &= ~s2->activedirtybit; - dirtybits &= ~s2->dirtybits; + bits &= ~s2->bits; break; } } - if (!activedirtybit && !dirtybits) - break; } } // if the bits haven't all been cleared, there were some bits // lost with this packet, so set them again now - if (activedirtybit) - d->activedirtybits[s->entitynumber / 8] |= 1 << (s->entitynumber & 7); - if (dirtybits) - d->dirtybits[s->entitynumber] |= dirtybits; + if (bits) + { + d->deltabits[s->number] |= bits; + d->priorities[s->number] = EntityState5_Priority(d, d->states + viewentnum, d->states + s->number, d->deltabits[s->number], d->latestframenum - d->updateframenum[s->number]); + } } } // delete this packet log as it is now obsolete @@ -1263,8 +1807,129 @@ void EntityFrame5_AckFrame(entityframe5_t *d, int framenum) } } -void EntityFrame5_WriteFrame(sizebuf_t *msg, int numstates, entity_state_t *states) +int entityframe5_prioritychaincounts[E5_PROTOCOL_PRIORITYLEVELS]; +unsigned short entityframe5_prioritychains[E5_PROTOCOL_PRIORITYLEVELS][ENTITYFRAME5_MAXSTATES]; + +void EntityFrame5_WriteFrame(sizebuf_t *msg, entityframe5_database_t *d, int numstates, const entity_state_t *states, int viewentnum) { + const entity_state_t *n; + int i, num, l, framenum, packetlognumber, priority; + sizebuf_t buf; + qbyte data[128]; + entityframe5_packetlog_t *packetlog; + + framenum = d->latestframenum + 1; + + // prepare the buffer + memset(&buf, 0, sizeof(buf)); + buf.data = data; + buf.maxsize = sizeof(data); + + // detect changes in states + num = 0; + for (i = 0, n = states;i < numstates;i++, n++) + { + // mark gaps in entity numbering as removed entities + for (;num < n->number;num++) + { + // if the entity used to exist, clear it + if (CHECKPVSBIT(d->visiblebits, num)) + { + CLEARPVSBIT(d->visiblebits, num); + d->deltabits[num] = E5_FULLUPDATE; + d->priorities[num] = EntityState5_Priority(d, d->states + viewentnum, d->states + num, d->deltabits[num], framenum - d->updateframenum[num]); + d->states[num] = defaultstate; + d->states[num].number = num; + } + } + // update the entity state data + if (!CHECKPVSBIT(d->visiblebits, num)) + { + // entity just spawned in, don't let it completely hog priority + // because of being ancient on the first frame + d->updateframenum[num] = framenum; + } + SETPVSBIT(d->visiblebits, num); + d->deltabits[num] |= EntityState5_DeltaBits(d->states + num, n); + d->priorities[num] = EntityState5_Priority(d, d->states + viewentnum, d->states + num, d->deltabits[num], framenum - d->updateframenum[num]); + d->states[num] = *n; + d->states[num].number = num; + // advance to next entity so the next iteration doesn't immediately remove it + num++; + } + // all remaining entities are dead + for (;num < MAX_EDICTS;num++) + { + if (CHECKPVSBIT(d->visiblebits, num)) + { + CLEARPVSBIT(d->visiblebits, num); + d->deltabits[num] = E5_FULLUPDATE; + d->priorities[num] = EntityState5_Priority(d, d->states + viewentnum, d->states + num, d->deltabits[num], framenum - d->updateframenum[num]); + d->states[num] = defaultstate; + d->states[num].number = num; + } + } + + // build lists of entities by priority level + memset(entityframe5_prioritychaincounts, 0, sizeof(entityframe5_prioritychaincounts)); + l = 0; + for (num = 0;num < MAX_EDICTS;num++) + { + if (d->priorities[num]) + { + l = num; + priority = d->priorities[num]; + if (entityframe5_prioritychaincounts[priority] < ENTITYFRAME5_MAXSTATES) + entityframe5_prioritychains[priority][entityframe5_prioritychaincounts[priority]++] = num; + } + } + + // return early if there are no entities to send this time + if (l == 0) + return; + + d->latestframenum = framenum; + MSG_WriteByte(msg, svc_entities); + MSG_WriteLong(msg, framenum); + + // if packet log is full, an empty update is still written + // (otherwise the client might have nothing to ack to remove packetlogs) + for (packetlognumber = 0, packetlog = d->packetlog;packetlognumber < ENTITYFRAME5_MAXPACKETLOGS;packetlognumber++, packetlog++) + if (packetlog->packetnumber == 0) + break; + if (packetlognumber < ENTITYFRAME5_MAXPACKETLOGS) + { + // write to packet and log + packetlog->packetnumber = framenum; + packetlog->numstates = 0; + for (priority = E5_PROTOCOL_PRIORITYLEVELS - 1;priority >= 0 && packetlog->numstates < ENTITYFRAME5_MAXSTATES;priority--) + { + for (i = 0;i < entityframe5_prioritychaincounts[priority] && packetlog->numstates < ENTITYFRAME5_MAXSTATES;i++) + { + num = entityframe5_prioritychains[priority][i]; + n = d->states + num; + if (d->deltabits[num] & E5_FULLUPDATE) + d->deltabits[num] = E5_FULLUPDATE | EntityState5_DeltaBits(&defaultstate, n); + buf.cursize = 0; + EntityState5_WriteUpdate(num, n, d->deltabits[num], &buf); + // if the entity won't fit, try the next one + if (msg->cursize + buf.cursize + 2 > msg->maxsize) + continue; + // write entity to the packet + SZ_Write(msg, buf.data, buf.cursize); + // mark age on entity for prioritization + d->updateframenum[num] = framenum; + // log entity so deltabits can be restored later if lost + packetlog->states[packetlog->numstates].number = num; + packetlog->states[packetlog->numstates].bits = d->deltabits[num]; + packetlog->numstates++; + // clear deltabits and priority so it won't be sent again + d->deltabits[num] = 0; + d->priorities[num] = 0; + } + } + } + + MSG_WriteShort(msg, 0x8000); } -*/ diff --git a/protocol.h b/protocol.h index 3f9e77c6..e8fa52f4 100644 --- a/protocol.h +++ b/protocol.h @@ -22,14 +22,25 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifndef PROTOCOL_H #define PROTOCOL_H +// LordHavoc: I own protocol ranges 96, 97, 3500-3599 + +// quake or darkplaces extended quake entity protocol +// (still used by TomazQuake and others) #define PROTOCOL_QUAKE 15 + +// neh_gl entity protocol +// (failed QSG protocol, used only by nehahra movie) #define PROTOCOL_NEHAHRAMOVIE 250 + +// entityframe protocol #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 + +// entityframe4 protocol #define PROTOCOL_DARKPLACES3 3500 #define PROTOCOL_DARKPLACES4 3501 + +// entityframe5 protocol #define PROTOCOL_DARKPLACES5 3502 // model effects @@ -318,37 +329,48 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // this is 80 bytes typedef struct { - // ! means this is sent to client - double time; // time this state was built (used on client for interpolation) - float origin[3]; // ! - float angles[3]; // ! - int number; // ! entity number this state is for - int effects; // ! - unsigned short modelindex; // ! - unsigned short frame; // ! - unsigned short tagentity; // ! - unsigned short specialvisibilityradius; // larger if it has effects/light - unsigned short viewmodelforclient; - unsigned short exteriormodelforclient; // not shown if first person viewing from this entity, shown in all other cases - unsigned short nodrawtoclient; - unsigned short drawonlytoclient; - unsigned short light[4]; // ! color*256 (0.00 to 255.996), and radius*1 - unsigned char active; // ! true if a valid state - unsigned char lightstyle; // ! - unsigned char lightpflags; // ! - unsigned char colormap; // ! - unsigned char skin; // ! also chooses cubemap for rtlights if lightpflags & LIGHTPFLAGS_FULLDYNAMIC - unsigned char alpha; // ! - unsigned char scale; // ! - unsigned char glowsize; // ! - unsigned char glowcolor; // ! - unsigned char flags; // ! - unsigned char tagindex; // ! + // ! means this is not sent to client + double time; // ! time this state was built (used on client for interpolation) + float origin[3]; + float angles[3]; + int number; // entity number this state is for + int effects; + unsigned short modelindex; + unsigned short frame; + unsigned short tagentity; + unsigned short specialvisibilityradius; // ! larger if it has effects/light + unsigned short viewmodelforclient; // ! + unsigned short exteriormodelforclient; // ! not shown if first person viewing from this entity, shown in all other cases + unsigned short nodrawtoclient; // ! + unsigned short drawonlytoclient; // ! + unsigned short light[4]; // color*256 (0.00 to 255.996), and radius*1 + unsigned char active; // true if a valid state + unsigned char lightstyle; + unsigned char lightpflags; + unsigned char colormap; + unsigned char skin; // also chooses cubemap for rtlights if lightpflags & LIGHTPFLAGS_FULLDYNAMIC + unsigned char alpha; + unsigned char scale; + unsigned char glowsize; + unsigned char glowcolor; + unsigned char flags; + unsigned char tagindex; + unsigned char colormod; // padding to a multiple of 8 bytes (to align the double time) - unsigned char unused[5]; + unsigned char unused[4]; } entity_state_t; +// baseline state values +entity_state_t defaultstate; +// reads a quake entity from the network stream +void EntityFrameQuake_ReadEntity(int bits); +// writes a list of quake entities to the network stream +// (or as many will fit) +void EntityFrameQuake_WriteFrame(sizebuf_t *msg, int numstates, const entity_state_t *states); +// cleans up dead entities each frame after ReadEntity (which doesn't clear unused entities) +void EntityFrameQuake_ISeeDeadEntities(void); + /* PROTOCOL_DARKPLACES3 server updates entities according to some (unmentioned) scheme. @@ -429,8 +451,10 @@ typedef struct // 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 sent frame + int latestframenum; // server only: last acknowledged frame - int ackframe; + int ackframenum; // the current state in the database vec3_t eye; // table of entities in the entityhistorydata @@ -438,7 +462,7 @@ typedef struct // entities entity_state_t entitydata[MAX_ENTITY_DATABASE]; } -entity_database_t; +entityframe_database_t; // build entity data in this, to pass to entity read/write functions typedef struct @@ -498,44 +522,41 @@ entity_frame_t; #define E_UNUSED7 (1<<30) #define E_EXTEND4 (1<<31) -// baseline state values -entity_state_t defaultstate; - -// clears a state to baseline values -void ClearStateToDefault(entity_state_t *s); // returns difference between two states as E_ flags int EntityState_DeltaBits(const entity_state_t *o, const entity_state_t *n); // write E_ flags to a msg void EntityState_WriteExtendBits(sizebuf_t *msg, unsigned int bits); // write values for the E_ flagged fields to a msg -void EntityState_WriteFields(entity_state_t *ent, sizebuf_t *msg, unsigned int bits); +void EntityState_WriteFields(const entity_state_t *ent, sizebuf_t *msg, unsigned int bits); // write entity number and E_ flags and their values, or a remove number, describing the change from delta to ent -void EntityState_WriteUpdate(entity_state_t *ent, sizebuf_t *msg, entity_state_t *delta); +void EntityState_WriteUpdate(const entity_state_t *ent, sizebuf_t *msg, const entity_state_t *delta); // read E_ flags int EntityState_ReadExtendBits(void); // read values for E_ flagged fields and apply them to a state void EntityState_ReadFields(entity_state_t *e, unsigned int bits); +// (client and server) allocates a new empty database +entityframe_database_t *EntityFrame_AllocDatabase(mempool_t *mempool); +// (client and server) frees the database +void EntityFrame_FreeDatabase(entityframe_database_t *d); // (server) clears the database to contain no frames (thus delta compression // compresses against nothing) -void EntityFrame_ClearDatabase(entity_database_t *d); +void EntityFrame_ClearDatabase(entityframe_database_t *d); // (server and client) removes frames older than 'frame' from database -void EntityFrame_AckFrame(entity_database_t *d, int frame); +void EntityFrame_AckFrame(entityframe_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); +void EntityFrame_FetchFrame(entityframe_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); +void EntityFrame_AddFrame(entityframe_database_t *d, vec3_t eye, int framenum, int numentities, const entity_state_t *entitydata); // (server) writes a frame to network stream -void EntityFrame_Write(entity_database_t *d, entity_frame_t *f, sizebuf_t *msg); +void EntityFrame_WriteFrame(sizebuf_t *msg, entityframe_database_t *d, int numstates, const entity_state_t *states, int viewentnum); // (client) reads a frame from network stream -void EntityFrame_Read(entity_database_t *d); +void EntityFrame_CL_ReadFrame(void); // (client) returns the frame number of the most recent frame recieved -int EntityFrame_MostRecentlyRecievedFrameNum(entity_database_t *d); +int EntityFrame_MostRecentlyRecievedFrameNum(entityframe_database_t *d); typedef struct entity_database4_commit_s { @@ -567,31 +588,30 @@ typedef struct entity_database4_s // (server only) if a commit won't fit entirely, continue where it left // off next frame int currententitynumber; + // (server only) + int latestframenumber; // (client only) most recently received frame number to be sent in next // input update int ackframenum; } -entity_database4_t; +entityframe4_database_t; // should-be-private functions that aren't -entity_state_t *EntityFrame4_GetReferenceEntity(entity_database4_t *d, int number); -void EntityFrame4_AddCommitEntity(entity_database4_t *d, entity_state_t *s); +entity_state_t *EntityFrame4_GetReferenceEntity(entityframe4_database_t *d, int number); +void EntityFrame4_AddCommitEntity(entityframe4_database_t *d, const entity_state_t *s); // allocate a database -entity_database4_t *EntityFrame4_AllocDatabase(mempool_t *pool); +entityframe4_database_t *EntityFrame4_AllocDatabase(mempool_t *pool); // free a database -void EntityFrame4_FreeDatabase(entity_database4_t *d); +void EntityFrame4_FreeDatabase(entityframe4_database_t *d); // reset a database (resets compression but does not reallocate anything) -void EntityFrame4_ResetDatabase(entity_database4_t *d); +void EntityFrame4_ResetDatabase(entityframe4_database_t *d); // updates database to account for a frame-received acknowledgment -int EntityFrame4_AckFrame(entity_database4_t *d, 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); - +int EntityFrame4_AckFrame(entityframe4_database_t *d, int framenum); +// writes a frame to the network stream +void EntityFrame4_WriteFrame(sizebuf_t *msg, entityframe4_database_t *d, int numstates, const entity_state_t *states); // reads a frame from the network stream -void EntityFrame4_CL_ReadFrame(entity_database4_t *d); +void EntityFrame4_CL_ReadFrame(void); // reset all entity fields (typically used if status changed) #define E5_FULLUPDATE (1<<0) @@ -617,42 +637,46 @@ void EntityFrame4_CL_ReadFrame(entity_database4_t *d); // bits >= (1<<8) #define E5_EXTEND1 (1<<7) -// flag -#define E5_ORIGIN32 (1<<9) -// flag -#define E5_ANGLES16 (1<<10) -// flag -#define E5_MODEL16 (1<<11) // byte = s->renderflags -#define E5_FLAGS (1<<6) +#define E5_FLAGS (1<<8) // byte = bound(0, s->alpha * 255, 255) -#define E5_ALPHA (1<<13) +#define E5_ALPHA (1<<9) // byte = bound(0, s->scale * 16, 255) -#define E5_SCALE (1<<14) +#define E5_SCALE (1<<10) +// flag +#define E5_ORIGIN32 (1<<11) +// flag +#define E5_ANGLES16 (1<<12) +// flag +#define E5_MODEL16 (1<<13) +// byte = s->colormap +#define E5_COLORMAP (1<<14) // bits >= (1<<16) #define E5_EXTEND2 (1<<15) // short = s->tagentity // byte = s->tagindex #define E5_ATTACHMENT (1<<16) -// short = s->exteriormodelforentity -#define E5_EXTERIORFORENTITY (1<<17) // short[4] = s->light[0], s->light[1], s->light[2], s->light[3] -#define E5_LIGHT (1<<18) -// byte = s->colormap -#define E5_COLORMAP (1<<19) +// byte = s->lightstyle +// byte = s->lightpflags +#define E5_LIGHT (1<<17) // byte = s->glowsize // byte = s->glowcolor -#define E5_GLOW (1<<20) +#define E5_GLOW (1<<18) // short = s->effects -#define E5_EFFECTS16 (1<<21) +#define E5_EFFECTS16 (1<<19) // int = s->effects -#define E5_EFFECTS32 (1<<22) +#define E5_EFFECTS32 (1<<20) +// flag +#define E5_FRAME16 (1<<21) +// unused +#define E5_UNUSED22 (1<<22) // bits >= (1<<24) #define E5_EXTEND3 (1<<23) -// flag -#define E5_FRAME16 (1<<24) +// unused +#define E5_UNUSED24 (1<<24) // unused #define E5_UNUSED25 (1<<25) // unused @@ -668,24 +692,74 @@ void EntityFrame4_CL_ReadFrame(entity_database4_t *d); // bits2 > 0 #define E5_EXTEND4 (1<<31) -typedef struct entity_database5_client_s +#define ENTITYFRAME5_MAXPACKETLOGS 64 +#define ENTITYFRAME5_MAXSTATES 1024 + +typedef struct entityframe5_changestate_s +{ + unsigned int number; + unsigned int bits; +} +entityframe5_changestate_t; + +typedef struct entityframe5_packetlog_s { - qbyte visible[MAX_EDICTS]; - qbyte visibledelta[MAX_EDICTS]; - int statedelta[MAX_EDICTS]; + int packetnumber; + int numstates; + entityframe5_changestate_t states[ENTITYFRAME5_MAXSTATES]; } -entity_database5_t; +entityframe5_packetlog_t; -typedef struct entity_database5_server_s +typedef struct entityframe5_database_s { - // temporary working space for client data building - // 0-255 priority level, 0 = don't send + // number of the latest message sent to client + int latestframenum; + // number of the latest message acknowledged by client + int ackframenum; + + // logs of all recently sent messages (between acked and latest) + entityframe5_packetlog_t packetlog[ENTITYFRAME5_MAXPACKETLOGS]; + + // which properties of each entity have changed since last send + int deltabits[MAX_EDICTS]; + // priorities of entities (updated whenever deltabits change) + // (derived from deltabits) qbyte priorities[MAX_EDICTS]; - // this is the visible entity numbers, sorted by their priority level - int numentitylist; - int entitylist[MAX_EDICTS]; + // last frame this entity was sent on, for prioritzation + int updateframenum[MAX_EDICTS]; + + // database of current status of all entities + // (FIXME: this is 2.5mb per client even if most is unused!) + entity_state_t states[MAX_EDICTS]; + // which entities are currently active + // (duplicate of the active bit of every state in states[]) + // (derived from states) + qbyte visiblebits[(MAX_EDICTS+7)/8]; + + // old notes + + // this is used to decide which changestates to set each frame + //int numvisiblestates; + //entity_state_t visiblestates[MAX_EDICTS]; + + // sorted changing states that need to be sent to the client + // kept sorted in lowest to highest priority order, because this allows + // the numchangestates to simply be decremented whenever an state is sent, + // rather than a memmove to remove them from the start. + //int numchangestates; + //entityframe5_changestate_t changestates[MAX_EDICTS]; } -entity_database5_server_t; +entityframe5_database_t; + +entityframe5_database_t *EntityFrame5_AllocDatabase(mempool_t *pool); +void EntityFrame5_FreeDatabase(entityframe5_database_t *d); +void EntityFrame5_ResetDatabase(entityframe5_database_t *d); +int EntityState5_Priority(entityframe5_database_t *d, entity_state_t *view, entity_state_t *s, int changedbits, int age); +void EntityState5_WriteUpdate(int number, const entity_state_t *s, int changedbits, sizebuf_t *msg); +int EntityState5_DeltaBitsForState(entity_state_t *o, entity_state_t *n); +void EntityFrame5_CL_ReadFrame(void); +void EntityFrame5_AckFrame(entityframe5_database_t *d, int framenum, int viewentnum); +void EntityFrame5_WriteFrame(sizebuf_t *msg, entityframe5_database_t *d, int numstates, const entity_state_t *states, int viewentnum); extern cvar_t developer_networkentities; diff --git a/prvm_cmds.c b/prvm_cmds.c index 4991e6ed..4e7712e7 100644 --- a/prvm_cmds.c +++ b/prvm_cmds.c @@ -1361,12 +1361,12 @@ void VM_WriteLong (void) void VM_WriteAngle (void) { - MSG_WriteAngle (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0)); + MSG_WriteAngle16i (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0)); } void VM_WriteCoord (void) { - MSG_WriteDPCoord (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0)); + MSG_WriteCoord (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0), sv.protocol); } void VM_WriteString (void) diff --git a/quakedef.h b/quakedef.h index bb5e7843..5165ef93 100644 --- a/quakedef.h +++ b/quakedef.h @@ -47,7 +47,7 @@ extern char *buildstring; #define MAX_PACKETFRAGMENT 1024 // max length of packet fragment #define NET_MAXMESSAGE 65536 -#define NET_MINRATE 500 // limits "rate" and "sv_maxrate" cvars +#define NET_MINRATE 1000 // limits "rate" and "sv_maxrate" cvars #define NET_MAXRATE 25000 // limits "rate" and "sv_maxrate" cvars // diff --git a/server.h b/server.h index 656781d3..8e94e5ad 100644 --- a/server.h +++ b/server.h @@ -47,6 +47,11 @@ typedef struct // handle connections specially qboolean loadgame; + // one of the PROTOCOL_ values + int protocol; + // this disables extensions when using PROTOCOL_QUAKE + qboolean netquakecompatible; + double time; double frametime; @@ -153,16 +158,9 @@ typedef struct client_s // prevent animated names float nametime; -#ifdef QUAKEENTITIES - // delta compression state - float nextfullupdate[MAX_EDICTS]; -#elif 0 - entity_database_t entitydatabase; - int entityframenumber; // incremented each time an entity frame is sent -#else - entity_database4_t *entitydatabase4; - int entityframenumber; // incremented each time an entity frame is sent -#endif + entityframe_database_t *entitydatabase; + entityframe4_database_t *entitydatabase4; + entityframe5_database_t *entitydatabase5; } client_t; @@ -256,6 +254,8 @@ extern cvar_t sv_idealpitchscale; extern cvar_t sv_aim; extern cvar_t sv_stepheight; extern cvar_t sv_jumpstep; +extern cvar_t sv_public; +extern cvar_t sv_maxrate; extern cvar_t sv_gameplayfix_grenadebouncedownslopes; extern cvar_t sv_gameplayfix_noairborncorpse; diff --git a/sv_main.c b/sv_main.c index 736cee1f..b8c14c72 100644 --- a/sv_main.c +++ b/sv_main.c @@ -21,6 +21,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "quakedef.h" +// select which protocol to host, by name +// this is named the same as PROTOCOL_DARKPLACES5 for example, minus the PROTOCOL_ prefix +cvar_t sv_protocolname = {0, "sv_protocolname", "DARKPLACES5"}; +cvar_t sv_ratelimitlocalplayer = {0, "sv_ratelimitlocalplayer", "0"}; +cvar_t sv_maxrate = {CVAR_SAVE | CVAR_NOTIFY, "sv_maxrate", "10000"}; + static cvar_t sv_cullentities_pvs = {0, "sv_cullentities_pvs", "1"}; // fast but loose static cvar_t sv_cullentities_trace = {0, "sv_cullentities_trace", "0"}; // tends to get false negatives, uses a timeout to keep entities visible a short time after becoming hidden static cvar_t sv_cullentities_stats = {0, "sv_cullentities_stats", "0"}; @@ -75,6 +81,9 @@ void SV_Init (void) Cvar_RegisterVariable (&sv_gameplayfix_stepdown); Cvar_RegisterVariable (&sv_gameplayfix_stepwhilejumping); Cvar_RegisterVariable (&sv_gameplayfix_swiminbmodels); + Cvar_RegisterVariable (&sv_protocolname); + Cvar_RegisterVariable (&sv_ratelimitlocalplayer); + Cvar_RegisterVariable (&sv_maxrate); SV_Phys_Init(); SV_World_Init(); @@ -119,9 +128,9 @@ void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count) if (sv.datagram.cursize > MAX_PACKETFRAGMENT-18) return; MSG_WriteByte (&sv.datagram, svc_particle); - MSG_WriteDPCoord (&sv.datagram, org[0]); - MSG_WriteDPCoord (&sv.datagram, org[1]); - MSG_WriteDPCoord (&sv.datagram, org[2]); + MSG_WriteCoord (&sv.datagram, org[0], sv.protocol); + MSG_WriteCoord (&sv.datagram, org[1], sv.protocol); + MSG_WriteCoord (&sv.datagram, org[2], sv.protocol); for (i=0 ; i<3 ; i++) { v = dir[i]*16; @@ -149,9 +158,9 @@ void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount, if (sv.datagram.cursize > MAX_PACKETFRAGMENT-19) return; MSG_WriteByte (&sv.datagram, svc_effect2); - MSG_WriteDPCoord (&sv.datagram, org[0]); - MSG_WriteDPCoord (&sv.datagram, org[1]); - MSG_WriteDPCoord (&sv.datagram, org[2]); + MSG_WriteCoord (&sv.datagram, org[0], sv.protocol); + MSG_WriteCoord (&sv.datagram, org[1], sv.protocol); + MSG_WriteCoord (&sv.datagram, org[2], sv.protocol); MSG_WriteShort (&sv.datagram, modelindex); MSG_WriteShort (&sv.datagram, startframe); MSG_WriteByte (&sv.datagram, framecount); @@ -162,9 +171,9 @@ void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount, if (sv.datagram.cursize > MAX_PACKETFRAGMENT-17) return; MSG_WriteByte (&sv.datagram, svc_effect); - MSG_WriteDPCoord (&sv.datagram, org[0]); - MSG_WriteDPCoord (&sv.datagram, org[1]); - MSG_WriteDPCoord (&sv.datagram, org[2]); + MSG_WriteCoord (&sv.datagram, org[0], sv.protocol); + MSG_WriteCoord (&sv.datagram, org[1], sv.protocol); + MSG_WriteCoord (&sv.datagram, org[2], sv.protocol); MSG_WriteByte (&sv.datagram, modelindex); MSG_WriteByte (&sv.datagram, startframe); MSG_WriteByte (&sv.datagram, framecount); @@ -245,7 +254,7 @@ void SV_StartSound (edict_t *entity, int channel, char *sample, int volume, floa else MSG_WriteByte (&sv.datagram, sound_num); for (i = 0;i < 3;i++) - MSG_WriteDPCoord (&sv.datagram, entity->v->origin[i]+0.5*(entity->v->mins[i]+entity->v->maxs[i])); + MSG_WriteCoord (&sv.datagram, entity->v->origin[i]+0.5*(entity->v->mins[i]+entity->v->maxs[i]), sv.protocol); } /* @@ -272,18 +281,29 @@ void SV_SendServerinfo (client_t *client) // edicts get reallocated on level changes, so we need to update it here client->edict = EDICT_NUM(client->number + 1); + // LordHavoc: clear entityframe tracking - client->entityframenumber = 0; + + if (client->entitydatabase) + EntityFrame_FreeDatabase(client->entitydatabase); if (client->entitydatabase4) EntityFrame4_FreeDatabase(client->entitydatabase4); - client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_clients_mempool); + if (client->entitydatabase5) + EntityFrame5_FreeDatabase(client->entitydatabase5); + + if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3) + client->entitydatabase = EntityFrame_AllocDatabase(sv_clients_mempool); + if (sv.protocol == PROTOCOL_DARKPLACES4) + client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_clients_mempool); + if (sv.protocol == PROTOCOL_DARKPLACES5) + client->entitydatabase5 = EntityFrame5_AllocDatabase(sv_clients_mempool); MSG_WriteByte (&client->message, svc_print); snprintf (message, sizeof (message), "\002\nServer: %s build %s (progs %i crc)", gamename, buildstring, pr_crc); MSG_WriteString (&client->message,message); MSG_WriteByte (&client->message, svc_serverinfo); - MSG_WriteLong (&client->message, PROTOCOL_DARKPLACES5); + MSG_WriteLong (&client->message, sv.protocol); MSG_WriteByte (&client->message, svs.maxclients); if (!coop.integer && deathmatch.integer) @@ -404,8 +424,8 @@ SV_WriteEntitiesToClient ============= */ -#ifdef QUAKEENTITIES -void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg) +/* +void SV_WriteEntitiesToClient_QUAKE (client_t *client, edict_t *clent, sizebuf_t *msg) { int e, clentnum, bits, alpha, glowcolor, glowsize, scale, effects, lightsize; int culled_pvs, culled_trace, visibleentities, totalentities; @@ -710,12 +730,12 @@ void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg) if (bits & U_COLORMAP) MSG_WriteByte(msg, ent->v->colormap); if (bits & U_SKIN) MSG_WriteByte(msg, ent->v->skin); if (bits & U_EFFECTS) MSG_WriteByte(msg, ent->v->effects); - if (bits & U_ORIGIN1) MSG_WriteDPCoord(msg, origin[0]); - if (bits & U_ANGLE1) MSG_WriteAngle(msg, angles[0]); - if (bits & U_ORIGIN2) MSG_WriteDPCoord(msg, origin[1]); - if (bits & U_ANGLE2) MSG_WriteAngle(msg, angles[1]); - if (bits & U_ORIGIN3) MSG_WriteDPCoord(msg, origin[2]); - if (bits & U_ANGLE3) MSG_WriteAngle(msg, angles[2]); + if (bits & U_ORIGIN1) MSG_WriteCoord13i(msg, origin[0]); + if (bits & U_ANGLE1) MSG_WriteAngle8i(msg, angles[0]); + if (bits & U_ORIGIN2) MSG_WriteCoord13i(msg, origin[1]); + if (bits & U_ANGLE2) MSG_WriteAngle8i(msg, angles[1]); + if (bits & U_ORIGIN3) MSG_WriteCoord13i(msg, origin[2]); + if (bits & U_ANGLE3) MSG_WriteAngle8i(msg, angles[2]); // LordHavoc: new stuff if (bits & U_ALPHA) MSG_WriteByte(msg, alpha); @@ -730,7 +750,8 @@ void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg) if (sv_cullentities_stats.integer) Con_Printf("client \"%s\" entities: %d total, %d visible, %d culled by: %d pvs %d trace\n", client->name, totalentities, visibleentities, culled_pvs + culled_trace, culled_pvs, culled_trace); } -#else +*/ + static int numsendentities; static entity_state_t sendentities[MAX_EDICTS]; static entity_state_t *sendentitiesindex[MAX_EDICTS]; @@ -750,7 +771,7 @@ void SV_PrepareEntitiesForSending(void) if (ent->e->free) continue; - ClearStateToDefault(&cs); + cs = defaultstate; cs.active = true; cs.number = e; VectorCopy(ent->v->origin, cs.origin); @@ -900,6 +921,7 @@ static client_t *sv_writeentitiestoclient_client; void SV_MarkWriteEntityStateToClient(entity_state_t *s) { + int isbmodel; vec3_t entmins, entmaxs, lightmins, lightmaxs, testorigin; model_t *model; trace_t trace; @@ -925,6 +947,7 @@ void SV_MarkWriteEntityStateToClient(entity_state_t *s) // LordHavoc: only send entities with a model or important effects if (!s->modelindex && s->specialvisibilityradius == 0) return; + isbmodel = (model = sv.models[s->modelindex]) == NULL || model->name[0] != '*'; if (s->tagentity) { // tag attached entities simply check their parent @@ -935,7 +958,7 @@ void SV_MarkWriteEntityStateToClient(entity_state_t *s) return; } // always send world submodels, they don't generate much traffic - else if ((model = sv.models[s->modelindex]) == NULL || model->name[0] != '*') + else if (!isbmodel || sv.protocol == PROTOCOL_QUAKE) { Mod_CheckLoaded(model); // entity has survived every check so far, check if visible @@ -981,7 +1004,7 @@ void SV_MarkWriteEntityStateToClient(entity_state_t *s) return; } // or not seen by random tracelines - if (sv_cullentities_trace.integer) + if (sv_cullentities_trace.integer && !isbmodel) { // LordHavoc: test center first testorigin[0] = (entmins[0] + entmaxs[0]) * 0.5f; @@ -1028,12 +1051,16 @@ void SV_MarkWriteEntityStateToClient(entity_state_t *s) sententities[s->number] = sententitiesmark; } -void SV_WriteEntitiesToClient(client_t *client, edict_t *clent, sizebuf_t *msg) +entity_state_t sendstates[MAX_EDICTS]; + +/* +// entityframe4 protocol +void SV_WriteEntitiesToClient_EF4(client_t *client, edict_t *clent, sizebuf_t *msg) { int i; vec3_t testorigin; entity_state_t *s; - entity_database4_t *d; + entityframe4_database_t *d; int n, startnumber; entity_state_t *e, inactiveentitystate; sizebuf_t buf; @@ -1059,8 +1086,7 @@ void SV_WriteEntitiesToClient(client_t *client, edict_t *clent, sizebuf_t *msg) d->currentcommit = d->commit + i; // this state's number gets played around with later - ClearStateToDefault(&inactiveentitystate); - //inactiveentitystate = defaultstate; + inactiveentitystate = defaultstate; sv_writeentitiestoclient_client = client; @@ -1095,7 +1121,7 @@ void SV_WriteEntitiesToClient(client_t *client, edict_t *clent, sizebuf_t *msg) SV_MarkWriteEntityStateToClient(sendentities + i); d->currentcommit->numentities = 0; - d->currentcommit->framenum = ++client->entityframenumber; + d->currentcommit->framenum = ++d->latestframenumber; MSG_WriteByte(msg, svc_entities); MSG_WriteLong(msg, d->referenceframenum); MSG_WriteLong(msg, d->currentcommit->framenum); @@ -1177,7 +1203,64 @@ void SV_WriteEntitiesToClient(client_t *client, edict_t *clent, sizebuf_t *msg) if (sv_cullentities_stats.integer) Con_Printf("client \"%s\" entities: %d total, %d visible, %d culled by: %d pvs %d trace\n", client->name, sv_writeentitiestoclient_totalentities, sv_writeentitiestoclient_visibleentities, sv_writeentitiestoclient_culled_pvs + sv_writeentitiestoclient_culled_trace, sv_writeentitiestoclient_culled_pvs, sv_writeentitiestoclient_culled_trace); } -#endif +*/ + +void SV_WriteEntitiesToClient(client_t *client, edict_t *clent, sizebuf_t *msg) +{ + int i, numsendstates; + entity_state_t *s; + + // if there isn't enough space to accomplish anything, skip it + if (msg->cursize + 25 > msg->maxsize) + return; + + sv_writeentitiestoclient_client = client; + + sv_writeentitiestoclient_culled_pvs = 0; + sv_writeentitiestoclient_culled_trace = 0; + sv_writeentitiestoclient_visibleentities = 0; + sv_writeentitiestoclient_totalentities = 0; + + Mod_CheckLoaded(sv.worldmodel); + +// find the client's PVS + // the real place being tested from + VectorAdd(clent->v->origin, clent->v->view_ofs, sv_writeentitiestoclient_testeye); + sv_writeentitiestoclient_pvsbytes = 0; + if (sv.worldmodel && sv.worldmodel->brush.FatPVS) + sv_writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv_writeentitiestoclient_testeye, 8, sv_writeentitiestoclient_pvs, sizeof(sv_writeentitiestoclient_pvs)); + + sv_writeentitiestoclient_clentnum = EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes + + sententitiesmark++; + + for (i = 0;i < numsendentities;i++) + SV_MarkWriteEntityStateToClient(sendentities + i); + + numsendstates = 0; + for (i = 0;i < numsendentities;i++) + { + if (sententities[sendentities[i].number] == sententitiesmark) + { + s = &sendstates[numsendstates++]; + *s = sendentities[i]; + if (s->exteriormodelforclient && s->exteriormodelforclient == sv_writeentitiestoclient_clentnum) + s->flags |= RENDER_EXTERIORMODEL; + } + } + + if (sv_cullentities_stats.integer) + Con_Printf("client \"%s\" entities: %d total, %d visible, %d culled by: %d pvs %d trace\n", client->name, sv_writeentitiestoclient_totalentities, sv_writeentitiestoclient_visibleentities, sv_writeentitiestoclient_culled_pvs + sv_writeentitiestoclient_culled_trace, sv_writeentitiestoclient_culled_pvs, sv_writeentitiestoclient_culled_trace); + + if (client->entitydatabase5) + EntityFrame5_WriteFrame(msg, client->entitydatabase5, numsendstates, sendstates, client - svs.clients + 1); + else if (client->entitydatabase4) + EntityFrame4_WriteFrame(msg, client->entitydatabase4, numsendstates, sendstates); + else if (client->entitydatabase) + EntityFrame_WriteFrame(msg, client->entitydatabase, numsendstates, sendstates, client - svs.clients + 1); + else + EntityFrameQuake_WriteFrame(msg, numsendstates, sendstates); +} /* ============= @@ -1221,7 +1304,7 @@ void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg) MSG_WriteByte (msg, ent->v->dmg_save); MSG_WriteByte (msg, ent->v->dmg_take); for (i=0 ; i<3 ; i++) - MSG_WriteDPCoord (msg, other->v->origin[i] + 0.5*(other->v->mins[i] + other->v->maxs[i])); + MSG_WriteCoord (msg, other->v->origin[i] + 0.5*(other->v->mins[i] + other->v->maxs[i]), sv.protocol); ent->v->dmg_take = 0; ent->v->dmg_save = 0; @@ -1237,7 +1320,12 @@ void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg) { MSG_WriteByte (msg, svc_setangle); for (i=0 ; i < 3 ; i++) - MSG_WriteAngle (msg, ent->v->angles[i] ); + { + if (sv.protocol == PROTOCOL_DARKPLACES5) + MSG_WriteAngle16i (msg, ent->v->angles[i] ); + else + MSG_WriteAngle8i (msg, ent->v->angles[i] ); + } ent->v->fixangle = 0; } @@ -1278,19 +1366,22 @@ void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg) if (i == 0) i = 255; else - i = bound(0, i, 255); + i = bound(0, i, 65535); } viewzoom = i; - if (viewzoom != 255) - bits |= SU_VIEWZOOM; + // FIXME: which protocols support this? does PROTOCOL_DARKPLACES3 support viewzoom? + if (sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5) + if (viewzoom != 255) + bits |= SU_VIEWZOOM; for (i=0 ; i<3 ; i++) { if (ent->v->punchangle[i]) bits |= (SU_PUNCH1<v->velocity[i]) bits |= (SU_VELOCITY1<v->punchangle[i]); // PROTOCOL_DARKPLACES - if (bits & (SU_PUNCHVEC1<v->punchangle[i]); + else if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5) + MSG_WriteAngle16i(msg, ent->v->punchangle[i]); + } + if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5) + { + if (bits & (SU_PUNCHVEC1<v->velocity[i]); + { + if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4) + MSG_WriteChar(msg, ent->v->velocity[i] * (1.0f / 16.0f)); + else if (sv.protocol == PROTOCOL_DARKPLACES5) + MSG_WriteCoord32f(msg, ent->v->velocity[i]); + } } // [always sent] if (bits & SU_ITEMS) MSG_WriteLong (msg, items); - if (bits & SU_WEAPONFRAME) - MSG_WriteByte (msg, ent->v->weaponframe); - if (bits & SU_ARMOR) - MSG_WriteByte (msg, ent->v->armorvalue); - if (bits & SU_WEAPON) - MSG_WriteByte (msg, SV_ModelIndex(PR_GetString(ent->v->weaponmodel))); - - MSG_WriteShort (msg, ent->v->health); - MSG_WriteByte (msg, ent->v->currentammo); - MSG_WriteByte (msg, ent->v->ammo_shells); - MSG_WriteByte (msg, ent->v->ammo_nails); - MSG_WriteByte (msg, ent->v->ammo_rockets); - MSG_WriteByte (msg, ent->v->ammo_cells); - - if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ) + if (sv.protocol == PROTOCOL_DARKPLACES5) { - for(i=0;i<32;i++) + if (bits & SU_WEAPONFRAME) + MSG_WriteShort (msg, ent->v->weaponframe); + if (bits & SU_ARMOR) + MSG_WriteShort (msg, ent->v->armorvalue); + if (bits & SU_WEAPON) { - if ( ((int)ent->v->weapon) & (1<v->weaponmodel)); + if (i < 0) { - MSG_WriteByte (msg, i); - break; + Con_DPrintf("weaponmodel \"%s\" not precached\n", PR_GetString(ent->v->weaponmodel)); + i = 0; } + MSG_WriteShort (msg, i); } + + MSG_WriteShort (msg, ent->v->health); + MSG_WriteShort (msg, ent->v->currentammo); + MSG_WriteShort (msg, ent->v->ammo_shells); + MSG_WriteShort (msg, ent->v->ammo_nails); + MSG_WriteShort (msg, ent->v->ammo_rockets); + MSG_WriteShort (msg, ent->v->ammo_cells); + + MSG_WriteShort (msg, ent->v->weapon); + + if (bits & SU_VIEWZOOM) + MSG_WriteShort (msg, viewzoom); } else { - MSG_WriteByte (msg, ent->v->weapon); - } + if (bits & SU_WEAPONFRAME) + MSG_WriteByte (msg, ent->v->weaponframe); + if (bits & SU_ARMOR) + MSG_WriteByte (msg, ent->v->armorvalue); + if (bits & SU_WEAPON) + { + i = SV_ModelIndex(PR_GetString(ent->v->weaponmodel)); + if (i < 0) + { + Con_DPrintf("weaponmodel \"%s\" not precached\n", PR_GetString(ent->v->weaponmodel)); + i = 0; + } + MSG_WriteByte (msg, i); + } + + MSG_WriteShort (msg, ent->v->health); + MSG_WriteByte (msg, ent->v->currentammo); + MSG_WriteByte (msg, ent->v->ammo_shells); + MSG_WriteByte (msg, ent->v->ammo_nails); + MSG_WriteByte (msg, ent->v->ammo_rockets); + MSG_WriteByte (msg, ent->v->ammo_cells); - if (bits & SU_VIEWZOOM) - MSG_WriteByte (msg, viewzoom); + if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ) + { + for(i=0;i<32;i++) + { + if ( ((int)ent->v->weapon) & (1<v->weapon); + } + + if (bits & SU_VIEWZOOM) + { + if (sv.protocol == PROTOCOL_DARKPLACES4) + { + viewzoom = min(viewzoom, 255); + MSG_WriteByte (msg, viewzoom); + } + else if (sv.protocol == PROTOCOL_DARKPLACES5) + MSG_WriteShort (msg, viewzoom); + } + } } /* @@ -1378,10 +1535,38 @@ SV_SendClientDatagram static qbyte sv_sendclientdatagram_buf[NET_MAXMESSAGE]; // FIXME? qboolean SV_SendClientDatagram (client_t *client) { - sizebuf_t msg; + int rate, maxrate, maxsize, maxsize2; + sizebuf_t msg; + + if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer) + { + // for good singleplayer, send huge packets + maxsize = sizeof(sv_sendclientdatagram_buf); + maxsize2 = sizeof(sv_sendclientdatagram_buf); + } + else if (sv.protocol == PROTOCOL_DARKPLACES5) + { + // PROTOCOL_DARKPLACES5 supports packet size limiting of updates + maxrate = bound(NET_MINRATE, sv_maxrate.integer, NET_MAXRATE); + if (sv_maxrate.integer != maxrate) + Cvar_SetValueQuick(&sv_maxrate, maxrate); + + rate = bound(NET_MINRATE, client->netconnection->rate, maxrate); + rate = (int)(client->netconnection->rate * sys_ticrate.value); + maxsize = bound(100, rate, 1400); + maxsize2 = 1400; + } + else + { + // no rate limiting support on older protocols because dp protocols + // 1-4 kick the client off if they overflow, and quake protocol shows + // less than the full entity set if rate limited + maxsize = 1400; + maxsize2 = 1400; + } msg.data = sv_sendclientdatagram_buf; - msg.maxsize = (int)bound(50.0, client->netconnection->rate * host_realframetime, (double)sizeof(sv_sendclientdatagram_buf)); + msg.maxsize = maxsize; msg.cursize = 0; MSG_WriteByte (&msg, svc_time); @@ -1392,9 +1577,13 @@ qboolean SV_SendClientDatagram (client_t *client) SV_WriteEntitiesToClient (client, client->edict, &msg); + // expand packet size to allow effects to go over the rate limit + // (dropping them is FAR too ugly) + msg.maxsize = maxsize2; + // copy the server datagram if there is space // FIXME: put in delayed queue of effects to send - if (msg.cursize + sv.datagram.cursize <= msg.maxsize) + if (sv.datagram.cursize > 0 && msg.cursize + sv.datagram.cursize <= msg.maxsize) SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize); // send the datagram @@ -1614,11 +1803,13 @@ int SV_ModelIndex (const char *name) if (!strcmp(sv.model_precache[i], name)) return i; if (i==MAX_MODELS || !sv.model_precache[i]) - Host_Error ("SV_ModelIndex: model %s not precached", name); + { + Con_DPrintf ("SV_ModelIndex: model %s not precached", name); + return -1; + } return i; } -#ifdef SV_QUAKEENTITIES /* ================ SV_CreateBaseline @@ -1637,7 +1828,7 @@ void SV_CreateBaseline (void) svent = EDICT_NUM(entnum); // LordHavoc: always clear state values, whether the entity is in use or not - ClearStateToDefault(&svent->e->baseline); + svent->e->baseline = defaultstate; if (svent->e->free) continue; @@ -1652,7 +1843,10 @@ void SV_CreateBaseline (void) if (entnum > 0 && entnum <= svs.maxclients) { svent->e->baseline.colormap = entnum; - svent->e->baseline.modelindex = SV_ModelIndex("progs/player.mdl"); + i = SV_ModelIndex("progs/player.mdl"); + if (i < 0) + i = 0; + svent->e->baseline.modelindex = i; } else { @@ -1685,12 +1879,11 @@ void SV_CreateBaseline (void) MSG_WriteByte (&sv.signon, svent->e->baseline.skin); for (i=0 ; i<3 ; i++) { - MSG_WriteDPCoord(&sv.signon, svent->e->baseline.origin[i]); - MSG_WriteAngle(&sv.signon, svent->e->baseline.angles[i]); + MSG_WriteCoord(&sv.signon, svent->e->baseline.origin[i], sv.protocol); + MSG_WriteAngle8i(&sv.signon, svent->e->baseline.angles[i]); } } } -#endif /* @@ -1852,6 +2045,49 @@ void SV_SpawnServer (const char *server) strlcpy (sv.name, server, sizeof (sv.name)); + // FIXME: cvar + if (!strcasecmp(sv_protocolname.string, "QUAKE")) + { + sv.protocol = PROTOCOL_QUAKE; + sv.netquakecompatible = true; + } + else if (!strcasecmp(sv_protocolname.string, "QUAKEDP")) + { + sv.protocol = PROTOCOL_QUAKE; + sv.netquakecompatible = false; + } + else if (!strcasecmp(sv_protocolname.string, "DARKPLACES1")) + { + sv.protocol = PROTOCOL_DARKPLACES1; + sv.netquakecompatible = false; + } + else if (!strcasecmp(sv_protocolname.string, "DARKPLACES2")) + { + sv.protocol = PROTOCOL_DARKPLACES2; + sv.netquakecompatible = false; + } + else if (!strcasecmp(sv_protocolname.string, "DARKPLACES3")) + { + sv.protocol = PROTOCOL_DARKPLACES3; + sv.netquakecompatible = false; + } + else if (!strcasecmp(sv_protocolname.string, "DARKPLACES4")) + { + sv.protocol = PROTOCOL_DARKPLACES4; + sv.netquakecompatible = false; + } + else if (!strcasecmp(sv_protocolname.string, "DARKPLACES5")) + { + sv.protocol = PROTOCOL_DARKPLACES5; + sv.netquakecompatible = false; + } + else + { + sv.protocol = PROTOCOL_DARKPLACES5; + sv.netquakecompatible = false; + Con_Printf("Unknown sv_protocolname \"%s\", valid values are QUAKE, QUAKEDP, DARKPLACES1, DARKPLACES2, DARKPLACES3, DARKPLACES4, DARKPLACES5, falling back to DARKPLACES5 protocol\n", sv_protocolname.string); + } + // load progs to get entity field count PR_LoadProgs (); @@ -1972,10 +2208,9 @@ void SV_SpawnServer (const char *server) Mod_PurgeUnused(); -#ifdef QUAKEENTITIES // create a baseline for more efficient communications - SV_CreateBaseline (); -#endif + if (sv.protocol == PROTOCOL_QUAKE) + SV_CreateBaseline (); // send serverinfo to all connected clients for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++) diff --git a/sv_user.c b/sv_user.c index ada7f28a..3eb4d0fd 100644 --- a/sv_user.c +++ b/sv_user.c @@ -613,7 +613,9 @@ void SV_ReadClientMove (usercmd_t *move) float total; // read ping time + if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__); host_client->ping_times[host_client->num_pings % NUM_PING_TIMES] = sv.time - MSG_ReadFloat (); + if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__); host_client->num_pings++; for (i=0, total = 0;i < NUM_PING_TIMES;i++) total += host_client->ping_times[i]; @@ -623,16 +625,28 @@ void SV_ReadClientMove (usercmd_t *move) val->_float = host_client->ping * 1000.0; // read current angles - // PROTOCOL_DARKPLACES4 for (i = 0;i < 3;i++) - angle[i] = MSG_ReadPreciseAngle(); + { + if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__); + if (sv.protocol == PROTOCOL_QUAKE) + angle[i] = MSG_ReadAngle8i(); + else if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3) + angle[i] = MSG_ReadAngle32f(); + else if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5) + angle[i] = MSG_ReadAngle16i(); + if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__); + } VectorCopy (angle, sv_player->v->v_angle); // read movement - move->forwardmove = MSG_ReadShort (); - move->sidemove = MSG_ReadShort (); - move->upmove = MSG_ReadShort (); + if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__); + move->forwardmove = MSG_ReadCoord16i (); + if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__); + move->sidemove = MSG_ReadCoord16i (); + if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__); + move->upmove = MSG_ReadCoord16i (); + if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__); if ((val = GETEDICTFIELDVALUE(sv_player, eval_movement))) { val->vector[0] = move->forwardmove; @@ -642,6 +656,7 @@ void SV_ReadClientMove (usercmd_t *move) // read buttons bits = MSG_ReadByte (); + if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__); sv_player->v->button0 = bits & 1; sv_player->v->button2 = (bits & 2)>>1; // LordHavoc: added 6 new buttons @@ -653,6 +668,7 @@ void SV_ReadClientMove (usercmd_t *move) if ((val = GETEDICTFIELDVALUE(sv_player, eval_button8))) val->_float = ((bits >> 7) & 1); i = MSG_ReadByte (); + if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__); if (i) sv_player->v->impulse = i; } @@ -665,7 +681,7 @@ SV_ReadClientMessage extern void SV_SendServerinfo(client_t *client); void SV_ReadClientMessage(void) { - int cmd; + int cmd, num; char *s; //MSG_BeginReading (); @@ -744,10 +760,17 @@ void SV_ReadClientMessage(void) break; case clc_ackentities: - host_client->entitydatabase4->ackframenum = MSG_ReadLong(); + if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__); + num = MSG_ReadLong(); + if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__); if (developer_networkentities.integer >= 1) - Con_Printf("recv clc_ackentities %i\n", host_client->entitydatabase4->ackframenum); - EntityFrame4_AckFrame(host_client->entitydatabase4, host_client->entitydatabase4->ackframenum); + Con_Printf("recv clc_ackentities %i\n", num); + if (host_client->entitydatabase) + EntityFrame_AckFrame(host_client->entitydatabase, num); + else if (host_client->entitydatabase4) + EntityFrame4_AckFrame(host_client->entitydatabase4, host_client->entitydatabase4->ackframenum); + else if (host_client->entitydatabase5) + EntityFrame5_AckFrame(host_client->entitydatabase5, num, host_client - svs.clients + 1); break; } } diff --git a/view.c b/view.c index 78ac5d30..060464ac 100644 --- a/view.c +++ b/view.c @@ -214,7 +214,7 @@ void V_ParseDamage (void) armor = MSG_ReadByte (); blood = MSG_ReadByte (); - MSG_ReadVector(from); + MSG_ReadVector(from, cl.protocol); count = blood*0.5 + armor*0.5; if (count < 10)