Merge pull request #89 from trml/fix_antipingweapons

Add updated/fixed weapons prediction
This commit is contained in:
Dennis Felsing 2014-10-28 20:07:47 +01:00
commit 8334f1641a
11 changed files with 584 additions and 41 deletions

View file

@ -104,6 +104,7 @@ enum
VERSION_DDNET_GOODHOOK = 221,
VERSION_DDNET_EXTRATUNES = 302,
VERSION_DDNET_RCONPROTECT = 408,
VERSION_DDNET_ANTIPING_PROJECTILE = 604
};
#endif

View file

@ -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);

View file

@ -1793,17 +1793,23 @@ void CMenus::RenderSettingsDDRace(CUIRect MainView)
}
Right.HSplitTop(20.0f, &Button, &Right);
if(DoButton_CheckBox(&g_Config.m_ClAntiPing, Localize("AntiPing (predict other players)"), g_Config.m_ClAntiPing, &Button))
if(DoButton_CheckBox(&g_Config.m_ClAntiPing, Localize("AntiPing: predict other players"), g_Config.m_ClAntiPing, &Button))
{
g_Config.m_ClAntiPing ^= 1;
}
Right.HSplitTop(20.0f, &Button, &Right);
if(DoButton_CheckBox(&g_Config.m_ClAntiPingGrenade, Localize("AntiPing (predict grenades)"), g_Config.m_ClAntiPingGrenade, &Button))
if(DoButton_CheckBox(&g_Config.m_ClAntiPingGrenade, Localize("AntiPing: predict grenade path"), g_Config.m_ClAntiPingGrenade, &Button))
{
g_Config.m_ClAntiPingGrenade ^= 1;
}
Right.HSplitTop(20.0f, &Button, &Right);
if(DoButton_CheckBox(&g_Config.m_ClAntiPingWeapons, Localize("AntiPing: predict weapons"), g_Config.m_ClAntiPingWeapons, &Button))
{
g_Config.m_ClAntiPingWeapons ^= 1;
}
Right.HSplitTop(20.0f, &Button, &Right);
if(DoButton_CheckBox(&g_Config.m_ClUnpredictedShadow, Localize("Show unpredicted shadow tee"), g_Config.m_ClUnpredictedShadow, &Button))
{

View file

@ -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();
}
@ -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,7 +1258,6 @@ 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])
@ -1224,19 +1265,153 @@ void CGameClient::OnPredict()
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; i<MAX_CLIENTS; i++)
{
if(!World->m_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);
}
}

View file

@ -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:

View file

@ -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;
}

View file

@ -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

View file

@ -16,33 +16,6 @@
#include <game/server/score.h>
#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,6 +522,9 @@ void CCharacter::FireWeapon()
// pack the Projectile and send it to the client Directly
CNetObj_Projectile p;
if(m_pPlayer && m_pPlayer->m_ClientVersion >= VERSION_DDNET_ANTIPING_PROJECTILE)
pProj->FillExtraInfo(&p);
else
pProj->FillInfo(&p);
CMsgPacker Msg(NETMSGTYPE_SV_EXTRAPROJECTILE);

View file

@ -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<CNetObj_Projectile *>(Server()->SnapNewItem(NETOBJTYPE_PROJECTILE, m_ID, sizeof(CNetObj_Projectile)));
if(pProj)
{
if (SnappingClient > -1 && GameServer()->m_apPlayers[SnappingClient] && GameServer()->m_apPlayers[SnappingClient]->m_ClientVersion >= VERSION_DDNET_ANTIPING_PROJECTILE)
FillExtraInfo(pProj);
else
FillInfo(pProj);
}
}
// DDRace

View file

@ -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();

View file

@ -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")