|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
#ifndef _TF_GC_SHARED_H
#define _TF_GC_SHARED_H
#ifdef _WIN32
#pragma once
#endif
#include "gcsdk/msgprotobuf.h"
using namespace GCSDK;
#define MMLog(...) do { Log( __VA_ARGS__ ); } while(false)
//-----------------------------------------------------------------------------
// ReliableMessage - A message/job class that retry until confirmed, and be sent
// In order with other such messages.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Check for pending messages
//-----------------------------------------------------------------------------
static bool BPendingReliableMessages();
//-----------------------------------------------------------------------------
GCSDK::CGCClientJob *s_pCurrentConfirmJob = NULL; CUtlQueue< GCSDK::CGCClientJob * > s_queuePendingConfirmJobs;
template < typename RELIABLE_MSG_CLASS, typename MSG_TYPE, ETFGCMsg E_MSG_TYPE, typename REPLY_TYPE, ETFGCMsg E_REPLY_TYPE> class CJobReliableMessageBase : public GCSDK::CGCClientJob { public: typedef CProtoBufMsg< MSG_TYPE > Msg_t; typedef CProtoBufMsg< REPLY_TYPE > Reply_t;
CJobReliableMessageBase() : GCSDK::CGCClientJob( GCClientSystem()->GetGCClient() ) , m_msg( E_MSG_TYPE ) , m_msgReply() {}
Msg_t &Msg() { return m_msg; } void Enqueue() { static_cast<RELIABLE_MSG_CLASS *>(this)->InitDebugString( m_strDebug ); MMLog( "[SendMsgUntilConfirmed] %s queued for %s\n", GetMsgName(), DebugString() );
if ( !s_pCurrentConfirmJob ) { s_pCurrentConfirmJob = this; this->StartJobDelayed( NULL ); } else { // Queue, confirm jobs will kick next in queue as necessary
s_queuePendingConfirmJobs.Insert( this ); } }
virtual bool BYieldingRunJob( void *pvStartParam ) { Assert( s_pCurrentConfirmJob == this ); bool bRet = BYieldingRunJobInternal();
if ( s_queuePendingConfirmJobs.Count() ) { // Kick off next job
s_pCurrentConfirmJob = s_queuePendingConfirmJobs.RemoveAtHead(); s_pCurrentConfirmJob->StartJob( NULL ); } else { s_pCurrentConfirmJob = NULL; }
return bRet; }
bool BYieldingRunJobInternal() { MMLog( "[SendMsgUntilConfirmed] %s started for %s\n", GetMsgName(), DebugString() );
// Trigger OnPrepare
static_cast<RELIABLE_MSG_CLASS *>(this)->OnPrepare();
for ( ;; ) { BYieldingWaitOneFrame();
// Create and load the message
// continuously attempt to send the message to the GC
BYldSendMessageAndGetReply_t result = BYldSendMessageAndGetReplyEx( m_msg, 30, &m_msgReply, E_REPLY_TYPE );
switch ( result ) { case BYLDREPLY_SUCCESS: MMLog( "[SendMsgUntilConfirmed] %s successfully sent for %s\n", GetMsgName(), DebugString() ); // Trigger OnReply
static_cast<RELIABLE_MSG_CLASS *>(this)->OnReply( m_msgReply ); return true; case BYLDREPLY_SEND_FAILED: MMLog( "[SendMsgUntilConfirmed] %s send FAILED for %s -- retrying\n", GetMsgName(), DebugString() ); break; case BYLDREPLY_TIMEOUT: MMLog( "[SendMsgUntilConfirmed] %s send TIMEOUT for %s -- retrying\n", GetMsgName(), DebugString() ); break; case BYLDREPLY_MSG_TYPE_MISMATCH: MMLog( "[SendMsgUntilConfirmed] %s send TYPE MISMATCH for %s\n", GetMsgName(), DebugString() ); Assert( !"Mismatched response type in reliable message" ); return true; } } }
protected: // Overrides
// Must be overridden by reliable message implementers. Debug string is e.g. "Match 12345, Lobby 4"
void InitDebugString( CUtlString &debugStr ) {} const char *MsgName() { return "<unknown>"; }
// Optionally overridden
void OnReply( Reply_t &msgReply ) {} // Called before sending, after previous messages in queue have flushed
void OnPrepare() {}
private: const char *DebugString() { return m_strDebug.Get(); }
// Forward to override
const char *GetMsgName() { return static_cast<RELIABLE_MSG_CLASS *>(this)->MsgName(); }
Msg_t m_msg; Reply_t m_msgReply; CUtlString m_strDebug;
void _static_asserts() { // Ensure we passed an override and provided provided these
#if __cplusplus >= 201103L && !defined ( OSX ) // (Don't have time to figure out what criteria the OS X toolchain has to not blow this)
static_assert( std::is_base_of< decltype( *this ), RELIABLE_MSG_CLASS >::value, "RELIABLE_MSG_CLASS Must be an override of this base" ); static_assert( !std::is_same< decltype( &(decltype( *this )::InitDebugString) ), decltype( &RELIABLE_MSG_CLASS::InitDebugString ) >::value && \ !std::is_same< decltype( &(decltype( *this )::MsgName) ), decltype( &RELIABLE_MSG_CLASS::MsgName ) >::value, "RELIABLE_MSG_CLASS class must override DebugString and MsgName" ); #endif // __cplusplus >= 201103L && !defined ( OSX )
} };
static bool BPendingReliableMessages() { Assert( !s_queuePendingConfirmJobs.Count() || s_pCurrentConfirmJob ); return !!s_pCurrentConfirmJob || s_queuePendingConfirmJobs.Count(); }
#endif // _TF_GC_SHARED_H
|