Add DDNetCharacterDisplayInfo NetObj

- Show all components of new HUD also in Spectator (Ninja Bar, Freeze
  Bar and Jumps)
- hide freeze bar if you sit in freeze
This commit is contained in:
c0d3d3v 2022-03-27 18:18:53 +02:00
parent b403f474a0
commit e71578e468
No known key found for this signature in database
GPG key ID: 068AF680530DFF31
11 changed files with 100 additions and 25 deletions

View file

@ -245,6 +245,13 @@ Objects = [
NetIntRange("m_StrongWeakID", 0, 'MAX_CLIENTS-1'),
]),
NetObjectEx("DDNetCharacterDisplayInfo", "character-display-info@netobj.ddnet.tw", [
NetIntRange("m_JumpedTotal", -2, 255),
NetTick("m_NinjaActivationTick"),
NetTick("m_FreezeTick"),
NetBool("m_IsInFreeze"),
]),
NetObjectEx("DDNetPlayer", "player@netobj.ddnet.tw", [
NetIntAny("m_Flags"),
NetIntRange("m_AuthLevel", "AUTHED_NO", "AUTHED_ADMIN"),

View file

@ -2,29 +2,34 @@
#include "freezebars.h"
void CFreezeBars::RenderFreezeBar(const int ClientID)
{
const float FreezeBarWidth = 64.0f;
const float FreezeBarHalfWidth = 32.0f;
const float FreezeBarHight = 16.0f;
if(m_pClient->m_aClients[ClientID].m_Predicted.m_FreezeEnd <= 0.0f)
// pCharacter contains the predicted character for local players or the last snap for players who are spectated
CCharacterCore *pCharacter = &m_pClient->m_aClients[ClientID].m_Predicted;
const float PhysSize = 28.0f;
bool Grounded = false;
if(Collision()->CheckPoint(pCharacter->m_Pos.x + PhysSize / 2, pCharacter->m_Pos.y + PhysSize / 2 + 5))
Grounded = true;
if(Collision()->CheckPoint(pCharacter->m_Pos.x - PhysSize / 2, pCharacter->m_Pos.y + PhysSize / 2 + 5))
Grounded = true;
if(pCharacter->m_FreezeEnd <= 0.0f || !m_pClient->m_Snap.m_aCharacters[ClientID].m_HasExtendedDisplayInfo || (pCharacter->m_IsInFreeze && Grounded))
{
return;
}
const int Max = m_pClient->m_aClients[ClientID].m_Predicted.m_FreezeEnd - m_pClient->m_aClients[ClientID].m_Predicted.m_FreezeTick;
float FreezeProgress = clamp(Max - (m_pClient->m_GameWorld.GameTick() - m_pClient->m_aClients[ClientID].m_Predicted.m_FreezeTick), 0, Max) / (float)Max;
const int Max = pCharacter->m_FreezeEnd - pCharacter->m_FreezeTick;
float FreezeProgress = clamp(Max - (Client()->GameTick(g_Config.m_ClDummy) - pCharacter->m_FreezeTick), 0, Max) / (float)Max;
if(FreezeProgress <= 0.0f)
{
return;
}
vec2 Position;
if(ClientID >= 0 && ClientID < MAX_CLIENTS)
Position = m_pClient->m_aClients[ClientID].m_RenderPos;
else
Position = mix(vec2(m_pClient->m_aClients[ClientID].m_RenderPrev.m_X, m_pClient->m_aClients[ClientID].m_RenderPrev.m_Y), vec2(m_pClient->m_aClients[ClientID].m_RenderCur.m_X, m_pClient->m_aClients[ClientID].m_RenderCur.m_Y), Client()->IntraGameTick(g_Config.m_ClDummy));
vec2 Position = m_pClient->m_aClients[ClientID].m_RenderPos;
Position.x -= FreezeBarHalfWidth;
Position.y += 32;
@ -33,6 +38,13 @@ void CFreezeBars::RenderFreezeBar(const int ClientID)
m_pClient->m_Hud.RenderProgressBar(Position.x, Position.y, FreezeBarWidth, FreezeBarHight, FreezeProgress, Alpha);
}
inline bool CFreezeBars::IsPlayerInfoAvailable(int ClientID) const
{
const void *pPrevInfo = Client()->SnapFindItem(IClient::SNAP_PREV, NETOBJTYPE_PLAYERINFO, ClientID);
const void *pInfo = Client()->SnapFindItem(IClient::SNAP_CURRENT, NETOBJTYPE_PLAYERINFO, ClientID);
return pPrevInfo && pInfo;
}
void CFreezeBars::OnRender()
{
// get screen edges to avoid rendering offscreen
@ -53,7 +65,7 @@ void CFreezeBars::OnRender()
// render everyone else's freeze bar, then our own
for(int ClientID = 0; ClientID < MAX_CLIENTS; ClientID++)
{
if(ClientID == LocalClientID || !m_pClient->m_Snap.m_aCharacters[ClientID].m_Active || !m_pClient->m_Players.IsPlayerInfoAvailable(ClientID))
if(ClientID == LocalClientID || !m_pClient->m_Snap.m_aCharacters[ClientID].m_Active || !IsPlayerInfoAvailable(ClientID))
{
continue;
}
@ -66,10 +78,8 @@ void CFreezeBars::OnRender()
}
RenderFreezeBar(ClientID);
}
if(LocalClientID != -1 && m_pClient->m_Snap.m_aCharacters[LocalClientID].m_Active && m_pClient->m_Players.IsPlayerInfoAvailable(LocalClientID))
if(LocalClientID != -1 && m_pClient->m_Snap.m_aCharacters[LocalClientID].m_Active && IsPlayerInfoAvailable(LocalClientID))
{
RenderFreezeBar(LocalClientID);
}

View file

@ -5,6 +5,7 @@
class CFreezeBars : public CComponent
{
void RenderFreezeBar(const int ClientID);
bool IsPlayerInfoAvailable(int ClientID) const;
public:
virtual int Sizeof() const override { return sizeof(*this); }

View file

@ -830,14 +830,14 @@ void CHud::RenderPlayerState(const int ClientID)
{
Graphics()->SetColor(1.f, 1.f, 1.f, 1.f);
// pCharacter contains the predicted character for local players and the last snap for spectated players.
// pCharacter contains the predicted character for local players or the last snap for players who are spectated
CCharacterCore *pCharacter = &m_pClient->m_aClients[ClientID].m_Predicted;
int TotalJumpsToDisplay, AvailableJumpsToDisplay;
// If the player is predicted in the Game World, we take the predicted jump values, otherwise the values from a snap
if(m_pClient->m_Snap.m_pLocalCharacter)
if(m_pClient->m_Snap.m_aCharacters[ClientID].m_HasExtendedDisplayInfo)
{
float PhysSize = 28.0f;
const float PhysSize = 28.0f;
bool Grounded = false;
if(Collision()->CheckPoint(pCharacter->m_Pos.x + PhysSize / 2, pCharacter->m_Pos.y + PhysSize / 2 + 5))
Grounded = true;
@ -960,9 +960,9 @@ void CHud::RenderPlayerState(const int ClientID)
Graphics()->QuadsSetRotation(0);
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
const int Max = g_pData->m_Weapons.m_Ninja.m_Duration * m_pClient->m_GameWorld.GameTickSpeed() / 1000;
float NinjaProgress = clamp(pCharacter->m_Ninja.m_ActivationTick + g_pData->m_Weapons.m_Ninja.m_Duration * m_pClient->m_GameWorld.GameTickSpeed() / 1000 - m_pClient->m_GameWorld.GameTick(), 0, Max) / (float)Max;
if(NinjaProgress > 0.0f)
const int Max = g_pData->m_Weapons.m_Ninja.m_Duration * Client()->GameTickSpeed() / 1000;
float NinjaProgress = clamp(pCharacter->m_Ninja.m_ActivationTick + g_pData->m_Weapons.m_Ninja.m_Duration * Client()->GameTickSpeed() / 1000 - Client()->GameTick(g_Config.m_ClDummy), 0, Max) / (float)Max;
if(NinjaProgress > 0.0f && m_pClient->m_Snap.m_aCharacters[ClientID].m_HasExtendedDisplayInfo)
{
x = 5;
y += 12;
@ -1117,7 +1117,7 @@ void CHud::RenderProgressBar(float x, const float y, const float width, const fl
const float MiddleProgressProportion = MiddleBarWidth / ProgressBarWidth;
// we cut 10% of both sides (right and left) of all sprites so we don't get edge bleeding
// beginning piece
float BeginningPieceProgress = 1;
if(Progress <= EndProgressProportion)

View file

@ -40,8 +40,6 @@ public:
virtual int Sizeof() const override { return sizeof(*this); }
virtual void OnInit() override;
virtual void OnRender() override;
bool IsPlayerInfoAvailable(int ClientID) const;
};
#endif

View file

@ -1346,6 +1346,19 @@ void CGameClient::OnNewSnapshot()
pClient->m_Predicted.ReadDDNet(pCharacterData);
}
}
else if(Item.m_Type == NETOBJTYPE_DDNETCHARACTERDISPLAYINFO)
{
const CNetObj_DDNetCharacterDisplayInfo *pCharacterDisplayInfo = (const CNetObj_DDNetCharacterDisplayInfo *)pData;
if(Item.m_ID < MAX_CLIENTS)
{
m_Snap.m_aCharacters[Item.m_ID].m_ExtendedDisplayInfo = *pCharacterDisplayInfo;
m_Snap.m_aCharacters[Item.m_ID].m_HasExtendedDisplayInfo = true;
CClientData *pClient = &m_aClients[Item.m_ID];
pClient->m_Predicted.ReadDDNetDisplayInfo(pCharacterDisplayInfo);
}
}
else if(Item.m_Type == NETOBJTYPE_SPECCHAR)
{
const CNetObj_SpecChar *pSpecCharData = (const CNetObj_SpecChar *)pData;

View file

@ -318,6 +318,9 @@ public:
CNetObj_DDNetCharacter m_ExtendedData;
bool m_HasExtendedData;
CNetObj_DDNetCharacterDisplayInfo m_ExtendedDisplayInfo;
bool m_HasExtendedDisplayInfo;
// interpolated position
vec2 m_Position;
};

View file

@ -697,7 +697,13 @@ void CCharacter::HandleTiles(int Index)
if(Collision()->GetSwitchType(MapIndex) == TILE_FREEZE && Team() != TEAM_SUPER)
{
if(Collision()->GetSwitchNumber(MapIndex) == 0 || Collision()->m_pSwitchers[Collision()->GetSwitchNumber(MapIndex)].m_Status[Team()])
{
Freeze(Collision()->GetSwitchDelay(MapIndex));
if(IsGrounded())
{
m_Core.m_IsInFreeze = true;
}
}
}
else if(Collision()->GetSwitchType(MapIndex) == TILE_DFREEZE && Team() != TEAM_SUPER)
{
@ -781,6 +787,10 @@ void CCharacter::HandleTiles(int Index)
if(((m_TileIndex == TILE_FREEZE) || (m_TileFIndex == TILE_FREEZE)) && !m_Super && !m_DeepFreeze)
{
Freeze();
if(IsGrounded())
{
m_Core.m_IsInFreeze = true;
}
}
else if(((m_TileIndex == TILE_UNFREEZE) || (m_TileFIndex == TILE_UNFREEZE)) && !m_DeepFreeze)
{
@ -946,6 +956,7 @@ void CCharacter::DDRacePostCoreTick()
m_Core.m_HookTick = 0;
m_FrozenLastTick = false;
m_Core.m_IsInFreeze = false;
if(m_DeepFreeze && !m_Super)
Freeze();
@ -1101,6 +1112,7 @@ void CCharacter::ResetPrediction()
m_NumInputs = 0;
m_FreezeTime = 0;
m_Core.m_FreezeTick = 0;
m_Core.m_IsInFreeze = false;
m_DeepFreeze = false;
m_LiveFreeze = false;
m_FrozenLastTick = false;

View file

@ -586,6 +586,14 @@ void CCharacterCore::ReadDDNet(const CNetObj_DDNetCharacter *pObjDDNet)
m_Jumps = pObjDDNet->m_Jumps;
}
void CCharacterCore::ReadDDNetDisplayInfo(const CNetObj_DDNetCharacterDisplayInfo *pObjDDNet)
{
m_JumpedTotal = pObjDDNet->m_JumpedTotal;
m_Ninja.m_ActivationTick = pObjDDNet->m_NinjaActivationTick;
m_FreezeTick = pObjDDNet->m_FreezeTick;
m_IsInFreeze = pObjDDNet->m_IsInFreeze;
}
void CCharacterCore::Quantize()
{
CNetObj_CharacterCore Core;

View file

@ -276,6 +276,7 @@ public:
void SetTeamsCore(CTeamsCore *pTeams);
void SetTeleOuts(std::map<int, std::vector<vec2>> *pTeleOuts);
void ReadDDNet(const CNetObj_DDNetCharacter *pObjDDNet);
void ReadDDNetDisplayInfo(const CNetObj_DDNetCharacterDisplayInfo *pObjDDNet);
bool m_Solo;
bool m_Jetpack;
bool m_NoCollision;
@ -292,6 +293,7 @@ public:
bool m_HasTelegunLaser;
int m_FreezeTick;
int m_FreezeEnd;
bool m_IsInFreeze;
bool m_DeepFrozen;
bool m_LiveFrozen;
CTuningParams m_Tuning;

View file

@ -1242,6 +1242,14 @@ void CCharacter::Snap(int SnappingClient)
pDDNetCharacter->m_Jumps = m_Core.m_Jumps;
pDDNetCharacter->m_TeleCheckpoint = m_TeleCheckpoint;
pDDNetCharacter->m_StrongWeakID = m_StrongWeakID;
CNetObj_DDNetCharacterDisplayInfo *pDDNetCharacterDisplayInfo = static_cast<CNetObj_DDNetCharacterDisplayInfo *>(Server()->SnapNewItem(NETOBJTYPE_DDNETCHARACTERDISPLAYINFO, ID, sizeof(CNetObj_DDNetCharacterDisplayInfo)));
if(!pDDNetCharacterDisplayInfo)
return;
pDDNetCharacterDisplayInfo->m_JumpedTotal = m_Core.m_JumpedTotal;
pDDNetCharacterDisplayInfo->m_NinjaActivationTick = m_Core.m_Ninja.m_ActivationTick;
pDDNetCharacterDisplayInfo->m_FreezeTick = m_Core.m_FreezeTick;
pDDNetCharacterDisplayInfo->m_IsInFreeze = m_Core.m_IsInFreeze;
}
// DDRace
@ -1476,7 +1484,13 @@ void CCharacter::HandleTiles(int Index)
// freeze
if(((m_TileIndex == TILE_FREEZE) || (m_TileFIndex == TILE_FREEZE)) && !m_Super && !m_DeepFreeze)
{
Freeze();
if(IsGrounded())
{
m_Core.m_IsInFreeze = true;
}
}
else if(((m_TileIndex == TILE_UNFREEZE) || (m_TileFIndex == TILE_UNFREEZE)) && !m_DeepFreeze)
UnFreeze();
@ -1699,7 +1713,13 @@ void CCharacter::HandleTiles(int Index)
else if(GameServer()->Collision()->GetSwitchType(MapIndex) == TILE_FREEZE && Team() != TEAM_SUPER)
{
if(GameServer()->Collision()->GetSwitchNumber(MapIndex) == 0 || GameServer()->Collision()->m_pSwitchers[GameServer()->Collision()->GetSwitchNumber(MapIndex)].m_Status[Team()])
{
Freeze(GameServer()->Collision()->GetSwitchDelay(MapIndex));
if(IsGrounded())
{
m_Core.m_IsInFreeze = true;
}
}
}
else if(GameServer()->Collision()->GetSwitchType(MapIndex) == TILE_DFREEZE && Team() != TEAM_SUPER)
{
@ -2095,16 +2115,16 @@ void CCharacter::DDRaceTick()
GameServer()->Collision()->GetSwitchType(Index)};
if(IsGrounded() && !m_DeepFreeze)
{
bool IsInFreeze = false;
bool IsInAnyFreeze = false;
for(const int Tile : aTiles)
{
if(Tile == TILE_FREEZE || Tile == TILE_DFREEZE || Tile == TILE_LFREEZE)
{
IsInFreeze = true;
IsInAnyFreeze = true;
break;
}
}
if(!IsInFreeze)
if(!IsInAnyFreeze)
{
SetRescue();
}
@ -2122,6 +2142,7 @@ void CCharacter::DDRacePostCoreTick()
m_Core.m_HookTick = 0;
m_FrozenLastTick = false;
m_Core.m_IsInFreeze = false;
if(m_DeepFreeze && !m_Super)
Freeze();