Mercurial > games > semicongine
changeset 973:7fb8f62a9ea5
add: api to interact with steam
author | sam <sam@basx.dev> |
---|---|
date | Thu, 04 Apr 2024 17:21:56 +0700 |
parents | 6f71f765a546 |
children | 2a5e7b54736e |
files | libs/libsteam_api.so libs/steam_api.dll semicongine.nim semicongine/build.nim semicongine/engine.nim semicongine/steam.nim |
diffstat | 6 files changed, 102 insertions(+), 4 deletions(-) [+] |
line wrap: on
line diff
--- a/semicongine.nim Wed Apr 03 21:07:33 2024 +0700 +++ b/semicongine.nim Thu Apr 04 17:21:56 2024 +0700 @@ -17,6 +17,7 @@ import semicongine/renderer import semicongine/resources import semicongine/settings +import semicongine/steam import semicongine/text import semicongine/platform/window import semicongine/vulkan @@ -34,6 +35,7 @@ export renderer export resources export settings +export steam export text export window export vulkan
--- a/semicongine/build.nim Wed Apr 03 21:07:33 2024 +0700 +++ b/semicongine/build.nim Thu Apr 04 17:21:56 2024 +0700 @@ -9,7 +9,15 @@ const BLENDER_CONVERT_SCRIPT = currentSourcePath().parentDir().parentDir().joinPath("tools/blender_gltf_converter.py") const STEAMCMD_ZIP = currentSourcePath().parentDir().parentDir().joinPath("tools/steamcmd.zip") -const STEAM_DIR_NAME = "steam" +const STEAMBUILD_DIR_NAME = "steam" + +var STEAMLIB: string +if defined(linux): + STEAMLIB = currentSourcePath().parentDir().parentDir().joinPath("libs/libsteam_api.so") +elif defined(windows): + STEAMLIB = currentSourcePath().parentDir().parentDir().joinPath("libs/steam_api.dll") +else: + raise newException(Exception, "Unsupported platform") proc semicongine_builddir*(buildname: string, builddir = "./build"): string = var platformDir = "unkown" @@ -30,8 +38,9 @@ switch("define", "VK_USE_PLATFORM_WIN32_KHR") switch("app", "gui") switch("outdir", semicongine_builddir(buildname, builddir = builddir)) + switch("passL", "-Wl,-rpath,'$ORIGIN'") # adds directory of executable to dynlib search path -proc semicongine_pack*(outdir: string, bundleType: string, resourceRoot: string) = +proc semicongine_pack*(outdir: string, bundleType: string, resourceRoot: string, withSteam: bool) = switch("define", "PACKAGETYPE=" & bundleType) outdir.rmDir() @@ -52,6 +61,8 @@ exec &"powershell Compress-Archive * {outputfile}" elif bundleType == "exe": switch("define", "BUILD_RESOURCEROOT=" & joinPath(getCurrentDir(), resourceRoot)) # required for in-exe packing of resources, must be absolute + if withSteam: + STEAMLIB.cpFile(outdir.joinPath(STEAMLIB.extractFilename)) proc semicongine_zip*(dir: string) = withdir dir.parentDir: @@ -120,7 +131,7 @@ if not defined(linux): echo "steam uploads must be done on linux for now" return - let steamdir = thisDir().joinPath(STEAM_DIR_NAME) + let steamdir = thisDir().joinPath(STEAMBUILD_DIR_NAME) if not dirExists(steamdir): steamdir.mkDir let zipFilename = STEAMCMD_ZIP.extractFilename @@ -131,6 +142,6 @@ exec "steamcmd/steamcmd.sh +quit" # self-update steamcmd let - steamcmd = STEAM_DIR_NAME.joinPath("steamcmd").joinPath("steamcmd.sh") + steamcmd = STEAMBUILD_DIR_NAME.joinPath("steamcmd").joinPath("steamcmd.sh") scriptPath = "..".joinPath("..").joinPath(buildscript) exec &"./{steamcmd} +login \"{steamaccount}\" \"{password}\" +run_app_build {scriptPath} +quit"
--- a/semicongine/engine.nim Wed Apr 03 21:07:33 2024 +0700 +++ b/semicongine/engine.nim Thu Apr 04 17:21:56 2024 +0700 @@ -22,6 +22,8 @@ import ./text import ./panel +import ./steam + const COUNT_N_RENDERTIMES = 199 type @@ -71,6 +73,8 @@ engine.debugger.destroy() engine.window.destroy() engine.instance.destroy() + if SteamAvailable(): + SteamShutdown() proc initEngine*( @@ -86,6 +90,12 @@ echo "Set log level to ", ENGINE_LOGLEVEL setLogFilter(ENGINE_LOGLEVEL) + TrySteamInit() + if SteamAvailable(): + echo "Starting with Steam enabled" + else: + echo "Starting without Steam enabled" + result.state = Starting result.exitHandler = exitHandler result.resizeHandler = resizeHandler
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/semicongine/steam.nim Thu Apr 04 17:21:56 2024 +0700 @@ -0,0 +1,75 @@ +import std/dynlib +import std/strutils +import std/logging + +var + steam_api: LibHandle + steam_is_loaded = false + +when defined(linux): + proc dlerror(): cstring {.stdcall, importc.} + steam_api = "libsteam_api.so".loadLib() + if steam_api == nil: + echo dlerror() +elif defined(windows): + steam_api = "steam_api".loadLib() + + +# required to store reference, when calling certain APIs +type + SteamUserStatsRef = ptr object +var userStats: SteamUserStatsRef + +# load function points for steam API +var + Shutdown*: proc() {.stdcall.} + Init: proc(msg: ptr array[1024, char]): cint {.stdcall.} + SteamUserStats: proc(): SteamUserStatsRef {.stdcall.} + RequestCurrentStats: proc(self: SteamUserStatsRef): bool {.stdcall.} # needs to be called before the achievment-stuff + ClearAchievement: proc(self: SteamUserStatsRef, pchName: cstring): bool {.stdcall.} + SetAchievement: proc(self: SteamUserStatsRef, pchName: cstring): bool {.stdcall.} + StoreStats: proc(self: SteamUserStatsRef): bool {.stdcall.} # needs to be called in order for achievments to be saved + # dynlib-helper function +proc loadFunc[T](nimFunc: var T, dllFuncName: string) = + nimFunc = cast[T](steam_api.checkedSymAddr(dllFuncName)) +if steam_api != nil: + loadFunc(Init, "SteamAPI_InitFlat") + loadFunc(Shutdown, "SteamAPI_Shutdown") + loadFunc(SteamUserStats, "SteamAPI_SteamUserStats_v012") + loadFunc(RequestCurrentStats, "SteamAPI_ISteamUserStats_RequestCurrentStats") + loadFunc(ClearAchievement, "SteamAPI_ISteamUserStats_ClearAchievement") + loadFunc(SetAchievement, "SteamAPI_ISteamUserStats_SetAchievement") + loadFunc(StoreStats, "SteamAPI_ISteamUserStats_StoreStats") + + +# nice wrappers for steam API + +proc SteamRequestCurrentStats*(): bool = + RequestCurrentStats(userStats) + +proc SteamClearAchievement*(name: string): bool = + userStats.ClearAchievement(name.cstring) + +proc SteamSetAchievement*(name: string): bool = + userStats.SetAchievement(name.cstring) + +proc SteamStoreStats*(name: string): bool = + userStats.StoreStats() + +proc SteamShutdown*() = + Shutdown() + + +# helper funcs +proc SteamAvailable*(): bool = + steam_api != nil and steam_is_loaded + +# first function that should be called +proc TrySteamInit*() = + if steam_api != nil and not steam_is_loaded: + var msg: array[1024, char] + let success = Init(addr msg) == 0 + warn join(@msg, "") + if success: + userStats = SteamUserStats() + steam_is_loaded = SteamRequestCurrentStats()