mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 01:58:19 +00:00
6226: Remove projectiles on save and load r=def- a=Zwelf Restructured CSaveTeam a bit, because I also needed access to CGameWorld. I don't store pointer to IGameController in CSaveTeam anymore, because we pass CSaveTeam to the database thread. If it would be accessed there, it could cause a race conditions. ## 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 - [x] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional) 6230: For integrated and discrete GPUs always prefer what comes first in the list r=def- a=Jupeyy fixes #6200 ## 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 (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: Zwelf <zwelf@strct.cc> Co-authored-by: Jupeyy <jupjopjap@gmail.com>
This commit is contained in:
commit
c7192d703e
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -50,6 +50,8 @@ private:
|
|||
public:
|
||||
void SetBouncing(int Value);
|
||||
bool FillExtraInfo(CNetObj_DDNetProjectile *pProj);
|
||||
|
||||
virtual int GetOwnerID() const override { return m_Owner; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <cstdio>
|
||||
|
||||
#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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<CScoreSaveResult>(ClientID, pController);
|
||||
auto SaveResult = std::make_shared<CScoreSaveResult>(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<CScoreSaveResult>(ClientID, pController);
|
||||
auto SaveResult = std::make_shared<CScoreSaveResult>(ClientID);
|
||||
SaveResult->m_Status = CScoreSaveResult::LOAD_FAILED;
|
||||
pController->m_Teams.SetSaving(Team, SaveResult);
|
||||
auto Tmp = std::make_unique<CSqlTeamLoad>(SaveResult);
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue