X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=steam%2Fsteamworks_thin.h;fp=steam%2Fsteamworks_thin.h;h=5c6397bb667707abf805d01af9ce6cf0dadb1c4f;hb=6836e834f8db725e08015a98401f2be97e5b9849;hp=0000000000000000000000000000000000000000;hpb=b5740880fe3ffe59546bb80173ad3a6e1312648e;p=vg.git diff --git a/steam/steamworks_thin.h b/steam/steamworks_thin.h new file mode 100644 index 0000000..5c6397b --- /dev/null +++ b/steam/steamworks_thin.h @@ -0,0 +1,848 @@ +/* + steamworks_thin.h - simple wrapper / macro set for building steamworks apps in pure C + Usage: + Put the latest steam_api.dll in your build folder + link against -lsteam_api + + all functions are prefixed with sw_ +*/ + +#ifndef STEAMWORKS_H +#define STEAMWORKS_H + +#include +#include + +GLuint _localplayer_image; +char _localplayer_name[128]; + +#ifndef NO_STEAM + +#ifndef VOYAGER_RELEASE_MODE + #define STRUCTURE_PACK_CHECK +#endif + +/*______________________________________________________________________________________________________________________________ + + ENUMS +______________________________________________________________________________________________________________________________*/ + +typedef enum{ + + k_ESteamIPTypeIPv4 = 0, + k_ESteamIPTypeIPv6 = 1, + +} ESteamIPType_t; + +typedef enum{ + + k_ESNetSocketConnectionTypeNotConnected = 0, + k_ESNetSocketConnectionTypeUDP = 1, + k_ESNetSocketConnectionTypeUDPRelay = 2, + +} ESNetSocketConnectionType_t; + +//----------------------------------------------------------------------------- +// Purpose: Base values for callback identifiers, each callback must +// have a unique ID. +//----------------------------------------------------------------------------- + +enum { k_iSteamUserCallbacks = 100 }; +enum { k_iSteamGameServerCallbacks = 200 }; +enum { k_iSteamFriendsCallbacks = 300 }; +enum { k_iSteamBillingCallbacks = 400 }; +enum { k_iSteamMatchmakingCallbacks = 500 }; +enum { k_iSteamContentServerCallbacks = 600 }; +enum { k_iSteamUtilsCallbacks = 700 }; +enum { k_iClientFriendsCallbacks = 800 }; +enum { k_iClientUserCallbacks = 900 }; +enum { k_iSteamAppsCallbacks = 1000 }; +enum { k_iSteamUserStatsCallbacks = 1100 }; +enum { k_iSteamNetworkingCallbacks = 1200 }; +enum { k_iSteamNetworkingSocketsCallbacks = 1220 }; +enum { k_iSteamNetworkingMessagesCallbacks = 1250 }; +enum { k_iSteamNetworkingUtilsCallbacks = 1280 }; +enum { k_iClientRemoteStorageCallbacks = 1300 }; +enum { k_iClientDepotBuilderCallbacks = 1400 }; +enum { k_iSteamGameServerItemsCallbacks = 1500 }; +enum { k_iClientUtilsCallbacks = 1600 }; +enum { k_iSteamGameCoordinatorCallbacks = 1700 }; +enum { k_iSteamGameServerStatsCallbacks = 1800 }; +enum { k_iSteam2AsyncCallbacks = 1900 }; +enum { k_iSteamGameStatsCallbacks = 2000 }; +enum { k_iClientHTTPCallbacks = 2100 }; +enum { k_iClientScreenshotsCallbacks = 2200 }; +enum { k_iSteamScreenshotsCallbacks = 2300 }; +enum { k_iClientAudioCallbacks = 2400 }; +enum { k_iClientUnifiedMessagesCallbacks = 2500 }; +enum { k_iSteamStreamLauncherCallbacks = 2600 }; +enum { k_iClientControllerCallbacks = 2700 }; +enum { k_iSteamControllerCallbacks = 2800 }; +enum { k_iClientParentalSettingsCallbacks = 2900 }; +enum { k_iClientDeviceAuthCallbacks = 3000 }; +enum { k_iClientNetworkDeviceManagerCallbacks = 3100 }; +enum { k_iClientMusicCallbacks = 3200 }; +enum { k_iClientRemoteClientManagerCallbacks = 3300 }; +enum { k_iClientUGCCallbacks = 3400 }; +enum { k_iSteamStreamClientCallbacks = 3500 }; +enum { k_IClientProductBuilderCallbacks = 3600 }; +enum { k_iClientShortcutsCallbacks = 3700 }; +enum { k_iClientRemoteControlManagerCallbacks = 3800 }; +enum { k_iSteamAppListCallbacks = 3900 }; +enum { k_iSteamMusicCallbacks = 4000 }; +enum { k_iSteamMusicRemoteCallbacks = 4100 }; +enum { k_iClientVRCallbacks = 4200 }; +enum { k_iClientGameNotificationCallbacks = 4300 }; +enum { k_iSteamGameNotificationCallbacks = 4400 }; +enum { k_iSteamHTMLSurfaceCallbacks = 4500 }; +enum { k_iClientVideoCallbacks = 4600 }; +enum { k_iClientInventoryCallbacks = 4700 }; +enum { k_iClientBluetoothManagerCallbacks = 4800 }; +enum { k_iClientSharedConnectionCallbacks = 4900 }; +enum { k_ISteamParentalSettingsCallbacks = 5000 }; +enum { k_iClientShaderCallbacks = 5100 }; +enum { k_iSteamGameSearchCallbacks = 5200 }; +enum { k_iSteamPartiesCallbacks = 5300 }; +enum { k_iClientPartiesCallbacks = 5400 }; +enum { k_iSteamSTARCallbacks = 5500 }; +enum { k_iClientSTARCallbacks = 5600 }; +enum { k_iSteamRemotePlayCallbacks = 5700 }; +enum { k_iClientCompatCallbacks = 5800 }; +enum { k_iSteamChatCallbacks = 5900 }; + +// Steam universes. Each universe is a self-contained Steam instance. +typedef enum { + k_EUniverseInvalid = 0, + k_EUniversePublic = 1, + k_EUniverseBeta = 2, + k_EUniverseInternal = 3, + k_EUniverseDev = 4, + // k_EUniverseRC = 5, // no such universe anymore + k_EUniverseMax +} EUniverse_t; + +typedef enum{ + // Basic UDP send. Packets can't be bigger than 1200 bytes (your typical MTU size). Can be lost, or arrive out of order (rare). + // The sending API does have some knowledge of the underlying connection, so if there is no NAT-traversal accomplished or + // there is a recognized adjustment happening on the connection, the packet will be batched until the connection is open again. + k_EP2PSendUnreliable = 0, + + // As above, but if the underlying p2p connection isn't yet established the packet will just be thrown away. Using this on the first + // packet sent to a remote host almost guarantees the packet will be dropped. + // This is only really useful for kinds of data that should never buffer up, i.e. voice payload packets + k_EP2PSendUnreliableNoDelay = 1, + + // Reliable message send. Can send up to 1MB of data in a single message. + // Does fragmentation/re-assembly of messages under the hood, as well as a sliding window for efficient sends of large chunks of data. + k_EP2PSendReliable = 2, + + // As above, but applies the Nagle algorithm to the send - sends will accumulate + // until the current MTU size (typically ~1200 bytes, but can change) or ~200ms has passed (Nagle algorithm). + // Useful if you want to send a set of smaller messages but have the coalesced into a single packet + // Since the reliable stream is all ordered, you can do several small message sends with k_EP2PSendReliableWithBuffering and then + // do a normal k_EP2PSendReliable to force all the buffered data to be sent. + k_EP2PSendReliableWithBuffering = 3, + +} EP2PSend_t; + +// list of possible errors returned by SendP2PPacket() API +// these will be posted in the P2PSessionConnectFail_t callback +typedef enum { + k_EP2PSessionErrorNone = 0, + k_EP2PSessionErrorNotRunningApp = 1, // target is not running the same game + k_EP2PSessionErrorNoRightsToApp = 2, // local user doesn't own the app that is running + k_EP2PSessionErrorDestinationNotLoggedIn = 3, // target user isn't connected to Steam + k_EP2PSessionErrorTimeout = 4, // target isn't responding, perhaps not calling AcceptP2PSessionWithUser() + // corporate firewalls can also block this (NAT traversal is not firewall traversal) + // make sure that UDP ports 3478, 4379, and 4380 are open in an outbound direction + k_EP2PSessionErrorMax = 5 +} EP2PSessionError_t; + +typedef enum { + + k_EFriendFlagNone = 0x00, + k_EFriendFlagBlocked = 0x01, + k_EFriendFlagFriendshipRequested = 0x02, + k_EFriendFlagImmediate = 0x04, // "regular" friend + k_EFriendFlagClanMember = 0x08, + k_EFriendFlagOnGameServer = 0x10, + // k_EFriendFlagHasPlayedWith = 0x20, // not currently used + // k_EFriendFlagFriendOfFriend = 0x40, // not currently used + k_EFriendFlagRequestingFriendship = 0x80, + k_EFriendFlagRequestingInfo = 0x100, + k_EFriendFlagIgnored = 0x200, + k_EFriendFlagIgnoredFriend = 0x400, + // k_EFriendFlagSuggested = 0x800, // not used + k_EFriendFlagChatMember = 0x1000, + k_EFriendFlagAll = 0xFFFF, + +} EFriendFlags_t; + +// size limits on Rich Presence data +enum { k_cchMaxRichPresenceKeys = 30 }; +enum { k_cchMaxRichPresenceKeyLength = 64 }; +enum { k_cchMaxRichPresenceValueLength = 256 }; + +/*______________________________________________________________________________________________________________________________ + + STEAM TYPES +______________________________________________________________________________________________________________________________*/ + +// Redefube class pointers to void +typedef void ISteamFriends; +typedef void ISteamUserStats; +typedef void ISteamUtils; +typedef void ISteamUser; +typedef void ISteamNetworking; + +typedef int32_t HSteamPipe; +typedef int32_t HSteamUser; + +typedef int E_iCallBack_t; + +typedef uint32_t SNetSocket_t; // CreateP2PConnectionSocket() +typedef uint32_t SNetListenSocket_t; // CreateListenSocket() + +typedef uint64_t uint64_steamid; +typedef uint64_t SteamAPICall_t; + +/*______________________________________________________________________________________________________________________________ + + PACKING: 1 Byte +______________________________________________________________________________________________________________________________*/ + +#pragma pack( push, 1 ) + +typedef struct +{ + // 64 bits total + union { + struct SteamIDComponent_t + { +#ifdef VALVE_BIG_ENDIAN + EUniverse_t m_EUniverse : 8; // universe this account belongs to + unsigned int m_EAccountType : 4; // type of account - can't show as EAccountType, due to signed / unsigned difference + unsigned int m_unAccountInstance : 20; // dynamic instance ID + uint32_t m_unAccountID : 32; // unique account identifier +#else + uint32_t m_unAccountID : 32; // unique account identifier + unsigned int m_unAccountInstance : 20; // dynamic instance ID + unsigned int m_EAccountType : 4; // type of account - can't show as EAccountType, due to signed / unsigned difference + EUniverse_t m_EUniverse : 8; // universe this account belongs to +#endif + } m_comp; + + uint64_t m_unAll64Bits; + }; +} CSteamID; + +typedef struct{ + union { + + uint32_t m_unIPv4; // Host order + uint8_t m_rgubIPv6[16]; // Network order! Same as inaddr_in6. (0011:2233:4455:6677:8899:aabb:ccdd:eeff) + + // Internal use only + uint64_t m_ipv6Qword[2]; // big endian + + }; + + ESteamIPType_t m_eType; + +} SteamIPAddress_t; + +#pragma pack(pop) + +/*______________________________________________________________________________________________________________________________ + + PACKING: Some kind of strange alignment thing +______________________________________________________________________________________________________________________________*/ + +#if defined(__linux__) || defined(__APPLE__) +// The 32-bit version of gcc has the alignment requirement for uint64 and double set to +// 4 meaning that even with #pragma pack(8) these types will only be four-byte aligned. +// The 64-bit version of gcc has the alignment requirement for these types set to +// 8 meaning that unless we use #pragma pack(4) our structures will get bigger. +// The 64-bit structure packing has to match the 32-bit structure packing for each platform. + #define VALVE_CALLBACK_PACK_SMALL +#else + #define VALVE_CALLBACK_PACK_LARGE +#endif + +#if defined( VALVE_CALLBACK_PACK_SMALL ) + #pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) + #pragma pack( push, 8 ) +#else + #error steam_api_common.h should define VALVE_CALLBACK_PACK_xxx +#endif + +typedef struct{ + + uint8_t m_bConnectionActive; // true if we've got an active open connection + uint8_t m_bConnecting; // true if we're currently trying to establish a connection + uint8_t m_eP2PSessionError; // last error recorded (see enum above) + uint8_t m_bUsingRelay; // true if it's going through a relay server (TURN) + int32_t m_nBytesQueuedForSend; + int32_t m_nPacketsQueuedForSend; + uint32_t m_nRemoteIP; // potential IP:Port of remote host. Could be TURN server. + uint16_t m_nRemotePort; // Only exists for compatibility with older authentication api's + +} P2PSessionState_t; + +typedef struct { + + HSteamUser m_hSteamUser; // Specific user to whom this callback applies. + int m_iCallback; // Callback identifier. (Corresponds to the k_iCallback enum in the callback structure.) + uint8_t *m_pubParam; // Points to the callback structure + int m_cubParam; // Size of the data pointed to by m_pubParam + +} CallbackMsg_t; + +typedef struct { + + SteamAPICall_t m_hAsyncCall; + int m_iCallback; + uint32_t m_cubParam; + +} SteamAPICallCompleted_t; +#define SW_CBID_SteamAPICallCompleted (k_iSteamUtilsCallbacks + 3) + + +// callback notification - a user wants to talk to us over the P2P channel via the SendP2PPacket() API +// in response, a call to AcceptP2PPacketsFromUser() needs to be made, if you want to talk with them +typedef struct { + + CSteamID m_steamIDRemote; // user who wants to talk to us + +} P2PSessionRequest_t; +#define SW_CBID_P2PSessionRequest (k_iSteamNetworkingCallbacks + 2) + + +// callback notification - packets can't get through to the specified user via the SendP2PPacket() API +// all packets queued packets unsent at this point will be dropped +// further attempts to send will retry making the connection (but will be dropped if we fail again) +typedef struct { + + CSteamID m_steamIDRemote; // user we were sending packets to + uint8_t m_eP2PSessionError; // EP2PSessionError indicating why we're having trouble + +} P2PSessionConnectFail_t; +#define SW_CBID_P2PSessionConnectFail (k_iSteamNetworkingCallbacks + 3) + +// callback notification - status of a socket has changed +// used as part of the CreateListenSocket() / CreateP2PConnectionSocket() +typedef struct { + + SNetSocket_t m_hSocket; // the socket used to send/receive data to the remote host + SNetListenSocket_t m_hListenSocket; // this is the server socket that we were listening on; NULL if this was an outgoing connection + CSteamID m_steamIDRemote; // remote steamID we have connected to, if it has one + int m_eSNetSocketState; // socket state, ESNetSocketState + +} SocketStatusCallback_t; +#define SW_CBID_SocketStatusCallback (k_iSteamNetworkingCallbacks + 1) + +//----------------------------------------------------------------------------- +// Purpose: called when the user tries to join a game from their friends list +// rich presence will have been set with the "connect" key which is set here +//----------------------------------------------------------------------------- +typedef struct { + CSteamID m_steamIDFriend; // the friend they did the join via (will be invalid if not directly via a friend) + char m_rgchConnect[k_cchMaxRichPresenceValueLength]; +} GameRichPresenceJoinRequested_t; +#define SW_CBID_GameRichPresenceJoinRequested (k_iSteamFriendsCallbacks + 37) + +// Making SURE we have alignment +#ifdef STRUCTURE_PACK_CHECK +typedef struct { + uint32_t m_u32; + uint64_t m_u64; + uint16_t m_u16; + double m_d; +} ValvePackingSentinel_t; +#endif + +#pragma pack( pop ) + +#ifndef NO_STEAM + +/*______________________________________________________________________________________________________________________________ + + Forward linker declerations. Type: cdecl (obviously) +______________________________________________________________________________________________________________________________*/ + +void SteamAPI_Shutdown(); +int SteamAPI_Init(); +int SteamAPI_RestartAppIfNecessary( uint32_t unOwnAppID ); + +void SteamAPI_ManualDispatch_Init(); +void SteamAPI_ManualDispatch_RunFrame( HSteamPipe hSteamPipe ); +int SteamAPI_ManualDispatch_GetNextCallback( HSteamPipe hSteamPipe, CallbackMsg_t *pCallbackMsg ); +void SteamAPI_ManualDispatch_FreeLastCallback( HSteamPipe hSteamPipe ); +int SteamAPI_ManualDispatch_GetAPICallResult( HSteamPipe hSteamPipe, SteamAPICall_t hSteamAPICall, void *pCallback, int cubCallback, int iCallbackExpected, int *pbFailed ); + + +char *SteamAPI_ISteamFriends_GetPersonaName( ISteamFriends *self ); +const char *SteamAPI_ISteamFriends_GetFriendPersonaName( ISteamFriends *self, uint64_steamid steamIDFriend ); +uint64_steamid SteamAPI_ISteamUser_GetSteamID( ISteamUser *self ); +int SteamAPI_ISteamFriends_SetRichPresence( ISteamFriends* self, const char * pchKey, const char * pchValue ); +int SteamAPI_ISteamFriends_HasFriend( ISteamFriends* self, uint64_steamid steamIDFriend, int iFriendFlags ); +int SteamAPI_ISteamFriends_GetSmallFriendAvatar ( ISteamFriends *self, uint64_steamid steamIDFriend ); // 32x32 +int SteamAPI_ISteamFriends_GetMediumFriendAvatar ( ISteamFriends *self, uint64_steamid steamIDFriend ); +int SteamAPI_ISteamFriends_GetLargeFriendAvatar ( ISteamFriends *self, uint64_steamid steamIDFriend ); +int SteamAPI_ISteamUtils_GetImageSize( ISteamUtils *self, int iImage, uint32_t *pnWidth, uint32_t *pnHeight ); +int SteamAPI_ISteamUtils_GetImageRGBA( ISteamUtils *self, int iImage, uint8_t *pubDest, int nDestBufferSize ); +int SteamAPI_ISteamUserStats_SetAchievement( ISteamUserStats *self, const char *pchName ); + +HSteamPipe SteamAPI_GetHSteamPipe(); +HSteamUser SteamAPI_GetHSteamUser(); + +/* NETWORKING INTERFACES +-------------------------*/ + +int /* SendP2PPacket */ SteamAPI_ISteamNetworking_SendP2PPacket( ISteamNetworking *self, + uint64_steamid steamIDRemote, + const void *pubData, + uint32_t cubData, + EP2PSend_t eP2PSendType, + int nChannel +); + +int /* IsP2PPacketAvailable */ SteamAPI_ISteamNetworking_IsP2PPacketAvailable( ISteamNetworking *self, + uint32_t *pcubMsgSize, + int nChannel +); + +int /* ReadP2PPacket */ SteamAPI_ISteamNetworking_ReadP2PPacket( ISteamNetworking *self, + void *pubDest, + uint32_t cubDest, + uint32_t *pcubMsgSize, + CSteamID *psteamIDRemote, + int nChannel +); + +int /* AcceptP2PSessionWithUser */ SteamAPI_ISteamNetworking_AcceptP2PSessionWithUser( ISteamNetworking *self, + uint64_steamid steamIDRemote +); + +int /* CloseP2PSessionWithUser */ SteamAPI_ISteamNetworking_CloseP2PSessionWithUser( ISteamNetworking *self, + uint64_steamid steamIDRemote +); + +int /* CloseP2PChannelWithUser */ SteamAPI_ISteamNetworking_CloseP2PChannelWithUser( ISteamNetworking *self, + uint64_steamid steamIDRemote, + int nChannel +); + +int /* GetP2PSessionState */ SteamAPI_ISteamNetworking_GetP2PSessionState( ISteamNetworking *self, + uint64_steamid steamIDRemote, + P2PSessionState_t *pConnectionState +); + +int /* AllowP2PPacketRelay */ SteamAPI_ISteamNetworking_AllowP2PPacketRelay( ISteamNetworking *self, + int bAllow +); + +SNetListenSocket_t /* CreateListenSocket */ SteamAPI_ISteamNetworking_CreateListenSocket( ISteamNetworking *self, + int nVirtualP2PPort, + SteamIPAddress_t nIP, + uint16_t nPort, + int bAllowUseOfPacketRelay +); + +SNetSocket_t /* CreateP2PConnectionSocket */ SteamAPI_ISteamNetworking_CreateP2PConnectionSocket( ISteamNetworking *self, + uint64_steamid steamIDTarget, + int nVirtualPort, + int nTimeoutSec, + int bAllowUseOfPacketRelay +); + +SNetSocket_t /* CreateConnectionSocket */ SteamAPI_ISteamNetworking_CreateConnectionSocket( ISteamNetworking *self, + SteamIPAddress_t nIP, + uint16_t nPort, + int nTimeoutSec +); + +int /* DestroySocket */ SteamAPI_ISteamNetworking_DestroySocket( ISteamNetworking *self, + SNetSocket_t hSocket, + int bNotifyRemoteEnd +); + +int /* DestroyListenSocket */ SteamAPI_ISteamNetworking_DestroyListenSocket( ISteamNetworking *self, + SNetListenSocket_t hSocket, + int bNotifyRemoteEnd +); + +int /* SendDataOnSocket */ SteamAPI_ISteamNetworking_SendDataOnSocket( ISteamNetworking *self, + SNetSocket_t hSocket, + void *pubData, + uint32_t cubData, + int bReliable +); + +int /* IsDataAvailableOnSocket */ SteamAPI_ISteamNetworking_IsDataAvailableOnSocket( ISteamNetworking *self, + SNetSocket_t hSocket, + uint32_t *pcubMsgSize +); + +int /* RetrieveDataFromSocket */ SteamAPI_ISteamNetworking_RetrieveDataFromSocket( ISteamNetworking *self, + SNetSocket_t hSocket, + void *pubDest, + uint32_t cubDest, + uint32_t *pcubMsgSize +); + +int /* IsDataAvailable */ SteamAPI_ISteamNetworking_IsDataAvailable( ISteamNetworking *self, + SNetListenSocket_t hListenSocket, + uint32_t *pcubMsgSize, + SNetSocket_t *phSocket +); + +int /* RetrieveData */ SteamAPI_ISteamNetworking_RetrieveData( ISteamNetworking *self, + SNetListenSocket_t hListenSocket, + void *pubDest, + uint32_t cubDest, + uint32_t *pcubMsgSize, + SNetSocket_t *phSocket +); + +int /* GetSocketInfo */ SteamAPI_ISteamNetworking_GetSocketInfo( ISteamNetworking *self, + SNetSocket_t hSocket, + CSteamID *pSteamIDRemote, + int *peSocketStatus, + SteamIPAddress_t *punIPRemote, + uint16_t *punPortRemote +); + +int /* GetListenSocketInfo */ SteamAPI_ISteamNetworking_GetListenSocketInfo( ISteamNetworking *self, + SNetListenSocket_t hListenSocket, + SteamIPAddress_t *pnIP, + uint16_t *pnPort +); + +ESNetSocketConnectionType_t /* GetSocketConnectionType */ SteamAPI_ISteamNetworking_GetSocketConnectionType( ISteamNetworking *self, + SNetSocket_t hSocket +); + +int /* GetMaxPacketSize */ SteamAPI_ISteamNetworking_GetMaxPacketSize( ISteamNetworking *self, + SNetSocket_t hSocket +); + +#define sw_SteamAPI_Shutdown SteamAPI_Shutdown +#define sw_SteamAPI_Init() SteamAPI_Init() +#define sw_SteamAPI_RestartAppIfNecessary(...) SteamAPI_RestartAppIfNecessary( __VA_ARGS__ ) + +// This method can only be cleared correctly in first party c++ mode +// See: sw_SteamAPI_ManualDispatch_Init +// #define sw_SteamAPI_RunCallbacks() + +// Steam pipe stuff +#define sw_SteamAPI_GetHSteamPipe() SteamAPI_GetHSteamPipe() +#define sw_SteamAPI_GetHSteamUser() SteamAPI_GetHSteamUser() + +#define sw_SteamAPI_ManualDispatch_Init() SteamAPI_ManualDispatch_Init() +#define sw_SteamAPI_ManualDispatch_GetNextCallback(...) SteamAPI_ManualDispatch_GetNextCallback( __VA_ARGS__ ) +#define sw_SteamAPI_ManualDispatch_FreeLastCallback(...) SteamAPI_ManualDispatch_FreeLastCallback( __VA_ARGS__ ) +#define sw_SteamAPI_ManualDispatch_GetAPICallResult(...) SteamAPI_ManualDispatch_GetAPICallResult( __VA_ARGS__ ) +#define sw_SteamAPI_ManualDispatch_RunFrame(...) SteamAPI_ManualDispatch_RunFrame( __VA_ARGS__ ) + +#define sw_GetPersonaName(...) SteamAPI_ISteamFriends_GetPersonaName( __thinsteam_friends, ##__VA_ARGS__ ) +#define sw_GetFriendPersonaName(...) SteamAPI_ISteamFriends_GetFriendPersonaName( __thinsteam_friends, __VA_ARGS__ ) +#define sw_GetSteamID(...) SteamAPI_ISteamUser_GetSteamID( __thinsteam_user, ##__VA_ARGS__ ) +#define sw_HasFriend(...) SteamAPI_ISteamFriends_HasFriend( __thinsteam_friends, __VA_ARGS__ ) +#define sw_SetRichPresence(...) SteamAPI_ISteamFriends_SetRichPresence( __thinsteam_friends, __VA_ARGS__ ) + +#define sw_GetSmallFriendAvatar(...) SteamAPI_ISteamFriends_GetSmallFriendAvatar( __thinsteam_friends, ##__VA_ARGS__ ) +#define sw_GetMediumFriendAvatar(...) SteamAPI_ISteamFriends_GetMediumFriendAvatar( __thinsteam_friends, ##__VA_ARGS__ ) +#define sw_GetLargeFriendAvatar(...) SteamAPI_ISteamFriends_GetLargeFriendAvatar( __thinsteam_friends, ##__VA_ARGS__ ) +#define sw_GetImageSize(...) SteamAPI_ISteamUtils_GetImageSize( __thinsteam_utils, ##__VA_ARGS__ ) +#define sw_GetImageRGBA(...) SteamAPI_ISteamUtils_GetImageRGBA( __thinsteam_utils, ##__VA_ARGS__ ) + +#define sw_SetAchievement(...) SteamAPI_ISteamUserStats_SetAchievement( __thinsteam_stats, ##__VA_ARGS__ ) + +// https://partner.steamgames.com/doc/api/ISteamNetworkingUtils +#define sw_SendP2PPacket(...) SteamAPI_ISteamNetworking_SendP2PPacket( __thinsteam_net, ##__VA_ARGS__ ) +#define sw_IsP2PPacketAvailable(...) SteamAPI_ISteamNetworking_IsP2PPacketAvailable( __thinsteam_net, ##__VA_ARGS__ ) +#define sw_ReadP2PPacket(...) SteamAPI_ISteamNetworking_ReadP2PPacket( __thinsteam_net, ##__VA_ARGS__ ) +#define sw_AcceptP2PSessionWithUser(...) SteamAPI_ISteamNetworking_AcceptP2PSessionWithUser( __thinsteam_net, ##__VA_ARGS__ ) +#define sw_CloseP2PSessionWithUser(...) SteamAPI_ISteamNetworking_CloseP2PSessionWithUser( __thinsteam_net, ##__VA_ARGS__ ) +#define sw_CloseP2PChannelWithUser(...) SteamAPI_ISteamNetworking_CloseP2PChannelWithUser( __thinsteam_net, ##__VA_ARGS__ ) +#define sw_GetP2PSessionState(...) SteamAPI_ISteamNetworking_GetP2PSessionState( __thinsteam_net, ##__VA_ARGS__ ) +#define sw_AllowP2PPacketRelay(...) SteamAPI_ISteamNetworking_AllowP2PPacketRelay( __thinsteam_net, ##__VA_ARGS__ ) +#define sw_CreateListenSocket(...) SteamAPI_ISteamNetworking_CreateListenSocket( __thinsteam_net, ##__VA_ARGS__ ) +#define sw_CreateP2PConnectionSocket(...) SteamAPI_ISteamNetworking_CreateP2PConnectionSocket( __thinsteam_net, ##__VA_ARGS__ ) +#define sw_CreateConnectionSocket(...) SteamAPI_ISteamNetworking_CreateConnectionSocket( __thinsteam_net, ##__VA_ARGS__ ) +#define sw_DestroySocket(...) SteamAPI_ISteamNetworking_DestroySocket( __thinsteam_net, ##__VA_ARGS__ ) +#define sw_DestroyListenSocket(...) SteamAPI_ISteamNetworking_DestroyListenSocket( __thinsteam_net, ##__VA_ARGS__ ) +#define sw_SendDataOnSocket(...) SteamAPI_ISteamNetworking_SendDataOnSocket( __thinsteam_net, ##__VA_ARGS__ ) +#define sw_IsDataAvailableOnSocket(...) SteamAPI_ISteamNetworking_IsDataAvailableOnSocket( __thinsteam_net, ##__VA_ARGS__ ) +#define sw_RetrieveDataFromSocket(...) SteamAPI_ISteamNetworking_RetrieveDataFromSocket( __thinsteam_net, ##__VA_ARGS__ ) +#define sw_IsDataAvailable(...) SteamAPI_ISteamNetworking_IsDataAvailable( __thinsteam_net, ##__VA_ARGS__ ) +#define sw_RetrieveData(...) SteamAPI_ISteamNetworking_RetrieveData( __thinsteam_net, ##__VA_ARGS__ ) +#define sw_GetSocketInfo(...) SteamAPI_ISteamNetworking_GetSocketInfo( __thinsteam_net, ##__VA_ARGS__ ) +#define sw_GetListenSocketInfo(...) SteamAPI_ISteamNetworking_GetListenSocketInfo( __thinsteam_net, ##__VA_ARGS__ ) +#define sw_GetSocketConnectionType(...) SteamAPI_ISteamNetworking_GetSocketConnectionType( __thinsteam_net,##__VA_ARGS__ ) +#define sw_GetMaxPacketSize(...) SteamAPI_ISteamNetworking_GetMaxPacketSize( __thinsteam_net, ##__VA_ARGS__ ) + +#define _sw__fill( self, func, ... ) func( self, ##__VA_ARGS__ ) +#endif + +/*______________________________________________________________________________________________________________________________ + + WRAPPER LAYER +______________________________________________________________________________________________________________________________*/ + +ISteamFriends *__thinsteam_friends = NULL; +ISteamUser *__thinsteam_user = NULL; +ISteamUtils *__thinsteam_utils = NULL; +ISteamUserStats *__thinsteam_stats = NULL; +ISteamNetworking *__thinsteam_net = NULL; + +ISteamFriends *SteamAPI_SteamFriends_v017(); +ISteamUser *SteamAPI_SteamUser_v021(); +ISteamUtils *SteamAPI_SteamUtils_v009(); +ISteamUserStats *SteamAPI_SteamUserStats_v012(); +ISteamNetworking *SteamAPI_SteamNetworking_v006(); + +HSteamPipe g_hSteamPipe; + +GLuint get_player_image( uint64_steamid usr ) +{ + GLuint gl_img; + + uint32_t x = 64, y = 64; + int steam_image; + + steam_image = sw_GetMediumFriendAvatar( usr ); + sw_GetImageSize( steam_image, &x, &y ); + + unsigned char * img_buf = (unsigned char *)calloc( x * y * 4, 1 ); + + sw_GetImageRGBA( steam_image, img_buf, x * y * 4 ); + + glGenTextures( 1, &gl_img ); + glBindTexture( GL_TEXTURE_2D, gl_img ); + + glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, img_buf ); + glGenerateMipmap( GL_TEXTURE_2D ); + + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); + + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + + free( img_buf ); + + return gl_img; +} + +int sw_vipid( uint64_steamid usr ) +{ + static uint64_steamid massiveLEGENDS[] = + { + 76561198134179460, // Spud + 76561198020563704, // Assasssin + 76561198062961277, // lopen + 76561198084693332 // ernie + }; + + for( int i = 0; i < sizeof(massiveLEGENDS)/sizeof(massiveLEGENDS[0]); i ++ ) + { + if( massiveLEGENDS[i] == usr ) + return 1; + } + + return 0; +} + +// Initialize steamworks through this function and your appid +int sw_init( uint32_t appid ) { + +#ifdef STRUCTURE_PACK_CHECK + +// This code should never fail and if it does something went wrong with the build +// Remember to undefine STRUCTURE_PACK_CHECK for publishing!!! + +#if defined(VALVE_CALLBACK_PACK_SMALL) + if( sizeof(ValvePackingSentinel_t) != 24 ){ + printf( "Struct packing error: ValvePackingSentinel_t expected 24 got %i\nThe application is built incorrectly\n", (int)sizeof(ValvePackingSentinel_t)); + return 0; + } +#elif defined(VALVE_CALLBACK_PACK_LARGE) + if( sizeof(ValvePackingSentinel_t) != 32 ){ + printf( "Struct packing error: ValvePackingSentinel_t expected 32 got %i\nThe application is built incorrectly\n", (int)sizeof(ValvePackingSentinel_t)); + return 0; + } +#else + #error ??? +#endif + +#endif + + #ifdef STEAMWORKS_VERBOSE + printf( "Initializing steamworks..\n" ); + #endif + + if( sw_SteamAPI_RestartAppIfNecessary( appid ) == 1 ){ + #ifdef STEAMWORKS_VERBOSE + printf( "Restarting via steam\n" ); + #endif + return 0; + } + + if( !sw_SteamAPI_Init() ){ + #ifdef STEAMWORKS_VERBOSE + printf( "Steamworks connection failed\n" ); + #endif + return 0; + } + + // We are using C so we have to deal with callbacks microsoft event loop style + sw_SteamAPI_ManualDispatch_Init(); + + __thinsteam_friends = SteamAPI_SteamFriends_v017(); + __thinsteam_user = SteamAPI_SteamUser_v021(); + __thinsteam_utils = SteamAPI_SteamUtils_v009(); + __thinsteam_stats = SteamAPI_SteamUserStats_v012(); + __thinsteam_net = SteamAPI_SteamNetworking_v006(); + + // This might happen if the DLL is too old + if( !__thinsteam_friends | !__thinsteam_user | !__thinsteam_utils | !__thinsteam_stats | !__thinsteam_net ){ + #ifdef STEAMWORKS_VERBOSE + printf( "Interface hooks failed\n" ); + #endif + return 0; + } + + g_hSteamPipe = sw_SteamAPI_GetHSteamPipe(); + + #ifdef STEAMWORKS_VERBOSE + printf( "Steamworks ready\n" ); + #endif + + return 1; +} + +void sw_init_postgl() +{ + _localplayer_image = get_player_image( sw_GetSteamID() ); + strcpy( _localplayer_name, sw_GetPersonaName() ); +} + +/*______________________________________________________________________________________________________________________________ + + USER CODE +______________________________________________________________________________________________________________________________*/ + +// Macro Creates (args): +// Function(args) pointer definition +// Callback global pointer +// sw_SetCallback (*ptr) function + +#define _swCallbackPair( CNAME, ... ) \ +typedef void(*sw_##CNAME##Fun)( __VA_ARGS__ ); \ +sw_##CNAME##Fun CNAME = NULL; \ +void sw_Set##CNAME##Callback(sw_##CNAME##Fun d) { CNAME = d; } + +_swCallbackPair( OnSocketStatus, SNetSocket_t, SNetListenSocket_t, CSteamID, int ) +_swCallbackPair( OnP2PSessionConnectFail, CSteamID, EP2PSessionError_t ) +_swCallbackPair( OnP2PSessionRequest, CSteamID ) +_swCallbackPair( OnSteamJoinRequest, CSteamID, char * ) + +void sw_RunSteamEventLoop(void) +{ + sw_SteamAPI_ManualDispatch_RunFrame( g_hSteamPipe ); + CallbackMsg_t callback; + while( sw_SteamAPI_ManualDispatch_GetNextCallback( g_hSteamPipe, &callback ) ){ + + // Check for dispatching API call results + if( callback.m_iCallback == SW_CBID_SteamAPICallCompleted ){ + + SteamAPICallCompleted_t *pCallCompleted = (SteamAPICallCompleted_t *)&callback; + void *pTmpCallResult = malloc( pCallCompleted->m_cubParam ); + int bFailed; + + if( sw_SteamAPI_ManualDispatch_GetAPICallResult( g_hSteamPipe, pCallCompleted->m_hAsyncCall, pTmpCallResult, \ + pCallCompleted->m_cubParam, pCallCompleted->m_iCallback, &bFailed ) ){ + + // Dispatch the call result to the registered handler(s) for the + // call identified by pCallCompleted->m_hAsyncCall + + } + + free( pTmpCallResult ); + + } else { + + // Look at callback.m_iCallback to see what kind of callback it is, + // and dispatch to appropriate handler(s) + + vg_info( "steamworks_event::callback( %i )\n", callback.m_iCallback ); + + void *data = callback.m_pubParam; + + switch( callback.m_iCallback ){ + + case SW_CBID_P2PSessionRequest: if( OnP2PSessionRequest ) OnP2PSessionRequest( + ((P2PSessionRequest_t *)data)->m_steamIDRemote + ); break; + + case SW_CBID_SocketStatusCallback: if( OnSocketStatus ) OnSocketStatus( + ((SocketStatusCallback_t *)data)->m_hSocket, + ((SocketStatusCallback_t *)data)->m_hListenSocket, + ((SocketStatusCallback_t *)data)->m_steamIDRemote, + ((SocketStatusCallback_t *)data)->m_eSNetSocketState + ); break; + + case SW_CBID_P2PSessionConnectFail: if( OnP2PSessionConnectFail ) OnP2PSessionConnectFail( + ((P2PSessionConnectFail_t *)data)->m_steamIDRemote, + ((P2PSessionConnectFail_t *)data)->m_eP2PSessionError + ); break; + + case SW_CBID_GameRichPresenceJoinRequested: if( OnSteamJoinRequest ) OnSteamJoinRequest( + ((GameRichPresenceJoinRequested_t *)data)->m_steamIDFriend, + ((GameRichPresenceJoinRequested_t *)data)->m_rgchConnect + ); break; + + default: break; + + } + + } + + SteamAPI_ManualDispatch_FreeLastCallback( g_hSteamPipe ); + + } + +} + +/*______________________________________________________________________________________________________________________________ + + NO_STEAM +______________________________________________________________________________________________________________________________*/ + +#else // #define NO_STEAM +// In case we dont want to spam the steam servers + +char *__str_sw_unlinked = "__NO_STEAMWORKS__"; + +#define SW_BLANK_RETURN 0 + +#define sw_init( x ) 1 +#define sw_exit() +#define sw_runcallbacks() +#define sw_get_persona_name() __str_sw_unlinked +#define sw_get_steamid() SW_BLANK_RETURN +#define sw_get_friend_smallavatar( x ) SW_BLANK_RETURN +#define sw_get_friend_mediumavatar( x ) SW_BLANK_RETURN +#define sw_get_friend_largeavatar( x ) SW_BLANK_RETURN + +#define sw_get_image_size( x, y, z ) +#define sw_get_image_rgba( x, y, z ) +#define sw_set_achievement( x ) + +#endif + +#endif +