mirror of
https://github.com/ddnet/ddnet.git
synced 2024-09-19 01:02:20 +00:00
Compare commits
10 commits
f3ae436842
...
b8eee4c25f
Author | SHA1 | Date | |
---|---|---|---|
b8eee4c25f | |||
fc058fa432 | |||
3b22a3e02f | |||
ed1ef4e694 | |||
9103332e36 | |||
0948a53648 | |||
bbd34c9452 | |||
e4282f100a | |||
eb9e73f68b | |||
7c45688fd2 |
|
@ -378,6 +378,15 @@ Objects = [
|
||||||
NetEventEx("MapSoundWorld:Common", "map-sound-world@netevent.ddnet.org", [
|
NetEventEx("MapSoundWorld:Common", "map-sound-world@netevent.ddnet.org", [
|
||||||
NetIntAny("m_SoundId"),
|
NetIntAny("m_SoundId"),
|
||||||
]),
|
]),
|
||||||
|
|
||||||
|
# Spectating cursor
|
||||||
|
NetObjectEx("SpecCursor", "spec-cursor@netobj.ddnet.org", [
|
||||||
|
NetIntAny("m_Weapon"),
|
||||||
|
NetIntAny("m_TargetX"),
|
||||||
|
NetIntAny("m_TargetY"),
|
||||||
|
NetIntAny("m_DeltaPrevTargetX"),
|
||||||
|
NetIntAny("m_DeltaPrevTargetY"),
|
||||||
|
]),
|
||||||
]
|
]
|
||||||
|
|
||||||
Messages = [
|
Messages = [
|
||||||
|
|
|
@ -668,10 +668,7 @@ void CClient::DisconnectWithReason(const char *pReason)
|
||||||
m_CurrentServerCurrentPingTime = -1;
|
m_CurrentServerCurrentPingTime = -1;
|
||||||
m_CurrentServerNextPingTime = -1;
|
m_CurrentServerNextPingTime = -1;
|
||||||
|
|
||||||
ResetMapDownload();
|
ResetMapDownload(true);
|
||||||
m_aMapdownloadFilename[0] = '\0';
|
|
||||||
m_aMapdownloadFilenameTemp[0] = '\0';
|
|
||||||
m_aMapdownloadName[0] = '\0';
|
|
||||||
|
|
||||||
// clear the current server info
|
// clear the current server info
|
||||||
mem_zero(&m_CurrentServerInfo, sizeof(m_CurrentServerInfo));
|
mem_zero(&m_CurrentServerInfo, sizeof(m_CurrentServerInfo));
|
||||||
|
@ -1528,7 +1525,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket, int Conn, bool Dummy)
|
||||||
DummyDisconnect(0);
|
DummyDisconnect(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResetMapDownload();
|
ResetMapDownload(true);
|
||||||
|
|
||||||
SHA256_DIGEST *pMapSha256 = nullptr;
|
SHA256_DIGEST *pMapSha256 = nullptr;
|
||||||
const char *pMapUrl = nullptr;
|
const char *pMapUrl = nullptr;
|
||||||
|
@ -2196,7 +2193,7 @@ int CClient::UnpackAndValidateSnapshot(CSnapshot *pFrom, CSnapshot *pTo)
|
||||||
return Builder.Finish(pTo);
|
return Builder.Finish(pTo);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CClient::ResetMapDownload()
|
void CClient::ResetMapDownload(bool ResetActive)
|
||||||
{
|
{
|
||||||
if(m_pMapdownloadTask)
|
if(m_pMapdownloadTask)
|
||||||
{
|
{
|
||||||
|
@ -2215,19 +2212,24 @@ void CClient::ResetMapDownload()
|
||||||
Storage()->RemoveFile(m_aMapdownloadFilenameTemp, IStorage::TYPE_SAVE);
|
Storage()->RemoveFile(m_aMapdownloadFilenameTemp, IStorage::TYPE_SAVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_MapdownloadChunk = 0;
|
if(ResetActive)
|
||||||
m_MapdownloadSha256Present = false;
|
{
|
||||||
m_MapdownloadSha256 = SHA256_ZEROED;
|
m_MapdownloadChunk = 0;
|
||||||
m_MapdownloadCrc = 0;
|
m_MapdownloadSha256Present = false;
|
||||||
m_MapdownloadTotalsize = -1;
|
m_MapdownloadSha256 = SHA256_ZEROED;
|
||||||
m_MapdownloadAmount = 0;
|
m_MapdownloadCrc = 0;
|
||||||
|
m_MapdownloadTotalsize = -1;
|
||||||
|
m_MapdownloadAmount = 0;
|
||||||
|
m_aMapdownloadFilename[0] = '\0';
|
||||||
|
m_aMapdownloadFilenameTemp[0] = '\0';
|
||||||
|
m_aMapdownloadName[0] = '\0';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CClient::FinishMapDownload()
|
void CClient::FinishMapDownload()
|
||||||
{
|
{
|
||||||
m_pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "client/network", "download complete, loading map");
|
m_pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "client/network", "download complete, loading map");
|
||||||
|
|
||||||
const int PrevMapdownloadTotalsize = m_MapdownloadTotalsize;
|
|
||||||
SHA256_DIGEST *pSha256 = m_MapdownloadSha256Present ? &m_MapdownloadSha256 : nullptr;
|
SHA256_DIGEST *pSha256 = m_MapdownloadSha256Present ? &m_MapdownloadSha256 : nullptr;
|
||||||
|
|
||||||
bool FileSuccess = true;
|
bool FileSuccess = true;
|
||||||
|
@ -2236,7 +2238,6 @@ void CClient::FinishMapDownload()
|
||||||
FileSuccess &= Storage()->RenameFile(m_aMapdownloadFilenameTemp, m_aMapdownloadFilename, IStorage::TYPE_SAVE);
|
FileSuccess &= Storage()->RenameFile(m_aMapdownloadFilenameTemp, m_aMapdownloadFilename, IStorage::TYPE_SAVE);
|
||||||
if(!FileSuccess)
|
if(!FileSuccess)
|
||||||
{
|
{
|
||||||
ResetMapDownload();
|
|
||||||
char aError[128 + IO_MAX_PATH_LENGTH];
|
char aError[128 + IO_MAX_PATH_LENGTH];
|
||||||
str_format(aError, sizeof(aError), Localize("Could not save downloaded map. Try manually deleting this file: %s"), m_aMapdownloadFilename);
|
str_format(aError, sizeof(aError), Localize("Could not save downloaded map. Try manually deleting this file: %s"), m_aMapdownloadFilename);
|
||||||
DisconnectWithReason(aError);
|
DisconnectWithReason(aError);
|
||||||
|
@ -2246,19 +2247,17 @@ void CClient::FinishMapDownload()
|
||||||
const char *pError = LoadMap(m_aMapdownloadName, m_aMapdownloadFilename, pSha256, m_MapdownloadCrc);
|
const char *pError = LoadMap(m_aMapdownloadName, m_aMapdownloadFilename, pSha256, m_MapdownloadCrc);
|
||||||
if(!pError)
|
if(!pError)
|
||||||
{
|
{
|
||||||
ResetMapDownload();
|
ResetMapDownload(true);
|
||||||
m_pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "client/network", "loading done");
|
m_pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "client/network", "loading done");
|
||||||
SendReady(CONN_MAIN);
|
SendReady(CONN_MAIN);
|
||||||
}
|
}
|
||||||
else if(m_pMapdownloadTask) // fallback
|
else if(m_pMapdownloadTask) // fallback
|
||||||
{
|
{
|
||||||
ResetMapDownload();
|
ResetMapDownload(false);
|
||||||
m_MapdownloadTotalsize = PrevMapdownloadTotalsize;
|
|
||||||
SendMapRequest();
|
SendMapRequest();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ResetMapDownload();
|
|
||||||
DisconnectWithReason(pError);
|
DisconnectWithReason(pError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2784,7 +2783,7 @@ void CClient::Update()
|
||||||
else if(m_pMapdownloadTask->State() == EHttpState::ERROR || m_pMapdownloadTask->State() == EHttpState::ABORTED)
|
else if(m_pMapdownloadTask->State() == EHttpState::ERROR || m_pMapdownloadTask->State() == EHttpState::ABORTED)
|
||||||
{
|
{
|
||||||
dbg_msg("webdl", "http failed, falling back to gameserver");
|
dbg_msg("webdl", "http failed, falling back to gameserver");
|
||||||
ResetMapDownload();
|
ResetMapDownload(false);
|
||||||
SendMapRequest();
|
SendMapRequest();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -360,7 +360,7 @@ public:
|
||||||
|
|
||||||
int UnpackAndValidateSnapshot(CSnapshot *pFrom, CSnapshot *pTo);
|
int UnpackAndValidateSnapshot(CSnapshot *pFrom, CSnapshot *pTo);
|
||||||
|
|
||||||
void ResetMapDownload();
|
void ResetMapDownload(bool ResetActive);
|
||||||
void FinishMapDownload();
|
void FinishMapDownload();
|
||||||
|
|
||||||
void RequestDDNetInfo() override;
|
void RequestDDNetInfo() override;
|
||||||
|
|
|
@ -73,6 +73,9 @@ MACRO_CONFIG_INT(ClShowfps, cl_showfps, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE,
|
||||||
MACRO_CONFIG_INT(ClShowpred, cl_showpred, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show ingame prediction time in milliseconds")
|
MACRO_CONFIG_INT(ClShowpred, cl_showpred, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show ingame prediction time in milliseconds")
|
||||||
MACRO_CONFIG_INT(ClEyeWheel, cl_eye_wheel, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show eye wheel along together with emotes")
|
MACRO_CONFIG_INT(ClEyeWheel, cl_eye_wheel, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show eye wheel along together with emotes")
|
||||||
MACRO_CONFIG_INT(ClEyeDuration, cl_eye_duration, 999999, 1, 999999, CFGFLAG_CLIENT | CFGFLAG_SAVE, "How long the eyes emotes last")
|
MACRO_CONFIG_INT(ClEyeDuration, cl_eye_duration, 999999, 1, 999999, CFGFLAG_CLIENT | CFGFLAG_SAVE, "How long the eyes emotes last")
|
||||||
|
MACRO_CONFIG_INT(ClSpecCursor, cl_spec_cursor, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Enable the cursor of spectating player if available")
|
||||||
|
MACRO_CONFIG_INT(ClSpecCursorInterp, cl_spec_cursor_interp, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Interpolate the cursor of spectating player")
|
||||||
|
MACRO_CONFIG_INT(ClSpecCursorDemo, cl_spec_cursor_demo, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show cursor during demo playback if available")
|
||||||
|
|
||||||
MACRO_CONFIG_INT(ClAirjumpindicator, cl_airjumpindicator, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show the air jump indicator")
|
MACRO_CONFIG_INT(ClAirjumpindicator, cl_airjumpindicator, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show the air jump indicator")
|
||||||
MACRO_CONFIG_INT(ClThreadsoundloading, cl_threadsoundloading, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Load sound files threaded")
|
MACRO_CONFIG_INT(ClThreadsoundloading, cl_threadsoundloading, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Load sound files threaded")
|
||||||
|
|
|
@ -585,16 +585,35 @@ void CHud::RenderTeambalanceWarning()
|
||||||
|
|
||||||
void CHud::RenderCursor()
|
void CHud::RenderCursor()
|
||||||
{
|
{
|
||||||
if(!m_pClient->m_Snap.m_pLocalCharacter || Client()->State() == IClient::STATE_DEMOPLAYBACK)
|
int CurWeapon;
|
||||||
|
vec2 TargetPos;
|
||||||
|
|
||||||
|
if(Client()->State() != IClient::STATE_DEMOPLAYBACK && m_pClient->m_Snap.m_pLocalCharacter)
|
||||||
|
{
|
||||||
|
// render local cursor
|
||||||
|
CurWeapon = m_pClient->m_Snap.m_pLocalCharacter->m_Weapon % NUM_WEAPONS;
|
||||||
|
TargetPos = m_pClient->m_Controls.m_aTargetPos[g_Config.m_ClDummy];
|
||||||
|
}
|
||||||
|
else if(g_Config.m_ClSpecCursor && m_pClient->m_Snap.m_pSpecCursor && m_pClient->m_Snap.m_SpecInfo.m_Active && m_pClient->m_Snap.m_SpecInfo.m_SpectatorId != SPEC_FREEVIEW)
|
||||||
|
{
|
||||||
|
// render spec cursor
|
||||||
|
CurWeapon = m_pClient->m_Snap.m_pSpecCursor->m_Weapon % NUM_WEAPONS;
|
||||||
|
TargetPos = m_pClient->m_Snap.m_SpecInfo.m_Position + m_pClient->m_Snap.m_DisplayCursorPos;
|
||||||
|
}
|
||||||
|
else if(g_Config.m_ClSpecCursorDemo && m_pClient->m_Snap.m_pSpecCursor && Client()->State() == IClient::STATE_DEMOPLAYBACK && m_pClient->m_Snap.m_pLocalCharacter)
|
||||||
|
{
|
||||||
|
CurWeapon = m_pClient->m_Snap.m_pLocalCharacter->m_Weapon % NUM_WEAPONS;
|
||||||
|
TargetPos = m_pClient->m_LocalCharacterPos + m_pClient->m_Snap.m_DisplayCursorPos;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
RenderTools()->MapScreenToInterface(m_pClient->m_Camera.m_Center.x, m_pClient->m_Camera.m_Center.y);
|
RenderTools()->MapScreenToInterface(m_pClient->m_Camera.m_Center.x, m_pClient->m_Camera.m_Center.y);
|
||||||
|
|
||||||
// render cursor
|
|
||||||
int CurWeapon = m_pClient->m_Snap.m_pLocalCharacter->m_Weapon % NUM_WEAPONS;
|
|
||||||
Graphics()->SetColor(1.f, 1.f, 1.f, 1.f);
|
Graphics()->SetColor(1.f, 1.f, 1.f, 1.f);
|
||||||
Graphics()->TextureSet(m_pClient->m_GameSkin.m_aSpriteWeaponCursors[CurWeapon]);
|
Graphics()->TextureSet(m_pClient->m_GameSkin.m_aSpriteWeaponCursors[CurWeapon]);
|
||||||
Graphics()->RenderQuadContainerAsSprite(m_HudQuadContainerIndex, m_aCursorOffset[CurWeapon], m_pClient->m_Controls.m_aTargetPos[g_Config.m_ClDummy].x, m_pClient->m_Controls.m_aTargetPos[g_Config.m_ClDummy].y);
|
Graphics()->RenderQuadContainerAsSprite(m_HudQuadContainerIndex, m_aCursorOffset[CurWeapon], TargetPos.x, TargetPos.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CHud::PrepareAmmoHealthAndArmorQuads()
|
void CHud::PrepareAmmoHealthAndArmorQuads()
|
||||||
|
|
|
@ -718,6 +718,8 @@ void CGameClient::UpdatePositions()
|
||||||
if(!m_MultiViewActivated && m_MultiView.m_IsInit)
|
if(!m_MultiViewActivated && m_MultiView.m_IsInit)
|
||||||
ResetMultiView();
|
ResetMultiView();
|
||||||
|
|
||||||
|
UpdateSpectatorCursor();
|
||||||
|
|
||||||
UpdateRenderedCharacters();
|
UpdateRenderedCharacters();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1831,6 +1833,11 @@ void CGameClient::OnNewSnapshot()
|
||||||
m_aSwitchStateTeam[g_Config.m_ClDummy] = -1;
|
m_aSwitchStateTeam[g_Config.m_ClDummy] = -1;
|
||||||
GotSwitchStateTeam = true;
|
GotSwitchStateTeam = true;
|
||||||
}
|
}
|
||||||
|
else if(Item.m_Type == NETOBJTYPE_SPECCURSOR)
|
||||||
|
{
|
||||||
|
m_Snap.m_pSpecCursor = (const CNetObj_SpecCursor *)Item.m_pData;
|
||||||
|
m_Snap.m_pPrevSpecCursor = (const CNetObj_SpecCursor *)Client()->SnapFindItem(IClient::SNAP_PREV, NETOBJTYPE_SPECCURSOR, Item.m_Id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2985,6 +2992,55 @@ void CGameClient::UpdatePrediction()
|
||||||
m_GameWorld.NetObjEnd();
|
m_GameWorld.NetObjEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CGameClient::UpdateSpectatorCursor()
|
||||||
|
{
|
||||||
|
if(m_Snap.m_pSpecCursor)
|
||||||
|
{
|
||||||
|
const float IntraTickSincePrev = Client()->IntraGameTickSincePrev(g_Config.m_ClDummy);
|
||||||
|
|
||||||
|
// Decode previous cursor position from current snapshot
|
||||||
|
const int TargetX = m_Snap.m_pSpecCursor->m_TargetX;
|
||||||
|
const int TargetY = m_Snap.m_pSpecCursor->m_TargetY;
|
||||||
|
|
||||||
|
const int PrevTargetX = TargetX + m_Snap.m_pSpecCursor->m_DeltaPrevTargetX;
|
||||||
|
const int PrevTargetY = TargetY + m_Snap.m_pSpecCursor->m_DeltaPrevTargetY;
|
||||||
|
|
||||||
|
int PrevPrevTargetX, PrevPrevTargetY;
|
||||||
|
int PrevPrevPrevTargetX, PrevPrevPrevTargetY;
|
||||||
|
|
||||||
|
if(m_Snap.m_pPrevSpecCursor)
|
||||||
|
{
|
||||||
|
PrevPrevTargetX = m_Snap.m_pPrevSpecCursor->m_TargetX;
|
||||||
|
PrevPrevTargetY = m_Snap.m_pPrevSpecCursor->m_TargetY;
|
||||||
|
PrevPrevPrevTargetX = PrevPrevTargetX + m_Snap.m_pPrevSpecCursor->m_DeltaPrevTargetX;
|
||||||
|
PrevPrevPrevTargetY = PrevPrevTargetY + m_Snap.m_pPrevSpecCursor->m_DeltaPrevTargetY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PrevPrevTargetX = PrevTargetX;
|
||||||
|
PrevPrevTargetY = PrevTargetY;
|
||||||
|
PrevPrevPrevTargetX = PrevTargetX;
|
||||||
|
PrevPrevPrevTargetY = PrevTargetX;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(IntraTickSincePrev <= 1.0f)
|
||||||
|
{
|
||||||
|
float Intra = g_Config.m_ClSpecCursorInterp ? IntraTickSincePrev : 1.0f;
|
||||||
|
m_Snap.m_DisplayCursorPos = mix(vec2(PrevPrevPrevTargetX, PrevPrevPrevTargetY), vec2(PrevPrevTargetX, PrevPrevTargetY), Intra);
|
||||||
|
}
|
||||||
|
else if(IntraTickSincePrev <= 2.0f)
|
||||||
|
{
|
||||||
|
float Intra = g_Config.m_ClSpecCursorInterp ? IntraTickSincePrev - 1.0f : 1.0f;
|
||||||
|
m_Snap.m_DisplayCursorPos = mix(vec2(PrevPrevTargetX, PrevPrevTargetY), vec2(PrevTargetX, PrevTargetY), Intra);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float Intra = g_Config.m_ClSpecCursorInterp ? IntraTickSincePrev - 2.0f : 1.0f;
|
||||||
|
m_Snap.m_DisplayCursorPos = mix(vec2(PrevTargetX, PrevTargetY), vec2(TargetX, TargetY), Intra);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CGameClient::UpdateRenderedCharacters()
|
void CGameClient::UpdateRenderedCharacters()
|
||||||
{
|
{
|
||||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||||
|
|
|
@ -313,6 +313,8 @@ public:
|
||||||
const CNetObj_PlayerInfo *m_pLocalInfo;
|
const CNetObj_PlayerInfo *m_pLocalInfo;
|
||||||
const CNetObj_SpectatorInfo *m_pSpectatorInfo;
|
const CNetObj_SpectatorInfo *m_pSpectatorInfo;
|
||||||
const CNetObj_SpectatorInfo *m_pPrevSpectatorInfo;
|
const CNetObj_SpectatorInfo *m_pPrevSpectatorInfo;
|
||||||
|
const CNetObj_SpecCursor *m_pSpecCursor;
|
||||||
|
const CNetObj_SpecCursor *m_pPrevSpecCursor;
|
||||||
const CNetObj_Flag *m_apFlags[2];
|
const CNetObj_Flag *m_apFlags[2];
|
||||||
const CNetObj_GameInfo *m_pGameInfoObj;
|
const CNetObj_GameInfo *m_pGameInfoObj;
|
||||||
const CNetObj_GameData *m_pGameDataObj;
|
const CNetObj_GameData *m_pGameDataObj;
|
||||||
|
@ -338,6 +340,9 @@ public:
|
||||||
vec2 m_Position;
|
vec2 m_Position;
|
||||||
} m_SpecInfo;
|
} m_SpecInfo;
|
||||||
|
|
||||||
|
// cursor data
|
||||||
|
vec2 m_DisplayCursorPos;
|
||||||
|
|
||||||
//
|
//
|
||||||
struct CCharacterInfo
|
struct CCharacterInfo
|
||||||
{
|
{
|
||||||
|
@ -794,6 +799,7 @@ private:
|
||||||
int m_aShowOthers[NUM_DUMMIES];
|
int m_aShowOthers[NUM_DUMMIES];
|
||||||
|
|
||||||
void UpdatePrediction();
|
void UpdatePrediction();
|
||||||
|
void UpdateSpectatorCursor();
|
||||||
void UpdateRenderedCharacters();
|
void UpdateRenderedCharacters();
|
||||||
|
|
||||||
int m_aLastUpdateTick[MAX_CLIENTS] = {0};
|
int m_aLastUpdateTick[MAX_CLIENTS] = {0};
|
||||||
|
|
|
@ -123,6 +123,13 @@ bool CCharacter::Spawn(CPlayer *pPlayer, vec2 Pos)
|
||||||
delete GameServer()->m_apSavedTees[m_pPlayer->GetCid()];
|
delete GameServer()->m_apSavedTees[m_pPlayer->GetCid()];
|
||||||
GameServer()->m_apSavedTees[m_pPlayer->GetCid()] = nullptr;
|
GameServer()->m_apSavedTees[m_pPlayer->GetCid()] = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(GameServer()->m_apSavedTeleTees[m_pPlayer->GetCid()])
|
||||||
|
{
|
||||||
|
m_pPlayer->m_LastTeleTee = *GameServer()->m_apSavedTeleTees[m_pPlayer->GetCid()];
|
||||||
|
delete GameServer()->m_apSavedTeleTees[m_pPlayer->GetCid()];
|
||||||
|
GameServer()->m_apSavedTeleTees[m_pPlayer->GetCid()] = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -1136,6 +1143,24 @@ void CCharacter::SnapCharacter(int SnappingClient, int Id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CCharacter::SnapSpecCursor(int SnappingClient)
|
||||||
|
{
|
||||||
|
CNetObj_SpecCursor *pCursorInfo = static_cast<CNetObj_SpecCursor *>(Server()->SnapNewItem(NETOBJTYPE_SPECCURSOR, SnappingClient, sizeof(CNetObj_SpecCursor)));
|
||||||
|
if(pCursorInfo)
|
||||||
|
{
|
||||||
|
pCursorInfo->m_Weapon = GetActiveWeapon();
|
||||||
|
|
||||||
|
pCursorInfo->m_TargetX = m_Input.m_TargetX;
|
||||||
|
pCursorInfo->m_TargetY = m_Input.m_TargetY;
|
||||||
|
|
||||||
|
/*
|
||||||
|
ensure info density at SERVER_TICK_SPEED even if sv_high_bandwidth is 0
|
||||||
|
*/
|
||||||
|
pCursorInfo->m_DeltaPrevTargetX = m_PrevInput.m_TargetX - m_Input.m_TargetX;
|
||||||
|
pCursorInfo->m_DeltaPrevTargetY = m_PrevInput.m_TargetY - m_Input.m_TargetY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool CCharacter::CanSnapCharacter(int SnappingClient)
|
bool CCharacter::CanSnapCharacter(int SnappingClient)
|
||||||
{
|
{
|
||||||
if(SnappingClient == SERVER_DEMO_CLIENT)
|
if(SnappingClient == SERVER_DEMO_CLIENT)
|
||||||
|
|
|
@ -100,6 +100,8 @@ public:
|
||||||
void AddVelocity(vec2 Addition);
|
void AddVelocity(vec2 Addition);
|
||||||
void ApplyMoveRestrictions();
|
void ApplyMoveRestrictions();
|
||||||
|
|
||||||
|
void SnapSpecCursor(int SnappingClient);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// player controlling this character
|
// player controlling this character
|
||||||
class CPlayer *m_pPlayer;
|
class CPlayer *m_pPlayer;
|
||||||
|
|
|
@ -108,6 +108,9 @@ void CGameContext::Construct(int Resetting)
|
||||||
for(auto &pSavedTee : m_apSavedTees)
|
for(auto &pSavedTee : m_apSavedTees)
|
||||||
pSavedTee = nullptr;
|
pSavedTee = nullptr;
|
||||||
|
|
||||||
|
for(auto &pSavedTeleTee : m_apSavedTeleTees)
|
||||||
|
pSavedTeleTee = nullptr;
|
||||||
|
|
||||||
for(auto &pSavedTeam : m_apSavedTeams)
|
for(auto &pSavedTeam : m_apSavedTeams)
|
||||||
pSavedTeam = nullptr;
|
pSavedTeam = nullptr;
|
||||||
|
|
||||||
|
@ -131,6 +134,9 @@ void CGameContext::Destruct(int Resetting)
|
||||||
for(auto &pSavedTee : m_apSavedTees)
|
for(auto &pSavedTee : m_apSavedTees)
|
||||||
delete pSavedTee;
|
delete pSavedTee;
|
||||||
|
|
||||||
|
for(auto &pSavedTeleTee : m_apSavedTeleTees)
|
||||||
|
delete pSavedTeleTee;
|
||||||
|
|
||||||
for(auto &pSavedTeam : m_apSavedTeams)
|
for(auto &pSavedTeam : m_apSavedTeams)
|
||||||
delete pSavedTeam;
|
delete pSavedTeam;
|
||||||
|
|
||||||
|
@ -773,7 +779,6 @@ void CGameContext::StartVote(const char *pDesc, const char *pCommand, const char
|
||||||
{
|
{
|
||||||
// reset votes
|
// reset votes
|
||||||
m_VoteEnforce = VOTE_ENFORCE_UNKNOWN;
|
m_VoteEnforce = VOTE_ENFORCE_UNKNOWN;
|
||||||
m_VoteEnforcer = -1;
|
|
||||||
for(auto &pPlayer : m_apPlayers)
|
for(auto &pPlayer : m_apPlayers)
|
||||||
{
|
{
|
||||||
if(pPlayer)
|
if(pPlayer)
|
||||||
|
@ -1204,7 +1209,7 @@ void CGameContext::OnTick()
|
||||||
}
|
}
|
||||||
else if(m_VoteEnforce == VOTE_ENFORCE_YES_ADMIN)
|
else if(m_VoteEnforce == VOTE_ENFORCE_YES_ADMIN)
|
||||||
{
|
{
|
||||||
Console()->ExecuteLine(m_aVoteCommand, m_VoteEnforcer);
|
Console()->ExecuteLine(m_aVoteCommand, m_VoteCreator);
|
||||||
SendChat(-1, TEAM_ALL, "Vote passed enforced by authorized player", -1, FLAG_SIX);
|
SendChat(-1, TEAM_ALL, "Vote passed enforced by authorized player", -1, FLAG_SIX);
|
||||||
EndVote();
|
EndVote();
|
||||||
}
|
}
|
||||||
|
@ -1712,6 +1717,9 @@ void CGameContext::OnClientDrop(int ClientId, const char *pReason)
|
||||||
delete m_apSavedTees[ClientId];
|
delete m_apSavedTees[ClientId];
|
||||||
m_apSavedTees[ClientId] = nullptr;
|
m_apSavedTees[ClientId] = nullptr;
|
||||||
|
|
||||||
|
delete m_apSavedTeleTees[ClientId];
|
||||||
|
m_apSavedTeleTees[ClientId] = nullptr;
|
||||||
|
|
||||||
m_aTeamMapping[ClientId] = -1;
|
m_aTeamMapping[ClientId] = -1;
|
||||||
|
|
||||||
m_VoteUpdate = true;
|
m_VoteUpdate = true;
|
||||||
|
@ -3208,12 +3216,19 @@ void CGameContext::ConHotReload(IConsole::IResult *pResult, void *pUserData)
|
||||||
if(!pSelf->GetPlayerChar(i))
|
if(!pSelf->GetPlayerChar(i))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
CCharacter *pChar = pSelf->GetPlayerChar(i);
|
||||||
|
|
||||||
// Save the tee individually
|
// Save the tee individually
|
||||||
pSelf->m_apSavedTees[i] = new CSaveTee();
|
pSelf->m_apSavedTees[i] = new CSaveTee();
|
||||||
pSelf->m_apSavedTees[i]->Save(pSelf->GetPlayerChar(i), false);
|
pSelf->m_apSavedTees[i]->Save(pChar, false);
|
||||||
|
|
||||||
|
if(pSelf->m_apPlayers[i])
|
||||||
|
pSelf->m_apSavedTeleTees[i] = new CSaveTee(pSelf->m_apPlayers[i]->m_LastTeleTee);
|
||||||
|
|
||||||
// Save the team state
|
// Save the team state
|
||||||
pSelf->m_aTeamMapping[i] = pSelf->GetDDRaceTeam(i);
|
pSelf->m_aTeamMapping[i] = pSelf->GetDDRaceTeam(i);
|
||||||
|
if(pSelf->m_aTeamMapping[i] == TEAM_SUPER)
|
||||||
|
pSelf->m_aTeamMapping[i] = pChar->m_TeamBeforeSuper;
|
||||||
|
|
||||||
if(pSelf->m_apSavedTeams[pSelf->m_aTeamMapping[i]])
|
if(pSelf->m_apSavedTeams[pSelf->m_aTeamMapping[i]])
|
||||||
continue;
|
continue;
|
||||||
|
@ -4820,7 +4835,6 @@ void CGameContext::ForceVote(int EnforcerId, bool Success)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_VoteEnforce = Success ? CGameContext::VOTE_ENFORCE_YES_ADMIN : CGameContext::VOTE_ENFORCE_NO_ADMIN;
|
m_VoteEnforce = Success ? CGameContext::VOTE_ENFORCE_YES_ADMIN : CGameContext::VOTE_ENFORCE_NO_ADMIN;
|
||||||
m_VoteEnforcer = EnforcerId;
|
|
||||||
|
|
||||||
char aBuf[256];
|
char aBuf[256];
|
||||||
const char *pOption = Success ? "yes" : "no";
|
const char *pOption = Success ? "yes" : "no";
|
||||||
|
|
|
@ -183,6 +183,7 @@ public:
|
||||||
bool m_aPlayerHasInput[MAX_CLIENTS];
|
bool m_aPlayerHasInput[MAX_CLIENTS];
|
||||||
CSaveTeam *m_apSavedTeams[MAX_CLIENTS];
|
CSaveTeam *m_apSavedTeams[MAX_CLIENTS];
|
||||||
CSaveTee *m_apSavedTees[MAX_CLIENTS];
|
CSaveTee *m_apSavedTees[MAX_CLIENTS];
|
||||||
|
CSaveTee *m_apSavedTeleTees[MAX_CLIENTS];
|
||||||
int m_aTeamMapping[MAX_CLIENTS];
|
int m_aTeamMapping[MAX_CLIENTS];
|
||||||
|
|
||||||
// returns last input if available otherwise nulled PlayerInput object
|
// returns last input if available otherwise nulled PlayerInput object
|
||||||
|
@ -575,7 +576,6 @@ public:
|
||||||
VOTE_TYPE_SPECTATE,
|
VOTE_TYPE_SPECTATE,
|
||||||
};
|
};
|
||||||
int m_VoteVictim;
|
int m_VoteVictim;
|
||||||
int m_VoteEnforcer;
|
|
||||||
|
|
||||||
inline bool IsOptionVote() const { return m_VoteType == VOTE_TYPE_OPTION; }
|
inline bool IsOptionVote() const { return m_VoteType == VOTE_TYPE_OPTION; }
|
||||||
inline bool IsKickVote() const { return m_VoteType == VOTE_TYPE_KICK; }
|
inline bool IsKickVote() const { return m_VoteType == VOTE_TYPE_KICK; }
|
||||||
|
|
|
@ -410,6 +410,29 @@ void CPlayer::Snap(int SnappingClient)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(m_ClientId == SnappingClient && !Server()->IsSixup(SnappingClient))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Snap spectator cursors for local players by default.
|
||||||
|
The information is not visible to local player unless they recorded demo, which the spectator cursor will act as local player's cursor.
|
||||||
|
*/
|
||||||
|
CPlayer *pCursorOwner = this;
|
||||||
|
|
||||||
|
if(m_Team == TEAM_SPECTATORS || IsPaused())
|
||||||
|
{
|
||||||
|
pCursorOwner = m_SpectatorId != SPEC_FREEVIEW ? GameServer()->m_apPlayers[m_SpectatorId] : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pCursorOwner)
|
||||||
|
{
|
||||||
|
CCharacter *pCursorOwnerChar = pCursorOwner->GetCharacter();
|
||||||
|
if(pCursorOwnerChar && pCursorOwnerChar->IsAlive())
|
||||||
|
{
|
||||||
|
pCursorOwnerChar->SnapSpecCursor(m_ClientId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CNetObj_DDNetPlayer *pDDNetPlayer = Server()->SnapNewItem<CNetObj_DDNetPlayer>(id);
|
CNetObj_DDNetPlayer *pDDNetPlayer = Server()->SnapNewItem<CNetObj_DDNetPlayer>(id);
|
||||||
if(!pDDNetPlayer)
|
if(!pDDNetPlayer)
|
||||||
return;
|
return;
|
||||||
|
|
Loading…
Reference in a new issue