diff --git a/source/client/defs/custom.qc b/source/client/defs/custom.qc index 53273f8..85f6b83 100644 --- a/source/client/defs/custom.qc +++ b/source/client/defs/custom.qc @@ -248,4 +248,9 @@ string build_datetime; vector gun_kick; -float hide_viewmodel; \ No newline at end of file +float hide_viewmodel; + +// csqc player prediction by eukara +vector playerOrigin; +vector playerOriginOld; +vector playerVelocity; \ No newline at end of file diff --git a/source/client/main.qc b/source/client/main.qc index 1a5d77a..a0e613f 100644 --- a/source/client/main.qc +++ b/source/client/main.qc @@ -62,6 +62,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = precache_sound("sounds/menu/enter.wav"); precache_sound("sounds/menu/navigate.wav"); + precache_model("models/player.mdl"); registercommand("togglemenu"); registercommand("startwalk"); @@ -507,10 +508,97 @@ void() Update_Vmodel = mzlflash.alpha = 0.01; } +float Player_PreDraw() = +{ + if (self.entnum == player_localentnum) { + self.movetype = MOVETYPE_WALK; + // Prepare rollback + vector vOldOrigin = self.origin; + vector vOldVelocity = self.velocity; + float fOldPMoveFlags = self.pmove_flags; + + // Apply physics for every single input-frame that has not yet been + // acknowledged by the server (servercommandframe = last acknowledged frame) + for (int i = servercommandframe + 1; i <= clientcommandframe; i++) { + float flSuccess = getinputstate(i); + + if (flSuccess == FALSE) { + continue; + } + + // Partial frames are the worst + if (input_timelength == 0) { + break; + } + runstandardplayerphysics(self); + } + + // Smooth stair stepping, this has to be done manually! + playerOriginOld = playerOrigin; + + if ((self.flags & FL_ONGROUND) && (self.origin_z - playerOriginOld_z > 0)) { + playerOriginOld_z += frametime * 150; + + if (playerOriginOld_z > self.origin_z) { + playerOriginOld_z = self.origin_z; + } + if (self.origin_z - playerOriginOld_z > 18) { + playerOriginOld_z = self.origin_z - 18; + } + playerOrigin_z += playerOriginOld_z - self.origin_z; + } else { + playerOriginOld_z = self.origin_z; + } + + playerOrigin = [self.origin_x, self.origin_y, playerOriginOld_z]; + playerVelocity = self.velocity; + addentity(self); + + // Time to roll back + self.origin = vOldOrigin; + setorigin(self, self.origin); + self.velocity = vOldVelocity; + self.pmove_flags = fOldPMoveFlags; + self.movetype = MOVETYPE_NONE; + + // Set renderflag for mirrors! + self.renderflags = RF_EXTERNALMODEL; + } else { + addentity(self); + } + return PREDRAW_NEXT; +} + noref void(float isnew) CSQC_Ent_Update = { - if(isnew) - addentity(self); + float ent_type = readbyte(); + + if (ent_type == 1) { + if (isnew == TRUE) { + self.classname = "player"; + self.solid = SOLID_SLIDEBOX; + self.predraw = Player_PreDraw; + self.drawmask = MASK_ENGINE; + setmodel(self, "models/player.mdl"); + } + + self.origin_x = readcoord(); + self.origin_y = readcoord(); + self.origin_z = readcoord(); + self.angles_x = readcoord(); + self.angles_y = readcoord(); + self.angles_z = readcoord(); + self.velocity_x = readshort(); + self.velocity_y = readshort(); + self.velocity_z = readshort(); + self.flags = readfloat(); + + setsize(self, [-16, -16, -32], [16, 16, 40]); + setorigin(self, self.origin); + } else { + if(isnew) + addentity(self); + } } float(__inout vector v) VectorNormalize = @@ -849,6 +937,9 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = //autoadd entities received from servers for drawing addentities(MASK_ENGINE); + setproperty(VF_ORIGIN, playerOrigin + [ 0, 0, getstatf(STAT_VIEWHEIGHT)]); + //setproperty(VF_ANGLES, view_angles); + //do viewmodel manipulation, purely cosmetic stuff if(vmodel) { diff --git a/source/server/clientfuncs.qc b/source/server/clientfuncs.qc index 9b744e1..32bfb96 100644 --- a/source/server/clientfuncs.qc +++ b/source/server/clientfuncs.qc @@ -534,6 +534,32 @@ void (float achievement_id, optional entity who) GiveAchievement = } } +#ifdef FTE + +/* +================= +Player_SendEntity + + Networks the player info +================= +*/ +float Player_SendEntity( entity ePVEnt, float flChanged ) { + WriteByte( MSG_ENTITY, 1 ); + WriteCoord( MSG_ENTITY, self.origin_x ); // Position X + WriteCoord( MSG_ENTITY, self.origin_y ); // Position Y + WriteCoord( MSG_ENTITY, self.origin_z ); // Position Z + WriteCoord( MSG_ENTITY, self.angles_x ); // Angle X + WriteCoord( MSG_ENTITY, self.angles_y ); // Angle Y + WriteCoord( MSG_ENTITY, self.angles_z ); // Angle Z + WriteShort( MSG_ENTITY, self.velocity_x ); // Velocity X + WriteShort( MSG_ENTITY, self.velocity_y ); // Velocity X + WriteShort( MSG_ENTITY, self.velocity_z ); // Velocity X + WriteFloat( MSG_ENTITY, self.flags ); // Flags, important for physics + return TRUE; +} + +#endif // FTE + void (float achievement_id, float progress_value, optional entity who) UpdateAchievementProgress = { diff --git a/source/server/player.qc b/source/server/player.qc index d74a119..f9e3fad 100644 --- a/source/server/player.qc +++ b/source/server/player.qc @@ -347,6 +347,14 @@ void() PlayerPreThink = float player_trace_time; void() PlayerPostThink = { + +#ifdef FTE + + // Network everything + self.SendFlags = 1; + +#endif // FTE + if(self.isspec) return; @@ -671,6 +679,7 @@ void() PlayerSpawn = stuffcmd(self, "cl_gunx 8;cl_guny 16;cl_gunz 25\n"); SetRound(self, G_STARTROUND); self.viewzoom = 1; + self.SendEntity = Player_SendEntity; self.weapon_animduration = getWeaponDelay(self.weapon, FIRE); if (G_WORLDTEXT)