From 8f7e24b4db240161cdb604fcea68e3076bea9aac Mon Sep 17 00:00:00 2001 From: nuborn Date: Tue, 28 Oct 2014 15:50:28 +0100 Subject: [PATCH] Revert "Revert "Add antiping for weapons (by nuborn)"" This reverts commit 755e9f4d1c2a8eda489ef6fb4186f48b2a80c5f0. --- src/engine/shared/protocol.h | 1 + src/game/client/components/items.cpp | 6 +- src/game/client/gameclient.cpp | 400 +++++++++++++++++++++++- src/game/client/gameclient.h | 36 +++ src/game/gamecore.cpp | 70 +++++ src/game/gamecore.h | 33 ++ src/game/server/entities/character.cpp | 37 +-- src/game/server/entities/projectile.cpp | 34 +- src/game/server/entities/projectile.h | 1 + src/game/variables.h | 1 + 10 files changed, 579 insertions(+), 40 deletions(-) diff --git a/src/engine/shared/protocol.h b/src/engine/shared/protocol.h index 94c5bdadd..a3080aa6b 100644 --- a/src/engine/shared/protocol.h +++ b/src/engine/shared/protocol.h @@ -104,6 +104,7 @@ enum VERSION_DDNET_GOODHOOK = 221, VERSION_DDNET_EXTRATUNES = 302, VERSION_DDNET_RCONPROTECT = 408, + VERSION_DDNET_ANTIPING_PROJECTILE = 600 }; #endif diff --git a/src/game/client/components/items.cpp b/src/game/client/components/items.cpp index 5389122c1..c396db707 100644 --- a/src/game/client/components/items.cpp +++ b/src/game/client/components/items.cpp @@ -49,8 +49,10 @@ void CItems::RenderProjectile(const CNetObj_Projectile *pCurrent, int ItemID) if(Ct < 0) return; // projectile havn't been shot yet - vec2 StartPos(pCurrent->m_X, pCurrent->m_Y); - vec2 StartVel(pCurrent->m_VelX/100.0f, pCurrent->m_VelY/100.0f); + vec2 StartPos, StartVel; + ExtractInfo(pCurrent, &StartPos, &StartVel); + //vec2 StartPos(pCurrent->m_X, pCurrent->m_Y); + //vec2 StartVel(pCurrent->m_VelX/100.00000f, pCurrent->m_VelY/100.00000f); vec2 Pos = CalcPos(StartPos, StartVel, Curvature, Speed, Ct); vec2 PrevPos = CalcPos(StartPos, StartVel, Curvature, Speed, Ct-0.001f); diff --git a/src/game/client/gameclient.cpp b/src/game/client/gameclient.cpp index 484279492..7cafed2d2 100644 --- a/src/game/client/gameclient.cpp +++ b/src/game/client/gameclient.cpp @@ -267,7 +267,7 @@ void CGameClient::OnInit() m_UI.SetGraphics(Graphics(), TextRender()); m_RenderTools.m_pGraphics = Graphics(); m_RenderTools.m_pUI = UI(); - + int64 Start = time_get(); // set the language @@ -440,6 +440,9 @@ void CGameClient::OnReset() m_DDRaceMsgSent[1] = false; m_ShowOthers[0] = -1; m_ShowOthers[1] = -1; + + for(int i=0; i<64; i++) + m_aLocalProjectiles[i].Deactivate(); } @@ -474,7 +477,7 @@ void CGameClient::UpdatePositions() vec2(m_Snap.m_pLocalPrevCharacter->m_X, m_Snap.m_pLocalPrevCharacter->m_Y), vec2(m_Snap.m_pLocalCharacter->m_X, m_Snap.m_pLocalCharacter->m_Y), Client()->IntraGameTick()); } - + if (g_Config.m_ClAntiPing) { for (int i = 0; i < MAX_CLIENTS; i++) @@ -646,7 +649,7 @@ void CGameClient::OnMessage(int MsgId, CUnpacker *pUnpacker, bool IsDummy) m_Tuning[IsDummy ? !g_Config.m_ClDummy : g_Config.m_ClDummy] = NewTuning; return; } - + void *pRawMsg = m_NetObjHandler.SecureUnpackMsg(MsgId, pUnpacker); if(!pRawMsg) { @@ -1168,6 +1171,9 @@ void CGameClient::OnNewSnapshot() void CGameClient::OnPredict() { + float PhysSize = 28.0f; + float ProximityRadius = PhysSize; + // store the previous values so we can detect prediction errors CCharacterCore BeforePrevChar = m_PredictedPrevChar; CCharacterCore BeforeChar = m_PredictedChar; @@ -1209,6 +1215,42 @@ void CGameClient::OnPredict() g_GameClient.m_aClients[i].m_Predicted.m_ActiveWeapon = m_Snap.m_aCharacters[i].m_Cur.m_Weapon; } + class CLocalProjectile TempProjectiles[64]; + int NumProjectiles = 0; + + if(g_Config.m_ClAntiPingWeapons) + { + for(int Index=0; Index<64; Index++) + TempProjectiles[Index].Deactivate(); + int Num = Client()->SnapNumItems(IClient::SNAP_CURRENT); + for(int Index = 0; Index < Num && NumProjectiles < 64; Index++) + { + IClient::CSnapItem Item; + const void *pData = Client()->SnapGetItem(IClient::SNAP_CURRENT, Index, &Item); + if(Item.m_Type == NETOBJTYPE_PROJECTILE) + { + if(((const CNetObj_Projectile*)pData)->m_Type == WEAPON_GRENADE) + { + TempProjectiles[NumProjectiles].Init(this, &World, Collision(), (const CNetObj_Projectile *)pData); + + int Index = TempProjectiles[NumProjectiles].m_StartTick % 64; + if(m_aLocalProjectiles[Index].m_Active) + if(m_aLocalProjectiles[Index].m_StartTick == TempProjectiles[NumProjectiles].m_StartTick) + if(distance(m_aLocalProjectiles[Index].m_Pos, TempProjectiles[NumProjectiles].m_Pos) < 3) + TempProjectiles[NumProjectiles] = m_aLocalProjectiles[Index]; + NumProjectiles++; + } + } + } + } + + int ReloadTimer; + if(World.m_apCharacters[m_Snap.m_LocalClientID]->m_ActiveWeapon == WEAPON_HAMMER) + ReloadTimer = SERVER_TICK_SPEED / 3 - (Client()->GameTick() - m_Snap.m_aCharacters[m_Snap.m_LocalClientID].m_Cur.m_AttackTick); + else + ReloadTimer = g_pData->m_Weapons.m_aId[World.m_apCharacters[m_Snap.m_LocalClientID]->m_ActiveWeapon].m_Firedelay * SERVER_TICK_SPEED / 1000 - (Client()->GameTick() - m_Snap.m_aCharacters[m_Snap.m_LocalClientID].m_Cur.m_AttackTick); + ReloadTimer = max(ReloadTimer, 0); + // predict for(int Tick = Client()->GameTick()+1; Tick <= Client()->PredGameTick(); Tick++) { @@ -1216,27 +1258,160 @@ void CGameClient::OnPredict() if(Tick == Client()->PredGameTick() && World.m_apCharacters[m_Snap.m_LocalClientID]) m_PredictedPrevChar = *World.m_apCharacters[m_Snap.m_LocalClientID]; - // first calculate where everyone should move for(int c = 0; c < MAX_CLIENTS; c++) { if(!World.m_apCharacters[c]) continue; - + if(g_Config.m_ClAntiPing && Tick == Client()->PredGameTick()) g_GameClient.m_aClients[c].m_PrevPredicted = *World.m_apCharacters[c]; + } + + // input + CNetObj_PlayerInput Input; + CNetObj_PlayerInput PrevInput; + for(int c = 0; c < MAX_CLIENTS; c++) + { + if(!World.m_apCharacters[c]) + continue; mem_zero(&World.m_apCharacters[c]->m_Input, sizeof(World.m_apCharacters[c]->m_Input)); if(m_Snap.m_LocalClientID == c) { // apply player input + mem_zero(&Input, sizeof(Input)); + mem_zero(&PrevInput, sizeof(PrevInput)); int *pInput = Client()->GetInput(Tick); if(pInput) + { World.m_apCharacters[c]->m_Input = *((CNetObj_PlayerInput*)pInput); + Input = *((CNetObj_PlayerInput*)pInput); + } + int *pPrevInput = Client()->GetInput(Tick-1); + if(pPrevInput) + PrevInput = *((CNetObj_PlayerInput*)pPrevInput); + } + } + + // handle weapons + do + { + if(!g_Config.m_ClAntiPingWeapons) + break; + if(ReloadTimer) + break; + if(!World.m_apCharacters[m_Snap.m_LocalClientID]) + break; + CCharacterCore *Local = World.m_apCharacters[m_Snap.m_LocalClientID]; + + //DoWeaponSwitch(); + + bool FullAuto = false; + if(Local->m_ActiveWeapon == WEAPON_GRENADE || Local->m_ActiveWeapon == WEAPON_SHOTGUN || Local->m_ActiveWeapon == WEAPON_RIFLE) + FullAuto = true; + + bool WillFire = false; + + if(CountInput(PrevInput.m_Fire, Input.m_Fire).m_Presses) + WillFire = true; + if(FullAuto && (Input.m_Fire&1)) + WillFire = true; + if(!WillFire) + break; + //if(!m_pControls->m_AmmoCount[Local->m_ActiveWeapon%NUM_WEAPONS]) break; + vec2 Direction = normalize(vec2(Input.m_TargetX, Input.m_TargetY)); + vec2 Pos = Local->m_Pos; + vec2 ProjStartPos = Pos + Direction * ProximityRadius * 0.75f; + + ReloadTimer = g_pData->m_Weapons.m_aId[Local->m_ActiveWeapon].m_Firedelay * SERVER_TICK_SPEED / 1000; + switch(Local->m_ActiveWeapon) + { + case WEAPON_GRENADE: + { + if(NumProjectiles >= 64) + break; + TempProjectiles[NumProjectiles].Init( + this, &World, Collision(), + Direction, //StartDir + ProjStartPos, //StartPos + Tick-1, //StartTick + WEAPON_GRENADE, //Type + m_Snap.m_LocalClientID, //Owner + WEAPON_GRENADE, //Weapon + 1000, //LifeSpan + 1, 0, 0, 1); //Explosive, Bouncing, Freeze, ExtraInfo + m_aLocalProjectiles[(Tick-1)%64] = TempProjectiles[NumProjectiles]; + NumProjectiles++; + } break; + + case WEAPON_HAMMER: + { + vec2 ProjPos = ProjStartPos; + float Radius = ProximityRadius*0.5f; + + int Hits = 0; + bool OwnerCanProbablyHitOthers = (m_Tuning[g_Config.m_ClDummy].m_PlayerCollision || m_Tuning[g_Config.m_ClDummy].m_PlayerHooking); + if(!OwnerCanProbablyHitOthers) + break; + for(int i = 0; i < MAX_CLIENTS; i++) + { + if(!World.m_apCharacters[i]) + continue; + if(i == m_Snap.m_LocalClientID) + continue; + if(!(distance(World.m_apCharacters[i]->m_Pos, ProjPos) < Radius+ProximityRadius)) + continue;; + + CCharacterCore *pTarget = World.m_apCharacters[i]; + + if(m_aClients[i].m_Active && !m_Teams.CanCollide(i, m_Snap.m_LocalClientID)) + continue; + + vec2 Dir; + if (length(pTarget->m_Pos - Pos) > 0.0f) + Dir = normalize(pTarget->m_Pos - Pos); + else + Dir = vec2(0.f, -1.f); + + float Strength; + Strength = World.m_Tuning[g_Config.m_ClDummy].m_HammerStrength; + + vec2 Temp = pTarget->m_Vel + normalize(Dir + vec2(0.f, -1.1f)) * 10.0f; + + Temp -= pTarget->m_Vel; + pTarget->TakeDamage((vec2(0.f, -1.0f) + Temp) * Strength); + Hits++; + } + // if we Hit anything, we have to wait for the reload + //if(Hits) + //ReloadTimer = SERVER_TICK_SPEED/3; + } break; + default: + break; + } + } while(false); + + if(ReloadTimer) + ReloadTimer--; + + // projectiles + if(g_Config.m_ClAntiPingWeapons) + for(int g = 0; g < 64; g++) + if(TempProjectiles[g].m_Active) + TempProjectiles[g].Tick(Tick, Client()->GameTickSpeed(), m_Snap.m_LocalClientID); + + // first calculate where everyone should move + for(int c = 0; c < MAX_CLIENTS; c++) + { + if(!World.m_apCharacters[c]) + continue; + + if(m_Snap.m_LocalClientID == c) + { World.m_apCharacters[c]->Tick(true, true); } else World.m_apCharacters[c]->Tick(false, true); - } // move all players and quantize their data @@ -1281,6 +1456,7 @@ void CGameClient::OnPredict() } } + if(Tick == Client()->PredGameTick() && World.m_apCharacters[m_Snap.m_LocalClientID]) { m_PredictedChar = *World.m_apCharacters[m_Snap.m_LocalClientID]; @@ -1298,6 +1474,7 @@ void CGameClient::OnPredict() } } + if(g_Config.m_Debug && g_Config.m_ClPredict && m_PredictedTick == Client()->PredGameTick()) { CNetObj_CharacterCore Before = {0}, Now = {0}, BeforePrev = {0}, NowPrev = {0}; @@ -1492,6 +1669,7 @@ IGameClient *CreateGameClient() return &g_GameClient; } + int CGameClient::IntersectCharacter(vec2 HookPos, vec2 NewPos, vec2& NewPos2, int ownID) { float PhysSize = 28.0f; @@ -1523,6 +1701,214 @@ int CGameClient::IntersectCharacter(vec2 HookPos, vec2 NewPos, vec2& NewPos2, in } } } - return ClosestID; } + +int CGameClient::IntersectCharacter(vec2 OldPos, vec2 NewPos, float Radius, vec2 *NewPos2, int ownID, CWorldCore *World) +{ + + float PhysSize = 28.0f; + float Distance = 0.0f; + int ClosestID = -1; + + if(!World) + return ClosestID; + + for (int i=0; im_apCharacters[i]) + continue; + CClientData cData = m_aClients[i]; + + if(!cData.m_Active || i == ownID || !m_Teams.CanCollide(i, ownID)) + continue; + vec2 Position = World->m_apCharacters[i]->m_Pos; + vec2 ClosestPoint = closest_point_on_line(OldPos, NewPos, Position); + if(distance(Position, ClosestPoint) < PhysSize+Radius) + { + if(ClosestID == -1 || distance(OldPos, Position) < Distance) + { + *NewPos2 = ClosestPoint; + ClosestID = i; + Distance = distance(OldPos, Position); + } + } + } + return ClosestID; +} + +void CLocalProjectile::Init(CGameClient *pGameClient, CWorldCore *pWorld, CCollision *pCollision, const CNetObj_Projectile *pProj) +{ + m_Active = 1; + m_pGameClient = pGameClient; + m_pWorld = pWorld; + m_pCollision = pCollision; + m_StartTick = pProj->m_StartTick; + m_Type = pProj->m_Type; + m_Weapon = m_Type; + + ExtractInfo(pProj, &m_Pos, &m_Direction); + + if(HasExtraInfo(pProj)) + { + ExtractExtraInfo(pProj, &m_Owner, &m_LifeSpan, &m_Explosive, &m_Bouncing, &m_Freeze); + m_ExtraInfo = true; + } + else + { + m_Owner = -1; + m_Explosive = (m_Type == WEAPON_GRENADE ? true : false); + m_Bouncing = 0; + m_Freeze = 0; + m_LifeSpan = -2; + m_ExtraInfo = false; + } +} + +void CLocalProjectile::Init(CGameClient *pGameClient, CWorldCore *pWorld, CCollision *pCollision, vec2 Direction, vec2 Pos, int StartTick, int Type, int Owner, int Weapon, int LifeSpan, bool Explosive, int Bouncing, bool Freeze, bool ExtraInfo) +{ + m_Active = 1; + m_pGameClient = pGameClient; + m_pWorld = pWorld; + m_pCollision = pCollision; + m_Direction = Direction; + m_Pos = Pos; + m_StartTick = StartTick; + m_Type = Type; + m_Weapon = Weapon; + m_LifeSpan = LifeSpan; + m_Owner = Owner; + m_Explosive = Explosive; + m_Bouncing = Bouncing; + m_Freeze = Freeze; + m_ExtraInfo = ExtraInfo; +} + +vec2 CLocalProjectile::GetPos(float Time) +{ + float Curvature = 0; + float Speed = 0; + + switch(m_Type) + { + case WEAPON_GRENADE: + Curvature = m_pWorld->m_Tuning[g_Config.m_ClDummy].m_GrenadeCurvature; + Speed = m_pWorld->m_Tuning[g_Config.m_ClDummy].m_GrenadeSpeed; + break; + + case WEAPON_SHOTGUN: + Curvature = m_pWorld->m_Tuning[g_Config.m_ClDummy].m_ShotgunCurvature; + Speed = m_pWorld->m_Tuning[g_Config.m_ClDummy].m_ShotgunSpeed; + break; + + case WEAPON_GUN: + Curvature = m_pWorld->m_Tuning[g_Config.m_ClDummy].m_GunCurvature; + Speed = m_pWorld->m_Tuning[g_Config.m_ClDummy].m_GunSpeed; + break; + } + + return CalcPos(m_Pos, m_Direction, Curvature, Speed, Time); +} + +bool CLocalProjectile::GameLayerClipped(vec2 CheckPos) +{ + return round_to_int(CheckPos.x)/32 < -200 || round_to_int(CheckPos.x)/32 > m_pCollision->GetWidth()+200 || + round_to_int(CheckPos.y)/32 < -200 || round_to_int(CheckPos.y)/32 > m_pCollision->GetHeight()+200 ? true : false; +} + + +void CLocalProjectile::Tick(int CurrentTick, int GameTickSpeed, int LocalClientID) +{ + if(!m_pWorld) + return; + float Pt = (CurrentTick-m_StartTick-1)/(float)GameTickSpeed; + float Ct = (CurrentTick-m_StartTick)/(float)GameTickSpeed; + + vec2 PrevPos = GetPos(Pt); + vec2 CurPos = GetPos(Ct); + vec2 ColPos; + vec2 NewPos; + int Collide = 0; + if(m_pCollision) + Collide = m_pCollision->IntersectLine(PrevPos, CurPos, &ColPos, &NewPos, false); + int Target = m_pGameClient->IntersectCharacter(PrevPos, ColPos, m_Freeze ? 1.0f : 6.0f, &ColPos, m_Owner, m_pWorld); + + if(m_LifeSpan > -1) + m_LifeSpan--; + + bool isWeaponCollide = false; + if + ( + m_Owner >= 0 && + Target >= 0 && + m_pGameClient->m_aClients[m_Owner].m_Active && + m_pGameClient->m_aClients[Target].m_Active && + !m_pGameClient->m_Teams.CanCollide(m_Owner, Target) + ) + isWeaponCollide = true; + + bool OwnerCanProbablyHitOthers = (m_pWorld->m_Tuning[g_Config.m_ClDummy].m_PlayerCollision || m_pWorld->m_Tuning[g_Config.m_ClDummy].m_PlayerHooking); + + if(((Target >= 0 && (m_Owner >= 0 ? OwnerCanProbablyHitOthers : 1 || Target == m_Owner)) || Collide || GameLayerClipped(CurPos)) && !isWeaponCollide) + { + if(m_Explosive && (Target < 0 || (Target >= 0 && (!m_Freeze || (m_Weapon == WEAPON_SHOTGUN && Collide))))) + CreateExplosion(ColPos, m_Owner); + if(Collide && m_Bouncing != 0) + { + m_StartTick = CurrentTick; + m_Pos = NewPos+(-(m_Direction*4)); + if (m_Bouncing == 1) + m_Direction.x = -m_Direction.x; + else if(m_Bouncing == 2) + m_Direction.y =- m_Direction.y; + if (fabs(m_Direction.x) < 1e-6) + m_Direction.x = 0; + if (fabs(m_Direction.y) < 1e-6) + m_Direction.y = 0; + m_Pos += m_Direction; + } + else if(!m_Bouncing) + Deactivate(); + } + //if(m_LifeSpan == -1) + //{ + //if(m_Explosive) + //{ + //CreateExplosion(ColPos, LocalClientID); + //} + //Deactivate(); + //} +} + +void CLocalProjectile::CreateExplosion(vec2 Pos, int LocalClientID) +{ + if(!m_pWorld) + return; + float Radius = 135.0f; + float InnerRadius = 48.0f; + + bool OwnerCanProbablyHitOthers = (m_pWorld->m_Tuning[g_Config.m_ClDummy].m_PlayerCollision || m_pWorld->m_Tuning[g_Config.m_ClDummy].m_PlayerHooking); + + for(int c = 0; c < MAX_CLIENTS; c++) + { + if(!m_pWorld->m_apCharacters[c]) + continue; + if(m_Owner >= 0 && c >= 0) + if(m_pGameClient->m_aClients[c].m_Active && !m_pGameClient->m_Teams.CanCollide(c, m_Owner)) + continue; + if(c != LocalClientID && !OwnerCanProbablyHitOthers) + continue; + vec2 Diff = m_pWorld->m_apCharacters[c]->m_Pos - Pos; + vec2 ForceDir(0,1); + float l = length(Diff); + if(l) + ForceDir = normalize(Diff); + l = 1-clamp((l-InnerRadius)/(Radius-InnerRadius), 0.0f, 1.0f); + + float Strength = m_pWorld->m_Tuning[g_Config.m_ClDummy].m_ExplosionStrength; + float Dmg = Strength * l; + + if((int)Dmg) + m_pWorld->m_apCharacters[c]->TakeDamage(ForceDir*Dmg*2); + } +} diff --git a/src/game/client/gameclient.h b/src/game/client/gameclient.h index 2849b05b7..2fccc61b2 100644 --- a/src/game/client/gameclient.h +++ b/src/game/client/gameclient.h @@ -22,6 +22,39 @@ : \ ((x) >= (z) ? (x) : (z))) +class CGameClient; + +class CLocalProjectile +{ +public: + int m_Active; + CGameClient *m_pGameClient; + CWorldCore *m_pWorld; + CCollision *m_pCollision; + + vec2 m_Direction; + vec2 m_Pos; + int m_StartTick; + int m_Type; + + int m_Owner; + int m_Weapon; + int m_LifeSpan; + bool m_Explosive; + int m_Bouncing; + bool m_Freeze; + bool m_ExtraInfo; + + vec2 GetPos(float Time); + void CreateExplosion(vec2 Pos, int LocalClientID); + void Tick(int CurrentTick, int GameTickSpeed, int LocalClientID); + void Init(CGameClient *pGameClient, CWorldCore *pWorld, CCollision *pCollision, const CNetObj_Projectile *pProj); + void Init(CGameClient *pGameClient, CWorldCore *pWorld, CCollision *pCollision, vec2 Direction, vec2 Pos, int StartTick, int Type, int Owner, int Weapon, int LifeSpan, bool Explosive, int Bouncing, bool Freeze, bool ExtraInfo); + + bool GameLayerClipped(vec2 CheckPos); + void Deactivate() { m_Active = 0; } +}; + class CGameClient : public IGameClient { class CStack @@ -283,6 +316,9 @@ public: class CTeamsCore m_Teams; int IntersectCharacter(vec2 Pos0, vec2 Pos1, vec2& NewPos, int ownID); + int IntersectCharacter(vec2 OldPos, vec2 NewPos, float Radius, vec2* NewPos2, int ownID, CWorldCore *World); + + class CLocalProjectile m_aLocalProjectiles[64]; private: diff --git a/src/game/gamecore.cpp b/src/game/gamecore.cpp index e4a60033d..b3657d5ea 100644 --- a/src/game/gamecore.cpp +++ b/src/game/gamecore.cpp @@ -697,6 +697,61 @@ void CCharacterCore::Quantize() // DDRace +bool HasExtraInfo(const CNetObj_Projectile *pProj) +{ + return ((abs(pProj->m_VelY) & (1<<9)) != 0); +} + +void ExtractInfo(const CNetObj_Projectile *pProj, vec2 *StartPos, vec2 *StartVel) +{ + if(!StartPos || !StartVel) + return; + if(!HasExtraInfo(pProj)) + { + StartPos->x = pProj->m_X + 0.5f * sign(pProj->m_X); + StartPos->y = pProj->m_Y + 0.5f * sign(pProj->m_Y); + StartVel->x = pProj->m_VelX + 0.5f *sign(pProj->m_VelX); + StartVel->y = pProj->m_VelY + 0.5f *sign(pProj->m_VelY); + //StartVel->x = pProj->m_VelX/100.0f; + //StartVel->y = pProj->m_VelY/100.0f; + } + else + { + StartPos->x = (pProj->m_X + 0.5f * sign(pProj->m_X))/1000.0f; + StartPos->y = (pProj->m_Y + 0.5f * sign(pProj->m_Y))/1000.0f; + float Angle = (pProj->m_VelX + 0.5f * sign(pProj->m_VelX))/1000000.0f; + StartVel->x = sin(-Angle); + StartVel->y = cos(-Angle); + } + *StartVel = normalize(*StartVel); +} + +void ExtractExtraInfo(const CNetObj_Projectile *pProj, int *Owner, int *LifeSpan, bool *Explosive, int *Bouncing = 0, bool *Freeze = 0) +{ + if(!HasExtraInfo(pProj)) + return; + int Data = pProj->m_VelY; + if(Owner) + { + *Owner = Data & 255; + if((Data>>8) & 1) + *Owner = -(*Owner); + } + // HasExtraInfo = ((Data>>9) & 1); + if(LifeSpan) + { + *LifeSpan = (Data>>10) & 255; + if((Data >> 18) & 1) + *LifeSpan = -(*LifeSpan); + } + if(Explosive) + *Explosive = (Data>>19) & 1; + if(Bouncing) + *Bouncing = (Data>>20) & 3; + if(Freeze) + *Freeze = (Data>>22) & 1; +} + bool CCharacterCore::IsRightTeam(int MapIndex) { if(Collision()->m_pSwitchers) @@ -704,3 +759,18 @@ bool CCharacterCore::IsRightTeam(int MapIndex) return Collision()->m_pSwitchers[Collision()->GetDTileNumber(MapIndex)].m_Status[m_pTeams->Team(m_Id)]; return false; } + + +void CCharacterCore::TakeDamage(vec2 Force) +{ + vec2 Temp = m_Vel + Force; + if(Temp.x > 0 && ((m_TileIndex == TILE_STOP && m_TileFlags == ROTATION_270) || (m_TileIndexL == TILE_STOP && m_TileFlagsL == ROTATION_270) || (m_TileIndexL == TILE_STOPS && (m_TileFlagsL == ROTATION_90 || m_TileFlagsL ==ROTATION_270)) || (m_TileIndexL == TILE_STOPA) || (m_TileFIndex == TILE_STOP && m_TileFFlags == ROTATION_270) || (m_TileFIndexL == TILE_STOP && m_TileFFlagsL == ROTATION_270) || (m_TileFIndexL == TILE_STOPS && (m_TileFFlagsL == ROTATION_90 || m_TileFFlagsL == ROTATION_270)) || (m_TileFIndexL == TILE_STOPA) || (m_TileSIndex == TILE_STOP && m_TileSFlags == ROTATION_270) || (m_TileSIndexL == TILE_STOP && m_TileSFlagsL == ROTATION_270) || (m_TileSIndexL == TILE_STOPS && (m_TileSFlagsL == ROTATION_90 || m_TileSFlagsL == ROTATION_270)) || (m_TileSIndexL == TILE_STOPA))) + Temp.x = 0; + if(Temp.x < 0 && ((m_TileIndex == TILE_STOP && m_TileFlags == ROTATION_90) || (m_TileIndexR == TILE_STOP && m_TileFlagsR == ROTATION_90) || (m_TileIndexR == TILE_STOPS && (m_TileFlagsR == ROTATION_90 || m_TileFlagsR == ROTATION_270)) || (m_TileIndexR == TILE_STOPA) || (m_TileFIndex == TILE_STOP && m_TileFFlags == ROTATION_90) || (m_TileFIndexR == TILE_STOP && m_TileFFlagsR == ROTATION_90) || (m_TileFIndexR == TILE_STOPS && (m_TileFFlagsR == ROTATION_90 || m_TileFFlagsR == ROTATION_270)) || (m_TileFIndexR == TILE_STOPA) || (m_TileSIndex == TILE_STOP && m_TileSFlags == ROTATION_90) || (m_TileSIndexR == TILE_STOP && m_TileSFlagsR == ROTATION_90) || (m_TileSIndexR == TILE_STOPS && (m_TileSFlagsR == ROTATION_90 || m_TileSFlagsR == ROTATION_270)) || (m_TileSIndexR == TILE_STOPA))) + Temp.x = 0; + if(Temp.y < 0 && ((m_TileIndex == TILE_STOP && m_TileFlags == ROTATION_180) || (m_TileIndexB == TILE_STOP && m_TileFlagsB == ROTATION_180) || (m_TileIndexB == TILE_STOPS && (m_TileFlagsB == ROTATION_0 || m_TileFlagsB == ROTATION_180)) || (m_TileIndexB == TILE_STOPA) || (m_TileFIndex == TILE_STOP && m_TileFFlags == ROTATION_180) || (m_TileFIndexB == TILE_STOP && m_TileFFlagsB == ROTATION_180) || (m_TileFIndexB == TILE_STOPS && (m_TileFFlagsB == ROTATION_0 || m_TileFFlagsB == ROTATION_180)) || (m_TileFIndexB == TILE_STOPA) || (m_TileSIndex == TILE_STOP && m_TileSFlags == ROTATION_180) || (m_TileSIndexB == TILE_STOP && m_TileSFlagsB == ROTATION_180) || (m_TileSIndexB == TILE_STOPS && (m_TileSFlagsB == ROTATION_0 || m_TileSFlagsB == ROTATION_180)) || (m_TileSIndexB == TILE_STOPA))) + Temp.y = 0; + if(Temp.y > 0 && ((m_TileIndex == TILE_STOP && m_TileFlags == ROTATION_0) || (m_TileIndexT == TILE_STOP && m_TileFlagsT == ROTATION_0) || (m_TileIndexT == TILE_STOPS && (m_TileFlagsT == ROTATION_0 || m_TileFlagsT == ROTATION_180)) || (m_TileIndexT == TILE_STOPA) || (m_TileFIndex == TILE_STOP && m_TileFFlags == ROTATION_0) || (m_TileFIndexT == TILE_STOP && m_TileFFlagsT == ROTATION_0) || (m_TileFIndexT == TILE_STOPS && (m_TileFFlagsT == ROTATION_0 || m_TileFFlagsT == ROTATION_180)) || (m_TileFIndexT == TILE_STOPA) || (m_TileSIndex == TILE_STOP && m_TileSFlags == ROTATION_0) || (m_TileSIndexT == TILE_STOP && m_TileSFlagsT == ROTATION_0) || (m_TileSIndexT == TILE_STOPS && (m_TileSFlagsT == ROTATION_0 || m_TileSFlagsT == ROTATION_180)) || (m_TileSIndexT == TILE_STOPA))) + Temp.y = 0; + m_Vel = Temp; +} diff --git a/src/game/gamecore.h b/src/game/gamecore.h index 641e6e394..07bc015c0 100644 --- a/src/game/gamecore.h +++ b/src/game/gamecore.h @@ -233,6 +233,8 @@ public: int m_Colliding; bool m_LeftWall; + void TakeDamage(vec2 Force); + private: CTeamsCore* m_pTeams; @@ -269,4 +271,35 @@ private: bool IsRightTeam(int MapIndex); }; +bool HasExtraInfo(const CNetObj_Projectile *pProj); +void ExtractInfo(const CNetObj_Projectile *pProj, vec2 *StartPos, vec2 *StartVel); +void ExtractExtraInfo(const CNetObj_Projectile *pProj, int *Owner, int *m_LifeSpan, bool *Explosive, int *Bouncing, bool *Freeze); + +//input count +struct CInputCount +{ + int m_Presses; + int m_Releases; +}; + +inline CInputCount CountInput(int Prev, int Cur) +{ + CInputCount c = {0, 0}; + Prev &= INPUT_STATE_MASK; + Cur &= INPUT_STATE_MASK; + int i = Prev; + + while(i != Cur) + { + i = (i+1)&INPUT_STATE_MASK; + if(i&1) + c.m_Presses++; + else + c.m_Releases++; + } + + return c; +} + + #endif diff --git a/src/game/server/entities/character.cpp b/src/game/server/entities/character.cpp index f4dd3c657..732d83818 100644 --- a/src/game/server/entities/character.cpp +++ b/src/game/server/entities/character.cpp @@ -16,33 +16,6 @@ #include #include "light.h" -//input count -struct CInputCount -{ - int m_Presses; - int m_Releases; -}; - -CInputCount CountInput(int Prev, int Cur) -{ - CInputCount c = {0, 0}; - Prev &= INPUT_STATE_MASK; - Cur &= INPUT_STATE_MASK; - int i = Prev; - - while(i != Cur) - { - i = (i+1)&INPUT_STATE_MASK; - if(i&1) - c.m_Presses++; - else - c.m_Releases++; - } - - return c; -} - - MACRO_ALLOC_POOL_ID_IMPL(CCharacter, MAX_CLIENTS) // Character, "physical" player's part @@ -372,7 +345,6 @@ void CCharacter::FireWeapon() } return; } - vec2 ProjStartPos = m_Pos+Direction*m_ProximityRadius*0.75f; switch(m_Core.m_ActiveWeapon) @@ -550,7 +522,10 @@ void CCharacter::FireWeapon() // pack the Projectile and send it to the client Directly CNetObj_Projectile p; - pProj->FillInfo(&p); + if(m_pPlayer && m_pPlayer->m_ClientVersion >= VERSION_DDNET_ANTIPING_PROJECTILE) + pProj->FillExtraInfo(&p); + else + pProj->FillInfo(&p); CMsgPacker Msg(NETMSGTYPE_SV_EXTRAPROJECTILE); Msg.AddInt(1); @@ -613,7 +588,7 @@ void CCharacter::HandleWeapons() } // fire Weapon, if wanted - FireWeapon(); + //FireWeapon(); /* // ammo regen int AmmoRegenTime = g_pData->m_Weapons.m_aId[m_Core.m_ActiveWeapon].m_Ammoregentime; @@ -843,6 +818,8 @@ void CCharacter::TickDefered() m_Core.m_pReset = false; } } + + FireWeapon(); } void CCharacter::TickPaused() diff --git a/src/game/server/entities/projectile.cpp b/src/game/server/entities/projectile.cpp index 9d10bc6d3..0f604da57 100644 --- a/src/game/server/entities/projectile.cpp +++ b/src/game/server/entities/projectile.cpp @@ -232,6 +232,33 @@ void CProjectile::FillInfo(CNetObj_Projectile *pProj) pProj->m_Type = m_Type; } +void CProjectile::FillExtraInfo(CNetObj_Projectile *pProj) +{ + //Send additional/modified info, by modifiying the fields of the netobj + float Angle = -atan2f(m_Direction.x, m_Direction.y); + + int Data = 0; + Data |= (abs(m_Owner) & 255); + if(m_Owner < 0) + Data |= 1 << 8; + Data |= 1<<9; //This bit tells the client to use the extra info + Data |= ((abs(m_LifeSpan) <= 255 ? abs(m_LifeSpan) : 255) & 255) << 10; + if(m_LifeSpan < 0) + Data |= 1 << 18; + if(m_Explosive) + Data |= (1 << 19); + Data |= (m_Bouncing & 3) << 20; + if(m_Freeze) + Data |= (1 << 22); + + pProj->m_X = (int)(m_Pos.x * 1000.0f); + pProj->m_Y = (int)(m_Pos.y * 1000.0f); + pProj->m_VelX = (int)(Angle * 1000000.0f); + pProj->m_VelY = Data; + pProj->m_StartTick = m_StartTick; + pProj->m_Type = m_Type; +} + void CProjectile::Snap(int SnappingClient) { float Ct = (Server()->Tick()-m_StartTick)/(float)Server()->TickSpeed(); @@ -258,7 +285,12 @@ void CProjectile::Snap(int SnappingClient) CNetObj_Projectile *pProj = static_cast(Server()->SnapNewItem(NETOBJTYPE_PROJECTILE, m_ID, sizeof(CNetObj_Projectile))); if(pProj) - FillInfo(pProj); + { + if (SnappingClient > -1 && GameServer()->m_apPlayers[SnappingClient] && GameServer()->m_apPlayers[SnappingClient]->m_ClientVersion >= VERSION_DDNET_ANTIPING_PROJECTILE) + FillExtraInfo(pProj); + else + FillInfo(pProj); + } } // DDRace diff --git a/src/game/server/entities/projectile.h b/src/game/server/entities/projectile.h index 8eac4c707..c897d8c86 100644 --- a/src/game/server/entities/projectile.h +++ b/src/game/server/entities/projectile.h @@ -25,6 +25,7 @@ public: vec2 GetPos(float Time); void FillInfo(CNetObj_Projectile *pProj); + void FillExtraInfo(CNetObj_Projectile *pProj); virtual void Reset(); virtual void Tick(); diff --git a/src/game/variables.h b/src/game/variables.h index 4637c2930..b0c86296a 100644 --- a/src/game/variables.h +++ b/src/game/variables.h @@ -9,6 +9,7 @@ MACRO_CONFIG_INT(ClPredict, cl_predict, 1, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Predict client movements") MACRO_CONFIG_INT(ClAntiPing, cl_antiping, 0, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Antiping (predict other players' movements)") MACRO_CONFIG_INT(ClAntiPingGrenade, cl_antiping_grenade, 0, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Antiping (predict grenades)") +MACRO_CONFIG_INT(ClAntiPingWeapons, cl_antiping_weapons, 0, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Antiping (predict weapons)") MACRO_CONFIG_INT(ClNameplates, cl_nameplates, 1, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Show name plates") MACRO_CONFIG_INT(ClNameplatesAlways, cl_nameplates_always, 1, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Always show name plates disregarding of distance") MACRO_CONFIG_INT(ClNameplatesTeamcolors, cl_nameplates_teamcolors, 1, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Use team colors for name plates")