6293: rewrite int64_t to bitset for clients mask r=Robyt3 a=0xfaulty

Alternative version for PR [#6292](https://github.com/ddnet/ddnet/pull/6292) with bitset used.
I did the naming as I would like, but I can change it if there is a more suitable one, typedef is just for shortening, can be removed.

## 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: Valentin Bashkirov <v.bashkirov@dev.tassta.com>
Co-authored-by: Valentin Bashkirov <valenteen3d@ya.ru>
This commit is contained in:
bors[bot] 2023-01-31 17:06:49 +00:00 committed by GitHub
commit 9bd43795c8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 70 additions and 68 deletions

View file

@ -3,6 +3,8 @@
#ifndef ENGINE_SHARED_PROTOCOL_H
#define ENGINE_SHARED_PROTOCOL_H
#include <bitset>
/*
Connection diagram - How the initialization works.
@ -123,4 +125,6 @@ enum
VERSION_DDNET_MULTI_LASER = 16040,
};
typedef std::bitset<MAX_CLIENTS> CClientMask;
#endif

View file

@ -101,7 +101,7 @@ void CProjectile::Tick()
{
if(m_Explosive && (!pTargetChr || (!m_Freeze || (m_Type == WEAPON_SHOTGUN && Collide))))
{
GameWorld()->CreateExplosion(ColPos, m_Owner, m_Type, m_Owner == -1, (!pTargetChr ? -1 : pTargetChr->Team()), -1LL);
GameWorld()->CreateExplosion(ColPos, m_Owner, m_Type, m_Owner == -1, (!pTargetChr ? -1 : pTargetChr->Team()), CClientMask().set());
}
else if(m_Freeze)
{
@ -142,7 +142,7 @@ void CProjectile::Tick()
if(m_Owner >= 0)
pOwnerChar = GameWorld()->GetCharacterByID(m_Owner);
GameWorld()->CreateExplosion(ColPos, m_Owner, m_Type, m_Owner == -1, (!pOwnerChar ? -1 : pOwnerChar->Team()), -1LL);
GameWorld()->CreateExplosion(ColPos, m_Owner, m_Type, m_Owner == -1, (!pOwnerChar ? -1 : pOwnerChar->Team()), CClientMask().set());
}
m_MarkedForDestroy = true;
}

View file

@ -336,7 +336,7 @@ CEntity *CGameWorld::GetEntity(int ID, int EntityType)
return 0;
}
void CGameWorld::CreateExplosion(vec2 Pos, int Owner, int Weapon, bool NoDamage, int ActivatedTeam, int64_t Mask)
void CGameWorld::CreateExplosion(vec2 Pos, int Owner, int Weapon, bool NoDamage, int ActivatedTeam, CClientMask Mask)
{
if(Owner < 0 && m_WorldConfig.m_IsSolo && !(Weapon == WEAPON_SHOTGUN && m_WorldConfig.m_IsDDRace))
return;

View file

@ -61,7 +61,7 @@ public:
CCharacter *GetCharacterByID(int ID) { return (ID >= 0 && ID < MAX_CLIENTS) ? m_apCharacters[ID] : nullptr; }
// from gamecontext
void CreateExplosion(vec2 Pos, int Owner, int Weapon, bool NoDamage, int ActivatedTeam, int64_t Mask);
void CreateExplosion(vec2 Pos, int Owner, int Weapon, bool NoDamage, int ActivatedTeam, CClientMask Mask);
// for client side prediction
struct

View file

@ -830,12 +830,12 @@ void CCharacter::TickDeferred()
int Events = m_Core.m_TriggeredEvents;
int CID = m_pPlayer->GetCID();
int64_t TeamMask = Teams()->TeamMask(Team(), -1, CID);
CClientMask TeamMask = Teams()->TeamMask(Team(), -1, CID);
// Some sounds are triggered client-side for the acting player
// so we need to avoid duplicating them
int64_t TeamMaskExceptSelf = Teams()->TeamMask(Team(), CID, CID);
CClientMask TeamMaskExceptSelf = Teams()->TeamMask(Team(), CID, CID);
// Some are triggered client-side but only on Sixup
int64_t TeamMaskExceptSelfIfSixup = Server()->IsSixup(CID) ? TeamMaskExceptSelf : TeamMask;
CClientMask TeamMaskExceptSelfIfSixup = Server()->IsSixup(CID) ? TeamMaskExceptSelf : TeamMask;
if(Events & COREEVENT_GROUND_JUMP)
GameServer()->CreateSound(m_Pos, SOUND_PLAYER_JUMP, TeamMaskExceptSelf);
@ -2322,7 +2322,7 @@ void CCharacter::Rescue()
}
}
int64_t CCharacter::TeamMask()
CClientMask CCharacter::TeamMask()
{
return Teams()->TeamMask(Team(), -1, GetPlayer()->GetCID());
}

View file

@ -85,7 +85,7 @@ public:
bool IsAlive() const { return m_Alive; }
bool IsPaused() const { return m_Paused; }
class CPlayer *GetPlayer() { return m_pPlayer; }
int64_t TeamMask();
CClientMask TeamMask();
private:
// player controlling this character

View file

@ -27,7 +27,7 @@ CLaser::CLaser(CGameWorld *pGameWorld, vec2 Pos, vec2 Direction, float StartEner
m_ZeroEnergyBounceInLastTick = false;
m_TuneZone = GameServer()->Collision()->IsTune(GameServer()->Collision()->GetMapIndex(m_Pos));
CCharacter *pOwnerChar = GameServer()->GetPlayerChar(m_Owner);
m_TeamMask = pOwnerChar ? pOwnerChar->TeamMask() : 0;
m_TeamMask = pOwnerChar ? pOwnerChar->TeamMask() : CClientMask();
m_BelongsToPracticeTeam = pOwnerChar && pOwnerChar->Teams()->IsPractice(pOwnerChar->Team());
GameWorld()->InsertEntity(this);
@ -303,7 +303,7 @@ void CLaser::Snap(int SnappingClient)
return;
pOwnerChar = nullptr;
int64_t TeamMask = -1LL;
CClientMask TeamMask = CClientMask().set();
if(m_Owner >= 0)
pOwnerChar = GameServer()->GetPlayerChar(m_Owner);
@ -311,7 +311,7 @@ void CLaser::Snap(int SnappingClient)
if(pOwnerChar && pOwnerChar->IsAlive())
TeamMask = pOwnerChar->TeamMask();
if(SnappingClient != SERVER_DEMO_CLIENT && !CmaskIsSet(TeamMask, SnappingClient))
if(SnappingClient != SERVER_DEMO_CLIENT && !TeamMask.test(SnappingClient))
return;
if(GameServer()->GetClientVersion(SnappingClient) >= VERSION_DDNET_MULTI_LASER)

View file

@ -31,7 +31,7 @@ private:
int m_Bounces;
int m_EvalTick;
int m_Owner;
int m_TeamMask;
CClientMask m_TeamMask;
bool m_ZeroEnergyBounceInLastTick;
// DDRace

View file

@ -126,7 +126,7 @@ void CProjectile::Tick()
if(m_LifeSpan > -1)
m_LifeSpan--;
int64_t TeamMask = -1LL;
CClientMask TeamMask = CClientMask().set();
bool IsWeaponCollide = false;
if(
pOwnerChar &&
@ -159,9 +159,9 @@ void CProjectile::Tick()
for(int i = 0; i < Number; i++)
{
GameServer()->CreateExplosion(ColPos, m_Owner, m_Type, m_Owner == -1, (!pTargetChr ? -1 : pTargetChr->Team()),
(m_Owner != -1) ? TeamMask : -1LL);
(m_Owner != -1) ? TeamMask : CClientMask().set());
GameServer()->CreateSound(ColPos, m_SoundImpact,
(m_Owner != -1) ? TeamMask : -1LL);
(m_Owner != -1) ? TeamMask : CClientMask().set());
}
}
else if(m_Freeze)
@ -233,7 +233,7 @@ void CProjectile::Tick()
}
else if(m_Type == WEAPON_GUN)
{
GameServer()->CreateDamageInd(CurPos, -atan2(m_Direction.x, m_Direction.y), 10, (m_Owner != -1) ? TeamMask : -1LL);
GameServer()->CreateDamageInd(CurPos, -atan2(m_Direction.x, m_Direction.y), 10, (m_Owner != -1) ? TeamMask : CClientMask().set());
m_MarkedForDestroy = true;
return;
}
@ -253,16 +253,16 @@ void CProjectile::Tick()
if(m_Owner >= 0)
pOwnerChar = GameServer()->GetPlayerChar(m_Owner);
TeamMask = -1LL;
TeamMask = CClientMask().set();
if(pOwnerChar && pOwnerChar->IsAlive())
{
TeamMask = pOwnerChar->TeamMask();
}
GameServer()->CreateExplosion(ColPos, m_Owner, m_Type, m_Owner == -1, (!pOwnerChar ? -1 : pOwnerChar->Team()),
(m_Owner != -1) ? TeamMask : -1LL);
(m_Owner != -1) ? TeamMask : CClientMask().set());
GameServer()->CreateSound(ColPos, m_SoundImpact,
(m_Owner != -1) ? TeamMask : -1LL);
(m_Owner != -1) ? TeamMask : CClientMask().set());
}
m_MarkedForDestroy = true;
return;
@ -326,7 +326,7 @@ void CProjectile::Snap(int SnappingClient)
}
CCharacter *pOwnerChar = 0;
int64_t TeamMask = -1LL;
CClientMask TeamMask = CClientMask().set();
if(m_Owner >= 0)
pOwnerChar = GameServer()->GetPlayerChar(m_Owner);
@ -334,7 +334,7 @@ void CProjectile::Snap(int SnappingClient)
if(pOwnerChar && pOwnerChar->IsAlive())
TeamMask = pOwnerChar->TeamMask();
if(SnappingClient != SERVER_DEMO_CLIENT && m_Owner != -1 && !CmaskIsSet(TeamMask, SnappingClient))
if(SnappingClient != SERVER_DEMO_CLIENT && m_Owner != -1 && !TeamMask.test(SnappingClient))
return;
CNetObj_DDNetProjectile DDNetProjectile;

View file

@ -22,7 +22,7 @@ void CEventHandler::SetGameServer(CGameContext *pGameServer)
m_pGameServer = pGameServer;
}
void *CEventHandler::Create(int Type, int Size, int64_t Mask)
void *CEventHandler::Create(int Type, int Size, CClientMask Mask)
{
if(m_NumEvents == MAX_EVENTS)
return 0;
@ -49,7 +49,7 @@ void CEventHandler::Snap(int SnappingClient)
{
for(int i = 0; i < m_NumEvents; i++)
{
if(SnappingClient == SERVER_DEMO_CLIENT || CmaskIsSet(m_aClientMasks[i], SnappingClient))
if(SnappingClient == SERVER_DEMO_CLIENT || m_aClientMasks[i].test(SnappingClient))
{
CNetEvent_Common *pEvent = (CNetEvent_Common *)&m_aData[m_aOffsets[i]];
if(!NetworkClipped(GameServer(), SnappingClient, vec2(pEvent->m_X, pEvent->m_Y)))

View file

@ -5,6 +5,8 @@
#include <stdint.h>
#include <engine/shared/protocol.h>
class CEventHandler
{
enum
@ -16,7 +18,7 @@ class CEventHandler
int m_aTypes[MAX_EVENTS]; // TODO: remove some of these arrays
int m_aOffsets[MAX_EVENTS];
int m_aSizes[MAX_EVENTS];
int64_t m_aClientMasks[MAX_EVENTS];
CClientMask m_aClientMasks[MAX_EVENTS];
char m_aData[MAX_DATASIZE];
class CGameContext *m_pGameServer;
@ -29,7 +31,7 @@ public:
void SetGameServer(CGameContext *pGameServer);
CEventHandler();
void *Create(int Type, int Size, int64_t Mask = -1LL);
void *Create(int Type, int Size, CClientMask Mask = CClientMask().set());
void Clear();
void Snap(int SnappingClient);

View file

@ -230,7 +230,7 @@ void CGameContext::FillAntibot(CAntibotRoundData *pData)
}
}
void CGameContext::CreateDamageInd(vec2 Pos, float Angle, int Amount, int64_t Mask)
void CGameContext::CreateDamageInd(vec2 Pos, float Angle, int Amount, CClientMask Mask)
{
float a = 3 * pi / 2 + Angle;
//float a = get_angle(dir);
@ -249,7 +249,7 @@ void CGameContext::CreateDamageInd(vec2 Pos, float Angle, int Amount, int64_t Ma
}
}
void CGameContext::CreateHammerHit(vec2 Pos, int64_t Mask)
void CGameContext::CreateHammerHit(vec2 Pos, CClientMask Mask)
{
// create the event
CNetEvent_HammerHit *pEvent = (CNetEvent_HammerHit *)m_Events.Create(NETEVENTTYPE_HAMMERHIT, sizeof(CNetEvent_HammerHit), Mask);
@ -260,7 +260,7 @@ void CGameContext::CreateHammerHit(vec2 Pos, int64_t Mask)
}
}
void CGameContext::CreateExplosion(vec2 Pos, int Owner, int Weapon, bool NoDamage, int ActivatedTeam, int64_t Mask)
void CGameContext::CreateExplosion(vec2 Pos, int Owner, int Weapon, bool NoDamage, int ActivatedTeam, CClientMask Mask)
{
// create the event
CNetEvent_Explosion *pEvent = (CNetEvent_Explosion *)m_Events.Create(NETEVENTTYPE_EXPLOSION, sizeof(CNetEvent_Explosion), Mask);
@ -275,7 +275,7 @@ void CGameContext::CreateExplosion(vec2 Pos, int Owner, int Weapon, bool NoDamag
float Radius = 135.0f;
float InnerRadius = 48.0f;
int Num = m_World.FindEntities(Pos, Radius, apEnts, MAX_CLIENTS, CGameWorld::ENTTYPE_CHARACTER);
int64_t TeamMask = -1;
CClientMask TeamMask = CClientMask().set();
for(int i = 0; i < Num; i++)
{
auto *pChr = static_cast<CCharacter *>(apEnts[i]);
@ -306,9 +306,9 @@ void CGameContext::CreateExplosion(vec2 Pos, int Owner, int Weapon, bool NoDamag
int PlayerTeam = pChr->Team();
if((GetPlayerChar(Owner) ? GetPlayerChar(Owner)->GrenadeHitDisabled() : !g_Config.m_SvHit) || NoDamage)
{
if(!CmaskIsSet(TeamMask, PlayerTeam))
if(!TeamMask.test(PlayerTeam))
continue;
TeamMask = CmaskUnset(TeamMask, PlayerTeam);
TeamMask.reset(PlayerTeam);
}
pChr->TakeDamage(ForceDir * Dmg * 2, (int)Dmg, Owner, Weapon);
@ -316,7 +316,7 @@ void CGameContext::CreateExplosion(vec2 Pos, int Owner, int Weapon, bool NoDamag
}
}
void CGameContext::CreatePlayerSpawn(vec2 Pos, int64_t Mask)
void CGameContext::CreatePlayerSpawn(vec2 Pos, CClientMask Mask)
{
// create the event
CNetEvent_Spawn *pEvent = (CNetEvent_Spawn *)m_Events.Create(NETEVENTTYPE_SPAWN, sizeof(CNetEvent_Spawn), Mask);
@ -327,7 +327,7 @@ void CGameContext::CreatePlayerSpawn(vec2 Pos, int64_t Mask)
}
}
void CGameContext::CreateDeath(vec2 Pos, int ClientID, int64_t Mask)
void CGameContext::CreateDeath(vec2 Pos, int ClientID, CClientMask Mask)
{
// create the event
CNetEvent_Death *pEvent = (CNetEvent_Death *)m_Events.Create(NETEVENTTYPE_DEATH, sizeof(CNetEvent_Death), Mask);
@ -339,7 +339,7 @@ void CGameContext::CreateDeath(vec2 Pos, int ClientID, int64_t Mask)
}
}
void CGameContext::CreateSound(vec2 Pos, int Sound, int64_t Mask)
void CGameContext::CreateSound(vec2 Pos, int Sound, CClientMask Mask)
{
if(Sound < 0)
return;
@ -4172,14 +4172,14 @@ int CGameContext::GetClientVersion(int ClientID) const
return Server()->GetClientVersion(ClientID);
}
int64_t CGameContext::ClientsMaskExcludeClientVersionAndHigher(int Version)
CClientMask CGameContext::ClientsMaskExcludeClientVersionAndHigher(int Version)
{
int64_t Mask = 0;
CClientMask Mask;
for(int i = 0; i < MAX_CLIENTS; ++i)
{
if(GetClientVersion(i) >= Version)
continue;
Mask |= 1LL << i;
Mask.set(i);
}
return Mask;
}

View file

@ -205,12 +205,12 @@ public:
CVoteOptionServer *m_pVoteOptionLast;
// helper functions
void CreateDamageInd(vec2 Pos, float AngleMod, int Amount, int64_t Mask = -1);
void CreateExplosion(vec2 Pos, int Owner, int Weapon, bool NoDamage, int ActivatedTeam, int64_t Mask);
void CreateHammerHit(vec2 Pos, int64_t Mask = -1);
void CreatePlayerSpawn(vec2 Pos, int64_t Mask = -1);
void CreateDeath(vec2 Pos, int ClientID, int64_t Mask = -1);
void CreateSound(vec2 Pos, int Sound, int64_t Mask = -1);
void CreateDamageInd(vec2 Pos, float AngleMod, int Amount, CClientMask Mask = CClientMask().set());
void CreateExplosion(vec2 Pos, int Owner, int Weapon, bool NoDamage, int ActivatedTeam, CClientMask Mask = CClientMask().set());
void CreateHammerHit(vec2 Pos, CClientMask Mask = CClientMask().set());
void CreatePlayerSpawn(vec2 Pos, CClientMask Mask = CClientMask().set());
void CreateDeath(vec2 Pos, int ClientID, CClientMask Mask = CClientMask().set());
void CreateSound(vec2 Pos, int Sound, CClientMask Mask = CClientMask().set());
void CreateSoundGlobal(int Sound, int Target = -1);
enum
@ -296,7 +296,7 @@ public:
int64_t m_NonEmptySince;
int64_t m_LastMapVote;
int GetClientVersion(int ClientID) const;
int64_t ClientsMaskExcludeClientVersionAndHigher(int Version);
CClientMask ClientsMaskExcludeClientVersionAndHigher(int Version);
bool PlayerExists(int ClientID) const override { return m_apPlayers[ClientID]; }
// Returns true if someone is actively moderating.
bool PlayerModerating() const;
@ -316,7 +316,7 @@ private:
bool m_VoteWillPass;
CScore *m_pScore;
//DDRace Console Commands
// DDRace Console Commands
static void ConKillPlayer(IConsole::IResult *pResult, void *pUserData);
@ -503,9 +503,4 @@ public:
void ResetTuning();
};
inline int64_t CmaskAll() { return -1LL; }
inline int64_t CmaskOne(int ClientID) { return 1LL << ClientID; }
inline int64_t CmaskUnset(int64_t Mask, int ClientID) { return Mask ^ CmaskOne(ClientID); }
inline int64_t CmaskAllExceptOne(int ClientID) { return CmaskUnset(CmaskAll(), ClientID); }
inline bool CmaskIsSet(int64_t Mask, int ClientID) { return (Mask & CmaskOne(ClientID)) != 0; }
#endif

View file

@ -721,10 +721,10 @@ int IGameController::ClampTeam(int Team)
return 0;
}
int64_t IGameController::GetMaskForPlayerWorldEvent(int Asker, int ExceptID)
CClientMask IGameController::GetMaskForPlayerWorldEvent(int Asker, int ExceptID)
{
// Send all world events to everyone by default
return CmaskAllExceptOne(ExceptID);
return CClientMask().set().reset(ExceptID);
}
void IGameController::DoTeamChange(CPlayer *pPlayer, int Team, bool DoChatMsg)

View file

@ -5,6 +5,7 @@
#include <base/vmath.h>
#include <engine/map.h>
#include <engine/shared/protocol.h>
#include <vector>
@ -143,7 +144,7 @@ public:
virtual bool CanJoinTeam(int Team, int NotThisID);
int ClampTeam(int Team);
virtual int64_t GetMaskForPlayerWorldEvent(int Asker, int ExceptID = -1);
virtual CClientMask GetMaskForPlayerWorldEvent(int Asker, int ExceptID = -1);
// DDRace

View file

@ -212,10 +212,10 @@ void CGameControllerDDRace::DoTeamChange(class CPlayer *pPlayer, int Team, bool
IGameController::DoTeamChange(pPlayer, Team, DoChatMsg);
}
int64_t CGameControllerDDRace::GetMaskForPlayerWorldEvent(int Asker, int ExceptID)
CClientMask CGameControllerDDRace::GetMaskForPlayerWorldEvent(int Asker, int ExceptID)
{
if(Asker == -1)
return CmaskAllExceptOne(ExceptID);
return CClientMask().set().reset(ExceptID);
return m_Teams.TeamMask(GetPlayerTeam(Asker), ExceptID, Asker);
}

View file

@ -29,7 +29,7 @@ public:
void DoTeamChange(class CPlayer *pPlayer, int Team, bool DoChatMsg = true) override;
int64_t GetMaskForPlayerWorldEvent(int Asker, int ExceptID = -1) override;
CClientMask GetMaskForPlayerWorldEvent(int Asker, int ExceptID = -1) override;
void InitTeleporter();

View file

@ -475,16 +475,16 @@ bool CGameTeams::TeamFinished(int Team)
return true;
}
int64_t CGameTeams::TeamMask(int Team, int ExceptID, int Asker)
CClientMask CGameTeams::TeamMask(int Team, int ExceptID, int Asker)
{
if(Team == TEAM_SUPER)
{
if(ExceptID == -1)
return 0xffffffffffffffff;
return 0xffffffffffffffff & ~(1 << ExceptID);
return CClientMask().set();
return CClientMask().set().reset(ExceptID);
}
int64_t Mask = 0;
CClientMask Mask;
for(int i = 0; i < MAX_CLIENTS; ++i)
{
if(i == ExceptID)
@ -545,7 +545,7 @@ int64_t CGameTeams::TeamMask(int Team, int ExceptID, int Asker)
}
}
Mask |= 1LL << i;
Mask.set(i);
}
return Mask;
}
@ -1093,7 +1093,7 @@ void CGameTeams::SetTeamLock(int Team, bool Lock)
void CGameTeams::ResetInvited(int Team)
{
m_aInvited[Team] = 0;
m_aInvited[Team].reset();
}
void CGameTeams::SetClientInvited(int Team, int ClientID, bool Invited)
@ -1101,9 +1101,9 @@ void CGameTeams::SetClientInvited(int Team, int ClientID, bool Invited)
if(Team > TEAM_FLOCK && Team < TEAM_SUPER)
{
if(Invited)
m_aInvited[Team] |= 1ULL << ClientID;
m_aInvited[Team].set(ClientID);
else
m_aInvited[Team] &= ~(1ULL << ClientID);
m_aInvited[Team].reset(ClientID);
}
}

View file

@ -25,7 +25,7 @@ class CGameTeams
int m_aTeamState[NUM_TEAMS];
bool m_aTeamLocked[NUM_TEAMS];
uint64_t m_aInvited[NUM_TEAMS];
CClientMask m_aInvited[NUM_TEAMS];
bool m_aPractice[NUM_TEAMS];
std::shared_ptr<CScoreSaveResult> m_apSaveTeamResult[NUM_TEAMS];
uint64_t m_aLastSwap[MAX_CLIENTS]; // index is id of player who initiated swap
@ -96,7 +96,7 @@ public:
void ChangeTeamState(int Team, int State);
int64_t TeamMask(int Team, int ExceptID = -1, int Asker = -1);
CClientMask TeamMask(int Team, int ExceptID = -1, int Asker = -1);
int Count(int Team) const;
@ -151,7 +151,7 @@ public:
bool IsInvited(int Team, int ClientID)
{
return m_aInvited[Team] & 1LL << ClientID;
return m_aInvited[Team].test(ClientID);
}
bool IsStarted(int Team)