Use existing code for rendering the ghost

This commit is contained in:
Redix 2017-09-10 00:57:32 +02:00
parent 5cc0d16029
commit d09e825065
6 changed files with 122 additions and 162 deletions

View file

@ -6,9 +6,7 @@
#include <engine/storage.h>
#include <engine/shared/config.h>
#include <game/generated/client_data.h>
#include <game/client/animstate.h>
#include "players.h"
#include "race.h"
#include "skins.h"
#include "menus.h"
@ -16,7 +14,7 @@
CGhost::CGhost() : m_StartRenderTick(-1), m_LastDeathTick(-1), m_Rendering(false), m_Recording(false) {}
void CGhost::GetGhostCharacter(CGhostCharacter_NoTick *pGhostChar, const CNetObj_Character *pChar)
void CGhost::GetGhostCharacter(CGhostCharacter *pGhostChar, const CNetObj_Character *pChar)
{
pGhostChar->m_X = pChar->m_X;
pGhostChar->m_Y = pChar->m_Y;
@ -29,6 +27,25 @@ void CGhost::GetGhostCharacter(CGhostCharacter_NoTick *pGhostChar, const CNetObj
pGhostChar->m_HookX = pChar->m_HookX;
pGhostChar->m_HookY = pChar->m_HookY;
pGhostChar->m_AttackTick = pChar->m_AttackTick;
pGhostChar->m_Tick = pChar->m_Tick;
}
void CGhost::GetNetObjCharacter(CNetObj_Character *pChar, const CGhostCharacter *pGhostChar)
{
mem_zero(pChar, sizeof(CNetObj_Character));
pChar->m_X = pGhostChar->m_X;
pChar->m_Y = pGhostChar->m_Y;
pChar->m_VelX = pGhostChar->m_VelX;
pChar->m_VelY = 0;
pChar->m_Angle = pGhostChar->m_Angle;
pChar->m_Direction = pGhostChar->m_Direction;
pChar->m_Weapon = pGhostChar->m_Weapon == WEAPON_GRENADE ? WEAPON_GRENADE : WEAPON_GUN;
pChar->m_HookState = pGhostChar->m_HookState;
pChar->m_HookX = pGhostChar->m_HookX;
pChar->m_HookY = pGhostChar->m_HookY;
pChar->m_AttackTick = pGhostChar->m_AttackTick;
pChar->m_HookedPlayer = -1;
pChar->m_Tick = pGhostChar->m_Tick;
}
void CGhost::AddInfos(const CNetObj_Character *pChar)
@ -60,7 +77,6 @@ void CGhost::AddInfos(const CNetObj_Character *pChar)
CGhostCharacter GhostChar;
GetGhostCharacter(&GhostChar, pChar);
GhostChar.m_Tick = pChar->m_Tick;
m_CurGhost.m_lPath.add(GhostChar);
if(GhostRecorder()->IsRecording())
GhostRecorder()->WriteData(GHOSTDATA_TYPE_CHARACTER, (const char*)&GhostChar, sizeof(CGhostCharacter));
@ -141,8 +157,9 @@ void CGhost::OnRender()
int CurPos = pGhost->m_PlaybackPos;
int PrevPos = max(0, CurPos - 1);
CGhostCharacter Player = pGhost->m_lPath[CurPos];
CGhostCharacter Prev = pGhost->m_lPath[PrevPos];
CNetObj_Character Player, Prev;
GetNetObjCharacter(&Player, &pGhost->m_lPath[CurPos]);
GetNetObjCharacter(&Prev, &pGhost->m_lPath[PrevPos]);
int TickDiff = Player.m_Tick - Prev.m_Tick;
float IntraTick = 0.f;
@ -151,100 +168,14 @@ void CGhost::OnRender()
Player.m_AttackTick += Client()->GameTick() - GhostTick;
RenderGhostHook(&Prev, &Player, IntraTick);
RenderGhost(&Prev, &Player, &pGhost->m_RenderInfo, IntraTick);
m_pClient->m_pPlayers->RenderHook(&Prev, &Player, &pGhost->m_RenderInfo , -2, vec2(), vec2(), IntraTick);
m_pClient->m_pPlayers->RenderPlayer(&Prev, &Player, &pGhost->m_RenderInfo, -2, vec2(), IntraTick);
}
if(!ActiveGhosts)
StopRender();
}
void CGhost::RenderGhost(const CGhostCharacter_NoTick *pPrev, const CGhostCharacter_NoTick *pPlayer, CTeeRenderInfo *pInfo, float IntraTick)
{
float Angle = mix((float)pPrev->m_Angle, (float)pPlayer->m_Angle, IntraTick)/256.0f;
vec2 Direction = GetDirection((int)(Angle*256.0f));
vec2 Position = mix(vec2(pPrev->m_X, pPrev->m_Y), vec2(pPlayer->m_X, pPlayer->m_Y), IntraTick);
vec2 Vel = mix(vec2(pPrev->m_VelX/256.0f, pPrev->m_VelY/256.0f), vec2(pPlayer->m_VelX/256.0f, pPlayer->m_VelY/256.0f), IntraTick);
bool Stationary = pPlayer->m_VelX <= 1 && pPlayer->m_VelX >= -1;
bool InAir = !Collision()->CheckPoint(pPlayer->m_X, pPlayer->m_Y+16);
bool WantOtherDir = (pPlayer->m_Direction == -1 && Vel.x > 0) || (pPlayer->m_Direction == 1 && Vel.x < 0);
float WalkTime = fmod(absolute(Position.x), 100.0f)/100.0f;
CAnimState State;
State.Set(&g_pData->m_aAnimations[ANIM_BASE], 0);
if(InAir)
State.Add(&g_pData->m_aAnimations[ANIM_INAIR], 0, 1.0f);
else if(Stationary)
State.Add(&g_pData->m_aAnimations[ANIM_IDLE], 0, 1.0f);
else if(!WantOtherDir)
State.Add(&g_pData->m_aAnimations[ANIM_WALK], WalkTime, 1.0f);
if (pPlayer->m_Weapon == WEAPON_GRENADE)
{
Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GAME].m_Id);
Graphics()->QuadsBegin();
Graphics()->QuadsSetRotation(State.GetAttach()->m_Angle*pi*2+Angle);
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.5f);
// normal weapons
int iw = clamp(pPlayer->m_Weapon, 0, NUM_WEAPONS-1);
RenderTools()->SelectSprite(g_pData->m_Weapons.m_aId[iw].m_pSpriteBody, Direction.x < 0 ? SPRITE_FLAG_FLIP_Y : 0);
vec2 Dir = Direction;
float Recoil = 0.0f;
// TODO: is this correct?
float a = (Client()->PredGameTick()-pPlayer->m_AttackTick+IntraTick)/5.0f;
if(a < 1)
Recoil = sinf(a*pi);
vec2 p = Position + Dir * g_pData->m_Weapons.m_aId[iw].m_Offsetx - Direction*Recoil*10.0f;
p.y += g_pData->m_Weapons.m_aId[iw].m_Offsety;
RenderTools()->DrawSprite(p.x, p.y, g_pData->m_Weapons.m_aId[iw].m_VisualSize);
Graphics()->QuadsEnd();
}
// Render ghost
RenderTools()->RenderTee(&State, pInfo, 0, Direction, Position, true);
}
void CGhost::RenderGhostHook(const CGhostCharacter_NoTick *pPrev, const CGhostCharacter_NoTick *pPlayer, float IntraTick)
{
if(pPrev->m_HookState<=0 || pPlayer->m_HookState<=0)
return;
vec2 Pos = mix(vec2(pPrev->m_X, pPrev->m_Y), vec2(pPlayer->m_X, pPlayer->m_Y), IntraTick);
vec2 HookPos = mix(vec2(pPrev->m_HookX, pPrev->m_HookY), vec2(pPlayer->m_HookX, pPlayer->m_HookY), IntraTick);
float d = distance(Pos, HookPos);
vec2 Dir = normalize(Pos-HookPos);
Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GAME].m_Id);
Graphics()->QuadsBegin();
Graphics()->QuadsSetRotation(GetAngle(Dir)+pi);
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.5f);
// render head
RenderTools()->SelectSprite(SPRITE_HOOK_HEAD);
IGraphics::CQuadItem QuadItem(HookPos.x, HookPos.y, 24, 16);
Graphics()->QuadsDraw(&QuadItem, 1);
// render chain
RenderTools()->SelectSprite(SPRITE_HOOK_CHAIN);
IGraphics::CQuadItem Array[1024];
int j = 0;
for(float f = 24; f < d && j < 1024; f += 24, j++)
{
vec2 p = HookPos + Dir*f;
Array[j] = IGraphics::CQuadItem(p.x, p.y, 24, 16);
}
Graphics()->QuadsDraw(Array, j);
Graphics()->QuadsSetRotation(0);
Graphics()->QuadsEnd();
}
void CGhost::InitRenderInfos(CTeeRenderInfo *pRenderInfo, const char *pSkinName, int UseCustomColor, int ColorBody, int ColorFeet)
{
int SkinId = m_pClient->m_pSkins->Find(pSkinName);

View file

@ -81,7 +81,8 @@ private:
bool m_Recording;
bool m_Rendering;
static void GetGhostCharacter(CGhostCharacter_NoTick *pGhostChar, const CNetObj_Character *pChar);
static void GetGhostCharacter(CGhostCharacter *pGhostChar, const CNetObj_Character *pChar);
static void GetNetObjCharacter(CNetObj_Character *pChar, const CGhostCharacter *pGhostChar);
void AddInfos(const CNetObj_Character *pChar);
int GetSlot() const;
@ -91,9 +92,6 @@ private:
void StartRender();
void StopRender();
void RenderGhost(const CGhostCharacter_NoTick *pPrev, const CGhostCharacter_NoTick *pPlayer, CTeeRenderInfo *pInfo, float IntraTick);
void RenderGhostHook(const CGhostCharacter_NoTick *pPrev, const CGhostCharacter_NoTick *pPlayer, float IntraTick);
void InitRenderInfos(CTeeRenderInfo *pRenderInfo, const char *pSkinName, int UseCustomColor, int ColorBody, int ColorFeet);
static void ConGPlay(IConsole::IResult *pResult, void *pUserData);

View file

@ -219,10 +219,11 @@ vec2 NonPredPos = mix(vec2(Prev.m_X, Prev.m_Y), vec2(Player.m_X, Player.m_Y), In
void CPlayers::RenderHook(
const CNetObj_Character *pPrevChar,
const CNetObj_Character *pPlayerChar,
const CNetObj_PlayerInfo *pPrevInfo,
const CNetObj_PlayerInfo *pPlayerInfo,
const CTeeRenderInfo *pRenderInfo,
int ClientID,
const vec2 &parPosition,
const vec2 &PositionTo
const vec2 &PositionTo,
float Intra
)
{
CNetObj_Character Prev;
@ -230,23 +231,30 @@ void CPlayers::RenderHook(
Prev = *pPrevChar;
Player = *pPlayerChar;
CNetObj_PlayerInfo pInfo = *pPlayerInfo;
CTeeRenderInfo RenderInfo = m_aRenderInfo[pInfo.m_ClientID];
CTeeRenderInfo RenderInfo = *pRenderInfo;
bool AntiPingPlayers = m_pClient->AntiPingPlayers();
bool Local = m_pClient->m_Snap.m_LocalClientID == ClientID;
// don't render hooks to not active character cores
if (pPlayerChar->m_HookedPlayer != -1 && !m_pClient->m_Snap.m_aCharacters[pPlayerChar->m_HookedPlayer].m_Active)
return;
float IntraTick = Client()->IntraGameTick();
if(ClientID < 0)
{
IntraTick = Intra;
AntiPingPlayers = false;
}
bool OtherTeam;
if (m_pClient->m_aClients[m_pClient->m_Snap.m_LocalClientID].m_Team == TEAM_SPECTATORS && m_pClient->m_Snap.m_SpecInfo.m_SpectatorID == SPEC_FREEVIEW)
if (m_pClient->m_aClients[m_pClient->m_Snap.m_LocalClientID].m_Team == TEAM_SPECTATORS && m_pClient->m_Snap.m_SpecInfo.m_SpectatorID == SPEC_FREEVIEW || ClientID < 0)
OtherTeam = false;
else if (m_pClient->m_Snap.m_SpecInfo.m_Active && m_pClient->m_Snap.m_SpecInfo.m_SpectatorID != SPEC_FREEVIEW)
OtherTeam = m_pClient->m_Teams.Team(pInfo.m_ClientID) != m_pClient->m_Teams.Team(m_pClient->m_Snap.m_SpecInfo.m_SpectatorID);
OtherTeam = m_pClient->m_Teams.Team(ClientID) != m_pClient->m_Teams.Team(m_pClient->m_Snap.m_SpecInfo.m_SpectatorID);
else
OtherTeam = m_pClient->m_Teams.Team(pInfo.m_ClientID) != m_pClient->m_Teams.Team(m_pClient->m_Snap.m_LocalClientID);
OtherTeam = m_pClient->m_Teams.Team(ClientID) != m_pClient->m_Teams.Team(m_pClient->m_Snap.m_LocalClientID);
if (OtherTeam)
{
@ -257,10 +265,10 @@ void CPlayers::RenderHook(
// set size
RenderInfo.m_Size = 64.0f;
if (!m_pClient->AntiPingPlayers())
if (!AntiPingPlayers)
{
// use preditect players if needed
if(pInfo.m_Local && g_Config.m_ClPredict && Client()->State() != IClient::STATE_DEMOPLAYBACK)
if(Local && g_Config.m_ClPredict && Client()->State() != IClient::STATE_DEMOPLAYBACK)
{
if(!m_pClient->m_Snap.m_pLocalCharacter || (m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER))
{
@ -281,8 +289,8 @@ void CPlayers::RenderHook(
if(m_pClient->m_Snap.m_pLocalCharacter && !(m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER))
{
// apply predicted results
m_pClient->m_aClients[pInfo.m_ClientID].m_Predicted.Write(&Player);
m_pClient->m_aClients[pInfo.m_ClientID].m_PrevPredicted.Write(&Prev);
m_pClient->m_aClients[ClientID].m_Predicted.Write(&Player);
m_pClient->m_aClients[ClientID].m_PrevPredicted.Write(&Prev);
IntraTick = Client()->PredIntraGameTick();
}
@ -290,7 +298,7 @@ void CPlayers::RenderHook(
}
vec2 Position;
if (!m_pClient->AntiPingPlayers())
if (!AntiPingPlayers)
Position = mix(vec2(Prev.m_X, Prev.m_Y), vec2(Player.m_X, Player.m_Y), IntraTick);
else
Position = parPosition;
@ -302,14 +310,17 @@ void CPlayers::RenderHook(
Graphics()->QuadsBegin();
//Graphics()->QuadsBegin();
if(ClientID < 0)
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.5f);
vec2 Pos = Position;
vec2 HookPos;
if (!m_pClient->AntiPingPlayers())
if (!AntiPingPlayers)
{
if(pPlayerChar->m_HookedPlayer != -1)
{
if(m_pClient->m_Snap.m_pLocalInfo && pPlayerChar->m_HookedPlayer == m_pClient->m_Snap.m_pLocalInfo->m_ClientID && !m_pClient->m_Snap.m_SpecInfo.m_Active)
if(m_pClient->m_Snap.m_LocalClientID != -1 && pPlayerChar->m_HookedPlayer == m_pClient->m_Snap.m_LocalClientID && !m_pClient->m_Snap.m_SpecInfo.m_Active)
{
if(Client()->State() == IClient::STATE_DEMOPLAYBACK) // only use prediction if needed
HookPos = vec2(m_pClient->m_LocalCharacterPos.x, m_pClient->m_LocalCharacterPos.y);
@ -317,7 +328,7 @@ void CPlayers::RenderHook(
HookPos = mix(vec2(m_pClient->m_PredictedPrevChar.m_Pos.x, m_pClient->m_PredictedPrevChar.m_Pos.y),
vec2(m_pClient->m_PredictedChar.m_Pos.x, m_pClient->m_PredictedChar.m_Pos.y), Client()->PredIntraGameTick());
}
else if(pInfo.m_Local)
else if(Local)
{
HookPos = mix(vec2(m_pClient->m_Snap.m_aCharacters[pPlayerChar->m_HookedPlayer].m_Prev.m_X,
m_pClient->m_Snap.m_aCharacters[pPlayerChar->m_HookedPlayer].m_Prev.m_Y),
@ -374,9 +385,10 @@ void CPlayers::RenderHook(
void CPlayers::RenderPlayer(
const CNetObj_Character *pPrevChar,
const CNetObj_Character *pPlayerChar,
const CNetObj_PlayerInfo *pPrevInfo,
const CNetObj_PlayerInfo *pPlayerInfo,
const vec2 &parPosition
const CTeeRenderInfo *pRenderInfo,
int ClientID,
const vec2 &parPosition,
float Intra
/* vec2 &PrevPos,
vec2 &SmoothPos,
int &MoveCnt
@ -387,27 +399,34 @@ void CPlayers::RenderPlayer(
Prev = *pPrevChar;
Player = *pPlayerChar;
CNetObj_PlayerInfo pInfo = *pPlayerInfo;
CTeeRenderInfo RenderInfo = m_aRenderInfo[pInfo.m_ClientID];
CTeeRenderInfo RenderInfo = *pRenderInfo;
bool AntiPingPlayers = m_pClient->AntiPingPlayers();
bool Local = m_pClient->m_Snap.m_LocalClientID == ClientID;
bool NewTick = m_pClient->m_NewTick;
bool OtherTeam;
if (m_pClient->m_aClients[m_pClient->m_Snap.m_LocalClientID].m_Team == TEAM_SPECTATORS && m_pClient->m_Snap.m_SpecInfo.m_SpectatorID == SPEC_FREEVIEW)
if (m_pClient->m_aClients[m_pClient->m_Snap.m_LocalClientID].m_Team == TEAM_SPECTATORS && m_pClient->m_Snap.m_SpecInfo.m_SpectatorID == SPEC_FREEVIEW || ClientID < 0)
OtherTeam = false;
else if (m_pClient->m_Snap.m_SpecInfo.m_Active && m_pClient->m_Snap.m_SpecInfo.m_SpectatorID != SPEC_FREEVIEW)
OtherTeam = m_pClient->m_Teams.Team(pInfo.m_ClientID) != m_pClient->m_Teams.Team(m_pClient->m_Snap.m_SpecInfo.m_SpectatorID);
OtherTeam = m_pClient->m_Teams.Team(ClientID) != m_pClient->m_Teams.Team(m_pClient->m_Snap.m_SpecInfo.m_SpectatorID);
else
OtherTeam = m_pClient->m_Teams.Team(pInfo.m_ClientID) != m_pClient->m_Teams.Team(m_pClient->m_Snap.m_LocalClientID);
OtherTeam = m_pClient->m_Teams.Team(ClientID) != m_pClient->m_Teams.Team(m_pClient->m_Snap.m_LocalClientID);
// set size
RenderInfo.m_Size = 64.0f;
float IntraTick = Client()->IntraGameTick();
if(ClientID < 0)
{
IntraTick = Intra;
AntiPingPlayers = false;
}
float Angle;
if(pInfo.m_Local && Client()->State() != IClient::STATE_DEMOPLAYBACK)
if(Local && Client()->State() != IClient::STATE_DEMOPLAYBACK)
{
// just use the direct input if it's the local player we are rendering
Angle = GetAngle(m_pClient->m_pControls->m_MousePos[g_Config.m_ClDummy]);
@ -436,9 +455,9 @@ void CPlayers::RenderPlayer(
// use preditect players if needed
if (!m_pClient->AntiPingPlayers())
if (!AntiPingPlayers)
{
if(pInfo.m_Local && g_Config.m_ClPredict && Client()->State() != IClient::STATE_DEMOPLAYBACK)
if(Local && g_Config.m_ClPredict && Client()->State() != IClient::STATE_DEMOPLAYBACK)
{
if(!m_pClient->m_Snap.m_pLocalCharacter || (m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER))
{
@ -460,8 +479,8 @@ void CPlayers::RenderPlayer(
if(m_pClient->m_Snap.m_pLocalCharacter && !(m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER))
{
// apply predicted results
m_pClient->m_aClients[pInfo.m_ClientID].m_Predicted.Write(&Player);
m_pClient->m_aClients[pInfo.m_ClientID].m_PrevPredicted.Write(&Prev);
m_pClient->m_aClients[ClientID].m_Predicted.Write(&Player);
m_pClient->m_aClients[ClientID].m_PrevPredicted.Write(&Prev);
IntraTick = Client()->PredIntraGameTick();
NewTick = m_pClient->m_NewPredictedTick;
@ -471,7 +490,7 @@ void CPlayers::RenderPlayer(
vec2 Direction = GetDirection((int)(Angle*256.0f));
vec2 Position;
if (!m_pClient->AntiPingPlayers())
if (!AntiPingPlayers)
Position = mix(vec2(Prev.m_X, Prev.m_Y), vec2(Player.m_X, Player.m_Y), IntraTick);
else
Position = parPosition;
@ -539,7 +558,7 @@ void CPlayers::RenderPlayer(
// draw gun
{
if (Player.m_PlayerFlags&PLAYERFLAG_AIM && ((!pPlayerInfo->m_Local && g_Config.m_ClShowHookCollOther) || (pPlayerInfo->m_Local && g_Config.m_ClShowHookCollOwn)))
if (ClientID >= 0 && Player.m_PlayerFlags&PLAYERFLAG_AIM && ((!Local && g_Config.m_ClShowHookCollOther) || (Local && g_Config.m_ClShowHookCollOwn)))
{
float Alpha = 1.0f;
if (OtherTeam)
@ -547,7 +566,7 @@ void CPlayers::RenderPlayer(
vec2 ExDirection = Direction;
if (pPlayerInfo->m_Local && Client()->State() != IClient::STATE_DEMOPLAYBACK)
if (Local && Client()->State() != IClient::STATE_DEMOPLAYBACK)
ExDirection = normalize(vec2(m_pClient->m_pControls->m_InputData[g_Config.m_ClDummy].m_TargetX, m_pClient->m_pControls->m_InputData[g_Config.m_ClDummy].m_TargetY));
Graphics()->TextureSet(-1);
@ -583,7 +602,7 @@ void CPlayers::RenderPlayer(
Graphics()->SetColor(130.0f/255.0f, 232.0f/255.0f, 160.0f/255.0f, Alpha);
}
if(m_pClient->m_Tuning[g_Config.m_ClDummy].m_PlayerHooking && m_pClient->IntersectCharacter(OldPos, FinishPos, FinishPos, pPlayerInfo->m_ClientID) != -1)
if(m_pClient->m_Tuning[g_Config.m_ClDummy].m_PlayerHooking && m_pClient->IntersectCharacter(OldPos, FinishPos, FinishPos, ClientID) != -1)
{
Graphics()->SetColor(1.0f, 1.0f, 0.0f, Alpha);
break;
@ -611,6 +630,9 @@ void CPlayers::RenderPlayer(
Graphics()->QuadsBegin();
Graphics()->QuadsSetRotation(State.GetAttach()->m_Angle*pi*2+Angle);
if(ClientID < 0)
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.5f);
// normal weapons
int iw = clamp(Player.m_Weapon, 0, NUM_WEAPONS-1);
RenderTools()->SelectSprite(g_pData->m_Weapons.m_aId[iw].m_pSpriteBody, Direction.x < 0 ? SPRITE_FLAG_FLIP_Y : 0);
@ -772,7 +794,7 @@ void CPlayers::RenderPlayer(
}
// render the "shadow" tee
if(pInfo.m_Local && (g_Config.m_Debug || g_Config.m_ClUnpredictedShadow))
if(Local && (g_Config.m_Debug || g_Config.m_ClUnpredictedShadow))
{
vec2 GhostPosition = mix(vec2(pPrevChar->m_X, pPrevChar->m_Y), vec2(pPlayerChar->m_X, pPlayerChar->m_Y), Client()->IntraGameTick());
CTeeRenderInfo Ghost = RenderInfo;
@ -789,7 +811,7 @@ void CPlayers::RenderPlayer(
RenderInfo.m_ColorFeet.a = g_Config.m_ClShowOthersAlpha / 100.0f;
}
if (g_Config.m_ClShowDirection && (!pInfo.m_Local || DemoPlayer()->IsPlaying()))
if (g_Config.m_ClShowDirection && ClientID >= 0 && (Local || DemoPlayer()->IsPlaying()))
{
if (Player.m_Direction == -1)
{
@ -825,7 +847,7 @@ void CPlayers::RenderPlayer(
}
}
RenderTools()->RenderTee(&State, &RenderInfo, Player.m_Emote, Direction, Position, OtherTeam);
RenderTools()->RenderTee(&State, &RenderInfo, Player.m_Emote, Direction, Position, OtherTeam || ClientID < 0);
if(Player.m_PlayerFlags&PLAYERFLAG_CHATTING)
{
@ -839,13 +861,16 @@ void CPlayers::RenderPlayer(
Graphics()->QuadsEnd();
}
if (m_pClient->m_aClients[pInfo.m_ClientID].m_EmoticonStart != -1 && m_pClient->m_aClients[pInfo.m_ClientID].m_EmoticonStart + 2 * Client()->GameTickSpeed() > Client()->GameTick())
if(ClientID < 0)
return;
if (m_pClient->m_aClients[ClientID].m_EmoticonStart != -1 && m_pClient->m_aClients[ClientID].m_EmoticonStart + 2 * Client()->GameTickSpeed() > Client()->GameTick())
{
Graphics()->TextureSet(g_pData->m_aImages[IMAGE_EMOTICONS].m_Id);
Graphics()->QuadsBegin();
int SinceStart = Client()->GameTick() - m_pClient->m_aClients[pInfo.m_ClientID].m_EmoticonStart;
int FromEnd = m_pClient->m_aClients[pInfo.m_ClientID].m_EmoticonStart + 2 * Client()->GameTickSpeed() - Client()->GameTick();
int SinceStart = Client()->GameTick() - m_pClient->m_aClients[ClientID].m_EmoticonStart;
int FromEnd = m_pClient->m_aClients[ClientID].m_EmoticonStart + 2 * Client()->GameTickSpeed() - Client()->GameTick();
float a = 1;
@ -868,29 +893,29 @@ void CPlayers::RenderPlayer(
if (OtherTeam)
Graphics()->SetColor(1.0f, 1.0f, 1.0f, a * (float)g_Config.m_ClShowOthersAlpha / 100.0f);
// client_datas::emoticon is an offset from the first emoticon
RenderTools()->SelectSprite(SPRITE_OOP + m_pClient->m_aClients[pInfo.m_ClientID].m_Emoticon);
RenderTools()->SelectSprite(SPRITE_OOP + m_pClient->m_aClients[ClientID].m_Emoticon);
IGraphics::CQuadItem QuadItem(Position.x, Position.y - 23 - 32*h, 64, 64*h);
Graphics()->QuadsDraw(&QuadItem, 1);
Graphics()->QuadsEnd();
}
if(g_Config.m_ClNameplates && m_pClient->AntiPingPlayers())
if(g_Config.m_ClNameplates && AntiPingPlayers)
{
float FontSize = 18.0f + 20.0f * g_Config.m_ClNameplatesSize / 100.0f;
float FontSizeClan = 18.0f + 20.0f * g_Config.m_ClNameplatesClanSize / 100.0f;
// render name plate
if(!pPlayerInfo->m_Local)
if(Local)
{
float a = 1;
if(g_Config.m_ClNameplatesAlways == 0)
a = clamp(1-powf(distance(m_pClient->m_pControls->m_TargetPos[g_Config.m_ClDummy], Position)/200.0f,16.0f), 0.0f, 1.0f);
const char *pName = m_pClient->m_aClients[pPlayerInfo->m_ClientID].m_aName;
const char *pName = m_pClient->m_aClients[ClientID].m_aName;
float tw = TextRender()->TextWidth(0, FontSize, pName, -1);
vec3 rgb = vec3(1.0f, 1.0f, 1.0f);
if(g_Config.m_ClNameplatesTeamcolors && m_pClient->m_Teams.Team(pPlayerInfo->m_ClientID))
rgb = HslToRgb(vec3(m_pClient->m_Teams.Team(pPlayerInfo->m_ClientID) / 64.0f, 1.0f, 0.75f));
if(g_Config.m_ClNameplatesTeamcolors && m_pClient->m_Teams.Team(ClientID))
rgb = HslToRgb(vec3(m_pClient->m_Teams.Team(ClientID) / 64.0f, 1.0f, 0.75f));
if (OtherTeam)
{
@ -904,9 +929,9 @@ void CPlayers::RenderPlayer(
}
if(g_Config.m_ClNameplatesTeamcolors && m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameFlags&GAMEFLAG_TEAMS)
{
if(pPlayerInfo->m_Team == TEAM_RED)
if(m_pClient->m_aClients[ClientID].m_Team == TEAM_RED)
TextRender()->TextColor(1.0f, 0.5f, 0.5f, a);
else if(pPlayerInfo->m_Team == TEAM_BLUE)
else if(m_pClient->m_aClients[ClientID].m_Team == TEAM_BLUE)
TextRender()->TextColor(0.7f, 0.7f, 1.0f, a);
}
@ -914,7 +939,7 @@ void CPlayers::RenderPlayer(
if(g_Config.m_ClNameplatesClan)
{
const char *pClan = m_pClient->m_aClients[pPlayerInfo->m_ClientID].m_aClan;
const char *pClan = m_pClient->m_aClients[ClientID].m_aClan;
float tw_clan = TextRender()->TextWidth(0, FontSizeClan, pClan, -1);
TextRender()->Text(0, Position.x-tw_clan/2.0f, Position.y-FontSize-FontSizeClan-38.0f, FontSizeClan, pClan, -1);
}
@ -922,7 +947,7 @@ void CPlayers::RenderPlayer(
if(g_Config.m_Debug) // render client id when in debug aswell
{
char aBuf[128];
str_format(aBuf, sizeof(aBuf),"%d", pPlayerInfo->m_ClientID);
str_format(aBuf, sizeof(aBuf),"%d", ClientID);
float Offset = g_Config.m_ClNameplatesClan ? (FontSize * 2 + FontSizeClan) : (FontSize * 2);
float tw_id = TextRender()->TextWidth(0, FontSize, aBuf, -1);
TextRender()->Text(0, Position.x-tw_id/2.0f, Position.y-Offset-38.0f, 28.0f, aBuf, -1);
@ -1027,7 +1052,7 @@ void CPlayers::OnRender()
if(pPrevInfo && pInfo)
{
//
bool Local = ((const CNetObj_PlayerInfo *)pInfo)->m_Local !=0;
bool Local = m_pClient->m_Snap.m_LocalClientID == i;
if((p % 2) == 0 && Local) continue;
if((p % 2) == 1 && !Local) continue;
@ -1040,8 +1065,8 @@ void CPlayers::OnRender()
RenderHook(
&PrevChar,
&CurChar,
(const CNetObj_PlayerInfo *)pPrevInfo,
(const CNetObj_PlayerInfo *)pInfo,
&m_aRenderInfo[i],
i,
PredictedPos[i],
PredictedPos[PrevChar.m_HookedPlayer]
);
@ -1049,8 +1074,8 @@ void CPlayers::OnRender()
RenderHook(
&PrevChar,
&CurChar,
(const CNetObj_PlayerInfo *)pPrevInfo,
(const CNetObj_PlayerInfo *)pInfo,
&m_aRenderInfo[i],
i,
PredictedPos[i],
PredictedPos[i]
);
@ -1060,8 +1085,8 @@ void CPlayers::OnRender()
RenderPlayer(
&PrevChar,
&CurChar,
(const CNetObj_PlayerInfo *)pPrevInfo,
(const CNetObj_PlayerInfo *)pInfo,
&m_aRenderInfo[i],
i,
PredictedPos[i]
);
}

View file

@ -6,14 +6,17 @@
class CPlayers : public CComponent
{
friend class CGhost;
CTeeRenderInfo m_aRenderInfo[MAX_CLIENTS];
void RenderHand(class CTeeRenderInfo *pInfo, vec2 CenterPos, vec2 Dir, float AngleOffset, vec2 PostRotOffset);
void RenderPlayer(
const CNetObj_Character *pPrevChar,
const CNetObj_Character *pPlayerChar,
const CNetObj_PlayerInfo *pPrevInfo,
const CNetObj_PlayerInfo *pPlayerInfo,
const vec2 &Position
const CTeeRenderInfo *pRenderInfo,
int ClientID,
const vec2 &Position,
float Intra = 0.f
/* vec2 &PrevPredPos,
vec2 &SmoothPos,
int &MoveCnt
@ -22,10 +25,11 @@ class CPlayers : public CComponent
void RenderHook(
const CNetObj_Character *pPrevChar,
const CNetObj_Character *pPlayerChar,
const CNetObj_PlayerInfo *pPrevInfo,
const CNetObj_PlayerInfo *pPlayerInfo,
const CTeeRenderInfo *pRenderInfo,
int ClientID,
const vec2 &Position,
const vec2 &PositionTo
const vec2 &PositionTo,
float Intra = 0.f
);
void Predict(

View file

@ -155,6 +155,7 @@ void CGameClient::OnConsoleInit()
m_pBackGround = &::gs_BackGround;
m_pMapSounds = &::gs_MapSounds;
m_pPlayers = &::gs_Players;
m_pRaceDemo = &::gs_RaceDemo;
m_pGhost = &::gs_Ghost;
@ -178,7 +179,7 @@ void CGameClient::OnConsoleInit()
m_All.Add(&gs_MapLayersBackGround); // first to render
m_All.Add(&m_pParticles->m_RenderTrail);
m_All.Add(m_pItems);
m_All.Add(&gs_Players);
m_All.Add(m_pPlayers);
m_All.Add(m_pGhost);
m_All.Add(&gs_MapLayersForeGround);
m_All.Add(&m_pParticles->m_RenderExplosions);

View file

@ -354,6 +354,7 @@ public:
class CBackground *m_pBackGround;
class CMapSounds *m_pMapSounds;
class CPlayers *m_pPlayers;
// DDRace