Replay playback changes:

- Store level state periodically
- Load the closest usable level state when done rewinding for
  quicker resumes
- Make playback menu fade out after 5 seconds of no activity
  (but not while paused)
- Remove wrapping from replay hut (original wrapping was broken
  at some point before 1.1 and it's not necessary anyway)
- Allow holding enter on frame advance for noisy slow-mo

from fickleheart
This commit is contained in:
TehRealSalt 2019-10-28 12:14:51 -04:00 committed by Latapostrophe
parent eb8cb12b8f
commit 190b0d4660
4 changed files with 129 additions and 16 deletions

View File

@ -5567,3 +5567,61 @@ tic_t GetLag(INT32 node)
{
return gametic - nettics[node];
}
#define REWIND_POINT_INTERVAL 4*TICRATE + 16
rewind_t *rewindhead;
void CL_ClearRewinds(void)
{
rewind_t *head;
while ((head = rewindhead))
{
rewindhead = rewindhead->next;
free(head);
}
}
rewind_t *CL_SaveRewindPoint(size_t demopos)
{
rewind_t *rewind;
if (rewindhead && rewindhead->leveltime + REWIND_POINT_INTERVAL > leveltime)
return NULL;
rewind = (rewind_t *)malloc(sizeof (rewind_t));
if (!rewind)
return NULL;
CONS_Printf("Saving rewind point for time %d\n", leveltime);
save_p = rewind->savebuffer;
P_SaveNetGame();
rewind->leveltime = leveltime;
rewind->next = rewindhead;
rewind->demopos = demopos;
rewindhead = rewind;
return rewind;
}
rewind_t *CL_RewindToTime(tic_t time)
{
rewind_t *rewind;
while (rewindhead && rewindhead->leveltime > time)
{
rewind = rewindhead->next;
free(rewindhead);
rewindhead = rewind;
}
if (!rewindhead)
return NULL;
CONS_Printf("Restoring rewind to time %d for goal time %d\n", rewindhead->leveltime, time);
save_p = rewindhead->savebuffer;
P_LoadNetGame();
wipegamestate = gamestate; // No fading back in!
timeinmap = leveltime;
return rewindhead;
}

View File

@ -604,4 +604,19 @@ UINT8 GetFreeXCmdSize(void);
extern UINT8 hu_resynching;
extern UINT8 hu_stopped; // kart, true when the game is stopped for players due to a disconnecting or connecting player
typedef struct rewind_s {
UINT8 savebuffer[(768*1024)];
tic_t leveltime;
size_t demopos;
ticcmd_t oldcmd[MAXPLAYERS];
mobj_t oldghost[MAXPLAYERS];
struct rewind_s *next;
} rewind_t;
void CL_ClearRewinds(void);
rewind_t *CL_SaveRewindPoint(size_t demopos);
rewind_t *CL_RewindToTime(tic_t time);
#endif

View File

@ -4863,6 +4863,16 @@ void G_ReadDemoExtraData(void)
INT32 p, extradata, i;
char name[17];
if (leveltime > starttime)
{
rewind_t *rewind = CL_SaveRewindPoint(demo_p - demobuffer);
if (rewind)
{
memcpy(rewind->oldcmd, oldcmd, sizeof (oldcmd));
memcpy(rewind->oldghost, oldghost, sizeof (oldghost));
}
}
memset(name, '\0', 17);
p = READUINT8(demo_p);
@ -5901,6 +5911,8 @@ static rewindinfo_t *rewindhead = NULL; // Reverse chronological order
void G_InitDemoRewind(void)
{
CL_ClearRewinds();
while (rewindhead)
{
rewindinfo_t *p = rewindhead->prev;
@ -6022,19 +6034,35 @@ void G_ConfirmRewind(tic_t rewindtime)
CV_StealthSetValue(&cv_renderview, 0);
if (rewindtime > starttime)
if (rewindtime <= starttime)
{
sound_disabled = true; // Prevent sound spam
demo.rewinding = true;
demo.rewinding = false;
G_DoPlayDemo(NULL); // Restart the current demo
}
else
demo.rewinding = false;
{
rewind_t *rewind;
sound_disabled = true; // Prevent sound spam
demo.rewinding = true;
G_DoPlayDemo(NULL); // Restart the current demo
rewind = CL_RewindToTime(rewindtime);
if (rewind)
{
demo_p = demobuffer + rewind->demopos;
memcpy(oldcmd, rewind->oldcmd, sizeof (oldcmd));
memcpy(oldghost, rewind->oldghost, sizeof (oldghost));
paused = false;
}
else
{
demo.rewinding = true;
G_DoPlayDemo(NULL); // Restart the current demo
}
}
for (j = 0; j < rewindtime && leveltime < rewindtime; j++)
{
//TryRunTics(1);
G_Ticker((j % NEWTICRATERATIO) == 0);
}
@ -8093,6 +8121,7 @@ void G_StopDemo(void)
CV_SetValue(&cv_playbackspeed, 1);
demo.rewinding = false;
CL_ClearRewinds();
if (gamestate == GS_LEVEL && rendermode != render_none)
{

View File

@ -516,6 +516,7 @@ static menuitem_t MISC_ReplayOptionsMenu[] =
{IT_CVAR|IT_STRING, NULL, "Sync Check Interval", &cv_netdemosyncquality, 10},
};
static tic_t playback_last_menu_interaction_leveltime = 0;
static menuitem_t PlaybackMenu[] =
{
{IT_CALL | IT_STRING, "M_PHIDE", "Hide Menu", M_SelectableClearMenus, 0},
@ -2785,6 +2786,7 @@ boolean M_Responder(event_t *ev)
if (currentMenu == &PlaybackMenuDef)
{
playback_last_menu_interaction_leveltime = leveltime;
// Flip left/right with up/down for the playback menu, since it's a horizontal icon row.
switch (ch)
{
@ -2846,9 +2848,9 @@ boolean M_Responder(event_t *ev)
if (currentMenu == &PlaybackMenuDef)
{
boolean held = (boolean)playback_enterheld;
playback_enterheld = TICRATE/7;
if (held)
return true;
playback_enterheld = 3;
}
if (routine)
@ -3021,6 +3023,7 @@ void M_StartControlPanel(void)
if (demo.playback)
{
currentMenu = &PlaybackMenuDef;
playback_last_menu_interaction_leveltime = leveltime;
}
else if (!Playing())
{
@ -5193,6 +5196,7 @@ void M_ReplayHut(INT32 choice)
G_SetGamestate(GS_TIMEATTACK);
demo.rewinding = false;
CL_ClearRewinds();
S_ChangeMusicInternal("replst", true);
}
@ -5205,7 +5209,8 @@ static void M_HandleReplayHutList(INT32 choice)
if (dir_on[menudepthleft])
dir_on[menudepthleft]--;
else
M_PrevOpt();
return;
//M_PrevOpt();
S_StartSound(NULL, sfx_menu1);
replayScrollTitle = 0; replayScrollDelay = TICRATE; replayScrollDir = 1;
@ -5215,7 +5220,8 @@ static void M_HandleReplayHutList(INT32 choice)
if (dir_on[menudepthleft] < sizedirmenu-1)
dir_on[menudepthleft]++;
else
itemOn = 0; // Not M_NextOpt because that would take us to the extra dummy item
return;
//itemOn = 0; // Not M_NextOpt because that would take us to the extra dummy item
S_StartSound(NULL, sfx_menu1);
replayScrollTitle = 0; replayScrollDelay = TICRATE; replayScrollDir = 1;
@ -5722,6 +5728,11 @@ static void M_DrawPlaybackMenu(void)
INT16 i;
patch_t *icon;
UINT8 *activemap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_GOLD, GTC_MENUCACHE);
UINT32 transmap = max(0, (INT32)(leveltime - playback_last_menu_interaction_leveltime - 4*TICRATE)) / 5;
transmap = min(8, transmap) << V_ALPHASHIFT;
if (leveltime - playback_last_menu_interaction_leveltime >= 6*TICRATE)
playback_last_menu_interaction_leveltime = leveltime - 6*TICRATE;
// Toggle items
if (paused && !demo.rewinding)
@ -5803,16 +5814,16 @@ static void M_DrawPlaybackMenu(void)
icon = W_CachePatchName("PLAYRANK", PU_CACHE); // temp
if ((i == playback_fastforward && cv_playbackspeed.value > 1) || (i == playback_rewind && demo.rewinding))
V_DrawMappedPatch(currentMenu->x + currentMenu->menuitems[i].alphaKey, currentMenu->y, V_SNAPTOTOP, icon, R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_JAWZ, GTC_MENUCACHE));
V_DrawMappedPatch(currentMenu->x + currentMenu->menuitems[i].alphaKey, currentMenu->y, transmap|V_SNAPTOTOP, icon, R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_JAWZ, GTC_MENUCACHE));
else
V_DrawMappedPatch(currentMenu->x + currentMenu->menuitems[i].alphaKey, currentMenu->y, V_SNAPTOTOP, icon, (i == itemOn) ? activemap : inactivemap);
V_DrawMappedPatch(currentMenu->x + currentMenu->menuitems[i].alphaKey, currentMenu->y, transmap|V_SNAPTOTOP, icon, (i == itemOn) ? activemap : inactivemap);
if (i == itemOn)
{
V_DrawCharacter(currentMenu->x + currentMenu->menuitems[i].alphaKey + 4, currentMenu->y + 14,
'\x1A' | V_SNAPTOTOP|highlightflags, false);
'\x1A' | transmap|V_SNAPTOTOP|highlightflags, false);
V_DrawCenteredString(BASEVIDWIDTH/2, currentMenu->y + 18, V_SNAPTOTOP|V_ALLOWLOWERCASE, currentMenu->menuitems[i].text);
V_DrawCenteredString(BASEVIDWIDTH/2, currentMenu->y + 18, transmap|V_SNAPTOTOP|V_ALLOWLOWERCASE, currentMenu->menuitems[i].text);
if ((currentMenu->menuitems[i].status & IT_TYPE) == IT_ARROWS)
{
@ -5820,11 +5831,11 @@ static void M_DrawPlaybackMenu(void)
if (!(i == playback_viewcount && splitscreen == 3))
V_DrawCharacter(BASEVIDWIDTH/2 - 4, currentMenu->y + 28 - (skullAnimCounter/5),
'\x1A' | V_SNAPTOTOP|highlightflags, false); // up arrow
'\x1A' | transmap|V_SNAPTOTOP|highlightflags, false); // up arrow
if (!(i == playback_viewcount && splitscreen == 0))
V_DrawCharacter(BASEVIDWIDTH/2 - 4, currentMenu->y + 48 + (skullAnimCounter/5),
'\x1B' | V_SNAPTOTOP|highlightflags, false); // down arrow
'\x1B' | transmap|V_SNAPTOTOP|highlightflags, false); // down arrow
switch (i)
{
@ -5843,7 +5854,7 @@ static void M_DrawPlaybackMenu(void)
continue;
}
V_DrawCenteredString(BASEVIDWIDTH/2, currentMenu->y + 38, V_SNAPTOTOP|V_ALLOWLOWERCASE|highlightflags, str);
V_DrawCenteredString(BASEVIDWIDTH/2, currentMenu->y + 38, transmap|V_SNAPTOTOP|V_ALLOWLOWERCASE|highlightflags, str);
}
}
}