diff options
| author | oy <Tom_Adams@web.de> | 2011-03-12 18:07:57 +0100 |
|---|---|---|
| committer | oy <Tom_Adams@web.de> | 2011-03-12 18:07:57 +0100 |
| commit | b834426548107af96c2568af22cbf8604f230965 (patch) | |
| tree | 893a04ec6b37d7b1d92ee66d39707463f48e847c | |
| parent | 7b98b3ddeddd34bf0fa0c84b13d928a9dafe140c (diff) | |
| download | zcatch-b834426548107af96c2568af22cbf8604f230965.tar.gz zcatch-b834426548107af96c2568af22cbf8604f230965.zip | |
fixed several problems with spectator view in game and demo player. Closes #83
| -rw-r--r-- | src/engine/demo.h | 8 | ||||
| -rw-r--r-- | src/engine/shared/demo.cpp | 13 | ||||
| -rw-r--r-- | src/engine/shared/demo.h | 2 | ||||
| -rw-r--r-- | src/game/client/components/camera.cpp | 19 | ||||
| -rw-r--r-- | src/game/client/components/camera.h | 13 | ||||
| -rw-r--r-- | src/game/client/components/controls.cpp | 17 | ||||
| -rw-r--r-- | src/game/client/components/emoticon.cpp | 4 | ||||
| -rw-r--r-- | src/game/client/components/hud.cpp | 10 | ||||
| -rw-r--r-- | src/game/client/components/menus_demo.cpp | 4 | ||||
| -rw-r--r-- | src/game/client/components/scoreboard.cpp | 13 | ||||
| -rw-r--r-- | src/game/client/components/spectator.cpp | 19 | ||||
| -rw-r--r-- | src/game/client/gameclient.cpp | 43 | ||||
| -rw-r--r-- | src/game/client/gameclient.h | 13 | ||||
| -rw-r--r-- | src/game/server/player.cpp | 2 |
14 files changed, 130 insertions, 50 deletions
diff --git a/src/engine/demo.h b/src/engine/demo.h index dacd96dd..3ca68299 100644 --- a/src/engine/demo.h +++ b/src/engine/demo.h @@ -20,6 +20,13 @@ public: int m_LastTick; }; + enum + { + DEMOTYPE_INVALID=0, + DEMOTYPE_CLIENT, + DEMOTYPE_SERVER, + }; + ~IDemoPlayer() {} virtual void SetSpeed(float Speed) = 0; virtual int SetPos(float Precent) = 0; @@ -28,6 +35,7 @@ public: virtual const CInfo *BaseInfo() const = 0; virtual char *GetDemoName() = 0; virtual bool GetDemoInfo(class IStorage *pStorage, const char *pFilename, int StorageType, char *pMap, int BufferSize) const = 0; + virtual int GetDemoType() const = 0; }; class IDemoRecorder : public IInterface diff --git a/src/engine/shared/demo.cpp b/src/engine/shared/demo.cpp index bf883456..586e7318 100644 --- a/src/engine/shared/demo.cpp +++ b/src/engine/shared/demo.cpp @@ -562,6 +562,12 @@ int CDemoPlayer::Load(class IStorage *pStorage, class IConsole *pConsole, const return -1; } + // get demo type + if(!str_comp(m_Info.m_Header.m_aType, "client")) + m_DemoType = DEMOTYPE_CLIENT; + else if(!str_comp(m_Info.m_Header.m_aType, "server")) + m_DemoType = DEMOTYPE_SERVER; + else DEMOTYPE_INVALID; // get map if(m_Info.m_Header.m_Version >= gs_VersionWithMap) @@ -771,3 +777,10 @@ bool CDemoPlayer::GetDemoInfo(class IStorage *pStorage, const char *pFilename, i io_close(File); return true; } + +int CDemoPlayer::GetDemoType() const +{ + if(m_File) + return m_DemoType; + return DEMOTYPE_INVALID; +} diff --git a/src/engine/shared/demo.h b/src/engine/shared/demo.h index d8ce70b2..62e2bfd1 100644 --- a/src/engine/shared/demo.h +++ b/src/engine/shared/demo.h @@ -94,6 +94,7 @@ private: CKeyFrame *m_pKeyFrames; CPlaybackInfo m_Info; + int m_DemoType; unsigned char m_aLastSnapshotData[CSnapshot::MAX_SIZE]; int m_LastSnapshotDataSize; class CSnapshotDelta *m_pSnapshotDelta; @@ -119,6 +120,7 @@ public: const CInfo *BaseInfo() const { return &m_Info.m_Info; } char *GetDemoName(); bool GetDemoInfo(class IStorage *pStorage, const char *pFilename, int StorageType, char *pMap, int BufferSize) const; + int GetDemoType() const; int Update(); diff --git a/src/game/client/components/camera.cpp b/src/game/client/components/camera.cpp index b4c2debb..f02b2861 100644 --- a/src/game/client/components/camera.cpp +++ b/src/game/client/components/camera.cpp @@ -12,7 +12,7 @@ CCamera::CCamera() { - m_WasSpectator = false; + m_CamType = CAMTYPE_UNDEFINED; } void CCamera::OnRender() @@ -21,21 +21,22 @@ void CCamera::OnRender() m_Zoom = 1.0f; // update camera center - if(m_pClient->m_Snap.m_Spectate && (!m_pClient->m_Snap.m_pSpectatorInfo || m_pClient->m_Snap.m_pSpectatorInfo->m_SpectatorID == SPEC_FREEVIEW)) + if(m_pClient->m_Snap.m_SpecInfo.m_Active && !m_pClient->m_Snap.m_SpecInfo.m_UsePosition) { - if(!m_WasSpectator) + if(m_CamType != CAMTYPE_SPEC) { + m_pClient->m_pControls->m_MousePos = m_PrevCenter; m_pClient->m_pControls->ClampMousePos(); - m_WasSpectator = true; + m_CamType = CAMTYPE_SPEC; } m_Center = m_pClient->m_pControls->m_MousePos; } else { - if(m_WasSpectator) + if(m_CamType != CAMTYPE_PLAYER) { m_pClient->m_pControls->ClampMousePos(); - m_WasSpectator = false; + m_CamType = CAMTYPE_PLAYER; } vec2 CameraOffset(0, 0); @@ -50,9 +51,11 @@ void CCamera::OnRender() CameraOffset = normalize(m_pClient->m_pControls->m_MousePos)*OffsetAmount; } - if(m_pClient->m_Snap.m_Spectate) - m_Center = m_pClient->m_Snap.m_SpectatorPos + CameraOffset; + if(m_pClient->m_Snap.m_SpecInfo.m_Active) + m_Center = m_pClient->m_Snap.m_SpecInfo.m_Position + CameraOffset; else m_Center = m_pClient->m_LocalCharacterPos + CameraOffset; } + + m_PrevCenter = m_Center; } diff --git a/src/game/client/components/camera.h b/src/game/client/components/camera.h index ba433285..75725d56 100644 --- a/src/game/client/components/camera.h +++ b/src/game/client/components/camera.h @@ -6,11 +6,20 @@ #include <game/client/component.h> class CCamera : public CComponent -{ +{ + enum + { + CAMTYPE_UNDEFINED=-1, + CAMTYPE_SPEC, + CAMTYPE_PLAYER, + }; + + int m_CamType; + vec2 m_PrevCenter; + public: vec2 m_Center; float m_Zoom; - bool m_WasSpectator; CCamera(); virtual void OnRender(); diff --git a/src/game/client/components/controls.cpp b/src/game/client/components/controls.cpp index c884b394..56b6e63b 100644 --- a/src/game/client/components/controls.cpp +++ b/src/game/client/components/controls.cpp @@ -199,18 +199,17 @@ int CControls::SnapInput(int *pData) void CControls::OnRender() { // update target pos - if(m_pClient->m_Snap.m_pGameInfoObj && !(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_PAUSED || m_pClient->m_Snap.m_Spectate)) + if(m_pClient->m_Snap.m_pGameInfoObj && !(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_PAUSED || m_pClient->m_Snap.m_SpecInfo.m_Active)) m_TargetPos = m_pClient->m_LocalCharacterPos + m_MousePos; - - if(m_pClient->m_Snap.m_Spectate && m_pClient->m_Snap.m_pSpectatorInfo && m_pClient->m_Snap.m_pSpectatorInfo->m_SpectatorID != SPEC_FREEVIEW) - m_TargetPos = m_pClient->m_Snap.m_SpectatorPos + m_MousePos; + else if(m_pClient->m_Snap.m_SpecInfo.m_Active && m_pClient->m_Snap.m_SpecInfo.m_UsePosition) + m_TargetPos = m_pClient->m_Snap.m_SpecInfo.m_Position + m_MousePos; + else + m_TargetPos = m_MousePos; } bool CControls::OnMouseMove(float x, float y) { - if((m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_PAUSED) || - (m_pClient->m_Snap.m_Spectate && (!m_pClient->m_Snap.m_pSpectatorInfo || m_pClient->m_Snap.m_pSpectatorInfo->m_SpectatorID == SPEC_FREEVIEW) && - m_pClient->m_pChat->IsActive())) + if(m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_PAUSED) return false; m_MousePos += vec2(x, y); // TODO: ugly @@ -221,11 +220,11 @@ bool CControls::OnMouseMove(float x, float y) void CControls::ClampMousePos() { - if(m_pClient->m_Snap.m_Spectate && (!m_pClient->m_Snap.m_pSpectatorInfo || m_pClient->m_Snap.m_pSpectatorInfo->m_SpectatorID == SPEC_FREEVIEW)) + if(m_pClient->m_Snap.m_SpecInfo.m_Active && !m_pClient->m_Snap.m_SpecInfo.m_UsePosition) { m_MousePos.x = clamp(m_MousePos.x, 200.0f, Collision()->GetWidth()*32-200.0f); m_MousePos.y = clamp(m_MousePos.y, 200.0f, Collision()->GetHeight()*32-200.0f); - m_TargetPos = m_MousePos; + } else { diff --git a/src/game/client/components/emoticon.cpp b/src/game/client/components/emoticon.cpp index 1fa72a7f..64b47b74 100644 --- a/src/game/client/components/emoticon.cpp +++ b/src/game/client/components/emoticon.cpp @@ -18,8 +18,8 @@ CEmoticon::CEmoticon() void CEmoticon::ConKeyEmoticon(IConsole::IResult *pResult, void *pUserData) { CEmoticon *pSelf = (CEmoticon *)pUserData; - if(!pSelf->m_pClient->m_Snap.m_Spectate && pSelf->Client()->State() != IClient::STATE_DEMOPLAYBACK) - ((CEmoticon *)pUserData)->m_Active = pResult->GetInteger(0) != 0; + if(!pSelf->m_pClient->m_Snap.m_SpecInfo.m_Active && pSelf->Client()->State() != IClient::STATE_DEMOPLAYBACK) + pSelf->m_Active = pResult->GetInteger(0) != 0; } void CEmoticon::ConEmote(IConsole::IResult *pResult, void *pUserData) diff --git a/src/game/client/components/hud.cpp b/src/game/client/components/hud.cpp index aff76bc8..a9869bb3 100644 --- a/src/game/client/components/hud.cpp +++ b/src/game/client/components/hud.cpp @@ -406,8 +406,8 @@ void CHud::RenderSpectatorHud() // draw the text char aBuf[128]; - str_format(aBuf, sizeof(aBuf), "%s: %s", Localize("Spectate"), m_pClient->m_Snap.m_pSpectatorInfo && m_pClient->m_Snap.m_pSpectatorInfo->m_SpectatorID != SPEC_FREEVIEW ? - m_pClient->m_aClients[m_pClient->m_Snap.m_pSpectatorInfo->m_SpectatorID].m_aName : Localize("Free-View")); + str_format(aBuf, sizeof(aBuf), "%s: %s", Localize("Spectate"), m_pClient->m_Snap.m_SpecInfo.m_SpectatorID != SPEC_FREEVIEW ? + m_pClient->m_aClients[m_pClient->m_Snap.m_SpecInfo.m_SpectatorID].m_aName : Localize("Free-View")); TextRender()->Text(0, m_Width-174.0f, m_Height-13.0f, 8.0f, aBuf, -1); } @@ -422,10 +422,10 @@ void CHud::OnRender() if(m_pClient->m_Snap.m_pLocalCharacter && !(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER)) RenderHealthAndAmmo(m_pClient->m_Snap.m_pLocalCharacter); - else if(m_pClient->m_Snap.m_Spectate) + else if(m_pClient->m_Snap.m_SpecInfo.m_Active) { - if(m_pClient->m_Snap.m_pSpectatorInfo && m_pClient->m_Snap.m_pSpectatorInfo->m_SpectatorID != SPEC_FREEVIEW) - RenderHealthAndAmmo(&m_pClient->m_Snap.m_aCharacters[m_pClient->m_Snap.m_pSpectatorInfo->m_SpectatorID].m_Cur); + if(m_pClient->m_Snap.m_SpecInfo.m_SpectatorID != SPEC_FREEVIEW) + RenderHealthAndAmmo(&m_pClient->m_Snap.m_aCharacters[m_pClient->m_Snap.m_SpecInfo.m_SpectatorID].m_Cur); RenderSpectatorHud(); } diff --git a/src/game/client/components/menus_demo.cpp b/src/game/client/components/menus_demo.cpp index 92dd381d..068d9c32 100644 --- a/src/game/client/components/menus_demo.cpp +++ b/src/game/client/components/menus_demo.cpp @@ -55,8 +55,8 @@ void CMenus::RenderDemoPlayer(CUIRect MainView) TotalHeight = SeekBarHeight+Margins*2; MainView.HSplitBottom(TotalHeight, 0, &MainView); - MainView.VSplitLeft(250.0f, 0, &MainView); - MainView.VSplitRight(250.0f, &MainView, 0); + MainView.VSplitLeft(50.0f, 0, &MainView); + MainView.VSplitRight(450.0f, &MainView, 0); RenderTools()->DrawUIRect(&MainView, ms_ColorTabbarActive, CUI::CORNER_T, 10.0f); diff --git a/src/game/client/components/scoreboard.cpp b/src/game/client/components/scoreboard.cpp index a9b249ed..0d355456 100644 --- a/src/game/client/components/scoreboard.cpp +++ b/src/game/client/components/scoreboard.cpp @@ -151,11 +151,14 @@ void CScoreboard::RenderScoreboard(float x, float y, float w, int Team, const ch } else { - char aBuf[128]; - int Score = m_pClient->m_Snap.m_pLocalInfo->m_Score; - str_format(aBuf, sizeof(aBuf), "%d", Score); - tw = TextRender()->TextWidth(0, 48, aBuf, -1); - TextRender()->Text(0, x+w-tw-30, y, 48, aBuf, -1); + if(m_pClient->m_Snap.m_pLocalInfo) + { + char aBuf[128]; + int Score = m_pClient->m_Snap.m_pLocalInfo->m_Score; + str_format(aBuf, sizeof(aBuf), "%d", Score); + tw = TextRender()->TextWidth(0, 48, aBuf, -1); + TextRender()->Text(0, x+w-tw-30, y, 48, aBuf, -1); + } } y += 54.0f; diff --git a/src/game/client/components/spectator.cpp b/src/game/client/components/spectator.cpp index 18035248..706dbc63 100644 --- a/src/game/client/components/spectator.cpp +++ b/src/game/client/components/spectator.cpp @@ -1,5 +1,6 @@ /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ /* If you are missing that file, acquire a complete release at teeworlds.com. */ +#include <engine/demo.h> #include <engine/graphics.h> #include <engine/textrender.h> #include <engine/shared/config.h> @@ -16,7 +17,8 @@ void CSpectator::ConKeySpectator(IConsole::IResult *pResult, void *pUserData) { CSpectator *pSelf = (CSpectator *)pUserData; - if(pSelf->m_pClient->m_Snap.m_Spectate) + if(pSelf->m_pClient->m_Snap.m_SpecInfo.m_Active && + (pSelf->Client()->State() != IClient::STATE_DEMOPLAYBACK || pSelf->DemoPlayer()->GetDemoType() == IDemoPlayer::DEMOTYPE_SERVER)) pSelf->m_Active = pResult->GetInteger(0) != 0; } @@ -58,7 +60,7 @@ void CSpectator::OnRender() { if(m_SelectedSpectatorID != NO_SELECTION) Spectate(m_SelectedSpectatorID); - OnReset(); + m_WasActive = false; } return; } @@ -89,8 +91,7 @@ void CSpectator::OnRender() float LineHeight = 60.0f; bool Selected = false; - int SpectatorID = m_pClient->m_Snap.m_pSpectatorInfo ? m_pClient->m_Snap.m_pSpectatorInfo->m_SpectatorID : SPEC_FREEVIEW; - if(SpectatorID == SPEC_FREEVIEW) + if(m_pClient->m_Snap.m_SpecInfo.m_SpectatorID == SPEC_FREEVIEW) { Graphics()->TextureSet(-1); Graphics()->QuadsBegin(); @@ -120,7 +121,7 @@ void CSpectator::OnRender() y = StartY; } - if(SpectatorID == i) + if(m_pClient->m_Snap.m_SpecInfo.m_SpectatorID == i) { Graphics()->TextureSet(-1); Graphics()->QuadsBegin(); @@ -163,7 +164,13 @@ void CSpectator::OnReset() void CSpectator::Spectate(int SpectatorID) { - if(m_pClient->m_Snap.m_pSpectatorInfo && m_pClient->m_Snap.m_pSpectatorInfo->m_SpectatorID == SpectatorID) + if(Client()->State() == IClient::STATE_DEMOPLAYBACK) + { + m_pClient->m_DemoSpecID = clamp(SpectatorID, (int)SPEC_FREEVIEW, MAX_CLIENTS-1); + return; + } + + if(m_pClient->m_Snap.m_SpecInfo.m_SpectatorID == SpectatorID) return; CNetMsg_Cl_SetSpectatorMode Msg; diff --git a/src/game/client/gameclient.cpp b/src/game/client/gameclient.cpp index 0d847162..0e2e8056 100644 --- a/src/game/client/gameclient.cpp +++ b/src/game/client/gameclient.cpp @@ -337,6 +337,8 @@ void CGameClient::OnReset() for(int i = 0; i < m_All.m_Num; i++) m_All.m_paComponents[i]->OnReset(); + + m_DemoSpecID = SPEC_FREEVIEW; } @@ -360,13 +362,26 @@ void CGameClient::UpdatePositions() } // spectator position - if(m_Snap.m_Spectate && m_Snap.m_pSpectatorInfo) + if(m_Snap.m_SpecInfo.m_Active) { - if(m_Snap.m_pPrevSpectatorInfo) - m_Snap.m_SpectatorPos = mix(vec2(m_Snap.m_pPrevSpectatorInfo->m_X, m_Snap.m_pPrevSpectatorInfo->m_Y), - vec2(m_Snap.m_pSpectatorInfo->m_X, m_Snap.m_pSpectatorInfo->m_Y), Client()->IntraGameTick()); - else - m_Snap.m_SpectatorPos = vec2(m_Snap.m_pSpectatorInfo->m_X, m_Snap.m_pSpectatorInfo->m_Y); + if(Client()->State() == IClient::STATE_DEMOPLAYBACK && DemoPlayer()->GetDemoType() == IDemoPlayer::DEMOTYPE_SERVER && + m_Snap.m_SpecInfo.m_SpectatorID != SPEC_FREEVIEW) + { + m_Snap.m_SpecInfo.m_Position = mix( + vec2(m_Snap.m_aCharacters[m_Snap.m_SpecInfo.m_SpectatorID].m_Prev.m_X, m_Snap.m_aCharacters[m_Snap.m_SpecInfo.m_SpectatorID].m_Prev.m_Y), + vec2(m_Snap.m_aCharacters[m_Snap.m_SpecInfo.m_SpectatorID].m_Cur.m_X, m_Snap.m_aCharacters[m_Snap.m_SpecInfo.m_SpectatorID].m_Cur.m_Y), + Client()->IntraGameTick()); + m_Snap.m_SpecInfo.m_UsePosition = true; + } + else if(m_Snap.m_pSpectatorInfo && (Client()->State() == IClient::STATE_DEMOPLAYBACK || m_Snap.m_SpecInfo.m_SpectatorID != SPEC_FREEVIEW)) + { + if(m_Snap.m_pPrevSpectatorInfo) + m_Snap.m_SpecInfo.m_Position = mix(vec2(m_Snap.m_pPrevSpectatorInfo->m_X, m_Snap.m_pPrevSpectatorInfo->m_Y), + vec2(m_Snap.m_pSpectatorInfo->m_X, m_Snap.m_pSpectatorInfo->m_Y), Client()->IntraGameTick()); + else + m_Snap.m_SpecInfo.m_Position = vec2(m_Snap.m_pSpectatorInfo->m_X, m_Snap.m_pSpectatorInfo->m_Y); + m_Snap.m_SpecInfo.m_UsePosition = true; + } } } @@ -720,7 +735,10 @@ void CGameClient::OnNewSnapshot() m_Snap.m_pLocalInfo = pInfo; if(pInfo->m_Team == TEAM_SPECTATORS) - m_Snap.m_Spectate = true; + { + m_Snap.m_SpecInfo.m_Active = true; + m_Snap.m_SpecInfo.m_SpectatorID = SPEC_FREEVIEW; + } } // calculate team-balance @@ -747,6 +765,8 @@ void CGameClient::OnNewSnapshot() { m_Snap.m_pSpectatorInfo = (const CNetObj_SpectatorInfo *)pData; m_Snap.m_pPrevSpectatorInfo = (const CNetObj_SpectatorInfo *)Client()->SnapFindItem(IClient::SNAP_PREV, NETOBJTYPE_SPECTATORINFO, Item.m_ID); + + m_Snap.m_SpecInfo.m_SpectatorID = m_Snap.m_pSpectatorInfo->m_SpectatorID; } else if(Item.m_Type == NETOBJTYPE_GAMEINFO) { @@ -785,7 +805,14 @@ void CGameClient::OnNewSnapshot() } } else - m_Snap.m_Spectate = true; + { + m_Snap.m_SpecInfo.m_Active = true; + if(Client()->State() == IClient::STATE_DEMOPLAYBACK && DemoPlayer()->GetDemoType() == IDemoPlayer::DEMOTYPE_SERVER && + m_DemoSpecID != SPEC_FREEVIEW && m_Snap.m_aCharacters[m_DemoSpecID].m_Active) + m_Snap.m_SpecInfo.m_SpectatorID = m_DemoSpecID; + else + m_Snap.m_SpecInfo.m_SpectatorID = SPEC_FREEVIEW; + } // sort player infos by score mem_copy(m_Snap.m_paInfoByScore, m_Snap.m_paPlayerInfos, sizeof(m_Snap.m_paInfoByScore)); diff --git a/src/game/client/gameclient.h b/src/game/client/gameclient.h index 5e8b9391..831cae24 100644 --- a/src/game/client/gameclient.h +++ b/src/game/client/gameclient.h @@ -97,6 +97,8 @@ public: }; int m_ServerMode; + int m_DemoSpecID; + vec2 m_LocalCharacterPos; // predicted players @@ -122,8 +124,15 @@ public: int m_LocalClientID; int m_NumPlayers; int m_aTeamSize[2]; - bool m_Spectate; - vec2 m_SpectatorPos; + + // spectate data + struct CSpectateInfo + { + bool m_Active; + int m_SpectatorID; + bool m_UsePosition; + vec2 m_Position; + } m_SpecInfo; // struct CCharacterInfo diff --git a/src/game/server/player.cpp b/src/game/server/player.cpp index 7d2f4ad9..82b45011 100644 --- a/src/game/server/player.cpp +++ b/src/game/server/player.cpp @@ -126,7 +126,7 @@ void CPlayer::Snap(int SnappingClient) if(m_ClientID == SnappingClient) pPlayerInfo->m_Local = 1; - if(m_ClientID == SnappingClient && m_Team == TEAM_SPECTATORS && m_SpectatorID != SPEC_FREEVIEW) + if(m_ClientID == SnappingClient && m_Team == TEAM_SPECTATORS) { CNetObj_SpectatorInfo *pSpectatorInfo = static_cast<CNetObj_SpectatorInfo *>(Server()->SnapNewItem(NETOBJTYPE_SPECTATORINFO, m_ClientID, sizeof(CNetObj_SpectatorInfo))); if(!pSpectatorInfo) |