diff --git a/src/engine/client/backend/vulkan/backend_vulkan.cpp b/src/engine/client/backend/vulkan/backend_vulkan.cpp index 8e95fb772..1ecf46d41 100644 --- a/src/engine/client/backend/vulkan/backend_vulkan.cpp +++ b/src/engine/client/backend/vulkan/backend_vulkan.cpp @@ -3753,7 +3753,7 @@ public: AutoGPUType = GPUType; } - if(((IsAutoGPU && GPUType < FoundGPUType) || str_comp(DeviceProp.deviceName, g_Config.m_GfxGPUName) == 0) && (DevAPIMajor > gs_BackendVulkanMajor || (DevAPIMajor == gs_BackendVulkanMajor && DevAPIMinor >= gs_BackendVulkanMinor))) + if(((IsAutoGPU && (FoundGPUType > STWGraphicGPU::ETWGraphicsGPUType::GRAPHICS_GPU_TYPE_INTEGRATED && GPUType < FoundGPUType)) || str_comp(DeviceProp.deviceName, g_Config.m_GfxGPUName) == 0) && (DevAPIMajor > gs_BackendVulkanMajor || (DevAPIMajor == gs_BackendVulkanMajor && DevAPIMinor >= gs_BackendVulkanMinor))) { FoundDeviceIndex = Index; FoundGPUType = GPUType; diff --git a/src/game/server/ddracecommands.cpp b/src/game/server/ddracecommands.cpp index a1f18187b..78a986d5a 100644 --- a/src/game/server/ddracecommands.cpp +++ b/src/game/server/ddracecommands.cpp @@ -801,8 +801,8 @@ void CGameContext::ConDrySave(IConsole::IResult *pResult, void *pUserData) if(!pPlayer || pSelf->Server()->GetAuthedState(pResult->m_ClientID) != AUTHED_ADMIN) return; - CSaveTeam SavedTeam(pSelf->m_pController); - int Result = SavedTeam.Save(pPlayer->GetTeam()); + CSaveTeam SavedTeam; + int Result = SavedTeam.Save(pSelf, pPlayer->GetTeam(), true); if(CSaveTeam::HandleSaveError(Result, pResult->m_ClientID, pSelf)) return; diff --git a/src/game/server/entities/laser.h b/src/game/server/entities/laser.h index f606e0b1d..19a8ea1e3 100644 --- a/src/game/server/entities/laser.h +++ b/src/game/server/entities/laser.h @@ -16,6 +16,8 @@ public: virtual void Snap(int SnappingClient) override; virtual void SwapClients(int Client1, int Client2) override; + virtual int GetOwnerID() const override { return m_Owner; } + protected: bool HitCharacter(vec2 From, vec2 To); void DoBounce(); diff --git a/src/game/server/entities/projectile.h b/src/game/server/entities/projectile.h index b3b2d1ca2..70f83865c 100644 --- a/src/game/server/entities/projectile.h +++ b/src/game/server/entities/projectile.h @@ -50,6 +50,8 @@ private: public: void SetBouncing(int Value); bool FillExtraInfo(CNetObj_DDNetProjectile *pProj); + + virtual int GetOwnerID() const override { return m_Owner; } }; #endif diff --git a/src/game/server/entity.h b/src/game/server/entity.h index c897a9073..799fde8f4 100644 --- a/src/game/server/entity.h +++ b/src/game/server/entity.h @@ -128,6 +128,16 @@ public: // TODO: Maybe make protected */ virtual void SwapClients(int Client1, int Client2) {} + /* + Function GetOwnerID + Returns: + ClientID of the initiator from this entity. -1 created by map. + This is used by save/load to remove related entities to the tee. + CCharacter should not return the PlayerId, because they get + handled separatly in save/load code. + */ + virtual int GetOwnerID() const { return -1; } + /* Function: NetworkClipped Performs a series of test to see if a client can see the diff --git a/src/game/server/gameworld.cpp b/src/game/server/gameworld.cpp index 0d6d46fe3..dc2a3251a 100644 --- a/src/game/server/gameworld.cpp +++ b/src/game/server/gameworld.cpp @@ -150,6 +150,26 @@ void CGameWorld::Reset() GameServer()->CreateAllEntities(false); } +void CGameWorld::RemoveEntitiesFromPlayers(int PlayerIds[], int NumPlayers) +{ + for(auto *pEnt : m_apFirstEntityTypes) + { + for(; pEnt;) + { + m_pNextTraverseEntity = pEnt->m_pNextTypeEntity; + for(int i = 0; i < NumPlayers; i++) + { + if(pEnt->GetOwnerID() == PlayerIds[i]) + { + RemoveEntity(pEnt); + pEnt->Destroy(); + } + } + pEnt = m_pNextTraverseEntity; + } + } +} + void CGameWorld::RemoveEntities() { // destroy objects marked for destruction diff --git a/src/game/server/gameworld.h b/src/game/server/gameworld.h index 510f640af..41b451873 100644 --- a/src/game/server/gameworld.h +++ b/src/game/server/gameworld.h @@ -121,6 +121,8 @@ public: */ void RemoveEntity(CEntity *pEntity); + void RemoveEntitiesFromPlayers(int PlayerIds[], int NumPlayers); + /* Function: Snap Calls Snap on all the entities in the world to create diff --git a/src/game/server/save.cpp b/src/game/server/save.cpp index 8967c7cf9..6e6f955d6 100644 --- a/src/game/server/save.cpp +++ b/src/game/server/save.cpp @@ -2,6 +2,7 @@ #include +#include "engine/shared/protocol.h" #include "entities/character.h" #include "gamemodes/DDRace.h" #include "player.h" @@ -427,11 +428,9 @@ bool CSaveTee::IsHooking() const return m_HookState == HOOK_GRABBED || m_HookState == HOOK_FLYING; } -CSaveTeam::CSaveTeam(IGameController *pController) +CSaveTeam::CSaveTeam() { - m_pController = pController; - m_pSwitchers = 0; - m_pSavedTees = 0; + m_aString[0] = '\0'; } CSaveTeam::~CSaveTeam() @@ -440,62 +439,67 @@ CSaveTeam::~CSaveTeam() delete[] m_pSavedTees; } -int CSaveTeam::Save(int Team) +int CSaveTeam::Save(CGameContext *pGameServer, int Team, bool Dry) { - if(g_Config.m_SvTeam == SV_TEAM_FORCED_SOLO || (Team > 0 && Team < MAX_CLIENTS)) - { - CGameTeams *pTeams = &(((CGameControllerDDRace *)m_pController)->m_Teams); - - m_MembersCount = pTeams->Count(Team); - if(m_MembersCount <= 0) - { - return 2; - } - - m_TeamState = pTeams->GetTeamState(Team); - - if(m_TeamState != CGameTeams::TEAMSTATE_STARTED) - { - return 4; - } - - m_HighestSwitchNumber = m_pController->GameServer()->Collision()->m_HighestSwitchNumber; - m_TeamLocked = pTeams->TeamLocked(Team); - m_Practice = pTeams->IsPractice(Team); - - m_pSavedTees = new CSaveTee[m_MembersCount]; - int j = 0; - CCharacter *p = (CCharacter *)m_pController->GameServer()->m_World.FindFirst(CGameWorld::ENTTYPE_CHARACTER); - for(; p; p = (CCharacter *)p->TypeNext()) - { - if(pTeams->m_Core.Team(p->GetPlayer()->GetCID()) != Team) - continue; - if(m_MembersCount == j) - return 3; - m_pSavedTees[j].Save(p); - j++; - } - if(m_MembersCount != j) - return 3; - - if(m_pController->GameServer()->Collision()->m_HighestSwitchNumber) - { - m_pSwitchers = new SSimpleSwitchers[m_pController->GameServer()->Collision()->m_HighestSwitchNumber + 1]; - - for(int i = 1; i < m_pController->GameServer()->Collision()->m_HighestSwitchNumber + 1; i++) - { - m_pSwitchers[i].m_Status = m_pController->GameServer()->Switchers()[i].m_aStatus[Team]; - if(m_pController->GameServer()->Switchers()[i].m_aEndTick[Team]) - m_pSwitchers[i].m_EndTime = m_pController->Server()->Tick() - m_pController->GameServer()->Switchers()[i].m_aEndTick[Team]; - else - m_pSwitchers[i].m_EndTime = 0; - m_pSwitchers[i].m_Type = m_pController->GameServer()->Switchers()[i].m_aType[Team]; - } - } - return 0; - } - else + if(g_Config.m_SvTeam != SV_TEAM_FORCED_SOLO && (Team <= 0 || MAX_CLIENTS <= Team)) return 1; + + IGameController *pController = pGameServer->m_pController; + CGameTeams *pTeams = &(((CGameControllerDDRace *)pController)->m_Teams); + + m_MembersCount = pTeams->Count(Team); + if(m_MembersCount <= 0) + { + return 2; + } + + m_TeamState = pTeams->GetTeamState(Team); + + if(m_TeamState != CGameTeams::TEAMSTATE_STARTED) + { + return 4; + } + + m_HighestSwitchNumber = pGameServer->Collision()->m_HighestSwitchNumber; + m_TeamLocked = pTeams->TeamLocked(Team); + m_Practice = pTeams->IsPractice(Team); + + m_pSavedTees = new CSaveTee[m_MembersCount]; + int aPlayerCIDs[MAX_CLIENTS]; + int j = 0; + CCharacter *p = (CCharacter *)pGameServer->m_World.FindFirst(CGameWorld::ENTTYPE_CHARACTER); + for(; p; p = (CCharacter *)p->TypeNext()) + { + if(pTeams->m_Core.Team(p->GetPlayer()->GetCID()) != Team) + continue; + if(m_MembersCount == j) + return 3; + m_pSavedTees[j].Save(p); + aPlayerCIDs[j] = p->GetPlayer()->GetCID(); + j++; + } + if(m_MembersCount != j) + return 3; + + if(pGameServer->Collision()->m_HighestSwitchNumber) + { + m_pSwitchers = new SSimpleSwitchers[pGameServer->Collision()->m_HighestSwitchNumber + 1]; + + for(int i = 1; i < pGameServer->Collision()->m_HighestSwitchNumber + 1; i++) + { + m_pSwitchers[i].m_Status = pGameServer->Switchers()[i].m_aStatus[Team]; + if(pGameServer->Switchers()[i].m_aEndTick[Team]) + m_pSwitchers[i].m_EndTime = pController->Server()->Tick() - pGameServer->Switchers()[i].m_aEndTick[Team]; + else + m_pSwitchers[i].m_EndTime = 0; + m_pSwitchers[i].m_Type = pGameServer->Switchers()[i].m_aType[Team]; + } + } + if(!Dry) + { + pGameServer->m_World.RemoveEntitiesFromPlayers(aPlayerCIDs, m_MembersCount); + } + return 0; } bool CSaveTeam::HandleSaveError(int Result, int ClientID, CGameContext *pGameContext) @@ -523,45 +527,50 @@ bool CSaveTeam::HandleSaveError(int Result, int ClientID, CGameContext *pGameCon return true; } -void CSaveTeam::Load(int Team, bool KeepCurrentWeakStrong) +void CSaveTeam::Load(CGameContext *pGameServer, int Team, bool KeepCurrentWeakStrong) { - CGameTeams *pTeams = &(((CGameControllerDDRace *)m_pController)->m_Teams); + IGameController *pController = pGameServer->m_pController; + CGameTeams *pTeams = &(((CGameControllerDDRace *)pController)->m_Teams); pTeams->ChangeTeamState(Team, m_TeamState); pTeams->SetTeamLock(Team, m_TeamLocked); pTeams->SetPractice(Team, m_Practice); + int aPlayerCIDs[MAX_CLIENTS]; for(int i = m_MembersCount; i-- > 0;) { int ClientID = m_pSavedTees[i].GetClientID(); - if(m_pController->GameServer()->m_apPlayers[ClientID] && pTeams->m_Core.Team(ClientID) == Team) + aPlayerCIDs[i] = ClientID; + if(pGameServer->m_apPlayers[ClientID] && pTeams->m_Core.Team(ClientID) == Team) { - CCharacter *pChr = MatchCharacter(m_pSavedTees[i].GetClientID(), i, KeepCurrentWeakStrong); + CCharacter *pChr = MatchCharacter(pGameServer, m_pSavedTees[i].GetClientID(), i, KeepCurrentWeakStrong); m_pSavedTees[i].Load(pChr, Team); } } - if(m_pController->GameServer()->Collision()->m_HighestSwitchNumber) + if(pGameServer->Collision()->m_HighestSwitchNumber) { - for(int i = 1; i < minimum(m_HighestSwitchNumber, m_pController->GameServer()->Collision()->m_HighestSwitchNumber) + 1; i++) + for(int i = 1; i < minimum(m_HighestSwitchNumber, pGameServer->Collision()->m_HighestSwitchNumber) + 1; i++) { - m_pController->GameServer()->Switchers()[i].m_aStatus[Team] = m_pSwitchers[i].m_Status; + pGameServer->Switchers()[i].m_aStatus[Team] = m_pSwitchers[i].m_Status; if(m_pSwitchers[i].m_EndTime) - m_pController->GameServer()->Switchers()[i].m_aEndTick[Team] = m_pController->Server()->Tick() - m_pSwitchers[i].m_EndTime; - m_pController->GameServer()->Switchers()[i].m_aType[Team] = m_pSwitchers[i].m_Type; + pGameServer->Switchers()[i].m_aEndTick[Team] = pController->Server()->Tick() - m_pSwitchers[i].m_EndTime; + pGameServer->Switchers()[i].m_aType[Team] = m_pSwitchers[i].m_Type; } } + // remove projectiles and laser + pGameServer->m_World.RemoveEntitiesFromPlayers(aPlayerCIDs, m_MembersCount); } -CCharacter *CSaveTeam::MatchCharacter(int ClientID, int SaveID, bool KeepCurrentCharacter) +CCharacter *CSaveTeam::MatchCharacter(CGameContext *pGameServer, int ClientID, int SaveID, bool KeepCurrentCharacter) { - if(KeepCurrentCharacter && m_pController->GameServer()->m_apPlayers[ClientID]->GetCharacter()) + if(KeepCurrentCharacter && pGameServer->m_apPlayers[ClientID]->GetCharacter()) { // keep old character to retain current weak/strong order - return m_pController->GameServer()->m_apPlayers[ClientID]->GetCharacter(); + return pGameServer->m_apPlayers[ClientID]->GetCharacter(); } - m_pController->GameServer()->m_apPlayers[ClientID]->KillCharacter(WEAPON_GAME); - return m_pController->GameServer()->m_apPlayers[ClientID]->ForceSpawn(m_pSavedTees[SaveID].GetPos()); + pGameServer->m_apPlayers[ClientID]->KillCharacter(WEAPON_GAME); + return pGameServer->m_apPlayers[ClientID]->ForceSpawn(m_pSavedTees[SaveID].GetPos()); } char *CSaveTeam::GetString() diff --git a/src/game/server/save.h b/src/game/server/save.h index 1aeb189da..f1425cbb2 100644 --- a/src/game/server/save.h +++ b/src/game/server/save.h @@ -8,6 +8,7 @@ class IGameController; class CGameContext; +class CGameWorld; class CCharacter; class CSaveTeam; @@ -123,7 +124,7 @@ private: class CSaveTeam { public: - CSaveTeam(IGameController *pController); + CSaveTeam(); ~CSaveTeam(); char *GetString(); int GetMembersCount() const { return m_MembersCount; } @@ -131,17 +132,16 @@ public: int FromString(const char *pString); // returns true if a team can load, otherwise writes a nice error Message in pMessage bool MatchPlayers(const char (*paNames)[MAX_NAME_LENGTH], const int *pClientID, int NumPlayer, char *pMessage, int MessageLen); - int Save(int Team); - void Load(int Team, bool KeepCurrentWeakStrong); - CSaveTee *m_pSavedTees; + int Save(CGameContext *pGameServer, int Team, bool Dry = false); + void Load(CGameContext *pGameServer, int Team, bool KeepCurrentWeakStrong); + + CSaveTee *m_pSavedTees = nullptr; // returns true if an error occurred static bool HandleSaveError(int Result, int ClientID, CGameContext *pGameContext); private: - CCharacter *MatchCharacter(int ClientID, int SaveID, bool KeepCurrentCharacter); - - IGameController *m_pController; + CCharacter *MatchCharacter(CGameContext *pGameServer, int ClientID, int SaveID, bool KeepCurrentCharacter); char m_aString[65536]; @@ -151,13 +151,13 @@ private: int m_EndTime; int m_Type; }; - SSimpleSwitchers *m_pSwitchers; + SSimpleSwitchers *m_pSwitchers = nullptr; - int m_TeamState; - int m_MembersCount; - int m_HighestSwitchNumber; - int m_TeamLocked; - int m_Practice; + int m_TeamState = 0; + int m_MembersCount = 0; + int m_HighestSwitchNumber = 0; + int m_TeamLocked = 0; + int m_Practice = 0; }; #endif // GAME_SERVER_SAVE_H diff --git a/src/game/server/score.cpp b/src/game/server/score.cpp index 77988a43c..5e88400b4 100644 --- a/src/game/server/score.cpp +++ b/src/game/server/score.cpp @@ -286,9 +286,9 @@ void CScore::SaveTeam(int ClientID, const char *pCode, const char *pServer) if(pController->m_Teams.GetSaving(Team)) return; - auto SaveResult = std::make_shared(ClientID, pController); + auto SaveResult = std::make_shared(ClientID); SaveResult->m_SaveID = RandomUuid(); - int Result = SaveResult->m_SavedTeam.Save(Team); + int Result = SaveResult->m_SavedTeam.Save(GameServer(), Team); if(CSaveTeam::HandleSaveError(Result, ClientID, GameServer())) return; pController->m_Teams.SetSaving(Team, SaveResult); @@ -340,7 +340,7 @@ void CScore::LoadTeam(const char *pCode, int ClientID) GameServer()->SendChatTarget(ClientID, "Team can't be loaded while racing"); return; } - auto SaveResult = std::make_shared(ClientID, pController); + auto SaveResult = std::make_shared(ClientID); SaveResult->m_Status = CScoreSaveResult::LOAD_FAILED; pController->m_Teams.SetSaving(Team, SaveResult); auto Tmp = std::make_unique(SaveResult); diff --git a/src/game/server/scoreworker.h b/src/game/server/scoreworker.h index 54c388c04..16d523f90 100644 --- a/src/game/server/scoreworker.h +++ b/src/game/server/scoreworker.h @@ -149,9 +149,8 @@ struct CSqlScoreData : ISqlData struct CScoreSaveResult : ISqlResult { - CScoreSaveResult(int PlayerID, IGameController *pController) : + CScoreSaveResult(int PlayerID) : m_Status(SAVE_FAILED), - m_SavedTeam(CSaveTeam(pController)), m_RequestingPlayer(PlayerID) { m_aMessage[0] = '\0'; diff --git a/src/game/server/teams.cpp b/src/game/server/teams.cpp index faa47cb4f..73bb2a2e6 100644 --- a/src/game/server/teams.cpp +++ b/src/game/server/teams.cpp @@ -982,7 +982,7 @@ void CGameTeams::ProcessSaveTeam() if(Count(Team) > 0) { // load weak/strong order to prevent switching weak/strong while saving - m_apSaveTeamResult[Team]->m_SavedTeam.Load(Team, false); + m_apSaveTeamResult[Team]->m_SavedTeam.Load(GameServer(), Team, false); } break; case CScoreSaveResult::LOAD_SUCCESS: @@ -997,7 +997,7 @@ void CGameTeams::ProcessSaveTeam() if(Count(Team) > 0) { // keep current weak/strong order as on some maps there is no other way of switching - m_apSaveTeamResult[Team]->m_SavedTeam.Load(Team, true); + m_apSaveTeamResult[Team]->m_SavedTeam.Load(GameServer(), Team, true); } char aSaveID[UUID_MAXSTRSIZE]; FormatUuid(m_apSaveTeamResult[Team]->m_SaveID, aSaveID, UUID_MAXSTRSIZE);