diff --git a/dll/flat.cpp b/dll/flat.cpp index e0545038..af045adc 100644 --- a/dll/flat.cpp +++ b/dll/flat.cpp @@ -757,6 +757,16 @@ STEAMAPI_API bool SteamAPI_ISteamFriends_RegisterProtocolInOverlayBrowser( IStea return (get_steam_client()->steam_friends)->RegisterProtocolInOverlayBrowser(pchProtocol); } +STEAMAPI_API ISteamUtils *SteamAPI_SteamUtils_v010() +{ + return get_steam_client()->GetISteamUtils(flat_hsteampipe(), "SteamUtils010"); +} + +STEAMAPI_API ISteamUtils *SteamAPI_SteamGameServerUtils_v010() +{ + return get_steam_client()->GetISteamUtils(flat_gs_hsteampipe(), "SteamUtils010"); +} + STEAMAPI_API ISteamUtils *SteamAPI_SteamUtils_v009() { return get_steam_client()->GetISteamUtils(flat_hsteampipe(), "SteamUtils009"); @@ -1127,28 +1137,14 @@ STEAMAPI_API bool SteamAPI_ISteamUtils_IsSteamChinaLauncher( ISteamUtils* self ) return (ptr)->IsSteamChinaLauncher(); } -STEAMAPI_API bool SteamAPI_ISteamUtils_InitFilterText( ISteamUtils* self ) +STEAMAPI_API bool SteamAPI_ISteamUtils_InitFilterText( ISteamUtils* self, uint32 unFilterOptions ) { - int test1 = ((char *)self - (char*)get_steam_client()->steam_utils); - int test2 = ((char *)self - (char*)get_steam_client()->steam_gameserver_utils); - auto ptr = get_steam_client()->steam_gameserver_utils; - if (test1 >= 0 && (test2 < 0 || test1 < test2)) { - ptr = get_steam_client()->steam_utils; - } - - return (ptr)->InitFilterText(); + return (self)->InitFilterText(unFilterOptions); } -STEAMAPI_API int SteamAPI_ISteamUtils_FilterText( ISteamUtils* self, char * pchOutFilteredText, uint32 nByteSizeOutFilteredText, const char * pchInputMessage, bool bLegalOnly ) +int SteamAPI_ISteamUtils_FilterText( ISteamUtils* self, ETextFilteringContext eContext, uint64_steamid sourceSteamID, const char * pchInputMessage, char * pchOutFilteredText, uint32 nByteSizeOutFilteredText ) { - int test1 = ((char *)self - (char*)get_steam_client()->steam_utils); - int test2 = ((char *)self - (char*)get_steam_client()->steam_gameserver_utils); - auto ptr = get_steam_client()->steam_gameserver_utils; - if (test1 >= 0 && (test2 < 0 || test1 < test2)) { - ptr = get_steam_client()->steam_utils; - } - - return (ptr)->FilterText(pchOutFilteredText, nByteSizeOutFilteredText, pchInputMessage, bLegalOnly); + return (self)->FilterText(eContext, sourceSteamID, pchInputMessage, pchOutFilteredText, nByteSizeOutFilteredText); } STEAMAPI_API ESteamIPv6ConnectivityState SteamAPI_ISteamUtils_GetIPv6ConnectivityState( ISteamUtils* self, ESteamIPv6ConnectivityProtocol eProtocol ) @@ -5111,6 +5107,56 @@ STEAMAPI_API bool SteamAPI_ISteamRemotePlay_BSendRemotePlayTogetherInvite( IStea return self->BSendRemotePlayTogetherInvite(steamIDFriend); } +STEAMAPI_API ISteamNetworkingMessages *SteamAPI_SteamNetworkingMessages_v002() +{ + return (ISteamNetworkingMessages *)get_steam_client()->GetISteamGenericInterface(flat_hsteamuser(), flat_hsteampipe(), "SteamNetworkingMessages002"); +} + +STEAMAPI_API ISteamNetworkingMessages *SteamAPI_SteamGameServerNetworkingMessages_v002() +{ + return (ISteamNetworkingMessages *)get_steam_client()->GetISteamGenericInterface(flat_gs_hsteamuser(), flat_gs_hsteampipe(), "SteamNetworkingMessages002"); +} + +STEAMAPI_API EResult SteamAPI_ISteamNetworkingMessages_SendMessageToUser( ISteamNetworkingMessages* self, const SteamNetworkingIdentity & identityRemote, const void * pubData, uint32 cubData, int nSendFlags, int nRemoteChannel ) +{ + return self->SendMessageToUser(identityRemote, pubData, cubData, nSendFlags, nRemoteChannel); +} + +STEAMAPI_API int SteamAPI_ISteamNetworkingMessages_ReceiveMessagesOnChannel( ISteamNetworkingMessages* self, int nLocalChannel, SteamNetworkingMessage_t ** ppOutMessages, int nMaxMessages ) +{ + return self->ReceiveMessagesOnChannel(nLocalChannel, ppOutMessages, nMaxMessages); +} + +STEAMAPI_API bool SteamAPI_ISteamNetworkingMessages_AcceptSessionWithUser( ISteamNetworkingMessages* self, const SteamNetworkingIdentity & identityRemote ) +{ + return self->AcceptSessionWithUser(identityRemote); +} + +STEAMAPI_API bool SteamAPI_ISteamNetworkingMessages_CloseSessionWithUser( ISteamNetworkingMessages* self, const SteamNetworkingIdentity & identityRemote ) +{ + return self->CloseSessionWithUser(identityRemote); +} + +STEAMAPI_API bool SteamAPI_ISteamNetworkingMessages_CloseChannelWithUser( ISteamNetworkingMessages* self, const SteamNetworkingIdentity & identityRemote, int nLocalChannel ) +{ + return self->CloseChannelWithUser(identityRemote, nLocalChannel); +} + +STEAMAPI_API ESteamNetworkingConnectionState SteamAPI_ISteamNetworkingMessages_GetSessionConnectionInfo( ISteamNetworkingMessages* self, const SteamNetworkingIdentity & identityRemote, SteamNetConnectionInfo_t * pConnectionInfo, SteamNetworkingQuickConnectionStatus * pQuickStatus ) +{ + return self->GetSessionConnectionInfo(identityRemote, pConnectionInfo, pQuickStatus); +} + +STEAMAPI_API ISteamNetworkingSockets *SteamAPI_SteamNetworkingSockets_v009() +{ + return (ISteamNetworkingSockets *)get_steam_client()->GetISteamGenericInterface(flat_hsteamuser(), flat_hsteampipe(), "SteamNetworkingSockets009"); +} + +STEAMAPI_API ISteamNetworkingSockets *SteamAPI_SteamGameServerNetworkingSockets_v009() +{ + return (ISteamNetworkingSockets *)get_steam_client()->GetISteamGenericInterface(flat_gs_hsteamuser(), flat_gs_hsteampipe(), "SteamNetworkingSockets009"); +} + STEAMAPI_API ISteamNetworkingSockets *SteamAPI_SteamNetworkingSockets_v008() { return (ISteamNetworkingSockets *)get_steam_client()->GetISteamGenericInterface(flat_hsteamuser(), flat_hsteampipe(), "SteamNetworkingSockets008"); @@ -5296,9 +5342,9 @@ STEAMAPI_API EResult SteamAPI_ISteamNetworkingSockets_GetGameCoordinatorServerLo return self->GetGameCoordinatorServerLogin(pLoginInfo, pcbSignedBlob, pBlob); } -STEAMAPI_API HSteamNetConnection SteamAPI_ISteamNetworkingSockets_ConnectP2PCustomSignaling( ISteamNetworkingSockets* self, ISteamNetworkingConnectionCustomSignaling * pSignaling, const SteamNetworkingIdentity * pPeerIdentity, int nOptions, const SteamNetworkingConfigValue_t * pOptions ) +STEAMAPI_API HSteamNetConnection SteamAPI_ISteamNetworkingSockets_ConnectP2PCustomSignaling( ISteamNetworkingSockets* self, ISteamNetworkingConnectionCustomSignaling * pSignaling, const SteamNetworkingIdentity * pPeerIdentity, int nRemoteVirtualPort, int nOptions, const SteamNetworkingConfigValue_t * pOptions ) { - return self->ConnectP2PCustomSignaling(pSignaling, pPeerIdentity, nOptions, pOptions); + return self->ConnectP2PCustomSignaling(pSignaling, pPeerIdentity, nRemoteVirtualPort, nOptions, pOptions); } STEAMAPI_API bool SteamAPI_ISteamNetworkingSockets_ReceivedP2PCustomSignal( ISteamNetworkingSockets* self, const void * pMsg, int cbMsg, ISteamNetworkingCustomSignalingRecvContext * pContext ) @@ -5316,6 +5362,11 @@ STEAMAPI_API bool SteamAPI_ISteamNetworkingSockets_SetCertificate( ISteamNetwork return self->SetCertificate(pCertificate, cbCertificate, errMsg); } +STEAMAPI_API void SteamAPI_ISteamNetworkingSockets_RunCallbacks( ISteamNetworkingSockets* self ) +{ + return self->RunCallbacks(); +} + STEAMAPI_API bool SteamAPI_ISteamNetworkingConnectionCustomSignaling_SendSignal( ISteamNetworkingConnectionCustomSignaling* self, HSteamNetConnection hConn, const SteamNetConnectionInfo_t & info, const void * pMsg, int cbMsg ) { return self->SendSignal(hConn, info, pMsg, cbMsg); @@ -5431,6 +5482,11 @@ STEAMAPI_API bool SteamAPI_ISteamNetworkingUtils_SetGlobalConfigValueString( ISt return self->SetGlobalConfigValueString(eValue, val); } +STEAMAPI_API bool SteamAPI_ISteamNetworkingUtils_SetGlobalConfigValuePtr( ISteamNetworkingUtils* self, ESteamNetworkingConfigValue eValue, void * val ) +{ + return self->SetGlobalConfigValuePtr(eValue, val); +} + STEAMAPI_API bool SteamAPI_ISteamNetworkingUtils_SetConnectionConfigValueInt32( ISteamNetworkingUtils* self, HSteamNetConnection hConn, ESteamNetworkingConfigValue eValue, int32 val ) { return self->SetConnectionConfigValueInt32(hConn, eValue, val); @@ -5446,6 +5502,31 @@ STEAMAPI_API bool SteamAPI_ISteamNetworkingUtils_SetConnectionConfigValueString( return self->SetConnectionConfigValueString(hConn, eValue, val); } +STEAMAPI_API bool SteamAPI_ISteamNetworkingUtils_SetGlobalCallback_SteamNetConnectionStatusChanged( ISteamNetworkingUtils* self, FnSteamNetConnectionStatusChanged fnCallback ) +{ + return self->SetGlobalCallback_SteamNetConnectionStatusChanged(fnCallback); +} + +STEAMAPI_API bool SteamAPI_ISteamNetworkingUtils_SetGlobalCallback_SteamNetAuthenticationStatusChanged( ISteamNetworkingUtils* self, FnSteamNetAuthenticationStatusChanged fnCallback ) +{ + return self->SetGlobalCallback_SteamNetAuthenticationStatusChanged(fnCallback); +} + +STEAMAPI_API bool SteamAPI_ISteamNetworkingUtils_SetGlobalCallback_SteamRelayNetworkStatusChanged( ISteamNetworkingUtils* self, FnSteamRelayNetworkStatusChanged fnCallback ) +{ + return self->SetGlobalCallback_SteamRelayNetworkStatusChanged(fnCallback); +} + +STEAMAPI_API bool SteamAPI_ISteamNetworkingUtils_SetGlobalCallback_MessagesSessionRequest( ISteamNetworkingUtils* self, FnSteamNetworkingMessagesSessionRequest fnCallback ) +{ + return self->SetGlobalCallback_MessagesSessionRequest(fnCallback); +} + +STEAMAPI_API bool SteamAPI_ISteamNetworkingUtils_SetGlobalCallback_MessagesSessionFailed( ISteamNetworkingUtils* self, FnSteamNetworkingMessagesSessionFailed fnCallback ) +{ + return self->SetGlobalCallback_MessagesSessionFailed(fnCallback); +} + STEAMAPI_API bool SteamAPI_ISteamNetworkingUtils_SetConfigValue( ISteamNetworkingUtils* self, ESteamNetworkingConfigValue eValue, ESteamNetworkingConfigScope eScopeType, intptr_t scopeObj, ESteamNetworkingConfigDataType eDataType, const void * pArg ) { return self->SetConfigValue(eValue, eScopeType, scopeObj, eDataType, pArg); @@ -6037,6 +6118,31 @@ STEAMAPI_API void SteamAPI_SteamNetworkingMessage_t_Release( SteamNetworkingMess return self->Release(); } +STEAMAPI_API void SteamAPI_SteamNetworkingConfigValue_t_SetInt32( SteamNetworkingConfigValue_t* self, ESteamNetworkingConfigValue eVal, int32_t data ) +{ + return self->SetInt32(eVal, data); +} + +STEAMAPI_API void SteamAPI_SteamNetworkingConfigValue_t_SetInt64( SteamNetworkingConfigValue_t* self, ESteamNetworkingConfigValue eVal, int64_t data ) +{ + return self->SetInt64(eVal, data); +} + +STEAMAPI_API void SteamAPI_SteamNetworkingConfigValue_t_SetFloat( SteamNetworkingConfigValue_t* self, ESteamNetworkingConfigValue eVal, float data ) +{ + return self->SetFloat(eVal, data); +} + +STEAMAPI_API void SteamAPI_SteamNetworkingConfigValue_t_SetPtr( SteamNetworkingConfigValue_t* self, ESteamNetworkingConfigValue eVal, void * data ) +{ + return self->SetPtr(eVal, data); +} + +STEAMAPI_API void SteamAPI_SteamNetworkingConfigValue_t_SetString( SteamNetworkingConfigValue_t* self, ESteamNetworkingConfigValue eVal, const char * data ) +{ + return self->SetString(eVal, data); +} + STEAMAPI_API const char * SteamAPI_SteamNetworkingPOPIDRender_c_str( SteamNetworkingPOPIDRender* self ) { return self->c_str(); diff --git a/dll/steam_client.cpp b/dll/steam_client.cpp index 0e10d75a..8d0506a5 100644 --- a/dll/steam_client.cpp +++ b/dll/steam_client.cpp @@ -85,6 +85,7 @@ Steam_Client::Steam_Client() steam_parental = new Steam_Parental(); steam_networking_sockets = new Steam_Networking_Sockets(settings_client, network, callback_results_client, callbacks_client, run_every_runcb); steam_networking_sockets_serialized = new Steam_Networking_Sockets_Serialized(settings_client, network, callback_results_client, callbacks_client, run_every_runcb); + steam_networking_messages = new Steam_Networking_Messages(settings_client, network, callback_results_client, callbacks_client, run_every_runcb); steam_game_coordinator = new Steam_Game_Coordinator(settings_client, network, callback_results_client, callbacks_client, run_every_runcb); steam_networking_utils = new Steam_Networking_Utils(settings_client, network, callback_results_client, callbacks_client, run_every_runcb); steam_unified_messages = new Steam_Unified_Messages(settings_client, network, callback_results_client, callbacks_client, run_every_runcb); @@ -104,6 +105,7 @@ Steam_Client::Steam_Client() steam_gameserver_apps = new Steam_Apps(settings_server, callback_results_server); steam_gameserver_networking_sockets = new Steam_Networking_Sockets(settings_server, network, callback_results_server, callbacks_server, run_every_runcb); steam_gameserver_networking_sockets_serialized = new Steam_Networking_Sockets_Serialized(settings_server, network, callback_results_server, callbacks_server, run_every_runcb); + steam_gameserver_networking_messages = new Steam_Networking_Messages(settings_server, network, callback_results_server, callbacks_server, run_every_runcb); steam_gameserver_game_coordinator = new Steam_Game_Coordinator(settings_server, network, callback_results_server, callbacks_server, run_every_runcb); steam_masterserver_updater = new Steam_Masterserver_Updater(settings_server, network, callback_results_server, callbacks_server, run_every_runcb); @@ -390,6 +392,8 @@ ISteamUtils *Steam_Client::GetISteamUtils( HSteamPipe hSteamPipe, const char *pc return (ISteamUtils *)(void *)(ISteamUtils007 *)steam_utils_temp; } else if (strcmp(pchVersion, "SteamUtils008") == 0) { return (ISteamUtils *)(void *)(ISteamUtils008 *)steam_utils_temp; + } else if (strcmp(pchVersion, "SteamUtils009") == 0) { + return (ISteamUtils *)(void *)(ISteamUtils009 *)steam_utils_temp; } else if (strcmp(pchVersion, STEAMUTILS_INTERFACE_VERSION) == 0) { return (ISteamUtils *)(void *)(ISteamUtils *)steam_utils_temp; } else { @@ -492,9 +496,20 @@ void *Steam_Client::GetISteamGenericInterface( HSteamUser hSteamUser, HSteamPipe return (void *)(ISteamNetworkingSockets003 *) steam_networking_sockets_temp; } else if (strcmp(pchVersion, "SteamNetworkingSockets006") == 0) { return (void *)(ISteamNetworkingSockets006 *) steam_networking_sockets_temp; + } else if (strcmp(pchVersion, "SteamNetworkingSockets008") == 0) { + return (void *)(ISteamNetworkingSockets008 *) steam_networking_sockets_temp; } else { return (void *)(ISteamNetworkingSockets *) steam_networking_sockets_temp; } + } else if (strstr(pchVersion, "SteamNetworkingMessages") == pchVersion) { + Steam_Networking_Messages *steam_networking_messages_temp; + if (server) { + steam_networking_messages_temp = steam_gameserver_networking_messages; + } else { + steam_networking_messages_temp = steam_networking_messages; + } + + return (void *)(ISteamNetworkingMessages *)steam_networking_messages_temp; } else if (strstr(pchVersion, "SteamGameCoordinator") == pchVersion) { Steam_Game_Coordinator *steam_game_coordinator_temp; if (server) { diff --git a/dll/steam_client.h b/dll/steam_client.h index bb5943c9..c0857094 100644 --- a/dll/steam_client.h +++ b/dll/steam_client.h @@ -43,6 +43,7 @@ #include "steam_game_coordinator.h" #include "steam_networking_socketsserialized.h" #include "steam_networking_sockets.h" +#include "steam_networking_messages.h" #include "steam_networking_utils.h" #include "steam_unified_messages.h" #include "steam_gamesearch.h" @@ -108,6 +109,7 @@ public: Steam_Parental *steam_parental; Steam_Networking_Sockets *steam_networking_sockets; Steam_Networking_Sockets_Serialized *steam_networking_sockets_serialized; + Steam_Networking_Messages *steam_networking_messages; Steam_Game_Coordinator *steam_game_coordinator; Steam_Networking_Utils *steam_networking_utils; Steam_Unified_Messages *steam_unified_messages; @@ -126,6 +128,7 @@ public: Steam_Apps *steam_gameserver_apps; Steam_Networking_Sockets *steam_gameserver_networking_sockets; Steam_Networking_Sockets_Serialized *steam_gameserver_networking_sockets_serialized; + Steam_Networking_Messages *steam_gameserver_networking_messages; Steam_Game_Coordinator *steam_gameserver_game_coordinator; Steam_Masterserver_Updater *steam_masterserver_updater; diff --git a/dll/steam_networking_messages.h b/dll/steam_networking_messages.h new file mode 100644 index 00000000..deadca5a --- /dev/null +++ b/dll/steam_networking_messages.h @@ -0,0 +1,189 @@ +/* Copyright (C) 2019 Mr Goldberg + This file is part of the Goldberg Emulator + + The Goldberg Emulator is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + The Goldberg Emulator is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the Goldberg Emulator; if not, see + . */ + +#include "base.h" + +class Steam_Networking_Messages : +public ISteamNetworkingMessages +{ + class Settings *settings; + class Networking *network; + class SteamCallResults *callback_results; + class SteamCallBacks *callbacks; + class RunEveryRunCB *run_every_runcb; + +public: +static void steam_callback(void *object, Common_Message *msg) +{ + PRINT_DEBUG("steam_networking_messages_callback\n"); + + Steam_Networking_Messages *steam_networking_messages = (Steam_Networking_Messages *)object; + steam_networking_messages->Callback(msg); +} + +static void steam_run_every_runcb(void *object) +{ + PRINT_DEBUG("steam_networking_messages_run_every_runcb\n"); + + Steam_Networking_Messages *steam_networking_messages = (Steam_Networking_Messages *)object; + steam_networking_messages->RunCallbacks(); +} + +Steam_Networking_Messages(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb) +{ + this->settings = settings; + this->network = network; + this->run_every_runcb = run_every_runcb; + this->network->setCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Networking_Messages::steam_callback, this); + this->run_every_runcb->add(&Steam_Networking_Messages::steam_run_every_runcb, this); + + this->callback_results = callback_results; + this->callbacks = callbacks; +} + +~Steam_Networking_Messages() +{ + //TODO rm network callbacks + this->run_every_runcb->remove(&Steam_Networking_Messages::steam_run_every_runcb, this); +} + +/// Sends a message to the specified host. If we don't already have a session with that user, +/// a session is implicitly created. There might be some handshaking that needs to happen +/// before we can actually begin sending message data. If this handshaking fails and we can't +/// get through, an error will be posted via the callback SteamNetworkingMessagesSessionFailed_t. +/// There is no notification when the operation succeeds. (You should have the peer send a reply +/// for this purpose.) +/// +/// Sending a message to a host will also implicitly accept any incoming connection from that host. +/// +/// nSendFlags is a bitmask of k_nSteamNetworkingSend_xxx options +/// +/// nRemoteChannel is a routing number you can use to help route message to different systems. +/// You'll have to call ReceiveMessagesOnChannel() with the same channel number in order to retrieve +/// the data on the other end. +/// +/// Using different channels to talk to the same user will still use the same underlying +/// connection, saving on resources. If you don't need this feature, use 0. +/// Otherwise, small integers are the most efficient. +/// +/// It is guaranteed that reliable messages to the same host on the same channel +/// will be be received by the remote host (if they are received at all) exactly once, +/// and in the same order that they were send. +/// +/// NO other order guarantees exist! In particular, unreliable messages may be dropped, +/// received out of order with respect to each other and with respect to reliable data, +/// or may be received multiple times. Messages on different channels are *not* guaranteed +/// to be received in the order they were sent. +/// +/// A note for those familiar with TCP/IP ports, or converting an existing codebase that +/// opened multiple sockets: You might notice that there is only one channel, and with +/// TCP/IP each endpoint has a port number. You can think of the channel number as the +/// *destination* port. If you need each message to also include a "source port" (so the +/// recipient can route the reply), then just put that in your message. That is essentially +/// how UDP works! +/// +/// Returns: +/// - k_EREsultOK on success. +/// - k_EResultNoConnection will be returned if the session has failed or was closed by the peer, +/// and k_nSteamNetworkingSend_AutoRestartBrokwnSession is not used. (You can use +/// GetSessionConnectionInfo to get the details.) In order to acknowledge the broken session +/// and start a new one, you must call CloseSessionWithUser +/// - See SendMessageToConnection::SendMessageToConnection for more +EResult SendMessageToUser( const SteamNetworkingIdentity &identityRemote, const void *pubData, uint32 cubData, int nSendFlags, int nRemoteChannel ) +{ + PRINT_DEBUG("Steam_Networking_Messages::SendMessageToUser\n"); + return k_EResultNoConnection; +} + +/// Reads the next message that has been sent from another user via SendMessageToUser() on the given channel. +/// Returns number of messages returned into your list. (0 if no message are available on that channel.) +/// +/// When you're done with the message object(s), make sure and call Release()! +int ReceiveMessagesOnChannel( int nLocalChannel, SteamNetworkingMessage_t **ppOutMessages, int nMaxMessages ) +{ + PRINT_DEBUG("Steam_Networking_Messages::ReceiveMessagesOnChannel\n"); + return 0; +} + +/// AcceptSessionWithUser() should only be called in response to a SteamP2PSessionRequest_t callback +/// SteamP2PSessionRequest_t will be posted if another user tries to send you a message, and you haven't +/// tried to talk to them. If you don't want to talk to them, just ignore the request. +/// If the user continues to send you messages, SteamP2PSessionRequest_t callbacks will continue to +/// be posted periodically. This may be called multiple times for a single user. +/// +/// Calling SendMessage() on the other user, this implicitly accepts any pending session request. +bool AcceptSessionWithUser( const SteamNetworkingIdentity &identityRemote ) +{ + PRINT_DEBUG("Steam_Networking_Messages::AcceptSessionWithUser\n"); + return false; +} + +/// Call this when you're done talking to a user to immediately free up resources under-the-hood. +/// If the remote user tries to send data to you again, another P2PSessionRequest_t callback will +/// be posted. +/// +/// Note that sessions that go unused for a few minutes are automatically timed out. +bool CloseSessionWithUser( const SteamNetworkingIdentity &identityRemote ) +{ + PRINT_DEBUG("Steam_Networking_Messages::CloseSessionWithUser\n"); + return false; +} + +/// Call this when you're done talking to a user on a specific channel. Once all +/// open channels to a user have been closed, the open session to the user will be +/// closed, and any new data from this user will trigger a SteamP2PSessionRequest_t +/// callback +bool CloseChannelWithUser( const SteamNetworkingIdentity &identityRemote, int nLocalChannel ) +{ + PRINT_DEBUG("Steam_Networking_Messages::CloseChannelWithUser\n"); + return false; +} + +/// Returns information about the latest state of a connection, if any, with the given peer. +/// Primarily intended for debugging purposes, but can also be used to get more detailed +/// failure information. (See SendMessageToUser and k_nSteamNetworkingSend_AutoRestartBrokwnSession.) +/// +/// Returns the value of SteamNetConnectionInfo_t::m_eState, or k_ESteamNetworkingConnectionState_None +/// if no connection exists with specified peer. You may pass nullptr for either parameter if +/// you do not need the corresponding details. Note that sessions time out after a while, +/// so if a connection fails, or SendMessageToUser returns SendMessageToUser, you cannot wait +/// indefinitely to obtain the reason for failure. +ESteamNetworkingConnectionState GetSessionConnectionInfo( const SteamNetworkingIdentity &identityRemote, SteamNetConnectionInfo_t *pConnectionInfo, SteamNetworkingQuickConnectionStatus *pQuickStatus ) +{ + PRINT_DEBUG("Steam_Networking_Messages::GetSessionConnectionInfo\n"); + return k_ESteamNetworkingConnectionState_None; +} + + +void RunCallbacks() +{ +} + +void Callback(Common_Message *msg) +{ + if (msg->has_low_level()) { + if (msg->low_level().type() == Low_Level::CONNECT) { + + } + + if (msg->low_level().type() == Low_Level::DISCONNECT) { + + } + } +} + +}; diff --git a/dll/steam_networking_sockets.h b/dll/steam_networking_sockets.h index 34d185f5..59d36a66 100644 --- a/dll/steam_networking_sockets.h +++ b/dll/steam_networking_sockets.h @@ -51,6 +51,7 @@ public ISteamNetworkingSockets001, public ISteamNetworkingSockets002, public ISteamNetworkingSockets003, public ISteamNetworkingSockets006, +public ISteamNetworkingSockets008, public ISteamNetworkingSockets { class Settings *settings; @@ -1421,11 +1422,18 @@ EResult GetGameCoordinatorServerLogin( SteamDatagramGameCoordinatorServerLogin * /// SteamNetworkingConfigValue_t for more about why this is preferable to /// setting the options "immediately" after creation. HSteamNetConnection ConnectP2PCustomSignaling( ISteamNetworkingConnectionCustomSignaling *pSignaling, const SteamNetworkingIdentity *pPeerIdentity, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) +{ + PRINT_DEBUG("Steam_Networking_Sockets::ConnectP2PCustomSignaling old\n"); + return ConnectP2PCustomSignaling(pSignaling, pPeerIdentity, 0, nOptions, pOptions); +} + +HSteamNetConnection ConnectP2PCustomSignaling( ISteamNetworkingConnectionCustomSignaling *pSignaling, const SteamNetworkingIdentity *pPeerIdentity, int nRemoteVirtualPort, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) { PRINT_DEBUG("Steam_Networking_Sockets::ConnectP2PCustomSignaling\n"); return k_HSteamNetConnection_Invalid; } + /// Called when custom signaling has received a message. When your /// signaling channel receives a message, it should save off whatever /// routing information was in the envelope into the context object, diff --git a/dll/steam_utils.h b/dll/steam_utils.h index 69c320b5..ce76e8c8 100644 --- a/dll/steam_utils.h +++ b/dll/steam_utils.h @@ -30,6 +30,7 @@ public ISteamUtils005, public ISteamUtils006, public ISteamUtils007, public ISteamUtils008, +public ISteamUtils009, public ISteamUtils { private: @@ -356,6 +357,15 @@ bool IsSteamChinaLauncher() // Initializes text filtering. // Returns false if filtering is unavailable for the language the user is currently running in. bool InitFilterText() +{ + PRINT_DEBUG("InitFilterText old\n"); + return false; +} + +// Initializes text filtering. +// unFilterOptions are reserved for future use and should be set to 0 +// Returns false if filtering is unavailable for the language the user is currently running in. +bool InitFilterText( uint32 unFilterOptions ) { PRINT_DEBUG("InitFilterText\n"); return false; @@ -368,11 +378,25 @@ bool InitFilterText() // bLegalOnly should be false if you want profanity and legally required filtering (where required) and true if you want legally required filtering only // Returns the number of characters (not bytes) filtered. int FilterText( char* pchOutFilteredText, uint32 nByteSizeOutFilteredText, const char * pchInputMessage, bool bLegalOnly ) +{ + PRINT_DEBUG("FilterText old\n"); + return 0; +} + +// Filters the provided input message and places the filtered result into pchOutFilteredText, using legally required filtering and additional filtering based on the context and user settings +// eContext is the type of content in the input string +// sourceSteamID is the Steam ID that is the source of the input string (e.g. the player with the name, or who said the chat text) +// pchInputText is the input string that should be filtered, which can be ASCII or UTF-8 +// pchOutFilteredText is where the output will be placed, even if no filtering is performed +// nByteSizeOutFilteredText is the size (in bytes) of pchOutFilteredText, should be at least strlen(pchInputText)+1 +// Returns the number of characters (not bytes) filtered +int FilterText( ETextFilteringContext eContext, CSteamID sourceSteamID, const char *pchInputMessage, char *pchOutFilteredText, uint32 nByteSizeOutFilteredText ) { PRINT_DEBUG("FilterText\n"); return 0; } + // Return what we believe your current ipv6 connectivity to "the internet" is on the specified protocol. // This does NOT tell you if the Steam client is currently connected to Steam via ipv6. ESteamIPv6ConnectivityState GetIPv6ConnectivityState( ESteamIPv6ConnectivityProtocol eProtocol ) diff --git a/sdk_includes/isteamnetworking.h b/sdk_includes/isteamnetworking.h index 1f7202fa..20356c06 100644 --- a/sdk_includes/isteamnetworking.h +++ b/sdk_includes/isteamnetworking.h @@ -120,6 +120,10 @@ enum ESNetSocketConnectionType //----------------------------------------------------------------------------- // Purpose: Functions for making connections and sending data between clients, // traversing NAT's where possible +// +// NOTE: This interface is deprecated and may be removed in a future release of +/// the Steamworks SDK. Please see ISteamNetworkingSockets and +/// ISteamNetworkingMessages //----------------------------------------------------------------------------- class ISteamNetworking { @@ -133,6 +137,9 @@ public: // Both interface styles can send both reliable and unreliable messages. // // Automatically establishes NAT-traversing or Relay server connections + // + // These APIs are deprecated, and may be removed in a future version of the Steamworks + // SDK. See ISteamNetworkingMessages. // Sends a P2P packet to the specified user // UDP-like, unreliable and a max packet size of 1200 bytes @@ -181,6 +188,10 @@ public: // or to existing connections that need to automatically reconnect after this value is set. // // P2P packet relay is allowed by default + // + // NOTE: This function is deprecated and may be removed in a future version of the SDK. For + // security purposes, we may decide to relay the traffic to certain peers, even if you pass false + // to this function, to prevent revealing the client's IP address top another peer. virtual bool AllowP2PPacketRelay( bool bAllow ) = 0; @@ -198,6 +209,9 @@ public: // // Both methods can send both reliable and unreliable methods. // + // These APIs are deprecated, and may be removed in a future version of the Steamworks + // SDK. See ISteamNetworkingSockets. + // //////////////////////////////////////////////////////////////////////////////////////////// diff --git a/sdk_includes/isteamnetworkingmessages.h b/sdk_includes/isteamnetworkingmessages.h new file mode 100644 index 00000000..2c5ccb92 --- /dev/null +++ b/sdk_includes/isteamnetworkingmessages.h @@ -0,0 +1,186 @@ +//====== Copyright Valve Corporation, All rights reserved. ==================== + +#ifndef ISTEAMNETWORKINGMESSAGES +#define ISTEAMNETWORKINGMESSAGES +#ifdef STEAM_WIN32 +#pragma once +#endif + +#include "steamnetworkingtypes.h" + +//----------------------------------------------------------------------------- +/// The non-connection-oriented interface to send and receive messages +/// (whether they be "clients" or "servers"). +/// +/// ISteamNetworkingSockets is connection-oriented (like TCP), meaning you +/// need to listen and connect, and then you send messages using a connection +/// handle. ISteamNetworkingMessages is more like UDP, in that you can just send +/// messages to arbitrary peers at any time. The underlying connections are +/// established implicitly. +/// +/// Under the hood ISteamNetworkingMessages works on top of the ISteamNetworkingSockets +/// code, so you get the same routing and messaging efficiency. The difference is +/// mainly in your responsibility to explicitly establish a connection and +/// the type of feedback you get about the state of the connection. Both +/// interfaces can do "P2P" communications, and both support both unreliable +/// and reliable messages, fragmentation and reassembly. +/// +/// The primary purpose of this interface is to be "like UDP", so that UDP-based code +/// can be ported easily to take advantage of relayed connections. If you find +/// yourself needing more low level information or control, or to be able to better +/// handle failure, then you probably need to use ISteamNetworkingSockets directly. +/// Also, note that if your main goal is to obtain a connection between two peers +/// without concerning yourself with assigning roles of "client" and "server", +/// you may find the symmetric connection mode of ISteamNetworkingSockets useful. +/// (See k_ESteamNetworkingConfig_SymmetricConnect.) +/// +class ISteamNetworkingMessages +{ +public: + /// Sends a message to the specified host. If we don't already have a session with that user, + /// a session is implicitly created. There might be some handshaking that needs to happen + /// before we can actually begin sending message data. If this handshaking fails and we can't + /// get through, an error will be posted via the callback SteamNetworkingMessagesSessionFailed_t. + /// There is no notification when the operation succeeds. (You should have the peer send a reply + /// for this purpose.) + /// + /// Sending a message to a host will also implicitly accept any incoming connection from that host. + /// + /// nSendFlags is a bitmask of k_nSteamNetworkingSend_xxx options + /// + /// nRemoteChannel is a routing number you can use to help route message to different systems. + /// You'll have to call ReceiveMessagesOnChannel() with the same channel number in order to retrieve + /// the data on the other end. + /// + /// Using different channels to talk to the same user will still use the same underlying + /// connection, saving on resources. If you don't need this feature, use 0. + /// Otherwise, small integers are the most efficient. + /// + /// It is guaranteed that reliable messages to the same host on the same channel + /// will be be received by the remote host (if they are received at all) exactly once, + /// and in the same order that they were send. + /// + /// NO other order guarantees exist! In particular, unreliable messages may be dropped, + /// received out of order with respect to each other and with respect to reliable data, + /// or may be received multiple times. Messages on different channels are *not* guaranteed + /// to be received in the order they were sent. + /// + /// A note for those familiar with TCP/IP ports, or converting an existing codebase that + /// opened multiple sockets: You might notice that there is only one channel, and with + /// TCP/IP each endpoint has a port number. You can think of the channel number as the + /// *destination* port. If you need each message to also include a "source port" (so the + /// recipient can route the reply), then just put that in your message. That is essentially + /// how UDP works! + /// + /// Returns: + /// - k_EREsultOK on success. + /// - k_EResultNoConnection will be returned if the session has failed or was closed by the peer, + /// and k_nSteamNetworkingSend_AutoRestartBrokwnSession is not used. (You can use + /// GetSessionConnectionInfo to get the details.) In order to acknowledge the broken session + /// and start a new one, you must call CloseSessionWithUser + /// - See SendMessageToConnection::SendMessageToConnection for more + virtual EResult SendMessageToUser( const SteamNetworkingIdentity &identityRemote, const void *pubData, uint32 cubData, int nSendFlags, int nRemoteChannel ) = 0; + + /// Reads the next message that has been sent from another user via SendMessageToUser() on the given channel. + /// Returns number of messages returned into your list. (0 if no message are available on that channel.) + /// + /// When you're done with the message object(s), make sure and call Release()! + virtual int ReceiveMessagesOnChannel( int nLocalChannel, SteamNetworkingMessage_t **ppOutMessages, int nMaxMessages ) = 0; + + /// AcceptSessionWithUser() should only be called in response to a SteamP2PSessionRequest_t callback + /// SteamP2PSessionRequest_t will be posted if another user tries to send you a message, and you haven't + /// tried to talk to them. If you don't want to talk to them, just ignore the request. + /// If the user continues to send you messages, SteamP2PSessionRequest_t callbacks will continue to + /// be posted periodically. This may be called multiple times for a single user. + /// + /// Calling SendMessage() on the other user, this implicitly accepts any pending session request. + virtual bool AcceptSessionWithUser( const SteamNetworkingIdentity &identityRemote ) = 0; + + /// Call this when you're done talking to a user to immediately free up resources under-the-hood. + /// If the remote user tries to send data to you again, another P2PSessionRequest_t callback will + /// be posted. + /// + /// Note that sessions that go unused for a few minutes are automatically timed out. + virtual bool CloseSessionWithUser( const SteamNetworkingIdentity &identityRemote ) = 0; + + /// Call this when you're done talking to a user on a specific channel. Once all + /// open channels to a user have been closed, the open session to the user will be + /// closed, and any new data from this user will trigger a SteamP2PSessionRequest_t + /// callback + virtual bool CloseChannelWithUser( const SteamNetworkingIdentity &identityRemote, int nLocalChannel ) = 0; + + /// Returns information about the latest state of a connection, if any, with the given peer. + /// Primarily intended for debugging purposes, but can also be used to get more detailed + /// failure information. (See SendMessageToUser and k_nSteamNetworkingSend_AutoRestartBrokwnSession.) + /// + /// Returns the value of SteamNetConnectionInfo_t::m_eState, or k_ESteamNetworkingConnectionState_None + /// if no connection exists with specified peer. You may pass nullptr for either parameter if + /// you do not need the corresponding details. Note that sessions time out after a while, + /// so if a connection fails, or SendMessageToUser returns SendMessageToUser, you cannot wait + /// indefinitely to obtain the reason for failure. + virtual ESteamNetworkingConnectionState GetSessionConnectionInfo( const SteamNetworkingIdentity &identityRemote, SteamNetConnectionInfo_t *pConnectionInfo, SteamNetworkingQuickConnectionStatus *pQuickStatus ) = 0; +}; +#define STEAMNETWORKINGMESSAGES_VERSION "SteamNetworkingMessages002" + +// +// Callbacks +// + +#pragma pack( push, 1 ) + +/// Posted when a remote host is sending us a message, and we do not already have a session with them +struct SteamNetworkingMessagesSessionRequest_t +{ + enum { k_iCallback = k_iSteamNetworkingMessagesCallbacks + 1 }; + SteamNetworkingIdentity m_identityRemote; // user who wants to talk to us +}; + +/// Posted when we fail to establish a connection, or we detect that communications +/// have been disrupted it an unusual way. There is no notification when a peer proactively +/// closes the session. ("Closed by peer" is not a concept of UDP-style communications, and +/// SteamNetworkingMessages is primarily intended to make porting UDP code easy.) +/// +/// Remember: callbacks are asynchronous. See notes on SendMessageToUser, +/// and k_nSteamNetworkingSend_AutoRestartBrokwnSession in particular. +/// +/// Also, if a session times out due to inactivity, no callbacks will be posted. The only +/// way to detect that this is happening is that querying the session state may return +/// none, connecting, and findingroute again. +struct SteamNetworkingMessagesSessionFailed_t +{ + enum { k_iCallback = k_iSteamNetworkingMessagesCallbacks + 2 }; + + /// Detailed info about the connection. This will include the + SteamNetConnectionInfo_t m_info; +}; + +#pragma pack(pop) + +// +// Global accessor +// + +#if defined( STEAMNETWORKINGSOCKETS_PARTNER ) + + // Standalone lib. Use different symbol name, so that we can dynamically switch between steamclient.dll + // and the standalone lib + STEAMNETWORKINGSOCKETS_INTERFACE ISteamNetworkingMessages *SteamNetworkingMessages_Lib(); + STEAMNETWORKINGSOCKETS_INTERFACE ISteamNetworkingMessages *SteamGameServerNetworkingMessages_Lib(); + inline ISteamNetworkingMessages *SteamNetworkingMessages() { return SteamNetworkingMessages_Lib(); } + inline ISteamNetworkingMessages *SteamGameServerNetworkingMessages() { return SteamGameServerNetworkingMessages_Lib(); } + +#elif defined( STEAMNETWORKINGSOCKETS_OPENSOURCE ) + + // Opensource GameNetworkingSockets + STEAMNETWORKINGSOCKETS_INTERFACE ISteamNetworkingMessages *SteamNetworkingMessages(); + +#else + + // Steamworks SDK + inline ISteamNetworkingMessages *SteamNetworkingMessages(); + STEAM_DEFINE_USER_INTERFACE_ACCESSOR( ISteamNetworkingMessages *, SteamNetworkingMessages, STEAMNETWORKINGMESSAGES_VERSION ); + inline ISteamNetworkingMessages *SteamGameServerNetworkingMessages(); + STEAM_DEFINE_GAMESERVER_INTERFACE_ACCESSOR( ISteamNetworkingMessages *, SteamGameServerNetworkingMessages, STEAMNETWORKINGMESSAGES_VERSION ); +#endif + +#endif // ISTEAMNETWORKINGMESSAGES diff --git a/sdk_includes/isteamnetworkingsockets.h b/sdk_includes/isteamnetworkingsockets.h index 2ff8c902..4204f44b 100644 --- a/sdk_includes/isteamnetworkingsockets.h +++ b/sdk_includes/isteamnetworkingsockets.h @@ -1,16 +1,4 @@ //====== Copyright Valve Corporation, All rights reserved. ==================== -// -// Networking API similar to Berkeley sockets, but for games. -// - connection-oriented API (like TCP, not UDP) -// - but unlike TCP, it's message-oriented, not stream-oriented -// - mix of reliable and unreliable messages -// - fragmentation and reassembly -// - Supports connectivity over plain UDPv4 -// - Also supports SDR ("Steam Datagram Relay") connections, which are -// addressed by SteamID. There is a "P2P" use case and also a "hosted -// dedicated server" use case. -// -//============================================================================= #ifndef ISTEAMNETWORKINGSOCKETS #define ISTEAMNETWORKINGSOCKETS @@ -20,24 +8,33 @@ #include "steamnetworkingtypes.h" -class ISteamNetworkingSocketsCallbacks; struct SteamNetAuthenticationStatus_t; class ISteamNetworkingConnectionCustomSignaling; class ISteamNetworkingCustomSignalingRecvContext; //----------------------------------------------------------------------------- -/// Lower level networking interface that more closely mirrors the standard -/// Berkeley sockets model. Sockets are hard! You should probably only use -/// this interface under the existing circumstances: +/// Lower level networking API. /// -/// - You have an existing socket-based codebase you want to port, or coexist with. -/// - You want to be able to connect based on IP address, rather than (just) Steam ID. -/// - You need low-level control of bandwidth utilization, when to drop packets, etc. +/// - Connection-oriented API (like TCP, not UDP). When sending and receiving +/// messages, a connection handle is used. (For a UDP-style interface, see +/// ISteamNetworkingMessages.) In this TCP-style interface, the "server" will +/// "listen" on a "listen socket." A "client" will "connect" to the server, +/// and the server will "accept" the connection. +/// - But unlike TCP, it's message-oriented, not stream-oriented. +/// - Mix of reliable and unreliable messages +/// - Fragmentation and reassembly +/// - Supports connectivity over plain UDP +/// - Also supports SDR ("Steam Datagram Relay") connections, which are +/// addressed by the identity of the peer. There is a "P2P" use case and +/// a "hosted dedicated server" use case. /// -/// Note that neither of the terms "connection" and "socket" will correspond +/// Note that neither of the terms "connection" nor "socket" necessarily correspond /// one-to-one with an underlying UDP socket. An attempt has been made to /// keep the semantics as similar to the standard socket model when appropriate, /// but some deviations do exist. +/// +/// See also: ISteamNetworkingMessages, the UDP-style interface. This API might be +/// easier to use, especially when porting existing UDP code. class ISteamNetworkingSockets { public: @@ -87,14 +84,13 @@ public: /// setting the options "immediately" after creation. virtual HSteamNetConnection ConnectByIPAddress( const SteamNetworkingIPAddr &address, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) = 0; -#ifdef STEAMNETWORKINGSOCKETS_ENABLE_SDR /// Like CreateListenSocketIP, but clients will connect using ConnectP2P /// - /// nVirtualPort specifies how clients can connect to this socket using + /// nLocalVirtualPort specifies how clients can connect to this socket using /// ConnectP2P. It's very common for applications to only have one listening socket; /// in that case, use zero. If you need to open multiple listen sockets and have clients - /// be able to connect to one or the other, then nVirtualPort should be a small integer (<1000) - /// unique to each listen socket you create. + /// be able to connect to one or the other, then nLocalVirtualPort should be a small + /// integer (<1000) unique to each listen socket you create. /// /// If you use this, you probably want to call ISteamNetworkingUtils::InitRelayNetworkAccess() /// when your app initializes @@ -102,21 +98,16 @@ public: /// If you need to set any initial config options, pass them here. See /// SteamNetworkingConfigValue_t for more about why this is preferable to /// setting the options "immediately" after creation. - virtual HSteamListenSocket CreateListenSocketP2P( int nVirtualPort, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) = 0; + virtual HSteamListenSocket CreateListenSocketP2P( int nLocalVirtualPort, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) = 0; - /// Begin connecting to a server that is identified using a platform-specific identifier. + /// Begin connecting to a peer that is identified using a platform-specific identifier. /// This uses the default rendezvous service, which depends on the platform and library - /// configuration. (E.g. on Steam, it goes through the steam backend.) The traffic is relayed - /// over the Steam Datagram Relay network. - /// - /// If you use this, you probably want to call ISteamNetworkingUtils::InitRelayNetworkAccess() - /// when your app initializes + /// configuration. (E.g. on Steam, it goes through the steam backend.) /// /// If you need to set any initial config options, pass them here. See /// SteamNetworkingConfigValue_t for more about why this is preferable to /// setting the options "immediately" after creation. - virtual HSteamNetConnection ConnectP2P( const SteamNetworkingIdentity &identityRemote, int nVirtualPort, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) = 0; -#endif + virtual HSteamNetConnection ConnectP2P( const SteamNetworkingIdentity &identityRemote, int nRemoteVirtualPort, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) = 0; /// Accept an incoming connection that has been received on a listen socket. /// @@ -465,7 +456,7 @@ public: /// /// Typically this is useful just to confirm that you have a ticket, before you /// call ConnectToHostedDedicatedServer to connect to the server. - virtual int FindRelayAuthTicketForServer( const SteamNetworkingIdentity &identityGameServer, int nVirtualPort, SteamDatagramRelayAuthTicket *pOutParsedTicket ) = 0; + virtual int FindRelayAuthTicketForServer( const SteamNetworkingIdentity &identityGameServer, int nRemoteVirtualPort, SteamDatagramRelayAuthTicket *pOutParsedTicket ) = 0; /// Client call to connect to a server hosted in a Valve data center, on the specified virtual /// port. You must have placed a ticket for this server into the cache, or else this connect attempt will fail! @@ -480,7 +471,7 @@ public: /// If you need to set any initial config options, pass them here. See /// SteamNetworkingConfigValue_t for more about why this is preferable to /// setting the options "immediately" after creation. - virtual HSteamNetConnection ConnectToHostedDedicatedServer( const SteamNetworkingIdentity &identityTarget, int nVirtualPort, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) = 0; + virtual HSteamNetConnection ConnectToHostedDedicatedServer( const SteamNetworkingIdentity &identityTarget, int nRemoteVirtualPort, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) = 0; // // Servers hosted in data centers known to the Valve relay network @@ -536,7 +527,7 @@ public: /// If you need to set any initial config options, pass them here. See /// SteamNetworkingConfigValue_t for more about why this is preferable to /// setting the options "immediately" after creation. - virtual HSteamListenSocket CreateHostedDedicatedServerListenSocket( int nVirtualPort, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) = 0; + virtual HSteamListenSocket CreateHostedDedicatedServerListenSocket( int nLocalVirtualPort, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) = 0; /// Generate an authentication blob that can be used to securely login with /// your backend, using SteamDatagram_ParseHostedServerLogin. (See @@ -569,6 +560,7 @@ public: /// NOTE: The routing blob returned here is not encrypted. Send it to your backend /// and don't share it directly with clients. virtual EResult GetGameCoordinatorServerLogin( SteamDatagramGameCoordinatorServerLogin *pLoginInfo, int *pcbSignedBlob, void *pBlob ) = 0; +#endif // #ifndef STEAMNETWORKINGSOCKETS_ENABLE_SDR // @@ -611,7 +603,7 @@ public: /// If you need to set any initial config options, pass them here. See /// SteamNetworkingConfigValue_t for more about why this is preferable to /// setting the options "immediately" after creation. - virtual HSteamNetConnection ConnectP2PCustomSignaling( ISteamNetworkingConnectionCustomSignaling *pSignaling, const SteamNetworkingIdentity *pPeerIdentity, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) = 0; + virtual HSteamNetConnection ConnectP2PCustomSignaling( ISteamNetworkingConnectionCustomSignaling *pSignaling, const SteamNetworkingIdentity *pPeerIdentity, int nRemoteVirtualPort, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) = 0; /// Called when custom signaling has received a message. When your /// signaling channel receives a message, it should save off whatever @@ -643,7 +635,6 @@ public: /// If you expect to be using relayed connections, then you probably want /// to call ISteamNetworkingUtils::InitRelayNetworkAccess() when your app initializes virtual bool ReceivedP2PCustomSignal( const void *pMsg, int cbMsg, ISteamNetworkingCustomSignalingRecvContext *pContext ) = 0; -#endif // #ifndef STEAMNETWORKINGSOCKETS_ENABLE_SDR // // Certificate provision by the application. On Steam, we normally handle all this automatically @@ -662,94 +653,16 @@ public: /// SteamDatagram_CreateCert. virtual bool SetCertificate( const void *pCertificate, int cbCertificate, SteamNetworkingErrMsg &errMsg ) = 0; - // Invoke all callbacks queued for this interface. - // On Steam, callbacks are dispatched via the ordinary Steamworks callbacks mechanism. - // So if you have code that is also targeting Steam, you should call this at about the - // same time you would call SteamAPI_RunCallbacks and SteamGameServer_RunCallbacks. -#ifdef STEAMNETWORKINGSOCKETS_STANDALONELIB - virtual void RunCallbacks( ISteamNetworkingSocketsCallbacks *pCallbacks ) = 0; -#endif + /// Invoke all callback functions queued for this interface. + /// See k_ESteamNetworkingConfig_Callback_ConnectionStatusChanged, etc + /// + /// You don't need to call this if you are using Steam's callback dispatch + /// mechanism (SteamAPI_RunCallbacks and SteamGameserver_RunCallbacks). + virtual void RunCallbacks() = 0; protected: // ~ISteamNetworkingSockets(); // Silence some warnings }; -#define STEAMNETWORKINGSOCKETS_INTERFACE_VERSION "SteamNetworkingSockets008" - -/// Interface used to send signaling messages for a particular connection. -/// You will need to construct one of these per connection. -/// -/// - For connections initiated locally, you will construct it and pass -/// it to ISteamNetworkingSockets::ConnectP2PCustomSignaling. -/// - For connections initiated remotely and "accepted" locally, you -/// will return it from ISteamNetworkingCustomSignalingRecvContext::OnConnectRequest -class ISteamNetworkingConnectionCustomSignaling -{ -public: - /// Called to send a rendezvous message to the remote peer. This may be called - /// from any thread, at any time, so you need to be thread-safe! Don't take - /// any locks that might hold while calling into SteamNetworkingSockets functions, - /// because this could lead to deadlocks. - /// - /// Note that when initiating a connection, we may not know the identity - /// of the peer, if you did not specify it in ConnectP2PCustomSignaling. - /// - /// Return true if a best-effort attempt was made to deliver the message. - /// If you return false, it is assumed that the situation is fatal; - /// the connection will be closed, and Release() will be called - /// eventually. - /// - /// Signaling objects will not be shared between connections. - /// You can assume that the same value of hConn will be used - /// every time. - virtual bool SendSignal( HSteamNetConnection hConn, const SteamNetConnectionInfo_t &info, const void *pMsg, int cbMsg ) = 0; - - /// Called when the connection no longer needs to send signals. - /// Note that this happens eventually (but not immediately) after - /// the connection is closed. Signals may need to be sent for a brief - /// time after the connection is closed, to clean up the connection. - virtual void Release() = 0; -}; - -/// Interface used when a custom signal is received. -/// See ISteamNetworkingSockets::ReceivedP2PCustomSignal -class ISteamNetworkingCustomSignalingRecvContext -{ -public: - - /// Called when the signal represents a request for a new connection. - /// - /// If you want to ignore the request, just return NULL. In this case, - /// the peer will NOT receive any reply. You should consider ignoring - /// requests rather than actively rejecting them, as a security measure. - /// If you actively reject requests, then this makes it possible to detect - /// if a user is online or not, just by sending them a request. - /// - /// If you wish to send back a rejection, then use - /// ISteamNetworkingSockets::CloseConnection() and then return NULL. - /// We will marshal a properly formatted rejection signal and - /// call SendRejectionSignal() so you can send it to them. - /// - /// If you return a signaling object, the connection is NOT immediately - /// accepted by default. Instead, it stays in the "connecting" state, - /// and the usual callback is posted, and your app can accept the - /// connection using ISteamNetworkingSockets::AcceptConnection. This - /// may be useful so that these sorts of connections can be more similar - /// to your application code as other types of connections accepted on - /// a listen socket. If this is not useful and you want to skip this - /// callback process and immediately accept the connection, call - /// ISteamNetworkingSockets::AcceptConnection before returning the - /// signaling object. - /// - /// After accepting a connection (through either means), the connection - /// will transition into the "finding route" state. - virtual ISteamNetworkingConnectionCustomSignaling *OnConnectRequest( HSteamNetConnection hConn, const SteamNetworkingIdentity &identityPeer ) = 0; - - /// This is called actively communication rejection or failure - /// to the incoming message. If you intend to ignore all incoming requests - /// that you do not wish to accept, then it's not strictly necessary to - /// implement this. - virtual void SendRejectionSignal( const SteamNetworkingIdentity &identityPeer, const void *pMsg, int cbMsg ) = 0; -}; - +#define STEAMNETWORKINGSOCKETS_INTERFACE_VERSION "SteamNetworkingSockets009" // Global accessor. #if defined( STEAMNETWORKINGSOCKETS_PARTNER ) diff --git a/sdk_includes/isteamnetworkingsockets008.h b/sdk_includes/isteamnetworkingsockets008.h new file mode 100644 index 00000000..f98e776a --- /dev/null +++ b/sdk_includes/isteamnetworkingsockets008.h @@ -0,0 +1,720 @@ + +#ifndef ISTEAMNETWORKINGSOCKETS008 +#define ISTEAMNETWORKINGSOCKETS008 + + +class ISteamNetworkingSockets008 +{ +public: + + /// Creates a "server" socket that listens for clients to connect to by + /// calling ConnectByIPAddress, over ordinary UDP (IPv4 or IPv6) + /// + /// You must select a specific local port to listen on and set it + /// the port field of the local address. + /// + /// Usually you will set the IP portion of the address to zero (SteamNetworkingIPAddr::Clear()). + /// This means that you will not bind to any particular local interface (i.e. the same + /// as INADDR_ANY in plain socket code). Furthermore, if possible the socket will be bound + /// in "dual stack" mode, which means that it can accept both IPv4 and IPv6 client connections. + /// If you really do wish to bind a particular interface, then set the local address to the + /// appropriate IPv4 or IPv6 IP. + /// + /// If you need to set any initial config options, pass them here. See + /// SteamNetworkingConfigValue_t for more about why this is preferable to + /// setting the options "immediately" after creation. + /// + /// When a client attempts to connect, a SteamNetConnectionStatusChangedCallback_t + /// will be posted. The connection will be in the connecting state. + virtual HSteamListenSocket CreateListenSocketIP( const SteamNetworkingIPAddr &localAddress, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) = 0; + + /// Creates a connection and begins talking to a "server" over UDP at the + /// given IPv4 or IPv6 address. The remote host must be listening with a + /// matching call to CreateListenSocketIP on the specified port. + /// + /// A SteamNetConnectionStatusChangedCallback_t callback will be triggered when we start + /// connecting, and then another one on either timeout or successful connection. + /// + /// If the server does not have any identity configured, then their network address + /// will be the only identity in use. Or, the network host may provide a platform-specific + /// identity with or without a valid certificate to authenticate that identity. (These + /// details will be contained in the SteamNetConnectionStatusChangedCallback_t.) It's + /// up to your application to decide whether to allow the connection. + /// + /// By default, all connections will get basic encryption sufficient to prevent + /// casual eavesdropping. But note that without certificates (or a shared secret + /// distributed through some other out-of-band mechanism), you don't have any + /// way of knowing who is actually on the other end, and thus are vulnerable to + /// man-in-the-middle attacks. + /// + /// If you need to set any initial config options, pass them here. See + /// SteamNetworkingConfigValue_t for more about why this is preferable to + /// setting the options "immediately" after creation. + virtual HSteamNetConnection ConnectByIPAddress( const SteamNetworkingIPAddr &address, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) = 0; + +#ifdef STEAMNETWORKINGSOCKETS_ENABLE_SDR + /// Like CreateListenSocketIP, but clients will connect using ConnectP2P + /// + /// nVirtualPort specifies how clients can connect to this socket using + /// ConnectP2P. It's very common for applications to only have one listening socket; + /// in that case, use zero. If you need to open multiple listen sockets and have clients + /// be able to connect to one or the other, then nVirtualPort should be a small integer (<1000) + /// unique to each listen socket you create. + /// + /// If you use this, you probably want to call ISteamNetworkingUtils::InitRelayNetworkAccess() + /// when your app initializes + /// + /// If you need to set any initial config options, pass them here. See + /// SteamNetworkingConfigValue_t for more about why this is preferable to + /// setting the options "immediately" after creation. + virtual HSteamListenSocket CreateListenSocketP2P( int nVirtualPort, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) = 0; + + /// Begin connecting to a server that is identified using a platform-specific identifier. + /// This uses the default rendezvous service, which depends on the platform and library + /// configuration. (E.g. on Steam, it goes through the steam backend.) The traffic is relayed + /// over the Steam Datagram Relay network. + /// + /// If you use this, you probably want to call ISteamNetworkingUtils::InitRelayNetworkAccess() + /// when your app initializes + /// + /// If you need to set any initial config options, pass them here. See + /// SteamNetworkingConfigValue_t for more about why this is preferable to + /// setting the options "immediately" after creation. + virtual HSteamNetConnection ConnectP2P( const SteamNetworkingIdentity &identityRemote, int nVirtualPort, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) = 0; +#endif + + /// Accept an incoming connection that has been received on a listen socket. + /// + /// When a connection attempt is received (perhaps after a few basic handshake + /// packets have been exchanged to prevent trivial spoofing), a connection interface + /// object is created in the k_ESteamNetworkingConnectionState_Connecting state + /// and a SteamNetConnectionStatusChangedCallback_t is posted. At this point, your + /// application MUST either accept or close the connection. (It may not ignore it.) + /// Accepting the connection will transition it either into the connected state, + /// or the finding route state, depending on the connection type. + /// + /// You should take action within a second or two, because accepting the connection is + /// what actually sends the reply notifying the client that they are connected. If you + /// delay taking action, from the client's perspective it is the same as the network + /// being unresponsive, and the client may timeout the connection attempt. In other + /// words, the client cannot distinguish between a delay caused by network problems + /// and a delay caused by the application. + /// + /// This means that if your application goes for more than a few seconds without + /// processing callbacks (for example, while loading a map), then there is a chance + /// that a client may attempt to connect in that interval and fail due to timeout. + /// + /// If the application does not respond to the connection attempt in a timely manner, + /// and we stop receiving communication from the client, the connection attempt will + /// be timed out locally, transitioning the connection to the + /// k_ESteamNetworkingConnectionState_ProblemDetectedLocally state. The client may also + /// close the connection before it is accepted, and a transition to the + /// k_ESteamNetworkingConnectionState_ClosedByPeer is also possible depending the exact + /// sequence of events. + /// + /// Returns k_EResultInvalidParam if the handle is invalid. + /// Returns k_EResultInvalidState if the connection is not in the appropriate state. + /// (Remember that the connection state could change in between the time that the + /// notification being posted to the queue and when it is received by the application.) + /// + /// A note about connection configuration options. If you need to set any configuration + /// options that are common to all connections accepted through a particular listen + /// socket, consider setting the options on the listen socket, since such options are + /// inherited automatically. If you really do need to set options that are connection + /// specific, it is safe to set them on the connection before accepting the connection. + virtual EResult AcceptConnection( HSteamNetConnection hConn ) = 0; + + /// Disconnects from the remote host and invalidates the connection handle. + /// Any unread data on the connection is discarded. + /// + /// nReason is an application defined code that will be received on the other + /// end and recorded (when possible) in backend analytics. The value should + /// come from a restricted range. (See ESteamNetConnectionEnd.) If you don't need + /// to communicate any information to the remote host, and do not want analytics to + /// be able to distinguish "normal" connection terminations from "exceptional" ones, + /// You may pass zero, in which case the generic value of + /// k_ESteamNetConnectionEnd_App_Generic will be used. + /// + /// pszDebug is an optional human-readable diagnostic string that will be received + /// by the remote host and recorded (when possible) in backend analytics. + /// + /// If you wish to put the socket into a "linger" state, where an attempt is made to + /// flush any remaining sent data, use bEnableLinger=true. Otherwise reliable data + /// is not flushed. + /// + /// If the connection has already ended and you are just freeing up the + /// connection interface, the reason code, debug string, and linger flag are + /// ignored. + virtual bool CloseConnection( HSteamNetConnection hPeer, int nReason, const char *pszDebug, bool bEnableLinger ) = 0; + + /// Destroy a listen socket. All the connections that were accepting on the listen + /// socket are closed ungracefully. + virtual bool CloseListenSocket( HSteamListenSocket hSocket ) = 0; + + /// Set connection user data. the data is returned in the following places + /// - You can query it using GetConnectionUserData. + /// - The SteamNetworkingmessage_t structure. + /// - The SteamNetConnectionInfo_t structure. (Which is a member of SteamNetConnectionStatusChangedCallback_t.) + /// + /// Returns false if the handle is invalid. + virtual bool SetConnectionUserData( HSteamNetConnection hPeer, int64 nUserData ) = 0; + + /// Fetch connection user data. Returns -1 if handle is invalid + /// or if you haven't set any userdata on the connection. + virtual int64 GetConnectionUserData( HSteamNetConnection hPeer ) = 0; + + /// Set a name for the connection, used mostly for debugging + virtual void SetConnectionName( HSteamNetConnection hPeer, const char *pszName ) = 0; + + /// Fetch connection name. Returns false if handle is invalid + virtual bool GetConnectionName( HSteamNetConnection hPeer, char *pszName, int nMaxLen ) = 0; + + /// Send a message to the remote host on the specified connection. + /// + /// nSendFlags determines the delivery guarantees that will be provided, + /// when data should be buffered, etc. E.g. k_nSteamNetworkingSend_Unreliable + /// + /// Note that the semantics we use for messages are not precisely + /// the same as the semantics of a standard "stream" socket. + /// (SOCK_STREAM) For an ordinary stream socket, the boundaries + /// between chunks are not considered relevant, and the sizes of + /// the chunks of data written will not necessarily match up to + /// the sizes of the chunks that are returned by the reads on + /// the other end. The remote host might read a partial chunk, + /// or chunks might be coalesced. For the message semantics + /// used here, however, the sizes WILL match. Each send call + /// will match a successful read call on the remote host + /// one-for-one. If you are porting existing stream-oriented + /// code to the semantics of reliable messages, your code should + /// work the same, since reliable message semantics are more + /// strict than stream semantics. The only caveat is related to + /// performance: there is per-message overhead to retain the + /// message sizes, and so if your code sends many small chunks + /// of data, performance will suffer. Any code based on stream + /// sockets that does not write excessively small chunks will + /// work without any changes. + /// + /// The pOutMessageNumber is an optional pointer to receive the + /// message number assigned to the message, if sending was successful. + /// + /// Returns: + /// - k_EResultInvalidParam: invalid connection handle, or the individual message is too big. + /// (See k_cbMaxSteamNetworkingSocketsMessageSizeSend) + /// - k_EResultInvalidState: connection is in an invalid state + /// - k_EResultNoConnection: connection has ended + /// - k_EResultIgnored: You used k_nSteamNetworkingSend_NoDelay, and the message was dropped because + /// we were not ready to send it. + /// - k_EResultLimitExceeded: there was already too much data queued to be sent. + /// (See k_ESteamNetworkingConfig_SendBufferSize) + virtual EResult SendMessageToConnection( HSteamNetConnection hConn, const void *pData, uint32 cbData, int nSendFlags, int64 *pOutMessageNumber ) = 0; + + /// Send one or more messages without copying the message payload. + /// This is the most efficient way to send messages. To use this + /// function, you must first allocate a message object using + /// ISteamNetworkingUtils::AllocateMessage. (Do not declare one + /// on the stack or allocate your own.) + /// + /// You should fill in the message payload. You can either let + /// it allocate the buffer for you and then fill in the payload, + /// or if you already have a buffer allocated, you can just point + /// m_pData at your buffer and set the callback to the appropriate function + /// to free it. Note that if you use your own buffer, it MUST remain valid + /// until the callback is executed. And also note that your callback can be + /// invoked at ant time from any thread (perhaps even before SendMessages + /// returns!), so it MUST be fast and threadsafe. + /// + /// You MUST also fill in: + /// - m_conn - the handle of the connection to send the message to + /// - m_nFlags - bitmask of k_nSteamNetworkingSend_xxx flags. + /// + /// All other fields are currently reserved and should not be modified. + /// + /// The library will take ownership of the message structures. They may + /// be modified or become invalid at any time, so you must not read them + /// after passing them to this function. + /// + /// pOutMessageNumberOrResult is an optional array that will receive, + /// for each message, the message number that was assigned to the message + /// if sending was successful. If sending failed, then a negative EResult + /// value is placed into the array. For example, the array will hold + /// -k_EResultInvalidState if the connection was in an invalid state. + /// See ISteamNetworkingSockets::SendMessageToConnection for possible + /// failure codes. + virtual void SendMessages( int nMessages, SteamNetworkingMessage_t *const *pMessages, int64 *pOutMessageNumberOrResult ) = 0; + + /// Flush any messages waiting on the Nagle timer and send them + /// at the next transmission opportunity (often that means right now). + /// + /// If Nagle is enabled (it's on by default) then when calling + /// SendMessageToConnection the message will be buffered, up to the Nagle time + /// before being sent, to merge small messages into the same packet. + /// (See k_ESteamNetworkingConfig_NagleTime) + /// + /// Returns: + /// k_EResultInvalidParam: invalid connection handle + /// k_EResultInvalidState: connection is in an invalid state + /// k_EResultNoConnection: connection has ended + /// k_EResultIgnored: We weren't (yet) connected, so this operation has no effect. + virtual EResult FlushMessagesOnConnection( HSteamNetConnection hConn ) = 0; + + /// Fetch the next available message(s) from the connection, if any. + /// Returns the number of messages returned into your array, up to nMaxMessages. + /// If the connection handle is invalid, -1 is returned. + /// + /// The order of the messages returned in the array is relevant. + /// Reliable messages will be received in the order they were sent (and with the + /// same sizes --- see SendMessageToConnection for on this subtle difference from a stream socket). + /// + /// Unreliable messages may be dropped, or delivered out of order with respect to + /// each other or with respect to reliable messages. The same unreliable message + /// may be received multiple times. + /// + /// If any messages are returned, you MUST call SteamNetworkingMessage_t::Release() on each + /// of them free up resources after you are done. It is safe to keep the object alive for + /// a little while (put it into some queue, etc), and you may call Release() from any thread. + virtual int ReceiveMessagesOnConnection( HSteamNetConnection hConn, SteamNetworkingMessage_t **ppOutMessages, int nMaxMessages ) = 0; + + /// Returns basic information about the high-level state of the connection. + virtual bool GetConnectionInfo( HSteamNetConnection hConn, SteamNetConnectionInfo_t *pInfo ) = 0; + + /// Returns a small set of information about the real-time state of the connection + /// Returns false if the connection handle is invalid, or the connection has ended. + virtual bool GetQuickConnectionStatus( HSteamNetConnection hConn, SteamNetworkingQuickConnectionStatus *pStats ) = 0; + + /// Returns detailed connection stats in text format. Useful + /// for dumping to a log, etc. + /// + /// Returns: + /// -1 failure (bad connection handle) + /// 0 OK, your buffer was filled in and '\0'-terminated + /// >0 Your buffer was either nullptr, or it was too small and the text got truncated. + /// Try again with a buffer of at least N bytes. + virtual int GetDetailedConnectionStatus( HSteamNetConnection hConn, char *pszBuf, int cbBuf ) = 0; + + /// Returns local IP and port that a listen socket created using CreateListenSocketIP is bound to. + /// + /// An IPv6 address of ::0 means "any IPv4 or IPv6" + /// An IPv6 address of ::ffff:0000:0000 means "any IPv4" + virtual bool GetListenSocketAddress( HSteamListenSocket hSocket, SteamNetworkingIPAddr *address ) = 0; + + /// Create a pair of connections that are talking to each other, e.g. a loopback connection. + /// This is very useful for testing, or so that your client/server code can work the same + /// even when you are running a local "server". + /// + /// The two connections will immediately be placed into the connected state, and no callbacks + /// will be posted immediately. After this, if you close either connection, the other connection + /// will receive a callback, exactly as if they were communicating over the network. You must + /// close *both* sides in order to fully clean up the resources! + /// + /// By default, internal buffers are used, completely bypassing the network, the chopping up of + /// messages into packets, encryption, copying the payload, etc. This means that loopback + /// packets, by default, will not simulate lag or loss. Passing true for bUseNetworkLoopback will + /// cause the socket pair to send packets through the local network loopback device (127.0.0.1) + /// on ephemeral ports. Fake lag and loss are supported in this case, and CPU time is expended + /// to encrypt and decrypt. + /// + /// If you wish to assign a specific identity to either connection, you may pass a particular + /// identity. Otherwise, if you pass nullptr, the respective connection will assume a generic + /// "localhost" identity. If you use real network loopback, this might be translated to the + /// actual bound loopback port. Otherwise, the port will be zero. + virtual bool CreateSocketPair( HSteamNetConnection *pOutConnection1, HSteamNetConnection *pOutConnection2, bool bUseNetworkLoopback, const SteamNetworkingIdentity *pIdentity1, const SteamNetworkingIdentity *pIdentity2 ) = 0; + + /// Get the identity assigned to this interface. + /// E.g. on Steam, this is the user's SteamID, or for the gameserver interface, the SteamID assigned + /// to the gameserver. Returns false and sets the result to an invalid identity if we don't know + /// our identity yet. (E.g. GameServer has not logged in. On Steam, the user will know their SteamID + /// even if they are not signed into Steam.) + virtual bool GetIdentity( SteamNetworkingIdentity *pIdentity ) = 0; + + /// Indicate our desire to be ready participate in authenticated communications. + /// If we are currently not ready, then steps will be taken to obtain the necessary + /// certificates. (This includes a certificate for us, as well as any CA certificates + /// needed to authenticate peers.) + /// + /// You can call this at program init time if you know that you are going to + /// be making authenticated connections, so that we will be ready immediately when + /// those connections are attempted. (Note that essentially all connections require + /// authentication, with the exception of ordinary UDP connections with authentication + /// disabled using k_ESteamNetworkingConfig_IP_AllowWithoutAuth.) If you don't call + /// this function, we will wait until a feature is utilized that that necessitates + /// these resources. + /// + /// You can also call this function to force a retry, if failure has occurred. + /// Once we make an attempt and fail, we will not automatically retry. + /// In this respect, the behavior of the system after trying and failing is the same + /// as before the first attempt: attempting authenticated communication or calling + /// this function will call the system to attempt to acquire the necessary resources. + /// + /// You can use GetAuthenticationStatus or listen for SteamNetAuthenticationStatus_t + /// to monitor the status. + /// + /// Returns the current value that would be returned from GetAuthenticationStatus. + virtual ESteamNetworkingAvailability InitAuthentication() = 0; + + /// Query our readiness to participate in authenticated communications. A + /// SteamNetAuthenticationStatus_t callback is posted any time this status changes, + /// but you can use this function to query it at any time. + /// + /// The value of SteamNetAuthenticationStatus_t::m_eAvail is returned. If you only + /// want this high level status, you can pass NULL for pDetails. If you want further + /// details, pass non-NULL to receive them. + virtual ESteamNetworkingAvailability GetAuthenticationStatus( SteamNetAuthenticationStatus_t *pDetails ) = 0; + + // + // Poll groups. A poll group is a set of connections that can be polled efficiently. + // (In our API, to "poll" a connection means to retrieve all pending messages. We + // actually don't have an API to "poll" the connection *state*, like BSD sockets.) + // + + /// Create a new poll group. + /// + /// You should destroy the poll group when you are done using DestroyPollGroup + virtual HSteamNetPollGroup CreatePollGroup() = 0; + + /// Destroy a poll group created with CreatePollGroup(). + /// + /// If there are any connections in the poll group, they are removed from the group, + /// and left in a state where they are not part of any poll group. + /// Returns false if passed an invalid poll group handle. + virtual bool DestroyPollGroup( HSteamNetPollGroup hPollGroup ) = 0; + + /// Assign a connection to a poll group. Note that a connection may only belong to a + /// single poll group. Adding a connection to a poll group implicitly removes it from + /// any other poll group it is in. + /// + /// You can pass k_HSteamNetPollGroup_Invalid to remove a connection from its current + /// poll group without adding it to a new poll group. + /// + /// If there are received messages currently pending on the connection, an attempt + /// is made to add them to the queue of messages for the poll group in approximately + /// the order that would have applied if the connection was already part of the poll + /// group at the time that the messages were received. + /// + /// Returns false if the connection handle is invalid, or if the poll group handle + /// is invalid (and not k_HSteamNetPollGroup_Invalid). + virtual bool SetConnectionPollGroup( HSteamNetConnection hConn, HSteamNetPollGroup hPollGroup ) = 0; + + /// Same as ReceiveMessagesOnConnection, but will return the next messages available + /// on any connection in the poll group. Examine SteamNetworkingMessage_t::m_conn + /// to know which connection. (SteamNetworkingMessage_t::m_nConnUserData might also + /// be useful.) + /// + /// Delivery order of messages among different connections will usually match the + /// order that the last packet was received which completed the message. But this + /// is not a strong guarantee, especially for packets received right as a connection + /// is being assigned to poll group. + /// + /// Delivery order of messages on the same connection is well defined and the + /// same guarantees are present as mentioned in ReceiveMessagesOnConnection. + /// (But the messages are not grouped by connection, so they will not necessarily + /// appear consecutively in the list; they may be interleaved with messages for + /// other connections.) + virtual int ReceiveMessagesOnPollGroup( HSteamNetPollGroup hPollGroup, SteamNetworkingMessage_t **ppOutMessages, int nMaxMessages ) = 0; + +#ifdef STEAMNETWORKINGSOCKETS_ENABLE_SDR + + // + // Clients connecting to dedicated servers hosted in a data center, + // using central-authority-granted tickets. + // + + /// Call this when you receive a ticket from your backend / matchmaking system. Puts the + /// ticket into a persistent cache, and optionally returns the parsed ticket. + /// + /// See stamdatagram_ticketgen.h for more details. + virtual bool ReceivedRelayAuthTicket( const void *pvTicket, int cbTicket, SteamDatagramRelayAuthTicket *pOutParsedTicket ) = 0; + + /// Search cache for a ticket to talk to the server on the specified virtual port. + /// If found, returns the number of seconds until the ticket expires, and optionally + /// the complete cracked ticket. Returns 0 if we don't have a ticket. + /// + /// Typically this is useful just to confirm that you have a ticket, before you + /// call ConnectToHostedDedicatedServer to connect to the server. + virtual int FindRelayAuthTicketForServer( const SteamNetworkingIdentity &identityGameServer, int nVirtualPort, SteamDatagramRelayAuthTicket *pOutParsedTicket ) = 0; + + /// Client call to connect to a server hosted in a Valve data center, on the specified virtual + /// port. You must have placed a ticket for this server into the cache, or else this connect attempt will fail! + /// + /// You may wonder why tickets are stored in a cache, instead of simply being passed as an argument + /// here. The reason is to make reconnection to a gameserver robust, even if the client computer loses + /// connection to Steam or the central backend, or the app is restarted or crashes, etc. + /// + /// If you use this, you probably want to call ISteamNetworkingUtils::InitRelayNetworkAccess() + /// when your app initializes + /// + /// If you need to set any initial config options, pass them here. See + /// SteamNetworkingConfigValue_t for more about why this is preferable to + /// setting the options "immediately" after creation. + virtual HSteamNetConnection ConnectToHostedDedicatedServer( const SteamNetworkingIdentity &identityTarget, int nVirtualPort, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) = 0; + + // + // Servers hosted in data centers known to the Valve relay network + // + + /// Returns the value of the SDR_LISTEN_PORT environment variable. This + /// is the UDP server your server will be listening on. This will + /// configured automatically for you in production environments. + /// + /// In development, you'll need to set it yourself. See + /// https://partner.steamgames.com/doc/api/ISteamNetworkingSockets + /// for more information on how to configure dev environments. + virtual uint16 GetHostedDedicatedServerPort() = 0; + + /// Returns 0 if SDR_LISTEN_PORT is not set. Otherwise, returns the data center the server + /// is running in. This will be k_SteamDatagramPOPID_dev in non-production environment. + virtual SteamNetworkingPOPID GetHostedDedicatedServerPOPID() = 0; + + /// Return info about the hosted server. This contains the PoPID of the server, + /// and opaque routing information that can be used by the relays to send traffic + /// to your server. + /// + /// You will need to send this information to your backend, and put it in tickets, + /// so that the relays will know how to forward traffic from + /// clients to your server. See SteamDatagramRelayAuthTicket for more info. + /// + /// Also, note that the routing information is contained in SteamDatagramGameCoordinatorServerLogin, + /// so if possible, it's preferred to use GetGameCoordinatorServerLogin to send this info + /// to your game coordinator service, and also login securely at the same time. + /// + /// On a successful exit, k_EResultOK is returned + /// + /// Unsuccessful exit: + /// - Something other than k_EResultOK is returned. + /// - k_EResultInvalidState: We are not configured to listen for SDR (SDR_LISTEN_SOCKET + /// is not set.) + /// - k_EResultPending: we do not (yet) have the authentication information needed. + /// (See GetAuthenticationStatus.) If you use environment variables to pre-fetch + /// the network config, this data should always be available immediately. + /// - A non-localized diagnostic debug message will be placed in m_data that describes + /// the cause of the failure. + /// + /// NOTE: The returned blob is not encrypted. Send it to your backend, but don't + /// directly share it with clients. + virtual EResult GetHostedDedicatedServerAddress( SteamDatagramHostedAddress *pRouting ) = 0; + + /// Create a listen socket on the specified virtual port. The physical UDP port to use + /// will be determined by the SDR_LISTEN_PORT environment variable. If a UDP port is not + /// configured, this call will fail. + /// + /// Note that this call MUST be made through the SteamGameServerNetworkingSockets() interface + /// + /// If you need to set any initial config options, pass them here. See + /// SteamNetworkingConfigValue_t for more about why this is preferable to + /// setting the options "immediately" after creation. + virtual HSteamListenSocket CreateHostedDedicatedServerListenSocket( int nVirtualPort, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) = 0; + + /// Generate an authentication blob that can be used to securely login with + /// your backend, using SteamDatagram_ParseHostedServerLogin. (See + /// steamdatagram_gamecoordinator.h) + /// + /// Before calling the function: + /// - Populate the app data in pLoginInfo (m_cbAppData and m_appData). You can leave + /// all other fields uninitialized. + /// - *pcbSignedBlob contains the size of the buffer at pBlob. (It should be + /// at least k_cbMaxSteamDatagramGameCoordinatorServerLoginSerialized.) + /// + /// On a successful exit: + /// - k_EResultOK is returned + /// - All of the remaining fields of pLoginInfo will be filled out. + /// - *pcbSignedBlob contains the size of the serialized blob that has been + /// placed into pBlob. + /// + /// Unsuccessful exit: + /// - Something other than k_EResultOK is returned. + /// - k_EResultNotLoggedOn: you are not logged in (yet) + /// - See GetHostedDedicatedServerAddress for more potential failure return values. + /// - A non-localized diagnostic debug message will be placed in pBlob that describes + /// the cause of the failure. + /// + /// This works by signing the contents of the SteamDatagramGameCoordinatorServerLogin + /// with the cert that is issued to this server. In dev environments, it's OK if you do + /// not have a cert. (You will need to enable insecure dev login in SteamDatagram_ParseHostedServerLogin.) + /// Otherwise, you will need a signed cert. + /// + /// NOTE: The routing blob returned here is not encrypted. Send it to your backend + /// and don't share it directly with clients. + virtual EResult GetGameCoordinatorServerLogin( SteamDatagramGameCoordinatorServerLogin *pLoginInfo, int *pcbSignedBlob, void *pBlob ) = 0; + + + // + // Relayed connections using custom signaling protocol + // + // This is used if you have your own method of sending out-of-band + // signaling / rendezvous messages through a mutually trusted channel. + // + + /// Create a P2P "client" connection that does signaling over a custom + /// rendezvous/signaling channel. + /// + /// pSignaling points to a new object that you create just for this connection. + /// It must stay valid until Release() is called. Once you pass the + /// object to this function, it assumes ownership. Release() will be called + /// from within the function call if the call fails. Furthermore, until Release() + /// is called, you should be prepared for methods to be invoked on your + /// object from any thread! You need to make sure your object is threadsafe! + /// Furthermore, you should make sure that dispatching the methods is done + /// as quickly as possible. + /// + /// This function will immediately construct a connection in the "connecting" + /// state. Soon after (perhaps before this function returns, perhaps in another thread), + /// the connection will begin sending signaling messages by calling + /// ISteamNetworkingConnectionCustomSignaling::SendSignal. + /// + /// When the remote peer accepts the connection (See + /// ISteamNetworkingCustomSignalingRecvContext::OnConnectRequest), + /// it will begin sending signaling messages. When these messages are received, + /// you can pass them to the connection using ReceivedP2PCustomSignal. + /// + /// If you know the identity of the peer that you expect to be on the other end, + /// you can pass their identity to improve debug output or just detect bugs. + /// If you don't know their identity yet, you can pass NULL, and their + /// identity will be established in the connection handshake. + /// + /// If you use this, you probably want to call ISteamNetworkingUtils::InitRelayNetworkAccess() + /// when your app initializes + /// + /// If you need to set any initial config options, pass them here. See + /// SteamNetworkingConfigValue_t for more about why this is preferable to + /// setting the options "immediately" after creation. + virtual HSteamNetConnection ConnectP2PCustomSignaling( ISteamNetworkingConnectionCustomSignaling *pSignaling, const SteamNetworkingIdentity *pPeerIdentity, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) = 0; + + /// Called when custom signaling has received a message. When your + /// signaling channel receives a message, it should save off whatever + /// routing information was in the envelope into the context object, + /// and then pass the payload to this function. + /// + /// A few different things can happen next, depending on the message: + /// + /// - If the signal is associated with existing connection, it is dealt + /// with immediately. If any replies need to be sent, they will be + /// dispatched using the ISteamNetworkingConnectionCustomSignaling + /// associated with the connection. + /// - If the message represents a connection request (and the request + /// is not redundant for an existing connection), a new connection + /// will be created, and ReceivedConnectRequest will be called on your + /// context object to determine how to proceed. + /// - Otherwise, the message is for a connection that does not + /// exist (anymore). In this case, we *may* call SendRejectionReply + /// on your context object. + /// + /// In any case, we will not save off pContext or access it after this + /// function returns. + /// + /// Returns true if the message was parsed and dispatched without anything + /// unusual or suspicious happening. Returns false if there was some problem + /// with the message that prevented ordinary handling. (Debug output will + /// usually have more information.) + /// + /// If you expect to be using relayed connections, then you probably want + /// to call ISteamNetworkingUtils::InitRelayNetworkAccess() when your app initializes + virtual bool ReceivedP2PCustomSignal( const void *pMsg, int cbMsg, ISteamNetworkingCustomSignalingRecvContext *pContext ) = 0; +#endif // #ifndef STEAMNETWORKINGSOCKETS_ENABLE_SDR + +// +// Certificate provision by the application. On Steam, we normally handle all this automatically +// and you will not need to use these advanced functions. +// + + /// Get blob that describes a certificate request. You can send this to your game coordinator. + /// Upon entry, *pcbBlob should contain the size of the buffer. On successful exit, it will + /// return the number of bytes that were populated. You can pass pBlob=NULL to query for the required + /// size. (256 bytes is a very conservative estimate.) + /// + /// Pass this blob to your game coordinator and call SteamDatagram_CreateCert. + virtual bool GetCertificateRequest( int *pcbBlob, void *pBlob, SteamNetworkingErrMsg &errMsg ) = 0; + + /// Set the certificate. The certificate blob should be the output of + /// SteamDatagram_CreateCert. + virtual bool SetCertificate( const void *pCertificate, int cbCertificate, SteamNetworkingErrMsg &errMsg ) = 0; + + // Invoke all callbacks queued for this interface. + // On Steam, callbacks are dispatched via the ordinary Steamworks callbacks mechanism. + // So if you have code that is also targeting Steam, you should call this at about the + // same time you would call SteamAPI_RunCallbacks and SteamGameServer_RunCallbacks. +#ifdef STEAMNETWORKINGSOCKETS_STANDALONELIB + virtual void RunCallbacks( ISteamNetworkingSocketsCallbacks *pCallbacks ) = 0; +#endif +protected: +// ~ISteamNetworkingSockets(); // Silence some warnings +}; + + +/// Interface used to send signaling messages for a particular connection. +/// You will need to construct one of these per connection. +/// +/// - For connections initiated locally, you will construct it and pass +/// it to ISteamNetworkingSockets::ConnectP2PCustomSignaling. +/// - For connections initiated remotely and "accepted" locally, you +/// will return it from ISteamNetworkingCustomSignalingRecvContext::OnConnectRequest +class ISteamNetworkingConnectionCustomSignaling +{ +public: + /// Called to send a rendezvous message to the remote peer. This may be called + /// from any thread, at any time, so you need to be thread-safe! Don't take + /// any locks that might hold while calling into SteamNetworkingSockets functions, + /// because this could lead to deadlocks. + /// + /// Note that when initiating a connection, we may not know the identity + /// of the peer, if you did not specify it in ConnectP2PCustomSignaling. + /// + /// Return true if a best-effort attempt was made to deliver the message. + /// If you return false, it is assumed that the situation is fatal; + /// the connection will be closed, and Release() will be called + /// eventually. + /// + /// Signaling objects will not be shared between connections. + /// You can assume that the same value of hConn will be used + /// every time. + virtual bool SendSignal( HSteamNetConnection hConn, const SteamNetConnectionInfo_t &info, const void *pMsg, int cbMsg ) = 0; + + /// Called when the connection no longer needs to send signals. + /// Note that this happens eventually (but not immediately) after + /// the connection is closed. Signals may need to be sent for a brief + /// time after the connection is closed, to clean up the connection. + virtual void Release() = 0; +}; + +/// Interface used when a custom signal is received. +/// See ISteamNetworkingSockets::ReceivedP2PCustomSignal +class ISteamNetworkingCustomSignalingRecvContext +{ +public: + + /// Called when the signal represents a request for a new connection. + /// + /// If you want to ignore the request, just return NULL. In this case, + /// the peer will NOT receive any reply. You should consider ignoring + /// requests rather than actively rejecting them, as a security measure. + /// If you actively reject requests, then this makes it possible to detect + /// if a user is online or not, just by sending them a request. + /// + /// If you wish to send back a rejection, then use + /// ISteamNetworkingSockets::CloseConnection() and then return NULL. + /// We will marshal a properly formatted rejection signal and + /// call SendRejectionSignal() so you can send it to them. + /// + /// If you return a signaling object, the connection is NOT immediately + /// accepted by default. Instead, it stays in the "connecting" state, + /// and the usual callback is posted, and your app can accept the + /// connection using ISteamNetworkingSockets::AcceptConnection. This + /// may be useful so that these sorts of connections can be more similar + /// to your application code as other types of connections accepted on + /// a listen socket. If this is not useful and you want to skip this + /// callback process and immediately accept the connection, call + /// ISteamNetworkingSockets::AcceptConnection before returning the + /// signaling object. + /// + /// After accepting a connection (through either means), the connection + /// will transition into the "finding route" state. + virtual ISteamNetworkingConnectionCustomSignaling *OnConnectRequest( HSteamNetConnection hConn, const SteamNetworkingIdentity &identityPeer ) = 0; + + /// This is called actively communication rejection or failure + /// to the incoming message. If you intend to ignore all incoming requests + /// that you do not wish to accept, then it's not strictly necessary to + /// implement this. + virtual void SendRejectionSignal( const SteamNetworkingIdentity &identityPeer, const void *pMsg, int cbMsg ) = 0; +}; + + + +#endif // ISTEAMNETWORKINGSOCKETS008 diff --git a/sdk_includes/isteamnetworkingutils.h b/sdk_includes/isteamnetworkingutils.h index 6963dca3..f2a18c92 100644 --- a/sdk_includes/isteamnetworkingutils.h +++ b/sdk_includes/isteamnetworkingutils.h @@ -254,10 +254,23 @@ public: bool SetGlobalConfigValueInt32( ESteamNetworkingConfigValue eValue, int32 val ); bool SetGlobalConfigValueFloat( ESteamNetworkingConfigValue eValue, float val ); bool SetGlobalConfigValueString( ESteamNetworkingConfigValue eValue, const char *val ); + bool SetGlobalConfigValuePtr( ESteamNetworkingConfigValue eValue, void *val ); bool SetConnectionConfigValueInt32( HSteamNetConnection hConn, ESteamNetworkingConfigValue eValue, int32 val ); bool SetConnectionConfigValueFloat( HSteamNetConnection hConn, ESteamNetworkingConfigValue eValue, float val ); bool SetConnectionConfigValueString( HSteamNetConnection hConn, ESteamNetworkingConfigValue eValue, const char *val ); + // + // Set global callbacks. If you do not want to use Steam's callback dispatch mechanism and you + // want to use the same callback on all (or most) listen sockets and connections, then + // simply install these callbacks first thing, and you are good to go. + // See ISteamNetworkingSockets::RunCallbacks + // + bool SetGlobalCallback_SteamNetConnectionStatusChanged( FnSteamNetConnectionStatusChanged fnCallback ); + bool SetGlobalCallback_SteamNetAuthenticationStatusChanged( FnSteamNetAuthenticationStatusChanged fnCallback ); + bool SetGlobalCallback_SteamRelayNetworkStatusChanged( FnSteamRelayNetworkStatusChanged fnCallback ); + bool SetGlobalCallback_MessagesSessionRequest( FnSteamNetworkingMessagesSessionRequest fnCallback ); + bool SetGlobalCallback_MessagesSessionFailed( FnSteamNetworkingMessagesSessionFailed fnCallback ); + /// Set a configuration value. /// - eValue: which value is being set /// - eScope: Onto what type of object are you applying the setting? @@ -266,7 +279,7 @@ public: /// - pArg: Value to set it to. You can pass NULL to remove a non-global setting at this scope, /// causing the value for that object to use global defaults. Or at global scope, passing NULL /// will reset any custom value and restore it to the system default. - /// NOTE: When setting callback functions, do not pass the function pointer directly. + /// NOTE: When setting pointers (e.g. callback functions), do not pass the function pointer directly. /// Your argument should be a pointer to a function pointer. virtual bool SetConfigValue( ESteamNetworkingConfigValue eValue, ESteamNetworkingConfigScope eScopeType, intptr_t scopeObj, ESteamNetworkingConfigDataType eDataType, const void *pArg ) = 0; @@ -400,13 +413,22 @@ inline void ISteamNetworkingUtils::InitRelayNetworkAccess() { CheckPingDataUpToD inline bool ISteamNetworkingUtils::SetGlobalConfigValueInt32( ESteamNetworkingConfigValue eValue, int32 val ) { return SetConfigValue( eValue, k_ESteamNetworkingConfig_Global, 0, k_ESteamNetworkingConfig_Int32, &val ); } inline bool ISteamNetworkingUtils::SetGlobalConfigValueFloat( ESteamNetworkingConfigValue eValue, float val ) { return SetConfigValue( eValue, k_ESteamNetworkingConfig_Global, 0, k_ESteamNetworkingConfig_Float, &val ); } inline bool ISteamNetworkingUtils::SetGlobalConfigValueString( ESteamNetworkingConfigValue eValue, const char *val ) { return SetConfigValue( eValue, k_ESteamNetworkingConfig_Global, 0, k_ESteamNetworkingConfig_String, val ); } +inline bool ISteamNetworkingUtils::SetGlobalConfigValuePtr( ESteamNetworkingConfigValue eValue, void *val ) { return SetConfigValue( eValue, k_ESteamNetworkingConfig_Global, 0, k_ESteamNetworkingConfig_Ptr, &val ); } // Note: passing pointer to pointer. inline bool ISteamNetworkingUtils::SetConnectionConfigValueInt32( HSteamNetConnection hConn, ESteamNetworkingConfigValue eValue, int32 val ) { return SetConfigValue( eValue, k_ESteamNetworkingConfig_Connection, hConn, k_ESteamNetworkingConfig_Int32, &val ); } inline bool ISteamNetworkingUtils::SetConnectionConfigValueFloat( HSteamNetConnection hConn, ESteamNetworkingConfigValue eValue, float val ) { return SetConfigValue( eValue, k_ESteamNetworkingConfig_Connection, hConn, k_ESteamNetworkingConfig_Float, &val ); } inline bool ISteamNetworkingUtils::SetConnectionConfigValueString( HSteamNetConnection hConn, ESteamNetworkingConfigValue eValue, const char *val ) { return SetConfigValue( eValue, k_ESteamNetworkingConfig_Connection, hConn, k_ESteamNetworkingConfig_String, val ); } +inline bool ISteamNetworkingUtils::SetGlobalCallback_SteamNetConnectionStatusChanged( FnSteamNetConnectionStatusChanged fnCallback ) { return SetGlobalConfigValuePtr( k_ESteamNetworkingConfig_Callback_ConnectionStatusChanged, (void*)fnCallback ); } +inline bool ISteamNetworkingUtils::SetGlobalCallback_SteamNetAuthenticationStatusChanged( FnSteamNetAuthenticationStatusChanged fnCallback ) { return SetGlobalConfigValuePtr( k_ESteamNetworkingConfig_Callback_AuthStatusChanged, (void*)fnCallback ); } +inline bool ISteamNetworkingUtils::SetGlobalCallback_SteamRelayNetworkStatusChanged( FnSteamRelayNetworkStatusChanged fnCallback ) { return SetGlobalConfigValuePtr( k_ESteamNetworkingConfig_Callback_RelayNetworkStatusChanged, (void*)fnCallback ); } +inline bool ISteamNetworkingUtils::SetGlobalCallback_MessagesSessionRequest( FnSteamNetworkingMessagesSessionRequest fnCallback ) { return SetGlobalConfigValuePtr( k_ESteamNetworkingConfig_Callback_MessagesSessionRequest, (void*)fnCallback ); } +inline bool ISteamNetworkingUtils::SetGlobalCallback_MessagesSessionFailed( FnSteamNetworkingMessagesSessionFailed fnCallback ) { return SetGlobalConfigValuePtr( k_ESteamNetworkingConfig_Callback_MessagesSessionFailed, (void*)fnCallback ); } + inline bool ISteamNetworkingUtils::SetConfigValueStruct( const SteamNetworkingConfigValue_t &opt, ESteamNetworkingConfigScope eScopeType, intptr_t scopeObj ) { // Locate the argument. Strings are a special case, since the // "value" (the whole string buffer) doesn't fit in the struct + // NOTE: for pointer values, we pass a pointer to the pointer, + // we do not pass the pointer directly. const void *pVal = ( opt.m_eDataType == k_ESteamNetworkingConfig_String ) ? (const void *)opt.m_val.m_string : (const void *)&opt.m_val; return SetConfigValue( opt.m_eValue, eScopeType, scopeObj, opt.m_eDataType, pVal ); } diff --git a/sdk_includes/isteamutils.h b/sdk_includes/isteamutils.h index 3781db37..41110356 100644 --- a/sdk_includes/isteamutils.h +++ b/sdk_includes/isteamutils.h @@ -42,6 +42,16 @@ enum EGamepadTextInputLineMode }; +// The context where text filtering is being done +enum ETextFilteringContext +{ + k_ETextFilteringContextUnknown = 0, // Unknown context + k_ETextFilteringContextGameContent = 1, // Game content, only legally required filtering is performed + k_ETextFilteringContextChat = 2, // Chat from another player + k_ETextFilteringContextName = 3, // Character or item name +}; + + // function prototype for warning message hook #if defined( POSIX ) #define __cdecl @@ -174,23 +184,25 @@ public: virtual bool IsSteamChinaLauncher() = 0; // Initializes text filtering. - // Returns false if filtering is unavailable for the language the user is currently running in. - virtual bool InitFilterText() = 0; + // unFilterOptions are reserved for future use and should be set to 0 + // Returns false if filtering is unavailable for the language the user is currently running in. + virtual bool InitFilterText( uint32 unFilterOptions = 0 ) = 0; - // Filters the provided input message and places the filtered result into pchOutFilteredText. - // pchOutFilteredText is where the output will be placed, even if no filtering or censoring is performed - // nByteSizeOutFilteredText is the size (in bytes) of pchOutFilteredText + // Filters the provided input message and places the filtered result into pchOutFilteredText, using legally required filtering and additional filtering based on the context and user settings + // eContext is the type of content in the input string + // sourceSteamID is the Steam ID that is the source of the input string (e.g. the player with the name, or who said the chat text) // pchInputText is the input string that should be filtered, which can be ASCII or UTF-8 - // bLegalOnly should be false if you want profanity and legally required filtering (where required) and true if you want legally required filtering only - // Returns the number of characters (not bytes) filtered. - virtual int FilterText( char* pchOutFilteredText, uint32 nByteSizeOutFilteredText, const char * pchInputMessage, bool bLegalOnly ) = 0; + // pchOutFilteredText is where the output will be placed, even if no filtering is performed + // nByteSizeOutFilteredText is the size (in bytes) of pchOutFilteredText, should be at least strlen(pchInputText)+1 + // Returns the number of characters (not bytes) filtered + virtual int FilterText( ETextFilteringContext eContext, CSteamID sourceSteamID, const char *pchInputMessage, char *pchOutFilteredText, uint32 nByteSizeOutFilteredText ) = 0; // Return what we believe your current ipv6 connectivity to "the internet" is on the specified protocol. // This does NOT tell you if the Steam client is currently connected to Steam via ipv6. virtual ESteamIPv6ConnectivityState GetIPv6ConnectivityState( ESteamIPv6ConnectivityProtocol eProtocol ) = 0; }; -#define STEAMUTILS_INTERFACE_VERSION "SteamUtils009" +#define STEAMUTILS_INTERFACE_VERSION "SteamUtils010" #ifndef STEAM_API_EXPORTS // Global interface accessor diff --git a/sdk_includes/isteamutils009.h b/sdk_includes/isteamutils009.h new file mode 100644 index 00000000..52a04bdf --- /dev/null +++ b/sdk_includes/isteamutils009.h @@ -0,0 +1,147 @@ + +#ifndef ISTEAMUTILS009_H +#define ISTEAMUTILS009_H +#ifdef STEAM_WIN32 +#pragma once +#endif + +class ISteamUtils009 +{ +public: + // return the number of seconds since the user + virtual uint32 GetSecondsSinceAppActive() = 0; + virtual uint32 GetSecondsSinceComputerActive() = 0; + + // the universe this client is connecting to + virtual EUniverse GetConnectedUniverse() = 0; + + // Steam server time. Number of seconds since January 1, 1970, GMT (i.e unix time) + virtual uint32 GetServerRealTime() = 0; + + // returns the 2 digit ISO 3166-1-alpha-2 format country code this client is running in (as looked up via an IP-to-location database) + // e.g "US" or "UK". + virtual const char *GetIPCountry() = 0; + + // returns true if the image exists, and valid sizes were filled out + virtual bool GetImageSize( int iImage, uint32 *pnWidth, uint32 *pnHeight ) = 0; + + // returns true if the image exists, and the buffer was successfully filled out + // results are returned in RGBA format + // the destination buffer size should be 4 * height * width * sizeof(char) + virtual bool GetImageRGBA( int iImage, uint8 *pubDest, int nDestBufferSize ) = 0; + + // returns the IP of the reporting server for valve - currently only used in Source engine games + virtual bool GetCSERIPPort( uint32 *unIP, uint16 *usPort ) = 0; + + // return the amount of battery power left in the current system in % [0..100], 255 for being on AC power + virtual uint8 GetCurrentBatteryPower() = 0; + + // returns the appID of the current process + virtual uint32 GetAppID() = 0; + + // Sets the position where the overlay instance for the currently calling game should show notifications. + // This position is per-game and if this function is called from outside of a game context it will do nothing. + virtual void SetOverlayNotificationPosition( ENotificationPosition eNotificationPosition ) = 0; + + // API asynchronous call results + // can be used directly, but more commonly used via the callback dispatch API (see steam_api.h) + virtual bool IsAPICallCompleted( SteamAPICall_t hSteamAPICall, bool *pbFailed ) = 0; + virtual ESteamAPICallFailure GetAPICallFailureReason( SteamAPICall_t hSteamAPICall ) = 0; + virtual bool GetAPICallResult( SteamAPICall_t hSteamAPICall, void *pCallback, int cubCallback, int iCallbackExpected, bool *pbFailed ) = 0; + + // Deprecated. Applications should use SteamAPI_RunCallbacks() instead. Game servers do not need to call this function. + STEAM_PRIVATE_API( virtual void RunFrame() = 0; ) + + // returns the number of IPC calls made since the last time this function was called + // Used for perf debugging so you can understand how many IPC calls your game makes per frame + // Every IPC call is at minimum a thread context switch if not a process one so you want to rate + // control how often you do them. + virtual uint32 GetIPCCallCount() = 0; + + // API warning handling + // 'int' is the severity; 0 for msg, 1 for warning + // 'const char *' is the text of the message + // callbacks will occur directly after the API function is called that generated the warning or message + virtual void SetWarningMessageHook( SteamAPIWarningMessageHook_t pFunction ) = 0; + + // Returns true if the overlay is running & the user can access it. The overlay process could take a few seconds to + // start & hook the game process, so this function will initially return false while the overlay is loading. + virtual bool IsOverlayEnabled() = 0; + + // Normally this call is unneeded if your game has a constantly running frame loop that calls the + // D3D Present API, or OGL SwapBuffers API every frame. + // + // However, if you have a game that only refreshes the screen on an event driven basis then that can break + // the overlay, as it uses your Present/SwapBuffers calls to drive it's internal frame loop and it may also + // need to Present() to the screen any time an even needing a notification happens or when the overlay is + // brought up over the game by a user. You can use this API to ask the overlay if it currently need a present + // in that case, and then you can check for this periodically (roughly 33hz is desirable) and make sure you + // refresh the screen with Present or SwapBuffers to allow the overlay to do it's work. + virtual bool BOverlayNeedsPresent() = 0; + + // Asynchronous call to check if an executable file has been signed using the public key set on the signing tab + // of the partner site, for example to refuse to load modified executable files. + // The result is returned in CheckFileSignature_t. + // k_ECheckFileSignatureNoSignaturesFoundForThisApp - This app has not been configured on the signing tab of the partner site to enable this function. + // k_ECheckFileSignatureNoSignaturesFoundForThisFile - This file is not listed on the signing tab for the partner site. + // k_ECheckFileSignatureFileNotFound - The file does not exist on disk. + // k_ECheckFileSignatureInvalidSignature - The file exists, and the signing tab has been set for this file, but the file is either not signed or the signature does not match. + // k_ECheckFileSignatureValidSignature - The file is signed and the signature is valid. + STEAM_CALL_RESULT( CheckFileSignature_t ) + virtual SteamAPICall_t CheckFileSignature( const char *szFileName ) = 0; + + // Activates the Big Picture text input dialog which only supports gamepad input + virtual bool ShowGamepadTextInput( EGamepadTextInputMode eInputMode, EGamepadTextInputLineMode eLineInputMode, const char *pchDescription, uint32 unCharMax, const char *pchExistingText ) = 0; + + // Returns previously entered text & length + virtual uint32 GetEnteredGamepadTextLength() = 0; + virtual bool GetEnteredGamepadTextInput( char *pchText, uint32 cchText ) = 0; + + // returns the language the steam client is running in, you probably want ISteamApps::GetCurrentGameLanguage instead, this is for very special usage cases + virtual const char *GetSteamUILanguage() = 0; + + // returns true if Steam itself is running in VR mode + virtual bool IsSteamRunningInVR() = 0; + + // Sets the inset of the overlay notification from the corner specified by SetOverlayNotificationPosition. + virtual void SetOverlayNotificationInset( int nHorizontalInset, int nVerticalInset ) = 0; + + // returns true if Steam & the Steam Overlay are running in Big Picture mode + // Games much be launched through the Steam client to enable the Big Picture overlay. During development, + // a game can be added as a non-steam game to the developers library to test this feature + virtual bool IsSteamInBigPictureMode() = 0; + + // ask SteamUI to create and render its OpenVR dashboard + virtual void StartVRDashboard() = 0; + + // Returns true if the HMD content will be streamed via Steam Remote Play + virtual bool IsVRHeadsetStreamingEnabled() = 0; + + // Set whether the HMD content will be streamed via Steam Remote Play + // If this is set to true, then the scene in the HMD headset will be streamed, and remote input will not be allowed. + // If this is set to false, then the application window will be streamed instead, and remote input will be allowed. + // The default is true unless "VRHeadsetStreaming" "0" is in the extended appinfo for a game. + // (this is useful for games that have asymmetric multiplayer gameplay) + virtual void SetVRHeadsetStreamingEnabled( bool bEnabled ) = 0; + + // Returns whether this steam client is a Steam China specific client, vs the global client. + virtual bool IsSteamChinaLauncher() = 0; + + // Initializes text filtering. + // Returns false if filtering is unavailable for the language the user is currently running in. + virtual bool InitFilterText() = 0; + + // Filters the provided input message and places the filtered result into pchOutFilteredText. + // pchOutFilteredText is where the output will be placed, even if no filtering or censoring is performed + // nByteSizeOutFilteredText is the size (in bytes) of pchOutFilteredText + // pchInputText is the input string that should be filtered, which can be ASCII or UTF-8 + // bLegalOnly should be false if you want profanity and legally required filtering (where required) and true if you want legally required filtering only + // Returns the number of characters (not bytes) filtered. + virtual int FilterText( char* pchOutFilteredText, uint32 nByteSizeOutFilteredText, const char * pchInputMessage, bool bLegalOnly ) = 0; + + // Return what we believe your current ipv6 connectivity to "the internet" is on the specified protocol. + // This does NOT tell you if the Steam client is currently connected to Steam via ipv6. + virtual ESteamIPv6ConnectivityState GetIPv6ConnectivityState( ESteamIPv6ConnectivityProtocol eProtocol ) = 0; +}; + +#endif // ISTEAMUTILS009_H diff --git a/sdk_includes/steam_api.h b/sdk_includes/steam_api.h index 7b707e49..10d0eace 100644 --- a/sdk_includes/steam_api.h +++ b/sdk_includes/steam_api.h @@ -70,6 +70,7 @@ #include "isteamutils006.h" #include "isteamutils007.h" #include "isteamutils008.h" +#include "isteamutils009.h" #include "isteammatchmaking.h" #include "isteammatchmaking006.h" #include "isteammatchmaking007.h" @@ -107,6 +108,7 @@ #include "isteamnetworkingsockets002.h" #include "isteamnetworkingsockets003.h" #include "isteamnetworkingsockets006.h" +#include "isteamnetworkingsockets008.h" #include "isteamremotestorage.h" #include "isteamremotestorage001.h" #include "isteamremotestorage002.h" @@ -160,6 +162,7 @@ #include "isteamunifiedmessages.h" #include "isteaminput.h" #include "isteamremoteplay.h" +#include "isteamnetworkingmessages.h" #include "isteamnetworkingsockets.h" #include "isteamnetworkingutils.h" #include "isteamtv.h" diff --git a/sdk_includes/steam_api_flat.h b/sdk_includes/steam_api_flat.h index 9802f5f6..b3293f90 100644 --- a/sdk_includes/steam_api_flat.h +++ b/sdk_includes/steam_api_flat.h @@ -170,6 +170,8 @@ STEAMAPI_API void SteamAPI_ISteamFriends_ActivateGameOverlayRemotePlayTogetherIn STEAMAPI_API bool SteamAPI_ISteamFriends_RegisterProtocolInOverlayBrowser( ISteamFriends* self, const char * pchProtocol ); // ISteamUtils +STEAMAPI_API ISteamUtils *SteamAPI_SteamUtils_v010(); +STEAMAPI_API ISteamUtils *SteamAPI_SteamGameServerUtils_v010(); STEAMAPI_API ISteamUtils *SteamAPI_SteamUtils_v009(); STEAMAPI_API ISteamUtils *SteamAPI_SteamGameServerUtils_v009(); STEAMAPI_API uint32 SteamAPI_ISteamUtils_GetSecondsSinceAppActive( ISteamUtils* self ); @@ -202,8 +204,8 @@ STEAMAPI_API void SteamAPI_ISteamUtils_StartVRDashboard( ISteamUtils* self ); STEAMAPI_API bool SteamAPI_ISteamUtils_IsVRHeadsetStreamingEnabled( ISteamUtils* self ); STEAMAPI_API void SteamAPI_ISteamUtils_SetVRHeadsetStreamingEnabled( ISteamUtils* self, bool bEnabled ); STEAMAPI_API bool SteamAPI_ISteamUtils_IsSteamChinaLauncher( ISteamUtils* self ); -STEAMAPI_API bool SteamAPI_ISteamUtils_InitFilterText( ISteamUtils* self ); -STEAMAPI_API int SteamAPI_ISteamUtils_FilterText( ISteamUtils* self, char * pchOutFilteredText, uint32 nByteSizeOutFilteredText, const char * pchInputMessage, bool bLegalOnly ); +STEAMAPI_API bool SteamAPI_ISteamUtils_InitFilterText( ISteamUtils* self, uint32 unFilterOptions ); +STEAMAPI_API int SteamAPI_ISteamUtils_FilterText( ISteamUtils* self, ETextFilteringContext eContext, uint64_steamid sourceSteamID, const char * pchInputMessage, char * pchOutFilteredText, uint32 nByteSizeOutFilteredText ); STEAMAPI_API ESteamIPv6ConnectivityState SteamAPI_ISteamUtils_GetIPv6ConnectivityState( ISteamUtils* self, ESteamIPv6ConnectivityProtocol eProtocol ); // ISteamMatchmaking @@ -856,13 +858,25 @@ STEAMAPI_API ESteamDeviceFormFactor SteamAPI_ISteamRemotePlay_GetSessionClientFo STEAMAPI_API bool SteamAPI_ISteamRemotePlay_BGetSessionClientResolution( ISteamRemotePlay* self, RemotePlaySessionID_t unSessionID, int * pnResolutionX, int * pnResolutionY ); STEAMAPI_API bool SteamAPI_ISteamRemotePlay_BSendRemotePlayTogetherInvite( ISteamRemotePlay* self, uint64_steamid steamIDFriend ); +// ISteamNetworkingMessages +STEAMAPI_API ISteamNetworkingMessages *SteamAPI_SteamNetworkingMessages_v002(); +STEAMAPI_API ISteamNetworkingMessages *SteamAPI_SteamGameServerNetworkingMessages_v002(); +STEAMAPI_API EResult SteamAPI_ISteamNetworkingMessages_SendMessageToUser( ISteamNetworkingMessages* self, const SteamNetworkingIdentity & identityRemote, const void * pubData, uint32 cubData, int nSendFlags, int nRemoteChannel ); +STEAMAPI_API int SteamAPI_ISteamNetworkingMessages_ReceiveMessagesOnChannel( ISteamNetworkingMessages* self, int nLocalChannel, SteamNetworkingMessage_t ** ppOutMessages, int nMaxMessages ); +STEAMAPI_API bool SteamAPI_ISteamNetworkingMessages_AcceptSessionWithUser( ISteamNetworkingMessages* self, const SteamNetworkingIdentity & identityRemote ); +STEAMAPI_API bool SteamAPI_ISteamNetworkingMessages_CloseSessionWithUser( ISteamNetworkingMessages* self, const SteamNetworkingIdentity & identityRemote ); +STEAMAPI_API bool SteamAPI_ISteamNetworkingMessages_CloseChannelWithUser( ISteamNetworkingMessages* self, const SteamNetworkingIdentity & identityRemote, int nLocalChannel ); +STEAMAPI_API ESteamNetworkingConnectionState SteamAPI_ISteamNetworkingMessages_GetSessionConnectionInfo( ISteamNetworkingMessages* self, const SteamNetworkingIdentity & identityRemote, SteamNetConnectionInfo_t * pConnectionInfo, SteamNetworkingQuickConnectionStatus * pQuickStatus ); + // ISteamNetworkingSockets +STEAMAPI_API ISteamNetworkingSockets *SteamAPI_SteamNetworkingSockets_v009(); +STEAMAPI_API ISteamNetworkingSockets *SteamAPI_SteamGameServerNetworkingSockets_v009(); STEAMAPI_API ISteamNetworkingSockets *SteamAPI_SteamNetworkingSockets_v008(); STEAMAPI_API ISteamNetworkingSockets *SteamAPI_SteamGameServerNetworkingSockets_v008(); STEAMAPI_API HSteamListenSocket SteamAPI_ISteamNetworkingSockets_CreateListenSocketIP( ISteamNetworkingSockets* self, const SteamNetworkingIPAddr & localAddress, int nOptions, const SteamNetworkingConfigValue_t * pOptions ); STEAMAPI_API HSteamNetConnection SteamAPI_ISteamNetworkingSockets_ConnectByIPAddress( ISteamNetworkingSockets* self, const SteamNetworkingIPAddr & address, int nOptions, const SteamNetworkingConfigValue_t * pOptions ); -STEAMAPI_API HSteamListenSocket SteamAPI_ISteamNetworkingSockets_CreateListenSocketP2P( ISteamNetworkingSockets* self, int nVirtualPort, int nOptions, const SteamNetworkingConfigValue_t * pOptions ); -STEAMAPI_API HSteamNetConnection SteamAPI_ISteamNetworkingSockets_ConnectP2P( ISteamNetworkingSockets* self, const SteamNetworkingIdentity & identityRemote, int nVirtualPort, int nOptions, const SteamNetworkingConfigValue_t * pOptions ); +STEAMAPI_API HSteamListenSocket SteamAPI_ISteamNetworkingSockets_CreateListenSocketP2P( ISteamNetworkingSockets* self, int nLocalVirtualPort, int nOptions, const SteamNetworkingConfigValue_t * pOptions ); +STEAMAPI_API HSteamNetConnection SteamAPI_ISteamNetworkingSockets_ConnectP2P( ISteamNetworkingSockets* self, const SteamNetworkingIdentity & identityRemote, int nRemoteVirtualPort, int nOptions, const SteamNetworkingConfigValue_t * pOptions ); STEAMAPI_API EResult SteamAPI_ISteamNetworkingSockets_AcceptConnection( ISteamNetworkingSockets* self, HSteamNetConnection hConn ); STEAMAPI_API bool SteamAPI_ISteamNetworkingSockets_CloseConnection( ISteamNetworkingSockets* self, HSteamNetConnection hPeer, int nReason, const char * pszDebug, bool bEnableLinger ); STEAMAPI_API bool SteamAPI_ISteamNetworkingSockets_CloseListenSocket( ISteamNetworkingSockets* self, HSteamListenSocket hSocket ); @@ -887,17 +901,18 @@ STEAMAPI_API bool SteamAPI_ISteamNetworkingSockets_DestroyPollGroup( ISteamNetwo STEAMAPI_API bool SteamAPI_ISteamNetworkingSockets_SetConnectionPollGroup( ISteamNetworkingSockets* self, HSteamNetConnection hConn, HSteamNetPollGroup hPollGroup ); STEAMAPI_API int SteamAPI_ISteamNetworkingSockets_ReceiveMessagesOnPollGroup( ISteamNetworkingSockets* self, HSteamNetPollGroup hPollGroup, SteamNetworkingMessage_t ** ppOutMessages, int nMaxMessages ); STEAMAPI_API bool SteamAPI_ISteamNetworkingSockets_ReceivedRelayAuthTicket( ISteamNetworkingSockets* self, const void * pvTicket, int cbTicket, SteamDatagramRelayAuthTicket * pOutParsedTicket ); -STEAMAPI_API int SteamAPI_ISteamNetworkingSockets_FindRelayAuthTicketForServer( ISteamNetworkingSockets* self, const SteamNetworkingIdentity & identityGameServer, int nVirtualPort, SteamDatagramRelayAuthTicket * pOutParsedTicket ); -STEAMAPI_API HSteamNetConnection SteamAPI_ISteamNetworkingSockets_ConnectToHostedDedicatedServer( ISteamNetworkingSockets* self, const SteamNetworkingIdentity & identityTarget, int nVirtualPort, int nOptions, const SteamNetworkingConfigValue_t * pOptions ); +STEAMAPI_API int SteamAPI_ISteamNetworkingSockets_FindRelayAuthTicketForServer( ISteamNetworkingSockets* self, const SteamNetworkingIdentity & identityGameServer, int nRemoteVirtualPort, SteamDatagramRelayAuthTicket * pOutParsedTicket ); +STEAMAPI_API HSteamNetConnection SteamAPI_ISteamNetworkingSockets_ConnectToHostedDedicatedServer( ISteamNetworkingSockets* self, const SteamNetworkingIdentity & identityTarget, int nRemoteVirtualPort, int nOptions, const SteamNetworkingConfigValue_t * pOptions ); STEAMAPI_API uint16 SteamAPI_ISteamNetworkingSockets_GetHostedDedicatedServerPort( ISteamNetworkingSockets* self ); STEAMAPI_API SteamNetworkingPOPID SteamAPI_ISteamNetworkingSockets_GetHostedDedicatedServerPOPID( ISteamNetworkingSockets* self ); STEAMAPI_API EResult SteamAPI_ISteamNetworkingSockets_GetHostedDedicatedServerAddress( ISteamNetworkingSockets* self, SteamDatagramHostedAddress * pRouting ); -STEAMAPI_API HSteamListenSocket SteamAPI_ISteamNetworkingSockets_CreateHostedDedicatedServerListenSocket( ISteamNetworkingSockets* self, int nVirtualPort, int nOptions, const SteamNetworkingConfigValue_t * pOptions ); +STEAMAPI_API HSteamListenSocket SteamAPI_ISteamNetworkingSockets_CreateHostedDedicatedServerListenSocket( ISteamNetworkingSockets* self, int nLocalVirtualPort, int nOptions, const SteamNetworkingConfigValue_t * pOptions ); STEAMAPI_API EResult SteamAPI_ISteamNetworkingSockets_GetGameCoordinatorServerLogin( ISteamNetworkingSockets* self, SteamDatagramGameCoordinatorServerLogin * pLoginInfo, int * pcbSignedBlob, void * pBlob ); -STEAMAPI_API HSteamNetConnection SteamAPI_ISteamNetworkingSockets_ConnectP2PCustomSignaling( ISteamNetworkingSockets* self, ISteamNetworkingConnectionCustomSignaling * pSignaling, const SteamNetworkingIdentity * pPeerIdentity, int nOptions, const SteamNetworkingConfigValue_t * pOptions ); +STEAMAPI_API HSteamNetConnection SteamAPI_ISteamNetworkingSockets_ConnectP2PCustomSignaling( ISteamNetworkingSockets* self, ISteamNetworkingConnectionCustomSignaling * pSignaling, const SteamNetworkingIdentity * pPeerIdentity, int nRemoteVirtualPort, int nOptions, const SteamNetworkingConfigValue_t * pOptions ); STEAMAPI_API bool SteamAPI_ISteamNetworkingSockets_ReceivedP2PCustomSignal( ISteamNetworkingSockets* self, const void * pMsg, int cbMsg, ISteamNetworkingCustomSignalingRecvContext * pContext ); STEAMAPI_API bool SteamAPI_ISteamNetworkingSockets_GetCertificateRequest( ISteamNetworkingSockets* self, int * pcbBlob, void * pBlob, SteamNetworkingErrMsg & errMsg ); STEAMAPI_API bool SteamAPI_ISteamNetworkingSockets_SetCertificate( ISteamNetworkingSockets* self, const void * pCertificate, int cbCertificate, SteamNetworkingErrMsg & errMsg ); +STEAMAPI_API void SteamAPI_ISteamNetworkingSockets_RunCallbacks( ISteamNetworkingSockets* self ); // ISteamNetworkingConnectionCustomSignaling STEAMAPI_API bool SteamAPI_ISteamNetworkingConnectionCustomSignaling_SendSignal( ISteamNetworkingConnectionCustomSignaling* self, HSteamNetConnection hConn, const SteamNetConnectionInfo_t & info, const void * pMsg, int cbMsg ); @@ -927,9 +942,15 @@ STEAMAPI_API void SteamAPI_ISteamNetworkingUtils_SetDebugOutputFunction( ISteamN STEAMAPI_API bool SteamAPI_ISteamNetworkingUtils_SetGlobalConfigValueInt32( ISteamNetworkingUtils* self, ESteamNetworkingConfigValue eValue, int32 val ); STEAMAPI_API bool SteamAPI_ISteamNetworkingUtils_SetGlobalConfigValueFloat( ISteamNetworkingUtils* self, ESteamNetworkingConfigValue eValue, float val ); STEAMAPI_API bool SteamAPI_ISteamNetworkingUtils_SetGlobalConfigValueString( ISteamNetworkingUtils* self, ESteamNetworkingConfigValue eValue, const char * val ); +STEAMAPI_API bool SteamAPI_ISteamNetworkingUtils_SetGlobalConfigValuePtr( ISteamNetworkingUtils* self, ESteamNetworkingConfigValue eValue, void * val ); STEAMAPI_API bool SteamAPI_ISteamNetworkingUtils_SetConnectionConfigValueInt32( ISteamNetworkingUtils* self, HSteamNetConnection hConn, ESteamNetworkingConfigValue eValue, int32 val ); STEAMAPI_API bool SteamAPI_ISteamNetworkingUtils_SetConnectionConfigValueFloat( ISteamNetworkingUtils* self, HSteamNetConnection hConn, ESteamNetworkingConfigValue eValue, float val ); STEAMAPI_API bool SteamAPI_ISteamNetworkingUtils_SetConnectionConfigValueString( ISteamNetworkingUtils* self, HSteamNetConnection hConn, ESteamNetworkingConfigValue eValue, const char * val ); +STEAMAPI_API bool SteamAPI_ISteamNetworkingUtils_SetGlobalCallback_SteamNetConnectionStatusChanged( ISteamNetworkingUtils* self, FnSteamNetConnectionStatusChanged fnCallback ); +STEAMAPI_API bool SteamAPI_ISteamNetworkingUtils_SetGlobalCallback_SteamNetAuthenticationStatusChanged( ISteamNetworkingUtils* self, FnSteamNetAuthenticationStatusChanged fnCallback ); +STEAMAPI_API bool SteamAPI_ISteamNetworkingUtils_SetGlobalCallback_SteamRelayNetworkStatusChanged( ISteamNetworkingUtils* self, FnSteamRelayNetworkStatusChanged fnCallback ); +STEAMAPI_API bool SteamAPI_ISteamNetworkingUtils_SetGlobalCallback_MessagesSessionRequest( ISteamNetworkingUtils* self, FnSteamNetworkingMessagesSessionRequest fnCallback ); +STEAMAPI_API bool SteamAPI_ISteamNetworkingUtils_SetGlobalCallback_MessagesSessionFailed( ISteamNetworkingUtils* self, FnSteamNetworkingMessagesSessionFailed fnCallback ); STEAMAPI_API bool SteamAPI_ISteamNetworkingUtils_SetConfigValue( ISteamNetworkingUtils* self, ESteamNetworkingConfigValue eValue, ESteamNetworkingConfigScope eScopeType, intptr_t scopeObj, ESteamNetworkingConfigDataType eDataType, const void * pArg ); STEAMAPI_API bool SteamAPI_ISteamNetworkingUtils_SetConfigValueStruct( ISteamNetworkingUtils* self, const SteamNetworkingConfigValue_t & opt, ESteamNetworkingConfigScope eScopeType, intptr_t scopeObj ); STEAMAPI_API ESteamNetworkingGetConfigValueResult SteamAPI_ISteamNetworkingUtils_GetConfigValue( ISteamNetworkingUtils* self, ESteamNetworkingConfigValue eValue, ESteamNetworkingConfigScope eScopeType, intptr_t scopeObj, ESteamNetworkingConfigDataType * pOutDataType, void * pResult, size_t * cbResult ); @@ -1061,6 +1082,13 @@ STEAMAPI_API bool SteamAPI_SteamNetworkingIdentity_ParseString( SteamNetworkingI // SteamNetworkingMessage_t STEAMAPI_API void SteamAPI_SteamNetworkingMessage_t_Release( SteamNetworkingMessage_t* self ); +// SteamNetworkingConfigValue_t +STEAMAPI_API void SteamAPI_SteamNetworkingConfigValue_t_SetInt32( SteamNetworkingConfigValue_t* self, ESteamNetworkingConfigValue eVal, int32_t data ); +STEAMAPI_API void SteamAPI_SteamNetworkingConfigValue_t_SetInt64( SteamNetworkingConfigValue_t* self, ESteamNetworkingConfigValue eVal, int64_t data ); +STEAMAPI_API void SteamAPI_SteamNetworkingConfigValue_t_SetFloat( SteamNetworkingConfigValue_t* self, ESteamNetworkingConfigValue eVal, float data ); +STEAMAPI_API void SteamAPI_SteamNetworkingConfigValue_t_SetPtr( SteamNetworkingConfigValue_t* self, ESteamNetworkingConfigValue eVal, void * data ); +STEAMAPI_API void SteamAPI_SteamNetworkingConfigValue_t_SetString( SteamNetworkingConfigValue_t* self, ESteamNetworkingConfigValue eVal, const char * data ); + // SteamNetworkingPOPIDRender STEAMAPI_API const char * SteamAPI_SteamNetworkingPOPIDRender_c_str( SteamNetworkingPOPIDRender* self ); diff --git a/sdk_includes/steamnetworkingtypes.h b/sdk_includes/steamnetworkingtypes.h index a64f8ab9..5bde1ca9 100644 --- a/sdk_includes/steamnetworkingtypes.h +++ b/sdk_includes/steamnetworkingtypes.h @@ -41,6 +41,14 @@ struct SteamDatagramGameCoordinatorServerLogin; struct SteamNetConnectionStatusChangedCallback_t; struct SteamNetAuthenticationStatus_t; struct SteamRelayNetworkStatus_t; +struct SteamNetworkingMessagesSessionRequest_t; +struct SteamNetworkingMessagesSessionFailed_t; + +typedef void (*FnSteamNetConnectionStatusChanged)( SteamNetConnectionStatusChangedCallback_t * ); +typedef void (*FnSteamNetAuthenticationStatusChanged)( SteamNetAuthenticationStatus_t * ); +typedef void (*FnSteamRelayNetworkStatusChanged)(SteamRelayNetworkStatus_t *); +typedef void (*FnSteamNetworkingMessagesSessionRequest)(SteamNetworkingMessagesSessionRequest_t *); +typedef void (*FnSteamNetworkingMessagesSessionFailed)(SteamNetworkingMessagesSessionFailed_t *); /// Handle used to identify a connection to a remote host. typedef uint32 HSteamNetConnection; @@ -581,6 +589,21 @@ enum ESteamNetConnectionEnd // level failure. k_ESteamNetConnectionEnd_Misc_P2P_NAT_Firewall = 5009, + // Our peer replied that it has no record of the connection. + // This should not happen ordinarily, but can happen in a few + // exception cases: + // + // - This is an old connection, and the peer has already cleaned + // up and forgotten about it. (Perhaps it timed out and they + // closed it and were not able to communicate this to us.) + // - A bug or internal protocol error has caused us to try to + // talk to the peer about the connection before we received + // confirmation that the peer has accepted the connection. + // - The peer thinks that we have closed the connection for some + // reason (perhaps a bug), and believes that is it is + // acknowledging our closure. + k_ESteamNetConnectionEnd_Misc_PeerSentNoConnection = 5010, + k_ESteamNetConnectionEnd_Misc_Max = 5999, k_ESteamNetConnectionEnd__Force32Bit = 0x7fffffff @@ -632,9 +655,10 @@ struct SteamNetConnectionInfo_t /// have some details specific to the issue. char m_szEndDebug[ k_cchSteamNetworkingMaxConnectionCloseReason ]; - /// Debug description. This includes the connection handle, - /// connection type (and peer information), and the app name. - /// This string is used in various internal logging messages + /// Debug description. This includes the internal connection ID, + /// connection type (and peer information), and any name + /// given to the connection by the app. This string is used in various + /// internal logging messages. char m_szConnectionDescription[ k_cchSteamNetworkingMaxConnectionDescription ]; /// Internal stuff, room to change API easily @@ -913,6 +937,27 @@ const int k_nSteamNetworkingSend_ReliableNoNagle = k_nSteamNetworkingSend_Reliab // Otherwise you will probably just make performance worse. const int k_nSteamNetworkingSend_UseCurrentThread = 16; +// When sending a message using ISteamNetworkingMessages, automatically re-establish +// a broken session, without returning k_EResultNoConnection. Without this flag, +// if you attempt to send a message, and the session was proactively closed by the +// peer, or an error occurred that disrupted communications, then you must close the +// session using ISteamNetworkingMessages::CloseSessionWithUser before attempting to +// send another message. (Or you can simply add this flag and retry.) In this way, +// the disruption cannot go unnoticed, and a more clear order of events can be +// ascertained. This is especially important when reliable messages are used, since +// if the connection is disrupted, some of those messages will not have been delivered, +// and it is in general not possible to know which. Although a +// SteamNetworkingMessagesSessionFailed_t callback will be posted when an error occurs +// to notify you that a failure has happened, callbacks are asynchronous, so it is not +// possible to tell exactly when it happened. And because the primary purpose of +// ISteamNetworkingMessages is to be like UDP, there is no notification when a peer closes +// the session. +// +// If you are not using any reliable messages (e.g. you are using ISteamNetworkingMessages +// exactly as a transport replacement for UDP-style datagrams only), you may not need to +// know when an underlying connection fails, and so you may not need this notification. +const int k_nSteamNetworkingSend_AutoRestartBrokenSession = 32; + // // Ping location / measurement // @@ -985,7 +1030,7 @@ enum ESteamNetworkingConfigDataType k_ESteamNetworkingConfig_Int64 = 2, k_ESteamNetworkingConfig_Float = 3, k_ESteamNetworkingConfig_String = 4, - k_ESteamNetworkingConfig_FunctionPtr = 5, // NOTE: When setting callbacks, you should put the pointer into a variable and pass a pointer to that variable. + k_ESteamNetworkingConfig_Ptr = 5, k_ESteamNetworkingConfigDataType__Force32Bit = 0x7fffffff }; @@ -1090,6 +1135,168 @@ enum ESteamNetworkingConfigValue /// (This flag is itself a dev variable.) k_ESteamNetworkingConfig_EnumerateDevVars = 35, + /// [connection int32] Set this to 1 on outbound connections and listen sockets, + /// to enable "symmetric connect mode", which is useful in the following + /// common peer-to-peer use case: + /// + /// - The two peers are "equal" to each other. (Neither is clearly the "client" + /// or "server".) + /// - Either peer may initiate the connection, and indeed they may do this + /// at the same time + /// - The peers only desire a single connection to each other, and if both + /// peers initiate connections simultaneously, a protocol is needed for them + /// to resolve the conflict, so that we end up with a single connection. + /// + /// This use case is both common, and involves subtle race conditions and tricky + /// pitfalls, which is why the API has support for dealing with it. + /// + /// If an incoming connection arrives on a listen socket or via custom signaling, + /// and the application has not attempted to make a matching outbound connection + /// in symmetric mode, then the incoming connection can be accepted as usual. + /// A "matching" connection means that the relevant endpoint information matches. + /// (At the time this comment is being written, this is only supported for P2P + /// connections, which means that the peer identities must match, and the virtual + /// port must match. At a later time, symmetric mode may be supported for other + /// connection types.) + /// + /// If connections are initiated by both peers simultaneously, race conditions + /// can arise, but fortunately, most of them are handled internally and do not + /// require any special awareness from the application. However, there + /// is one important case that application code must be aware of: + /// If application code attempts an outbound connection using a ConnectXxx + /// function in symmetric mode, and a matching incoming connection is already + /// waiting on a listen socket, then instead of forming a new connection, + /// the ConnectXxx call will accept the existing incoming connection, and return + /// a connection handle to this accepted connection. + /// IMPORTANT: in this case, a SteamNetConnectionStatusChangedCallback_t + /// has probably *already* been posted to the queue for the incoming connection! + /// (Once callbacks are posted to the queue, they are not modified.) It doesn't + /// matter if the callback has not been consumed by the app. Thus, application + /// code that makes use of symmetric connections must be aware that, when processing a + /// SteamNetConnectionStatusChangedCallback_t for an incoming connection, the + /// m_hConn may refer to a new connection that the app has has not + /// seen before (the usual case), but it may also refer to a connection that + /// has already been accepted implicitly through a call to Connect()! In this + /// case, AcceptConnection() will return k_EResultDuplicateRequest. + /// + /// Only one symmetric connection to a given peer (on a given virtual port) + /// may exist at any given time. If client code attempts to create a connection, + /// and a (live) connection already exists on the local host, then either the + /// existing connection will be accepted as described above, or the attempt + /// to create a new connection will fail. Furthermore, linger mode functionality + /// is not supported on symmetric connections. + /// + /// A more complicated race condition can arise if both peers initiate a connection + /// at roughly the same time. In this situation, each peer will receive an incoming + /// connection from the other peer, when the application code has already initiated + /// an outgoing connection to that peer. The peers must resolve this conflict and + /// decide who is going to act as the "server" and who will act as the "client". + /// Typically the application does not need to be aware of this case as it is handled + /// internally. On both sides, the will observe their outbound connection being + /// "accepted", although one of them one have been converted internally to act + /// as the "server". + /// + /// In general, symmetric mode should be all-or-nothing: do not mix symmetric + /// connections with a non-symmetric connection that it might possible "match" + /// with. If you use symmetric mode on any connections, then both peers should + /// use it on all connections, and the corresponding listen socket, if any. The + /// behaviour when symmetric and ordinary connections are mixed is not defined by + /// this API, and you should not rely on it. (This advice only applies when connections + /// might possibly "match". For example, it's OK to use all symmetric mode + /// connections on one virtual port, and all ordinary, non-symmetric connections + /// on a different virtual port, as there is no potential for ambiguity.) + /// + /// When using the feature, you should set it in the following situations on + /// applicable objects: + /// + /// - When creating an outbound connection using ConnectXxx function + /// - When creating a listen socket. (Note that this will automatically cause + /// any accepted connections to inherit the flag.) + /// - When using custom signaling, before accepting an incoming connection. + /// + /// Setting the flag on listen socket and accepted connections will enable the + /// API to automatically deal with duplicate incoming connections, even if the + /// local host has not made any outbound requests. (In general, such duplicate + /// requests from a peer are ignored internally and will not be visible to the + /// application code. The previous connection must be closed or resolved first.) + k_ESteamNetworkingConfig_SymmetricConnect = 37, + + /// [connection int32] For connection types that use "virtual ports", this can be used + /// to assign a local virtual port. For incoming connections, this will always be the + /// virtual port of the listen socket (or the port requested by the remote host if custom + /// signaling is used and the connection is accepted), and cannot be changed. For + /// connections initiated locally, the local virtual port will default to the same as the + /// requested remote virtual port, if you do not specify a different option when creating + /// the connection. The local port is only relevant for symmetric connections, when + /// determining if two connections "match." In this case, if you need the local and remote + /// port to differ, you can set this value. + /// + /// You can also read back this value on listen sockets. + /// + /// This value should not be read or written in any other context. + k_ESteamNetworkingConfig_LocalVirtualPort = 38, + + // + // Callbacks + // + + // On Steam, you may use the default Steam callback dispatch mechanism. If you prefer + // to not use this dispatch mechanism (or you are not running with Steam), or you want + // to associate specific functions with specific listen sockets or connections, you can + // register them as configuration values. + // + // Note also that ISteamNetworkingUtils has some helpers to set these globally. + + /// [connection FnSteamNetConnectionStatusChanged] Callback that will be invoked + /// when the state of a connection changes. + /// + /// IMPORTANT: callbacks are dispatched to the handler that is in effect at the time + /// the event occurs, which might be in another thread. For example, immediately after + /// creating a listen socket, you may receive an incoming connection. And then immediately + /// after this, the remote host may close the connection. All of this could happen + /// before the function to create the listen socket has returned. For this reason, + /// callbacks usually must be in effect at the time of object creation. This means + /// you should set them when you are creating the listen socket or connection, or have + /// them in effect so they will be inherited at the time of object creation. + /// + /// For example: + /// + /// exterm void MyStatusChangedFunc( SteamNetConnectionStatusChangedCallback_t *info ); + /// SteamNetworkingConfigValue_t opt; opt.SetPtr( k_ESteamNetworkingConfig_Callback_ConnectionStatusChanged, MyStatusChangedFunc ); + /// SteamNetworkingIPAddr localAddress; localAddress.Clear(); + /// HSteamListenSocket hListenSock = SteamNetworkingSockets()->CreateListenSocketIP( localAddress, 1, &opt ); + /// + /// When accepting an incoming connection, there is no atomic way to switch the + /// callback. However, if the connection is DOA, AcceptConnection() will fail, and + /// you can fetch the state of the connection at that time. + /// + /// If all connections and listen sockets can use the same callback, the simplest + /// method is to set it globally before you create any listen sockets or connections. + k_ESteamNetworkingConfig_Callback_ConnectionStatusChanged = 201, + + /// [global FnSteamNetAuthenticationStatusChanged] Callback that will be invoked + /// when our auth state changes. If you use this, install the callback before creating + /// any connections or listen sockets, and don't change it. + /// See: ISteamNetworkingUtils::SetGlobalCallback_SteamNetAuthenticationStatusChanged + k_ESteamNetworkingConfig_Callback_AuthStatusChanged = 202, + + /// [global FnSteamRelayNetworkStatusChanged] Callback that will be invoked + /// when our auth state changes. If you use this, install the callback before creating + /// any connections or listen sockets, and don't change it. + /// See: ISteamNetworkingUtils::SetGlobalCallback_SteamRelayNetworkStatusChanged + k_ESteamNetworkingConfig_Callback_RelayNetworkStatusChanged = 203, + + /// [global FnSteamNetworkingMessagesSessionRequest] Callback that will be invoked + /// when a peer wants to initiate a SteamNetworkingMessagesSessionRequest. + /// See: ISteamNetworkingUtils::SetGlobalCallback_MessagesSessionRequest + k_ESteamNetworkingConfig_Callback_MessagesSessionRequest = 204, + + /// [global FnSteamNetworkingMessagesSessionFailed] Callback that will be invoked + /// when a session you have initiated, or accepted either fails to connect, or loses + /// connection in some unexpected way. + /// See: ISteamNetworkingUtils::SetGlobalCallback_MessagesSessionFailed + k_ESteamNetworkingConfig_Callback_MessagesSessionFailed = 205, + // // P2P settings // @@ -1224,8 +1431,42 @@ struct SteamNetworkingConfigValue_t int64_t m_int64; float m_float; const char *m_string; // Points to your '\0'-terminated buffer - void *m_functionPtr; + void *m_ptr; } m_val; + + // + // Shortcut helpers to set the type and value in a single call + // + inline void SetInt32( ESteamNetworkingConfigValue eVal, int32_t data ) + { + m_eValue = eVal; + m_eDataType = k_ESteamNetworkingConfig_Int32; + m_val.m_int32 = data; + } + inline void SetInt64( ESteamNetworkingConfigValue eVal, int64_t data ) + { + m_eValue = eVal; + m_eDataType = k_ESteamNetworkingConfig_Int64; + m_val.m_int64 = data; + } + inline void SetFloat( ESteamNetworkingConfigValue eVal, float data ) + { + m_eValue = eVal; + m_eDataType = k_ESteamNetworkingConfig_Float; + m_val.m_float = data; + } + inline void SetPtr( ESteamNetworkingConfigValue eVal, void *data ) + { + m_eValue = eVal; + m_eDataType = k_ESteamNetworkingConfig_Ptr; + m_val.m_ptr = data; + } + inline void SetString( ESteamNetworkingConfigValue eVal, const char *data ) // WARNING - Just saves your pointer. Does NOT make a copy of the string + { + m_eValue = eVal; + m_eDataType = k_ESteamNetworkingConfig_Ptr; + m_val.m_string = data; + } }; /// Return value of ISteamNetworkintgUtils::GetConfigValue