5787: Allow spectator mode to be changed while demo is paused r=def- a=Robyt3

By updating and rendering the current tick again when changing the spectator mode while the demo playback is paused. Closes #1843.

Refactoring: Extract `IDemoPlayer::ETickOffset`, `IDemoPlayer::SeekTick` and `CMenus::DemoSeekTick`.

## Checklist

- [X] Tested the change ingame
- [ ] Provided screenshots if it is a visual change
- [ ] Tested in combination with possibly related configuration options
- [ ] Written a unit test (especially base/) or added coverage to integration test
- [ ] Considered possible null pointers and out of bounds array indexing
- [ ] Changed no physics that affect existing maps
- [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional)


Co-authored-by: Robert Müller <robytemueller@gmail.com>
This commit is contained in:
bors[bot] 2022-08-28 18:01:55 +00:00 committed by GitHub
commit 3e42d3df5a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 29 additions and 6 deletions

View file

@ -75,11 +75,19 @@ public:
DEMOTYPE_SERVER,
};
enum ETickOffset
{
TICK_CURRENT = 1, // update the current tick again
TICK_PREVIOUS = 0, // go to the previous tick
TICK_NEXT = 3, // go to the next tick
};
~IDemoPlayer() {}
virtual void SetSpeed(float Speed) = 0;
virtual void SetSpeedIndex(int Offset) = 0;
virtual int SeekPercent(float Percent) = 0;
virtual int SeekTime(float Seconds) = 0;
virtual int SeekTick(ETickOffset TickOffset) = 0;
virtual int SetPos(int WantedTick) = 0;
virtual void Pause() = 0;
virtual void Unpause() = 0;

View file

@ -934,6 +934,11 @@ int CDemoPlayer::SeekTime(float Seconds)
return SetPos(WantedTick);
}
int CDemoPlayer::SeekTick(ETickOffset TickOffset)
{
return SetPos(m_Info.m_Info.m_CurrentTick + (int)TickOffset);
}
int CDemoPlayer::SetPos(int WantedTick)
{
if(!m_File)

View file

@ -139,6 +139,7 @@ public:
void SetSpeedIndex(int Offset) override;
int SeekPercent(float Percent) override;
int SeekTime(float Seconds) override;
int SeekTick(ETickOffset TickOffset) override;
int SetPos(int WantedTick) override;
const CInfo *BaseInfo() const override { return &m_Info.m_Info; }
void GetDemoName(char *pBuffer, int BufferSize) const override;

View file

@ -633,6 +633,7 @@ public:
int DoButton_CheckBox_Tristate(const void *pID, const char *pText, TRISTATE Checked, const CUIRect *pRect);
std::vector<CDemoItem> m_vDemos;
void DemolistPopulate();
void DemoSeekTick(IDemoPlayer::ETickOffset TickOffset);
bool m_Dummy;
const char *GetCurrentDemoFolder() const { return m_aCurrentDemoFolder; }

View file

@ -94,6 +94,16 @@ void CMenus::HandleDemoSeeking(float PositionToSeek, float TimeToSeek)
}
}
void CMenus::DemoSeekTick(IDemoPlayer::ETickOffset TickOffset)
{
m_pClient->m_SuppressEvents = true;
DemoPlayer()->SeekTick(TickOffset);
m_pClient->m_SuppressEvents = false;
DemoPlayer()->Pause();
m_pClient->m_MapLayersBackGround.EnvelopeUpdate();
m_pClient->m_MapLayersForeGround.EnvelopeUpdate();
}
void CMenus::RenderDemoPlayer(CUIRect MainView)
{
const IDemoPlayer::CInfo *pInfo = DemoPlayer()->BaseInfo();
@ -270,12 +280,7 @@ void CMenus::RenderDemoPlayer(CUIRect MainView)
const bool TickBackwards = Input()->KeyPress(KEY_COMMA);
if(TickForwards || TickBackwards)
{
m_pClient->m_SuppressEvents = true;
DemoPlayer()->SetPos(pInfo->m_CurrentTick + (TickForwards ? 3 : 0));
m_pClient->m_SuppressEvents = false;
DemoPlayer()->Pause();
m_pClient->m_MapLayersBackGround.EnvelopeUpdate();
m_pClient->m_MapLayersForeGround.EnvelopeUpdate();
DemoSeekTick(TickForwards ? IDemoPlayer::TICK_NEXT : IDemoPlayer::TICK_PREVIOUS);
}
}

View file

@ -424,6 +424,9 @@ void CSpectator::Spectate(int SpectatorID)
if(Client()->State() == IClient::STATE_DEMOPLAYBACK)
{
m_pClient->m_DemoSpecID = clamp(SpectatorID, (int)SPEC_FOLLOW, MAX_CLIENTS - 1);
// The tick must be rendered for the spectator mode to be updated, so we do it manually when demo playback is paused
if(DemoPlayer()->BaseInfo()->m_Paused)
GameClient()->m_Menus.DemoSeekTick(IDemoPlayer::TICK_CURRENT);
return;
}