Created
September 22, 2019 13:08
-
-
Save silbinarywolf/18bd9bdcb5e9a113d6661eea17143ac4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// +build windows | |
package steamworks | |
import ( | |
"log" | |
"syscall" | |
"unsafe" | |
) | |
var ( | |
steamClientInterfaceVersion = []byte("SteamClient017\x00") | |
steamUserStatsInterfaceVersion = []byte("STEAMUSERSTATS_INTERFACE_VERSION011\x00") | |
) | |
var ( | |
steamUser int32 | |
steamPipe int32 | |
steamClient uintptr | |
steamUserStats uintptr | |
) | |
var ( | |
// DLL | |
steamApi syscall.Handle | |
// GetProcAddress | |
isSteamRunning uintptr | |
runCallbacks uintptr | |
steamInternal_CreateInterface uintptr | |
iSteamUserStats_SetAchievement uintptr | |
iSteamUserStats_ClearAchievement uintptr | |
) | |
func lazyInit() { | |
if steamApi == 0 { | |
steamApi, _ = syscall.LoadLibrary("steam_api64.dll") | |
isSteamRunning, _ = syscall.GetProcAddress(steamApi, "SteamAPI_IsSteamRunning") | |
runCallbacks, _ = syscall.GetProcAddress(steamApi, "SteamAPI_RunCallbacks") | |
steamInternal_CreateInterface, _ = syscall.GetProcAddress(steamApi, "SteamInternal_CreateInterface") | |
iSteamUserStats_SetAchievement, _ = syscall.GetProcAddress(steamApi, "SteamAPI_ISteamUserStats_SetAchievement") | |
iSteamUserStats_ClearAchievement, _ = syscall.GetProcAddress(steamApi, "SteamAPI_ISteamUserStats_ClearAchievement") | |
} | |
} | |
func IsSteamRunning() bool { | |
ret, _, callErr := syscall.Syscall(uintptr(isSteamRunning), 0, 0, 0, 0) | |
if callErr != 0 { | |
log.Fatalln(callErr.Error()) | |
} | |
return int(ret) == 1 | |
} | |
func RunCallbacks() error { | |
if _, _, callErr := syscall.Syscall(uintptr(runCallbacks), 0, 0, 0, 0); callErr != 0 { | |
return callErr | |
} | |
return nil | |
} | |
func RestartAppIfNecessary(appId uint32) bool { | |
lazyInit() | |
restartAppIfNecessary, _ := syscall.GetProcAddress(steamApi, "SteamAPI_RestartAppIfNecessary") | |
const nargs = 1 | |
ret, _, callErr := syscall.Syscall6( | |
uintptr(restartAppIfNecessary), | |
nargs, | |
uintptr(appId), | |
0, | |
0, | |
0, | |
0, | |
0, | |
) | |
if callErr != 0 { | |
log.Fatalln(callErr) | |
} | |
return ret == 1 | |
} | |
func Init() bool { | |
// TODO(Jake): 2019-09-22 | |
// Add guards to prevent calling more than once | |
lazyInit() | |
steamApiInit, _ := syscall.GetProcAddress(steamApi, "SteamAPI_Init") | |
const nargs = 0 | |
ret, _, callErr := syscall.Syscall( | |
uintptr(steamApiInit), | |
nargs, | |
0, | |
0, | |
0, | |
) | |
if callErr != 0 { | |
log.Fatalln(callErr) | |
} | |
switch ret { | |
case 0: | |
return false | |
case 1: | |
// ignore and continue loading | |
default: | |
log.Fatalf("Invalid return code: %v\n", ret) | |
} | |
// Initialize | |
steamUser = getHSteamUser() | |
steamPipe = getHSteamPipe() | |
steamClient = createInterface(steamClientInterfaceVersion) | |
steamUserStats = getISteamUserStats(steamClient, steamUser, steamPipe, steamUserStatsInterfaceVersion) | |
return true | |
} | |
func SetAchievement(name string) bool { | |
nameNullTerminated := []byte(name + "\x00") | |
const nargs = 2 | |
ret, _, callErr := syscall.Syscall6( | |
iSteamUserStats_SetAchievement, | |
nargs, | |
steamUserStats, | |
uintptr(unsafe.Pointer(&nameNullTerminated[0])), | |
0, | |
0, | |
0, | |
0, | |
) | |
if callErr != 0 { | |
log.Fatalln("SetAchievement: " + callErr.Error()) | |
} | |
switch ret { | |
case 0: | |
return false | |
case 1: | |
return true | |
default: | |
// This can occur if "steamUserStats" is invalid | |
log.Fatalf("SetAchievement: Bad return value: %v\n", ret) | |
} | |
return false | |
} | |
func ClearAchievement(name string) bool { | |
nameNullTerminated := []byte(name + "\x00") | |
const nargs = 2 | |
ret, _, callErr := syscall.Syscall6( | |
iSteamUserStats_ClearAchievement, | |
nargs, | |
steamUserStats, | |
uintptr(unsafe.Pointer(&nameNullTerminated[0])), | |
0, | |
0, | |
0, | |
0, | |
) | |
if callErr != 0 { | |
log.Fatalln("ClearAchievement: " + callErr.Error()) | |
} | |
switch ret { | |
case 0: | |
return false | |
case 1: | |
return true | |
default: | |
// This can occur if "steamUserStats" is invalid | |
log.Fatalf("ClearAchievement: Bad return value: %v\n", ret) | |
} | |
return false | |
} | |
func createInterface(name []byte) uintptr { | |
const nargs = 1 | |
res, _, callErr := syscall.Syscall( | |
steamInternal_CreateInterface, | |
nargs, | |
uintptr(unsafe.Pointer(&name[0])), | |
0, | |
0, | |
) | |
if callErr != 0 { | |
log.Fatalln("createInterface: " + callErr.Error()) | |
} | |
return res | |
} | |
// getHSteamUser number, starting at 1 | |
func getHSteamUser() int32 { | |
steamAPI_GetHSteamUser, _ := syscall.GetProcAddress(steamApi, "SteamAPI_GetHSteamUser") | |
const nargs = 0 | |
ret, _, callErr := syscall.Syscall( | |
steamAPI_GetHSteamUser, | |
nargs, | |
0, | |
0, | |
0, | |
) | |
if callErr != 0 { | |
log.Fatalln("getHSteamUser: " + callErr.Error()) | |
} | |
return int32(ret) | |
} | |
// getHSteamPipe number, starting at 1 | |
func getHSteamPipe() int32 { | |
steamAPI_GetHSteamPipe, _ := syscall.GetProcAddress(steamApi, "SteamAPI_GetHSteamPipe") | |
const nargs = 0 | |
ret, _, callErr := syscall.Syscall6( | |
steamAPI_GetHSteamPipe, | |
nargs, | |
0, | |
0, | |
0, | |
0, | |
0, | |
0, | |
) | |
if callErr != 0 { | |
log.Fatalln("getHSteamPipe: " + callErr.Error()) | |
} | |
return int32(ret) | |
} | |
func getISteamUserStats(instancePtr uintptr, steamUser int32, steamPipe int32, version []byte) uintptr { | |
steamAPI_ISteamClient_GetISteamUserStats, _ := syscall.GetProcAddress(steamApi, "SteamAPI_ISteamClient_GetISteamUserStats") | |
const nargs = 4 | |
ret, _, callErr := syscall.Syscall6( | |
steamAPI_ISteamClient_GetISteamUserStats, | |
nargs, | |
instancePtr, | |
uintptr(steamUser), | |
uintptr(steamPipe), | |
uintptr(unsafe.Pointer(&version[0])), | |
0, | |
0, | |
) | |
if callErr != 0 { | |
log.Fatalln("getHSteamPipe: " + callErr.Error()) | |
} | |
return ret | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment