/* Copyright (c) 2002-2012 Croteam Ltd. All rights reserved. */ #include "stdh.h" #include #include #include #include #include #include #include #include extern FLOAT net_tmConnectionTimeout; extern FLOAT net_tmProblemsTimeOut; /* * Constructor. */ CPlayerSource::CPlayerSource(void) { pls_Active = FALSE; pls_Index = -2; pls_csAction.cs_iIndex = -1; // clear action packet pls_paAction.Clear(); } /* * Destructor. */ CPlayerSource::~CPlayerSource(void) { } /* * Activate a new player. */ void CPlayerSource::Start_t(CPlayerCharacter &pcCharacter) // throw char * { ASSERT(!pls_Active); // set index to -1 what means that you are not yet registered properly pls_Index = -1; // copy the character data pls_pcCharacter = pcCharacter; // clear actions pls_paAction.Clear();; for(INDEX ipa=0; ipaSendToServerReliable(nmRegisterPlayer); for(TIME tmWait=0; tmWaitga_IsServer) { _pNetwork->TimerLoop(); } if (_cmiComm.Client_Update() == FALSE) { break; } // wait for message to come CNetworkMessage nmReceived; if (!_pNetwork->ReceiveFromServerReliable(nmReceived)) { continue; } // if this is the init message if (nmReceived.GetType() == MSG_REP_CONNECTPLAYER) { // remember your index nmReceived>>pls_Index; // finish waiting pls_Active = TRUE; return; // if this is disconnect message } else if (nmReceived.GetType() == MSG_INF_DISCONNECTED) { // confirm disconnect CNetworkMessage nmConfirmDisconnect(MSG_REP_DISCONNECTED); _pNetwork->SendToServerReliable(nmConfirmDisconnect); // throw exception CTString strReason; nmReceived>>strReason; _pNetwork->ga_sesSessionState.ses_strDisconnected = strReason; ThrowF_t(TRANS("Cannot add player because: %s\n"), strReason); // otherwise } else { // it is invalid message ThrowF_t(TRANS("Invalid message while waiting for player registration")); } // if client is disconnected if (!_cmiComm.Client_IsConnected()) { // quit ThrowF_t(TRANS("Client disconnected")); } } CNetworkMessage nmConfirmDisconnect(MSG_REP_DISCONNECTED); _pNetwork->SendToServerReliable(nmConfirmDisconnect); ThrowF_t(TRANS("Timeout while waiting for player registration")); } /* * Deactivate removed player. */ void CPlayerSource::Stop(void) { ASSERT(pls_Active); pls_Active = FALSE; pls_Index = -2; } // request character change for a player // NOTE: the request is asynchronious and possible failure cannot be detected void CPlayerSource::ChangeCharacter(CPlayerCharacter &pcNew) { // if the requested character has different guid if (!(pls_pcCharacter==pcNew)) { // fail CPrintF(TRANS("Cannot update character - different GUID\n")); } // just request the change CNetworkMessage nmChangeChar(MSG_REQ_CHARACTERCHANGE); nmChangeChar<SendToServerReliable(nmChangeChar); // remember new setting pls_pcCharacter = pcNew; } /* * Set player action. */ void CPlayerSource::SetAction(const CPlayerAction &paAction) { // synchronize access to action CTSingleLock slAction(&pls_csAction, TRUE); // set action pls_paAction = paAction; pls_paAction.pa_llCreated = _pTimer->GetHighPrecisionTimer().GetMilliseconds(); //CPrintF("%.2f - created: %d\n", _pTimer->GetRealTimeTick(), SLONG(pls_paAction.pa_llCreated)); } // get mask of this player for chat messages ULONG CPlayerSource::GetChatMask(void) { return 1UL<GetLocalPlayerEntity(this); } // if not if (ppe==NULL) { // just write a dummy bit BOOL bActive = 0; nm.WriteBits(&bActive, 1); return; } // normalize action (remove invalid floats like -0) pls_paAction.Normalize(); ASSERT(pls_Active); ASSERT(pls_Index>=0); // determine ping FLOAT tmPing = ppe->en_tmPing; INDEX iPing = (INDEX)ceil(tmPing*1000); // write all in the message BOOL bActive = 1; nm.WriteBits(&bActive, 1); nm.WriteBits(&pls_Index, 4); // your index nm.WriteBits(&iPing, 10); // your ping nm<GetRealTimeTick(), SLONG(pls_paAction.pa_llCreated)); // get sendbehind parameters extern INDEX cli_iSendBehind; extern INDEX cli_bPredictIfServer; cli_iSendBehind = Clamp(cli_iSendBehind, 0L, 3L); INDEX iSendBehind = cli_iSendBehind; // disable if server if (_pNetwork->IsServer() && !cli_bPredictIfServer) { iSendBehind = 0; } // save sendbehind if needed nm.WriteBits(&iSendBehind, 2); for(INDEX i=0; iIsPaused() && !_pNetwork->GetLocalPause()) { // get the index of the player target in game state INDEX iPlayerTarget = pls_Index; // if player is added if (iPlayerTarget>=0) { // get the player target CPlayerTarget &plt = _pNetwork->ga_sesSessionState.ses_apltPlayers[iPlayerTarget]; // let it buffer the packet plt.PrebufferActionPacket(pls_paAction); } } }