mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-14 03:58:18 +00:00
Replace projectile hack with a new extended snapshot object
Still send the old hack to old clients, still accept the old hack from old servers. This is so F-Client can support DDNet servers without such hacks.
This commit is contained in:
parent
9784726683
commit
43998ce41a
|
@ -1561,8 +1561,6 @@ set_src(GAME_SHARED GLOB src/game
|
||||||
collision.cpp
|
collision.cpp
|
||||||
collision.h
|
collision.h
|
||||||
ddracecommands.h
|
ddracecommands.h
|
||||||
extrainfo.cpp
|
|
||||||
extrainfo.h
|
|
||||||
gamecore.cpp
|
gamecore.cpp
|
||||||
gamecore.h
|
gamecore.h
|
||||||
layers.cpp
|
layers.cpp
|
||||||
|
@ -1779,6 +1777,8 @@ if(CLIENT)
|
||||||
prediction/entity.h
|
prediction/entity.h
|
||||||
prediction/gameworld.cpp
|
prediction/gameworld.cpp
|
||||||
prediction/gameworld.h
|
prediction/gameworld.h
|
||||||
|
projectile_data.cpp
|
||||||
|
projectile_data.h
|
||||||
race.cpp
|
race.cpp
|
||||||
race.h
|
race.h
|
||||||
render.cpp
|
render.cpp
|
||||||
|
|
|
@ -24,6 +24,10 @@ GameInfoFlags2 = [
|
||||||
"ALLOW_X_SKINS", "GAMETYPE_CITY", "GAMETYPE_FDDRACE", "ENTITIES_FDDRACE",
|
"ALLOW_X_SKINS", "GAMETYPE_CITY", "GAMETYPE_FDDRACE", "ENTITIES_FDDRACE",
|
||||||
]
|
]
|
||||||
ExPlayerFlags = ["AFK", "PAUSED", "SPEC"]
|
ExPlayerFlags = ["AFK", "PAUSED", "SPEC"]
|
||||||
|
ProjectileFlags = ["CLIENTID_BIT{}".format(i) for i in range(8)] + [
|
||||||
|
"NO_OWNER", "IS_DDNET", "BOUNCE_HORIZONTAL", "BOUNCE_VERTICAL",
|
||||||
|
"EXPLOSIVE", "FREEZE",
|
||||||
|
]
|
||||||
|
|
||||||
Emoticons = ["OOP", "EXCLAMATION", "HEARTS", "DROP", "DOTDOT", "MUSIC", "SORRY", "GHOST", "SUSHI", "SPLATTEE", "DEVILTEE", "ZOMG", "ZZZ", "WTF", "EYES", "QUESTION"]
|
Emoticons = ["OOP", "EXCLAMATION", "HEARTS", "DROP", "DOTDOT", "MUSIC", "SORRY", "GHOST", "SUSHI", "SPLATTEE", "DEVILTEE", "ZOMG", "ZZZ", "WTF", "EYES", "QUESTION"]
|
||||||
|
|
||||||
|
@ -80,6 +84,7 @@ Flags = [
|
||||||
Flags("GAMEINFOFLAG", GameInfoFlags),
|
Flags("GAMEINFOFLAG", GameInfoFlags),
|
||||||
Flags("GAMEINFOFLAG2", GameInfoFlags2),
|
Flags("GAMEINFOFLAG2", GameInfoFlags2),
|
||||||
Flags("EXPLAYERFLAG", ExPlayerFlags),
|
Flags("EXPLAYERFLAG", ExPlayerFlags),
|
||||||
|
Flags("PROJECTILEFLAG", ProjectileFlags),
|
||||||
]
|
]
|
||||||
|
|
||||||
Objects = [
|
Objects = [
|
||||||
|
@ -244,6 +249,17 @@ Objects = [
|
||||||
NetIntAny("m_Flags2"),
|
NetIntAny("m_Flags2"),
|
||||||
], validate_size=False),
|
], validate_size=False),
|
||||||
|
|
||||||
|
# The code assumes that this has the same in-memory representation as
|
||||||
|
# the Projectile net object.
|
||||||
|
NetObjectEx("DDNetProjectile", "projectile@netobj.ddnet.tw", [
|
||||||
|
NetIntAny("m_X"),
|
||||||
|
NetIntAny("m_Y"),
|
||||||
|
NetIntAny("m_Angle"),
|
||||||
|
NetIntAny("m_Data"),
|
||||||
|
NetIntRange("m_Type", 0, 'NUM_WEAPONS-1'),
|
||||||
|
NetTick("m_StartTick"),
|
||||||
|
]),
|
||||||
|
|
||||||
## Events
|
## Events
|
||||||
|
|
||||||
NetEvent("Common", [
|
NetEvent("Common", [
|
||||||
|
|
|
@ -261,5 +261,7 @@ public:
|
||||||
virtual bool IsDisplayingWarning() = 0;
|
virtual bool IsDisplayingWarning() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void SnapshotRemoveExtraProjectileInfo(unsigned char *pData);
|
||||||
|
|
||||||
extern IGameClient *CreateGameClient();
|
extern IGameClient *CreateGameClient();
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -50,7 +50,6 @@
|
||||||
#include <engine/shared/snapshot.h>
|
#include <engine/shared/snapshot.h>
|
||||||
#include <engine/shared/uuid_manager.h>
|
#include <engine/shared/uuid_manager.h>
|
||||||
|
|
||||||
#include <game/extrainfo.h>
|
|
||||||
#include <game/version.h>
|
#include <game/version.h>
|
||||||
|
|
||||||
#include <mastersrv/mastersrv.h>
|
#include <mastersrv/mastersrv.h>
|
||||||
|
@ -2025,7 +2024,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
|
||||||
// for antiping: if the projectile netobjects from the server contains extra data, this is removed and the original content restored before recording demo
|
// for antiping: if the projectile netobjects from the server contains extra data, this is removed and the original content restored before recording demo
|
||||||
unsigned char aExtraInfoRemoved[CSnapshot::MAX_SIZE];
|
unsigned char aExtraInfoRemoved[CSnapshot::MAX_SIZE];
|
||||||
mem_copy(aExtraInfoRemoved, pTmpBuffer3, SnapSize);
|
mem_copy(aExtraInfoRemoved, pTmpBuffer3, SnapSize);
|
||||||
SnapshotRemoveExtraInfo(aExtraInfoRemoved);
|
SnapshotRemoveExtraProjectileInfo(aExtraInfoRemoved);
|
||||||
|
|
||||||
// add snapshot to demo
|
// add snapshot to demo
|
||||||
for(auto &DemoRecorder : m_DemoRecorder)
|
for(auto &DemoRecorder : m_DemoRecorder)
|
||||||
|
|
|
@ -32,7 +32,6 @@
|
||||||
|
|
||||||
// DDRace
|
// DDRace
|
||||||
#include <engine/shared/linereader.h>
|
#include <engine/shared/linereader.h>
|
||||||
#include <game/extrainfo.h>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
|
|
||||||
|
@ -842,12 +841,8 @@ void CServer::DoSnapshot()
|
||||||
GameServer()->OnSnap(-1);
|
GameServer()->OnSnap(-1);
|
||||||
SnapshotSize = m_SnapshotBuilder.Finish(aData);
|
SnapshotSize = m_SnapshotBuilder.Finish(aData);
|
||||||
|
|
||||||
// for antiping: if the projectile netobjects contains extra data, this is removed and the original content restored before recording demo
|
|
||||||
unsigned char aExtraInfoRemoved[CSnapshot::MAX_SIZE];
|
|
||||||
mem_copy(aExtraInfoRemoved, aData, SnapshotSize);
|
|
||||||
SnapshotRemoveExtraInfo(aExtraInfoRemoved);
|
|
||||||
// write snapshot
|
// write snapshot
|
||||||
m_aDemoRecorder[MAX_CLIENTS].RecordSnapshot(Tick(), aExtraInfoRemoved, SnapshotSize);
|
m_aDemoRecorder[MAX_CLIENTS].RecordSnapshot(Tick(), aData, SnapshotSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
// create snapshots for all clients
|
// create snapshots for all clients
|
||||||
|
@ -887,12 +882,8 @@ void CServer::DoSnapshot()
|
||||||
|
|
||||||
if(m_aDemoRecorder[i].IsRecording())
|
if(m_aDemoRecorder[i].IsRecording())
|
||||||
{
|
{
|
||||||
// for antiping: if the projectile netobjects contains extra data, this is removed and the original content restored before recording demo
|
|
||||||
unsigned char aExtraInfoRemoved[CSnapshot::MAX_SIZE];
|
|
||||||
mem_copy(aExtraInfoRemoved, aData, SnapshotSize);
|
|
||||||
SnapshotRemoveExtraInfo(aExtraInfoRemoved);
|
|
||||||
// write snapshot
|
// write snapshot
|
||||||
m_aDemoRecorder[i].RecordSnapshot(Tick(), aExtraInfoRemoved, SnapshotSize);
|
m_aDemoRecorder[i].RecordSnapshot(Tick(), aData, SnapshotSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
Crc = pData->Crc();
|
Crc = pData->Crc();
|
||||||
|
|
|
@ -8,9 +8,9 @@
|
||||||
#include <game/generated/protocol.h>
|
#include <game/generated/protocol.h>
|
||||||
|
|
||||||
#include <game/client/gameclient.h>
|
#include <game/client/gameclient.h>
|
||||||
|
#include <game/client/projectile_data.h>
|
||||||
#include <game/client/render.h>
|
#include <game/client/render.h>
|
||||||
#include <game/client/ui.h>
|
#include <game/client/ui.h>
|
||||||
#include <game/extrainfo.h>
|
|
||||||
|
|
||||||
#include <game/client/components/effects.h>
|
#include <game/client/components/effects.h>
|
||||||
#include <game/client/components/flow.h>
|
#include <game/client/components/flow.h>
|
||||||
|
@ -22,7 +22,7 @@ void CItems::OnReset()
|
||||||
m_NumExtraProjectiles = 0;
|
m_NumExtraProjectiles = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CItems::RenderProjectile(const CNetObj_Projectile *pCurrent, int ItemID)
|
void CItems::RenderProjectile(const CProjectileData *pCurrent, int ItemID)
|
||||||
{
|
{
|
||||||
int CurWeapon = clamp(pCurrent->m_Type, 0, NUM_WEAPONS - 1);
|
int CurWeapon = clamp(pCurrent->m_Type, 0, NUM_WEAPONS - 1);
|
||||||
|
|
||||||
|
@ -62,20 +62,12 @@ void CItems::RenderProjectile(const CNetObj_Projectile *pCurrent, int ItemID)
|
||||||
if(Ct < 0)
|
if(Ct < 0)
|
||||||
return; // projectile haven't been shot yet
|
return; // projectile haven't been shot yet
|
||||||
|
|
||||||
vec2 StartPos;
|
vec2 Pos = CalcPos(pCurrent->m_StartPos, pCurrent->m_StartVel, Curvature, Speed, Ct);
|
||||||
vec2 StartVel;
|
vec2 PrevPos = CalcPos(pCurrent->m_StartPos, pCurrent->m_StartVel, Curvature, Speed, Ct - 0.001f);
|
||||||
|
|
||||||
ExtractInfo(pCurrent, &StartPos, &StartVel);
|
|
||||||
|
|
||||||
vec2 Pos = CalcPos(StartPos, StartVel, Curvature, Speed, Ct);
|
|
||||||
vec2 PrevPos = CalcPos(StartPos, StartVel, Curvature, Speed, Ct - 0.001f);
|
|
||||||
|
|
||||||
float Alpha = 1.f;
|
float Alpha = 1.f;
|
||||||
if(UseExtraInfo(pCurrent))
|
if(pCurrent->m_ExtraInfo && pCurrent->m_Owner >= 0 && m_pClient->IsOtherTeam(pCurrent->m_Owner))
|
||||||
{
|
{
|
||||||
int Owner;
|
|
||||||
ExtractExtraInfo(pCurrent, &Owner, 0, 0, 0);
|
|
||||||
if(Owner >= 0 && m_pClient->IsOtherTeam(Owner))
|
|
||||||
Alpha = g_Config.m_ClShowOthersAlpha / 100.0f;
|
Alpha = g_Config.m_ClShowOthersAlpha / 100.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,11 +302,7 @@ void CItems::OnRender()
|
||||||
{
|
{
|
||||||
for(auto *pProj = (CProjectile *)GameClient()->m_PredictedWorld.FindFirst(CGameWorld::ENTTYPE_PROJECTILE); pProj; pProj = (CProjectile *)pProj->NextEntity())
|
for(auto *pProj = (CProjectile *)GameClient()->m_PredictedWorld.FindFirst(CGameWorld::ENTTYPE_PROJECTILE); pProj; pProj = (CProjectile *)pProj->NextEntity())
|
||||||
{
|
{
|
||||||
CNetObj_Projectile Data;
|
CProjectileData Data = pProj->GetData();
|
||||||
if(pProj->m_Type != WEAPON_SHOTGUN || pProj->m_Explosive || pProj->m_Freeze)
|
|
||||||
pProj->FillExtraInfo(&Data);
|
|
||||||
else
|
|
||||||
pProj->FillInfo(&Data);
|
|
||||||
RenderProjectile(&Data, pProj->ID());
|
RenderProjectile(&Data, pProj->ID());
|
||||||
}
|
}
|
||||||
for(auto *pLaser = (CLaser *)GameClient()->m_PredictedWorld.FindFirst(CGameWorld::ENTTYPE_LASER); pLaser; pLaser = (CLaser *)pLaser->NextEntity())
|
for(auto *pLaser = (CLaser *)GameClient()->m_PredictedWorld.FindFirst(CGameWorld::ENTTYPE_LASER); pLaser; pLaser = (CLaser *)pLaser->NextEntity())
|
||||||
|
@ -343,8 +331,17 @@ void CItems::OnRender()
|
||||||
IClient::CSnapItem Item;
|
IClient::CSnapItem Item;
|
||||||
const void *pData = Client()->SnapGetItem(IClient::SNAP_CURRENT, i, &Item);
|
const void *pData = Client()->SnapGetItem(IClient::SNAP_CURRENT, i, &Item);
|
||||||
|
|
||||||
|
if(Item.m_Type == NETOBJTYPE_PROJECTILE || Item.m_Type == NETOBJTYPE_DDNETPROJECTILE)
|
||||||
|
{
|
||||||
|
CProjectileData Data;
|
||||||
if(Item.m_Type == NETOBJTYPE_PROJECTILE)
|
if(Item.m_Type == NETOBJTYPE_PROJECTILE)
|
||||||
{
|
{
|
||||||
|
Data = ExtractProjectileInfo((const CNetObj_Projectile *)pData);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Data = ExtractProjectileInfoDDNet((const CNetObj_DDNetProjectile *)pData);
|
||||||
|
}
|
||||||
if(UsePredicted)
|
if(UsePredicted)
|
||||||
{
|
{
|
||||||
if(auto *pProj = (CProjectile *)GameClient()->m_GameWorld.FindMatch(Item.m_ID, Item.m_Type, pData))
|
if(auto *pProj = (CProjectile *)GameClient()->m_GameWorld.FindMatch(Item.m_ID, Item.m_Type, pData))
|
||||||
|
@ -354,13 +351,13 @@ void CItems::OnRender()
|
||||||
&& (pProj->GetOwner() < 0 || !GameClient()->m_aClients[pProj->GetOwner()].m_IsPredictedLocal) // skip locally predicted projectiles
|
&& (pProj->GetOwner() < 0 || !GameClient()->m_aClients[pProj->GetOwner()].m_IsPredictedLocal) // skip locally predicted projectiles
|
||||||
&& !Client()->SnapFindItem(IClient::SNAP_PREV, Item.m_Type, Item.m_ID))
|
&& !Client()->SnapFindItem(IClient::SNAP_PREV, Item.m_Type, Item.m_ID))
|
||||||
{
|
{
|
||||||
ReconstructSmokeTrail((const CNetObj_Projectile *)pData, Item.m_ID, pProj->m_DestroyTick);
|
ReconstructSmokeTrail(&Data, pProj->m_DestroyTick);
|
||||||
}
|
}
|
||||||
pProj->m_LastRenderTick = Client()->GameTick(g_Config.m_ClDummy);
|
pProj->m_LastRenderTick = Client()->GameTick(g_Config.m_ClDummy);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RenderProjectile((const CNetObj_Projectile *)pData, Item.m_ID);
|
RenderProjectile(&Data, Item.m_ID);
|
||||||
}
|
}
|
||||||
else if(Item.m_Type == NETOBJTYPE_PICKUP)
|
else if(Item.m_Type == NETOBJTYPE_PICKUP)
|
||||||
{
|
{
|
||||||
|
@ -409,7 +406,10 @@ void CItems::OnRender()
|
||||||
m_NumExtraProjectiles--;
|
m_NumExtraProjectiles--;
|
||||||
}
|
}
|
||||||
else if(!UsePredicted)
|
else if(!UsePredicted)
|
||||||
RenderProjectile(&m_aExtraProjectiles[i], 0);
|
{
|
||||||
|
CProjectileData Data = ExtractProjectileInfo(&m_aExtraProjectiles[i]);
|
||||||
|
RenderProjectile(&Data, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Graphics()->QuadsSetRotation(0);
|
Graphics()->QuadsSetRotation(0);
|
||||||
|
@ -484,7 +484,7 @@ void CItems::AddExtraProjectile(CNetObj_Projectile *pProj)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CItems::ReconstructSmokeTrail(const CNetObj_Projectile *pCurrent, int ItemID, int DestroyTick)
|
void CItems::ReconstructSmokeTrail(const CProjectileData *pCurrent, int DestroyTick)
|
||||||
{
|
{
|
||||||
bool LocalPlayerInGame = false;
|
bool LocalPlayerInGame = false;
|
||||||
|
|
||||||
|
@ -520,17 +520,9 @@ void CItems::ReconstructSmokeTrail(const CNetObj_Projectile *pCurrent, int ItemI
|
||||||
|
|
||||||
float Gt = (Client()->PrevGameTick(g_Config.m_ClDummy) - pCurrent->m_StartTick) / (float)SERVER_TICK_SPEED + Client()->GameTickTime(g_Config.m_ClDummy);
|
float Gt = (Client()->PrevGameTick(g_Config.m_ClDummy) - pCurrent->m_StartTick) / (float)SERVER_TICK_SPEED + Client()->GameTickTime(g_Config.m_ClDummy);
|
||||||
|
|
||||||
vec2 StartPos;
|
|
||||||
vec2 StartVel;
|
|
||||||
|
|
||||||
ExtractInfo(pCurrent, &StartPos, &StartVel);
|
|
||||||
|
|
||||||
float Alpha = 1.f;
|
float Alpha = 1.f;
|
||||||
if(UseExtraInfo(pCurrent))
|
if(pCurrent->m_ExtraInfo && pCurrent->m_Owner >= 0 && m_pClient->IsOtherTeam(pCurrent->m_Owner))
|
||||||
{
|
{
|
||||||
int Owner;
|
|
||||||
ExtractExtraInfo(pCurrent, &Owner, 0, 0, 0);
|
|
||||||
if(Owner >= 0 && m_pClient->IsOtherTeam(Owner))
|
|
||||||
Alpha = g_Config.m_ClShowOthersAlpha / 100.0f;
|
Alpha = g_Config.m_ClShowOthersAlpha / 100.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -543,8 +535,8 @@ void CItems::ReconstructSmokeTrail(const CNetObj_Projectile *pCurrent, int ItemI
|
||||||
for(int i = 1 + (int)(Gt / Step); i < (int)(T / Step); i++)
|
for(int i = 1 + (int)(Gt / Step); i < (int)(T / Step); i++)
|
||||||
{
|
{
|
||||||
float t = Step * (float)i + 0.4f * Step * (frandom() - 0.5f);
|
float t = Step * (float)i + 0.4f * Step * (frandom() - 0.5f);
|
||||||
vec2 Pos = CalcPos(StartPos, StartVel, Curvature, Speed, t);
|
vec2 Pos = CalcPos(pCurrent->m_StartPos, pCurrent->m_StartVel, Curvature, Speed, t);
|
||||||
vec2 PrevPos = CalcPos(StartPos, StartVel, Curvature, Speed, t - 0.001f);
|
vec2 PrevPos = CalcPos(pCurrent->m_StartPos, pCurrent->m_StartVel, Curvature, Speed, t - 0.001f);
|
||||||
vec2 Vel = Pos - PrevPos;
|
vec2 Vel = Pos - PrevPos;
|
||||||
float TimePassed = Pt - t;
|
float TimePassed = Pt - t;
|
||||||
if(Pt - MinTrailSpan > 0.01f)
|
if(Pt - MinTrailSpan > 0.01f)
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
#define GAME_CLIENT_COMPONENTS_ITEMS_H
|
#define GAME_CLIENT_COMPONENTS_ITEMS_H
|
||||||
#include <game/client/component.h>
|
#include <game/client/component.h>
|
||||||
|
|
||||||
|
class CProjectileData;
|
||||||
|
|
||||||
class CItems : public CComponent
|
class CItems : public CComponent
|
||||||
{
|
{
|
||||||
enum
|
enum
|
||||||
|
@ -14,7 +16,7 @@ class CItems : public CComponent
|
||||||
CNetObj_Projectile m_aExtraProjectiles[MAX_EXTRA_PROJECTILES];
|
CNetObj_Projectile m_aExtraProjectiles[MAX_EXTRA_PROJECTILES];
|
||||||
int m_NumExtraProjectiles;
|
int m_NumExtraProjectiles;
|
||||||
|
|
||||||
void RenderProjectile(const CNetObj_Projectile *pCurrent, int ItemID);
|
void RenderProjectile(const CProjectileData *pCurrent, int ItemID);
|
||||||
void RenderPickup(const CNetObj_Pickup *pPrev, const CNetObj_Pickup *pCurrent, bool IsPredicted = false);
|
void RenderPickup(const CNetObj_Pickup *pPrev, const CNetObj_Pickup *pCurrent, bool IsPredicted = false);
|
||||||
void RenderFlag(const CNetObj_Flag *pPrev, const CNetObj_Flag *pCurrent, const CNetObj_GameData *pPrevGameData, const CNetObj_GameData *pCurGameData);
|
void RenderFlag(const CNetObj_Flag *pPrev, const CNetObj_Flag *pCurrent, const CNetObj_GameData *pPrevGameData, const CNetObj_GameData *pCurGameData);
|
||||||
void RenderLaser(const struct CNetObj_Laser *pCurrent, bool IsPredicted = false);
|
void RenderLaser(const struct CNetObj_Laser *pCurrent, bool IsPredicted = false);
|
||||||
|
@ -28,7 +30,7 @@ public:
|
||||||
|
|
||||||
void AddExtraProjectile(CNetObj_Projectile *pProj);
|
void AddExtraProjectile(CNetObj_Projectile *pProj);
|
||||||
|
|
||||||
void ReconstructSmokeTrail(const CNetObj_Projectile *pCurrent, int ItemID, int DestroyTick);
|
void ReconstructSmokeTrail(const CProjectileData *pCurrent, int DestroyTick);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
|
|
||||||
#include "race.h"
|
#include "race.h"
|
||||||
#include "render.h"
|
#include "render.h"
|
||||||
#include <game/extrainfo.h>
|
|
||||||
#include <game/localization.h>
|
#include <game/localization.h>
|
||||||
#include <game/version.h>
|
#include <game/version.h>
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
|
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
|
||||||
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
||||||
#include "projectile.h"
|
#include "projectile.h"
|
||||||
|
#include <game/client/projectile_data.h>
|
||||||
#include <game/generated/protocol.h>
|
#include <game/generated/protocol.h>
|
||||||
|
|
||||||
#include <engine/shared/config.h>
|
#include <engine/shared/config.h>
|
||||||
|
@ -150,16 +151,23 @@ void CProjectile::SetBouncing(int Value)
|
||||||
m_Bouncing = Value;
|
m_Bouncing = Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
CProjectile::CProjectile(CGameWorld *pGameWorld, int ID, CNetObj_Projectile *pProj) :
|
CProjectile::CProjectile(CGameWorld *pGameWorld, int ID, CProjectileData *pProj) :
|
||||||
CEntity(pGameWorld, CGameWorld::ENTTYPE_PROJECTILE)
|
CEntity(pGameWorld, CGameWorld::ENTTYPE_PROJECTILE)
|
||||||
{
|
{
|
||||||
ExtractInfo(pProj, &m_Pos, &m_Direction);
|
m_Pos = pProj->m_StartPos;
|
||||||
if(UseExtraInfo(pProj))
|
m_Direction = pProj->m_StartVel;
|
||||||
ExtractExtraInfo(pProj, &m_Owner, &m_Explosive, &m_Bouncing, &m_Freeze);
|
if(pProj->m_ExtraInfo)
|
||||||
|
{
|
||||||
|
m_Owner = pProj->m_Owner;
|
||||||
|
m_Explosive = pProj->m_Explosive;
|
||||||
|
m_Bouncing = pProj->m_Bouncing;
|
||||||
|
m_Freeze = pProj->m_Freeze;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_Owner = -1;
|
m_Owner = -1;
|
||||||
m_Bouncing = m_Freeze = 0;
|
m_Bouncing = 0;
|
||||||
|
m_Freeze = 0;
|
||||||
m_Explosive = (pProj->m_Type == WEAPON_GRENADE) && (fabs(1.0f - length(m_Direction)) < 0.015f);
|
m_Explosive = (pProj->m_Type == WEAPON_GRENADE) && (fabs(1.0f - length(m_Direction)) < 0.015f);
|
||||||
}
|
}
|
||||||
m_Type = pProj->m_Type;
|
m_Type = pProj->m_Type;
|
||||||
|
@ -181,45 +189,19 @@ CProjectile::CProjectile(CGameWorld *pGameWorld, int ID, CNetObj_Projectile *pPr
|
||||||
m_ID = ID;
|
m_ID = ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CProjectile::FillInfo(CNetObj_Projectile *pProj)
|
CProjectileData CProjectile::GetData() const
|
||||||
{
|
{
|
||||||
pProj->m_X = (int)m_Pos.x;
|
CProjectileData Result;
|
||||||
pProj->m_Y = (int)m_Pos.y;
|
Result.m_StartPos = m_Pos;
|
||||||
pProj->m_VelX = (int)(m_Direction.x * 100.0f);
|
Result.m_StartVel = m_Direction;
|
||||||
pProj->m_VelY = (int)(m_Direction.y * 100.0f);
|
Result.m_Type = m_Type;
|
||||||
pProj->m_StartTick = m_StartTick;
|
Result.m_StartTick = m_StartTick;
|
||||||
pProj->m_Type = m_Type;
|
Result.m_ExtraInfo = true;
|
||||||
}
|
Result.m_Owner = m_Owner;
|
||||||
|
Result.m_Explosive = m_Explosive;
|
||||||
void CProjectile::FillExtraInfo(CNetObj_Projectile *pProj)
|
Result.m_Bouncing = m_Bouncing;
|
||||||
{
|
Result.m_Freeze = m_Freeze;
|
||||||
const int MaxPos = 0x7fffffff / 100;
|
return Result;
|
||||||
if(abs((int)m_Pos.y) + 1 >= MaxPos || abs((int)m_Pos.x) + 1 >= MaxPos)
|
|
||||||
{
|
|
||||||
//If the modified data would be too large to fit in an integer, send normal data instead
|
|
||||||
FillInfo(pProj);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
//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) << 0;
|
|
||||||
if(m_Owner < 0)
|
|
||||||
Data |= 1 << 8;
|
|
||||||
Data |= 1 << 9; //This bit tells the client to use the extra info
|
|
||||||
Data |= (m_Bouncing & 3) << 10;
|
|
||||||
if(m_Explosive)
|
|
||||||
Data |= 1 << 12;
|
|
||||||
if(m_Freeze)
|
|
||||||
Data |= 1 << 13;
|
|
||||||
|
|
||||||
pProj->m_X = (int)(m_Pos.x * 100.0f);
|
|
||||||
pProj->m_Y = (int)(m_Pos.y * 100.0f);
|
|
||||||
pProj->m_VelX = (int)(Angle * 1000000.0f);
|
|
||||||
pProj->m_VelY = Data;
|
|
||||||
pProj->m_StartTick = m_StartTick;
|
|
||||||
pProj->m_Type = m_Type;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CProjectile::Match(CProjectile *pProj)
|
bool CProjectile::Match(CProjectile *pProj)
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
|
|
||||||
#include "character.h"
|
#include "character.h"
|
||||||
#include <game/client/prediction/entity.h>
|
#include <game/client/prediction/entity.h>
|
||||||
#include <game/extrainfo.h>
|
|
||||||
|
class CProjectileData;
|
||||||
|
|
||||||
class CProjectile : public CEntity
|
class CProjectile : public CEntity
|
||||||
{
|
{
|
||||||
|
@ -28,18 +29,17 @@ public:
|
||||||
int Number = 0);
|
int Number = 0);
|
||||||
|
|
||||||
vec2 GetPos(float Time);
|
vec2 GetPos(float Time);
|
||||||
void FillInfo(CNetObj_Projectile *pProj);
|
CProjectileData GetData() const;
|
||||||
|
|
||||||
virtual void Tick();
|
virtual void Tick();
|
||||||
|
|
||||||
bool Match(CProjectile *pProj);
|
bool Match(CProjectile *pProj);
|
||||||
void SetBouncing(int Value);
|
void SetBouncing(int Value);
|
||||||
void FillExtraInfo(CNetObj_Projectile *pProj);
|
|
||||||
|
|
||||||
const vec2 &GetDirection() { return m_Direction; }
|
const vec2 &GetDirection() { return m_Direction; }
|
||||||
const int &GetOwner() { return m_Owner; }
|
const int &GetOwner() { return m_Owner; }
|
||||||
const int &GetStartTick() { return m_StartTick; }
|
const int &GetStartTick() { return m_StartTick; }
|
||||||
CProjectile(CGameWorld *pGameWorld, int ID, CNetObj_Projectile *pProj);
|
CProjectile(CGameWorld *pGameWorld, int ID, CProjectileData *pProj);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
vec2 m_Direction;
|
vec2 m_Direction;
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "entity.h"
|
#include "entity.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <engine/shared/config.h>
|
#include <engine/shared/config.h>
|
||||||
|
#include <game/client/projectile_data.h>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
//////////////////////////////////////////////////
|
//////////////////////////////////////////////////
|
||||||
|
@ -368,9 +369,18 @@ void CGameWorld::NetCharAdd(int ObjID, CNetObj_Character *pCharObj, CNetObj_DDNe
|
||||||
|
|
||||||
void CGameWorld::NetObjAdd(int ObjID, int ObjType, const void *pObjData)
|
void CGameWorld::NetObjAdd(int ObjID, int ObjType, const void *pObjData)
|
||||||
{
|
{
|
||||||
if(ObjType == NETOBJTYPE_PROJECTILE && m_WorldConfig.m_PredictWeapons)
|
if((ObjType == NETOBJTYPE_PROJECTILE || ObjType == NETOBJTYPE_DDNETPROJECTILE) && m_WorldConfig.m_PredictWeapons)
|
||||||
{
|
{
|
||||||
CProjectile NetProj = CProjectile(this, ObjID, (CNetObj_Projectile *)pObjData);
|
CProjectileData Data;
|
||||||
|
if(ObjType == NETOBJTYPE_PROJECTILE)
|
||||||
|
{
|
||||||
|
Data = ExtractProjectileInfo((const CNetObj_Projectile *)pObjData);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Data = ExtractProjectileInfoDDNet((const CNetObj_DDNetProjectile *)pObjData);
|
||||||
|
}
|
||||||
|
CProjectile NetProj = CProjectile(this, ObjID, &Data);
|
||||||
|
|
||||||
if(NetProj.m_Type != WEAPON_SHOTGUN && fabs(length(NetProj.m_Direction) - 1.f) > 0.02f) // workaround to skip grenades on ball mod
|
if(NetProj.m_Type != WEAPON_SHOTGUN && fabs(length(NetProj.m_Direction) - 1.f) > 0.02f) // workaround to skip grenades on ball mod
|
||||||
return;
|
return;
|
||||||
|
@ -385,7 +395,7 @@ void CGameWorld::NetObjAdd(int ObjID, int ObjType, const void *pObjData)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!UseExtraInfo((CNetObj_Projectile *)pObjData))
|
if(!Data.m_ExtraInfo)
|
||||||
{
|
{
|
||||||
// try to match the newly received (unrecognized) projectile with a locally fired one
|
// try to match the newly received (unrecognized) projectile with a locally fired one
|
||||||
for(CProjectile *pProj = (CProjectile *)FindFirst(CGameWorld::ENTTYPE_PROJECTILE); pProj; pProj = (CProjectile *)pProj->TypeNext())
|
for(CProjectile *pProj = (CProjectile *)FindFirst(CGameWorld::ENTTYPE_PROJECTILE); pProj; pProj = (CProjectile *)pProj->TypeNext())
|
||||||
|
@ -570,7 +580,25 @@ CEntity *CGameWorld::FindMatch(int ObjID, int ObjType, const void *pObjData)
|
||||||
switch(ObjType)
|
switch(ObjType)
|
||||||
{
|
{
|
||||||
case NETOBJTYPE_CHARACTER: FindType(ENTTYPE_CHARACTER, CCharacter, CNetObj_Character);
|
case NETOBJTYPE_CHARACTER: FindType(ENTTYPE_CHARACTER, CCharacter, CNetObj_Character);
|
||||||
case NETOBJTYPE_PROJECTILE: FindType(ENTTYPE_PROJECTILE, CProjectile, CNetObj_Projectile);
|
case NETOBJTYPE_PROJECTILE:
|
||||||
|
case NETOBJTYPE_DDNETPROJECTILE:
|
||||||
|
{
|
||||||
|
CProjectileData Data;
|
||||||
|
if(ObjType == NETOBJTYPE_PROJECTILE)
|
||||||
|
{
|
||||||
|
Data = ExtractProjectileInfo((const CNetObj_Projectile *)pObjData);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Data = ExtractProjectileInfoDDNet((const CNetObj_DDNetProjectile *)pObjData);
|
||||||
|
}
|
||||||
|
CProjectile *pEnt = (CProjectile *)GetEntity(ObjID, ENTTYPE_PROJECTILE);
|
||||||
|
if(pEnt && CProjectile(this, ObjID, &Data).Match(pEnt))
|
||||||
|
{
|
||||||
|
return pEnt;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
case NETOBJTYPE_LASER: FindType(ENTTYPE_LASER, CLaser, CNetObj_Laser);
|
case NETOBJTYPE_LASER: FindType(ENTTYPE_LASER, CLaser, CNetObj_Laser);
|
||||||
case NETOBJTYPE_PICKUP: FindType(ENTTYPE_PICKUP, CPickup, CNetObj_Pickup);
|
case NETOBJTYPE_PICKUP: FindType(ENTTYPE_PICKUP, CPickup, CNetObj_Pickup);
|
||||||
}
|
}
|
||||||
|
|
80
src/game/client/projectile_data.cpp
Normal file
80
src/game/client/projectile_data.cpp
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
|
||||||
|
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
||||||
|
|
||||||
|
#include "projectile_data.h"
|
||||||
|
|
||||||
|
#include <base/math.h>
|
||||||
|
#include <engine/shared/snapshot.h>
|
||||||
|
#include <game/generated/protocol.h>
|
||||||
|
|
||||||
|
bool UseProjectileExtraInfo(const CNetObj_Projectile *pProj)
|
||||||
|
{
|
||||||
|
return pProj->m_VelY >= 0 && (pProj->m_VelY & PROJECTILEFLAG_IS_DDNET) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
CProjectileData ExtractProjectileInfo(const CNetObj_Projectile *pProj)
|
||||||
|
{
|
||||||
|
if(UseProjectileExtraInfo(pProj))
|
||||||
|
{
|
||||||
|
CNetObj_DDNetProjectile Proj;
|
||||||
|
mem_copy(&Proj, pProj, sizeof(Proj));
|
||||||
|
return ExtractProjectileInfoDDNet(&Proj);
|
||||||
|
}
|
||||||
|
|
||||||
|
CProjectileData Result = {vec2(0, 0)};
|
||||||
|
Result.m_StartPos.x = pProj->m_X;
|
||||||
|
Result.m_StartPos.y = pProj->m_Y;
|
||||||
|
Result.m_StartVel.x = pProj->m_VelX / 100.0f;
|
||||||
|
Result.m_StartVel.y = pProj->m_VelY / 100.0f;
|
||||||
|
Result.m_Type = pProj->m_Type;
|
||||||
|
Result.m_StartTick = pProj->m_StartTick;
|
||||||
|
Result.m_ExtraInfo = false;
|
||||||
|
Result.m_Owner = -1;
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
CProjectileData ExtractProjectileInfoDDNet(const CNetObj_DDNetProjectile *pProj)
|
||||||
|
{
|
||||||
|
CProjectileData Result = {vec2(0, 0)};
|
||||||
|
|
||||||
|
Result.m_StartPos.x = pProj->m_X / 100.0f;
|
||||||
|
Result.m_StartPos.y = pProj->m_Y / 100.0f;
|
||||||
|
float Angle = pProj->m_Angle / 1000000.0f;
|
||||||
|
Result.m_StartVel.x = sin(-Angle);
|
||||||
|
Result.m_StartVel.y = cos(-Angle);
|
||||||
|
Result.m_Type = pProj->m_Type;
|
||||||
|
Result.m_StartTick = pProj->m_StartTick;
|
||||||
|
|
||||||
|
Result.m_ExtraInfo = true;
|
||||||
|
Result.m_Owner = pProj->m_Data & 255;
|
||||||
|
if((pProj->m_Data & PROJECTILEFLAG_NO_OWNER) & 1)
|
||||||
|
{
|
||||||
|
Result.m_Owner = -1;
|
||||||
|
}
|
||||||
|
// PROJECTILEFLAG_BOUNCE_HORIZONTAL, PROJECTILEFLAG_BOUNCE_VERTICAL
|
||||||
|
Result.m_Bouncing = (pProj->m_Data >> 10) & 3;
|
||||||
|
Result.m_Explosive = pProj->m_Data & PROJECTILEFLAG_EXPLOSIVE;
|
||||||
|
Result.m_Freeze = pProj->m_Data & PROJECTILEFLAG_FREEZE;
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SnapshotRemoveExtraProjectileInfo(unsigned char *pData)
|
||||||
|
{
|
||||||
|
CSnapshot *pSnap = (CSnapshot *)pData;
|
||||||
|
for(int Index = 0; Index < pSnap->NumItems(); Index++)
|
||||||
|
{
|
||||||
|
CSnapshotItem *pItem = pSnap->GetItem(Index);
|
||||||
|
if(pItem->Type() == NETOBJTYPE_PROJECTILE)
|
||||||
|
{
|
||||||
|
CNetObj_Projectile *pProj = (CNetObj_Projectile *)((void *)pItem->Data());
|
||||||
|
if(UseProjectileExtraInfo(pProj))
|
||||||
|
{
|
||||||
|
CProjectileData Data = ExtractProjectileInfo(pProj);
|
||||||
|
pProj->m_X = Data.m_StartPos.x;
|
||||||
|
pProj->m_Y = Data.m_StartPos.y;
|
||||||
|
pProj->m_VelX = (int)(Data.m_StartVel.x * 100.0f);
|
||||||
|
pProj->m_VelY = (int)(Data.m_StartVel.y * 100.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
29
src/game/client/projectile_data.h
Normal file
29
src/game/client/projectile_data.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
|
||||||
|
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
||||||
|
#ifndef GAME_CLIENT_PROJECTILE_DATA_H
|
||||||
|
#define GAME_CLIENT_PROJECTILE_DATA_H
|
||||||
|
|
||||||
|
#include <base/vmath.h>
|
||||||
|
|
||||||
|
struct CNetObj_Projectile;
|
||||||
|
struct CNetObj_DDNetProjectile;
|
||||||
|
|
||||||
|
class CProjectileData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
vec2 m_StartPos;
|
||||||
|
vec2 m_StartVel;
|
||||||
|
int m_Type;
|
||||||
|
int m_StartTick;
|
||||||
|
bool m_ExtraInfo;
|
||||||
|
// The rest is only set if m_ExtraInfo is true.
|
||||||
|
int m_Owner;
|
||||||
|
bool m_Explosive;
|
||||||
|
int m_Bouncing;
|
||||||
|
bool m_Freeze;
|
||||||
|
};
|
||||||
|
|
||||||
|
CProjectileData ExtractProjectileInfo(const CNetObj_Projectile *pProj);
|
||||||
|
CProjectileData ExtractProjectileInfoDDNet(const CNetObj_DDNetProjectile *pProj);
|
||||||
|
|
||||||
|
#endif // GAME_CLIENT_PROJECTILE_DATA_H
|
|
@ -1,72 +0,0 @@
|
||||||
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
|
|
||||||
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
|
||||||
|
|
||||||
#include "extrainfo.h"
|
|
||||||
#include <base/math.h>
|
|
||||||
#include <engine/shared/snapshot.h>
|
|
||||||
#include <game/generated/protocol.h>
|
|
||||||
|
|
||||||
bool UseExtraInfo(const CNetObj_Projectile *pProj)
|
|
||||||
{
|
|
||||||
bool ExtraInfoFlag = ((abs(pProj->m_VelY) & (1 << 9)) != 0);
|
|
||||||
return ExtraInfoFlag;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExtractInfo(const CNetObj_Projectile *pProj, vec2 *StartPos, vec2 *StartVel)
|
|
||||||
{
|
|
||||||
if(!UseExtraInfo(pProj))
|
|
||||||
{
|
|
||||||
StartPos->x = pProj->m_X;
|
|
||||||
StartPos->y = pProj->m_Y;
|
|
||||||
StartVel->x = pProj->m_VelX / 100.0f;
|
|
||||||
StartVel->y = pProj->m_VelY / 100.0f;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
StartPos->x = pProj->m_X / 100.0f;
|
|
||||||
StartPos->y = pProj->m_Y / 100.0f;
|
|
||||||
float Angle = pProj->m_VelX / 1000000.0f;
|
|
||||||
StartVel->x = sin(-Angle);
|
|
||||||
StartVel->y = cos(-Angle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExtractExtraInfo(const CNetObj_Projectile *pProj, int *Owner, bool *Explosive, int *Bouncing, bool *Freeze)
|
|
||||||
{
|
|
||||||
int Data = pProj->m_VelY;
|
|
||||||
if(Owner)
|
|
||||||
{
|
|
||||||
*Owner = Data & 255;
|
|
||||||
if((Data >> 8) & 1)
|
|
||||||
*Owner = -(*Owner);
|
|
||||||
}
|
|
||||||
if(Bouncing)
|
|
||||||
*Bouncing = (Data >> 10) & 3;
|
|
||||||
if(Explosive)
|
|
||||||
*Explosive = (Data >> 12) & 1;
|
|
||||||
if(Freeze)
|
|
||||||
*Freeze = (Data >> 13) & 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SnapshotRemoveExtraInfo(unsigned char *pData)
|
|
||||||
{
|
|
||||||
CSnapshot *pSnap = (CSnapshot *)pData;
|
|
||||||
for(int Index = 0; Index < pSnap->NumItems(); Index++)
|
|
||||||
{
|
|
||||||
CSnapshotItem *pItem = pSnap->GetItem(Index);
|
|
||||||
if(pItem->Type() == NETOBJTYPE_PROJECTILE)
|
|
||||||
{
|
|
||||||
CNetObj_Projectile *pProj = (CNetObj_Projectile *)((void *)pItem->Data());
|
|
||||||
if(UseExtraInfo(pProj))
|
|
||||||
{
|
|
||||||
vec2 Pos;
|
|
||||||
vec2 Vel;
|
|
||||||
ExtractInfo(pProj, &Pos, &Vel);
|
|
||||||
pProj->m_X = Pos.x;
|
|
||||||
pProj->m_Y = Pos.y;
|
|
||||||
pProj->m_VelX = (int)(Vel.x * 100.0f);
|
|
||||||
pProj->m_VelY = (int)(Vel.y * 100.0f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
|
|
||||||
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
|
||||||
#ifndef GAME_EXTRAINFO_H
|
|
||||||
#define GAME_EXTRAINFO_H
|
|
||||||
|
|
||||||
#include <game/generated/protocol.h>
|
|
||||||
|
|
||||||
#include <base/vmath.h>
|
|
||||||
|
|
||||||
bool UseExtraInfo(const CNetObj_Projectile *pProj);
|
|
||||||
void ExtractInfo(const CNetObj_Projectile *pProj, vec2 *StartPos, vec2 *StartVel);
|
|
||||||
void ExtractExtraInfo(const CNetObj_Projectile *pProj, int *Owner, bool *Explosive, int *Bouncing, bool *Freeze);
|
|
||||||
void SnapshotRemoveExtraInfo(unsigned char *pData);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <game/server/gamecontext.h>
|
#include <game/server/gamecontext.h>
|
||||||
#include <game/server/gamemodes/DDRace.h>
|
#include <game/server/gamemodes/DDRace.h>
|
||||||
#include <game/server/player.h>
|
#include <game/server/player.h>
|
||||||
|
#include <game/version.h>
|
||||||
|
|
||||||
#include <engine/shared/config.h>
|
#include <engine/shared/config.h>
|
||||||
#include <game/server/teams.h>
|
#include <game/server/teams.h>
|
||||||
|
@ -319,12 +320,26 @@ void CProjectile::Snap(int SnappingClient)
|
||||||
if(m_Owner != -1 && !CmaskIsSet(TeamMask, SnappingClient))
|
if(m_Owner != -1 && !CmaskIsSet(TeamMask, SnappingClient))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
CNetObj_Projectile *pProj = static_cast<CNetObj_Projectile *>(Server()->SnapNewItem(NETOBJTYPE_PROJECTILE, GetID(), sizeof(CNetObj_Projectile)));
|
int SnappingClientVersion = SnappingClient >= 0 ? GameServer()->GetClientVersion(SnappingClient) : CLIENT_VERSIONNR;
|
||||||
if(pProj)
|
|
||||||
|
CNetObj_DDNetProjectile DDNetProjectile;
|
||||||
|
if(SnappingClientVersion >= VERSION_DDNET_ANTIPING_PROJECTILE && FillExtraInfo(&DDNetProjectile))
|
||||||
{
|
{
|
||||||
if(SnappingClient > -1 && GameServer()->m_apPlayers[SnappingClient] && GameServer()->m_apPlayers[SnappingClient]->GetClientVersion() >= VERSION_DDNET_ANTIPING_PROJECTILE)
|
int Type = SnappingClientVersion <= VERSION_DDNET_MSG_LEGACY ? (int)NETOBJTYPE_PROJECTILE : NETOBJTYPE_DDNETPROJECTILE;
|
||||||
FillExtraInfo(pProj);
|
void *pProj = Server()->SnapNewItem(Type, GetID(), sizeof(DDNetProjectile));
|
||||||
|
if(!pProj)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mem_copy(pProj, &DDNetProjectile, sizeof(DDNetProjectile));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
CNetObj_Projectile *pProj = static_cast<CNetObj_Projectile *>(Server()->SnapNewItem(NETOBJTYPE_PROJECTILE, GetID(), sizeof(CNetObj_Projectile)));
|
||||||
|
if(!pProj)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
FillInfo(pProj);
|
FillInfo(pProj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -336,14 +351,13 @@ void CProjectile::SetBouncing(int Value)
|
||||||
m_Bouncing = Value;
|
m_Bouncing = Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CProjectile::FillExtraInfo(CNetObj_Projectile *pProj)
|
bool CProjectile::FillExtraInfo(CNetObj_DDNetProjectile *pProj)
|
||||||
{
|
{
|
||||||
const int MaxPos = 0x7fffffff / 100;
|
const int MaxPos = 0x7fffffff / 100;
|
||||||
if(abs((int)m_Pos.y) + 1 >= MaxPos || abs((int)m_Pos.x) + 1 >= MaxPos)
|
if(abs((int)m_Pos.y) + 1 >= MaxPos || abs((int)m_Pos.x) + 1 >= MaxPos)
|
||||||
{
|
{
|
||||||
//If the modified data would be too large to fit in an integer, send normal data instead
|
//If the modified data would be too large to fit in an integer, send normal data instead
|
||||||
FillInfo(pProj);
|
return false;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
//Send additional/modified info, by modifiying the fields of the netobj
|
//Send additional/modified info, by modifiying the fields of the netobj
|
||||||
float Angle = -atan2f(m_Direction.x, m_Direction.y);
|
float Angle = -atan2f(m_Direction.x, m_Direction.y);
|
||||||
|
@ -351,18 +365,21 @@ void CProjectile::FillExtraInfo(CNetObj_Projectile *pProj)
|
||||||
int Data = 0;
|
int Data = 0;
|
||||||
Data |= (abs(m_Owner) & 255) << 0;
|
Data |= (abs(m_Owner) & 255) << 0;
|
||||||
if(m_Owner < 0)
|
if(m_Owner < 0)
|
||||||
Data |= 1 << 8;
|
Data |= PROJECTILEFLAG_NO_OWNER;
|
||||||
Data |= 1 << 9; //This bit tells the client to use the extra info
|
//This bit tells the client to use the extra info
|
||||||
|
Data |= PROJECTILEFLAG_IS_DDNET;
|
||||||
|
// PROJECTILEFLAG_BOUNCE_HORIZONTAL, PROJECTILEFLAG_BOUNCE_VERTICAL
|
||||||
Data |= (m_Bouncing & 3) << 10;
|
Data |= (m_Bouncing & 3) << 10;
|
||||||
if(m_Explosive)
|
if(m_Explosive)
|
||||||
Data |= 1 << 12;
|
Data |= PROJECTILEFLAG_EXPLOSIVE;
|
||||||
if(m_Freeze)
|
if(m_Freeze)
|
||||||
Data |= 1 << 13;
|
Data |= PROJECTILEFLAG_FREEZE;
|
||||||
|
|
||||||
pProj->m_X = (int)(m_Pos.x * 100.0f);
|
pProj->m_X = (int)(m_Pos.x * 100.0f);
|
||||||
pProj->m_Y = (int)(m_Pos.y * 100.0f);
|
pProj->m_Y = (int)(m_Pos.y * 100.0f);
|
||||||
pProj->m_VelX = (int)(Angle * 1000000.0f);
|
pProj->m_Angle = (int)(Angle * 1000000.0f);
|
||||||
pProj->m_VelY = Data;
|
pProj->m_Data = Data;
|
||||||
pProj->m_StartTick = m_StartTick;
|
pProj->m_StartTick = m_StartTick;
|
||||||
pProj->m_Type = m_Type;
|
pProj->m_Type = m_Type;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void SetBouncing(int Value);
|
void SetBouncing(int Value);
|
||||||
void FillExtraInfo(CNetObj_Projectile *pProj);
|
bool FillExtraInfo(CNetObj_DDNetProjectile *pProj);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue