//========= 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(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(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(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 ""; } // 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(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