X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=vg_steam.h;fp=vg_steam.h;h=b39da94fb1c0122aa06a843bf0c531ba11f7033f;hb=4c48fe01a5d1983be89b7dce6f08e6b708cfbb05;hp=0000000000000000000000000000000000000000;hpb=3dd767bb10e6fee9cbffeb185d1a9685810c17b5;p=vg.git diff --git a/vg_steam.h b/vg_steam.h new file mode 100644 index 0000000..b39da94 --- /dev/null +++ b/vg_steam.h @@ -0,0 +1,651 @@ +#ifndef VG_STEAM_H +#define VG_STEAM_H + +#include "vg.h" +#include "vg_log.h" + +/* + * TODO: Combine interfaces and stuff here instead of having them in client code + */ + +#if defined(__linux__) || defined(__APPLE__) +/* + * The 32-bit version of gcc has the alignment requirement for u64 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 +; + #pragma pack( push, 4 ) +#else + #define VALVE_CALLBACK_PACK_LARGE + #pragma pack( push, 8 ) +#endif + +typedef i32 HSteamPipe; +typedef i32 HSteamUser; + +typedef int E_iCallBack_t; + +typedef u64 u64_steamid; +typedef u64 SteamAPICall_t; + +typedef u32 AppId_t; +const AppId_t k_uAppIdInvalid = 0x0; + +typedef u32 DepotId_t; +const DepotId_t k_uDepotIdInvalid = 0x0; + +typedef u32 RTime32; + +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 }; + +// General result codes +typedef enum EResult +{ + k_EResultNone = 0, // no result + k_EResultOK = 1, // success + k_EResultFail = 2, // generic failure + k_EResultNoConnection = 3, // no/failed network connection +// k_EResultNoConnectionRetry = 4, // OBSOLETE - removed + k_EResultInvalidPassword = 5, // password/ticket is invalid + k_EResultLoggedInElsewhere = 6, // same user logged in elsewhere + k_EResultInvalidProtocolVer = 7, // protocol version is incorrect + k_EResultInvalidParam = 8, // a parameter is incorrect + k_EResultFileNotFound = 9, // file was not found + k_EResultBusy = 10, // called method busy - action not taken + k_EResultInvalidState = 11, // called object was in an invalid state + k_EResultInvalidName = 12, // name is invalid + k_EResultInvalidEmail = 13, // email is invalid + k_EResultDuplicateName = 14, // name is not unique + k_EResultAccessDenied = 15, // access is denied + k_EResultTimeout = 16, // operation timed out + k_EResultBanned = 17, // VAC2 banned + k_EResultAccountNotFound = 18, // account not found + k_EResultInvalidSteamID = 19, // steamID is invalid + k_EResultServiceUnavailable = 20,// The requested service is currently + // unavailable + k_EResultNotLoggedOn = 21, // The user is not logged on + k_EResultPending = 22, // Request is pending (may be in process, or + // waiting on third party) + k_EResultEncryptionFailure = 23, // Encryption or Decryption failed + k_EResultInsufficientPrivilege = 24,// Insufficient privilege + k_EResultLimitExceeded = 25, // Too much of a good thing + k_EResultRevoked = 26, // Access has been revoked (used for revoked + // guest passes) + k_EResultExpired = 27, // License/Guest pass the user is trying to + // access is expired + k_EResultAlreadyRedeemed = 28, // Guest pass has already been redeemed by + // account, cannot be acked again + k_EResultDuplicateRequest = 29, // The request is a duplicate and the action + // has already occurred in the past, ignored + // this time + k_EResultAlreadyOwned = 30, // All the games in this guest pass + // redemption request are already owned by + // the user + k_EResultIPNotFound = 31, // IP address not found + k_EResultPersistFailed = 32, // failed to write change to the data store + k_EResultLockingFailed = 33, // failed to acquire access lock for this + // operation + k_EResultLogonSessionReplaced = 34, + k_EResultConnectFailed = 35, + k_EResultHandshakeFailed = 36, + k_EResultIOFailure = 37, + k_EResultRemoteDisconnect = 38, + k_EResultShoppingCartNotFound = 39, // failed to find the shopping cart + // requested + k_EResultBlocked = 40, // a user didn't allow it + k_EResultIgnored = 41, // target is ignoring sender + k_EResultNoMatch = 42, // nothing matching the request found + k_EResultAccountDisabled = 43, + k_EResultServiceReadOnly = 44, // this service is not accepting content + // changes right now + k_EResultAccountNotFeatured = 45, // account doesn't have value, so this + // feature isn't available + k_EResultAdministratorOK = 46, // allowed to take this action, but only + // because requester is admin + k_EResultContentVersion = 47, // A Version mismatch in content + // transmitted within the Steam protocol. + k_EResultTryAnotherCM = 48, // The current CM can't service the user + // making a request, user should try + // another. + k_EResultPasswordRequiredToKickSession = 49, // You are already logged in + // elsewhere, this cached credential + // login has failed. + k_EResultAlreadyLoggedInElsewhere = 50, // You are already logged in + // elsewhere, you must wait + k_EResultSuspended = 51, // Long running operation (content download) + // suspended/paused + k_EResultCancelled = 52, // Operation canceled (typically by user: + // content download) + k_EResultDataCorruption = 53, // Operation canceled because data is ill + // formed or unrecoverable + k_EResultDiskFull = 54, // Operation canceled - not enough disk space. + k_EResultRemoteCallFailed = 55, // an remote call or IPC call failed + k_EResultPasswordUnset = 56, // Password could not be verified as it's + // unset server side + k_EResultExternalAccountUnlinked = 57, // External account (PSN, Facebook...) + // is not linked to a Steam account + k_EResultPSNTicketInvalid = 58, // PSN ticket was invalid + k_EResultExternalAccountAlreadyLinked = 59, // External account (PSN, + // Facebook...) is already linked to some other account, + // must explicitly request to replace/delete the link first + k_EResultRemoteFileConflict = 60, // The sync cannot resume due to a conflict + // between the local and remote files + k_EResultIllegalPassword = 61, // The requested new password is not legal + k_EResultSameAsPreviousValue = 62,// new value is the same as the old one ( + // secret question and answer ) + k_EResultAccountLogonDenied = 63, // account login denied due to 2nd factor + // authentication failure + k_EResultCannotUseOldPassword = 64, // The requested new password is not + // legal + k_EResultInvalidLoginAuthCode = 65, // account login denied due to auth code + // invalid + k_EResultAccountLogonDeniedNoMail = 66, // account login denied due to 2nd + // factor auth failure - and no mail + // has been sent + k_EResultHardwareNotCapableOfIPT = 67, + k_EResultIPTInitError = 68, + k_EResultParentalControlRestricted = 69,// operation failed due to parental + // control restrictions for current + // user + k_EResultFacebookQueryError = 70, // Facebook query returned an error + k_EResultExpiredLoginAuthCode = 71, // account login denied due to auth + // code expired + k_EResultIPLoginRestrictionFailed = 72, + k_EResultAccountLockedDown = 73, + k_EResultAccountLogonDeniedVerifiedEmailRequired = 74, + k_EResultNoMatchingURL = 75, + k_EResultBadResponse = 76, // parse failure, missing field, etc. + k_EResultRequirePasswordReEntry = 77, // The user cannot complete the action + // until they re-enter their password + k_EResultValueOutOfRange = 78, // the value entered is outside the + // acceptable range + k_EResultUnexpectedError = 79, // something happened that we didn't expect + // to ever happen + k_EResultDisabled = 80, // The requested service has been configured + // to be unavailable + k_EResultInvalidCEGSubmission = 81, // The set of files submitted to the CEG + // server are not valid ! + k_EResultRestrictedDevice = 82, // The device being used is not allowed + // to perform this action + k_EResultRegionLocked = 83, // The action could not be complete + // because it is region restricted + k_EResultRateLimitExceeded = 84, // Temporary rate limit exceeded, try + // again later, different from + // k_EResultLimitExceeded which may be + // permanent + k_EResultAccountLoginDeniedNeedTwoFactor = 85, // Need two-factor code to + // login + k_EResultItemDeleted = 86, // The thing we're trying to access has been + // deleted + k_EResultAccountLoginDeniedThrottle = 87, // login attempt failed, try to + // throttle response to possible + // attacker + k_EResultTwoFactorCodeMismatch = 88, // two factor code mismatch + k_EResultTwoFactorActivationCodeMismatch = 89, // activation code for + // two-factor didn't match + k_EResultAccountAssociatedToMultiplePartners = 90, // account has been + // associated with multiple partners + k_EResultNotModified = 91, // data not modified + k_EResultNoMobileDevice = 92, // the account does not have a mobile + // device associated with it + k_EResultTimeNotSynced = 93, // the time presented is out of range or + // tolerance + k_EResultSmsCodeFailed = 94, // SMS code failure (no match, none pending, + // etc.) + k_EResultAccountLimitExceeded = 95, // Too many accounts access this resource + k_EResultAccountActivityLimitExceeded = 96,// Too many changes to + // this account + k_EResultPhoneActivityLimitExceeded = 97, // Too many changes to this phone + k_EResultRefundToWallet = 98, // Cannot refund to payment method, must use + // wallet + k_EResultEmailSendFailure = 99, // Cannot send an email + k_EResultNotSettled = 100, // Can't perform operation till payment + // has settled + k_EResultNeedCaptcha = 101,// Needs to provide a valid captcha + k_EResultGSLTDenied = 102, // a game server login token owned by this token's + // owner has been banned + k_EResultGSOwnerDenied = 103, // game server owner is denied for other reason + // (account lock, community ban, vac ban, missing phone) + k_EResultInvalidItemType = 104,// the type of thing we were requested to act + // on is invalid + k_EResultIPBanned = 105,// the ip address has been banned from taking this + // action + k_EResultGSLTExpired = 106,// this token has expired from disuse; can be + // reset for use + k_EResultInsufficientFunds = 107,// user doesn't have enough wallet funds to + // complete the action + k_EResultTooManyPending = 108, // There are too many of this thing pending + // already + k_EResultNoSiteLicensesFound = 109, // No site licenses found + k_EResultWGNetworkSendExceeded = 110,// the WG couldn't send a response + // because we exceeded max network send size + k_EResultAccountNotFriends = 111, // the user is not mutually friends + k_EResultLimitedUserAccount = 112,// the user is limited + k_EResultCantRemoveItem = 113, // item can't be removed + k_EResultAccountDeleted = 114, // account has been deleted + k_EResultExistingUserCancelledLicense = 115, + // A license for this already exists, but cancelled + k_EResultCommunityCooldown = 116, // access is denied because of a + // community cooldown (probably from support profile data resets) + k_EResultNoLauncherSpecified = 117, // No launcher was specified, but a + // launcher was needed to choose correct realm for operation. + k_EResultMustAgreeToSSA = 118,// User must agree to china SSA or global SSA + // before login + k_EResultLauncherMigrated = 119, // The specified launcher type is no longer + // supported; the user should be directed elsewhere + k_EResultSteamRealmMismatch = 120, // The user's realm does not match the + // realm of the requested resource + k_EResultInvalidSignature = 121, // signature check did not match + k_EResultParseFailure = 122, // Failed to parse input + k_EResultNoVerifiedPhone = 123, // account does not have a verified phone + // number +} EResult; + +typedef struct { + + HSteamUser m_hSteamUser; // Specific user to whom this callback applies. + int m_iCallback; + u8 *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; + u32 m_cubParam; + +} SteamAPICallCompleted_t; + +enum { k_iSteamAPICallCompleted = k_iSteamUtilsCallbacks + 3 }; + +// 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; + +struct SteamIDComponent_t +{ +#ifdef VALVE_BIG_ENDIAN + EUniverse_t m_EUniverse : 8 + unsigned int m_EAccountType : 4; + unsigned int m_unAccountInstance : 20; + u32 m_unAccountID : 32; +#else + u32 m_unAccountID : 32; + unsigned int m_unAccountInstance : 20; + unsigned int m_EAccountType : 4; + EUniverse_t m_EUniverse : 8; +#endif +}; + +typedef struct +{ + // 64 bits total + union + { + struct SteamIDComponent_t m_comp; + u64 m_unAll64Bits; + }; +} +CSteamID; + +typedef struct GameID_t +{ +#ifdef VALVE_BIG_ENDIAN + unsigned int m_nModID : 32; + unsigned int m_nType : 8; + unsigned int m_nAppID : 24; +#else + unsigned int m_nAppID : 24; + unsigned int m_nType : 8; + unsigned int m_nModID : 32; +#endif +} CGameID; + +#pragma pack( pop ) + +/* + * Standard login + * ============================================================================= + */ + +int SteamAPI_RestartAppIfNecessary( u32 unOwnAppID ); +int SteamAPI_Init(void); +void SteamAPI_Shutdown(void); + +/* + * Server mode login + * ============================================================================= + */ + +typedef enum EServerMode EServerMode; +enum EServerMode +{ + eServerModeInvalid = 0, + eServerModeNoAuthentication = 1, + eServerModeAuthentication = 2, + eServerModeAuthenticationAndSecure = 3, +}; + +int SteamInternal_GameServer_Init( u32 unIP, u16 usLegacySteamPort, + u16 usGamePort, u16 usQueryPort, + EServerMode eServerMode, + const char *pchVersionString ); + +/* Initialize SteamGameServer client and interface objects, and set server + * properties which may not be changed. + * After calling this function, you should set any additional server parameters, + * and then call ISteamGameServer::LogOnAnonymous() or ISteamGameServer::LogOn() + * + * - unIP will usually be zero. If you are on a machine with multiple IP + * addresses, you can pass a non-zero value here and the relevant sockets will + * be bound to that IP. This can be used to ensure that the IP you desire is + * the one used in the server browser. + * - usGamePort is the port that clients will connect to for gameplay. You will + * usually open up your own socket bound to this port. + * - usQueryPort is the port that will manage server browser related duties and + * info pings from clients. If you pass STEAMGAMESERVER_QUERY_PORT_SHARED for + * usQueryPort, then it will use "GameSocketShare" mode, which means that the + * game is responsible for sending and receiving UDP packets for the master + * server updater. (See ISteamGameServer::HandleIncomingPacket and + * ISteamGameServer::GetNextOutgoingPacket.) + * - The version string should be in the form x.x.x.x, and is used by the master + * server to detect when the server is out of date. (Only servers with the + * latest version will be listed.) + */ +int SteamGameServer_Init( u32 unIP, u16 usGamePort, u16 usQueryPort, + EServerMode eServerMode, + const char *pchVersionString ) +{ + return SteamInternal_GameServer_Init( unIP, 0, usGamePort, usQueryPort, + eServerMode, pchVersionString ); +} + + +void *SteamAPI_SteamGameServer_v014(void); +void *SteamAPI_SteamGameServer(void) +{ + return SteamAPI_SteamGameServer_v014(); +} + +void SteamAPI_ISteamGameServer_LogOnAnonymous( void* self ); + +void SteamGameServer_Shutdown(void); + +int SteamGameServer_BSecure(void); +u64 SteamGameServer_GetSteamID(void); + +/* + * Async callbacks + * ============================================================================= + */ +typedef struct steam_async steam_async; +struct steam_async +{ + SteamAPICall_t id; + void *data; + + void (*p_handler)( void *result, void *userdata ); +} +static steam_async_trackers[32]; +static u32 steam_async_track_count; + +steam_async *steam_new_async(void) +{ + if( steam_async_track_count == vg_list_size(steam_async_trackers) ) + { + vg_error( "Maximum concurrent API calls exceeded (%u)\n", + steam_async_track_count ); + return NULL; + } + + return &steam_async_trackers[ steam_async_track_count ++ ]; +} + +/* + * Regular callbacks + * ============================================================================= + */ + +typedef struct steam_callback_handler steam_callback_handler; +struct steam_callback_handler +{ + u32 callback_id; + void (*p_handler)( CallbackMsg_t *msg ); +} +static steam_callback_handlers[64]; +static u32 steam_callback_handler_count; + +static int steam_register_callback( u32 id, + void (*p_handler)( CallbackMsg_t *msg ) ) +{ + if( steam_callback_handler_count == vg_list_size(steam_callback_handlers) ) + { + vg_error( "Too many steam callback handlers registered (%u)\n", + steam_callback_handler_count ); + + return 0; + } + + steam_callback_handler *handler = &steam_callback_handlers[ + steam_callback_handler_count ++ ]; + + handler->p_handler = p_handler; + handler->callback_id = id; + + return 1; +} + +/* + * Event loop + * ============================================================================= + */ +HSteamPipe SteamAPI_GetHSteamPipe(void); +HSteamPipe SteamGameServer_GetHSteamPipe(void); +HSteamUser SteamAPI_GetHSteamUser(void); +void SteamAPI_ManualDispatch_Init(void); +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 ); + +void SteamAPI_ReleaseCurrentThreadMemory(void); + +static void steamworks_process_api_call( HSteamPipe pipe, + CallbackMsg_t *callback ) +{ + SteamAPICallCompleted_t *pCallCompleted = + (SteamAPICallCompleted_t *)callback->m_pubParam; + + int bFailed; + + void *temp = alloca( pCallCompleted->m_cubParam ); + + if( SteamAPI_ManualDispatch_GetAPICallResult( + pipe, + pCallCompleted->m_hAsyncCall, + temp, + pCallCompleted->m_cubParam, + pCallCompleted->m_iCallback, + &bFailed ) + ) + { + /* + * Dispatch the call result to the registered handler(s) for the + * call identified by pCallCompleted->m_hAsyncCall + */ + + vg_info( "steamworks_event::api_call_completed( %lu )\n", + pCallCompleted->m_hAsyncCall ); + + int j=0; + for( int i=0; im_hAsyncCall ) + { + steam_async_trackers[j ++] = steam_async_trackers[i]; + } + else + { + steam_async *pasync = &steam_async_trackers[j]; + pasync->p_handler( temp, pasync->data ); + } + } + + if( steam_async_track_count == j ) + { + vg_error( "No tracker was register for API call\n" ); + } + + steam_async_track_count = j; + } + else + { +#if 0 + typedef enum ESteamAPICallFailure + { + k_ESteamAPICallFailureNone = -1, + k_ESteamAPICallFailureSteamGone = 0, + k_ESteamAPICallFailureNetworkFailure = 1, + k_ESteamAPICallFailureInvalidHandle = 2, + k_ESteamAPICallFailureMismatchedCallback = 3, + } + + ESteamAPICallFailure; + ESteamAPICallFailure fail_why = + SteamAPI_ISteamUtils_GetAPICallFailureReason( + steam_api_classes.utils, pCallCompleted->m_hAsyncCall ); + + vg_error( "steamworks_event: error getting call result on" + "%lu (code %d)\n", + pCallCompleted->m_hAsyncCall, fail_why ); +#endif + } +} + +static void steamworks_event_loop( HSteamPipe pipe ) +{ + SteamAPI_ManualDispatch_RunFrame( pipe ); + CallbackMsg_t callback; + + while( SteamAPI_ManualDispatch_GetNextCallback( pipe, &callback ) ) + { + vg_low( "steamworks_event::callback( %i )\n", callback.m_iCallback ); + + /* Check for dispatching API call results */ + if( callback.m_iCallback == k_iSteamAPICallCompleted ) + { + steamworks_process_api_call( pipe, &callback ); + } + else + { + /* + * Look at callback.m_iCallback to see what kind of callback it is, + * and dispatch to appropriate handler(s) + * void *data = callback.m_pubParam; + */ + + for( int i=0; icallback_id == callback.m_iCallback ) + { + handler->p_handler( &callback ); + break; + } + } + } + + SteamAPI_ManualDispatch_FreeLastCallback( pipe ); + } +} + +/* + * This is required to run the server outside of steamcmd environment. + * It can be any appid but idealy the one that is actually your game + */ +static void steamworks_ensure_txt( const char *appid_str ) +{ + FILE *txt = fopen("steam_appid.txt", "w"); + fputs( appid_str, txt ); + fclose( txt ); +} + +#endif /* VG_STEAM_H */