mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-17 13:38:18 +00:00
Render skins in 0.7 demos
This commit is contained in:
parent
be67622544
commit
8903f49716
|
@ -2427,6 +2427,7 @@ if(CLIENT)
|
|||
render.h
|
||||
render_map.cpp
|
||||
sixup_translate_game.cpp
|
||||
sixup_translate_snapshot.cpp
|
||||
skin.h
|
||||
ui.cpp
|
||||
ui.h
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include <game/generated/protocol7.h>
|
||||
|
||||
#include <engine/friends.h>
|
||||
#include <engine/shared/snapshot.h>
|
||||
#include <functional>
|
||||
|
||||
#include <engine/client/enums.h>
|
||||
|
@ -374,6 +373,7 @@ public:
|
|||
virtual const char *GetItemName(int Type) const = 0;
|
||||
virtual const char *Version() const = 0;
|
||||
virtual const char *NetVersion() const = 0;
|
||||
virtual const char *NetVersion7() const = 0;
|
||||
virtual int DDNetVersion() const = 0;
|
||||
virtual const char *DDNetVersionStr() const = 0;
|
||||
|
||||
|
@ -388,9 +388,13 @@ public:
|
|||
virtual protocol7::CNetObjHandler *GetNetObjHandler7() = 0;
|
||||
|
||||
virtual int ClientVersion7() const = 0;
|
||||
|
||||
virtual void ApplySkin7InfoFromSnapObj(const protocol7::CNetObj_De_ClientInfo *pObj, int ClientId) = 0;
|
||||
virtual int OnDemoRecSnap7(class CSnapshot *pFrom, class CSnapshot *pTo, int Conn) = 0;
|
||||
virtual int TranslateSnap(class CSnapshot *pSnapDstSix, class CSnapshot *pSnapSrcSeven, int Conn, bool Dummy) = 0;
|
||||
};
|
||||
|
||||
void SnapshotRemoveExtraProjectileInfo(CSnapshot *pSnap);
|
||||
void SnapshotRemoveExtraProjectileInfo(class CSnapshot *pSnap);
|
||||
|
||||
extern IGameClient *CreateGameClient();
|
||||
#endif
|
||||
|
|
|
@ -1988,15 +1988,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket, int Conn, bool Dummy)
|
|||
unsigned char aTmpTransSnapBuffer[CSnapshot::MAX_SIZE];
|
||||
CSnapshot *pTmpTransSnapBuffer = (CSnapshot *)aTmpTransSnapBuffer;
|
||||
mem_copy(pTmpTransSnapBuffer, pTmpBuffer3, CSnapshot::MAX_SIZE);
|
||||
AltSnapSize = pTmpTransSnapBuffer->TranslateSevenToSix(
|
||||
pAltSnapBuffer,
|
||||
m_TranslationContext,
|
||||
LocalTime(),
|
||||
CClient::GameTick(g_Config.m_ClDummy),
|
||||
Conn,
|
||||
Dummy,
|
||||
GameClient()->GetNetObjHandler7(),
|
||||
GameClient()->GetNetObjHandler());
|
||||
AltSnapSize = GameClient()->TranslateSnap(pAltSnapBuffer, pTmpTransSnapBuffer, Conn, Dummy);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2017,13 +2009,26 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket, int Conn, bool Dummy)
|
|||
// for antiping: if the projectile netobjects from the server contains extra data, this is removed and the original content restored before recording demo
|
||||
SnapshotRemoveExtraProjectileInfo(pTmpBuffer3);
|
||||
|
||||
unsigned char aSnapSeven[CSnapshot::MAX_SIZE];
|
||||
CSnapshot *pSnapSeven = (CSnapshot *)aSnapSeven;
|
||||
int DemoSnapSize = SnapSize;
|
||||
if(IsSixup())
|
||||
{
|
||||
DemoSnapSize = GameClient()->OnDemoRecSnap7(pTmpBuffer3, pSnapSeven, Conn);
|
||||
if(DemoSnapSize < 0)
|
||||
{
|
||||
dbg_msg("sixup", "demo snapshot failed. error=%d", DemoSnapSize);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// add snapshot to demo
|
||||
for(auto &DemoRecorder : m_aDemoRecorder)
|
||||
{
|
||||
if(DemoRecorder.IsRecording())
|
||||
{
|
||||
// write snapshot
|
||||
DemoRecorder.RecordSnapshot(GameTick, pTmpBuffer3, SnapSize);
|
||||
DemoRecorder.RecordSnapshot(GameTick, IsSixup() ? pSnapSeven : pTmpBuffer3, DemoSnapSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2524,25 +2529,24 @@ void CClient::OnDemoPlayerSnapshot(void *pData, int Size)
|
|||
// create a verified and unpacked snapshot
|
||||
unsigned char aAltSnapBuffer[CSnapshot::MAX_SIZE];
|
||||
CSnapshot *pAltSnapBuffer = (CSnapshot *)aAltSnapBuffer;
|
||||
const int AltSnapSize = UnpackAndValidateSnapshot((CSnapshot *)pData, pAltSnapBuffer);
|
||||
if(AltSnapSize < 0)
|
||||
{
|
||||
dbg_msg("client", "unpack snapshot and validate failed. error=%d", AltSnapSize);
|
||||
return;
|
||||
}
|
||||
int AltSnapSize;
|
||||
|
||||
unsigned char aTmpTranslateBuffer[CSnapshot::MAX_SIZE];
|
||||
CSnapshot *pTmpTranslateBuffer = nullptr;
|
||||
int TranslatedSize = 0;
|
||||
if(IsSixup())
|
||||
{
|
||||
pTmpTranslateBuffer = (CSnapshot *)aTmpTranslateBuffer;
|
||||
TranslatedSize = ((CSnapshot *)pData)->TranslateSevenToSix(pTmpTranslateBuffer, m_TranslationContext, LocalTime(), GameTick(g_Config.m_ClDummy), CONN_MAIN, false, GameClient()->GetNetObjHandler7(), GameClient()->GetNetObjHandler());
|
||||
if(TranslatedSize < 0)
|
||||
AltSnapSize = GameClient()->TranslateSnap(pAltSnapBuffer, (CSnapshot *)pData, CONN_MAIN, false);
|
||||
if(AltSnapSize < 0)
|
||||
{
|
||||
dbg_msg("sixup", "failed to translate snapshot. error=%d", TranslatedSize);
|
||||
pTmpTranslateBuffer = nullptr;
|
||||
TranslatedSize = 0;
|
||||
dbg_msg("sixup", "failed to translate snapshot. error=%d", AltSnapSize);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AltSnapSize = UnpackAndValidateSnapshot((CSnapshot *)pData, pAltSnapBuffer);
|
||||
if(AltSnapSize < 0)
|
||||
{
|
||||
dbg_msg("client", "unpack snapshot and validate failed. error=%d", AltSnapSize);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2551,9 +2555,6 @@ void CClient::OnDemoPlayerSnapshot(void *pData, int Size)
|
|||
mem_copy(m_aapSnapshots[0][SNAP_CURRENT]->m_pSnap, pData, Size);
|
||||
mem_copy(m_aapSnapshots[0][SNAP_CURRENT]->m_pAltSnap, pAltSnapBuffer, AltSnapSize);
|
||||
|
||||
if(pTmpTranslateBuffer && TranslatedSize > 0)
|
||||
mem_copy(m_aapSnapshots[0][SNAP_CURRENT]->m_pAltSnap, pTmpTranslateBuffer, TranslatedSize);
|
||||
|
||||
GameClient()->OnNewSnapshot();
|
||||
}
|
||||
|
||||
|
@ -3916,7 +3917,20 @@ void CClient::DemoRecorder_Start(const char *pFilename, bool WithTimestamp, int
|
|||
str_format(aFilename, sizeof(aFilename), "demos/%s.demo", pFilename);
|
||||
}
|
||||
|
||||
m_aDemoRecorder[Recorder].Start(Storage(), m_pConsole, aFilename, GameClient()->NetVersion(), m_aCurrentMap, m_pMap->Sha256(), m_pMap->Crc(), "client", m_pMap->MapSize(), 0, m_pMap->File());
|
||||
m_aDemoRecorder[Recorder].Start(
|
||||
Storage(),
|
||||
m_pConsole,
|
||||
aFilename,
|
||||
IsSixup() ? GameClient()->NetVersion7() : GameClient()->NetVersion(),
|
||||
m_aCurrentMap,
|
||||
m_pMap->Sha256(),
|
||||
m_pMap->Crc(),
|
||||
"client",
|
||||
m_pMap->MapSize(),
|
||||
0,
|
||||
m_pMap->File(),
|
||||
nullptr,
|
||||
nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4880,7 +4894,20 @@ void CClient::RaceRecord_Start(const char *pFilename)
|
|||
if(State() != IClient::STATE_ONLINE)
|
||||
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "demorec/record", "client is not online");
|
||||
else
|
||||
m_aDemoRecorder[RECORDER_RACE].Start(Storage(), m_pConsole, pFilename, GameClient()->NetVersion(), m_aCurrentMap, m_pMap->Sha256(), m_pMap->Crc(), "client", m_pMap->MapSize(), 0, m_pMap->File());
|
||||
m_aDemoRecorder[RECORDER_RACE].Start(
|
||||
Storage(),
|
||||
m_pConsole,
|
||||
pFilename,
|
||||
IsSixup() ? GameClient()->NetVersion7() : GameClient()->NetVersion(),
|
||||
m_aCurrentMap,
|
||||
m_pMap->Sha256(),
|
||||
m_pMap->Crc(),
|
||||
"client",
|
||||
m_pMap->MapSize(),
|
||||
0,
|
||||
m_pMap->File(),
|
||||
nullptr,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
void CClient::RaceRecord_Stop()
|
||||
|
|
|
@ -3375,7 +3375,20 @@ void CServer::DemoRecorder_HandleAutoStart()
|
|||
str_timestamp(aTimestamp, sizeof(aTimestamp));
|
||||
char aFilename[IO_MAX_PATH_LENGTH];
|
||||
str_format(aFilename, sizeof(aFilename), "demos/auto/server/%s_%s.demo", m_aCurrentMap, aTimestamp);
|
||||
m_aDemoRecorder[RECORDER_AUTO].Start(Storage(), m_pConsole, aFilename, GameServer()->NetVersion(), m_aCurrentMap, m_aCurrentMapSha256[MAP_TYPE_SIX], m_aCurrentMapCrc[MAP_TYPE_SIX], "server", m_aCurrentMapSize[MAP_TYPE_SIX], m_apCurrentMapData[MAP_TYPE_SIX]);
|
||||
m_aDemoRecorder[RECORDER_AUTO].Start(
|
||||
Storage(),
|
||||
m_pConsole,
|
||||
aFilename,
|
||||
GameServer()->NetVersion(),
|
||||
m_aCurrentMap,
|
||||
m_aCurrentMapSha256[MAP_TYPE_SIX],
|
||||
m_aCurrentMapCrc[MAP_TYPE_SIX],
|
||||
"server",
|
||||
m_aCurrentMapSize[MAP_TYPE_SIX],
|
||||
m_apCurrentMapData[MAP_TYPE_SIX],
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr);
|
||||
|
||||
if(Config()->m_SvAutoDemoMax)
|
||||
{
|
||||
|
@ -3402,7 +3415,20 @@ void CServer::StartRecord(int ClientId)
|
|||
{
|
||||
char aFilename[IO_MAX_PATH_LENGTH];
|
||||
str_format(aFilename, sizeof(aFilename), "demos/%s_%d_%d_tmp.demo", m_aCurrentMap, m_NetServer.Address().port, ClientId);
|
||||
m_aDemoRecorder[ClientId].Start(Storage(), Console(), aFilename, GameServer()->NetVersion(), m_aCurrentMap, m_aCurrentMapSha256[MAP_TYPE_SIX], m_aCurrentMapCrc[MAP_TYPE_SIX], "server", m_aCurrentMapSize[MAP_TYPE_SIX], m_apCurrentMapData[MAP_TYPE_SIX]);
|
||||
m_aDemoRecorder[ClientId].Start(
|
||||
Storage(),
|
||||
Console(),
|
||||
aFilename,
|
||||
GameServer()->NetVersion(),
|
||||
m_aCurrentMap,
|
||||
m_aCurrentMapSha256[MAP_TYPE_SIX],
|
||||
m_aCurrentMapCrc[MAP_TYPE_SIX],
|
||||
"server",
|
||||
m_aCurrentMapSize[MAP_TYPE_SIX],
|
||||
m_apCurrentMapData[MAP_TYPE_SIX],
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3451,7 +3477,20 @@ void CServer::ConRecord(IConsole::IResult *pResult, void *pUser)
|
|||
str_timestamp(aTimestamp, sizeof(aTimestamp));
|
||||
str_format(aFilename, sizeof(aFilename), "demos/demo_%s.demo", aTimestamp);
|
||||
}
|
||||
pServer->m_aDemoRecorder[RECORDER_MANUAL].Start(pServer->Storage(), pServer->Console(), aFilename, pServer->GameServer()->NetVersion(), pServer->m_aCurrentMap, pServer->m_aCurrentMapSha256[MAP_TYPE_SIX], pServer->m_aCurrentMapCrc[MAP_TYPE_SIX], "server", pServer->m_aCurrentMapSize[MAP_TYPE_SIX], pServer->m_apCurrentMapData[MAP_TYPE_SIX]);
|
||||
pServer->m_aDemoRecorder[RECORDER_MANUAL].Start(
|
||||
pServer->Storage(),
|
||||
pServer->Console(),
|
||||
aFilename,
|
||||
pServer->GameServer()->NetVersion(),
|
||||
pServer->m_aCurrentMap,
|
||||
pServer->m_aCurrentMapSha256[MAP_TYPE_SIX],
|
||||
pServer->m_aCurrentMapCrc[MAP_TYPE_SIX],
|
||||
"server",
|
||||
pServer->m_aCurrentMapSize[MAP_TYPE_SIX],
|
||||
pServer->m_apCurrentMapData[MAP_TYPE_SIX],
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
void CServer::ConStopRecord(IConsole::IResult *pResult, void *pUser)
|
||||
|
|
|
@ -316,6 +316,8 @@ void CDemoRecorder::RecordSnapshot(int Tick, const void *pData, int Size)
|
|||
|
||||
// create delta
|
||||
char aDeltaData[CSnapshot::MAX_SIZE + sizeof(int)];
|
||||
m_pSnapshotDelta->SetStaticsize(protocol7::NETEVENTTYPE_SOUNDWORLD, true);
|
||||
m_pSnapshotDelta->SetStaticsize(protocol7::NETEVENTTYPE_DAMAGE, true);
|
||||
const int DeltaSize = m_pSnapshotDelta->CreateDelta((CSnapshot *)m_aLastSnapshotData, (CSnapshot *)pData, &aDeltaData);
|
||||
if(DeltaSize)
|
||||
{
|
||||
|
|
|
@ -45,7 +45,7 @@ public:
|
|||
CDemoRecorder() {}
|
||||
~CDemoRecorder() override;
|
||||
|
||||
int Start(class IStorage *pStorage, class IConsole *pConsole, const char *pFilename, const char *pNetversion, const char *pMap, const SHA256_DIGEST &Sha256, unsigned MapCrc, const char *pType, unsigned MapSize, unsigned char *pMapData, IOHANDLE MapFile = nullptr, DEMOFUNC_FILTER pfnFilter = nullptr, void *pUser = nullptr);
|
||||
int Start(class IStorage *pStorage, class IConsole *pConsole, const char *pFilename, const char *pNetversion, const char *pMap, const SHA256_DIGEST &Sha256, unsigned MapCrc, const char *pType, unsigned MapSize, unsigned char *pMapData, IOHANDLE MapFile, DEMOFUNC_FILTER pfnFilter, void *pUser);
|
||||
int Stop(IDemoRecorder::EStopMode Mode, const char *pTargetFilename = "") override;
|
||||
|
||||
void AddDemoMarker();
|
||||
|
|
|
@ -1,516 +1,26 @@
|
|||
#include "compression.h"
|
||||
#include "snapshot.h"
|
||||
#include "uuid_manager.h"
|
||||
|
||||
#include <climits>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <base/math.h>
|
||||
#include <base/system.h>
|
||||
|
||||
#include <engine/shared/protocolglue.h>
|
||||
#include <engine/shared/translation_context.h>
|
||||
#include "snapshot.h"
|
||||
|
||||
#include <game/generated/protocol.h>
|
||||
#include <game/generated/protocol7.h>
|
||||
#include <game/generated/protocolglue.h>
|
||||
|
||||
#include <game/gamecore.h>
|
||||
|
||||
int CSnapshot::TranslateSevenToSix(
|
||||
CSnapshot *pSixSnapDest,
|
||||
CTranslationContext &TranslationContext,
|
||||
float LocalTime,
|
||||
int GameTick,
|
||||
int Conn,
|
||||
bool Dummy,
|
||||
protocol7::CNetObjHandler *pNetObjHandler,
|
||||
CNetObjHandler *pNetObjHandler6)
|
||||
void CSnapshotBuilder::Init7(const CSnapshot *pSnapshot)
|
||||
{
|
||||
CSnapshotBuilder Builder;
|
||||
Builder.Init();
|
||||
// the method is called Init7 because it is only used for 0.7 support
|
||||
// but the snap we are building is a 0.6 snap
|
||||
m_Sixup = false;
|
||||
|
||||
for(auto &PlayerInfosRace : TranslationContext.m_apPlayerInfosRace)
|
||||
PlayerInfosRace = nullptr;
|
||||
|
||||
int SpectatorId = -3;
|
||||
|
||||
for(int i = 0; i < m_NumItems; i++)
|
||||
if(pSnapshot->m_DataSize + sizeof(CSnapshot) + pSnapshot->m_NumItems * sizeof(int) * 2 > CSnapshot::MAX_SIZE || pSnapshot->m_NumItems > CSnapshot::MAX_ITEMS)
|
||||
{
|
||||
const CSnapshotItem *pItem7 = (CSnapshotItem *)GetItem(i);
|
||||
const int Size = GetItemSize(i);
|
||||
const int ItemType = GetItemType(i);
|
||||
|
||||
// ddnet ex snap items
|
||||
if((ItemType > __NETOBJTYPE_UUID_HELPER && ItemType < OFFSET_NETMSGTYPE_UUID) || pItem7->Type() == NETOBJTYPE_EX)
|
||||
{
|
||||
CUnpacker Unpacker;
|
||||
Unpacker.Reset(pItem7->Data(), Size);
|
||||
|
||||
void *pRawObj = pNetObjHandler6->SecureUnpackObj(ItemType, &Unpacker);
|
||||
if(!pRawObj)
|
||||
{
|
||||
if(ItemType != UUID_UNKNOWN)
|
||||
dbg_msg("sixup", "dropped weird ddnet ex object '%s' (%d), failed on '%s'", pNetObjHandler6->GetObjName(ItemType), ItemType, pNetObjHandler6->FailedObjOn());
|
||||
continue;
|
||||
}
|
||||
const int ItemSize = pNetObjHandler6->GetUnpackedObjSize(ItemType);
|
||||
|
||||
void *pObj = Builder.NewItem(pItem7->Type(), pItem7->Id(), ItemSize);
|
||||
if(!pObj)
|
||||
return -17;
|
||||
|
||||
mem_copy(pObj, pRawObj, ItemSize);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(pNetObjHandler->ValidateObj(pItem7->Type(), pItem7->Data(), Size) != 0)
|
||||
{
|
||||
if(pItem7->Type() > 0 && pItem7->Type() < OFFSET_UUID_TYPE)
|
||||
{
|
||||
dbg_msg(
|
||||
"sixup",
|
||||
"invalidated index=%d type=%d (%s) size=%d id=%d",
|
||||
i,
|
||||
pItem7->Type(),
|
||||
pNetObjHandler->GetObjName(pItem7->Type()),
|
||||
Size,
|
||||
pItem7->Id());
|
||||
}
|
||||
InvalidateItem(i);
|
||||
}
|
||||
|
||||
if(pItem7->Type() == protocol7::NETOBJTYPE_PLAYERINFORACE)
|
||||
{
|
||||
const protocol7::CNetObj_PlayerInfoRace *pInfo = (const protocol7::CNetObj_PlayerInfoRace *)pItem7->Data();
|
||||
int ClientId = pItem7->Id();
|
||||
if(ClientId < MAX_CLIENTS && TranslationContext.m_aClients[ClientId].m_Active)
|
||||
{
|
||||
TranslationContext.m_apPlayerInfosRace[ClientId] = pInfo;
|
||||
}
|
||||
}
|
||||
else if(pItem7->Type() == protocol7::NETOBJTYPE_SPECTATORINFO)
|
||||
{
|
||||
const protocol7::CNetObj_SpectatorInfo *pSpec7 = (const protocol7::CNetObj_SpectatorInfo *)pItem7->Data();
|
||||
SpectatorId = pSpec7->m_SpectatorId;
|
||||
if(pSpec7->m_SpecMode == protocol7::SPEC_FREEVIEW)
|
||||
SpectatorId = SPEC_FREEVIEW;
|
||||
}
|
||||
// key and offset per item
|
||||
dbg_assert(m_DataSize + sizeof(CSnapshot) + m_NumItems * sizeof(int) * 2 < CSnapshot::MAX_SIZE, "too much data");
|
||||
dbg_assert(m_NumItems < CSnapshot::MAX_ITEMS, "too many items");
|
||||
dbg_msg("sixup", "demo recording failed on invalid snapshot");
|
||||
m_DataSize = 0;
|
||||
m_NumItems = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// hack to put game info in the snap
|
||||
// even though in 0.7 we get it as a game message
|
||||
// this message has to be on the top
|
||||
// the client looks at the items in order and needs the gameinfo at the top
|
||||
// otherwise it will not render skins with team colors
|
||||
if(TranslationContext.m_ShouldSendGameInfo)
|
||||
{
|
||||
void *pObj = Builder.NewItem(NETOBJTYPE_GAMEINFO, 0, sizeof(CNetObj_GameInfo));
|
||||
if(!pObj)
|
||||
return -1;
|
||||
|
||||
int GameStateFlagsSix = 0;
|
||||
if(TranslationContext.m_GameStateFlags7 & protocol7::GAMESTATEFLAG_GAMEOVER)
|
||||
GameStateFlagsSix |= GAMESTATEFLAG_GAMEOVER;
|
||||
if(TranslationContext.m_GameStateFlags7 & protocol7::GAMESTATEFLAG_SUDDENDEATH)
|
||||
GameStateFlagsSix |= GAMESTATEFLAG_SUDDENDEATH;
|
||||
if(TranslationContext.m_GameStateFlags7 & protocol7::GAMESTATEFLAG_PAUSED)
|
||||
GameStateFlagsSix |= GAMESTATEFLAG_PAUSED;
|
||||
|
||||
/*
|
||||
This is a 0.7 only flag that we just ignore for now
|
||||
|
||||
GAMESTATEFLAG_ROUNDOVER
|
||||
*/
|
||||
|
||||
CNetObj_GameInfo Info6 = {};
|
||||
Info6.m_GameFlags = TranslationContext.m_GameFlags;
|
||||
Info6.m_GameStateFlags = GameStateFlagsSix;
|
||||
Info6.m_RoundStartTick = TranslationContext.m_GameStartTick7;
|
||||
Info6.m_WarmupTimer = 0; // removed in 0.7
|
||||
if(TranslationContext.m_GameStateFlags7 & protocol7::GAMESTATEFLAG_WARMUP)
|
||||
Info6.m_WarmupTimer = TranslationContext.m_GameStateEndTick7 - GameTick;
|
||||
if(TranslationContext.m_GameStateFlags7 & protocol7::GAMESTATEFLAG_STARTCOUNTDOWN)
|
||||
Info6.m_WarmupTimer = TranslationContext.m_GameStateEndTick7 - GameTick;
|
||||
|
||||
// hack to port 0.7 race timer to ddnet warmup gametimer hack
|
||||
int TimerClientId = clamp(TranslationContext.m_aLocalClientId[Conn], 0, (int)MAX_CLIENTS);
|
||||
if(SpectatorId >= 0)
|
||||
TimerClientId = SpectatorId;
|
||||
const protocol7::CNetObj_PlayerInfoRace *pRaceInfo = TranslationContext.m_apPlayerInfosRace[TimerClientId];
|
||||
if(pRaceInfo)
|
||||
{
|
||||
Info6.m_WarmupTimer = -pRaceInfo->m_RaceStartTick;
|
||||
Info6.m_GameStateFlags |= GAMESTATEFLAG_RACETIME;
|
||||
}
|
||||
|
||||
Info6.m_ScoreLimit = TranslationContext.m_ScoreLimit;
|
||||
Info6.m_TimeLimit = TranslationContext.m_TimeLimit;
|
||||
Info6.m_RoundNum = TranslationContext.m_MatchNum;
|
||||
Info6.m_RoundCurrent = TranslationContext.m_MatchCurrent;
|
||||
|
||||
mem_copy(pObj, &Info6, sizeof(CNetObj_GameInfo));
|
||||
}
|
||||
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
const CTranslationContext::CClientData &Client = TranslationContext.m_aClients[i];
|
||||
if(!Client.m_Active)
|
||||
continue;
|
||||
|
||||
void *pObj = Builder.NewItem(NETOBJTYPE_CLIENTINFO, i, sizeof(CNetObj_ClientInfo));
|
||||
if(!pObj)
|
||||
return -2;
|
||||
|
||||
CNetObj_ClientInfo Info6 = {};
|
||||
StrToInts(&Info6.m_Name0, 4, Client.m_aName);
|
||||
StrToInts(&Info6.m_Clan0, 3, Client.m_aClan);
|
||||
Info6.m_Country = Client.m_Country;
|
||||
StrToInts(&Info6.m_Skin0, 6, Client.m_aSkinName);
|
||||
Info6.m_UseCustomColor = Client.m_UseCustomColor;
|
||||
Info6.m_ColorBody = Client.m_ColorBody;
|
||||
Info6.m_ColorFeet = Client.m_ColorFeet;
|
||||
mem_copy(pObj, &Info6, sizeof(CNetObj_ClientInfo));
|
||||
}
|
||||
|
||||
bool NewGameData = false;
|
||||
|
||||
for(int i = 0; i < m_NumItems; i++)
|
||||
{
|
||||
const CSnapshotItem *pItem7 = GetItem(i);
|
||||
const int Size = GetItemSize(i);
|
||||
// the first few items are a full match
|
||||
// no translation needed
|
||||
if(pItem7->Type() == protocol7::NETOBJTYPE_PROJECTILE ||
|
||||
pItem7->Type() == protocol7::NETOBJTYPE_LASER ||
|
||||
pItem7->Type() == protocol7::NETOBJTYPE_FLAG)
|
||||
{
|
||||
void *pObj = Builder.NewItem(pItem7->Type(), pItem7->Id(), Size);
|
||||
if(!pObj)
|
||||
return -4;
|
||||
|
||||
mem_copy(pObj, pItem7->Data(), Size);
|
||||
}
|
||||
else if(pItem7->Type() == protocol7::NETOBJTYPE_PICKUP)
|
||||
{
|
||||
void *pObj = Builder.NewItem(NETOBJTYPE_PICKUP, pItem7->Id(), sizeof(CNetObj_Pickup));
|
||||
if(!pObj)
|
||||
return -5;
|
||||
|
||||
const protocol7::CNetObj_Pickup *pPickup7 = (const protocol7::CNetObj_Pickup *)pItem7->Data();
|
||||
CNetObj_Pickup Pickup6 = {};
|
||||
Pickup6.m_X = pPickup7->m_X;
|
||||
Pickup6.m_Y = pPickup7->m_Y;
|
||||
PickupType_SevenToSix(pPickup7->m_Type, Pickup6.m_Type, Pickup6.m_Subtype);
|
||||
|
||||
mem_copy(pObj, &Pickup6, sizeof(CNetObj_Pickup));
|
||||
}
|
||||
else if(pItem7->Type() == protocol7::NETOBJTYPE_GAMEDATA)
|
||||
{
|
||||
const protocol7::CNetObj_GameData *pGameData = (const protocol7::CNetObj_GameData *)pItem7->Data();
|
||||
TranslationContext.m_GameStateFlags7 = pGameData->m_GameStateFlags;
|
||||
TranslationContext.m_GameStartTick7 = pGameData->m_GameStartTick;
|
||||
TranslationContext.m_GameStateEndTick7 = pGameData->m_GameStateEndTick;
|
||||
}
|
||||
else if(pItem7->Type() == protocol7::NETOBJTYPE_GAMEDATATEAM)
|
||||
{
|
||||
// 0.7 added GameDataTeam and GameDataFlag
|
||||
// both items merged together have all fields of the 0.6 GameData
|
||||
// so if we get either one of them we store the details in the translation context
|
||||
// and build one GameData snap item after this loop
|
||||
const protocol7::CNetObj_GameDataTeam *pTeam7 = (const protocol7::CNetObj_GameDataTeam *)pItem7->Data();
|
||||
|
||||
TranslationContext.m_TeamscoreRed = pTeam7->m_TeamscoreRed;
|
||||
TranslationContext.m_TeamscoreBlue = pTeam7->m_TeamscoreBlue;
|
||||
NewGameData = true;
|
||||
}
|
||||
else if(pItem7->Type() == protocol7::NETOBJTYPE_GAMEDATAFLAG)
|
||||
{
|
||||
const protocol7::CNetObj_GameDataFlag *pFlag7 = (const protocol7::CNetObj_GameDataFlag *)pItem7->Data();
|
||||
|
||||
TranslationContext.m_FlagCarrierRed = pFlag7->m_FlagCarrierRed;
|
||||
TranslationContext.m_FlagCarrierBlue = pFlag7->m_FlagCarrierBlue;
|
||||
NewGameData = true;
|
||||
|
||||
// used for blinking the flags in the hud
|
||||
// but that already works the 0.6 way
|
||||
// and is covered by the NETOBJTYPE_GAMEDATA translation
|
||||
// pFlag7->m_FlagDropTickRed;
|
||||
// pFlag7->m_FlagDropTickBlue;
|
||||
}
|
||||
else if(pItem7->Type() == protocol7::NETOBJTYPE_CHARACTER)
|
||||
{
|
||||
void *pObj = Builder.NewItem(NETOBJTYPE_CHARACTER, pItem7->Id(), sizeof(CNetObj_Character));
|
||||
if(!pObj)
|
||||
return -6;
|
||||
|
||||
const protocol7::CNetObj_Character *pChar7 = (const protocol7::CNetObj_Character *)pItem7->Data();
|
||||
|
||||
CNetObj_Character Char6 = {};
|
||||
// character core is unchanged
|
||||
mem_copy(&Char6, pItem7->Data(), sizeof(CNetObj_CharacterCore));
|
||||
|
||||
Char6.m_PlayerFlags = 0;
|
||||
if(pItem7->Id() >= 0 && pItem7->Id() < MAX_CLIENTS)
|
||||
Char6.m_PlayerFlags = PlayerFlags_SevenToSix(TranslationContext.m_aClients[pItem7->Id()].m_PlayerFlags7);
|
||||
Char6.m_Health = pChar7->m_Health;
|
||||
Char6.m_Armor = pChar7->m_Armor;
|
||||
Char6.m_AmmoCount = pChar7->m_AmmoCount;
|
||||
Char6.m_Weapon = pChar7->m_Weapon;
|
||||
Char6.m_Emote = pChar7->m_Emote;
|
||||
Char6.m_AttackTick = pChar7->m_AttackTick;
|
||||
|
||||
if(TranslationContext.m_aLocalClientId[Conn] != pItem7->Id())
|
||||
{
|
||||
if(pChar7->m_TriggeredEvents & protocol7::COREEVENTFLAG_GROUND_JUMP)
|
||||
{
|
||||
void *pEvent = Builder.NewItem(NETEVENTTYPE_SOUNDWORLD, pItem7->Id(), sizeof(CNetEvent_SoundWorld));
|
||||
if(!pEvent)
|
||||
return -7;
|
||||
|
||||
CNetEvent_SoundWorld Sound = {};
|
||||
Sound.m_X = pChar7->m_X;
|
||||
Sound.m_Y = pChar7->m_Y;
|
||||
Sound.m_SoundId = SOUND_PLAYER_JUMP;
|
||||
mem_copy(pEvent, &Sound, sizeof(CNetEvent_SoundWorld));
|
||||
}
|
||||
if(pChar7->m_TriggeredEvents & protocol7::COREEVENTFLAG_HOOK_ATTACH_PLAYER)
|
||||
{
|
||||
void *pEvent = Builder.NewItem(NETEVENTTYPE_SOUNDWORLD, pItem7->Id(), sizeof(CNetEvent_SoundWorld));
|
||||
if(!pEvent)
|
||||
return -7;
|
||||
|
||||
CNetEvent_SoundWorld Sound = {};
|
||||
Sound.m_X = pChar7->m_X;
|
||||
Sound.m_Y = pChar7->m_Y;
|
||||
Sound.m_SoundId = SOUND_HOOK_ATTACH_PLAYER;
|
||||
mem_copy(pEvent, &Sound, sizeof(CNetEvent_SoundWorld));
|
||||
}
|
||||
if(pChar7->m_TriggeredEvents & protocol7::COREEVENTFLAG_HOOK_ATTACH_GROUND)
|
||||
{
|
||||
void *pEvent = Builder.NewItem(NETEVENTTYPE_SOUNDWORLD, pItem7->Id(), sizeof(CNetEvent_SoundWorld));
|
||||
if(!pEvent)
|
||||
return -7;
|
||||
|
||||
CNetEvent_SoundWorld Sound = {};
|
||||
Sound.m_X = pChar7->m_X;
|
||||
Sound.m_Y = pChar7->m_Y;
|
||||
Sound.m_SoundId = SOUND_HOOK_ATTACH_GROUND;
|
||||
mem_copy(pEvent, &Sound, sizeof(CNetEvent_SoundWorld));
|
||||
}
|
||||
if(pChar7->m_TriggeredEvents & protocol7::COREEVENTFLAG_HOOK_HIT_NOHOOK)
|
||||
{
|
||||
void *pEvent = Builder.NewItem(NETEVENTTYPE_SOUNDWORLD, pItem7->Id(), sizeof(CNetEvent_SoundWorld));
|
||||
if(!pEvent)
|
||||
return -7;
|
||||
|
||||
CNetEvent_SoundWorld Sound = {};
|
||||
Sound.m_X = pChar7->m_X;
|
||||
Sound.m_Y = pChar7->m_Y;
|
||||
Sound.m_SoundId = SOUND_HOOK_NOATTACH;
|
||||
mem_copy(pEvent, &Sound, sizeof(CNetEvent_SoundWorld));
|
||||
}
|
||||
}
|
||||
|
||||
mem_copy(pObj, &Char6, sizeof(CNetObj_Character));
|
||||
}
|
||||
else if(pItem7->Type() == protocol7::NETOBJTYPE_PLAYERINFO)
|
||||
{
|
||||
void *pObj = Builder.NewItem(NETOBJTYPE_PLAYERINFO, pItem7->Id(), sizeof(CNetObj_PlayerInfo));
|
||||
if(!pObj)
|
||||
return -8;
|
||||
|
||||
const protocol7::CNetObj_PlayerInfo *pInfo7 = (const protocol7::CNetObj_PlayerInfo *)pItem7->Data();
|
||||
CNetObj_PlayerInfo Info6 = {};
|
||||
Info6.m_Local = TranslationContext.m_aLocalClientId[Conn] == pItem7->Id();
|
||||
Info6.m_ClientId = pItem7->Id();
|
||||
Info6.m_Team = 0;
|
||||
if(pItem7->Id() >= 0 && pItem7->Id() < MAX_CLIENTS)
|
||||
{
|
||||
Info6.m_Team = TranslationContext.m_aClients[pItem7->Id()].m_Team;
|
||||
TranslationContext.m_aClients[pItem7->Id()].m_PlayerFlags7 = pInfo7->m_PlayerFlags;
|
||||
}
|
||||
Info6.m_Score = pInfo7->m_Score;
|
||||
Info6.m_Latency = pInfo7->m_Latency;
|
||||
mem_copy(pObj, &Info6, sizeof(CNetObj_PlayerInfo));
|
||||
}
|
||||
else if(pItem7->Type() == protocol7::NETOBJTYPE_SPECTATORINFO)
|
||||
{
|
||||
void *pObj = Builder.NewItem(NETOBJTYPE_SPECTATORINFO, pItem7->Id(), sizeof(CNetObj_SpectatorInfo));
|
||||
if(!pObj)
|
||||
return -9;
|
||||
|
||||
const protocol7::CNetObj_SpectatorInfo *pSpec7 = (const protocol7::CNetObj_SpectatorInfo *)pItem7->Data();
|
||||
CNetObj_SpectatorInfo Spec6 = {};
|
||||
Spec6.m_SpectatorId = pSpec7->m_SpectatorId;
|
||||
if(pSpec7->m_SpecMode == protocol7::SPEC_FREEVIEW)
|
||||
Spec6.m_SpectatorId = SPEC_FREEVIEW;
|
||||
Spec6.m_X = pSpec7->m_X;
|
||||
Spec6.m_Y = pSpec7->m_Y;
|
||||
mem_copy(pObj, &Spec6, sizeof(CNetObj_SpectatorInfo));
|
||||
}
|
||||
else if(pItem7->Type() == protocol7::NETEVENTTYPE_EXPLOSION)
|
||||
{
|
||||
void *pEvent = Builder.NewItem(NETEVENTTYPE_EXPLOSION, pItem7->Id(), sizeof(CNetEvent_Explosion));
|
||||
if(!pEvent)
|
||||
return -10;
|
||||
|
||||
const protocol7::CNetEvent_Explosion *pExplosion7 = (const protocol7::CNetEvent_Explosion *)pItem7->Data();
|
||||
CNetEvent_Explosion Explosion6 = {};
|
||||
Explosion6.m_X = pExplosion7->m_X;
|
||||
Explosion6.m_Y = pExplosion7->m_Y;
|
||||
mem_copy(pEvent, &Explosion6, sizeof(CNetEvent_Explosion));
|
||||
}
|
||||
else if(pItem7->Type() == protocol7::NETEVENTTYPE_SPAWN)
|
||||
{
|
||||
void *pEvent = Builder.NewItem(NETEVENTTYPE_SPAWN, pItem7->Id(), sizeof(CNetEvent_Spawn));
|
||||
if(!pEvent)
|
||||
return -11;
|
||||
|
||||
const protocol7::CNetEvent_Spawn *pSpawn7 = (const protocol7::CNetEvent_Spawn *)pItem7->Data();
|
||||
CNetEvent_Spawn Spawn6 = {};
|
||||
Spawn6.m_X = pSpawn7->m_X;
|
||||
Spawn6.m_Y = pSpawn7->m_Y;
|
||||
mem_copy(pEvent, &Spawn6, sizeof(CNetEvent_Spawn));
|
||||
}
|
||||
else if(pItem7->Type() == protocol7::NETEVENTTYPE_HAMMERHIT)
|
||||
{
|
||||
void *pEvent = Builder.NewItem(NETEVENTTYPE_HAMMERHIT, pItem7->Id(), sizeof(CNetEvent_HammerHit));
|
||||
if(!pEvent)
|
||||
return -12;
|
||||
|
||||
const protocol7::CNetEvent_HammerHit *pHammerHit7 = (const protocol7::CNetEvent_HammerHit *)pItem7->Data();
|
||||
CNetEvent_HammerHit HammerHit6 = {};
|
||||
HammerHit6.m_X = pHammerHit7->m_X;
|
||||
HammerHit6.m_Y = pHammerHit7->m_Y;
|
||||
mem_copy(pEvent, &HammerHit6, sizeof(CNetEvent_HammerHit));
|
||||
}
|
||||
else if(pItem7->Type() == protocol7::NETEVENTTYPE_DEATH)
|
||||
{
|
||||
void *pEvent = Builder.NewItem(NETEVENTTYPE_DEATH, pItem7->Id(), sizeof(CNetEvent_Death));
|
||||
if(!pEvent)
|
||||
return -13;
|
||||
|
||||
const protocol7::CNetEvent_Death *pDeath7 = (const protocol7::CNetEvent_Death *)pItem7->Data();
|
||||
CNetEvent_Death Death6 = {};
|
||||
Death6.m_X = pDeath7->m_X;
|
||||
Death6.m_Y = pDeath7->m_Y;
|
||||
Death6.m_ClientId = pDeath7->m_ClientId;
|
||||
mem_copy(pEvent, &Death6, sizeof(CNetEvent_Death));
|
||||
}
|
||||
else if(pItem7->Type() == protocol7::NETEVENTTYPE_SOUNDWORLD)
|
||||
{
|
||||
void *pEvent = Builder.NewItem(NETEVENTTYPE_SOUNDWORLD, pItem7->Id(), sizeof(CNetEvent_SoundWorld));
|
||||
if(!pEvent)
|
||||
return -14;
|
||||
|
||||
const protocol7::CNetEvent_SoundWorld *pSoundWorld7 = (const protocol7::CNetEvent_SoundWorld *)pItem7->Data();
|
||||
CNetEvent_SoundWorld SoundWorld6 = {};
|
||||
SoundWorld6.m_X = pSoundWorld7->m_X;
|
||||
SoundWorld6.m_Y = pSoundWorld7->m_Y;
|
||||
SoundWorld6.m_SoundId = pSoundWorld7->m_SoundId;
|
||||
mem_copy(pEvent, &SoundWorld6, sizeof(CNetEvent_SoundWorld));
|
||||
}
|
||||
else if(pItem7->Type() == protocol7::NETEVENTTYPE_DAMAGE)
|
||||
{
|
||||
// 0.7 introduced amount for damage indicators
|
||||
// so for one 0.7 item we might create multiple 0.6 ones
|
||||
const protocol7::CNetEvent_Damage *pDmg7 = (const protocol7::CNetEvent_Damage *)pItem7->Data();
|
||||
|
||||
int Amount = pDmg7->m_HealthAmount + pDmg7->m_ArmorAmount;
|
||||
if(Amount < 1)
|
||||
continue;
|
||||
|
||||
int ClientId = pDmg7->m_ClientId;
|
||||
TranslationContext.m_aDamageTaken[ClientId]++;
|
||||
|
||||
float Angle;
|
||||
// create healthmod indicator
|
||||
if(LocalTime < TranslationContext.m_aDamageTakenTick[ClientId] + 0.5f)
|
||||
{
|
||||
// make sure that the damage indicators don't group together
|
||||
Angle = TranslationContext.m_aDamageTaken[ClientId] * 0.25f;
|
||||
}
|
||||
else
|
||||
{
|
||||
TranslationContext.m_aDamageTaken[ClientId] = 0;
|
||||
Angle = 0;
|
||||
}
|
||||
|
||||
TranslationContext.m_aDamageTakenTick[ClientId] = LocalTime;
|
||||
|
||||
float a = 3 * pi / 2 + Angle;
|
||||
float s = a - pi / 3;
|
||||
float e = a + pi / 3;
|
||||
for(int k = 0; k < Amount; k++)
|
||||
{
|
||||
// pItem7->Id() is reused that is technically wrong
|
||||
// but the client implementation does not look at the ids
|
||||
// and renders the damage indicators just fine
|
||||
void *pEvent = Builder.NewItem(NETEVENTTYPE_DAMAGEIND, pItem7->Id(), sizeof(CNetEvent_DamageInd));
|
||||
if(!pEvent)
|
||||
return -16;
|
||||
|
||||
CNetEvent_DamageInd Dmg6 = {};
|
||||
Dmg6.m_X = pDmg7->m_X;
|
||||
Dmg6.m_Y = pDmg7->m_Y;
|
||||
float f = mix(s, e, float(k + 1) / float(Amount + 2));
|
||||
Dmg6.m_Angle = (int)(f * 256.0f);
|
||||
mem_copy(pEvent, &Dmg6, sizeof(CNetEvent_DamageInd));
|
||||
}
|
||||
}
|
||||
else if(pItem7->Type() == protocol7::NETOBJTYPE_DE_CLIENTINFO)
|
||||
{
|
||||
const protocol7::CNetObj_De_ClientInfo *pInfo = (const protocol7::CNetObj_De_ClientInfo *)pItem7->Data();
|
||||
|
||||
const int ClientId = pItem7->Id();
|
||||
|
||||
if(ClientId < 0 || ClientId >= MAX_CLIENTS)
|
||||
{
|
||||
dbg_msg("sixup", "De_ClientInfo got invalid ClientId: %d", ClientId);
|
||||
return -17;
|
||||
}
|
||||
|
||||
if(pInfo->m_Local)
|
||||
{
|
||||
TranslationContext.m_aLocalClientId[Conn] = ClientId;
|
||||
}
|
||||
CTranslationContext::CClientData &Client = TranslationContext.m_aClients[ClientId];
|
||||
Client.m_Active = true;
|
||||
Client.m_Team = pInfo->m_Team;
|
||||
IntsToStr(pInfo->m_aName, 4, Client.m_aName, std::size(Client.m_aName));
|
||||
IntsToStr(pInfo->m_aClan, 3, Client.m_aClan, std::size(Client.m_aClan));
|
||||
Client.m_Country = pInfo->m_Country;
|
||||
|
||||
// TODO: get this method into scope
|
||||
// ApplySkin7InfoFromGameMsg(pInfo, ClientId);
|
||||
}
|
||||
else if(pItem7->Type() == protocol7::NETOBJTYPE_DE_GAMEINFO)
|
||||
{
|
||||
const protocol7::CNetObj_De_GameInfo *pInfo = (const protocol7::CNetObj_De_GameInfo *)pItem7->Data();
|
||||
|
||||
TranslationContext.m_GameFlags = pInfo->m_GameFlags;
|
||||
TranslationContext.m_ScoreLimit = pInfo->m_ScoreLimit;
|
||||
TranslationContext.m_TimeLimit = pInfo->m_TimeLimit;
|
||||
TranslationContext.m_MatchNum = pInfo->m_MatchNum;
|
||||
TranslationContext.m_MatchCurrent = pInfo->m_MatchCurrent;
|
||||
TranslationContext.m_ShouldSendGameInfo = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(NewGameData)
|
||||
{
|
||||
void *pObj = Builder.NewItem(NETOBJTYPE_GAMEDATA, 0, sizeof(CNetObj_GameData));
|
||||
if(!pObj)
|
||||
return -17;
|
||||
|
||||
CNetObj_GameData GameData = {};
|
||||
GameData.m_TeamscoreRed = TranslationContext.m_TeamscoreRed;
|
||||
GameData.m_TeamscoreBlue = TranslationContext.m_TeamscoreBlue;
|
||||
GameData.m_FlagCarrierRed = TranslationContext.m_FlagCarrierRed;
|
||||
GameData.m_FlagCarrierBlue = TranslationContext.m_FlagCarrierBlue;
|
||||
mem_copy(pObj, &GameData, sizeof(CNetObj_GameData));
|
||||
}
|
||||
|
||||
return Builder.Finish(pSixSnapDest);
|
||||
m_DataSize = pSnapshot->m_DataSize;
|
||||
m_NumItems = pSnapshot->m_NumItems;
|
||||
mem_copy(m_aOffsets, pSnapshot->Offsets(), sizeof(int) * m_NumItems);
|
||||
mem_copy(m_aData, pSnapshot->DataStart(), m_DataSize);
|
||||
}
|
||||
|
|
|
@ -63,15 +63,6 @@ public:
|
|||
|
||||
unsigned Crc() const;
|
||||
void DebugDump() const;
|
||||
int TranslateSevenToSix(
|
||||
CSnapshot *pSixSnapDest,
|
||||
class CTranslationContext &TranslationContext,
|
||||
float LocalTime,
|
||||
int GameTick,
|
||||
int Conn,
|
||||
bool Dummy,
|
||||
protocol7::CNetObjHandler *pNetObjHandler,
|
||||
CNetObjHandler *pNetObjHandler6);
|
||||
bool IsValid(size_t ActualSize) const;
|
||||
|
||||
static const CSnapshot *EmptySnapshot() { return &ms_EmptySnapshot; }
|
||||
|
@ -171,12 +162,13 @@ class CSnapshotBuilder
|
|||
int GetExtendedItemTypeIndex(int TypeId);
|
||||
int GetTypeFromIndex(int Index) const;
|
||||
|
||||
bool m_Sixup;
|
||||
bool m_Sixup = false;
|
||||
|
||||
public:
|
||||
CSnapshotBuilder();
|
||||
|
||||
void Init(bool Sixup = false);
|
||||
void Init7(const CSnapshot *pSnapshot);
|
||||
|
||||
void *NewItem(int Type, int Id, int Size);
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef ENGINE_SHARED_TRANSLATION_CONTEXT_H
|
||||
#define ENGINE_SHARED_TRANSLATION_CONTEXT_H
|
||||
|
||||
#include <base/system.h>
|
||||
#include <engine/shared/protocol.h>
|
||||
#include <game/generated/protocol7.h>
|
||||
|
||||
|
@ -98,6 +99,9 @@ public:
|
|||
|
||||
bool m_ShouldSendGameInfo;
|
||||
int m_GameStateFlags7;
|
||||
// 0.7 game flags
|
||||
// use in combination with protocol7::GAMEFLAG_*
|
||||
// for example protocol7::GAMEFLAG_TEAMS
|
||||
int m_GameFlags;
|
||||
int m_ScoreLimit;
|
||||
int m_TimeLimit;
|
||||
|
|
|
@ -81,6 +81,7 @@ using namespace std::chrono_literals;
|
|||
|
||||
const char *CGameClient::Version() const { return GAME_VERSION; }
|
||||
const char *CGameClient::NetVersion() const { return GAME_NETVERSION; }
|
||||
const char *CGameClient::NetVersion7() const { return GAME_NETVERSION7; }
|
||||
int CGameClient::DDNetVersion() const { return DDNET_VERSION_NUMBER; }
|
||||
const char *CGameClient::DDNetVersionStr() const { return m_aDDNetVersionStr; }
|
||||
int CGameClient::ClientVersion7() const { return CLIENT_VERSION7; }
|
||||
|
@ -2336,9 +2337,9 @@ void CGameClient::CClientData::Reset()
|
|||
m_SkinColor = 0;
|
||||
for(int i = 0; i < protocol7::NUM_SKINPARTS; ++i)
|
||||
{
|
||||
m_aaSkinPartNames[i][0] = '\0';
|
||||
m_aUseCustomColors[i] = 0;
|
||||
m_aSkinPartColors[i] = 0;
|
||||
m_Sixup.m_aaSkinPartNames[i][0] = '\0';
|
||||
m_Sixup.m_aUseCustomColors[i] = 0;
|
||||
m_Sixup.m_aSkinPartColors[i] = 0;
|
||||
}
|
||||
m_Team = 0;
|
||||
m_Emoticon = 0;
|
||||
|
@ -2464,11 +2465,11 @@ bool CGameClient::GotWantedSkin7(bool Dummy)
|
|||
|
||||
for(int SkinPart = 0; SkinPart < protocol7::NUM_SKINPARTS; SkinPart++)
|
||||
{
|
||||
if(str_comp(m_aClients[m_aLocalIds[(int)Dummy]].m_aaSkinPartNames[SkinPart], apSkinPartsPtr[SkinPart]))
|
||||
if(str_comp(m_aClients[m_aLocalIds[(int)Dummy]].m_Sixup.m_aaSkinPartNames[SkinPart], apSkinPartsPtr[SkinPart]))
|
||||
return false;
|
||||
if(m_aClients[m_aLocalIds[(int)Dummy]].m_aUseCustomColors[SkinPart] != aUCCVars[SkinPart])
|
||||
if(m_aClients[m_aLocalIds[(int)Dummy]].m_Sixup.m_aUseCustomColors[SkinPart] != aUCCVars[SkinPart])
|
||||
return false;
|
||||
if(m_aClients[m_aLocalIds[(int)Dummy]].m_aSkinPartColors[SkinPart] != aColorVars[SkinPart])
|
||||
if(m_aClients[m_aLocalIds[(int)Dummy]].m_Sixup.m_aSkinPartColors[SkinPart] != aColorVars[SkinPart])
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -365,12 +365,6 @@ public:
|
|||
int m_Country;
|
||||
char m_aSkinName[24];
|
||||
int m_SkinColor;
|
||||
|
||||
// 0.7 Skin
|
||||
char m_aaSkinPartNames[protocol7::NUM_SKINPARTS][protocol7::MAX_SKIN_LENGTH];
|
||||
int m_aUseCustomColors[protocol7::NUM_SKINPARTS];
|
||||
int m_aSkinPartColors[protocol7::NUM_SKINPARTS];
|
||||
|
||||
int m_Team;
|
||||
int m_Emoticon;
|
||||
float m_EmoticonStartFraction;
|
||||
|
@ -433,6 +427,17 @@ public:
|
|||
|
||||
void UpdateRenderInfo(bool IsTeamPlay);
|
||||
void Reset();
|
||||
|
||||
class CSixup
|
||||
{
|
||||
public:
|
||||
char m_aaSkinPartNames[protocol7::NUM_SKINPARTS][protocol7::MAX_SKIN_LENGTH];
|
||||
int m_aUseCustomColors[protocol7::NUM_SKINPARTS];
|
||||
int m_aSkinPartColors[protocol7::NUM_SKINPARTS];
|
||||
};
|
||||
|
||||
// 0.7 Skin
|
||||
CSixup m_Sixup;
|
||||
};
|
||||
|
||||
CClientData m_aClients[MAX_CLIENTS];
|
||||
|
@ -493,7 +498,10 @@ public:
|
|||
void OnStateChange(int NewState, int OldState) override;
|
||||
template<typename T>
|
||||
void ApplySkin7InfoFromGameMsg(const T *pMsg, int ClientId);
|
||||
void ApplySkin7InfoFromSnapObj(const protocol7::CNetObj_De_ClientInfo *pObj, int ClientId) override;
|
||||
int OnDemoRecSnap7(class CSnapshot *pFrom, class CSnapshot *pTo, int Conn) override;
|
||||
void *TranslateGameMsg(int *pMsgId, CUnpacker *pUnpacker, int Conn);
|
||||
int TranslateSnap(CSnapshot *pSnapDstSix, CSnapshot *pSnapSrcSeven, int Conn, bool Dummy) override;
|
||||
void OnMessage(int MsgId, CUnpacker *pUnpacker, int Conn, bool Dummy) override;
|
||||
void InvalidateSnapshot() override;
|
||||
void OnNewSnapshot() override;
|
||||
|
@ -522,6 +530,7 @@ public:
|
|||
const char *GetItemName(int Type) const override;
|
||||
const char *Version() const override;
|
||||
const char *NetVersion() const override;
|
||||
const char *NetVersion7() const override;
|
||||
int DDNetVersion() const override;
|
||||
const char *DDNetVersionStr() const override;
|
||||
virtual int ClientVersion7() const override;
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
#include <base/system.h>
|
||||
#include <engine/shared/protocol7.h>
|
||||
#include <game/gamecore.h>
|
||||
#include <game/generated/protocol7.h>
|
||||
#include <game/localization.h>
|
||||
|
||||
#include <game/client/gameclient.h>
|
||||
|
@ -81,12 +85,12 @@ void CGameClient::ApplySkin7InfoFromGameMsg(const T *pMsg, int ClientId)
|
|||
char *apSkinPartsPtr[protocol7::NUM_SKINPARTS];
|
||||
for(int Part = 0; Part < protocol7::NUM_SKINPARTS; Part++)
|
||||
{
|
||||
str_utf8_copy_num(pClient->m_aaSkinPartNames[Part], pMsg->m_apSkinPartNames[Part], sizeof(pClient->m_aaSkinPartNames[Part]), protocol7::MAX_SKIN_LENGTH);
|
||||
apSkinPartsPtr[Part] = pClient->m_aaSkinPartNames[Part];
|
||||
pClient->m_aUseCustomColors[Part] = pMsg->m_aUseCustomColors[Part];
|
||||
pClient->m_aSkinPartColors[Part] = pMsg->m_aSkinPartColors[Part];
|
||||
str_utf8_copy_num(pClient->m_Sixup.m_aaSkinPartNames[Part], pMsg->m_apSkinPartNames[Part], sizeof(pClient->m_Sixup.m_aaSkinPartNames[Part]), protocol7::MAX_SKIN_LENGTH);
|
||||
apSkinPartsPtr[Part] = pClient->m_Sixup.m_aaSkinPartNames[Part];
|
||||
pClient->m_Sixup.m_aUseCustomColors[Part] = pMsg->m_aUseCustomColors[Part];
|
||||
pClient->m_Sixup.m_aSkinPartColors[Part] = pMsg->m_aSkinPartColors[Part];
|
||||
}
|
||||
m_Skins7.ValidateSkinParts(apSkinPartsPtr, pClient->m_aUseCustomColors, pClient->m_aSkinPartColors, m_pClient->m_TranslationContext.m_GameFlags);
|
||||
m_Skins7.ValidateSkinParts(apSkinPartsPtr, pClient->m_Sixup.m_aUseCustomColors, pClient->m_Sixup.m_aSkinPartColors, m_pClient->m_TranslationContext.m_GameFlags);
|
||||
|
||||
if(time_season() == SEASON_XMAS)
|
||||
{
|
||||
|
@ -98,12 +102,12 @@ void CGameClient::ApplySkin7InfoFromGameMsg(const T *pMsg, int ClientId)
|
|||
|
||||
for(int Part = 0; Part < protocol7::NUM_SKINPARTS; Part++)
|
||||
{
|
||||
int Id = m_Skins7.FindSkinPart(Part, pClient->m_aaSkinPartNames[Part], false);
|
||||
int Id = m_Skins7.FindSkinPart(Part, pClient->m_Sixup.m_aaSkinPartNames[Part], false);
|
||||
const CSkins7::CSkinPart *pSkinPart = m_Skins7.GetSkinPart(Part, Id);
|
||||
if(pClient->m_aUseCustomColors[Part])
|
||||
if(pClient->m_Sixup.m_aUseCustomColors[Part])
|
||||
{
|
||||
pClient->m_SkinInfo.m_Sixup.m_aTextures[Part] = pSkinPart->m_ColorTexture;
|
||||
pClient->m_SkinInfo.m_Sixup.m_aColors[Part] = m_Skins7.GetColor(pClient->m_aSkinPartColors[Part], Part == protocol7::SKINPART_MARKING);
|
||||
pClient->m_SkinInfo.m_Sixup.m_aColors[Part] = m_Skins7.GetColor(pMsg->m_aSkinPartColors[Part], Part == protocol7::SKINPART_MARKING);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -112,14 +116,29 @@ void CGameClient::ApplySkin7InfoFromGameMsg(const T *pMsg, int ClientId)
|
|||
}
|
||||
if(pClient->m_SkinInfo.m_Sixup.m_HatTexture.IsValid())
|
||||
{
|
||||
if(Part == protocol7::SKINPART_BODY && str_comp(pClient->m_aaSkinPartNames[Part], "standard"))
|
||||
if(Part == protocol7::SKINPART_BODY && str_comp(pClient->m_Sixup.m_aaSkinPartNames[Part], "standard"))
|
||||
pClient->m_SkinInfo.m_Sixup.m_HatSpriteIndex = CSkins7::HAT_OFFSET_SIDE + (ClientId % CSkins7::HAT_NUM);
|
||||
if(Part == protocol7::SKINPART_DECORATION && !str_comp(pClient->m_aaSkinPartNames[Part], "twinbopp"))
|
||||
if(Part == protocol7::SKINPART_DECORATION && !str_comp(pClient->m_Sixup.m_aaSkinPartNames[Part], "twinbopp"))
|
||||
pClient->m_SkinInfo.m_Sixup.m_HatSpriteIndex = CSkins7::HAT_OFFSET_SIDE + (ClientId % CSkins7::HAT_NUM);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CGameClient::ApplySkin7InfoFromSnapObj(const protocol7::CNetObj_De_ClientInfo *pObj, int ClientId)
|
||||
{
|
||||
char aSkinPartNames[protocol7::NUM_SKINPARTS][protocol7::MAX_SKIN_ARRAY_SIZE];
|
||||
protocol7::CNetMsg_Sv_SkinChange Msg;
|
||||
Msg.m_ClientId = ClientId;
|
||||
for(int Part = 0; Part < protocol7::NUM_SKINPARTS; Part++)
|
||||
{
|
||||
IntsToStr(pObj->m_aaSkinPartNames[Part], 6, aSkinPartNames[Part], std::size(aSkinPartNames[Part]));
|
||||
Msg.m_apSkinPartNames[Part] = aSkinPartNames[Part];
|
||||
Msg.m_aUseCustomColors[Part] = pObj->m_aUseCustomColors[Part];
|
||||
Msg.m_aSkinPartColors[Part] = pObj->m_aSkinPartColors[Part];
|
||||
}
|
||||
ApplySkin7InfoFromGameMsg(&Msg, ClientId);
|
||||
}
|
||||
|
||||
void *CGameClient::TranslateGameMsg(int *pMsgId, CUnpacker *pUnpacker, int Conn)
|
||||
{
|
||||
if(!m_pClient->IsSixup())
|
||||
|
|
564
src/game/client/sixup_translate_snapshot.cpp
Normal file
564
src/game/client/sixup_translate_snapshot.cpp
Normal file
|
@ -0,0 +1,564 @@
|
|||
#include <engine/shared/protocolglue.h>
|
||||
#include <engine/shared/snapshot.h>
|
||||
#include <engine/shared/translation_context.h>
|
||||
#include <game/client/gameclient.h>
|
||||
#include <game/generated/protocol7.h>
|
||||
|
||||
int CGameClient::TranslateSnap(CSnapshot *pSnapDstSix, CSnapshot *pSnapSrcSeven, int Conn, bool Dummy)
|
||||
{
|
||||
CSnapshotBuilder Builder;
|
||||
Builder.Init();
|
||||
|
||||
float LocalTime = Client()->LocalTime();
|
||||
int GameTick = Client()->GameTick(g_Config.m_ClDummy);
|
||||
CTranslationContext &TranslationContext = Client()->m_TranslationContext;
|
||||
|
||||
for(auto &PlayerInfosRace : TranslationContext.m_apPlayerInfosRace)
|
||||
PlayerInfosRace = nullptr;
|
||||
|
||||
int SpectatorId = -3;
|
||||
|
||||
for(int i = 0; i < pSnapSrcSeven->NumItems(); i++)
|
||||
{
|
||||
const CSnapshotItem *pItem7 = (CSnapshotItem *)pSnapSrcSeven->GetItem(i);
|
||||
const int Size = pSnapSrcSeven->GetItemSize(i);
|
||||
const int ItemType = pSnapSrcSeven->GetItemType(i);
|
||||
|
||||
// ddnet ex snap items
|
||||
if((ItemType > __NETOBJTYPE_UUID_HELPER && ItemType < OFFSET_NETMSGTYPE_UUID) || pItem7->Type() == NETOBJTYPE_EX)
|
||||
{
|
||||
CUnpacker Unpacker;
|
||||
Unpacker.Reset(pItem7->Data(), Size);
|
||||
|
||||
void *pRawObj = GetNetObjHandler()->SecureUnpackObj(ItemType, &Unpacker);
|
||||
if(!pRawObj)
|
||||
{
|
||||
if(ItemType != UUID_UNKNOWN)
|
||||
dbg_msg("sixup", "dropped weird ddnet ex object '%s' (%d), failed on '%s'", GetNetObjHandler()->GetObjName(ItemType), ItemType, GetNetObjHandler()->FailedObjOn());
|
||||
continue;
|
||||
}
|
||||
const int ItemSize = GetNetObjHandler()->GetUnpackedObjSize(ItemType);
|
||||
|
||||
void *pObj = Builder.NewItem(pItem7->Type(), pItem7->Id(), ItemSize);
|
||||
if(!pObj)
|
||||
return -17;
|
||||
|
||||
mem_copy(pObj, pRawObj, ItemSize);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(GetNetObjHandler7()->ValidateObj(pItem7->Type(), pItem7->Data(), Size) != 0)
|
||||
{
|
||||
if(pItem7->Type() > 0 && pItem7->Type() < CSnapshot::OFFSET_UUID_TYPE)
|
||||
{
|
||||
dbg_msg(
|
||||
"sixup",
|
||||
"invalidated index=%d type=%d (%s) size=%d id=%d",
|
||||
i,
|
||||
pItem7->Type(),
|
||||
GetNetObjHandler7()->GetObjName(pItem7->Type()),
|
||||
Size,
|
||||
pItem7->Id());
|
||||
}
|
||||
pSnapSrcSeven->InvalidateItem(i);
|
||||
}
|
||||
|
||||
if(pItem7->Type() == protocol7::NETOBJTYPE_PLAYERINFORACE)
|
||||
{
|
||||
const protocol7::CNetObj_PlayerInfoRace *pInfo = (const protocol7::CNetObj_PlayerInfoRace *)pItem7->Data();
|
||||
int ClientId = pItem7->Id();
|
||||
if(ClientId < MAX_CLIENTS && TranslationContext.m_aClients[ClientId].m_Active)
|
||||
{
|
||||
TranslationContext.m_apPlayerInfosRace[ClientId] = pInfo;
|
||||
}
|
||||
}
|
||||
else if(pItem7->Type() == protocol7::NETOBJTYPE_SPECTATORINFO)
|
||||
{
|
||||
const protocol7::CNetObj_SpectatorInfo *pSpec7 = (const protocol7::CNetObj_SpectatorInfo *)pItem7->Data();
|
||||
SpectatorId = pSpec7->m_SpectatorId;
|
||||
if(pSpec7->m_SpecMode == protocol7::SPEC_FREEVIEW)
|
||||
SpectatorId = SPEC_FREEVIEW;
|
||||
}
|
||||
}
|
||||
|
||||
// hack to put game info in the snap
|
||||
// even though in 0.7 we get it as a game message
|
||||
// this message has to be on the top
|
||||
// the client looks at the items in order and needs the gameinfo at the top
|
||||
// otherwise it will not render skins with team colors
|
||||
if(TranslationContext.m_ShouldSendGameInfo)
|
||||
{
|
||||
void *pObj = Builder.NewItem(NETOBJTYPE_GAMEINFO, 0, sizeof(CNetObj_GameInfo));
|
||||
if(!pObj)
|
||||
return -1;
|
||||
|
||||
int GameStateFlagsSix = 0;
|
||||
if(TranslationContext.m_GameStateFlags7 & protocol7::GAMESTATEFLAG_GAMEOVER)
|
||||
GameStateFlagsSix |= GAMESTATEFLAG_GAMEOVER;
|
||||
if(TranslationContext.m_GameStateFlags7 & protocol7::GAMESTATEFLAG_SUDDENDEATH)
|
||||
GameStateFlagsSix |= GAMESTATEFLAG_SUDDENDEATH;
|
||||
if(TranslationContext.m_GameStateFlags7 & protocol7::GAMESTATEFLAG_PAUSED)
|
||||
GameStateFlagsSix |= GAMESTATEFLAG_PAUSED;
|
||||
|
||||
/*
|
||||
This is a 0.7 only flag that we just ignore for now
|
||||
|
||||
GAMESTATEFLAG_ROUNDOVER
|
||||
*/
|
||||
|
||||
CNetObj_GameInfo Info6 = {};
|
||||
Info6.m_GameFlags = TranslationContext.m_GameFlags;
|
||||
Info6.m_GameStateFlags = GameStateFlagsSix;
|
||||
Info6.m_RoundStartTick = TranslationContext.m_GameStartTick7;
|
||||
Info6.m_WarmupTimer = 0; // removed in 0.7
|
||||
if(TranslationContext.m_GameStateFlags7 & protocol7::GAMESTATEFLAG_WARMUP)
|
||||
Info6.m_WarmupTimer = TranslationContext.m_GameStateEndTick7 - GameTick;
|
||||
if(TranslationContext.m_GameStateFlags7 & protocol7::GAMESTATEFLAG_STARTCOUNTDOWN)
|
||||
Info6.m_WarmupTimer = TranslationContext.m_GameStateEndTick7 - GameTick;
|
||||
|
||||
// hack to port 0.7 race timer to ddnet warmup gametimer hack
|
||||
int TimerClientId = clamp(TranslationContext.m_aLocalClientId[Conn], 0, (int)MAX_CLIENTS);
|
||||
if(SpectatorId >= 0)
|
||||
TimerClientId = SpectatorId;
|
||||
const protocol7::CNetObj_PlayerInfoRace *pRaceInfo = TranslationContext.m_apPlayerInfosRace[TimerClientId];
|
||||
if(pRaceInfo)
|
||||
{
|
||||
Info6.m_WarmupTimer = -pRaceInfo->m_RaceStartTick;
|
||||
Info6.m_GameStateFlags |= GAMESTATEFLAG_RACETIME;
|
||||
}
|
||||
|
||||
Info6.m_ScoreLimit = TranslationContext.m_ScoreLimit;
|
||||
Info6.m_TimeLimit = TranslationContext.m_TimeLimit;
|
||||
Info6.m_RoundNum = TranslationContext.m_MatchNum;
|
||||
Info6.m_RoundCurrent = TranslationContext.m_MatchCurrent;
|
||||
|
||||
mem_copy(pObj, &Info6, sizeof(CNetObj_GameInfo));
|
||||
}
|
||||
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
const CTranslationContext::CClientData &Client = TranslationContext.m_aClients[i];
|
||||
if(!Client.m_Active)
|
||||
continue;
|
||||
|
||||
void *pObj = Builder.NewItem(NETOBJTYPE_CLIENTINFO, i, sizeof(CNetObj_ClientInfo));
|
||||
if(!pObj)
|
||||
return -2;
|
||||
|
||||
CNetObj_ClientInfo Info6 = {};
|
||||
StrToInts(&Info6.m_Name0, 4, Client.m_aName);
|
||||
StrToInts(&Info6.m_Clan0, 3, Client.m_aClan);
|
||||
Info6.m_Country = Client.m_Country;
|
||||
StrToInts(&Info6.m_Skin0, 6, Client.m_aSkinName);
|
||||
Info6.m_UseCustomColor = Client.m_UseCustomColor;
|
||||
Info6.m_ColorBody = Client.m_ColorBody;
|
||||
Info6.m_ColorFeet = Client.m_ColorFeet;
|
||||
mem_copy(pObj, &Info6, sizeof(CNetObj_ClientInfo));
|
||||
}
|
||||
|
||||
bool NewGameData = false;
|
||||
|
||||
for(int i = 0; i < pSnapSrcSeven->NumItems(); i++)
|
||||
{
|
||||
const CSnapshotItem *pItem7 = pSnapSrcSeven->GetItem(i);
|
||||
const int Size = pSnapSrcSeven->GetItemSize(i);
|
||||
// the first few items are a full match
|
||||
// no translation needed
|
||||
if(pItem7->Type() == protocol7::NETOBJTYPE_PROJECTILE ||
|
||||
pItem7->Type() == protocol7::NETOBJTYPE_LASER ||
|
||||
pItem7->Type() == protocol7::NETOBJTYPE_FLAG)
|
||||
{
|
||||
void *pObj = Builder.NewItem(pItem7->Type(), pItem7->Id(), Size);
|
||||
if(!pObj)
|
||||
return -4;
|
||||
|
||||
mem_copy(pObj, pItem7->Data(), Size);
|
||||
}
|
||||
else if(pItem7->Type() == protocol7::NETOBJTYPE_PICKUP)
|
||||
{
|
||||
void *pObj = Builder.NewItem(NETOBJTYPE_PICKUP, pItem7->Id(), sizeof(CNetObj_Pickup));
|
||||
if(!pObj)
|
||||
return -5;
|
||||
|
||||
const protocol7::CNetObj_Pickup *pPickup7 = (const protocol7::CNetObj_Pickup *)pItem7->Data();
|
||||
CNetObj_Pickup Pickup6 = {};
|
||||
Pickup6.m_X = pPickup7->m_X;
|
||||
Pickup6.m_Y = pPickup7->m_Y;
|
||||
PickupType_SevenToSix(pPickup7->m_Type, Pickup6.m_Type, Pickup6.m_Subtype);
|
||||
|
||||
mem_copy(pObj, &Pickup6, sizeof(CNetObj_Pickup));
|
||||
}
|
||||
else if(pItem7->Type() == protocol7::NETOBJTYPE_GAMEDATA)
|
||||
{
|
||||
const protocol7::CNetObj_GameData *pGameData = (const protocol7::CNetObj_GameData *)pItem7->Data();
|
||||
TranslationContext.m_GameStateFlags7 = pGameData->m_GameStateFlags;
|
||||
TranslationContext.m_GameStartTick7 = pGameData->m_GameStartTick;
|
||||
TranslationContext.m_GameStateEndTick7 = pGameData->m_GameStateEndTick;
|
||||
}
|
||||
else if(pItem7->Type() == protocol7::NETOBJTYPE_GAMEDATATEAM)
|
||||
{
|
||||
// 0.7 added GameDataTeam and GameDataFlag
|
||||
// both items merged together have all fields of the 0.6 GameData
|
||||
// so if we get either one of them we store the details in the translation context
|
||||
// and build one GameData snap item after this loop
|
||||
const protocol7::CNetObj_GameDataTeam *pTeam7 = (const protocol7::CNetObj_GameDataTeam *)pItem7->Data();
|
||||
|
||||
TranslationContext.m_TeamscoreRed = pTeam7->m_TeamscoreRed;
|
||||
TranslationContext.m_TeamscoreBlue = pTeam7->m_TeamscoreBlue;
|
||||
NewGameData = true;
|
||||
}
|
||||
else if(pItem7->Type() == protocol7::NETOBJTYPE_GAMEDATAFLAG)
|
||||
{
|
||||
const protocol7::CNetObj_GameDataFlag *pFlag7 = (const protocol7::CNetObj_GameDataFlag *)pItem7->Data();
|
||||
|
||||
TranslationContext.m_FlagCarrierRed = pFlag7->m_FlagCarrierRed;
|
||||
TranslationContext.m_FlagCarrierBlue = pFlag7->m_FlagCarrierBlue;
|
||||
NewGameData = true;
|
||||
|
||||
// used for blinking the flags in the hud
|
||||
// but that already works the 0.6 way
|
||||
// and is covered by the NETOBJTYPE_GAMEDATA translation
|
||||
// pFlag7->m_FlagDropTickRed;
|
||||
// pFlag7->m_FlagDropTickBlue;
|
||||
}
|
||||
else if(pItem7->Type() == protocol7::NETOBJTYPE_CHARACTER)
|
||||
{
|
||||
void *pObj = Builder.NewItem(NETOBJTYPE_CHARACTER, pItem7->Id(), sizeof(CNetObj_Character));
|
||||
if(!pObj)
|
||||
return -6;
|
||||
|
||||
const protocol7::CNetObj_Character *pChar7 = (const protocol7::CNetObj_Character *)pItem7->Data();
|
||||
|
||||
CNetObj_Character Char6 = {};
|
||||
// character core is unchanged
|
||||
mem_copy(&Char6, pItem7->Data(), sizeof(CNetObj_CharacterCore));
|
||||
|
||||
Char6.m_PlayerFlags = 0;
|
||||
if(pItem7->Id() >= 0 && pItem7->Id() < MAX_CLIENTS)
|
||||
Char6.m_PlayerFlags = PlayerFlags_SevenToSix(TranslationContext.m_aClients[pItem7->Id()].m_PlayerFlags7);
|
||||
Char6.m_Health = pChar7->m_Health;
|
||||
Char6.m_Armor = pChar7->m_Armor;
|
||||
Char6.m_AmmoCount = pChar7->m_AmmoCount;
|
||||
Char6.m_Weapon = pChar7->m_Weapon;
|
||||
Char6.m_Emote = pChar7->m_Emote;
|
||||
Char6.m_AttackTick = pChar7->m_AttackTick;
|
||||
|
||||
if(pChar7->m_TriggeredEvents & protocol7::COREEVENTFLAG_HOOK_ATTACH_PLAYER)
|
||||
{
|
||||
void *pEvent = Builder.NewItem(NETEVENTTYPE_SOUNDWORLD, pItem7->Id(), sizeof(CNetEvent_SoundWorld));
|
||||
if(!pEvent)
|
||||
return -7;
|
||||
|
||||
CNetEvent_SoundWorld Sound = {};
|
||||
Sound.m_X = pChar7->m_X;
|
||||
Sound.m_Y = pChar7->m_Y;
|
||||
Sound.m_SoundId = SOUND_HOOK_ATTACH_PLAYER;
|
||||
mem_copy(pEvent, &Sound, sizeof(CNetEvent_SoundWorld));
|
||||
}
|
||||
|
||||
if(TranslationContext.m_aLocalClientId[Conn] != pItem7->Id())
|
||||
{
|
||||
if(pChar7->m_TriggeredEvents & protocol7::COREEVENTFLAG_GROUND_JUMP)
|
||||
{
|
||||
void *pEvent = Builder.NewItem(NETEVENTTYPE_SOUNDWORLD, pItem7->Id(), sizeof(CNetEvent_SoundWorld));
|
||||
if(!pEvent)
|
||||
return -7;
|
||||
|
||||
CNetEvent_SoundWorld Sound = {};
|
||||
Sound.m_X = pChar7->m_X;
|
||||
Sound.m_Y = pChar7->m_Y;
|
||||
Sound.m_SoundId = SOUND_PLAYER_JUMP;
|
||||
mem_copy(pEvent, &Sound, sizeof(CNetEvent_SoundWorld));
|
||||
}
|
||||
if(pChar7->m_TriggeredEvents & protocol7::COREEVENTFLAG_HOOK_ATTACH_GROUND)
|
||||
{
|
||||
void *pEvent = Builder.NewItem(NETEVENTTYPE_SOUNDWORLD, pItem7->Id(), sizeof(CNetEvent_SoundWorld));
|
||||
if(!pEvent)
|
||||
return -7;
|
||||
|
||||
CNetEvent_SoundWorld Sound = {};
|
||||
Sound.m_X = pChar7->m_X;
|
||||
Sound.m_Y = pChar7->m_Y;
|
||||
Sound.m_SoundId = SOUND_HOOK_ATTACH_GROUND;
|
||||
mem_copy(pEvent, &Sound, sizeof(CNetEvent_SoundWorld));
|
||||
}
|
||||
if(pChar7->m_TriggeredEvents & protocol7::COREEVENTFLAG_HOOK_HIT_NOHOOK)
|
||||
{
|
||||
void *pEvent = Builder.NewItem(NETEVENTTYPE_SOUNDWORLD, pItem7->Id(), sizeof(CNetEvent_SoundWorld));
|
||||
if(!pEvent)
|
||||
return -7;
|
||||
|
||||
CNetEvent_SoundWorld Sound = {};
|
||||
Sound.m_X = pChar7->m_X;
|
||||
Sound.m_Y = pChar7->m_Y;
|
||||
Sound.m_SoundId = SOUND_HOOK_NOATTACH;
|
||||
mem_copy(pEvent, &Sound, sizeof(CNetEvent_SoundWorld));
|
||||
}
|
||||
}
|
||||
|
||||
mem_copy(pObj, &Char6, sizeof(CNetObj_Character));
|
||||
}
|
||||
else if(pItem7->Type() == protocol7::NETOBJTYPE_PLAYERINFO)
|
||||
{
|
||||
void *pObj = Builder.NewItem(NETOBJTYPE_PLAYERINFO, pItem7->Id(), sizeof(CNetObj_PlayerInfo));
|
||||
if(!pObj)
|
||||
return -8;
|
||||
|
||||
const protocol7::CNetObj_PlayerInfo *pInfo7 = (const protocol7::CNetObj_PlayerInfo *)pItem7->Data();
|
||||
CNetObj_PlayerInfo Info6 = {};
|
||||
Info6.m_Local = TranslationContext.m_aLocalClientId[Conn] == pItem7->Id();
|
||||
Info6.m_ClientId = pItem7->Id();
|
||||
Info6.m_Team = 0;
|
||||
if(pItem7->Id() >= 0 && pItem7->Id() < MAX_CLIENTS)
|
||||
{
|
||||
Info6.m_Team = TranslationContext.m_aClients[pItem7->Id()].m_Team;
|
||||
TranslationContext.m_aClients[pItem7->Id()].m_PlayerFlags7 = pInfo7->m_PlayerFlags;
|
||||
}
|
||||
Info6.m_Score = pInfo7->m_Score;
|
||||
Info6.m_Latency = pInfo7->m_Latency;
|
||||
mem_copy(pObj, &Info6, sizeof(CNetObj_PlayerInfo));
|
||||
}
|
||||
else if(pItem7->Type() == protocol7::NETOBJTYPE_SPECTATORINFO)
|
||||
{
|
||||
void *pObj = Builder.NewItem(NETOBJTYPE_SPECTATORINFO, pItem7->Id(), sizeof(CNetObj_SpectatorInfo));
|
||||
if(!pObj)
|
||||
return -9;
|
||||
|
||||
const protocol7::CNetObj_SpectatorInfo *pSpec7 = (const protocol7::CNetObj_SpectatorInfo *)pItem7->Data();
|
||||
CNetObj_SpectatorInfo Spec6 = {};
|
||||
Spec6.m_SpectatorId = pSpec7->m_SpectatorId;
|
||||
if(pSpec7->m_SpecMode == protocol7::SPEC_FREEVIEW)
|
||||
Spec6.m_SpectatorId = SPEC_FREEVIEW;
|
||||
Spec6.m_X = pSpec7->m_X;
|
||||
Spec6.m_Y = pSpec7->m_Y;
|
||||
mem_copy(pObj, &Spec6, sizeof(CNetObj_SpectatorInfo));
|
||||
}
|
||||
else if(pItem7->Type() == protocol7::NETEVENTTYPE_EXPLOSION)
|
||||
{
|
||||
void *pEvent = Builder.NewItem(NETEVENTTYPE_EXPLOSION, pItem7->Id(), sizeof(CNetEvent_Explosion));
|
||||
if(!pEvent)
|
||||
return -10;
|
||||
|
||||
const protocol7::CNetEvent_Explosion *pExplosion7 = (const protocol7::CNetEvent_Explosion *)pItem7->Data();
|
||||
CNetEvent_Explosion Explosion6 = {};
|
||||
Explosion6.m_X = pExplosion7->m_X;
|
||||
Explosion6.m_Y = pExplosion7->m_Y;
|
||||
mem_copy(pEvent, &Explosion6, sizeof(CNetEvent_Explosion));
|
||||
}
|
||||
else if(pItem7->Type() == protocol7::NETEVENTTYPE_SPAWN)
|
||||
{
|
||||
void *pEvent = Builder.NewItem(NETEVENTTYPE_SPAWN, pItem7->Id(), sizeof(CNetEvent_Spawn));
|
||||
if(!pEvent)
|
||||
return -11;
|
||||
|
||||
const protocol7::CNetEvent_Spawn *pSpawn7 = (const protocol7::CNetEvent_Spawn *)pItem7->Data();
|
||||
CNetEvent_Spawn Spawn6 = {};
|
||||
Spawn6.m_X = pSpawn7->m_X;
|
||||
Spawn6.m_Y = pSpawn7->m_Y;
|
||||
mem_copy(pEvent, &Spawn6, sizeof(CNetEvent_Spawn));
|
||||
}
|
||||
else if(pItem7->Type() == protocol7::NETEVENTTYPE_HAMMERHIT)
|
||||
{
|
||||
void *pEvent = Builder.NewItem(NETEVENTTYPE_HAMMERHIT, pItem7->Id(), sizeof(CNetEvent_HammerHit));
|
||||
if(!pEvent)
|
||||
return -12;
|
||||
|
||||
const protocol7::CNetEvent_HammerHit *pHammerHit7 = (const protocol7::CNetEvent_HammerHit *)pItem7->Data();
|
||||
CNetEvent_HammerHit HammerHit6 = {};
|
||||
HammerHit6.m_X = pHammerHit7->m_X;
|
||||
HammerHit6.m_Y = pHammerHit7->m_Y;
|
||||
mem_copy(pEvent, &HammerHit6, sizeof(CNetEvent_HammerHit));
|
||||
}
|
||||
else if(pItem7->Type() == protocol7::NETEVENTTYPE_DEATH)
|
||||
{
|
||||
void *pEvent = Builder.NewItem(NETEVENTTYPE_DEATH, pItem7->Id(), sizeof(CNetEvent_Death));
|
||||
if(!pEvent)
|
||||
return -13;
|
||||
|
||||
const protocol7::CNetEvent_Death *pDeath7 = (const protocol7::CNetEvent_Death *)pItem7->Data();
|
||||
CNetEvent_Death Death6 = {};
|
||||
Death6.m_X = pDeath7->m_X;
|
||||
Death6.m_Y = pDeath7->m_Y;
|
||||
Death6.m_ClientId = pDeath7->m_ClientId;
|
||||
mem_copy(pEvent, &Death6, sizeof(CNetEvent_Death));
|
||||
}
|
||||
else if(pItem7->Type() == protocol7::NETEVENTTYPE_SOUNDWORLD)
|
||||
{
|
||||
void *pEvent = Builder.NewItem(NETEVENTTYPE_SOUNDWORLD, pItem7->Id(), sizeof(CNetEvent_SoundWorld));
|
||||
if(!pEvent)
|
||||
return -14;
|
||||
|
||||
const protocol7::CNetEvent_SoundWorld *pSoundWorld7 = (const protocol7::CNetEvent_SoundWorld *)pItem7->Data();
|
||||
CNetEvent_SoundWorld SoundWorld6 = {};
|
||||
SoundWorld6.m_X = pSoundWorld7->m_X;
|
||||
SoundWorld6.m_Y = pSoundWorld7->m_Y;
|
||||
SoundWorld6.m_SoundId = pSoundWorld7->m_SoundId;
|
||||
mem_copy(pEvent, &SoundWorld6, sizeof(CNetEvent_SoundWorld));
|
||||
}
|
||||
else if(pItem7->Type() == protocol7::NETEVENTTYPE_DAMAGE)
|
||||
{
|
||||
// 0.7 introduced amount for damage indicators
|
||||
// so for one 0.7 item we might create multiple 0.6 ones
|
||||
const protocol7::CNetEvent_Damage *pDmg7 = (const protocol7::CNetEvent_Damage *)pItem7->Data();
|
||||
|
||||
int Amount = pDmg7->m_HealthAmount + pDmg7->m_ArmorAmount;
|
||||
if(Amount < 1)
|
||||
continue;
|
||||
|
||||
int ClientId = pDmg7->m_ClientId;
|
||||
TranslationContext.m_aDamageTaken[ClientId]++;
|
||||
|
||||
float Angle;
|
||||
// create healthmod indicator
|
||||
if(LocalTime < TranslationContext.m_aDamageTakenTick[ClientId] + 0.5f)
|
||||
{
|
||||
// make sure that the damage indicators don't group together
|
||||
Angle = TranslationContext.m_aDamageTaken[ClientId] * 0.25f;
|
||||
}
|
||||
else
|
||||
{
|
||||
TranslationContext.m_aDamageTaken[ClientId] = 0;
|
||||
Angle = 0;
|
||||
}
|
||||
|
||||
TranslationContext.m_aDamageTakenTick[ClientId] = LocalTime;
|
||||
|
||||
float a = 3 * pi / 2 + Angle;
|
||||
float s = a - pi / 3;
|
||||
float e = a + pi / 3;
|
||||
for(int k = 0; k < Amount; k++)
|
||||
{
|
||||
// pItem7->Id() is reused that is technically wrong
|
||||
// but the client implementation does not look at the ids
|
||||
// and renders the damage indicators just fine
|
||||
void *pEvent = Builder.NewItem(NETEVENTTYPE_DAMAGEIND, pItem7->Id(), sizeof(CNetEvent_DamageInd));
|
||||
if(!pEvent)
|
||||
return -16;
|
||||
|
||||
CNetEvent_DamageInd Dmg6 = {};
|
||||
Dmg6.m_X = pDmg7->m_X;
|
||||
Dmg6.m_Y = pDmg7->m_Y;
|
||||
float f = mix(s, e, float(k + 1) / float(Amount + 2));
|
||||
Dmg6.m_Angle = (int)(f * 256.0f);
|
||||
mem_copy(pEvent, &Dmg6, sizeof(CNetEvent_DamageInd));
|
||||
}
|
||||
}
|
||||
else if(pItem7->Type() == protocol7::NETOBJTYPE_DE_CLIENTINFO)
|
||||
{
|
||||
const protocol7::CNetObj_De_ClientInfo *pInfo = (const protocol7::CNetObj_De_ClientInfo *)pItem7->Data();
|
||||
|
||||
const int ClientId = pItem7->Id();
|
||||
|
||||
if(ClientId < 0 || ClientId >= MAX_CLIENTS)
|
||||
{
|
||||
dbg_msg("sixup", "De_ClientInfo got invalid ClientId: %d", ClientId);
|
||||
return -17;
|
||||
}
|
||||
|
||||
if(pInfo->m_Local)
|
||||
{
|
||||
TranslationContext.m_aLocalClientId[Conn] = ClientId;
|
||||
}
|
||||
CTranslationContext::CClientData &Client = TranslationContext.m_aClients[ClientId];
|
||||
Client.m_Active = true;
|
||||
Client.m_Team = pInfo->m_Team;
|
||||
IntsToStr(pInfo->m_aName, 4, Client.m_aName, std::size(Client.m_aName));
|
||||
IntsToStr(pInfo->m_aClan, 3, Client.m_aClan, std::size(Client.m_aClan));
|
||||
Client.m_Country = pInfo->m_Country;
|
||||
|
||||
ApplySkin7InfoFromSnapObj(pInfo, ClientId);
|
||||
}
|
||||
else if(pItem7->Type() == protocol7::NETOBJTYPE_DE_GAMEINFO)
|
||||
{
|
||||
const protocol7::CNetObj_De_GameInfo *pInfo = (const protocol7::CNetObj_De_GameInfo *)pItem7->Data();
|
||||
|
||||
TranslationContext.m_GameFlags = pInfo->m_GameFlags;
|
||||
TranslationContext.m_ScoreLimit = pInfo->m_ScoreLimit;
|
||||
TranslationContext.m_TimeLimit = pInfo->m_TimeLimit;
|
||||
TranslationContext.m_MatchNum = pInfo->m_MatchNum;
|
||||
TranslationContext.m_MatchCurrent = pInfo->m_MatchCurrent;
|
||||
TranslationContext.m_ShouldSendGameInfo = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(NewGameData)
|
||||
{
|
||||
void *pObj = Builder.NewItem(NETOBJTYPE_GAMEDATA, 0, sizeof(CNetObj_GameData));
|
||||
if(!pObj)
|
||||
return -17;
|
||||
|
||||
CNetObj_GameData GameData = {};
|
||||
GameData.m_TeamscoreRed = TranslationContext.m_TeamscoreRed;
|
||||
GameData.m_TeamscoreBlue = TranslationContext.m_TeamscoreBlue;
|
||||
GameData.m_FlagCarrierRed = TranslationContext.m_FlagCarrierRed;
|
||||
GameData.m_FlagCarrierBlue = TranslationContext.m_FlagCarrierBlue;
|
||||
mem_copy(pObj, &GameData, sizeof(CNetObj_GameData));
|
||||
}
|
||||
|
||||
return Builder.Finish(pSnapDstSix);
|
||||
}
|
||||
|
||||
int CGameClient::OnDemoRecSnap7(CSnapshot *pFrom, CSnapshot *pTo, int Conn)
|
||||
{
|
||||
CSnapshotBuilder Builder;
|
||||
Builder.Init7(pFrom);
|
||||
|
||||
// add client info
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
if(!m_aClients[i].m_Active)
|
||||
continue;
|
||||
|
||||
void *pItem = Builder.NewItem(protocol7::NETOBJTYPE_DE_CLIENTINFO, i, sizeof(protocol7::CNetObj_De_ClientInfo));
|
||||
if(!pItem)
|
||||
return -1;
|
||||
|
||||
CTranslationContext::CClientData &ClientData = Client()->m_TranslationContext.m_aClients[i];
|
||||
|
||||
protocol7::CNetObj_De_ClientInfo ClientInfoObj;
|
||||
ClientInfoObj.m_Local = i == Client()->m_TranslationContext.m_aLocalClientId[Conn];
|
||||
ClientInfoObj.m_Team = ClientData.m_Team;
|
||||
StrToInts(ClientInfoObj.m_aName, 4, m_aClients[i].m_aName);
|
||||
StrToInts(ClientInfoObj.m_aClan, 3, m_aClients[i].m_aClan);
|
||||
ClientInfoObj.m_Country = ClientData.m_Country;
|
||||
|
||||
for(int Part = 0; Part < protocol7::NUM_SKINPARTS; Part++)
|
||||
{
|
||||
StrToInts(ClientInfoObj.m_aaSkinPartNames[Part], 6, m_aClients[i].m_Sixup.m_aaSkinPartNames[Part]);
|
||||
ClientInfoObj.m_aUseCustomColors[Part] = m_aClients[i].m_Sixup.m_aUseCustomColors[Part];
|
||||
ClientInfoObj.m_aSkinPartColors[Part] = m_aClients[i].m_Sixup.m_aSkinPartColors[Part];
|
||||
}
|
||||
|
||||
mem_copy(pItem, &ClientInfoObj, sizeof(protocol7::CNetObj_De_ClientInfo));
|
||||
}
|
||||
|
||||
// add tuning
|
||||
CTuningParams StandardTuning;
|
||||
if(mem_comp(&StandardTuning, &m_aTuning[Conn], sizeof(CTuningParams)) != 0)
|
||||
{
|
||||
void *pItem = Builder.NewItem(protocol7::NETOBJTYPE_DE_TUNEPARAMS, 0, sizeof(protocol7::CNetObj_De_TuneParams));
|
||||
if(!pItem)
|
||||
return -2;
|
||||
|
||||
protocol7::CNetObj_De_TuneParams TuneParams;
|
||||
mem_copy(&TuneParams.m_aTuneParams, &m_aTuning[Conn], sizeof(TuneParams));
|
||||
mem_copy(pItem, &TuneParams, sizeof(protocol7::CNetObj_De_TuneParams));
|
||||
}
|
||||
|
||||
// add game info
|
||||
void *pItem = Builder.NewItem(protocol7::NETOBJTYPE_DE_GAMEINFO, 0, sizeof(protocol7::CNetObj_De_GameInfo));
|
||||
if(!pItem)
|
||||
return -3;
|
||||
|
||||
protocol7::CNetObj_De_GameInfo GameInfo;
|
||||
|
||||
GameInfo.m_GameFlags = Client()->m_TranslationContext.m_GameFlags;
|
||||
GameInfo.m_ScoreLimit = Client()->m_TranslationContext.m_ScoreLimit;
|
||||
GameInfo.m_TimeLimit = Client()->m_TranslationContext.m_TimeLimit;
|
||||
GameInfo.m_MatchNum = Client()->m_TranslationContext.m_MatchNum;
|
||||
GameInfo.m_MatchCurrent = Client()->m_TranslationContext.m_MatchCurrent;
|
||||
|
||||
mem_copy(pItem, &GameInfo, sizeof(protocol7::CNetObj_De_GameInfo));
|
||||
|
||||
return Builder.Finish(pTo);
|
||||
}
|
Loading…
Reference in a new issue