+#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
+
+// Types
+typedef void ISteamFriends;
+typedef void ISteamUserStats;
+typedef void ISteamUtils;
+typedef void ISteamUser;
+typedef void ISteamNetworking;
+
+typedef i32 HSteamPipe;
+typedef i32 HSteamUser;
+
+typedef int E_iCallBack_t;
+
+typedef u32 SNetSocket_t; // CreateP2PConnectionSocket()
+typedef u32 SNetListenSocket_t; // CreateListenSocket()
+
+typedef u64 uint64_steamid;
+typedef u64 SteamAPICall_t;
+
+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 };
+
+// Structures
+typedef struct {
+ u32 m_u32;
+ u64 m_u64;
+ u16 m_u16;
+ double m_d;
+} ValvePackingSentinel_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;
+ u32 m_cubParam;
+
+} SteamAPICallCompleted_t;
+#define SW_CBID_SteamAPICallCompleted (k_iSteamUtilsCallbacks + 3)
+
+
+#pragma pack( pop )
+
+// API
+void SteamAPI_Shutdown();
+int SteamAPI_Init();
+int SteamAPI_RestartAppIfNecessary( u32 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 );
+void SteamAPI_ReleaseCurrentThreadMemory();
+
+int SteamAPI_ISteamUserStats_SetAchievement( ISteamUserStats *self, const char *pchName );
+
+HSteamPipe SteamAPI_GetHSteamPipe();
+HSteamUser SteamAPI_GetHSteamUser();
+
+struct
+{
+ ISteamFriends *friends;
+ ISteamUser *user;
+ ISteamUserStats *stats;
+ ISteamNetworking *net;
+
+ HSteamPipe pipe;
+} steam_api_classes;
+
+ISteamFriends *SteamAPI_SteamFriends_v017();
+ISteamUser *SteamAPI_SteamUser_v021();
+ISteamUserStats *SteamAPI_SteamUserStats_v012();
+ISteamNetworking *SteamAPI_SteamNetworking_v006();
+
+static void sw_exit(void)
+{
+ SteamAPI_Shutdown();
+}
+
+static int sw_init(void)
+{
+ #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;
+ }
+ #else
+ 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;
+ }
+ #endif
+
+ vg_info( "Intializing steamworks\n" );
+
+ if( SteamAPI_RestartAppIfNecessary( VG_STEAM_APPID ) == 1 )
+ {
+ vg_info( "Restarting app via steam\n" );
+ return 0;
+ }
+
+ if( !SteamAPI_Init() )
+ {
+ vg_error( "Steamworks connection failed\n" );
+ return 0;
+ }
+
+ SteamAPI_ManualDispatch_Init();
+
+ steam_api_classes.friends = SteamAPI_SteamFriends_v017();
+ steam_api_classes.user = SteamAPI_SteamUser_v021();
+ steam_api_classes.stats = SteamAPI_SteamUserStats_v012();
+ steam_api_classes.net = SteamAPI_SteamNetworking_v006();
+
+ if( !steam_api_classes.friends || !steam_api_classes.user || !steam_api_classes.stats || !steam_api_classes.net )
+ {
+ vg_error( "Steamworks interface pointers failed. Steamworks DLL may be old\n" );
+ SteamAPI_Shutdown();
+ return 0;
+ }
+
+ steam_api_classes.pipe = SteamAPI_GetHSteamPipe();
+ vg_success( "Steamworks API running\n" );
+
+ vg_register_exit( &sw_exit, "SteamAPI" );
+ return 1;
+}
+
+static void sw_event_loop(void)
+{
+ SteamAPI_ManualDispatch_RunFrame( steam_api_classes.pipe );
+ CallbackMsg_t callback;
+
+ while( SteamAPI_ManualDispatch_GetNextCallback( steam_api_classes.pipe, &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( SteamAPI_ManualDispatch_GetAPICallResult(
+ steam_api_classes.pipe,
+ 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 )
+ {
+ default: break;
+ }
+ }
+
+ SteamAPI_ManualDispatch_FreeLastCallback( steam_api_classes.pipe );
+ }
+}
+
+static void sw_set_achievement( const char *vg_ach_name )
+{
+ struct vg_achievement *ach = NULL;
+
+ for( int i = 0; i < vg_list_size( vg_achievements ); i ++ )
+ if( !strcmp( vg_ach_name, vg_achievements[i].name ) )
+ ach = &vg_achievements[i];
+
+ if( !ach->is_set )
+ {
+ SteamAPI_ISteamUserStats_SetAchievement( steam_api_classes.stats, vg_ach_name );
+ ach->is_set = 1;
+ vg_success( "Achievement set: '%s'\n", vg_ach_name );
+ }
+}