Merge branch 'packet-hack' into 'master'

Experimental: Improve level load processing

See merge request KartKrew/Kart!1077
This commit is contained in:
Sal 2023-03-28 23:41:33 +00:00
commit 83b5b26a12
9 changed files with 122 additions and 152 deletions

View file

@ -383,11 +383,13 @@ static UINT8* D_GetTextcmd(tic_t tic, INT32 playernum)
return textcmdplayer->cmd; return textcmdplayer->cmd;
} }
static void ExtraDataTicker(void) static boolean ExtraDataTicker(void)
{ {
boolean anyNetCmd = false;
INT32 i; INT32 i;
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] || i == 0) if (playeringame[i] || i == 0)
{ {
UINT8 *bufferstart = D_GetExistingTextcmd(gametic, i); UINT8 *bufferstart = D_GetExistingTextcmd(gametic, i);
@ -407,6 +409,7 @@ static void ExtraDataTicker(void)
DEBFILE(va("executing x_cmd %s ply %u ", netxcmdnames[id - 1], i)); DEBFILE(va("executing x_cmd %s ply %u ", netxcmdnames[id - 1], i));
(listnetxcmd[id])(&curpos, i); (listnetxcmd[id])(&curpos, i);
DEBFILE("done\n"); DEBFILE("done\n");
anyNetCmd = true;
} }
else else
{ {
@ -421,12 +424,17 @@ static void ExtraDataTicker(void)
} }
} }
} }
}
// If you are a client, you can safely forget the net commands for this tic // If you are a client, you can safely forget the net commands for this tic
// If you are the server, you need to remember them until every client has been acknowledged, // If you are the server, you need to remember them until every client has been acknowledged,
// because if you need to resend a PT_SERVERTICS packet, you will need to put the commands in it // because if you need to resend a PT_SERVERTICS packet, you will need to put the commands in it
if (client) if (client)
{
D_FreeTextcmd(gametic); D_FreeTextcmd(gametic);
}
return anyNetCmd;
} }
static void D_Clearticcmd(tic_t tic) static void D_Clearticcmd(tic_t tic)
@ -4995,7 +5003,7 @@ static void GetPackets(void)
if (netbuffer->packettype == PT_CLIENTJOIN && server) if (netbuffer->packettype == PT_CLIENTJOIN && server)
{ {
if (!levelloading) // Otherwise just ignore if (levelloading == false) // Otherwise just ignore
{ {
HandleConnect(node); HandleConnect(node);
} }
@ -5577,16 +5585,37 @@ boolean TryRunTics(tic_t realtics)
} }
if (ticking) if (ticking)
{
{ {
// run the count * tics // run the count * tics
while (neededtic > gametic) while (neededtic > gametic)
{ {
boolean dontRun = false;
DEBFILE(va("============ Running tic %d (local %d)\n", gametic, localgametic)); DEBFILE(va("============ Running tic %d (local %d)\n", gametic, localgametic));
ps_tictime = I_GetPreciseTime(); ps_tictime = I_GetPreciseTime();
dontRun = ExtraDataTicker();
if (levelloading == false
|| gametic > levelstarttic + 5) // Don't lock-up if a malicious client is sending tons of netxcmds
{
// During level load, we want to pause
// execution until we've finished loading
// all of the netxcmds in our buffer.
dontRun = false;
}
if (dontRun == false)
{
if (levelloading == true)
{
P_PostLoadLevel();
}
G_Ticker((gametic % NEWTICRATERATIO) == 0); G_Ticker((gametic % NEWTICRATERATIO) == 0);
}
if (Playing() && netgame && (gametic % TICRATE == 0)) if (Playing() && netgame && (gametic % TICRATE == 0))
{ {
Schedule_Run(); Schedule_Run();
@ -5597,15 +5626,14 @@ boolean TryRunTics(tic_t realtics)
} }
} }
ExtraDataTicker();
gametic++; gametic++;
consistancy[gametic%BACKUPTICS] = Consistancy(); consistancy[gametic % BACKUPTICS] = Consistancy();
ps_tictime = I_GetPreciseTime() - ps_tictime; ps_tictime = I_GetPreciseTime() - ps_tictime;
// Leave a certain amount of tics present in the net buffer as long as we've ran at least one tic this frame. // Leave a certain amount of tics present in the net buffer as long as we've ran at least one tic this frame.
if (client && gamestate == GS_LEVEL && leveltime > 3 && neededtic <= gametic + cv_netticbuffer.value) if (client && gamestate == GS_LEVEL && leveltime > 1 && neededtic <= gametic + cv_netticbuffer.value)
{
break; break;
} }
} }

View file

@ -96,7 +96,7 @@ static void K_SpawnDuelOnlyItems(void)
void K_TimerReset(void) void K_TimerReset(void)
{ {
starttime = introtime = 3; starttime = introtime = 0;
numbulbs = 1; numbulbs = 1;
inDuel = rainbowstartavailable = false; inDuel = rainbowstartavailable = false;
timelimitintics = extratimeintics = secretextratime = 0; timelimitintics = extratimeintics = secretextratime = 0;

View file

@ -118,7 +118,6 @@ ENUM (STRING_HOOK);
//#define LUA_HUDHOOK(type) LUA_HookHUD(HUD_HOOK(type)) //#define LUA_HUDHOOK(type) LUA_HookHUD(HUD_HOOK(type))
extern boolean hook_cmd_running; extern boolean hook_cmd_running;
extern int hook_defrosting;
void LUA_HookVoid(int hook); void LUA_HookVoid(int hook);
void LUA_HookHUD(huddrawlist_h, int hook); void LUA_HookHUD(huddrawlist_h, int hook);

View file

@ -39,8 +39,6 @@
lua_State *gL = NULL; lua_State *gL = NULL;
int hook_defrosting;
// List of internal libraries to load from SRB2 // List of internal libraries to load from SRB2
static lua_CFunction liblist[] = { static lua_CFunction liblist[] = {
LUA_EnumLib, // global metatable for enums LUA_EnumLib, // global metatable for enums
@ -288,9 +286,6 @@ int LUA_PushGlobals(lua_State *L, const char *word)
} else if (fastcmp(word,"starttime")) { } else if (fastcmp(word,"starttime")) {
lua_pushinteger(L, starttime); lua_pushinteger(L, starttime);
return 1; return 1;
} else if (fastcmp(word,"defrosting")) {
lua_pushinteger(L, hook_defrosting);
return 1;
} else if (fastcmp(word,"curWeather")) { } else if (fastcmp(word,"curWeather")) {
lua_pushinteger(L, curWeather); lua_pushinteger(L, curWeather);
return 1; return 1;

View file

@ -10964,7 +10964,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
// Call action functions when the state is set // Call action functions when the state is set
if (st->action.acp1 && (mobj->flags & MF_RUNSPAWNFUNC)) if (st->action.acp1 && (mobj->flags & MF_RUNSPAWNFUNC))
{ {
if (levelloading) if (levelloading == true)
{ {
// Cache actions in a linked list // Cache actions in a linked list
// with function pointer, and // with function pointer, and

View file

@ -7064,6 +7064,8 @@ static void P_InitLevelSettings(void)
leveltime = 0; leveltime = 0;
modulothing = 0; modulothing = 0;
K_TimerReset();
// special stage tokens, emeralds, and ring total // special stage tokens, emeralds, and ring total
runemeraldmanager = false; runemeraldmanager = false;
emeraldspawndelay = 60*TICRATE; emeraldspawndelay = 60*TICRATE;
@ -7623,8 +7625,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
sector_t *ss; sector_t *ss;
virtlump_t *encoreLump = NULL; virtlump_t *encoreLump = NULL;
K_TimerReset();
levelloading = true; levelloading = true;
// This is needed. Don't touch. // This is needed. Don't touch.
@ -8004,10 +8004,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
G_AddMapToBuffer(gamemap-1); G_AddMapToBuffer(gamemap-1);
levelloading = false;
P_RunCachedActions();
P_MapEnd(); // tm.thing is no longer needed from this point onwards P_MapEnd(); // tm.thing is no longer needed from this point onwards
// Took me 3 hours to figure out why my progression kept on getting overwritten with the titlemap... // Took me 3 hours to figure out why my progression kept on getting overwritten with the titlemap...
@ -8018,34 +8014,51 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
// I'd love to do this in the menu code instead of here, but everything's a mess and I can't guarantee saving proper player struct info before the first act's started. You could probably refactor it, but it'd be a lot of effort. Easier to just work off known good code. ~toast 22/06/2020 // I'd love to do this in the menu code instead of here, but everything's a mess and I can't guarantee saving proper player struct info before the first act's started. You could probably refactor it, but it'd be a lot of effort. Easier to just work off known good code. ~toast 22/06/2020
if (!(ultimatemode || netgame || multiplayer || demo.playback || demo.recording || metalrecording || modeattacking || marathonmode) if (!(ultimatemode || netgame || multiplayer || demo.playback || demo.recording || metalrecording || modeattacking || marathonmode)
&& !usedCheats && cursaveslot > 0) && !usedCheats && cursaveslot > 0)
{
G_SaveGame((UINT32)cursaveslot, gamemap); G_SaveGame((UINT32)cursaveslot, gamemap);
}
// If you're looking for saving sp file progression (distinct from G_SaveGameOver), check G_DoCompleted. // If you're looking for saving sp file progression (distinct from G_SaveGameOver), check G_DoCompleted.
} }
lastmaploaded = gamemap; // HAS to be set after saving!! lastmaploaded = gamemap; // HAS to be set after saving!!
} }
if (!fromnetsave) // uglier hack if (!fromnetsave)
{ // to make a newly loaded level start on the second frame. {
INT32 buf = gametic % BACKUPTICS; INT32 buf = gametic % BACKUPTICS;
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
{ {
if (playeringame[i]) if (playeringame[i])
{
G_CopyTiccmd(&players[i].cmd, &netcmds[buf][i], 1); G_CopyTiccmd(&players[i].cmd, &netcmds[buf][i], 1);
} }
P_PreTicker(2);
P_MapStart(); // just in case MapLoad modifies tm.thing
ACS_RunLevelStartScripts();
LUA_HookInt(gamemap, HOOK(MapLoad));
P_MapEnd(); // just in case MapLoad modifies tm.thing
} }
// No render mode or reloading gamestate, stop here. for (i = 0; i <= r_splitscreen; i++)
if (rendermode == render_none || reloadinggamestate) {
return true; postimgtype[i] = postimg_none;
}
if (marathonmode & MA_INGAME)
{
marathonmode |= MA_INIT;
}
P_MapStart(); // just in case MapLoad modifies tm.thing
ACS_RunLevelStartScripts();
LUA_HookInt(gamemap, HOOK(MapLoad));
P_MapEnd(); // just in case MapLoad modifies tm.thing
}
else
{
// Don't run P_PostLoadLevel when loading netgames.
levelloading = false;
}
if (rendermode != render_none && reloadinggamestate == false)
{
R_ResetViewInterpolation(0); R_ResetViewInterpolation(0);
R_ResetViewInterpolation(0); R_ResetViewInterpolation(0);
R_UpdateMobjInterpolators(); R_UpdateMobjInterpolators();
@ -8054,19 +8067,30 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
G_StartTitleCard(); G_StartTitleCard();
// Can the title card actually run, though? // Can the title card actually run, though?
if (!WipeStageTitle) if (WipeStageTitle && ranspecialwipe != 2 && fromnetsave == false)
return true; {
if (ranspecialwipe == 2)
return true;
// If so...
// but not if joining because the fade may time us out
if (!fromnetsave)
G_PreLevelTitleCard(); G_PreLevelTitleCard();
}
}
return true; return true;
} }
void P_PostLoadLevel(void)
{
K_TimerInit();
P_RunCachedActions();
if (marathonmode & MA_INGAME)
{
marathonmode &= ~MA_INIT;
}
// We're now done loading the level.
levelloading = false;
}
// //
// P_RunSOC // P_RunSOC
// //

View file

@ -103,6 +103,7 @@ extern mapthing_t *mapthings;
void P_SetupLevelSky(const char *skytexname, boolean global); void P_SetupLevelSky(const char *skytexname, boolean global);
void P_RespawnThings(void); void P_RespawnThings(void);
boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate); boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate);
void P_PostLoadLevel(void);
#ifdef HWRENDER #ifdef HWRENDER
void HWR_LoadLevel(void); void HWR_LoadLevel(void);
#endif #endif

View file

@ -959,86 +959,9 @@ void P_Ticker(boolean run)
if (demo.playback) if (demo.playback)
G_StoreRewindInfo(); G_StoreRewindInfo();
if (leveltime == 2)
{
// The values needed to set this properly are not correct at map load,
// so we have to do it at the second tick instead...
K_TimerInit();
}
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
{ {
G_CopyTiccmd(&players[i].oldcmd, &players[i].cmd, 1); G_CopyTiccmd(&players[i].oldcmd, &players[i].cmd, 1);
} }
// Z_CheckMemCleanup(); // Z_CheckMemCleanup();
} }
// Abbreviated ticker for pre-loading, calls thinkers and assorted things
void P_PreTicker(INT32 frames)
{
INT32 i;
ticcmd_t temptic;
for (i = 0; i <= r_splitscreen; i++)
postimgtype[i] = postimg_none;
if (marathonmode & MA_INGAME)
marathonmode |= MA_INIT;
hook_defrosting = frames;
while (hook_defrosting)
{
P_MapStart();
R_UpdateMobjInterpolators();
LUA_HOOK(PreThinkFrame);
K_UpdateAllPlayerPositions();
// OK! Now that we got all of that sorted, players can think!
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo))
{
// stupid fucking cmd hack
// if it isn't for this, players can move in preticker time
// (and disrupt demo recording and other things !!)
memcpy(&temptic, &players[i].cmd, sizeof(ticcmd_t));
memset(&players[i].cmd, 0, sizeof(ticcmd_t));
P_PlayerThink(&players[i]);
memcpy(&players[i].cmd, &temptic, sizeof(ticcmd_t));
}
P_RunThinkers();
// Run any "after all the other thinkers" stuff
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo))
P_PlayerAfterThink(&players[i]);
LUA_HOOK(ThinkFrame);
// Run shield positioning
P_RunOverlays();
P_UpdateSpecials();
P_RespawnSpecials();
LUA_HOOK(PostThinkFrame);
R_UpdateLevelInterpolators();
R_UpdateViewInterpolation();
R_ResetViewInterpolation(0);
P_MapEnd();
hook_defrosting--;
}
if (marathonmode & MA_INGAME)
marathonmode &= ~MA_INIT;
}