diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f9778a40b..124a89b09 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -234,7 +234,7 @@ set(SRB2_CONFIG_HAVE_GME ON CACHE BOOL set(SRB2_CONFIG_HAVE_OPENMPT ON CACHE BOOL "Enable OpenMPT support.") set(SRB2_CONFIG_HAVE_CURL ON CACHE BOOL - "Enable curl support, used for downloading files via HTTP.") + "Enable curl support.") set(SRB2_CONFIG_HAVE_THREADS ON CACHE BOOL "Enable multithreading support.") if(${CMAKE_SYSTEM} MATCHES Windows) @@ -460,7 +460,7 @@ endif() if(${SRB2_CONFIG_HAVE_CURL}) if(${SRB2_CONFIG_USE_INTERNAL_LIBRARIES}) set(CURL_FOUND ON) - set(CURL_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/libs/curl) + set(CURL_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/libs/curl/include) if(${SRB2_SYSTEM_BITS} EQUAL 64) set(CURL_LIBRARIES "-L${CMAKE_SOURCE_DIR}/libs/curl/lib64 -lcurl") else() # 32-bit @@ -554,6 +554,7 @@ if(${SRB2_CONFIG_USEASM}) endif() set(SRB2_USEASM ON) add_definitions(-DUSEASM) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse3 -mfpmath=sse") else() set(SRB2_USEASM OFF) add_definitions(-DNONX86 -DNORUSEASM) diff --git a/src/Makefile b/src/Makefile index 62a5e92f2..2cd6d5f6b 100644 --- a/src/Makefile +++ b/src/Makefile @@ -277,7 +277,7 @@ OPTS += -DCOMPVERSION ifndef NONX86 ifndef GCC29 - ARCHOPTS?=-march=pentium + ARCHOPTS?=-msse3 -mfpmath=sse else ARCHOPTS?=-mpentium endif diff --git a/src/d_clisrv.c b/src/d_clisrv.c index e314d419f..b198011a0 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -84,6 +84,8 @@ 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 savegameresendcooldown[MAXNETNODES]; // How long before we can resend again? static tic_t freezetimeout[MAXNETNODES]; // Until when can this node freeze the server before getting a timeout? // Incremented by cv_joindelay when a client joins, decremented each tic. @@ -107,15 +109,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; @@ -126,6 +121,7 @@ static ticcmd_t localcmds2; static boolean cl_packetmissed; // here it is for the secondary local player (splitscreen) static UINT8 mynode; // my address pointofview server +static boolean cl_redownloadinggamestate = false; static UINT8 localtextcmd[MAXTEXTCMD]; static UINT8 localtextcmd2[MAXTEXTCMD]; // splitscreen @@ -509,603 +505,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->angleturn = (INT16)SHORT(players[i].angleturn); - rsp->oldrelangleturn = (INT16)SHORT(players[i].oldrelangleturn); - - 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].angleturn = (INT16)SHORT(rsp->angleturn); - players[i].oldrelangleturn = (INT16)SHORT(rsp->oldrelangleturn); - - 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<outofcoop |= (1<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<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<>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<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<packettype = PT_SERVERCFG; @@ -1992,32 +1355,10 @@ static boolean SV_SendServerConfig(INT32 node) netbuffer->u.servercfg.gametype = (UINT8)gametype; netbuffer->u.servercfg.modifiedgame = (UINT8)modifiedgame; - // we fill these structs with FFs so that any players not in game get sent as 0xFFFF - // which is nice and easy for us to detect - memset(netbuffer->u.servercfg.playerskins, 0xFF, sizeof(netbuffer->u.servercfg.playerskins)); - memset(netbuffer->u.servercfg.playercolor, 0xFF, sizeof(netbuffer->u.servercfg.playercolor)); - memset(netbuffer->u.servercfg.playeravailabilities, 0xFF, sizeof(netbuffer->u.servercfg.playeravailabilities)); - - memset(netbuffer->u.servercfg.adminplayers, -1, sizeof(netbuffer->u.servercfg.adminplayers)); - - for (i = 0; i < MAXPLAYERS; i++) - { - netbuffer->u.servercfg.adminplayers[i] = (SINT8)adminplayers[i]; - - if (!playeringame[i]) - continue; - netbuffer->u.servercfg.playerskins[i] = (UINT8)players[i].skin; - netbuffer->u.servercfg.playercolor[i] = (UINT16)players[i].skincolor; - netbuffer->u.servercfg.playeravailabilities[i] = (UINT32)LONG(players[i].availabilities); - } - memcpy(netbuffer->u.servercfg.server_context, server_context, 8); - op = p = netbuffer->u.servercfg.varlengthinputs; - CV_SavePlayerNames(&p); - CV_SaveNetVars(&p); { - const size_t len = sizeof (serverconfig_pak) + (size_t)(p - op); + const size_t len = sizeof (serverconfig_pak); #ifdef DEBUGFILE if (debugfile) @@ -2050,7 +1391,17 @@ static boolean SV_SendServerConfig(INT32 node) #ifndef NONET #define SAVEGAMESIZE (768*1024) -static void SV_SendSaveGame(INT32 node) +static boolean SV_ResendingSavegameToAnyone(void) +{ + INT32 i; + + for (i = 0; i < MAXNETNODES; i++) + if (resendingsavegame[i]) + return true; + return false; +} + +static void SV_SendSaveGame(INT32 node, boolean resending) { size_t length, compressedlen; UINT8 *savebuffer; @@ -2068,7 +1419,7 @@ static void SV_SendSaveGame(INT32 node) // Leave room for the uncompressed length. save_p = savebuffer + sizeof(UINT32); - P_SaveNetGame(); + P_SaveNetGame(resending); length = save_p - savebuffer; if (length > SAVEGAMESIZE) @@ -2141,7 +1492,7 @@ static void SV_SavedGame(void) return; } - P_SaveNetGame(); + P_SaveNetGame(false); length = save_p - savebuffer; if (length > SAVEGAMESIZE) @@ -2164,7 +1515,7 @@ static void SV_SavedGame(void) #define TMPSAVENAME "$$$.sav" -static void CL_LoadReceivedSavegame(void) +static void CL_LoadReceivedSavegame(boolean reloading) { UINT8 *savebuffer = NULL; size_t length, decompressedlen; @@ -2200,7 +1551,7 @@ static void CL_LoadReceivedSavegame(void) automapactive = false; // load a base level - if (P_LoadNetGame()) + if (P_LoadNetGame(reloading)) { const UINT8 actnum = mapheaderinfo[gamemap-1]->actnum; CONS_Printf(M_GetText("Map is now \"%s"), G_BuildMapName(gamemap)); @@ -2231,6 +1582,45 @@ static void CL_LoadReceivedSavegame(void) 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) +{ + INT32 i; + + for (i = 0; i < MAXPLAYERS; i++) + { +#ifdef HAVE_BLUA + LUA_InvalidatePlayer(&players[i]); +#endif + sprintf(player_names[i], "Player %d", i + 1); + } + + CL_LoadReceivedSavegame(true); + + if (neededtic < gametic) + neededtic = gametic; + maketic = neededtic; + + ticcmd_oldangleturn[0] = players[consoleplayer].oldrelangleturn; + P_ForceLocalAngle(&players[consoleplayer], (angle_t)(players[consoleplayer].angleturn << 16)); + if (splitscreen) + { + ticcmd_oldangleturn[1] = players[secondarydisplayplayer].oldrelangleturn; + P_ForceLocalAngle(&players[secondarydisplayplayer], (angle_t)(players[secondarydisplayplayer].angleturn << 16)); + } + + camera.subsector = R_PointInSubsector(camera.x, camera.y); + camera2.subsector = R_PointInSubsector(camera2.x, camera2.y); + + cl_redownloadinggamestate = false; + + CONS_Printf(M_GetText("Game state reloaded\n")); } #endif @@ -2648,7 +2038,7 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic if (fileneeded[0].status == FS_FOUND) { // Gamestate is now handled within CL_LoadReceivedSavegame() - CL_LoadReceivedSavegame(); + CL_LoadReceivedSavegame(false); cl_mode = CL_CONNECTED; } // don't break case continue to CL_CONNECTED else @@ -3111,10 +2501,14 @@ static void CL_RemovePlayer(INT32 playernum, kickreason_t reason) } count--; - spheres = players[playernum].spheres; - rings = players[playernum].rings; - sincrement = spheres/count; - rincrement = rings/count; + sincrement = spheres = players[playernum].spheres; + rincrement = rings = players[playernum].rings; + + if (count) + { + sincrement /= count; + rincrement /= count; + } for (i = 0; i < MAXPLAYERS; i++) { @@ -3204,7 +2598,6 @@ void CL_Reset(void) multiplayer = false; servernode = 0; server = true; - resynch_local_inprogress = false; doomcom->numnodes = 1; doomcom->numslots = 1; SV_StopServer(); @@ -3676,6 +3069,34 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) CL_RemovePlayer(pnum, kickreason); } +static void Command_ResendGamestate(void) +{ + SINT8 playernum; + + if (COM_Argc() == 1) + { + CONS_Printf(M_GetText("resendgamestate : resend the game state to a player\n")); + return; + } + else if (client) + { + CONS_Printf(M_GetText("Only the server can use this.\n")); + return; + } + + playernum = nametonum(COM_Argv(1)); + if (playernum == -1 || playernum == 0) + return; + + // Send a PT_WILLRESENDGAMESTATE packet to the client so they know what's going on + netbuffer->packettype = PT_WILLRESENDGAMESTATE; + if (!HSendPacket(playernode[playernum], true, 0, 0)) + { + CONS_Alert(CONS_ERROR, M_GetText("A problem occured, please try again.\n")); + return; + } +} + static CV_PossibleValue_t netticbuffer_cons_t[] = {{0, "MIN"}, {3, "MAX"}, {0, NULL}}; consvar_t cv_netticbuffer = CVAR_INIT ("netticbuffer", "1", CV_SAVE, netticbuffer_cons_t, NULL); @@ -3719,6 +3140,7 @@ void D_ClientServerInit(void) COM_AddCommand("reloadbans", Command_ReloadBan); COM_AddCommand("connect", Command_connect); COM_AddCommand("nodes", Command_Nodes); + COM_AddCommand("resendgamestate", Command_ResendGamestate); #ifdef PACKETDROP COM_AddCommand("drop", Command_Drop); COM_AddCommand("droprate", Command_Droprate); @@ -3750,14 +3172,18 @@ void D_ClientServerInit(void) static void ResetNode(INT32 node) { nodeingame[node] = false; - nodetoplayer[node] = -1; - nodetoplayer2[node] = -1; + nodewaiting[node] = 0; + nettics[node] = gametic; supposedtics[node] = gametic; - nodewaiting[node] = 0; + + nodetoplayer[node] = -1; + nodetoplayer2[node] = -1; playerpernode[node] = 0; + sendingsavegame[node] = false; - SV_InitResynchVars(node); + resendingsavegame[node] = false; + savegameresendcooldown[node] = 0; } void SV_ResetServer(void) @@ -3791,6 +3217,7 @@ void SV_ResetServer(void) mynode = 0; cl_packetmissed = false; + cl_redownloadinggamestate = false; if (dedicated) { @@ -4260,12 +3687,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)) @@ -4287,7 +3708,7 @@ static void HandleConnect(SINT8 node) { if ((gamestate == GS_LEVEL || gamestate == GS_INTERMISSION) && newnode) { - SV_SendSaveGame(node); // send a complete game state + SV_SendSaveGame(node, false); // send a complete game state DEBFILE("send savegame\n"); } SV_AddWaitingPlayers(names[0], names[1]); @@ -4354,6 +3775,43 @@ static void HandleServerInfo(SINT8 node) } #endif +static void PT_WillResendGamestate(void) +{ + char tmpsave[256]; + + if (server || cl_redownloadinggamestate) + return; + + // Send back a PT_CANRECEIVEGAMESTATE packet to the server + // so they know they can start sending the game state + netbuffer->packettype = PT_CANRECEIVEGAMESTATE; + if (!HSendPacket(servernode, true, 0, 0)) + return; + + CONS_Printf(M_GetText("Reloading game state...\n")); + + sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home); + + // Don't get a corrupt savegame error because tmpsave already exists + if (FIL_FileExists(tmpsave) && unlink(tmpsave) == -1) + I_Error("Can't delete %s\n", tmpsave); + + CL_PrepareDownloadSaveGame(tmpsave); + + cl_redownloadinggamestate = true; +} + +static void PT_CanReceiveGamestate(SINT8 node) +{ + if (client || sendingsavegame[node]) + return; + + 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 * * \param node The packet sender @@ -4444,9 +3902,6 @@ static void HandlePacketFromAwayNode(SINT8 node) case PT_SERVERCFG: // Positive response of client join request { - INT32 j; - UINT8 *scp; - if (server && serverrunning && node != servernode) { // but wait I thought I'm the server? Net_CloseConnection(node); @@ -4462,8 +3917,6 @@ static void HandlePacketFromAwayNode(SINT8 node) maketic = gametic = neededtic = (tic_t)LONG(netbuffer->u.servercfg.gametic); G_SetGametype(netbuffer->u.servercfg.gametype); modifiedgame = netbuffer->u.servercfg.modifiedgame; - for (j = 0; j < MAXPLAYERS; j++) - adminplayers[j] = netbuffer->u.servercfg.adminplayers[j]; memcpy(server_context, netbuffer->u.servercfg.server_context, 8); } @@ -4482,23 +3935,6 @@ static void HandlePacketFromAwayNode(SINT8 node) #endif DEBFILE(va("Server accept join gametic=%u mynode=%d\n", gametic, mynode)); - memset(playeringame, 0, sizeof(playeringame)); - for (j = 0; j < MAXPLAYERS; j++) - { - if (netbuffer->u.servercfg.playerskins[j] == 0xFF - && netbuffer->u.servercfg.playercolor[j] == 0xFFFF - && netbuffer->u.servercfg.playeravailabilities[j] == 0xFFFFFFFF) - continue; // not in game - - playeringame[j] = true; - players[j].availabilities = (UINT32)LONG(netbuffer->u.servercfg.playeravailabilities[j]); - SetPlayerSkinByNum(j, (INT32)netbuffer->u.servercfg.playerskins[j]); - players[j].skincolor = netbuffer->u.servercfg.playercolor[j]; - } - - scp = netbuffer->u.servercfg.varlengthinputs; - CV_LoadPlayerNames(&scp); - CV_LoadNetVars(&scp); #ifndef NONET /// \note Wait. What if a Lua script uses some global custom variables synched with the NetVars hook? /// Shouldn't them be downloaded even at intermission time? @@ -4598,11 +4034,6 @@ static void HandlePacketFromPlayer(SINT8 node) switch (netbuffer->packettype) { // -------------------------------------------- SERVER RECEIVE ---------- - case PT_RESYNCHGET: - if (client) - break; - SV_AcknowledgeResynchAck(node, netbuffer->u.resynchgot); - break; case PT_CLIENTCMD: case PT_CLIENT2CMD: case PT_CLIENTMIS: @@ -4612,10 +4043,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, node); @@ -4642,9 +4069,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; @@ -4669,21 +4093,20 @@ 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)) + if (realstart <= gametic && realstart + BACKUPTICS - 1 > gametic && gamestate == GS_LEVEL + && consistancy[realstart%BACKUPTICS] != SHORT(netbuffer->u.clientpak.consistancy) + && !resendingsavegame[node] && savegameresendcooldown[node] <= I_GetTime() + && !SV_ResendingSavegameToAnyone()) { - 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], @@ -4703,8 +4126,6 @@ static void HandlePacketFromPlayer(SINT8 node) break; } } - else if (resynch_score[node]) - --resynch_score[node]; break; case PT_TEXTCMD2: // splitscreen special netconsole = nodetoplayer2[node]; @@ -4830,6 +4251,9 @@ static void HandlePacketFromPlayer(SINT8 node) Net_CloseConnection(node); nodeingame[node] = false; break; + case PT_CANRECEIVEGAMESTATE: + PT_CanReceiveGamestate(node); + break; case PT_ASKLUAFILE: if (server && luafiletransfers && luafiletransfers->nodestatus[node] == LFTNS_ASKED) AddLuaFileToSendQueue(node, luafiletransfers->realfilename); @@ -4838,25 +4262,12 @@ static void HandlePacketFromPlayer(SINT8 node) if (server && luafiletransfers && luafiletransfers->nodestatus[node] == LFTNS_SENDING) SV_HandleLuaFileSent(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; + savegameresendcooldown[node] = I_GetTime() + 15 * TICRATE; break; +// -------------------------------------------- CLIENT RECEIVE ---------- case PT_SERVERTICS: // Only accept PT_SERVERTICS from the server. if (node != servernode) @@ -4917,18 +4328,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) @@ -4973,6 +4372,9 @@ static void HandlePacketFromPlayer(SINT8 node) if (server) PT_FileReceived(); break; + case PT_WILLRESENDGAMESTATE: + PT_WillResendGamestate(); + break; case PT_SENDINGLUAFILE: if (client) CL_PrepareDownloadLuaFile(); @@ -5430,7 +4832,7 @@ void TryRunTics(tic_t realtics) if (player_joining) return; - if (neededtic > gametic && !resynch_local_inprogress) + if (neededtic > gametic) { if (advancedemo) { @@ -5596,9 +4998,12 @@ void NetUpdate(void) if (client) { - if (!resynch_local_inprogress) - CL_SendClientCmd(); // Send tic cmd - hu_resynching = resynch_local_inprogress; + // If the client just finished redownloading the game state, load it + if (cl_redownloadinggamestate && fileneeded[0].status == FS_FOUND) + CL_ReloadReceivedSavegame(); + + CL_SendClientCmd(); // Send tic cmd + hu_redownloadinggamestate = cl_redownloadinggamestate; } else { @@ -5606,7 +5011,7 @@ void NetUpdate(void) { INT32 counts; - hu_resynching = false; + hu_redownloadinggamestate = false; firstticstosend = gametic; for (i = 0; i < MAXNETNODES; i++) @@ -5621,36 +5026,18 @@ 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 - } + if (maketic + counts >= firstticstosend + BACKUPTICS) + counts = firstticstosend+BACKUPTICS-maketic-1; - // Do not make tics while resynching - if (counts != -666) - { - if (maketic + counts >= firstticstosend + BACKUPTICS) - counts = firstticstosend+BACKUPTICS-maketic-1; + for (i = 0; i < counts; i++) + SV_Maketic(); // Create missed tics and increment maketic - for (i = 0; i < counts; i++) - SV_Maketic(); // Create missed tics and increment maketic + for (; tictoclear < firstticstosend; tictoclear++) // Clear only when acknowledged + D_Clearticcmd(tictoclear); // Clear the maketic the new tic - for (; tictoclear < firstticstosend; tictoclear++) // Clear only when acknowledged - D_Clearticcmd(tictoclear); // Clear the maketic the new tic + SV_SendTics(); - SV_SendTics(); - - neededtic = maketic; // The server is a client too - } - else - hu_resynching = true; + neededtic = maketic; // The server is a client too } } diff --git a/src/d_clisrv.h b/src/d_clisrv.h index adc8a7cc9..3d67525da 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -64,8 +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_RECEIVEDGAMESTATE, // Thank you Server, I am ready to play again! PT_SENDINGLUAFILE, // Server telling a client Lua needs to open a file PT_ASKLUAFILE, // Client telling the server they don't have the file @@ -85,8 +87,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. @@ -139,168 +139,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 - - INT16 angleturn; - INT16 oldrelangleturn; - - 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; - - UINT16 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 @@ -314,18 +152,10 @@ typedef struct UINT8 clientnode; UINT8 gamestate; - // 0xFF == not in game; else player skin num - UINT8 playerskins[MAXPLAYERS]; - UINT16 playercolor[MAXPLAYERS]; - UINT32 playeravailabilities[MAXPLAYERS]; - UINT8 gametype; UINT8 modifiedgame; - SINT8 adminplayers[MAXPLAYERS]; // Needs to be signed char server_context[8]; // Unique context id, generated at server startup. - - UINT8 varlengthinputs[0]; // Playernames and netvars } ATTRPACK serverconfig_pak; typedef struct @@ -462,9 +292,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 fileack_pak fileack; @@ -606,7 +433,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; diff --git a/src/d_main.c b/src/d_main.c index ce1331fe3..fe8327e98 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1598,7 +1598,7 @@ void D_SRB2Main(void) { levelstarttic = gametic; G_SetGamestate(GS_LEVEL); - if (!P_LoadLevel(false)) + if (!P_LoadLevel(false, false)) I_Quit(); // fail so reset game stuff } } diff --git a/src/d_net.c b/src/d_net.c index 2823ce219..d534b1b08 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -798,8 +798,9 @@ static const char *packettypename[NUMPACKETTYPE] = "REQUESTFILE", "ASKINFOVIAMS", - "RESYNCHEND", - "RESYNCHGET", + "WILLRESENDGAMESTATE", + "CANRECEIVEGAMESTATE", + "RECEIVEDGAMESTATE", "SENDINGLUAFILE", "ASKLUAFILE", @@ -813,7 +814,6 @@ static const char *packettypename[NUMPACKETTYPE] = "TEXTCMD2", "CLIENTJOIN", "NODETIMEOUT", - "RESYNCHING", "LOGIN", "PING" }; diff --git a/src/dehacked.c b/src/dehacked.c index ca013a25d..0380cc30e 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -38,6 +38,7 @@ #include "lua_script.h" #include "lua_hook.h" #include "d_clisrv.h" +#include "g_state.h" // gamestate_t (for lua) #include "m_cond.h" @@ -5178,6 +5179,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_TAILSOVERLAY_PAIN", "S_TAILSOVERLAY_GASP", "S_TAILSOVERLAY_EDGE", + "S_TAILSOVERLAY_DASH", // [: "S_JETFUMEFLASH", @@ -10106,6 +10108,22 @@ struct { {"MA_NOCUTSCENES",MA_NOCUTSCENES}, {"MA_INGAME",MA_INGAME}, + // gamestates + {"GS_NULL",GS_NULL}, + {"GS_LEVEL",GS_LEVEL}, + {"GS_INTERMISSION",GS_INTERMISSION}, + {"GS_CONTINUING",GS_CONTINUING}, + {"GS_TITLESCREEN",GS_TITLESCREEN}, + {"GS_TIMEATTACK",GS_TIMEATTACK}, + {"GS_CREDITS",GS_CREDITS}, + {"GS_EVALUATION",GS_EVALUATION}, + {"GS_GAMEEND",GS_GAMEEND}, + {"GS_INTRO",GS_INTRO}, + {"GS_ENDING",GS_ENDING}, + {"GS_CUTSCENE",GS_CUTSCENE}, + {"GS_DEDICATEDSERVER",GS_DEDICATEDSERVER}, + {"GS_WAITINGPLAYERS",GS_WAITINGPLAYERS}, + {NULL,0} }; diff --git a/src/g_game.c b/src/g_game.c index 1ea7cd080..228295b62 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1829,7 +1829,7 @@ void G_DoLoadLevel(boolean resetplayer) } // Setup the level. - if (!P_LoadLevel(false)) // this never returns false? + if (!P_LoadLevel(false, false)) // this never returns false? { // fail so reset game stuff Command_ExitGame_f(); diff --git a/src/hardware/hw_batching.c b/src/hardware/hw_batching.c index a63be3a72..5ea9f55d4 100644 --- a/src/hardware/hw_batching.c +++ b/src/hardware/hw_batching.c @@ -1,7 +1,6 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/hardware/hw_batching.h b/src/hardware/hw_batching.h index 7c108a4bd..3d22324ac 100644 --- a/src/hardware/hw_batching.h +++ b/src/hardware/hw_batching.h @@ -1,7 +1,6 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h index 607d21ef5..644ab0ca2 100644 --- a/src/hardware/hw_defs.h +++ b/src/hardware/hw_defs.h @@ -295,6 +295,16 @@ enum hwdsetspecialstate typedef enum hwdsetspecialstate hwdspecialstate_t; +// Lactozilla: Shader options +enum hwdshaderoption +{ + HWD_SHADEROPTION_OFF, + HWD_SHADEROPTION_ON, + HWD_SHADEROPTION_NOCUSTOM, +}; + +typedef enum hwdshaderoption hwdshaderoption_t; + // Lactozilla: Shader info // Generally set at the start of the frame. enum hwdshaderinfo diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h index aaa41e86f..266134105 100644 --- a/src/hardware/hw_drv.h +++ b/src/hardware/hw_drv.h @@ -70,7 +70,7 @@ EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2]); // jimita EXPORT boolean HWRAPI(CompileShaders) (void); EXPORT void HWRAPI(CleanShaders) (void); -EXPORT void HWRAPI(SetShader) (int shader); +EXPORT void HWRAPI(SetShader) (int type); EXPORT void HWRAPI(UnSetShader) (void); EXPORT void HWRAPI(SetShaderInfo) (hwdshaderinfo_t info, INT32 value); diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 29978c71e..d694be823 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5580,6 +5580,20 @@ static void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean trans->anglex = (float)(gl_aimingangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES); } +// +// Sets the shader state. +// +static void HWR_SetShaderState(void) +{ + hwdshaderoption_t state = cv_glshaders.value; + + if (!cv_glallowshaders.value) + state = (cv_glshaders.value == HWD_SHADEROPTION_ON ? HWD_SHADEROPTION_NOCUSTOM : cv_glshaders.value); + + HWD.pfnSetSpecialState(HWD_SET_SHADERS, (INT32)state); + HWD.pfnSetShader(SHADER_DEFAULT); +} + // ========================================================================== // Same as rendering the player view, but from the skybox object // ========================================================================== @@ -5698,8 +5712,7 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player) HWD.pfnSetTransform(&atransform); // Reset the shader state. - HWD.pfnSetSpecialState(HWD_SET_SHADERS, cv_glshaders.value); - HWD.pfnSetShader(SHADER_DEFAULT); + HWR_SetShaderState(); validcount++; @@ -5913,8 +5926,7 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) HWD.pfnSetTransform(&atransform); // Reset the shader state. - HWD.pfnSetSpecialState(HWD_SET_SHADERS, cv_glshaders.value); - HWD.pfnSetShader(SHADER_DEFAULT); + HWR_SetShaderState(); ps_numbspcalls = 0; ps_numpolyobjects = 0; @@ -6009,9 +6021,10 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) // 3D ENGINE COMMANDS // ========================================================================== -static CV_PossibleValue_t grmodelinterpolation_cons_t[] = {{0, "Off"}, {1, "Sometimes"}, {2, "Always"}, {0, NULL}}; -static CV_PossibleValue_t grfakecontrast_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Smooth"}, {0, NULL}}; -static CV_PossibleValue_t grshearing_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Third-person"}, {0, NULL}}; +static CV_PossibleValue_t glshaders_cons_t[] = {{HWD_SHADEROPTION_OFF, "Off"}, {HWD_SHADEROPTION_ON, "On"}, {HWD_SHADEROPTION_NOCUSTOM, "Ignore custom shaders"}, {0, NULL}}; +static CV_PossibleValue_t glmodelinterpolation_cons_t[] = {{0, "Off"}, {1, "Sometimes"}, {2, "Always"}, {0, NULL}}; +static CV_PossibleValue_t glfakecontrast_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Smooth"}, {0, NULL}}; +static CV_PossibleValue_t glshearing_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Third-person"}, {0, NULL}}; static void CV_glfiltermode_OnChange(void); static void CV_glanisotropic_OnChange(void); @@ -6022,9 +6035,10 @@ static CV_PossibleValue_t glfiltermode_cons_t[]= {{HWD_SET_TEXTUREFILTER_POINTSA {HWD_SET_TEXTUREFILTER_MIXED2, "Nearest_Linear"}, {HWD_SET_TEXTUREFILTER_MIXED3, "Nearest_Mipmap"}, {0, NULL}}; -CV_PossibleValue_t granisotropicmode_cons_t[] = {{1, "MIN"}, {16, "MAX"}, {0, NULL}}; +CV_PossibleValue_t glanisotropicmode_cons_t[] = {{1, "MIN"}, {16, "MAX"}, {0, NULL}}; -consvar_t cv_glshaders = CVAR_INIT ("gr_shaders", "On", CV_SAVE, CV_OnOff, NULL); +consvar_t cv_glshaders = CVAR_INIT ("gr_shaders", "On", CV_SAVE, glshaders_cons_t, NULL); +consvar_t cv_glallowshaders = CVAR_INIT ("gr_allowclientshaders", "On", CV_NETVAR, CV_OnOff, NULL); consvar_t cv_fovchange = CVAR_INIT ("gr_fovchange", "Off", CV_SAVE, CV_OnOff, NULL); #ifdef ALAM_LIGHTING @@ -6035,17 +6049,17 @@ consvar_t cv_glcoronasize = CVAR_INIT ("gr_coronasize", "1", CV_SAVE|CV_FLOAT, 0 #endif consvar_t cv_glmodels = CVAR_INIT ("gr_models", "Off", CV_SAVE, CV_OnOff, NULL); -consvar_t cv_glmodelinterpolation = CVAR_INIT ("gr_modelinterpolation", "Sometimes", CV_SAVE, grmodelinterpolation_cons_t, NULL); +consvar_t cv_glmodelinterpolation = CVAR_INIT ("gr_modelinterpolation", "Sometimes", CV_SAVE, glmodelinterpolation_cons_t, NULL); consvar_t cv_glmodellighting = CVAR_INIT ("gr_modellighting", "Off", CV_SAVE, CV_OnOff, NULL); -consvar_t cv_glshearing = CVAR_INIT ("gr_shearing", "Off", CV_SAVE, grshearing_cons_t, NULL); +consvar_t cv_glshearing = CVAR_INIT ("gr_shearing", "Off", CV_SAVE, glshearing_cons_t, NULL); consvar_t cv_glspritebillboarding = CVAR_INIT ("gr_spritebillboarding", "Off", CV_SAVE, CV_OnOff, NULL); consvar_t cv_glskydome = CVAR_INIT ("gr_skydome", "On", CV_SAVE, CV_OnOff, NULL); -consvar_t cv_glfakecontrast = CVAR_INIT ("gr_fakecontrast", "Smooth", CV_SAVE, grfakecontrast_cons_t, NULL); +consvar_t cv_glfakecontrast = CVAR_INIT ("gr_fakecontrast", "Smooth", CV_SAVE, glfakecontrast_cons_t, NULL); consvar_t cv_glslopecontrast = CVAR_INIT ("gr_slopecontrast", "Off", CV_SAVE, CV_OnOff, NULL); consvar_t cv_glfiltermode = CVAR_INIT ("gr_filtermode", "Nearest", CV_SAVE|CV_CALL, glfiltermode_cons_t, CV_glfiltermode_OnChange); -consvar_t cv_glanisotropicmode = CVAR_INIT ("gr_anisotropicmode", "1", CV_CALL, granisotropicmode_cons_t, CV_glanisotropic_OnChange); +consvar_t cv_glanisotropicmode = CVAR_INIT ("gr_anisotropicmode", "1", CV_CALL, glanisotropicmode_cons_t, CV_glanisotropic_OnChange); consvar_t cv_glsolvetjoin = CVAR_INIT ("gr_solvetjoin", "On", 0, CV_OnOff, NULL); @@ -6084,6 +6098,7 @@ void HWR_AddCommands(void) CV_RegisterVar(&cv_glfakecontrast); CV_RegisterVar(&cv_glshearing); CV_RegisterVar(&cv_glshaders); + CV_RegisterVar(&cv_glallowshaders); CV_RegisterVar(&cv_glfiltermode); CV_RegisterVar(&cv_glsolvetjoin); diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index 85072dfd9..3a6b1a4e9 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -78,7 +78,7 @@ const char *HWR_GetShaderName(INT32 shader); extern customshaderxlat_t shaderxlat[]; -extern CV_PossibleValue_t granisotropicmode_cons_t[]; +extern CV_PossibleValue_t glanisotropicmode_cons_t[]; #ifdef ALAM_LIGHTING extern consvar_t cv_gldynamiclighting; @@ -87,7 +87,7 @@ extern consvar_t cv_glcoronas; extern consvar_t cv_glcoronasize; #endif -extern consvar_t cv_glshaders; +extern consvar_t cv_glshaders, cv_glallowshaders; extern consvar_t cv_glmodels; extern consvar_t cv_glmodelinterpolation; extern consvar_t cv_glmodellighting; diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index db3c6a17d..1d2852d91 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -91,13 +91,6 @@ static GLuint startScreenWipe = 0; static GLuint endScreenWipe = 0; static GLuint finalScreenTexture = 0; -// Lactozilla: Shader functions -static void *Shader_Load(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade); -static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade); -static void Shader_CompileError(const char *message, GLuint program, INT32 shadernum); - -static GLRGBAFloat shader_defaultcolor = {1.0f, 1.0f, 1.0f, 1.0f}; - // shortcut for ((float)1/i) static const GLfloat byte2float[256] = { 0.000000f, 0.003922f, 0.007843f, 0.011765f, 0.015686f, 0.019608f, 0.023529f, 0.027451f, @@ -533,8 +526,8 @@ boolean SetupGLfunc(void) return true; } -static boolean gl_allowshaders = false; static boolean gl_shadersenabled = false; +static hwdshaderoption_t gl_allowshaders = HWD_SHADEROPTION_OFF; #ifdef GL_SHADERS typedef GLuint (APIENTRY *PFNglCreateShader) (GLenum); @@ -544,6 +537,7 @@ typedef void (APIENTRY *PFNglGetShaderiv) (GLuint, GLenum, GLint*); typedef void (APIENTRY *PFNglGetShaderInfoLog) (GLuint, GLsizei, GLsizei*, GLchar*); typedef void (APIENTRY *PFNglDeleteShader) (GLuint); typedef GLuint (APIENTRY *PFNglCreateProgram) (void); +typedef void (APIENTRY *PFNglDeleteProgram) (GLuint); typedef void (APIENTRY *PFNglAttachShader) (GLuint, GLuint); typedef void (APIENTRY *PFNglLinkProgram) (GLuint); typedef void (APIENTRY *PFNglGetProgramiv) (GLuint, GLenum, GLint*); @@ -565,6 +559,7 @@ static PFNglGetShaderiv pglGetShaderiv; static PFNglGetShaderInfoLog pglGetShaderInfoLog; static PFNglDeleteShader pglDeleteShader; static PFNglCreateProgram pglCreateProgram; +static PFNglDeleteProgram pglDeleteProgram; static PFNglAttachShader pglAttachShader; static PFNglLinkProgram pglLinkProgram; static PFNglGetProgramiv pglGetProgramiv; @@ -579,12 +574,6 @@ static PFNglUniform2fv pglUniform2fv; static PFNglUniform3fv pglUniform3fv; static PFNglGetUniformLocation pglGetUniformLocation; -// 18032019 -static GLuint gl_currentshaderprogram = 0; -static boolean gl_shaderprogramchanged = true; - -static shadersource_t gl_customshaders[HWR_MAXSHADERS]; - // 13062019 typedef enum { @@ -602,17 +591,37 @@ typedef enum gluniform_max, } gluniform_t; -typedef struct gl_shaderprogram_s +typedef struct gl_shader_s { GLuint program; - boolean custom; GLint uniforms[gluniform_max+1]; -} gl_shaderprogram_t; -static gl_shaderprogram_t gl_shaderprograms[HWR_MAXSHADERS]; + boolean custom; +} gl_shader_t; + +static gl_shader_t gl_shaders[HWR_MAXSHADERS]; +static gl_shader_t gl_usershaders[HWR_MAXSHADERS]; +static shadersource_t gl_customshaders[HWR_MAXSHADERS]; + +// 09102020 +typedef struct gl_shaderstate_s +{ + gl_shader_t *current; + GLuint type; + GLuint program; + boolean changed; +} gl_shaderstate_t; +static gl_shaderstate_t gl_shaderstate; // Shader info static INT32 shader_leveltime = 0; +// Lactozilla: Shader functions +static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i, const GLchar *vert_shader, const GLchar *frag_shader); +static void Shader_CompileError(const char *message, GLuint program, INT32 shadernum); +static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade); + +static GLRGBAFloat shader_defaultcolor = {1.0f, 1.0f, 1.0f, 1.0f}; + // ================ // Vertex shaders // ================ @@ -873,6 +882,7 @@ void SetupGLFunc4(void) pglGetShaderInfoLog = GetGLFunc("glGetShaderInfoLog"); pglDeleteShader = GetGLFunc("glDeleteShader"); pglCreateProgram = GetGLFunc("glCreateProgram"); + pglDeleteProgram = GetGLFunc("glDeleteProgram"); pglAttachShader = GetGLFunc("glAttachShader"); pglLinkProgram = GetGLFunc("glLinkProgram"); pglGetProgramiv = GetGLFunc("glGetProgramiv"); @@ -896,20 +906,40 @@ void SetupGLFunc4(void) EXPORT boolean HWRAPI(CompileShaders) (void) { #ifdef GL_SHADERS - GLuint gl_vertShader, gl_fragShader; - GLint i, result; + GLint i; - if (!pglUseProgram) return false; + if (!pglUseProgram) + return false; - gl_customshaders[0].vertex = NULL; - gl_customshaders[0].fragment = NULL; + gl_customshaders[SHADER_DEFAULT].vertex = NULL; + gl_customshaders[SHADER_DEFAULT].fragment = NULL; for (i = 0; gl_shadersources[i].vertex && gl_shadersources[i].fragment; i++) { - gl_shaderprogram_t *shader; + gl_shader_t *shader, *usershader; const GLchar *vert_shader = gl_shadersources[i].vertex; const GLchar *frag_shader = gl_shadersources[i].fragment; - boolean custom = ((gl_customshaders[i].vertex || gl_customshaders[i].fragment) && (i > 0)); + + if (i >= HWR_MAXSHADERS) + break; + + shader = &gl_shaders[i]; + usershader = &gl_usershaders[i]; + + if (shader->program) + pglDeleteProgram(shader->program); + if (usershader->program) + pglDeleteProgram(usershader->program); + + shader->program = 0; + usershader->program = 0; + + if (!Shader_CompileProgram(shader, i, vert_shader, frag_shader)) + shader->program = 0; + + // Compile custom shader + if ((i == SHADER_DEFAULT) || !(gl_customshaders[i].vertex || gl_customshaders[i].fragment)) + continue; // 18032019 if (gl_customshaders[i].vertex) @@ -917,92 +947,15 @@ EXPORT boolean HWRAPI(CompileShaders) (void) if (gl_customshaders[i].fragment) frag_shader = gl_customshaders[i].fragment; - if (i >= HWR_MAXSHADERS) - break; - - shader = &gl_shaderprograms[i]; - shader->program = 0; - shader->custom = custom; - - // - // Load and compile vertex shader - // - gl_vertShader = pglCreateShader(GL_VERTEX_SHADER); - if (!gl_vertShader) + if (!Shader_CompileProgram(usershader, i, vert_shader, frag_shader)) { - GL_MSG_Error("CompileShaders: Error creating vertex shader %s\n", HWR_GetShaderName(i)); - continue; + GL_MSG_Warning("CompileShaders: Could not compile custom shader program for %s\n", HWR_GetShaderName(i)); + usershader->program = 0; } - - pglShaderSource(gl_vertShader, 1, &vert_shader, NULL); - pglCompileShader(gl_vertShader); - - // check for compile errors - pglGetShaderiv(gl_vertShader, GL_COMPILE_STATUS, &result); - if (result == GL_FALSE) - { - Shader_CompileError("Error compiling vertex shader", gl_vertShader, i); - continue; - } - - // - // Load and compile fragment shader - // - gl_fragShader = pglCreateShader(GL_FRAGMENT_SHADER); - if (!gl_fragShader) - { - GL_MSG_Error("CompileShaders: Error creating fragment shader %s\n", HWR_GetShaderName(i)); - continue; - } - - pglShaderSource(gl_fragShader, 1, &frag_shader, NULL); - pglCompileShader(gl_fragShader); - - // check for compile errors - pglGetShaderiv(gl_fragShader, GL_COMPILE_STATUS, &result); - if (result == GL_FALSE) - { - Shader_CompileError("Error compiling fragment shader", gl_fragShader, i); - continue; - } - - shader->program = pglCreateProgram(); - pglAttachShader(shader->program, gl_vertShader); - pglAttachShader(shader->program, gl_fragShader); - pglLinkProgram(shader->program); - - // check link status - pglGetProgramiv(shader->program, GL_LINK_STATUS, &result); - - // delete the shader objects - pglDeleteShader(gl_vertShader); - pglDeleteShader(gl_fragShader); - - // couldn't link? - if (result != GL_TRUE) - { - shader->program = 0; - shader->custom = false; - GL_MSG_Error("CompileShaders: Error linking shader program %s\n", HWR_GetShaderName(i)); - continue; - } - - // 13062019 -#define GETUNI(uniform) pglGetUniformLocation(shader->program, uniform); - - // lighting - shader->uniforms[gluniform_poly_color] = GETUNI("poly_color"); - shader->uniforms[gluniform_tint_color] = GETUNI("tint_color"); - shader->uniforms[gluniform_fade_color] = GETUNI("fade_color"); - shader->uniforms[gluniform_lighting] = GETUNI("lighting"); - shader->uniforms[gluniform_fade_start] = GETUNI("fade_start"); - shader->uniforms[gluniform_fade_end] = GETUNI("fade_end"); - - // misc. (custom shaders) - shader->uniforms[gluniform_leveltime] = GETUNI("leveltime"); - -#undef GETUNI } + + SetShader(SHADER_DEFAULT); + return true; #else return false; @@ -1070,26 +1023,45 @@ EXPORT void HWRAPI(LoadCustomShader) (int number, char *code, size_t size, boole #endif } -EXPORT void HWRAPI(SetShader) (int shader) +EXPORT void HWRAPI(SetShader) (int type) { #ifdef GL_SHADERS - if (gl_allowshaders) + if (gl_allowshaders != HWD_SHADEROPTION_OFF) { + gl_shader_t *shader = gl_shaderstate.current; + // If using model lighting, set the appropriate shader. // However don't override a custom shader. - if (shader == SHADER_MODEL && model_lighting - && !(gl_shaderprograms[SHADER_MODEL].custom && !gl_shaderprograms[SHADER_MODEL_LIGHTING].custom)) - shader = SHADER_MODEL_LIGHTING; - if ((GLuint)shader != gl_currentshaderprogram) + if (type == SHADER_MODEL && model_lighting + && !(gl_shaders[SHADER_MODEL].custom && !gl_shaders[SHADER_MODEL_LIGHTING].custom)) + type = SHADER_MODEL_LIGHTING; + + if ((shader == NULL) || (GLuint)type != gl_shaderstate.type) { - gl_currentshaderprogram = shader; - gl_shaderprogramchanged = true; + gl_shader_t *baseshader = &gl_shaders[type]; + gl_shader_t *usershader = &gl_usershaders[type]; + + if (usershader->program) + shader = (gl_allowshaders == HWD_SHADEROPTION_NOCUSTOM) ? baseshader : usershader; + else + shader = baseshader; + + gl_shaderstate.current = shader; + gl_shaderstate.type = type; + gl_shaderstate.changed = true; } - gl_shadersenabled = true; + + if (gl_shaderstate.program != shader->program) + { + gl_shaderstate.program = shader->program; + gl_shaderstate.changed = true; + } + + gl_shadersenabled = (shader->program != 0); return; } #else - (void)shader; + (void)type; #endif gl_shadersenabled = false; } @@ -1097,11 +1069,15 @@ EXPORT void HWRAPI(SetShader) (int shader) EXPORT void HWRAPI(UnSetShader) (void) { #ifdef GL_SHADERS - gl_shadersenabled = false; - gl_currentshaderprogram = 0; - if (!pglUseProgram) return; - pglUseProgram(0); + gl_shaderstate.current = NULL; + gl_shaderstate.type = 0; + gl_shaderstate.program = 0; + + if (pglUseProgram) + pglUseProgram(0); #endif + + gl_shadersenabled = false; } EXPORT void HWRAPI(CleanShaders) (void) @@ -1901,42 +1877,24 @@ EXPORT void HWRAPI(SetTexture) (FTextureInfo *pTexInfo) } } -static void *Shader_Load(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade) -{ -#ifdef GL_SHADERS - if (gl_shadersenabled && pglUseProgram) - { - gl_shaderprogram_t *shader = &gl_shaderprograms[gl_currentshaderprogram]; - if (shader->program) - { - if (gl_shaderprogramchanged) - { - pglUseProgram(gl_shaderprograms[gl_currentshaderprogram].program); - gl_shaderprogramchanged = false; - } - Shader_SetUniforms(Surface, poly, tint, fade); - return shader; - } - else - pglUseProgram(0); - } -#else - (void)Surface; - (void)poly; - (void)tint; - (void)fade; -#endif - return NULL; -} - static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade) { #ifdef GL_SHADERS - if (gl_shadersenabled) + gl_shader_t *shader = gl_shaderstate.current; + + if (gl_shadersenabled && (shader != NULL) && pglUseProgram) { - gl_shaderprogram_t *shader = &gl_shaderprograms[gl_currentshaderprogram]; if (!shader->program) + { + pglUseProgram(0); return; + } + + if (gl_shaderstate.changed) + { + pglUseProgram(shader->program); + gl_shaderstate.changed = false; + } // Color uniforms can be left NULL and will be set to white (1.0f, 1.0f, 1.0f, 1.0f) if (poly == NULL) @@ -1989,6 +1947,97 @@ static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAF #endif } +static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i, const GLchar *vert_shader, const GLchar *frag_shader) +{ + GLuint gl_vertShader, gl_fragShader; + GLint result; + + // + // Load and compile vertex shader + // + gl_vertShader = pglCreateShader(GL_VERTEX_SHADER); + if (!gl_vertShader) + { + GL_MSG_Error("Shader_CompileProgram: Error creating vertex shader %s\n", HWR_GetShaderName(i)); + return false; + } + + pglShaderSource(gl_vertShader, 1, &vert_shader, NULL); + pglCompileShader(gl_vertShader); + + // check for compile errors + pglGetShaderiv(gl_vertShader, GL_COMPILE_STATUS, &result); + if (result == GL_FALSE) + { + Shader_CompileError("Error compiling vertex shader", gl_vertShader, i); + pglDeleteShader(gl_vertShader); + return false; + } + + // + // Load and compile fragment shader + // + gl_fragShader = pglCreateShader(GL_FRAGMENT_SHADER); + if (!gl_fragShader) + { + GL_MSG_Error("Shader_CompileProgram: Error creating fragment shader %s\n", HWR_GetShaderName(i)); + pglDeleteShader(gl_vertShader); + pglDeleteShader(gl_fragShader); + return false; + } + + pglShaderSource(gl_fragShader, 1, &frag_shader, NULL); + pglCompileShader(gl_fragShader); + + // check for compile errors + pglGetShaderiv(gl_fragShader, GL_COMPILE_STATUS, &result); + if (result == GL_FALSE) + { + Shader_CompileError("Error compiling fragment shader", gl_fragShader, i); + pglDeleteShader(gl_vertShader); + pglDeleteShader(gl_fragShader); + return false; + } + + shader->program = pglCreateProgram(); + pglAttachShader(shader->program, gl_vertShader); + pglAttachShader(shader->program, gl_fragShader); + pglLinkProgram(shader->program); + + // check link status + pglGetProgramiv(shader->program, GL_LINK_STATUS, &result); + + // delete the shader objects + pglDeleteShader(gl_vertShader); + pglDeleteShader(gl_fragShader); + + // couldn't link? + if (result != GL_TRUE) + { + GL_MSG_Error("Shader_CompileProgram: Error linking shader program %s\n", HWR_GetShaderName(i)); + pglDeleteProgram(shader->program); + return false; + } + + // 13062019 +#define GETUNI(uniform) pglGetUniformLocation(shader->program, uniform); + + // lighting + shader->uniforms[gluniform_poly_color] = GETUNI("poly_color"); + shader->uniforms[gluniform_tint_color] = GETUNI("tint_color"); + shader->uniforms[gluniform_fade_color] = GETUNI("fade_color"); + shader->uniforms[gluniform_lighting] = GETUNI("lighting"); + shader->uniforms[gluniform_fade_start] = GETUNI("fade_start"); + shader->uniforms[gluniform_fade_end] = GETUNI("fade_end"); + + // misc. (custom shaders) + shader->uniforms[gluniform_leveltime] = GETUNI("leveltime"); + +#undef GETUNI + + return true; +} + static void Shader_CompileError(const char *message, GLuint program, INT32 shadernum) { GLchar *infoLog = NULL; @@ -2002,7 +2051,7 @@ static void Shader_CompileError(const char *message, GLuint program, INT32 shade pglGetShaderInfoLog(program, logLength, NULL, infoLog); } - GL_MSG_Error("CompileShaders: %s (%s)\n%s", message, HWR_GetShaderName(shadernum), (infoLog ? infoLog : "")); + GL_MSG_Error("Shader_CompileProgram: %s (%s)\n%s", message, HWR_GetShaderName(shadernum), (infoLog ? infoLog : "")); if (infoLog) free(infoLog); @@ -2112,7 +2161,7 @@ static void PreparePolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FBITFIELD pglColor4ubv(c); } - Shader_Load(pSurf, &poly, &tint, &fade); + Shader_SetUniforms(pSurf, &poly, &tint, &fade); } // -----------------+ @@ -2158,7 +2207,7 @@ EXPORT void HWRAPI(RenderSkyDome) (gl_sky_t *sky) { int i, j; - Shader_Load(NULL, NULL, NULL, NULL); + Shader_SetUniforms(NULL, NULL, NULL, NULL); // Build the sky dome! Yes! if (sky->rebuild) @@ -2250,15 +2299,7 @@ EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value) break; case HWD_SET_SHADERS: - switch (Value) - { - case 1: - gl_allowshaders = true; - break; - default: - gl_allowshaders = false; - break; - } + gl_allowshaders = (hwdshaderoption_t)Value; break; case HWD_SET_TEXTUREFILTERMODE: @@ -2607,7 +2648,7 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 fade.blue = byte2float[Surface->FadeColor.s.blue]; fade.alpha = byte2float[Surface->FadeColor.s.alpha]; - Shader_Load(Surface, &poly, &tint, &fade); + Shader_SetUniforms(Surface, &poly, &tint, &fade); pglEnable(GL_CULL_FACE); pglEnable(GL_NORMALIZE); diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 72fb9272d..604a509e0 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -2120,7 +2120,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]; diff --git a/src/info.c b/src/info.c index cb5fb0889..29a79b1d6 100644 --- a/src/info.c +++ b/src/info.c @@ -584,6 +584,7 @@ char spr2names[NUMPLAYERSPRITES][5] = "TAL9", "TALA", "TALB", + "TALC", "CNT1", "CNT2", @@ -661,6 +662,7 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = { SPR2_TAL0, // SPR2_TAL9, SPR2_TAL9, // SPR2_TALA, SPR2_TAL0, // SPR2_TALB, + SPR2_TAL6, // SPR2_TALC, SPR2_WAIT, // SPR2_CNT1, SPR2_FALL, // SPR2_CNT2, @@ -801,6 +803,7 @@ state_t states[NUMSTATES] = {SPR_PLAY, SPR2_TAL9|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_PAIN}, // S_TAILSOVERLAY_PAIN {SPR_PLAY, SPR2_TALA|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_GASP}, // S_TAILSOVERLAY_GASP {SPR_PLAY, SPR2_TALB , 35, {NULL}, 0, 0, S_TAILSOVERLAY_EDGE}, // S_TAILSOVERLAY_EDGE + {SPR_PLAY, SPR2_TALC|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_DASH}, // S_TAILSOVERLAY_DASH // [: {SPR_JETF, 3|FF_ANIMATE|FF_FULLBRIGHT, 2, {NULL}, 1, 1, S_JETFUME1}, // S_JETFUMEFLASH diff --git a/src/info.h b/src/info.h index 721ebf7f2..d84461617 100644 --- a/src/info.h +++ b/src/info.h @@ -856,6 +856,7 @@ typedef enum playersprite SPR2_TAL9, SPR2_TALA, SPR2_TALB, + SPR2_TALC, SPR2_CNT1, // continue disappointment SPR2_CNT2, // continue lift @@ -997,6 +998,7 @@ typedef enum state S_TAILSOVERLAY_PAIN, S_TAILSOVERLAY_GASP, S_TAILSOVERLAY_EDGE, + S_TAILSOVERLAY_DASH, // [: S_JETFUMEFLASH, diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 674de64b0..1295cbf4e 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -247,6 +247,56 @@ static int lib_userdataType(lua_State *L) return luaL_typerror(L, 1, "userdata"); } +// Takes a metatable as first and only argument +// Only callable during script loading +static int lib_registerMetatable(lua_State *L) +{ + static UINT16 nextid = 1; + + if (!lua_lumploading) + return luaL_error(L, "This function cannot be called from within a hook or coroutine!"); + luaL_checktype(L, 1, LUA_TTABLE); + + if (nextid == 0) + return luaL_error(L, "Too many metatables registered?! Please consider rewriting your script once you are sober again.\n"); + + lua_getfield(L, LUA_REGISTRYINDEX, LREG_METATABLES); // 2 + // registry.metatables[metatable] = nextid + lua_pushvalue(L, 1); // 3 + lua_pushnumber(L, nextid); // 4 + lua_settable(L, 2); + + // registry.metatables[nextid] = metatable + lua_pushnumber(L, nextid); // 3 + lua_pushvalue(L, 1); // 4 + lua_settable(L, 2); + lua_pop(L, 1); + + nextid++; + + return 0; +} + +// Takes a string as only argument and returns the metatable +// associated to the userdata type this string refers to +// Returns nil if the string does not refer to a valid userdata type +static int lib_userdataMetatable(lua_State *L) +{ + UINT32 i; + const char *udname = luaL_checkstring(L, 1); + + // Find internal metatable name + for (i = 0; meta2utype[i].meta; i++) + if (!strcmp(udname, meta2utype[i].utype)) + { + luaL_getmetatable(L, meta2utype[i].meta); + return 1; + } + + lua_pushnil(L); + return 1; +} + static int lib_isPlayerAdmin(lua_State *L) { player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); @@ -3495,6 +3545,8 @@ static luaL_Reg lib[] = { {"chatprint", lib_chatprint}, {"chatprintf", lib_chatprintf}, {"userdataType", lib_userdataType}, + {"registerMetatable", lib_registerMetatable}, + {"userdataMetatable", lib_userdataMetatable}, {"IsPlayerAdmin", lib_isPlayerAdmin}, {"reserveLuabanks", lib_reserveLuabanks}, diff --git a/src/lua_libs.h b/src/lua_libs.h index 03bd99cd2..062a3fe50 100644 --- a/src/lua_libs.h +++ b/src/lua_libs.h @@ -16,6 +16,7 @@ extern lua_State *gL; #define LREG_EXTVARS "LUA_VARS" #define LREG_STATEACTION "STATE_ACTION" #define LREG_ACTIONS "MOBJ_ACTION" +#define LREG_METATABLES "METATABLES" #define META_STATE "STATE_T*" #define META_MOBJINFO "MOBJINFO_T*" diff --git a/src/lua_script.c b/src/lua_script.c index ae7f479f6..bb022f9ce 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -34,6 +34,7 @@ #include "lua_hook.h" #include "doomstat.h" +#include "g_state.h" lua_State *gL = NULL; @@ -361,6 +362,9 @@ int LUA_PushGlobals(lua_State *L, const char *word) } else if (fastcmp(word, "token")) { lua_pushinteger(L, token); return 1; + } else if (fastcmp(word, "gamestate")) { + lua_pushinteger(L, gamestate); + return 1; } return 0; } @@ -439,6 +443,10 @@ static void LUA_ClearState(void) lua_newtable(L); lua_setfield(L, LUA_REGISTRYINDEX, LREG_VALID); + // make LREG_METATABLES table for all registered metatables + lua_newtable(L); + lua_setfield(L, LUA_REGISTRYINDEX, LREG_METATABLES); + // open srb2 libraries for(i = 0; liblist[i]; i++) { lua_pushcfunction(L, liblist[i]); @@ -976,8 +984,17 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) lua_pop(gL, 1); } if (!found) + { t++; + if (t == 0) + { + CONS_Alert(CONS_ERROR, "Too many tables to archive!\n"); + WRITEUINT8(save_p, ARCH_NULL); + return 0; + } + } + WRITEUINT8(save_p, ARCH_TABLE); WRITEUINT16(save_p, t); @@ -1290,8 +1307,22 @@ static void ArchiveTables(void) lua_pop(gL, 1); } - lua_pop(gL, 1); WRITEUINT8(save_p, ARCH_TEND); + + // Write metatable ID + if (lua_getmetatable(gL, -1)) + { + // registry.metatables[metatable] + lua_getfield(gL, LUA_REGISTRYINDEX, LREG_METATABLES); + lua_pushvalue(gL, -2); + lua_gettable(gL, -2); + WRITEUINT16(save_p, lua_isnil(gL, -1) ? 0 : lua_tointeger(gL, -1)); + lua_pop(gL, 3); + } + else + WRITEUINT16(save_p, 0); + + lua_pop(gL, 1); } } @@ -1462,6 +1493,7 @@ static void UnArchiveTables(void) { int TABLESINDEX; UINT16 i, n; + UINT16 metatableid; if (!gL) return; @@ -1486,6 +1518,19 @@ static void UnArchiveTables(void) else lua_rawset(gL, -3); } + + metatableid = READUINT16(save_p); + if (metatableid) + { + // setmetatable(table, registry.metatables[metatableid]) + lua_getfield(gL, LUA_REGISTRYINDEX, LREG_METATABLES); + lua_rawgeti(gL, -1, metatableid); + if (lua_isnil(gL, -1)) + I_Error("Unknown metatable ID %d\n", metatableid); + lua_setmetatable(gL, -3); + lua_pop(gL, 1); + } + lua_pop(gL, 1); } } diff --git a/src/m_anigif.c b/src/m_anigif.c index 85118790b..dbc8d3422 100644 --- a/src/m_anigif.c +++ b/src/m_anigif.c @@ -29,15 +29,21 @@ // GIFs are always little-endian #include "byteptr.h" +CV_PossibleValue_t gif_dynamicdelay_cons_t[] = { + {0, "Off"}, + {1, "On"}, + {2, "Accurate, experimental"}, +{0, NULL}}; + consvar_t cv_gif_optimize = CVAR_INIT ("gif_optimize", "On", CV_SAVE, CV_OnOff, NULL); consvar_t cv_gif_downscale = CVAR_INIT ("gif_downscale", "On", CV_SAVE, CV_OnOff, NULL); -consvar_t cv_gif_dynamicdelay = CVAR_INIT ("gif_dynamicdelay", "On", CV_SAVE, CV_OnOff, NULL); +consvar_t cv_gif_dynamicdelay = CVAR_INIT ("gif_dynamicdelay", "On", CV_SAVE, gif_dynamicdelay_cons_t, NULL); consvar_t cv_gif_localcolortable = CVAR_INIT ("gif_localcolortable", "On", CV_SAVE, CV_OnOff, NULL); #ifdef HAVE_ANIGIF static boolean gif_optimize = false; // So nobody can do something dumb static boolean gif_downscale = false; // like changing cvars mid output -static boolean gif_dynamicdelay = false; // and messing something up +static UINT8 gif_dynamicdelay = (UINT8)0; // and messing something up // Palette handling static boolean gif_localcolortable = false; @@ -47,7 +53,8 @@ static RGBA_t *gif_framepalette = NULL; static FILE *gif_out = NULL; static INT32 gif_frames = 0; -static UINT32 gif_prevframems = 0; +static UINT32 gif_prevframeus = 0; // "us" is microseconds +static UINT32 gif_delayus = 0; static UINT8 gif_writeover = 0; @@ -594,16 +601,30 @@ static void GIF_framewrite(void) // screen regions are handled in GIF_lzw { - UINT16 delay; + UINT16 delay = 0; INT32 startline; - if (gif_dynamicdelay) { + if (gif_dynamicdelay ==(UINT8) 2) + { // golden's attempt at creating a "dynamic delay" + UINT16 mingifdelay = 10; // minimum gif delay in milliseconds (keep at 10 because gifs can't get more precise). + gif_delayus += (I_GetTimeMicros() - gif_prevframeus); // increase delay by how much time was spent between last measurement + + if (gif_delayus/1000 >= mingifdelay) // delay is big enough to be able to effect gif frame delay? + { + int frames = (gif_delayus/1000) / mingifdelay; // get amount of frames to delay. + delay = frames; // set the delay to delay that amount of frames. + gif_delayus -= frames*(mingifdelay*1000); // remove frames by the amount of milliseconds they take. don't reset to 0, the microseconds help consistency. + } + } + else if (gif_dynamicdelay ==(UINT8) 1) + { float delayf = ceil(100.0f/NEWTICRATE); - delay = (UINT16)((I_GetTimeMicros() - gif_prevframems)/10/1000); - if (delay < (int)(delayf)) - delay = (int)(delayf); + delay = (UINT16)((I_GetTimeMicros() - gif_prevframeus)/10/1000); + + if (delay < (UINT16)(delayf)) + delay = (UINT16)(delayf); } else { @@ -690,7 +711,7 @@ static void GIF_framewrite(void) } fwrite(gifframe_data, 1, (p - gifframe_data), gif_out); ++gif_frames; - gif_prevframems = I_GetTimeMicros(); + gif_prevframeus = I_GetTimeMicros(); } @@ -711,14 +732,15 @@ INT32 GIF_open(const char *filename) gif_optimize = (!!cv_gif_optimize.value); gif_downscale = (!!cv_gif_downscale.value); - gif_dynamicdelay = (!!cv_gif_dynamicdelay.value); + gif_dynamicdelay = (UINT8)cv_gif_dynamicdelay.value; gif_localcolortable = (!!cv_gif_localcolortable.value); gif_colorprofile = (!!cv_screenshot_colorprofile.value); gif_headerpalette = GIF_getpalette(0); GIF_headwrite(); gif_frames = 0; - gif_prevframems = I_GetTimeMicros(); + gif_prevframeus = I_GetTimeMicros(); + gif_delayus = 0; return 1; } diff --git a/src/m_cheat.c b/src/m_cheat.c index 6fc06d353..6e0fb8c5c 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -1434,19 +1434,26 @@ void Command_Writethings_f(void) REQUIRE_SINGLEPLAYER; REQUIRE_OBJECTPLACE; - P_WriteThings(W_GetNumForName(G_BuildMapName(gamemap)) + ML_THINGS); + P_WriteThings(); } void Command_ObjectPlace_f(void) { + size_t thingarg; + size_t silent; + REQUIRE_INLEVEL; REQUIRE_SINGLEPLAYER; REQUIRE_NOULTIMATE; G_SetGameModified(multiplayer); + silent = COM_CheckParm("-silent"); + + thingarg = 2 - ( silent != 1 ); + // Entering objectplace? - if (!objectplacing || COM_Argc() > 1) + if (!objectplacing || thingarg < COM_Argc()) { if (!objectplacing) { @@ -1455,7 +1462,7 @@ void Command_ObjectPlace_f(void) if (players[0].powers[pw_carry] == CR_NIGHTSMODE) return; - if (!COM_CheckParm("-silent")) + if (! silent) { HU_SetCEchoFlags(V_RETURN8|V_MONOSPACE|V_AUTOFADEOUT); HU_SetCEchoDuration(10); @@ -1506,9 +1513,9 @@ void Command_ObjectPlace_f(void) op_oldstate = (statenum_t)(players[0].mo->state-states); } - if (COM_Argc() > 1) + if (thingarg < COM_Argc()) { - UINT16 mapthingnum = atoi(COM_Argv(1)); + UINT16 mapthingnum = atoi(COM_Argv(thingarg)); mobjtype_t type = P_GetMobjtype(mapthingnum); if (type == MT_UNKNOWN) CONS_Printf(M_GetText("No mobj type delegated to thing type %d.\n"), mapthingnum); diff --git a/src/m_menu.c b/src/m_menu.c index 6e0d520ae..5860f00ca 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -8246,7 +8246,7 @@ static void M_CacheLoadGameData(void) static void M_DrawLoadGameData(void) { - INT32 i, savetodraw, x, y, hsep = 90; + INT32 i, prev_i = 1, savetodraw, x, y, hsep = 90; skin_t *charskin = NULL; if (vid.width != BASEVIDWIDTH*vid.dupx) @@ -8255,8 +8255,9 @@ static void M_DrawLoadGameData(void) if (needpatchrecache) M_CacheLoadGameData(); - for (i = -2; i <= 2; i++) + for (i = 2; prev_i; i = -(i + ((UINT32)i >> 31))) // draws from outwards in; 2, -2, 1, -1, 0 { + prev_i = i; savetodraw = (saveSlotSelected + i + numsaves)%numsaves; x = (BASEVIDWIDTH/2 - 42 + loadgamescroll) + (i*hsep); y = 33 + 9; diff --git a/src/m_perfstats.c b/src/m_perfstats.c index df1e31b5e..085adda80 100644 --- a/src/m_perfstats.c +++ b/src/m_perfstats.c @@ -1,7 +1,6 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/m_perfstats.h b/src/m_perfstats.h index 1db46025e..01a818c1c 100644 --- a/src/m_perfstats.h +++ b/src/m_perfstats.h @@ -1,7 +1,6 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/p_map.c b/src/p_map.c index 0a9107ee5..922c0d9ec 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -2735,7 +2735,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) // Step up if (thing->z < tmfloorz) { - if (tmfloorz - thing->z <= maxstep) + if (maxstep > 0 && tmfloorz - thing->z <= maxstep) { thing->z = thing->floorz = tmfloorz; thing->floorrover = tmfloorrover; @@ -2748,7 +2748,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) } else if (tmceilingz < thingtop) { - if (thingtop - tmceilingz <= maxstep) + if (maxstep > 0 && thingtop - tmceilingz <= maxstep) { thing->z = ( thing->ceilingz = tmceilingz ) - thing->height; thing->ceilingrover = tmceilingrover; @@ -3107,7 +3107,7 @@ static void P_HitSlideLine(line_t *ld) lineangle >>= ANGLETOFINESHIFT; deltaangle >>= ANGLETOFINESHIFT; - movelen = P_AproxDistance(tmxmove, tmymove); + movelen = R_PointToDist2(0, 0, tmxmove, tmymove); newlen = FixedMul(movelen, FINECOSINE(deltaangle)); tmxmove = FixedMul(newlen, FINECOSINE(lineangle)); diff --git a/src/p_saveg.c b/src/p_saveg.c index 8e9bcf110..2abd65a95 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -98,13 +98,16 @@ static void P_NetArchivePlayers(void) for (i = 0; i < MAXPLAYERS; i++) { + WRITESINT8(save_p, (SINT8)adminplayers[i]); + if (!playeringame[i]) continue; flags = 0; - // no longer send ticcmds, player name, skin, or color + // no longer send ticcmds + WRITESTRINGN(save_p, player_names[i], MAXPLAYERNAME); WRITEINT16(save_p, players[i].angleturn); WRITEINT16(save_p, players[i].oldrelangleturn); WRITEANGLE(save_p, players[i].aiming); @@ -134,6 +137,9 @@ static void P_NetArchivePlayers(void) WRITEUINT16(save_p, players[i].flashpal); WRITEUINT16(save_p, players[i].flashcount); + WRITEUINT8(save_p, players[i].skincolor); + WRITEINT32(save_p, players[i].skin); + WRITEUINT32(save_p, players[i].availabilities); WRITEUINT32(save_p, players[i].score); WRITEFIXED(save_p, players[i].dashspeed); WRITESINT8(save_p, players[i].lives); @@ -305,6 +311,8 @@ static void P_NetUnArchivePlayers(void) for (i = 0; i < MAXPLAYERS; i++) { + adminplayers[i] = (INT32)READSINT8(save_p); + // Do NOT memset player struct to 0 // other areas may initialize data elsewhere //memset(&players[i], 0, sizeof (player_t)); @@ -312,9 +320,8 @@ static void P_NetUnArchivePlayers(void) continue; // NOTE: sending tics should (hopefully) no longer be necessary - // sending player names, skin and color should not be necessary at all! - // (that data is handled in the server config now) + READSTRINGN(save_p, player_names[i], MAXPLAYERNAME); players[i].angleturn = READINT16(save_p); players[i].oldrelangleturn = READINT16(save_p); players[i].aiming = READANGLE(save_p); @@ -344,6 +351,9 @@ static void P_NetUnArchivePlayers(void) players[i].flashpal = READUINT16(save_p); players[i].flashcount = READUINT16(save_p); + players[i].skincolor = READUINT8(save_p); + players[i].skin = READINT32(save_p); + players[i].availabilities = READUINT32(save_p); players[i].score = READUINT32(save_p); players[i].dashspeed = READFIXED(save_p); // dashing speed players[i].lives = READSINT8(save_p); @@ -3964,14 +3974,17 @@ static inline void P_UnArchiveSPGame(INT16 mapoverride) playeringame[consoleplayer] = true; } -static void P_NetArchiveMisc(void) +static void P_NetArchiveMisc(boolean resending) { INT32 i; WRITEUINT32(save_p, ARCHIVEBLOCK_MISC); + if (resending) + WRITEUINT32(save_p, gametic); WRITEINT16(save_p, gamemap); WRITEINT16(save_p, gamestate); + WRITEINT16(save_p, gametype); { UINT32 pig = 0; @@ -4034,13 +4047,16 @@ static void P_NetArchiveMisc(void) WRITEUINT8(save_p, 0x2e); } -static inline boolean P_NetUnArchiveMisc(void) +static inline boolean P_NetUnArchiveMisc(boolean reloading) { INT32 i; if (READUINT32(save_p) != ARCHIVEBLOCK_MISC) I_Error("Bad $$$.sav at archive block Misc"); + if (reloading) + gametic = READUINT32(save_p); + gamemap = READINT16(save_p); // gamemap changed; we assume that its map header is always valid, @@ -4054,6 +4070,8 @@ static inline boolean P_NetUnArchiveMisc(void) G_SetGamestate(READINT16(save_p)); + gametype = READINT16(save_p); + { UINT32 pig = READUINT32(save_p); for (i = 0; i < MAXPLAYERS; i++) @@ -4067,7 +4085,7 @@ static inline boolean P_NetUnArchiveMisc(void) tokenlist = READUINT32(save_p); - if (!P_LoadLevel(true)) + if (!P_LoadLevel(true, reloading)) return false; // get the time @@ -4166,14 +4184,14 @@ void P_SaveGame(INT16 mapnum) P_ArchiveLuabanksAndConsistency(); } -void P_SaveNetGame(void) +void P_SaveNetGame(boolean resending) { thinker_t *th; mobj_t *mobj; INT32 i = 1; // don't start from 0, it'd be confused with a blank pointer otherwise CV_SaveNetVars(&save_p); - P_NetArchiveMisc(); + P_NetArchiveMisc(resending); // Assign the mobjnumber for pointer tracking for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) @@ -4221,10 +4239,10 @@ boolean P_LoadGame(INT16 mapoverride) return true; } -boolean P_LoadNetGame(void) +boolean P_LoadNetGame(boolean reloading) { CV_LoadNetVars(&save_p); - if (!P_NetUnArchiveMisc()) + if (!P_NetUnArchiveMisc(reloading)) return false; P_NetUnArchivePlayers(); if (gamestate == GS_LEVEL) diff --git a/src/p_saveg.h b/src/p_saveg.h index d8756a7a9..be98953eb 100644 --- a/src/p_saveg.h +++ b/src/p_saveg.h @@ -22,9 +22,9 @@ // These are the load / save game routines. void P_SaveGame(INT16 mapnum); -void P_SaveNetGame(void); +void P_SaveNetGame(boolean resending); boolean P_LoadGame(INT16 mapoverride); -boolean P_LoadNetGame(void); +boolean P_LoadNetGame(boolean reloading); mobj_t *P_FindNewPosition(UINT32 oldposition); diff --git a/src/p_setup.c b/src/p_setup.c index 80510c9c3..87fb2ac0d 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -906,16 +906,13 @@ static void P_SpawnMapThings(boolean spawnemblems) } // Experimental groovy write function! -void P_WriteThings(lumpnum_t lumpnum) +void P_WriteThings(void) { size_t i, length; mapthing_t *mt; - UINT8 *data; UINT8 *savebuffer, *savebuf_p; INT16 temp; - data = W_CacheLumpNum(lumpnum, PU_LEVEL); - savebuf_p = savebuffer = (UINT8 *)malloc(nummapthings * sizeof (mapthing_t)); if (!savebuf_p) @@ -937,8 +934,6 @@ void P_WriteThings(lumpnum_t lumpnum) WRITEUINT16(savebuf_p, mt->options); } - Z_Free(data); - length = savebuf_p - savebuffer; FIL_WriteFile(va("newthings%d.lmp", gamemap), savebuffer, length); @@ -2432,6 +2427,10 @@ static boolean P_LoadExtendedSubsectorsAndSegs(UINT8 **data, nodetype_t nodetype seg->angle = R_PointToAngle2(v1->x, v1->y, v2->x, v2->y); if (seg->linedef) segs[i].offset = FixedHypot(v1->x - seg->linedef->v1->x, v1->y - seg->linedef->v1->y); + seg->length = P_SegLength(seg); +#ifdef HWRENDER + seg->flength = (rendermode == render_opengl) ? P_SegLengthFloat(seg) : 0; +#endif } return true; @@ -3359,8 +3358,6 @@ static void P_InitLevelSettings(void) leveltime = 0; - localaiming = 0; - localaiming2 = 0; modulothing = 0; // special stage tokens, emeralds, and ring total @@ -3475,6 +3472,9 @@ void P_RespawnThings(void) P_InitLevelSettings(); + localaiming = 0; + localaiming2 = 0; + P_SpawnMapThings(true); // restore skybox viewpoint/centerpoint if necessary, set them to defaults if we can't do that @@ -3982,7 +3982,7 @@ static void P_InitGametype(void) * \param fromnetsave If true, skip some stuff because we're loading a netgame snapshot. * \todo Clean up, refactor, split up; get rid of the bloat. */ -boolean P_LoadLevel(boolean fromnetsave) +boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) { // use gamemap to get map number. // 99% of the things already did, so. @@ -4052,7 +4052,10 @@ boolean P_LoadLevel(boolean fromnetsave) players[consoleplayer].viewz = 1; // Cancel all d_main.c fadeouts (keep fade in though). - wipegamestate = FORCEWIPEOFF; + if (reloadinggamestate) + wipegamestate = gamestate; // Don't fade if reloading the gamestate + else + wipegamestate = FORCEWIPEOFF; wipestyleflags = 0; // Special stage & record attack retry fade to white @@ -4078,18 +4081,20 @@ boolean P_LoadLevel(boolean fromnetsave) // Fade out music here. Deduct 2 tics so the fade volume actually reaches 0. // But don't halt the music! S_Start will take care of that. This dodges a MIDI crash bug. - if (!titlemapinaction && (RESETMUSIC || + if (!(reloadinggamestate || titlemapinaction) && (RESETMUSIC || strnicmp(S_MusicName(), (mapmusflags & MUSIC_RELOADRESET) ? mapheaderinfo[gamemap-1]->musname : mapmusname, 7))) + { S_FadeMusic(0, FixedMul( FixedDiv((F_GetWipeLength(wipedefs[wipe_level_toblack])-2)*NEWTICRATERATIO, NEWTICRATE), MUSICRATE)); + } // Let's fade to black here // But only if we didn't do the special stage wipe - if (rendermode != render_none && !ranspecialwipe) + if (rendermode != render_none && !(ranspecialwipe || reloadinggamestate)) P_RunLevelWipe(); - if (!titlemapinaction) + if (!(reloadinggamestate || titlemapinaction)) { if (ranspecialwipe == 2) { @@ -4214,7 +4219,12 @@ boolean P_LoadLevel(boolean fromnetsave) if (!fromnetsave) P_InitGametype(); - P_InitCamera(); + if (!reloadinggamestate) + { + P_InitCamera(); + localaiming = 0; + localaiming2 = 0; + } // clear special respawning que iquehead = iquetail = 0; @@ -4222,7 +4232,7 @@ boolean P_LoadLevel(boolean fromnetsave) P_MapEnd(); // Remove the loading shit from the screen - if (rendermode != render_none && !titlemapinaction) + if (rendermode != render_none && !(titlemapinaction || reloadinggamestate)) F_WipeColorFill(levelfadecol); if (precache || dedicated) @@ -4266,8 +4276,8 @@ boolean P_LoadLevel(boolean fromnetsave) LUAh_MapLoad(); } - // No render mode, stop here. - if (rendermode == render_none) + // No render mode or reloading gamestate, stop here. + if (rendermode == render_none || reloadinggamestate) return true; // Title card! diff --git a/src/p_setup.h b/src/p_setup.h index ef903e103..c82f93351 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -97,7 +97,7 @@ void P_SetupLevelSky(INT32 skynum, boolean global); void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum); #endif void P_RespawnThings(void); -boolean P_LoadLevel(boolean fromnetsave); +boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate); #ifdef HWRENDER void HWR_SetupLevel(void); #endif @@ -105,7 +105,7 @@ boolean P_AddWadFile(const char *wadfilename); boolean P_RunSOC(const char *socfilename); void P_LoadSoundsRange(UINT16 wadnum, UINT16 first, UINT16 num); void P_LoadMusicsRange(UINT16 wadnum, UINT16 first, UINT16 num); -void P_WriteThings(lumpnum_t lump); +void P_WriteThings(void); size_t P_PrecacheLevelFlats(void); void P_AllocMapHeader(INT16 i); diff --git a/src/p_user.c b/src/p_user.c index c8516e519..10b7e970e 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2029,6 +2029,7 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj) ghost->colorized = mobj->colorized; // alternatively, "true" for sonic advance style colourisation ghost->angle = (mobj->player ? mobj->player->drawangle : mobj->angle); + ghost->rollangle = mobj->rollangle; ghost->sprite = mobj->sprite; ghost->sprite2 = mobj->sprite2; ghost->frame = mobj->frame; @@ -11223,6 +11224,8 @@ static void P_DoTailsOverlay(player_t *player, mobj_t *tails) chosenstate = S_TAILSOVERLAY_GASP; else if (player->mo->state-states == S_PLAY_EDGE) chosenstate = S_TAILSOVERLAY_EDGE; + else if (player->panim == PA_DASH) + chosenstate = S_TAILSOVERLAY_DASH; else if (player->panim == PA_RUN) chosenstate = S_TAILSOVERLAY_RUN; else if (player->panim == PA_WALK) diff --git a/src/r_picformats.c b/src/r_picformats.c index 95fe23aeb..8d7cf37f2 100644 --- a/src/r_picformats.c +++ b/src/r_picformats.c @@ -887,26 +887,45 @@ static png_bytep *PNG_Read( // matches the color count of SRB2's palette: 256 colors. if (png_get_PLTE(png_ptr, png_info_ptr, &palette, &palette_size)) { - if (palette_size == 256) + if (palette_size == 256 && pMasterPalette) + { + png_colorp pal = palette; + INT32 i; + usepal = true; + + for (i = 0; i < 256; i++) + { + UINT32 rgb = R_PutRgbaRGBA(pal->red, pal->green, pal->blue, 0xFF); + if (rgb != pMasterPalette[i].rgba) + { + usepal = false; + break; + } + pal++; + } + } } // If any of the tRNS colors have an alpha lower than 0xFF, and that // color is present on the image, the palette flag is disabled. - png_get_tRNS(png_ptr, png_info_ptr, &trans, &trans_num, &trans_values); - - if (trans && trans_num == 256) + if (usepal) { - int i; - for (i = 0; i < trans_num; i++) + png_get_tRNS(png_ptr, png_info_ptr, &trans, &trans_num, &trans_values); + + if (trans && trans_num == 256) { - // libpng will transform this image into RGB even if - // the transparent index does not exist in the image, - // and there is no way around that. - if (trans[i] < 0xFF) + INT32 i; + for (i = 0; i < trans_num; i++) { - usepal = false; - break; + // libpng will transform this image into RGB even if + // the transparent index does not exist in the image, + // and there is no way around that. + if (trans[i] < 0xFF) + { + usepal = false; + break; + } } } } diff --git a/src/sdl/CMakeLists.txt b/src/sdl/CMakeLists.txt index bb5edf817..a7f015c86 100644 --- a/src/sdl/CMakeLists.txt +++ b/src/sdl/CMakeLists.txt @@ -272,7 +272,7 @@ if(${SDL2_FOUND}) endif() target_compile_definitions(SRB2SDL2 PRIVATE - -DDDIRECTFULLSCREEN -DHAVE_SDL + -DDIRECTFULLSCREEN -DHAVE_SDL ) ## strip debug symbols into separate file when using gcc. diff --git a/src/sdl/ogl_sdl.c b/src/sdl/ogl_sdl.c index 04214ad03..52727c056 100644 --- a/src/sdl/ogl_sdl.c +++ b/src/sdl/ogl_sdl.c @@ -189,7 +189,7 @@ boolean OglSdlSurface(INT32 w, INT32 h) SetupGLFunc4(); - granisotropicmode_cons_t[1].value = maximumAnisotropy; + glanisotropicmode_cons_t[1].value = maximumAnisotropy; SDL_GL_SetSwapInterval(cv_vidwait.value ? 1 : 0); diff --git a/src/w_wad.c b/src/w_wad.c index fd70f8ec3..42417a4b9 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -2074,14 +2074,59 @@ int W_VerifyNMUSlumps(const char *filename) {"CLM", 3}, // Colormap changes {"TRANS", 5}, // Translucency map changes + {"CONSBACK", 8}, // Console Background graphic + + {"SAVE", 4}, // Save Select graphics here and below + {"BLACXLVL", 8}, + {"GAMEDONE", 8}, + {"CONT", 4}, // Continue icons on saves (probably not used anymore) + {"STNONEX", 7}, // "X" graphic + {"ULTIMATE", 8}, // Ultimate no-save + + {"CRFNT", 5}, // Sonic 1 font changes + {"NTFNT", 5}, // Character Select font changes + {"NTFNO", 5}, // Character Select font (outline) {"LTFNT", 5}, // Level title font changes {"TTL", 3}, // Act number changes {"STCFN", 5}, // Console font changes {"TNYFN", 5}, // Tiny console font changes + + {"STLIVE", 6}, // Life graphics, background and the "X" that shows under skin's HUDNAME + {"CROSHAI", 7}, // First person crosshairs + {"INTERSC", 7}, // Default intermission backgrounds (co-op) {"STT", 3}, // Acceptable HUD changes (Score Time Rings) {"YB_", 3}, // Intermission graphics, goes with the above - {"M_", 2}, // As does menu stuff + {"RESULT", 6}, // Used in intermission for competitive modes, above too :3 + {"RACE", 4}, // Race mode graphics, 321go + {"M_", 2}, // Menu stuff + {"LT", 2}, // Titlecard changes + + {"SLID", 4}, // Continue + {"CONT", 4}, + + {"MINICAPS", 8}, // NiGHTS graphics here and below + {"BLUESTAT", 8}, // Sphere status + {"BYELSTAT", 8}, + {"ORNGSTAT", 8}, + {"REDSTAT", 7}, + {"YELSTAT", 7}, + {"NBRACKET", 8}, + {"NGHTLINK", 8}, + {"NGT", 3}, // Link numbers + {"NARROW", 6}, + {"NREDAR", 6}, + {"NSS", 3}, + {"NBON", 4}, + {"NRNG", 4}, + {"NHUD", 4}, + {"CAPS", 4}, + {"DRILL", 5}, + {"GRADE", 5}, + {"MINUS5", 6}, + {"MUSICDEF", 8}, // Song definitions (thanks kart) + {"SHADERS", 7}, // OpenGL shader definitions + {"SH_", 3}, // GLSL shader {NULL, 0}, };