Propagation of some of the weapon variables needed for prediction. Resetting of map entities for when a solo player spawns (risky, but needs testing!)

This commit is contained in:
Marco Cawthorne 2019-08-21 15:49:35 -07:00
parent ffb5ca5ff1
commit 8fd19cddc0
20 changed files with 158 additions and 60 deletions

View file

@ -22,14 +22,14 @@ void Predict_PreFrame(player pl)
pl.netflags = pl.flags; pl.netflags = pl.flags;
pl.netjumptime = pl.jumptime; pl.netjumptime = pl.jumptime;
pl.netteleport_time = pl.teleport_time; pl.netteleport_time = pl.teleport_time;
#ifdef VALVE #ifdef VALVE
//pl.net_w_attack_next = pl.w_attack_next; pl.net_w_attack_next = pl.w_attack_next;
//pl.net_w_idle_next = pl.w_idle_next; pl.net_w_idle_next = pl.w_idle_next;
pl.net_ammo1 = pl.a_ammo1; pl.net_ammo1 = pl.a_ammo1;
pl.net_ammo2 = pl.a_ammo2; pl.net_ammo2 = pl.a_ammo2;
pl.net_ammo3 = pl.a_ammo3; pl.net_ammo3 = pl.a_ammo3;
//pl.net_weapontime = pSeat->eViewModel.frame1time; pl.net_weapontime = pl.weapontime;
#endif #endif
//self.netpmove_flags = self.pmove_flags; //self.netpmove_flags = self.pmove_flags;
@ -37,8 +37,9 @@ void Predict_PreFrame(player pl)
//we want to predict an exact copy of the data in the new packet //we want to predict an exact copy of the data in the new packet
/*for (; self.pmove_frame <= servercommandframe; self.pmove_frame++) { /*for (; self.pmove_frame <= servercommandframe; self.pmove_frame++) {
float flSuccess = getinputstate(self.pmove_frame);*/ float flSuccess = getinputstate(self.pmove_frame);*/
for ( int i = servercommandframe + 1; i <= clientcommandframe; i++ ) { for ( int i = pl.sequence + 1; i <= clientcommandframe; i++ ) {
float flSuccess = getinputstate( i ); float flSuccess = getinputstate( i );
input_sequence = i;
if (flSuccess == FALSE) { if (flSuccess == FALSE) {
continue; continue;
} }
@ -60,8 +61,8 @@ void Predict_PreFrame(player pl)
Predict_PostFrame Predict_PostFrame
We're part way through parsing new player data. We're part way through parsing new player data.
Propagate our pmove state to whatever the current frame before its stomped on Rewind our pmove state back to before we started predicting.
(so any non-networked state updates locally). (to give consistent state instead of accumulating errors)
================= =================
*/ */
void Predict_PostFrame(player pl) void Predict_PostFrame(player pl)
@ -73,13 +74,12 @@ void Predict_PostFrame(player pl)
pl.teleport_time = pl.netteleport_time; pl.teleport_time = pl.netteleport_time;
#ifdef VALVE #ifdef VALVE
//pl.w_attack_next = pl.net_w_attack_next; pl.w_attack_next = pl.net_w_attack_next;
//pl.w_idle_next = pl.net_w_idle_next; pl.w_idle_next = pl.net_w_idle_next;
pl.a_ammo1 = pl.net_ammo1; pl.a_ammo1 = pl.net_ammo1;
pl.a_ammo2 = pl.net_ammo2; pl.a_ammo2 = pl.net_ammo2;
pl.a_ammo3 = pl.net_ammo3; pl.a_ammo3 = pl.net_ammo3;
//pSeat->eViewModel.frame1time = pl.net_weapontime; pl.weapontime = pl.net_weapontime;
//pSeat->eViewModel.frame2time = pl.net_weapontime;
#endif #endif
//self.pmove_flags = self.netpmove_flags; //self.pmove_flags = self.netpmove_flags;

View file

@ -70,6 +70,8 @@ void HUD_DrawWeaponSelect_Back(void)
void HUD_DrawWeaponSelect_Trigger(void) void HUD_DrawWeaponSelect_Trigger(void)
{ {
player pl = (player)pSeat->ePlayer;
pl.activeweapon = pSeat->fHUDWeaponSelected;
sendevent("PlayerSwitchWeapon", "f", pSeat->fHUDWeaponSelected); sendevent("PlayerSwitchWeapon", "f", pSeat->fHUDWeaponSelected);
sound(pSeat->ePlayer, CHAN_ITEM, "common/wpn_select.wav", 0.5f, ATTN_NONE); sound(pSeat->ePlayer, CHAN_ITEM, "common/wpn_select.wav", 0.5f, ATTN_NONE);
pSeat->fHUDWeaponSelected = pSeat->fHUDWeaponSelectTime = 0; pSeat->fHUDWeaponSelected = pSeat->fHUDWeaponSelectTime = 0;

View file

@ -6,6 +6,19 @@
* *
****/ ****/
//FOR DEBUGGING ONLY, remove when prediction is trusted (along with the extra network bloat).
static void warnifdiff(string name, __inout float expected, float got)
{
//this should only fire from prediction misses.
//this hopefully only happens when the server's anti-time-banking logic does its thing, or for things caused by other players/ents getting in the way.
if (expected != got)
print(sprintf("%s differs, expected %g, got %g\n", name, expected, got));
//enable the following line if you want to see if it actually makes a difference.
//expected = got;
}
void Player_ReadEntity(float flIsNew) void Player_ReadEntity(float flIsNew)
{ {
player pl = (player)self; player pl = (player)self;
@ -16,37 +29,56 @@ void Player_ReadEntity(float flIsNew)
pl.drawmask = MASK_ENGINE; pl.drawmask = MASK_ENGINE;
pl.customphysics = Empty; pl.customphysics = Empty;
setsize( pl, VEC_HULL_MIN, VEC_HULL_MAX ); setsize( pl, VEC_HULL_MIN, VEC_HULL_MAX );
}
pl.modelindex = readshort(); print(sprintf("Player %g is csqc ent %i\n", pl.entnum, pl));
}
else
{
if (pl.entnum == player_localentnum) //FIXME: splitscreen
{
pSeat = &seats[0]; //FIXME: splitscreen
for (int i = pl.sequence+1; i <= servercommandframe; i++)
{
if (!getinputstate(i))
break; //erk?... too old?
input_sequence = i;
QPhysics_Run(pl);
}
//any differences in things that are read below are now officially from prediction misses.
}
}
pl.sequence = servercommandframe;
pl.modelindex = readshort(); //make conditional
pl.origin[0] = readcoord(); pl.origin[0] = readcoord();
pl.origin[1] = readcoord(); pl.origin[1] = readcoord();
pl.origin[2] = readcoord(); pl.origin[2] = readcoord(); //make conditional
pl.pitch = readfloat(); pl.pitch = readfloat();
pl.angles[1] = readfloat(); pl.angles[1] = readfloat();
pl.angles[2] = readfloat(); pl.angles[2] = readfloat();
pl.velocity[0] = readcoord(); pl.velocity[0] = readcoord();
pl.velocity[1] = readcoord(); pl.velocity[1] = readcoord();
pl.velocity[2] = readcoord(); pl.velocity[2] = readcoord();
pl.flags = readfloat(); pl.flags = readfloat(); //make mostly conditional
pl.activeweapon = readbyte(); pl.activeweapon = readbyte(); //make conditional
pl.weapontime = readfloat(); warnifdiff("weapontime", pl.weapontime, readfloat()); //remove
pl.g_items = readfloat(); pl.g_items = readfloat(); //make conditional
pl.health = readbyte(); pl.health = readbyte(); //make conditional
pl.armor = readbyte(); pl.armor = readbyte(); //make conditional
pl.movetype = readbyte(); pl.movetype = readbyte(); //make conditional
pl.view_ofs[2] = readfloat(); pl.view_ofs[2] = readfloat(); //make conditional
pl.viewzoom = readfloat(); pl.viewzoom = readfloat(); //remove? or make conditional
pl.jumptime = readfloat(); warnifdiff("jumptime", pl.jumptime, readfloat()); //remove
pl.teleport_time = readfloat(); warnifdiff("teletime", pl.teleport_time, readfloat()); //remove
pl.baseframe = readbyte(); pl.baseframe = readbyte(); //make conditional
pl.frame = readbyte(); pl.frame = readbyte(); //make conditional
pl.a_ammo1 = readbyte(); pl.a_ammo1 = readbyte(); //make conditional
pl.a_ammo2 = readbyte(); pl.a_ammo2 = readbyte(); //make conditional
pl.a_ammo3 = readbyte(); pl.a_ammo3 = readbyte(); //make conditional
//pl.w_attack_next = readfloat(); warnifdiff("attack_next", pl.w_attack_next, readfloat()); //remove
//pl.w_idle_next = readfloat(); warnifdiff("idle_next", pl.w_idle_next, readfloat()); //remove
setorigin( pl, pl.origin ); setorigin( pl, pl.origin );
} }

View file

@ -193,7 +193,7 @@ void View_DrawViewModel(void)
float fBaseTime = eViewModel.frame1time; float fBaseTime = eViewModel.frame1time;
eViewModel.frame2time = pl.weapontime; eViewModel.frame2time = pl.weapontime;
eViewModel.frame1time = pl.weapontime; eViewModel.frame1time = pl.weapontime;
//processmodelevents(eViewModel.modelindex, eViewModel.frame, fBaseTime, eViewModel.frame1time, Event_ProcessModel); processmodelevents(eViewModel.modelindex, eViewModel.frame, fBaseTime, eViewModel.frame1time, Event_ProcessModel);
} }
makevectors(view_angles); makevectors(view_angles);

View file

@ -231,6 +231,7 @@ void Game_Worldspawn(void)
precache_model("models/player/vip/vip.mdl"); precache_model("models/player/vip/vip.mdl");
precache_model("models/w_c4.mdl"); precache_model("models/w_c4.mdl");
precache_sound("misc/null.wav");
precache_sound("hostage/hos1.wav"); precache_sound("hostage/hos1.wav");
precache_sound("hostage/hos2.wav"); precache_sound("hostage/hos2.wav");
precache_sound("hostage/hos3.wav"); precache_sound("hostage/hos3.wav");

View file

@ -14,6 +14,10 @@ void Flashlight_Toggle(void)
} }
} }
if (self.health <= 0) {
return;
}
if (self.flags & FL_FLASHLIGHT) { if (self.flags & FL_FLASHLIGHT) {
self.flags &= ~FL_FLASHLIGHT; self.flags &= ~FL_FLASHLIGHT;
} else { } else {

View file

@ -11,6 +11,19 @@ void Empty(void) {}
void Game_ClientConnect(void) void Game_ClientConnect(void)
{ {
bprint(PRINT_HIGH, sprintf("%s connected\n", self.netname)); bprint(PRINT_HIGH, sprintf("%s connected\n", self.netname));
int playercount = 0;
for (entity eFind = world; (eFind = find(eFind, classname, "player"));) {
playercount++;
}
/* We're the first. */
if (playercount == 0) {
for (entity a = world; (a = findfloat(a, gflags, GF_CANRESPAWN));) {
CBaseEntity caw = (CBaseEntity)a;
caw.Respawn();
}
}
} }
void Game_ClientDisconnect(void) void Game_ClientDisconnect(void)

View file

@ -19,6 +19,21 @@ float Game_ConsoleCmd(string cmd)
void Game_Worldspawn(void) void Game_Worldspawn(void)
{ {
precache_model("models/player.mdl"); precache_model("models/player.mdl");
Weapons_Init(); precache_model("models/w_weaponbox.mdl");
precache_sound("misc/null.wav");
precache_sound("fvox/flatline.wav");
/* TODO: Scan and precache models/player/.mdl */
precache_model("models/player/barney/barney.mdl");
precache_model("models/player/gman/gman.mdl");
precache_model("models/player/gordon/gordon.mdl");
precache_model("models/player/hgrunt/hgrunt.mdl");
precache_model("models/player/scientist/scientist.mdl");
precache_model("models/player/zombie/zombie.mdl");
precache_model("models/player/helmet/helmet.mdl");
precache_model("models/player/recon/recon.mdl");
precache_model("models/player/robo/robo.mdl");
Weapons_Init();
SHData_Parse(mapname); SHData_Parse(mapname);
} }

View file

@ -11,6 +11,19 @@ void Empty(void) {}
void Game_ClientConnect(void) void Game_ClientConnect(void)
{ {
bprint(PRINT_HIGH, sprintf("%s connected\n", self.netname)); bprint(PRINT_HIGH, sprintf("%s connected\n", self.netname));
int playercount = 0;
for (entity eFind = world; (eFind = find(eFind, classname, "player"));) {
playercount++;
}
/* We're the first. */
if (playercount == 0) {
for (entity a = world; (a = findfloat(a, gflags, GF_CANRESPAWN));) {
CBaseEntity caw = (CBaseEntity)a;
caw.Respawn();
}
}
} }
void Game_ClientDisconnect(void) void Game_ClientDisconnect(void)

View file

@ -19,6 +19,7 @@ void Player_Death(int hit)
pl.movetype = MOVETYPE_NONE; pl.movetype = MOVETYPE_NONE;
pl.solid = SOLID_NOT; pl.solid = SOLID_NOT;
pl.takedamage = DAMAGE_NO; pl.takedamage = DAMAGE_NO;
pl.flags &= ~FL_FLASHLIGHT;
pl.health = pl.armor = pl.activeweapon = pl.g_items = 0; pl.health = pl.armor = pl.activeweapon = pl.g_items = 0;
pl.think = PutClientInServer; pl.think = PutClientInServer;
@ -138,8 +139,8 @@ float Player_SendEntity(entity ePEnt, float fChanged)
WriteByte(MSG_ENTITY, pl.a_ammo1); WriteByte(MSG_ENTITY, pl.a_ammo1);
WriteByte(MSG_ENTITY, pl.a_ammo2); WriteByte(MSG_ENTITY, pl.a_ammo2);
WriteByte(MSG_ENTITY, pl.a_ammo3); WriteByte(MSG_ENTITY, pl.a_ammo3);
//WriteFloat(MSG_ENTITY, pl.w_attack_next); WriteFloat(MSG_ENTITY, pl.w_attack_next);
//WriteFloat(MSG_ENTITY, pl.w_idle_next); WriteFloat(MSG_ENTITY, pl.w_idle_next);
return TRUE; return TRUE;
} }

View file

@ -19,5 +19,20 @@ float Game_ConsoleCmd(string cmd)
void Game_Worldspawn(void) void Game_Worldspawn(void)
{ {
precache_model("models/player.mdl"); precache_model("models/player.mdl");
precache_model("models/w_weaponbox.mdl");
precache_sound("misc/null.wav");
precache_sound("fvox/flatline.wav");
/* TODO: Scan and precache models/player/.mdl */
precache_model("models/player/barney/barney.mdl");
precache_model("models/player/gman/gman.mdl");
precache_model("models/player/gordon/gordon.mdl");
precache_model("models/player/hgrunt/hgrunt.mdl");
precache_model("models/player/scientist/scientist.mdl");
precache_model("models/player/zombie/zombie.mdl");
precache_model("models/player/helmet/helmet.mdl");
precache_model("models/player/recon/recon.mdl");
precache_model("models/player/robo/robo.mdl");
Weapons_Init(); Weapons_Init();
} }

View file

@ -721,15 +721,9 @@ void PMove_Run(void)
#ifdef VALVE #ifdef VALVE
player pl = (player)self; player pl = (player)self;
pl.w_attack_next -= input_timelength; pl.w_attack_next = max(0, pl.w_attack_next-input_timelength);
pl.w_idle_next -= input_timelength; pl.w_idle_next = max(0, pl.w_idle_next-input_timelength);
pl.weapontime += input_timelength; pl.weapontime += input_timelength;
if (pl.w_attack_next <= 0) {
pl.w_attack_next = 0;
}
if (pl.w_idle_next <= 0) {
pl.w_idle_next = 0;
}
#endif #endif
Game_Input(); Game_Input();

View file

@ -1,4 +1,4 @@
int input_sequence;
class player class player
{ {
float health; float health;
@ -56,6 +56,8 @@ class player
int net_ammo1; int net_ammo1;
int net_ammo2; int net_ammo2;
int net_ammo3; int net_ammo3;
int sequence;
virtual void() gun_offset; virtual void() gun_offset;
virtual void() draw; virtual void() draw;
virtual float() predraw; virtual float() predraw;

View file

@ -28,9 +28,11 @@ void w_cannon_precache(void)
precache_sound("cannon/fire.wav"); precache_sound("cannon/fire.wav");
precache_sound("cannon/open.wav"); precache_sound("cannon/open.wav");
} }
string w_cannon_vmodel(void) void w_cannon_updateammo(player pl)
{ {
return "models/v_cannon.mdl"; #ifdef SSQC
Weapons_UpdateAmmo(pl, pl.cannon_mag, pl.ammo_buckshot, __NULL__);
#endif
} }
string w_cannon_pmodel(void) string w_cannon_pmodel(void)
{ {
@ -218,7 +220,7 @@ weapon_t w_cannon =
w_cannon_crosshair, w_cannon_crosshair,
w_cannon_precache, w_cannon_precache,
w_cannon_pickup, w_cannon_pickup,
w_cannon_vmodel, w_cannon_updateammo,
__NULL__, __NULL__,
w_cannon_pmodel, w_cannon_pmodel,
w_cannon_deathmsg, w_cannon_deathmsg,

View file

@ -29,9 +29,11 @@ void w_chainsaw_precache(void)
precache_model("models/p_saw.mdl"); precache_model("models/p_saw.mdl");
} }
string w_chainsaw_vmodel(void) void w_chainsaw_updateammo(player pl)
{ {
return "models/v_chainsaw.mdl"; #ifdef SSQC
Weapons_UpdateAmmo(pl, __NULL__, __NULL__, __NULL__);
#endif
} }
string w_chainsaw_pmodel(void) string w_chainsaw_pmodel(void)
{ {
@ -157,7 +159,7 @@ weapon_t w_chainsaw =
__NULL__, __NULL__,
w_chainsaw_precache, w_chainsaw_precache,
__NULL__, __NULL__,
w_chainsaw_vmodel, w_chainsaw_updateammo,
__NULL__, __NULL__,
w_chainsaw_pmodel, w_chainsaw_pmodel,
w_chainsaw_deathmsg, w_chainsaw_deathmsg,

View file

@ -30,9 +30,11 @@ void w_hammer_precache(void)
precache_model("models/v_hammer.mdl"); precache_model("models/v_hammer.mdl");
} }
string w_hammer_vmodel(void) void w_hammer_updateammo(player pl)
{ {
return "models/v_hammer.mdl"; #ifdef SSQC
Weapons_UpdateAmmo(pl, __NULL__, __NULL__, __NULL__);
#endif
} }
string w_hammer_pmodel(void) string w_hammer_pmodel(void)
{ {
@ -217,7 +219,7 @@ weapon_t w_hammer =
__NULL__, __NULL__,
w_hammer_precache, w_hammer_precache,
__NULL__, __NULL__,
w_hammer_vmodel, w_hammer_updateammo,
__NULL__, __NULL__,
w_hammer_pmodel, w_hammer_pmodel,
w_hammer_deathmsg, w_hammer_deathmsg,

View file

@ -1,3 +1,4 @@
int input_sequence;
class player class player
{ {
float health; float health;
@ -53,6 +54,7 @@ class player
int net_ammo1; int net_ammo1;
int net_ammo2; int net_ammo2;
int net_ammo3; int net_ammo3;
int sequence;
virtual void() gun_offset; virtual void() gun_offset;
virtual void() draw; virtual void() draw;

View file

@ -73,7 +73,7 @@ void w_crowbar_primary(void)
vector src = pl.origin + pl.view_ofs; vector src = pl.origin + pl.view_ofs;
traceline(src, src + (v_forward * 32), FALSE, pl); traceline(src, src + (v_forward * 32), FALSE, pl);
int r = floor(random(0,3)); int r = (float)input_sequence%3;
switch (r) { switch (r) {
case 0: case 0:
Weapons_ViewAnimation(trace_fraction >= 1 ? CROWBAR_ATTACK1MISS:CROWBAR_ATTACK1HIT); Weapons_ViewAnimation(trace_fraction >= 1 ? CROWBAR_ATTACK1MISS:CROWBAR_ATTACK1HIT);

View file

@ -110,7 +110,7 @@ void w_handgrenade_throw(void)
void w_handgrenade_draw(void) void w_handgrenade_draw(void)
{ {
Weapons_SetModel("models/v_crowbar.mdl"); Weapons_SetModel("models/v_grenade.mdl");
Weapons_ViewAnimation(HANDGRENADE_DRAW); Weapons_ViewAnimation(HANDGRENADE_DRAW);
#ifdef SSQC #ifdef SSQC
player pl = (player)self; player pl = (player)self;

View file

@ -38,9 +38,7 @@ void Weapons_Draw(void)
if (g_weapons[i].draw != __NULL__) { if (g_weapons[i].draw != __NULL__) {
g_weapons[i].draw(); g_weapons[i].draw();
} }
#ifdef CSQC #ifdef SSQC
View_UpdateWeapon(pSeat->eViewModel, pSeat->eMuzzleflash);
#else
if (g_weapons[i].updateammo != __NULL__) { if (g_weapons[i].updateammo != __NULL__) {
g_weapons[i].updateammo(pl); g_weapons[i].updateammo(pl);
} }