4158: Make emoticons smoother r=heinrich5991 a=Jupeyy

It's still not 100% the same as with high bandwidth, but atleast animation wise it should look the same.
The client doesn't predict if an emote actually is triggered, so it still only triggeres them every second tick without high bandwidth.

~Since this changes demo playing quite a bit, it should defs be tested~(not really xd)

fixes #4156

## Checklist

- [ ] Tested the change ingame
- [ ] Provided screenshots if it is a visual change
- [ ] Tested in combination with possibly related configuration options
- [ ] Written a unit test if it works standalone, system.c especially
- [ ] 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: heinrich5991 <heinrich5991@gmail.com>
This commit is contained in:
bors[bot] 2021-09-13 15:51:04 +00:00 committed by GitHub
commit 18eabe0038
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 55 additions and 8 deletions

View file

@ -36,6 +36,7 @@ protected:
int m_CurGameTick[NUM_DUMMIES]; int m_CurGameTick[NUM_DUMMIES];
float m_GameIntraTick[NUM_DUMMIES]; float m_GameIntraTick[NUM_DUMMIES];
float m_GameTickTime[NUM_DUMMIES]; float m_GameTickTime[NUM_DUMMIES];
float m_GameIntraTickSincePrev[NUM_DUMMIES];
int m_PredTick[NUM_DUMMIES]; int m_PredTick[NUM_DUMMIES];
float m_PredIntraTick[NUM_DUMMIES]; float m_PredIntraTick[NUM_DUMMIES];
@ -90,6 +91,7 @@ public:
inline int PredGameTick(int Dummy) const { return m_PredTick[Dummy]; } inline int PredGameTick(int Dummy) const { return m_PredTick[Dummy]; }
inline float IntraGameTick(int Dummy) const { return m_GameIntraTick[Dummy]; } inline float IntraGameTick(int Dummy) const { return m_GameIntraTick[Dummy]; }
inline float PredIntraGameTick(int Dummy) const { return m_PredIntraTick[Dummy]; } inline float PredIntraGameTick(int Dummy) const { return m_PredIntraTick[Dummy]; }
inline float IntraGameTickSincePrev(int Dummy) const { return m_GameIntraTickSincePrev[Dummy]; }
inline float GameTickTime(int Dummy) const { return m_GameTickTime[Dummy]; } inline float GameTickTime(int Dummy) const { return m_GameTickTime[Dummy]; }
inline int GameTickSpeed() const { return m_GameTickSpeed; } inline int GameTickSpeed() const { return m_GameTickSpeed; }

View file

@ -266,7 +266,7 @@ void CSmoothTime::Update(CGraph *pGraph, int64_t Target, int TimeLeft, int Adjus
} }
CClient::CClient() : CClient::CClient() :
m_DemoPlayer(&m_SnapshotDelta) m_DemoPlayer(&m_SnapshotDelta, [&]() { UpdateDemoIntraTimers(); })
{ {
for(auto &DemoRecorder : m_DemoRecorder) for(auto &DemoRecorder : m_DemoRecorder)
DemoRecorder = CDemoRecorder(&m_SnapshotDelta); DemoRecorder = CDemoRecorder(&m_SnapshotDelta);
@ -2654,6 +2654,17 @@ void DemoPlayer()->SetPause(int paused)
demorec_playback_unpause(); demorec_playback_unpause();
}*/ }*/
void CClient::UpdateDemoIntraTimers()
{
// update timers
const CDemoPlayer::CPlaybackInfo *pInfo = m_DemoPlayer.Info();
m_CurGameTick[g_Config.m_ClDummy] = pInfo->m_Info.m_CurrentTick;
m_PrevGameTick[g_Config.m_ClDummy] = pInfo->m_PreviousTick;
m_GameIntraTick[g_Config.m_ClDummy] = pInfo->m_IntraTick;
m_GameTickTime[g_Config.m_ClDummy] = pInfo->m_TickTime;
m_GameIntraTickSincePrev[g_Config.m_ClDummy] = pInfo->m_IntraTickSincePrev;
};
void CClient::Update() void CClient::Update()
{ {
if(State() == IClient::STATE_DEMOPLAYBACK) if(State() == IClient::STATE_DEMOPLAYBACK)
@ -2779,6 +2790,7 @@ void CClient::Update()
m_GameIntraTick[g_Config.m_ClDummy] = (Now - PrevtickStart) / (float)(CurtickStart - PrevtickStart); m_GameIntraTick[g_Config.m_ClDummy] = (Now - PrevtickStart) / (float)(CurtickStart - PrevtickStart);
m_GameTickTime[g_Config.m_ClDummy] = (Now - PrevtickStart) / (float)Freq; //(float)SERVER_TICK_SPEED); m_GameTickTime[g_Config.m_ClDummy] = (Now - PrevtickStart) / (float)Freq; //(float)SERVER_TICK_SPEED);
m_GameIntraTickSincePrev[g_Config.m_ClDummy] = (Now - PrevtickStart) / (float)(Freq / SERVER_TICK_SPEED);
CurtickStart = NewPredTick * time_freq() / 50; CurtickStart = NewPredTick * time_freq() / 50;
PrevtickStart = PrevPredTick * time_freq() / 50; PrevtickStart = PrevPredTick * time_freq() / 50;

View file

@ -279,6 +279,8 @@ class CClient : public IClient, public CDemoPlayer::IListener
IOHANDLE m_BenchmarkFile; IOHANDLE m_BenchmarkFile;
int64_t m_BenchmarkStopTime; int64_t m_BenchmarkStopTime;
void UpdateDemoIntraTimers();
public: public:
IEngine *Engine() { return m_pEngine; } IEngine *Engine() { return m_pEngine; }
IEngineGraphics *Graphics() { return m_pGraphics; } IEngineGraphics *Graphics() { return m_pGraphics; }

View file

@ -403,7 +403,19 @@ void CDemoRecorder::AddDemoMarker()
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "demo_recorder", "Added timeline marker", gs_DemoPrintColor); m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "demo_recorder", "Added timeline marker", gs_DemoPrintColor);
} }
CDemoPlayer::CDemoPlayer(class CSnapshotDelta *pSnapshotDelta, TUpdateIntraTimesFunc &&UpdateIntraTimesFunc)
{
Construct(pSnapshotDelta);
m_UpdateIntraTimesFunc = UpdateIntraTimesFunc;
}
CDemoPlayer::CDemoPlayer(class CSnapshotDelta *pSnapshotDelta) CDemoPlayer::CDemoPlayer(class CSnapshotDelta *pSnapshotDelta)
{
Construct(pSnapshotDelta);
}
void CDemoPlayer::Construct(class CSnapshotDelta *pSnapshotDelta)
{ {
m_File = 0; m_File = 0;
m_pKeyFrames = 0; m_pKeyFrames = 0;
@ -553,6 +565,15 @@ void CDemoPlayer::DoTick()
m_Info.m_Info.m_CurrentTick = m_Info.m_NextTick; m_Info.m_Info.m_CurrentTick = m_Info.m_NextTick;
ChunkTick = m_Info.m_Info.m_CurrentTick; ChunkTick = m_Info.m_Info.m_CurrentTick;
int64_t Freq = time_freq();
int64_t CurtickStart = (m_Info.m_Info.m_CurrentTick) * Freq / SERVER_TICK_SPEED;
int64_t PrevtickStart = (m_Info.m_PreviousTick) * Freq / SERVER_TICK_SPEED;
m_Info.m_IntraTick = (m_Info.m_CurrentTime - PrevtickStart) / (float)(CurtickStart - PrevtickStart);
m_Info.m_IntraTickSincePrev = (m_Info.m_CurrentTime - PrevtickStart) / (float)(Freq / SERVER_TICK_SPEED);
m_Info.m_TickTime = (m_Info.m_CurrentTime - PrevtickStart) / (float)Freq;
if(m_UpdateIntraTimesFunc)
m_UpdateIntraTimesFunc();
while(1) while(1)
{ {
if(ReadChunkHeader(&ChunkType, &ChunkSize, &ChunkTick)) if(ReadChunkHeader(&ChunkType, &ChunkSize, &ChunkTick))
@ -1005,7 +1026,10 @@ int CDemoPlayer::Update(bool RealTime)
int64_t CurtickStart = (m_Info.m_Info.m_CurrentTick) * Freq / SERVER_TICK_SPEED; int64_t CurtickStart = (m_Info.m_Info.m_CurrentTick) * Freq / SERVER_TICK_SPEED;
int64_t PrevtickStart = (m_Info.m_PreviousTick) * Freq / SERVER_TICK_SPEED; int64_t PrevtickStart = (m_Info.m_PreviousTick) * Freq / SERVER_TICK_SPEED;
m_Info.m_IntraTick = (m_Info.m_CurrentTime - PrevtickStart) / (float)(CurtickStart - PrevtickStart); m_Info.m_IntraTick = (m_Info.m_CurrentTime - PrevtickStart) / (float)(CurtickStart - PrevtickStart);
m_Info.m_IntraTickSincePrev = (m_Info.m_CurrentTime - PrevtickStart) / (float)(Freq / SERVER_TICK_SPEED);
m_Info.m_TickTime = (m_Info.m_CurrentTime - PrevtickStart) / (float)Freq; m_Info.m_TickTime = (m_Info.m_CurrentTime - PrevtickStart) / (float)Freq;
if(m_UpdateIntraTimesFunc)
m_UpdateIntraTimesFunc();
} }
if(m_Info.m_Info.m_CurrentTick == m_Info.m_PreviousTick || if(m_Info.m_Info.m_CurrentTick == m_Info.m_PreviousTick ||
@ -1019,10 +1043,8 @@ int CDemoPlayer::Update(bool RealTime)
m_pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "demo_player", aBuf); m_pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "demo_player", aBuf);
} }
} }
m_Time += m_TickTime; m_Time += m_TickTime;
} }
return 0; return 0;
} }

View file

@ -7,9 +7,12 @@
#include <engine/demo.h> #include <engine/demo.h>
#include <engine/shared/protocol.h> #include <engine/shared/protocol.h>
#include <functional>
#include "snapshot.h" #include "snapshot.h"
typedef std::function<void()> TUpdateIntraTimesFunc;
class CDemoRecorder : public IDemoRecorder class CDemoRecorder : public IDemoRecorder
{ {
class IConsole *m_pConsole; class IConsole *m_pConsole;
@ -75,12 +78,15 @@ public:
int m_PreviousTick; int m_PreviousTick;
float m_IntraTick; float m_IntraTick;
float m_IntraTickSincePrev;
float m_TickTime; float m_TickTime;
}; };
private: private:
IListener *m_pListener; IListener *m_pListener;
TUpdateIntraTimesFunc m_UpdateIntraTimesFunc;
// Playback // Playback
struct CKeyFrame struct CKeyFrame
{ {
@ -120,6 +126,9 @@ private:
public: public:
CDemoPlayer(class CSnapshotDelta *pSnapshotDelta); CDemoPlayer(class CSnapshotDelta *pSnapshotDelta);
CDemoPlayer(class CSnapshotDelta *pSnapshotDelta, TUpdateIntraTimesFunc &&UpdateIntraTimesFunc);
void Construct(class CSnapshotDelta *pSnapshotDelta);
void SetListener(IListener *pListener); void SetListener(IListener *pListener);

View file

@ -605,10 +605,10 @@ void CPlayers::RenderPlayer(
Graphics()->QuadsSetRotation(0); Graphics()->QuadsSetRotation(0);
} }
if(g_Config.m_ClShowEmotes && !m_pClient->m_aClients[ClientID].m_EmoticonIgnore && m_pClient->m_aClients[ClientID].m_EmoticonStart != -1 && m_pClient->m_aClients[ClientID].m_EmoticonStart <= Client()->GameTick(g_Config.m_ClDummy) && m_pClient->m_aClients[ClientID].m_EmoticonStart + 2 * Client()->GameTickSpeed() > Client()->GameTick(g_Config.m_ClDummy)) if(g_Config.m_ClShowEmotes && !m_pClient->m_aClients[ClientID].m_EmoticonIgnore && m_pClient->m_aClients[ClientID].m_EmoticonStart != -1 && m_pClient->m_aClients[ClientID].m_EmoticonStart <= (double)Client()->GameTick(g_Config.m_ClDummy) + Client()->IntraGameTickSincePrev(g_Config.m_ClDummy) && m_pClient->m_aClients[ClientID].m_EmoticonStart + 2 * Client()->GameTickSpeed() > ((double)Client()->GameTick(g_Config.m_ClDummy) + Client()->IntraGameTickSincePrev(g_Config.m_ClDummy)))
{ {
int SinceStart = Client()->GameTick(g_Config.m_ClDummy) - m_pClient->m_aClients[ClientID].m_EmoticonStart; float SinceStart = (float)((double)Client()->GameTick(g_Config.m_ClDummy) + Client()->IntraGameTickSincePrev(g_Config.m_ClDummy)) - m_pClient->m_aClients[ClientID].m_EmoticonStart;
int FromEnd = m_pClient->m_aClients[ClientID].m_EmoticonStart + 2 * Client()->GameTickSpeed() - Client()->GameTick(g_Config.m_ClDummy); float FromEnd = m_pClient->m_aClients[ClientID].m_EmoticonStart + 2 * Client()->GameTickSpeed() - ((double)Client()->GameTick(g_Config.m_ClDummy) + Client()->IntraGameTickSincePrev(g_Config.m_ClDummy));
float a = 1; float a = 1;

View file

@ -739,7 +739,7 @@ void CGameClient::OnMessage(int MsgId, CUnpacker *pUnpacker, bool IsDummy)
// apply // apply
m_aClients[pMsg->m_ClientID].m_Emoticon = pMsg->m_Emoticon; m_aClients[pMsg->m_ClientID].m_Emoticon = pMsg->m_Emoticon;
m_aClients[pMsg->m_ClientID].m_EmoticonStart = Client()->GameTick(g_Config.m_ClDummy); m_aClients[pMsg->m_ClientID].m_EmoticonStart = (double)Client()->GameTick(g_Config.m_ClDummy) + Client()->IntraGameTickSincePrev(g_Config.m_ClDummy);
} }
else if(MsgId == NETMSGTYPE_SV_SOUNDGLOBAL) else if(MsgId == NETMSGTYPE_SV_SOUNDGLOBAL)
{ {

View file

@ -334,7 +334,7 @@ public:
int m_SkinColor; int m_SkinColor;
int m_Team; int m_Team;
int m_Emoticon; int m_Emoticon;
int m_EmoticonStart; double m_EmoticonStart;
bool m_Solo; bool m_Solo;
bool m_Jetpack; bool m_Jetpack;
bool m_NoCollision; bool m_NoCollision;