Obliterate resynch

Okay, more precisely this substitutes the old resynch with
the newly added gamestate resend code.
This commit is contained in:
Louis-Antoine 2020-03-01 03:22:47 +01:00
parent 29d8389461
commit 846560910d
3 changed files with 31 additions and 848 deletions

View file

@ -83,6 +83,7 @@ char playeraddress[MAXPLAYERS][64];
// The actual timeout will be longer depending on the savegame length
tic_t jointimeout = (10*TICRATE);
static boolean sendingsavegame[MAXNETNODES]; // Are we sending the savegame?
static boolean resendingsavegame[MAXNETNODES]; // Are we resending the savegame?
static tic_t freezetimeout[MAXNETNODES]; // Until when can this node freeze the server before getting a timeout?
UINT16 pingmeasurecount = 1;
@ -102,15 +103,8 @@ static tic_t maketic;
static INT16 consistancy[BACKUPTICS];
// Resynching shit!
static UINT32 resynch_score[MAXNETNODES]; // "score" for kicking -- if this gets too high then cfail kick
static UINT16 resynch_delay[MAXNETNODES]; // delay time before the player can be considered to have desynched
static UINT32 resynch_status[MAXNETNODES]; // 0 bit means synched for that player, 1 means possibly desynched
static UINT8 resynch_sent[MAXNETNODES][MAXPLAYERS]; // what synch packets have we attempted to send to the player
static UINT8 resynch_inprogress[MAXNETNODES];
static UINT8 resynch_local_inprogress = false; // WE are desynched and getting packets to fix it.
static UINT8 player_joining = false;
UINT8 hu_resynching = 0;
UINT8 hu_redownloadinggamestate = 0;
UINT8 adminpassmd5[16];
boolean adminpasswordset = false;
@ -504,597 +498,6 @@ void ReadLmpExtraData(UINT8 **demo_pointer, INT32 playernum)
// end extra data function for lmps
// -----------------------------------------------------------------
// -----------------------------------------------------------------
// resynch player data
// -----------------------------------------------------------------
static inline void resynch_write_player(resynch_pak *rsp, const size_t i)
{
size_t j;
rsp->playernum = (UINT8)i;
// Do not send anything visual related.
// Only send data that we need to know for physics.
rsp->playerstate = (UINT8)players[i].playerstate; //playerstate_t
rsp->pflags = (UINT32)LONG(players[i].pflags); //pflags_t
rsp->panim = (UINT8)players[i].panim; //panim_t
rsp->aiming = (angle_t)LONG(players[i].aiming);
rsp->currentweapon = LONG(players[i].currentweapon);
rsp->ringweapons = LONG(players[i].ringweapons);
rsp->ammoremoval = (UINT16)SHORT(players[i].ammoremoval);
rsp->ammoremovaltimer = (tic_t)LONG(players[i].ammoremovaltimer);
rsp->ammoremovalweapon = LONG(players[i].ammoremovalweapon);
for (j = 0; j < NUMPOWERS; ++j)
rsp->powers[j] = (UINT16)SHORT(players[i].powers[j]);
// Score is resynched in the rspfirm resync packet
rsp->rings = SHORT(players[i].rings);
rsp->spheres = SHORT(players[i].spheres);
rsp->lives = players[i].lives;
rsp->continues = players[i].continues;
rsp->scoreadd = players[i].scoreadd;
rsp->xtralife = players[i].xtralife;
rsp->pity = players[i].pity;
rsp->skincolor = players[i].skincolor;
rsp->skin = LONG(players[i].skin);
rsp->availabilities = LONG(players[i].availabilities);
// Just in case Lua does something like
// modify these at runtime
rsp->camerascale = (fixed_t)LONG(players[i].camerascale);
rsp->shieldscale = (fixed_t)LONG(players[i].shieldscale);
rsp->normalspeed = (fixed_t)LONG(players[i].normalspeed);
rsp->runspeed = (fixed_t)LONG(players[i].runspeed);
rsp->thrustfactor = players[i].thrustfactor;
rsp->accelstart = players[i].accelstart;
rsp->acceleration = players[i].acceleration;
rsp->charability = players[i].charability;
rsp->charability2 = players[i].charability2;
rsp->charflags = (UINT32)LONG(players[i].charflags);
rsp->thokitem = (UINT32)LONG(players[i].thokitem); //mobjtype_t
rsp->spinitem = (UINT32)LONG(players[i].spinitem); //mobjtype_t
rsp->revitem = (UINT32)LONG(players[i].revitem); //mobjtype_t
rsp->followitem = (UINT32)LONG(players[i].followitem); //mobjtype_t
rsp->actionspd = (fixed_t)LONG(players[i].actionspd);
rsp->mindash = (fixed_t)LONG(players[i].mindash);
rsp->maxdash = (fixed_t)LONG(players[i].maxdash);
rsp->jumpfactor = (fixed_t)LONG(players[i].jumpfactor);
rsp->playerheight = (fixed_t)LONG(players[i].height);
rsp->playerspinheight = (fixed_t)LONG(players[i].spinheight);
rsp->speed = (fixed_t)LONG(players[i].speed);
rsp->secondjump = players[i].secondjump;
rsp->fly1 = players[i].fly1;
rsp->glidetime = (tic_t)LONG(players[i].glidetime);
rsp->climbing = players[i].climbing;
rsp->deadtimer = players[i].deadtimer;
rsp->exiting = (tic_t)LONG(players[i].exiting);
rsp->homing = players[i].homing;
rsp->dashmode = (tic_t)LONG(players[i].dashmode);
rsp->skidtime = (tic_t)LONG(players[i].skidtime);
rsp->cmomx = (fixed_t)LONG(players[i].cmomx);
rsp->cmomy = (fixed_t)LONG(players[i].cmomy);
rsp->rmomx = (fixed_t)LONG(players[i].rmomx);
rsp->rmomy = (fixed_t)LONG(players[i].rmomy);
rsp->weapondelay = LONG(players[i].weapondelay);
rsp->tossdelay = LONG(players[i].tossdelay);
rsp->starpostx = SHORT(players[i].starpostx);
rsp->starposty = SHORT(players[i].starposty);
rsp->starpostz = SHORT(players[i].starpostz);
rsp->starpostnum = LONG(players[i].starpostnum);
rsp->starposttime = (tic_t)LONG(players[i].starposttime);
rsp->starpostangle = (angle_t)LONG(players[i].starpostangle);
rsp->starpostscale = (fixed_t)LONG(players[i].starpostscale);
rsp->maxlink = LONG(players[i].maxlink);
rsp->dashspeed = (fixed_t)LONG(players[i].dashspeed);
rsp->angle_pos = (angle_t)LONG(players[i].angle_pos);
rsp->old_angle_pos = (angle_t)LONG(players[i].old_angle_pos);
rsp->bumpertime = (tic_t)LONG(players[i].bumpertime);
rsp->flyangle = LONG(players[i].flyangle);
rsp->drilltimer = (tic_t)LONG(players[i].drilltimer);
rsp->linkcount = LONG(players[i].linkcount);
rsp->linktimer = (tic_t)LONG(players[i].linktimer);
rsp->anotherflyangle = LONG(players[i].anotherflyangle);
rsp->nightstime = (tic_t)LONG(players[i].nightstime);
rsp->drillmeter = LONG(players[i].drillmeter);
rsp->drilldelay = players[i].drilldelay;
rsp->bonustime = players[i].bonustime;
rsp->mare = players[i].mare;
rsp->lastsidehit = SHORT(players[i].lastsidehit);
rsp->lastlinehit = SHORT(players[i].lastlinehit);
rsp->losstime = (tic_t)LONG(players[i].losstime);
rsp->timeshit = players[i].timeshit;
rsp->onconveyor = LONG(players[i].onconveyor);
rsp->hasmo = false;
//Transfer important mo information if the player has a body.
//This lets us resync players even if they are dead.
if (!players[i].mo)
return;
rsp->hasmo = true;
rsp->health = LONG(players[i].mo->health);
rsp->angle = (angle_t)LONG(players[i].mo->angle);
rsp->rollangle = (angle_t)LONG(players[i].mo->rollangle);
rsp->x = LONG(players[i].mo->x);
rsp->y = LONG(players[i].mo->y);
rsp->z = LONG(players[i].mo->z);
rsp->momx = LONG(players[i].mo->momx);
rsp->momy = LONG(players[i].mo->momy);
rsp->momz = LONG(players[i].mo->momz);
rsp->friction = LONG(players[i].mo->friction);
rsp->movefactor = LONG(players[i].mo->movefactor);
rsp->sprite = (spritenum_t)LONG(players[i].mo->sprite);
rsp->frame = LONG(players[i].mo->frame);
rsp->sprite2 = players[i].mo->sprite2;
rsp->anim_duration = SHORT(players[i].mo->anim_duration);
rsp->tics = LONG(players[i].mo->tics);
rsp->statenum = (statenum_t)LONG(players[i].mo->state-states); // :(
rsp->eflags = (UINT16)SHORT(players[i].mo->eflags);
rsp->flags = LONG(players[i].mo->flags);
rsp->flags2 = LONG(players[i].mo->flags2);
rsp->radius = LONG(players[i].mo->radius);
rsp->height = LONG(players[i].mo->height);
rsp->scale = LONG(players[i].mo->scale);
rsp->destscale = LONG(players[i].mo->destscale);
rsp->scalespeed = LONG(players[i].mo->scalespeed);
}
static void resynch_read_player(resynch_pak *rsp)
{
INT32 i = rsp->playernum, j;
mobj_t *savedmo = players[i].mo;
// Do not send anything visual related.
// Only send data that we need to know for physics.
players[i].playerstate = (UINT8)rsp->playerstate; //playerstate_t
players[i].pflags = (UINT32)LONG(rsp->pflags); //pflags_t
players[i].panim = (UINT8)rsp->panim; //panim_t
players[i].aiming = (angle_t)LONG(rsp->aiming);
players[i].currentweapon = LONG(rsp->currentweapon);
players[i].ringweapons = LONG(rsp->ringweapons);
players[i].ammoremoval = (UINT16)SHORT(rsp->ammoremoval);
players[i].ammoremovaltimer = (tic_t)LONG(rsp->ammoremovaltimer);
players[i].ammoremovalweapon = LONG(rsp->ammoremovalweapon);
for (j = 0; j < NUMPOWERS; ++j)
players[i].powers[j] = (UINT16)SHORT(rsp->powers[j]);
// Score is resynched in the rspfirm resync packet
players[i].rings = SHORT(rsp->rings);
players[i].spheres = SHORT(rsp->spheres);
players[i].lives = rsp->lives;
players[i].continues = rsp->continues;
players[i].scoreadd = rsp->scoreadd;
players[i].xtralife = rsp->xtralife;
players[i].pity = rsp->pity;
players[i].skincolor = rsp->skincolor;
players[i].skin = LONG(rsp->skin);
players[i].availabilities = LONG(rsp->availabilities);
// Just in case Lua does something like
// modify these at runtime
players[i].camerascale = (fixed_t)LONG(rsp->camerascale);
players[i].shieldscale = (fixed_t)LONG(rsp->shieldscale);
players[i].normalspeed = (fixed_t)LONG(rsp->normalspeed);
players[i].runspeed = (fixed_t)LONG(rsp->runspeed);
players[i].thrustfactor = rsp->thrustfactor;
players[i].accelstart = rsp->accelstart;
players[i].acceleration = rsp->acceleration;
players[i].charability = rsp->charability;
players[i].charability2 = rsp->charability2;
players[i].charflags = (UINT32)LONG(rsp->charflags);
players[i].thokitem = (UINT32)LONG(rsp->thokitem); //mobjtype_t
players[i].spinitem = (UINT32)LONG(rsp->spinitem); //mobjtype_t
players[i].revitem = (UINT32)LONG(rsp->revitem); //mobjtype_t
players[i].followitem = (UINT32)LONG(rsp->followitem); //mobjtype_t
players[i].actionspd = (fixed_t)LONG(rsp->actionspd);
players[i].mindash = (fixed_t)LONG(rsp->mindash);
players[i].maxdash = (fixed_t)LONG(rsp->maxdash);
players[i].jumpfactor = (fixed_t)LONG(rsp->jumpfactor);
players[i].height = (fixed_t)LONG(rsp->playerheight);
players[i].spinheight = (fixed_t)LONG(rsp->playerspinheight);
players[i].speed = (fixed_t)LONG(rsp->speed);
players[i].secondjump = rsp->secondjump;
players[i].fly1 = rsp->fly1;
players[i].glidetime = (tic_t)LONG(rsp->glidetime);
players[i].climbing = rsp->climbing;
players[i].deadtimer = rsp->deadtimer;
players[i].exiting = (tic_t)LONG(rsp->exiting);
players[i].homing = rsp->homing;
players[i].dashmode = (tic_t)LONG(rsp->dashmode);
players[i].skidtime = (tic_t)LONG(rsp->skidtime);
players[i].cmomx = (fixed_t)LONG(rsp->cmomx);
players[i].cmomy = (fixed_t)LONG(rsp->cmomy);
players[i].rmomx = (fixed_t)LONG(rsp->rmomx);
players[i].rmomy = (fixed_t)LONG(rsp->rmomy);
players[i].weapondelay = LONG(rsp->weapondelay);
players[i].tossdelay = LONG(rsp->tossdelay);
players[i].starpostx = SHORT(rsp->starpostx);
players[i].starposty = SHORT(rsp->starposty);
players[i].starpostz = SHORT(rsp->starpostz);
players[i].starpostnum = LONG(rsp->starpostnum);
players[i].starposttime = (tic_t)LONG(rsp->starposttime);
players[i].starpostangle = (angle_t)LONG(rsp->starpostangle);
players[i].starpostscale = (fixed_t)LONG(rsp->starpostscale);
players[i].maxlink = LONG(rsp->maxlink);
players[i].dashspeed = (fixed_t)LONG(rsp->dashspeed);
players[i].angle_pos = (angle_t)LONG(rsp->angle_pos);
players[i].old_angle_pos = (angle_t)LONG(rsp->old_angle_pos);
players[i].bumpertime = (tic_t)LONG(rsp->bumpertime);
players[i].flyangle = LONG(rsp->flyangle);
players[i].drilltimer = (tic_t)LONG(rsp->drilltimer);
players[i].linkcount = LONG(rsp->linkcount);
players[i].linktimer = (tic_t)LONG(rsp->linktimer);
players[i].anotherflyangle = LONG(rsp->anotherflyangle);
players[i].nightstime = (tic_t)LONG(rsp->nightstime);
players[i].drillmeter = LONG(rsp->drillmeter);
players[i].drilldelay = rsp->drilldelay;
players[i].bonustime = rsp->bonustime;
players[i].mare = rsp->mare;
players[i].lastsidehit = SHORT(rsp->lastsidehit);
players[i].lastlinehit = SHORT(rsp->lastlinehit);
players[i].losstime = (tic_t)LONG(rsp->losstime);
players[i].timeshit = rsp->timeshit;
players[i].onconveyor = LONG(rsp->onconveyor);
//We get a packet for each player in game.
if (!playeringame[i])
return;
//...but keep old mo even if it is corrupt or null!
players[i].mo = savedmo;
//Transfer important mo information if they have a valid mo.
if (!rsp->hasmo)
return;
//server thinks player has a body.
//Give them a new body that can be then manipulated by the server's info.
if (!players[i].mo) //client thinks it has no body.
P_SpawnPlayer(i);
//At this point, the player should have a body, whether they were respawned or not.
P_UnsetThingPosition(players[i].mo);
players[i].mo->angle = (angle_t)LONG(rsp->angle);
players[i].mo->rollangle = (angle_t)LONG(rsp->rollangle);
players[i].mo->eflags = (UINT16)SHORT(rsp->eflags);
players[i].mo->flags = LONG(rsp->flags);
players[i].mo->flags2 = LONG(rsp->flags2);
players[i].mo->friction = LONG(rsp->friction);
players[i].mo->health = LONG(rsp->health);
players[i].mo->momx = LONG(rsp->momx);
players[i].mo->momy = LONG(rsp->momy);
players[i].mo->momz = LONG(rsp->momz);
players[i].mo->movefactor = LONG(rsp->movefactor);
// Don't use P_SetMobjStateNF to restore state, write/read all the values manually!
// This should stop those stupid console errors, hopefully.
// -- Monster Iestyn
players[i].mo->sprite = (spritenum_t)LONG(rsp->sprite);
players[i].mo->frame = LONG(rsp->frame);
players[i].mo->sprite2 = rsp->sprite2;
players[i].mo->anim_duration = SHORT(rsp->anim_duration);
players[i].mo->tics = LONG(rsp->tics);
players[i].mo->state = &states[LONG(rsp->statenum)];
players[i].mo->x = LONG(rsp->x);
players[i].mo->y = LONG(rsp->y);
players[i].mo->z = LONG(rsp->z);
players[i].mo->radius = LONG(rsp->radius);
players[i].mo->height = LONG(rsp->height);
// P_SetScale is redundant for this, as all related variables are already restored properly.
players[i].mo->scale = LONG(rsp->scale);
players[i].mo->destscale = LONG(rsp->destscale);
players[i].mo->scalespeed = LONG(rsp->scalespeed);
// And finally, SET THE MOBJ SKIN damn it.
if ((players[i].powers[pw_carry] == CR_NIGHTSMODE) && (skins[players[i].skin].sprites[SPR2_NFLY].numframes == 0))
{
players[i].mo->skin = &skins[DEFAULTNIGHTSSKIN];
players[i].mo->color = skins[DEFAULTNIGHTSSKIN].prefcolor; // this will be corrected by thinker to super flash
}
else
{
players[i].mo->skin = &skins[players[i].skin];
players[i].mo->color = players[i].skincolor; // this will be corrected by thinker to super flash/mario star
}
P_SetThingPosition(players[i].mo);
}
static inline void resynch_write_ctf(resynchend_pak *rst)
{
mobj_t *mflag;
UINT8 i, j;
for (i = 0, mflag = redflag; i < 2; ++i, mflag = blueflag)
{
rst->flagx[i] = rst->flagy[i] = rst->flagz[i] = 0;
rst->flagloose[i] = rst->flagflags[i] = 0;
rst->flagplayer[i] = -1;
if (!mflag)
{
// Should be held by a player
for (j = 0; j < MAXPLAYERS; ++j)
{
// GF_REDFLAG is 1, GF_BLUEFLAG is 2
// redflag handling is i=0, blueflag is i=1
// so check for gotflag == (i+1)
if (!playeringame[j] || players[j].gotflag != (i+1))
continue;
rst->flagplayer[i] = (SINT8)j;
break;
}
if (j == MAXPLAYERS) // fine, no I_Error
{
CONS_Alert(CONS_ERROR, "One of the flags has gone completely missing...\n");
rst->flagplayer[i] = -2;
}
continue;
}
rst->flagx[i] = (fixed_t)LONG(mflag->x);
rst->flagy[i] = (fixed_t)LONG(mflag->y);
rst->flagz[i] = (fixed_t)LONG(mflag->z);
rst->flagflags[i] = LONG(mflag->flags2);
rst->flagloose[i] = LONG(mflag->fuse); // Dropped or not?
}
}
static inline void resynch_read_ctf(resynchend_pak *p)
{
UINT8 i;
for (i = 0; i < MAXPLAYERS; ++i)
players[i].gotflag = 0;
// Red flag
if (p->flagplayer[0] == -2)
; // The server doesn't even know what happened to it...
else if (p->flagplayer[0] != -1) // Held by a player
{
if (!playeringame[p->flagplayer[0]])
I_Error("Invalid red flag player %d who isn't in the game!", (INT32)p->flagplayer[0]);
players[p->flagplayer[0]].gotflag = GF_REDFLAG;
if (redflag)
{
P_RemoveMobj(redflag);
redflag = NULL;
}
}
else
{
if (!redflag)
redflag = P_SpawnMobj(0,0,0,MT_REDFLAG);
P_UnsetThingPosition(redflag);
redflag->x = (fixed_t)LONG(p->flagx[0]);
redflag->y = (fixed_t)LONG(p->flagy[0]);
redflag->z = (fixed_t)LONG(p->flagz[0]);
redflag->flags2 = LONG(p->flagflags[0]);
redflag->fuse = LONG(p->flagloose[0]);
P_SetThingPosition(redflag);
}
// Blue flag
if (p->flagplayer[1] == -2)
; // The server doesn't even know what happened to it...
else if (p->flagplayer[1] != -1) // Held by a player
{
if (!playeringame[p->flagplayer[1]])
I_Error("Invalid blue flag player %d who isn't in the game!", (INT32)p->flagplayer[1]);
players[p->flagplayer[1]].gotflag = GF_BLUEFLAG;
if (blueflag)
{
P_RemoveMobj(blueflag);
blueflag = NULL;
}
}
else
{
if (!blueflag)
blueflag = P_SpawnMobj(0,0,0,MT_BLUEFLAG);
P_UnsetThingPosition(blueflag);
blueflag->x = (fixed_t)LONG(p->flagx[1]);
blueflag->y = (fixed_t)LONG(p->flagy[1]);
blueflag->z = (fixed_t)LONG(p->flagz[1]);
blueflag->flags2 = LONG(p->flagflags[1]);
blueflag->fuse = LONG(p->flagloose[1]);
P_SetThingPosition(blueflag);
}
}
static inline void resynch_write_others(resynchend_pak *rst)
{
UINT8 i;
rst->ingame = 0;
rst->outofcoop = 0;
for (i = 0; i < MAXPLAYERS; ++i)
{
if (!playeringame[i])
{
rst->ctfteam[i] = 0;
rst->score[i] = 0;
rst->numboxes[i] = 0;
rst->totalring[i] = 0;
rst->realtime[i] = 0;
rst->laps[i] = 0;
continue;
}
if (!players[i].spectator)
rst->ingame |= (1<<i);
if (players[i].outofcoop)
rst->outofcoop |= (1<<i);
rst->ctfteam[i] = (INT32)LONG(players[i].ctfteam);
rst->score[i] = (UINT32)LONG(players[i].score);
rst->numboxes[i] = SHORT(players[i].numboxes);
rst->totalring[i] = SHORT(players[i].totalring);
rst->realtime[i] = (tic_t)LONG(players[i].realtime);
rst->laps[i] = players[i].laps;
}
// endian safeness
rst->ingame = (UINT32)LONG(rst->ingame);
}
static inline void resynch_read_others(resynchend_pak *p)
{
UINT8 i;
UINT32 loc_ingame = (UINT32)LONG(p->ingame);
UINT32 loc_outofcoop = (UINT32)LONG(p->outofcoop);
for (i = 0; i < MAXPLAYERS; ++i)
{
// We don't care if they're in the game or not, just write all the data.
players[i].spectator = !(loc_ingame & (1<<i));
players[i].outofcoop = (loc_outofcoop & (1<<i));
players[i].ctfteam = (INT32)LONG(p->ctfteam[i]); // no, 0 does not mean spectator, at least not in Match
players[i].score = (UINT32)LONG(p->score[i]);
players[i].numboxes = SHORT(p->numboxes[i]);
players[i].totalring = SHORT(p->totalring[i]);
players[i].realtime = (tic_t)LONG(p->realtime[i]);
players[i].laps = p->laps[i];
}
}
static void SV_InitResynchVars(INT32 node)
{
resynch_delay[node] = TICRATE; // initial one second delay
resynch_score[node] = 0; // clean slate
resynch_status[node] = 0x00;
resynch_inprogress[node] = false;
memset(resynch_sent[node], 0, MAXPLAYERS);
}
static void SV_RequireResynch(INT32 node)
{
INT32 i;
resynch_delay[node] = 10; // Delay before you can fail sync again
resynch_score[node] += 200; // Add score for initial desynch
resynch_status[node] = 0xFFFFFFFF; // No players assumed synched
resynch_inprogress[node] = true; // so we know to send a PT_RESYNCHEND after sync
// Initial setup
memset(resynch_sent[node], 0, MAXPLAYERS);
for (i = 0; i < MAXPLAYERS; ++i)
{
if (!playeringame[i]) // Player not in game so just drop it from required synch
resynch_status[node] &= ~(1<<i);
else if (playernode[i] == node); // instantly update THEIR position
else // Send at random times based on num players
resynch_sent[node][i] = M_RandomKey(D_NumPlayers()>>1)+1;
}
}
static void SV_SendResynch(INT32 node)
{
INT32 i, j;
if (!nodeingame[node])
{
// player left during resynch
// so obviously we don't need to do any of this anymore
resynch_inprogress[node] = false;
return;
}
// resynched?
if (!resynch_status[node])
{
// you are now synched
resynch_inprogress[node] = false;
netbuffer->packettype = PT_RESYNCHEND;
netbuffer->u.resynchend.randomseed = P_GetRandSeed();
if (gametyperules & GTR_TEAMFLAGS)
resynch_write_ctf(&netbuffer->u.resynchend);
resynch_write_others(&netbuffer->u.resynchend);
HSendPacket(node, true, 0, (sizeof(resynchend_pak)));
return;
}
netbuffer->packettype = PT_RESYNCHING;
for (i = 0, j = 0; i < MAXPLAYERS; ++i)
{
// if already synched don't bother
if (!(resynch_status[node] & 1<<i))
continue;
// waiting for a reply or just waiting in general
if (resynch_sent[node][i])
{
--resynch_sent[node][i];
continue;
}
resynch_write_player(&netbuffer->u.resynchpak, i);
HSendPacket(node, false, 0, (sizeof(resynch_pak)));
resynch_sent[node][i] = TICRATE;
resynch_score[node] += 2; // penalty for send
if (++j > 3)
break;
}
if (resynch_score[node] > (unsigned)cv_resynchattempts.value*250)
{
SendKick(nodetoplayer[node], KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
resynch_score[node] = 0;
}
}
static void CL_AcknowledgeResynch(resynch_pak *rsp)
{
resynch_read_player(rsp);
netbuffer->packettype = PT_RESYNCHGET;
netbuffer->u.resynchgot = rsp->playernum;
HSendPacket(servernode, true, 0, sizeof(UINT8));
}
static void SV_AcknowledgeResynchAck(INT32 node, UINT8 rsg)
{
if (rsg >= MAXPLAYERS)
resynch_score[node] += 16384; // lol.
else
{
resynch_status[node] &= ~(1<<rsg);
--resynch_score[node]; // unpenalize
}
// Don't let resynch cause a timeout
freezetimeout[node] = I_GetTime() + connectiontimeout;
}
// -----------------------------------------------------------------
// end resynch
// -----------------------------------------------------------------
static INT16 Consistancy(void);
#ifndef NONET
@ -1617,6 +1020,11 @@ static void CL_LoadReceivedSavegame(boolean reloading)
CONS_Alert(CONS_ERROR, M_GetText("Can't delete %s\n"), tmpsave);
consistancy[gametic%BACKUPTICS] = Consistancy();
CON_ToggleOff();
// Tell the server we have received and reloaded the gamestate
// so they know they can resume the game
netbuffer->packettype = PT_RECEIVEDGAMESTATE;
HSendPacket(servernode, true, 0, 0);
}
static void CL_ReloadReceivedSavegame(void)
@ -2535,7 +1943,6 @@ void CL_Reset(void)
multiplayer = false;
servernode = 0;
server = true;
resynch_local_inprogress = false;
doomcom->numnodes = 1;
doomcom->numslots = 1;
SV_StopServer();
@ -3112,7 +2519,7 @@ static void ResetNode(INT32 node)
nodewaiting[node] = 0;
playerpernode[node] = 0;
sendingsavegame[node] = false;
SV_InitResynchVars(node);
resendingsavegame[node] = false;
}
void SV_ResetServer(void)
@ -3634,12 +3041,6 @@ static void HandleConnect(SINT8 node)
#endif
SV_AddNode(node);
/// \note Wait what???
/// What if the gamestate takes more than one second to get downloaded?
/// Or if a lagspike happens?
// you get a free second before desynch checks. use it wisely.
SV_InitResynchVars(node);
if (cv_joinnextround.value && gameaction == ga_nothing)
G_SetGamestate(GS_WAITINGPLAYERS);
if (!SV_SendServerConfig(node))
@ -3762,6 +3163,7 @@ static void PT_CanReceiveGamestate(SINT8 node)
CONS_Printf(M_GetText("Resending game state to %s...\n"), player_names[nodetoplayer[node]]);
SV_SendSaveGame(node, true); // Resend a complete game state
resendingsavegame[node] = true;
}
/** Handles a packet received from a node that isn't in game
@ -3976,11 +3378,6 @@ static void HandlePacketFromPlayer(SINT8 node)
switch (netbuffer->packettype)
{
// -------------------------------------------- SERVER RECEIVE ----------
case PT_RESYNCHGET:
if (client)
break;
SV_AcknowledgeResynchAck(netconsole, netbuffer->u.resynchgot);
break;
case PT_CLIENTCMD:
case PT_CLIENT2CMD:
case PT_CLIENTMIS:
@ -3990,10 +3387,6 @@ static void HandlePacketFromPlayer(SINT8 node)
if (client)
break;
// Ignore tics from those not synched
if (resynch_inprogress[node] && nettics[node] == gametic)
break;
// To save bytes, only the low byte of tic numbers are sent
// Use ExpandTics to figure out what the rest of the bytes are
realstart = ExpandTics(netbuffer->u.clientpak.client_tic);
@ -4020,9 +3413,6 @@ static void HandlePacketFromPlayer(SINT8 node)
|| netbuffer->packettype == PT_NODEKEEPALIVEMIS)
break;
// If a client sends a ticcmd it should mean they are done receiving the savegame
sendingsavegame[node] = false;
// As long as clients send valid ticcmds, the server can keep running, so reset the timeout
/// \todo Use a separate cvar for that kind of timeout?
freezetimeout[node] = I_GetTime() + connectiontimeout;
@ -4047,21 +3437,19 @@ static void HandlePacketFromPlayer(SINT8 node)
G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][(UINT8)nodetoplayer2[node]],
&netbuffer->u.client2pak.cmd2, 1);
// A delay before we check resynching
// Used on join or just after a synch fail
if (resynch_delay[node])
{
--resynch_delay[node];
break;
}
// Check player consistancy during the level
if (realstart <= gametic && realstart > gametic - BACKUPTICS+1 && gamestate == GS_LEVEL
&& consistancy[realstart%BACKUPTICS] != SHORT(netbuffer->u.clientpak.consistancy))
&& consistancy[realstart%BACKUPTICS] != SHORT(netbuffer->u.clientpak.consistancy)
&& !resendingsavegame[node])
{
SV_RequireResynch(node);
if (cv_resynchattempts.value && resynch_score[node] <= (unsigned)cv_resynchattempts.value*250)
if (cv_resynchattempts.value)
{
// Tell the client we are about to resend them the gamestate
netbuffer->packettype = PT_WILLRESENDGAMESTATE;
HSendPacket(node, true, 0, 0);
resendingsavegame[node] = true;
if (cv_blamecfail.value)
CONS_Printf(M_GetText("Synch failure for player %d (%s); expected %hd, got %hd\n"),
netconsole+1, player_names[netconsole],
@ -4081,8 +3469,6 @@ static void HandlePacketFromPlayer(SINT8 node)
break;
}
}
else if (resynch_score[node])
--resynch_score[node];
break;
case PT_TEXTCMD2: // splitscreen special
netconsole = nodetoplayer2[node];
@ -4211,25 +3597,11 @@ static void HandlePacketFromPlayer(SINT8 node)
case PT_CANRECEIVEGAMESTATE:
PT_CanReceiveGamestate(node);
break;
// -------------------------------------------- CLIENT RECEIVE ----------
case PT_RESYNCHEND:
// Only accept PT_RESYNCHEND from the server.
if (node != servernode)
{
CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_RESYNCHEND", node);
if (server)
SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
break;
}
resynch_local_inprogress = false;
P_SetRandSeed(netbuffer->u.resynchend.randomseed);
if (gametyperules & GTR_TEAMFLAGS)
resynch_read_ctf(&netbuffer->u.resynchend);
resynch_read_others(&netbuffer->u.resynchend);
case PT_RECEIVEDGAMESTATE:
sendingsavegame[node] = false;
resendingsavegame[node] = false;
break;
// -------------------------------------------- CLIENT RECEIVE ----------
case PT_SERVERTICS:
// Only accept PT_SERVERTICS from the server.
if (node != servernode)
@ -4293,18 +3665,6 @@ static void HandlePacketFromPlayer(SINT8 node)
"IRC or Discord so it can be fixed.\n", (INT32)realstart, (INT32)realend, (INT32)neededtic);*/
}
break;
case PT_RESYNCHING:
// Only accept PT_RESYNCHING from the server.
if (node != servernode)
{
CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_RESYNCHING", node);
if (server)
SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
break;
}
resynch_local_inprogress = true;
CL_AcknowledgeResynch(&netbuffer->u.resynchpak);
break;
case PT_PING:
// Only accept PT_PING from the server.
if (node != servernode)
@ -4832,7 +4192,7 @@ void TryRunTics(tic_t realtics)
if (player_joining)
return;
if (neededtic > gametic && !resynch_local_inprogress)
if (neededtic > gametic)
{
if (advancedemo)
{
@ -4991,9 +4351,9 @@ void NetUpdate(void)
if (cl_redownloadinggamestate && fileneeded[0].status == FS_FOUND)
CL_ReloadReceivedSavegame();
if (!(resynch_local_inprogress || cl_redownloadinggamestate))
if (!cl_redownloadinggamestate)
CL_SendClientCmd(); // Send tic cmd
hu_resynching = resynch_local_inprogress;
hu_redownloadinggamestate = cl_redownloadinggamestate;
}
else
{
@ -5001,7 +4361,7 @@ void NetUpdate(void)
{
INT32 counts;
hu_resynching = false;
hu_redownloadinggamestate = false;
firstticstosend = gametic;
for (i = 0; i < MAXNETNODES; i++)
@ -5011,18 +4371,6 @@ void NetUpdate(void)
// Don't erase tics not acknowledged
counts = realtics;
for (i = 0; i < MAXNETNODES; ++i)
if (resynch_inprogress[i])
{
if (!nodeingame[i] || nettics[i] == gametic)
{
SV_SendResynch(i);
counts = -666;
}
else
counts = 0; // Let the client catch up with the server
}
// Do not make tics while resynching
if (counts != -666)
{
@ -5040,7 +4388,7 @@ void NetUpdate(void)
neededtic = maketic; // The server is a client too
}
else
hu_resynching = true;
hu_redownloadinggamestate = true;
}
}
Net_AckTicker();

View file

@ -64,11 +64,10 @@ typedef enum
PT_REQUESTFILE, // Client requests a file transfer
PT_ASKINFOVIAMS, // Packet from the MS requesting info be sent to new client.
// If this ID changes, update masterserver definition.
PT_RESYNCHEND, // Player is now resynched and is being requested to remake the gametic
PT_RESYNCHGET, // Player got resynch packet
PT_WILLRESENDGAMESTATE, // Hey Client, I am about to resend you the gamestate!
PT_CANRECEIVEGAMESTATE, // Okay Server, I'm ready to receive it, you can go ahead.
PT_CANRECEIVEGAMESTATE, // Okay Server, I'm ready to receive it, you can go ahead.
PT_RECEIVEDGAMESTATE, // Thank you Server, I am ready to play again!
// Add non-PT_CANFAIL packet types here to avoid breaking MS compatibility.
@ -82,8 +81,6 @@ typedef enum
PT_TEXTCMD2, // Splitscreen text commands.
PT_CLIENTJOIN, // Client wants to join; used in start game.
PT_NODETIMEOUT, // Packet sent to self if the connection times out.
PT_RESYNCHING, // Packet sent to resync players.
// Blocks game advance until synched.
PT_LOGIN, // Login attempt from the client.
@ -136,165 +133,6 @@ typedef struct
ticcmd_t cmds[45]; // Normally [BACKUPTIC][MAXPLAYERS] but too large
} ATTRPACK servertics_pak;
// Sent to client when all consistency data
// for players has been restored
typedef struct
{
UINT32 randomseed;
// CTF flag stuff
SINT8 flagplayer[2];
INT32 flagloose[2];
INT32 flagflags[2];
fixed_t flagx[2];
fixed_t flagy[2];
fixed_t flagz[2];
UINT32 ingame; // Spectator bit for each player
UINT32 outofcoop; // outofcoop bit for each player
INT32 ctfteam[MAXPLAYERS]; // Which team? (can't be 1 bit, since in regular Match there are no teams)
// Resynch game scores and the like all at once
UINT32 score[MAXPLAYERS]; // Everyone's score
INT16 numboxes[MAXPLAYERS];
INT16 totalring[MAXPLAYERS];
tic_t realtime[MAXPLAYERS];
UINT8 laps[MAXPLAYERS];
} ATTRPACK resynchend_pak;
typedef struct
{
// Player stuff
UINT8 playernum;
// Do not send anything visual related.
// Only send data that we need to know for physics.
UINT8 playerstate; // playerstate_t
UINT32 pflags; // pflags_t
UINT8 panim; // panim_t
angle_t aiming;
INT32 currentweapon;
INT32 ringweapons;
UINT16 ammoremoval;
tic_t ammoremovaltimer;
INT32 ammoremovalweapon;
UINT16 powers[NUMPOWERS];
// Score is resynched in the confirm resync packet
INT16 rings;
INT16 spheres;
SINT8 lives;
SINT8 continues;
UINT8 scoreadd;
SINT8 xtralife;
SINT8 pity;
UINT8 skincolor;
INT32 skin;
UINT32 availabilities;
// Just in case Lua does something like
// modify these at runtime
fixed_t camerascale;
fixed_t shieldscale;
fixed_t normalspeed;
fixed_t runspeed;
UINT8 thrustfactor;
UINT8 accelstart;
UINT8 acceleration;
UINT8 charability;
UINT8 charability2;
UINT32 charflags;
UINT32 thokitem; // mobjtype_t
UINT32 spinitem; // mobjtype_t
UINT32 revitem; // mobjtype_t
UINT32 followitem; // mobjtype_t
fixed_t actionspd;
fixed_t mindash;
fixed_t maxdash;
fixed_t jumpfactor;
fixed_t playerheight;
fixed_t playerspinheight;
fixed_t speed;
UINT8 secondjump;
UINT8 fly1;
tic_t glidetime;
UINT8 climbing;
INT32 deadtimer;
tic_t exiting;
UINT8 homing;
tic_t dashmode;
tic_t skidtime;
fixed_t cmomx;
fixed_t cmomy;
fixed_t rmomx;
fixed_t rmomy;
INT32 weapondelay;
INT32 tossdelay;
INT16 starpostx;
INT16 starposty;
INT16 starpostz;
INT32 starpostnum;
tic_t starposttime;
angle_t starpostangle;
fixed_t starpostscale;
INT32 maxlink;
fixed_t dashspeed;
angle_t angle_pos;
angle_t old_angle_pos;
tic_t bumpertime;
INT32 flyangle;
tic_t drilltimer;
INT32 linkcount;
tic_t linktimer;
INT32 anotherflyangle;
tic_t nightstime;
INT32 drillmeter;
UINT8 drilldelay;
UINT8 bonustime;
UINT8 mare;
INT16 lastsidehit, lastlinehit;
tic_t losstime;
UINT8 timeshit;
INT32 onconveyor;
//player->mo stuff
UINT8 hasmo; // Boolean
INT32 health;
angle_t angle;
angle_t rollangle;
fixed_t x;
fixed_t y;
fixed_t z;
fixed_t momx;
fixed_t momy;
fixed_t momz;
fixed_t friction;
fixed_t movefactor;
spritenum_t sprite;
UINT32 frame;
UINT8 sprite2;
UINT16 anim_duration;
INT32 tics;
statenum_t statenum;
UINT32 flags;
UINT32 flags2;
UINT16 eflags;
fixed_t radius;
fixed_t height;
fixed_t scale;
fixed_t destscale;
fixed_t scalespeed;
} ATTRPACK resynch_pak;
typedef struct
{
UINT8 version; // Different versions don't work
@ -430,9 +268,6 @@ typedef struct
client2cmd_pak client2pak; // 200 bytes
servertics_pak serverpak; // 132495 bytes (more around 360, no?)
serverconfig_pak servercfg; // 773 bytes
resynchend_pak resynchend; //
resynch_pak resynchpak; //
UINT8 resynchgot; //
UINT8 textcmd[MAXTEXTCMD+1]; // 66049 bytes (wut??? 64k??? More like 257 bytes...)
filetx_pak filetxpak; // 139 bytes
clientconfig_pak clientcfg; // 136 bytes
@ -567,7 +402,7 @@ UINT8 GetFreeXCmdSize(void);
void D_MD5PasswordPass(const UINT8 *buffer, size_t len, const char *salt, void *dest);
extern UINT8 hu_resynching;
extern UINT8 hu_redownloadinggamestate;
extern UINT8 adminpassmd5[16];
extern boolean adminpasswordset;

View file

@ -2206,7 +2206,7 @@ void HU_Drawer(void)
HU_DrawCrosshair2();
// draw desynch text
if (hu_resynching)
if (hu_redownloadinggamestate)
{
static UINT32 resynch_ticker = 0;
char resynch_text[14];