This commit is contained in:
nephacks
2025-06-04 03:22:50 +02:00
parent f234f23848
commit f12416cffd
14243 changed files with 6446499 additions and 26 deletions

View File

@@ -0,0 +1,121 @@
//====== Copyright Valve Corporation, All rights reserved. ====================
//
// Client interface to Steam datagram transport library.
//
//=============================================================================
#ifndef ISTEAMDATAGRAMCLIENT_H
#define ISTEAMDATAGRAMCLIENT_H
#ifdef _WIN32
#pragma once
#endif
#include "steamdatagram/steamdatagram_shared.h"
#include "steam/steamuniverse.h"
class CMsgSteamDatagramGameServerAuthTicket;
class ISteamNetworkingUtils;
/// Status of a particular network resource
enum ESteamDatagramAvailability
{
k_ESteamDatagramAvailability_CannotTry = -3, // A dependent resource is missing, so this service is unavailable. (E.g. we cannot talk to routers because Internet is down or we don't have the network config.)
k_ESteamDatagramAvailability_Failed = -2, // We have tried for enough time that we would expect to have been successful by now. We have never been successful
k_ESteamDatagramAvailability_Previously = -1, // We tried and were successful at one time, but now it looks like we have a problem
k_ESteamDatagramAvailability_NeverTried = 0, // We don't know because we haven't ever checked.
k_ESteamDatagramAvailability_Attempting = 1, // We're trying now, but are not yet successful. This is not an error, but it's not success, either.
k_ESteamDatagramAvailability_Current = 2, // Resource is online.
};
//-----------------------------------------------------------------------------
/// Interface to send datagrams to a Steam service that uses the
/// Steam datagram transport infrastructure.
class ISteamDatagramTransportClient
{
public:
/// Send a datagram to the service
virtual EResult SendDatagram( const void *pData, uint32 nSizeBytes, int nChannel ) = 0;
/// Receive the next available datagram from the service. Your buffer MUST
/// be at least k_nMaxSteamDatagramTransportPayload. Returns size of the datagram
/// returned into your buffer if a message is available. Returns 0 if nothing
/// available, or < 0 if there's an error.
virtual int RecvDatagram( void *pBuffer, uint32 nBufferSize, uint64 *pusecTimeRecv, int nChannel ) = 0;
/// Close the connection to the gameserver
virtual void Close() = 0;
/// Describe state of current connection
struct ConnectionStatus
{
/// Do we have a valid network configuration? We cannot do anything without this.
ESteamDatagramAvailability m_eAvailNetworkConfig;
// /// Does it look like we have a connection to the Internet at all?
// EAvailability m_eAvailInternet;
/// Successful communication with a box on the routing network.
/// This will be marked as failed if there is a general internet
/// connection.
ESteamDatagramAvailability m_eAvailAnyRouterCommunication;
/// End-to-end communication with the gameserver. This will be marked
/// as failed if there is a client problem.
ESteamDatagramAvailability m_eAvailGameserver;
/// Stats for end-to-end link to the gameserver
SteamDatagramLinkStats m_statsEndToEnd;
/// Index of data center containing the gameserver we are trying to talk to (if any)
int m_idxGameServerDataCenter;
/// Currently selected front router, if any
int m_idxPrimaryRouterCluster;
char m_szPrimaryRouterName[64];
uint32 m_unPrimaryRouterIP;
uint16 m_unPrimaryRouterPort;
/// Stats for "front" link to current router
SteamDatagramLinkStats m_statsPrimaryRouter;
/// Back ping time as reported by primary.
/// (The front ping is in m_statsPrimaryRouter,
/// and usually the front ping plus the back ping should
/// approximately equal the end-to-end ping)
int m_nPrimaryRouterBackPing;
/// Currently selected back router, if any
int m_idxBackupRouterCluster;
char m_szBackupRouterName[64];
uint32 m_unBackupRouterIP;
uint16 m_unBackupRouterPort;
/// Ping times to backup router, if any
int m_nBackupRouterFrontPing, m_nBackupRouterBackPing;
/// Print into a buffer. Returns the number of characters copied,
/// or needed if you pass NULL. (Includes the '\0' terminator in
/// both cases.)
int Print( char *pszBuf, int cbBuf ) const;
};
/// Status query
virtual void GetConnectionStatus( ConnectionStatus &result ) = 0;
};
/// !KLUDGE! Glue code that will go away when we move everything into
/// the ISteamNetwork interfaces
extern void SteamDatagramClient_Init( const char *pszCacheDirectory, ESteamDatagramPartner ePartner, int iPartnerMask );
/// Get ISteamNetworkingUtils object. This will eventually go in Steam_api.h with all the rest of its kin
extern ISteamNetworkingUtils *SteamNetworkingUtils();
/// Start talking to a gameserver.
ISteamDatagramTransportClient *SteamDatagramClient_Connect( CSteamID steamID );
/// Shutdown all clients and close all sockets
void SteamDatagramClient_Kill();
#endif // ISTEAMDATAGRAMCLIENT_H

View File

@@ -0,0 +1,55 @@
//====== Copyright Valve Corporation, All rights reserved. ====================
//
// Service interface to Steam datagram transport library.
//
//=============================================================================
#ifndef ISTEAMDATAGRAMSERVER_H
#define ISTEAMDATAGRAMSERVER_H
#ifdef _WIN32
#pragma once
#endif
#include "steamdatagram/steamdatagram_shared.h"
//-----------------------------------------------------------------------------
/// Interface a gameserver uses to communicate to clients through a proxy
class ISteamDatagramTransportGameserver
{
public:
/// Check for any incoming packets from any clients. Your buffer MUST
/// be at least k_nMaxSteamDatagramTransportPayload. Returns size of the datagram
/// returned into your buffer if a message is available. Returns 0 if nothing
/// available, or < 0 if there's an error.
virtual int RecvDatagram( void *pBuffer, uint32 nBufferSize, CSteamID *pSteamIDOutFromClient, uint64 *pusecTimeRecv, int nChannel ) = 0;
/// Send a datagram to the client. You must have sent or received data from this
/// client relatively recently. (Within the last 60 seconds or so.) If no communication
/// happens between a server and a client, the client will eventually be forgotten.
///
/// If you try to send a packet to a client that has been forgotten, k_EResultNotLoggedOn
/// will be returned.
virtual EResult SendDatagram( const void *pData, uint32 nSizeBytes, CSteamID steamIDToClient, int nChannel ) = 0;
/// Close down the socket and destroy the interface object.
virtual void Destroy() = 0;
/// Close the socket (used when forking). Does not do shutdown
virtual void CloseSockets() = 0;
/// !FIXME! Notification mechanism?
/// Connection quality metrics?
};
/// Start listening on the specified port. The port parameter is currently not optional,
/// you must choose port.
ISteamDatagramTransportGameserver *SteamDatagram_GameserverListen(
EUniverse eUniverse,
uint16 unBindPort,
EResult *pOutResult,
SteamDatagramErrMsg &errMsg
);
#endif // ISTEAMDATAGRAMSERVER_H

View File

@@ -0,0 +1,147 @@
//====== Copyright Valve Corporation, All rights reserved. ====================
//
// Purpose: misc networking utilities
//
//=============================================================================
#ifndef ISTEAMNETWORKINGUTILS
#define ISTEAMNETWORKINGUTILS
#ifdef _WIN32
#pragma once
#endif
#include "steamnetworkingtypes.h"
//-----------------------------------------------------------------------------
/// Misc networking utilities for checking the local networking environment
/// and estimating pings.
class ISteamNetworkingUtils
{
public:
/// Fetch current timestamp. These values never go backwards, and
/// the initial value is low enough that practically speaking it's
/// not necessary to worry about the value wrapping around.
virtual SteamNetworkingLocalTimestamp GetLocalTimestamp() = 0;
/// Check if the ping data of sufficient recency is available, and if
/// it's too old, start refreshing it.
///
/// Games that use the ping location information will typically
/// want to call this at boot time, to make sure all prerequisites
/// are ready. Especially since the first measurement might take
/// slightly longer than subsequent measurements.
///
/// Returns true if sufficiently recent data is already available.
///
/// Returns false if sufficiently recent data is not available. In this
/// case, ping measurement is initiated, if it is not already active.
/// (You cannot restart a measurement already in progress.)
///
/// A FIXME event will be posted when measurement is completed.
virtual bool CheckPingDataUpToDate( float flMaxAgeSeconds ) = 0;
/// Return location info for the current host. Returns the approximate
/// age of the data, in seconds, or -1 if no data is available.
/// Note that this might return an age older than the age of your game's
/// process, if the data was obtained before you game started.
///
/// This always return the most up-to-date information we have available
/// right now, even if we are in the middle of re-calculating ping times.
virtual float GetLocalPingLocation( SteamNetworkPingLocation_t &result ) = 0;
/// Return true if we are taking ping measurements to update our ping
/// location or select optimal routing. Ping measurement typically takes
/// a few seconds, perhaps up to 10 seconds.
virtual bool IsPingMeasurementInProgress() = 0;
/// Estimate the round-trip latency between two arbitrary locations, in
/// milliseconds. This is a conservative estimate, based on routing through
/// the relay network. For most basic connections based on SteamID,
/// this ping time will be pretty accurate, since it will be based on the
/// route likely to be actually used.
///
/// If a direct IP route is used (perhaps via NAT traversal), then the route
/// will be different, and the ping time might be better. Or it might actually
/// be a bit worse! Standard IP routing is frequently suboptimal!
///
/// but even in this case, the estimate obtained using this method is a
/// reasonable upper bound on the ping time. (Also it has the advantage
/// of returning immediately and not sending any packets.)
///
/// In a few cases we might not able to estimate the route. In this case
/// a negative value is returned. k_nSteamNetworkingPing_Failed means
/// the reason was because of some networking difficulty. (Failure to
/// ping, etc) k_nSteamNetworkingPing_Unknown is returned if we cannot
/// currently answer the question for some other reason.
virtual int EstimatePingTimeBetweenTwoLocations( const SteamNetworkPingLocation_t &location1, const SteamNetworkPingLocation_t &location2 ) = 0;
/// Same as EstimatePingTime, but assumes that one location is the local host.
/// This is a bit faster, especially if you need to calculate a bunch of
/// these in a loop to find the fastest one.
///
/// In rare cases this might return a slightly different estimate than combining
/// GetLocalPingLocation with EstimatePingTimeBetweenTwoLocations. That's because
/// this function uses a slightly more complete description
virtual int EstimatePingTimeFromLocalHost( const SteamNetworkPingLocation_t &remoteLocation ) = 0;
// FIXME:
//
// Check current internet connection status
//
// Low level ticket stuff. I need to get some advice and talk through how this should work
// or how best to tuck it away and make it transparent.
//
virtual void ReceivedTicket( const CMsgSteamDatagramGameServerAuthTicket &msgTicket ) = 0;
virtual bool HasTicketForServer( CSteamID steamID ) = 0;
virtual uint32 GetIPForServerSteamIDFromTicket( CSteamID steamID ) = 0;
//
// Low level network config stuff I haven't figure out how best to tuck away.
// Dota and CSGO use it because we have gameservers in the datacenter, and
// we need this information to do region selection. But most games won't
// need it.
//
/// Fetch directly measured ping time from local host to a particular network PoP.
/// Most games will not need to call this.
virtual int GetPingToDataCenter( SteamNetworkingPOPID popID, SteamNetworkingPOPID *pViaRelayPoP ) = 0;
virtual int GetDirectPingToPOP( SteamNetworkingPOPID popID ) = 0;
/// Get number of network PoPs in the config
virtual int GetPOPCount() = 0;
/// Get list of all POP IDs
virtual int GetPOPList( SteamNetworkingPOPID *list, int nListSz ) = 0;
};
#define STEAMNETWORKINGUTILS_VERSION "SteamNetworkingUtils001"
/// Convert 3- or 4-character ID to 32-bit int.
inline SteamNetworkingPOPID CalculateSteamNetworkingPOPIDFromString( const char *pszCode )
{
// OK we made a bad decision when we decided how to pack 3-character codes into a uint32. We'd like to support
// 4-character codes, but we don't want to break compatibility. The migration path has some subtleties that make
// this nontrivial, and there are already some IDs stored in SQL. Ug, so the 4 character code "abcd" will
// be encoded with the digits like "0xddaabbcc"
return
( uint32(pszCode[3]) << 24U )
| ( uint32(pszCode[0]) << 16U )
| ( uint32(pszCode[1]) << 8U )
| uint32(pszCode[2]);
}
/// Unpack integer to string representation, including terminating '\0'
template <int N>
inline void GetSteamNetworkingLocationPOPStringFromID( SteamNetworkingPOPID id, char (&szCode)[N] )
{
COMPILE_TIME_ASSERT( N >= 5 );
szCode[0] = ( id >> 16U );
szCode[1] = ( id >> 8U );
szCode[2] = ( id );
szCode[3] = ( id >> 24U ); // See comment above about deep regret and sadness
szCode[4] = 0;
}
#endif // ISTEAMNETWORKINGUTILS

View File

@@ -0,0 +1,279 @@
//====== Copyright Valve Corporation, All rights reserved. ====================
//
// Types and utilities used in the Steam datagram transport library
//
//=============================================================================
#ifndef STEAMDATAGRAM_SHARED_H
#define STEAMDATAGRAM_SHARED_H
#ifdef _WIN32
#pragma once
#endif
#include "tier0/dbg.h"
#include "steam/steamclientpublic.h"
#pragma pack(push)
#pragma pack(8)
// API-level datagram max size. (Actual UDP packets will be slightly bigger,
// due to the framing.)
const int k_nMaxSteamDatagramTransportPayload = 1200;
/// Max length of diagnostic error message
const int k_nMaxSteamDatagramErrMsg = 1024;
/// Used to return English-language diagnostic error messages to caller.
/// (For debugging or spewing to a console, etc. Not intended for UI.)
typedef char SteamDatagramErrMsg[ k_nMaxSteamDatagramErrMsg ];
/// Network-routable identifier for a service. In general, clients should
/// treat this as an opaque structure. The only thing that is important
/// is that this contains everything the system needs to route packets to a
/// service.
struct SteamDatagramServiceNetID
{
// Just use the private LAN address to identify the service
uint32 m_unIP;
uint16 m_unPort;
uint16 m__nPad1;
void Clear() { *(uint64 *)this = 0; }
uint64 ConvertToUint64() const { return ( uint64(m_unIP) << 16U ) | uint64(m_unPort); }
void SetFromUint64( uint64 x )
{
m_unIP = uint32(x >> 16U);
m_unPort = uint16(x);
m__nPad1 = 0;
}
inline bool operator==( const SteamDatagramServiceNetID &x ) const { return m_unIP == x.m_unIP && m_unPort == x.m_unPort; }
};
/// Ticket used to communicate with a gameserver. This structure should be
/// considered an opaque structure!
struct SteamDatagramGameserverAuthTicket
{
/// Ticket version
uint32 m_nTicketVersion;
/// Steam ID of the gameserver we want to talk to
CSteamID m_steamIDGameserver;
/// Steam ID of the person who was authorized.
CSteamID m_steamIDAuthorizedSender;
/// SteamID is authorized to send from a particular public IP. If this
/// is 0, then the sender is not restricted to a particular IP.
uint32 m_unPublicIP;
/// Time when the ticket expires.
RTime32 m_rtimeTicketExpiry;
/// Routing information
SteamDatagramServiceNetID m_routing;
/// Max length of ticket signature
enum { k_nMaxSignatureSize = 512 };
/// Length of signature.
int m_cbSignature;
/// Signature data
uint8 m_arbSignature[ k_nMaxSignatureSize ];
};
/// Size of socket read/write buffers. Set this before create a client
/// or server interface
extern int g_nSteamDatagramSocketBufferSize;
/// Instantaneous statistics for a link between two hosts.
struct SteamDatagramLinkInstantaneousStats
{
/// Data rates
float m_flOutPacketsPerSec;
float m_flOutBytesPerSec;
float m_flInPacketsPerSec;
float m_flInBytesPerSec;
/// Smoothed ping. This will be -1 if we don't have any idea!
int m_nPingMS;
/// 0...1, estimated number of packets that were sent to us, but we failed to receive.
/// <0 if we haven't received any sequenced packets and so we don't have any way to estimate this.
float m_flPacketsDroppedPct;
/// Packets received with a sequence number abnormality, other than basic packet loss. (Duplicated, out of order, lurch.)
/// <0 if we haven't received any sequenced packets and so we don't have any way to estimate this.
float m_flPacketsWeirdSequenceNumberPct;
/// Peak jitter
int m_usecMaxJitter;
void Clear();
};
/// Stats for the lifetime of a connection.
/// Should match CMsgSteamDatagramLinkLifetimeStats
struct SteamDatagramLinkLifetimeStats
{
//
// Lifetime counters.
// NOTE: Average packet loss, etc can be deduced from this.
//
int64 m_nPacketsSent;
int64 m_nBytesSent;
int64 m_nPacketsRecv; // total number of packets received, some of which might not have had a sequence number. Don't use this number to try to estimate lifetime packet loss, use m_nPacketsRecvSequenced
int64 m_nBytesRecv;
int64 m_nPktsRecvSequenced; // packets that we received that had a sequence number.
int64 m_nPktsRecvDropped;
int64 m_nPktsRecvOutOfOrder;
int64 m_nPktsRecvDuplicate;
int64 m_nPktsRecvSequenceNumberLurch;
//
// Ping distribution
//
int m_nPingHistogram25; // 0..25
int m_nPingHistogram50; // 26..50
int m_nPingHistogram75; // 51..75
int m_nPingHistogram100; // etc
int m_nPingHistogram125;
int m_nPingHistogram150;
int m_nPingHistogram200;
int m_nPingHistogram300;
int m_nPingHistogramMax; // >300
int PingHistogramTotalCount() const;
// Distribution.
// NOTE: Some of these might be -1 if we didn't have enough data to make a meaningful estimate!
// It takes fewer samples to make an estimate of the median than the 98th percentile!
short m_nPingNtile5th; // 5% of ping samples were <= Nms
short m_nPingNtile50th; // 50% of ping samples were <= Nms
short m_nPingNtile75th; // 70% of ping samples were <= Nms
short m_nPingNtile95th; // 95% of ping samples were <= Nms
short m_nPingNtile98th; // 98% of ping samples were <= Nms
short m__pad1;
//
// Connection quality distribution
//
int m_nQualityHistogram100; // This means everything was perfect. Even if we delivered over 100 packets in the interval and we should round up to 100, we will use 99% instead.
int m_nQualityHistogram99; // 99%+
int m_nQualityHistogram97;
int m_nQualityHistogram95;
int m_nQualityHistogram90;
int m_nQualityHistogram75;
int m_nQualityHistogram50;
int m_nQualityHistogram1;
int m_nQualityHistogramDead; // we received nothing during the interval; it looks like the connection dropped
int QualityHistogramTotalCount() const;
// Distribution. Some might be -1, see above for why.
short m_nQualityNtile2nd; // 2% of measurement intervals had quality <= N%
short m_nQualityNtile5th; // 5% of measurement intervals had quality <= N%
short m_nQualityNtile25th; // 25% of measurement intervals had quality <= N%
short m_nQualityNtile50th; // 50% of measurement intervals had quality <= N%
// Jitter histogram
int m_nJitterHistogramNegligible;
int m_nJitterHistogram1;
int m_nJitterHistogram2;
int m_nJitterHistogram5;
int m_nJitterHistogram10;
int m_nJitterHistogram20;
int JitterHistogramTotalCount() const;
void Clear();
};
/// Link stats. Pretty much everything you might possibly want to know about the connection
struct SteamDatagramLinkStats
{
/// Latest instantaneous stats, calculated locally
SteamDatagramLinkInstantaneousStats m_latest;
/// Peak values for each instantaneous stat
//SteamDatagramLinkInstantaneousStats m_peak;
/// Lifetime stats, calculated locally
SteamDatagramLinkLifetimeStats m_lifetime;
/// Latest instantaneous stats received from remote host.
/// (E.g. "sent" means they are reporting what they sent.)
SteamDatagramLinkInstantaneousStats m_latestRemote;
/// How many seconds ago did we receive m_latestRemote?
/// This will be <0 if the data is not valid!
float m_flAgeLatestRemote;
/// Latest lifetime stats received from remote host.
SteamDatagramLinkLifetimeStats m_lifetimeRemote;
/// How many seconds ago did we receive the lifetime stats?
/// This will be <0 if the data is not valid!
float m_flAgeLifetimeRemote;
/// Reset everything to unknown/initial state.
void Clear();
/// Print into a buffer. Returns the number of characters copied,
/// or needed if you pass NULL. (Includes the '\0' terminator in
/// both cases.)
int Print( char *pszBuf, int cbBuf ) const;
};
/// Identifier used for a datacenter.
typedef uint32 SteamDataCenterID;
// Convert 3-character string to ID
inline SteamDataCenterID CalculateSteamDataCenterIDFromCode( const char *pszCode )
{
// OK I made a bad decision when I decided how to pack 3-character codes into a uint32. I'd like to support 4-character
// codes, but I don't want to break compatibility. The migration path has some subtleties that make it nontrivial, and
// we're already storing them in SQL. Ug, so the 4 character code "abcd" will be encoded with the digits "dabc".
return
( uint32(pszCode[3]) << 24U )
| ( uint32(pszCode[0]) << 16U )
| ( uint32(pszCode[1]) << 8U )
| uint32(pszCode[2]);
}
/// Data center code, as string
template <int N>
inline void GetSteamDataCenterStringFromID( SteamDataCenterID id, char (&szCode)[N] )
{
COMPILE_TIME_ASSERT( N >= 5 );
szCode[0] = ( id >> 16U );
szCode[1] = ( id >> 8U );
szCode[2] = ( id );
szCode[3] = ( id >> 24U ); // See comment above about the deep regret and sadness I feel about this
szCode[4] = 0;
}
/// Fetch current time
extern uint64 SteamDatagram_GetCurrentTime();
/// Sometimes we put "fake" relays into the network config, which are used purely
/// to measure ping.
enum ESteamDatagramRouterType
{
k_ESteamDatagramRouterType_Normal,
k_ESteamDatagramRouterType_PingOnly,
//k_ESteamDatagramRouterType_FakeGameserver,
};
enum ESteamDatagramPartner
{
k_ESteamDatagramPartner_None = -1,
k_ESteamDatagramPartner_Steam = 0,
k_ESteamDatagramPartner_China = 1,
};
#pragma pack(pop)
#endif // STEAMDATAGRAM_SHARED_H

View File

@@ -0,0 +1,87 @@
//====== Copyright Valve Corporation, All rights reserved. ====================
//
// Purpose: misc networking utilities
//
//=============================================================================
#ifndef STEAMNETWORKINGTYPES
#define STEAMNETWORKINGTYPES
#ifdef _WIN32
#pragma once
#endif
#include "steamtypes.h"
#include "steamclientpublic.h"
struct SteamNetworkPingLocation_t;
class ISteamNetworkingMessage;
class CMsgSteamDatagramGameServerAuthTicket; // Ug
typedef uint32 SNetSocket_t; // Duplicate from the sockets API. That file should eventually include this one
/// Identifier used for a network location point of presence.
/// Typically you won't need to directly manipulate these.
typedef uint32 SteamNetworkingPOPID;
/// A local timestamp. You can subtract two timestamps to get the number of elapsed
/// microseconds. This is guaranteed to increase over time during the lifetime
/// of a process, but not globally across runs. You don't need to worry about
/// the value wrapping around. Note that the underlying clock might not actually have
/// microsecond *resolution*.
typedef int64 SteamNetworkingLocalTimestamp;
/// A message that has been received.
class ISteamNetworkingMessage
{
/// Call this when you're done with the object, to free up memory,
/// etc.
virtual void Release() = 0;
/// Get size of the payload.
inline uint32 GetSize() const { return m_cbSize; }
/// Get message payload
inline const void *GetData() const { return m_pData; }
/// Return the channel number the message was received on
inline int GetChannel() const { return m_nChannel; }
/// Return SteamID that sent this to us.
inline CSteamID GetSenderSteamID() const { return m_steamIDSender; }
/// The socket this came from. (Not used when using the P2P calls)
inline SNetSocket_t GetSocket() const { return m_sock; }
protected:
CSteamID m_steamIDSender;
void *m_pData;
uint32 m_cbSize;
int m_nChannel;
SNetSocket_t m_sock;
private:
virtual ~ISteamNetworkingMessage() {}
};
/// Object that describes a "location" on the Internet with sufficient
/// detail that we can reasonably estimate an upper bound on the ping between
/// the two hosts, even if a direct route between the hosts is not possible,
/// and the connection must be routed through the Steam Datagram Relay network.
/// This does not contain any information that identifies the host. Indeed,
/// if two hosts are in the same building or otherwise has nearly identical
/// networking characteristics, then it's valid to use the same location
/// object for both of them.
///
/// NOTE: This object should only be used in memory. If you need to persist
/// it or send it over the wire, convert it to a string representation using
/// the methods in ISteamNetworkingUtils()
struct SteamNetworkPingLocation_t
{
uint8 m_data[ 64 ];
};
/// Special ping values that are returned by some values that return a ping.
const int k_nSteamNetworkingPing_Failed = -1;
const int k_nSteamNetworkingPing_Unknown = -2;
#endif // STEAMNETWORKINGUTILS