diff --git a/datasrc/network.py b/datasrc/network.py index bbd436f8..c6780fca 100644 --- a/datasrc/network.py +++ b/datasrc/network.py @@ -20,6 +20,7 @@ "GAME_PAUSED"]) # todo 0.8: sort (1 para) +GamePredictionFlags = Flags("GAMEPREDICTIONFLAG", ["EVENT", "INPUT"]) RawHeader = ''' @@ -82,6 +83,7 @@ GameStateFlags, CoreEventFlags, RaceFlags, + GamePredictionFlags, ] Objects = [ @@ -269,6 +271,10 @@ NetIntRange("m_Precision", 0, 3), NetFlag("m_RaceFlags", RaceFlags), ]), + + NetObjectEx("GameDataPrediction", "game-data-prediction@netobj.teeworlds.wiki", [ + NetFlag("m_PredictionFlags", GamePredictionFlags), + ]) ] Messages = [ diff --git a/src/engine/shared/snapshot.cpp b/src/engine/shared/snapshot.cpp index d4b88ff0..3559ce5f 100644 --- a/src/engine/shared/snapshot.cpp +++ b/src/engine/shared/snapshot.cpp @@ -707,6 +707,7 @@ int CSnapshotBuilder::GetExtendedItemTypeIndex(int TypeID) } dbg_assert(m_NumExtendedItemTypes < MAX_EXTENDED_ITEM_TYPES, "too many extended item types"); int Index = m_NumExtendedItemTypes; + m_NumExtendedItemTypes++; m_aExtendedItemTypes[Index] = TypeID; if(AddExtendedItemType(Index)) { diff --git a/src/game/client/gameclient.cpp b/src/game/client/gameclient.cpp index f6013a96..a93fe98e 100644 --- a/src/game/client/gameclient.cpp +++ b/src/game/client/gameclient.cpp @@ -1295,7 +1295,6 @@ void CGameClient::OnNewSnapshot() // limit evolving to 3 seconds int EvolvePrevTick = minimum(pCharInfo->m_Prev.m_Tick + Client()->GameTickSpeed() * 3, Client()->PrevGameTick()); - int EvolveCurTick = minimum(pCharInfo->m_Cur.m_Tick + Client()->GameTickSpeed() * 3, Client()->GameTick()); // reuse the evolved char if(m_aClients[Item.m_ID].m_Evolved.m_Tick == EvolvePrevTick) @@ -1304,17 +1303,7 @@ void CGameClient::OnNewSnapshot() if(mem_comp(pData, pOld, sizeof(CNetObj_Character)) == 0) pCharInfo->m_Cur = m_aClients[Item.m_ID].m_Evolved; } - - if(pCharInfo->m_Prev.m_Tick) - EvolveCharacter(&pCharInfo->m_Prev, EvolvePrevTick); - if(pCharInfo->m_Cur.m_Tick) - EvolveCharacter(&pCharInfo->m_Cur, EvolveCurTick); - - m_aClients[Item.m_ID].m_Evolved = m_Snap.m_aCharacters[Item.m_ID].m_Cur; } - - if(Item.m_ID != m_LocalClientID || !Config()->m_ClPredict || Client()->State() == IClient::STATE_DEMOPLAYBACK) - ProcessTriggeredEvents(pCharInfo->m_Cur.m_TriggeredEvents, vec2(pCharInfo->m_Cur.m_X, pCharInfo->m_Cur.m_Y)); } } else if(Item.m_Type == NETOBJTYPE_SPECTATORINFO) @@ -1370,6 +1359,10 @@ void CGameClient::OnNewSnapshot() { m_Snap.m_pGameDataRace = (const CNetObj_GameDataRace *) pData; } + else if(Item.m_Type == NETOBJTYPE_GAMEDATAPREDICTION) + { + m_Snap.m_pGameDataPrediction = (const CNetObj_GameDataPrediction *) pData; + } else if(Item.m_Type == NETOBJTYPE_FLAG) { m_Snap.m_apFlags[Item.m_ID % 2] = (const CNetObj_Flag *) pData; @@ -1437,9 +1430,23 @@ void CGameClient::OnNewSnapshot() } } - // calc some player stats + // calc some player stats, also trigger events for(int i = 0; i < MAX_CLIENTS; ++i) { + if(m_Snap.m_aCharacters[i].m_Active) + { + int EvolvePrevTick = minimum(m_Snap.m_aCharacters[i].m_Prev.m_Tick + Client()->GameTickSpeed() * 3, Client()->PrevGameTick()); + int EvolveCurTick = minimum(m_Snap.m_aCharacters[i].m_Cur.m_Tick + Client()->GameTickSpeed() * 3, Client()->GameTick()); + if(m_Snap.m_aCharacters[i].m_Prev.m_Tick) + EvolveCharacter(&m_Snap.m_aCharacters[i].m_Prev, EvolvePrevTick); + if(m_Snap.m_aCharacters[i].m_Cur.m_Tick) + EvolveCharacter(&m_Snap.m_aCharacters[i].m_Cur, EvolveCurTick); + + m_aClients[i].m_Evolved = m_Snap.m_aCharacters[i].m_Cur; + if(i != m_LocalClientID || !Config()->m_ClPredict || Client()->State() == IClient::STATE_DEMOPLAYBACK || !GameDataPredictInput() || !GameDataPredictEvent()) + ProcessTriggeredEvents(m_Snap.m_aCharacters[i].m_Cur.m_TriggeredEvents, vec2(m_Snap.m_aCharacters[i].m_Cur.m_X, m_Snap.m_aCharacters[i].m_Cur.m_Y)); + } + if(!m_Snap.m_apPlayerInfos[i]) continue; @@ -1581,7 +1588,7 @@ void CGameClient::OnPredict() mem_zero(&World.m_apCharacters[c]->m_Input, sizeof(World.m_apCharacters[c]->m_Input)); - if(m_LocalClientID == c) + if(m_LocalClientID == c && GameDataPredictInput()) { // apply player input const int *pInput = Client()->GetInput(Tick); @@ -1620,7 +1627,7 @@ void CGameClient::OnPredict() // necessary to trigger events for them here. Also, our predictions // for other players will often be wrong, so it's safer not to // trigger events here. - if(m_LocalClientID != -1 && World.m_apCharacters[m_LocalClientID] && Config()->m_ClPredict) + if(m_LocalClientID != -1 && World.m_apCharacters[m_LocalClientID] && Config()->m_ClPredict && GameDataPredictInput() && GameDataPredictEvent()) { ProcessTriggeredEvents( World.m_apCharacters[m_LocalClientID]->m_TriggeredEvents, diff --git a/src/game/client/gameclient.h b/src/game/client/gameclient.h index 30be168a..eea47326 100644 --- a/src/game/client/gameclient.h +++ b/src/game/client/gameclient.h @@ -159,6 +159,7 @@ class CGameClient : public IGameClient const CNetObj_GameDataTeam *m_pGameDataTeam; const CNetObj_GameDataFlag *m_pGameDataFlag; const CNetObj_GameDataRace *m_pGameDataRace; + const CNetObj_GameDataPrediction *m_pGameDataPrediction; int m_GameDataFlagSnapID; int m_NotReadyCount; @@ -309,6 +310,10 @@ class CGameClient : public IGameClient int GetClientID(const char *pName); + // ----- gamedata prediction helper ----- + bool GameDataPredictInput() { return !m_Snap.m_pGameDataPrediction || m_Snap.m_pGameDataPrediction->m_PredictionFlags & GAMEPREDICTIONFLAG_INPUT; } + bool GameDataPredictEvent() { return !m_Snap.m_pGameDataPrediction || m_Snap.m_pGameDataPrediction->m_PredictionFlags & GAMEPREDICTIONFLAG_EVENT; } + // ----- send functions ----- // TODO: move these void SendSwitchTeam(int Team); diff --git a/src/game/server/gamecontroller.cpp b/src/game/server/gamecontroller.cpp index d607df04..d358322d 100644 --- a/src/game/server/gamecontroller.cpp +++ b/src/game/server/gamecontroller.cpp @@ -744,6 +744,11 @@ void IGameController::Snap(int SnappingClient) pGameDataTeam->m_TeamscoreBlue = m_aTeamscore[TEAM_BLUE]; } + CNetObj_GameDataPrediction *pGameDataPrediction = static_cast(Server()->SnapNewItem(NETOBJTYPE_GAMEDATAPREDICTION, 0, sizeof(CNetObj_GameDataPrediction))); + if(!pGameDataPrediction) + return; + + pGameDataPrediction->m_PredictionFlags = GAMEPREDICTIONFLAG_EVENT | GAMEPREDICTIONFLAG_INPUT; // demo recording if(SnappingClient == -1) {