Maelstrom: Added the Steamworks SDK to the build

From a5b739f4f217105078f334b1a8652bf42fb67103 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sun, 30 Nov 2025 18:26:25 -0800
Subject: [PATCH] Added the Steamworks SDK to the build

---
 .gitmodules                               |   3 +
 CMakeLists.txt                            |  19 ++++
 Xcode/Maelstrom.xcodeproj/project.pbxproj |  33 +++++++
 external/SteamworksSDK                    |   1 +
 game/main.cpp                             |   8 ++
 game/steam.cpp                            | 100 ++++++++++++++++++++++
 game/steam.h                              |  30 +++++++
 7 files changed, 194 insertions(+)
 create mode 160000 external/SteamworksSDK
 create mode 100644 game/steam.cpp
 create mode 100644 game/steam.h

diff --git a/.gitmodules b/.gitmodules
index 45920c96..c38f048a 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -4,3 +4,6 @@
 [submodule "external/SDL_net"]
 	path = external/SDL_net
 	url = https://github.com/libsdl-org/SDL_net
+[submodule "external/SteamworksSDK"]
+	path = external/SteamworksSDK
+	url = https://github.com/rlabrecque/SteamworksSDK
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 39511f66..f9176074 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -70,6 +70,8 @@ set(MAELSTROM_SOURCES
 	game/scores.cpp
 	game/scores.h
 	game/shinobi.h
+	game/steam.cpp
+	game/steam.h
 
 	screenlib/SDL_FrameBuf.cpp
 	screenlib/SDL_FrameBuf.h
@@ -156,6 +158,23 @@ if(NOT WIN32)
   endif()
 endif()
 
+dep_option(STEAM "Build with Steam support" ON "WIN32 OR LINUX OR MACOS" OFF)
+
+if(STEAM)
+    target_compile_definitions(Maelstrom PRIVATE ENABLE_STEAM)
+	target_include_directories(Maelstrom PRIVATE "${CMAKE_SOURCE_DIR}/external/SteamworksSDK/public")
+	if(WIN32)
+		target_link_directories(Maelstrom PRIVATE "${CMAKE_SOURCE_DIR}/external/SteamworksSDK/redistributable_bin/win64")
+		target_link_libraries(Maelstrom PRIVATE steam_api64)
+	elseif(LINUX)
+		target_link_directories(Maelstrom PRIVATE "${CMAKE_SOURCE_DIR}/external/SteamworksSDK/redistributable_bin/linux64")
+		target_link_libraries(Maelstrom PRIVATE steam_api)
+	elseif(MACOS)
+		target_link_directories(Maelstrom PRIVATE "${CMAKE_SOURCE_DIR}/external/SteamworksSDK/redistributable_bin/osx")
+		target_link_libraries(Maelstrom PRIVATE steam_api)
+	endif()
+endif()
+
 target_link_libraries(Maelstrom PRIVATE SDLmac)
 target_link_libraries(Maelstrom PRIVATE SDL3::SDL3)
 target_link_libraries(Maelstrom PRIVATE SDL3_net::SDL3_net)
diff --git a/Xcode/Maelstrom.xcodeproj/project.pbxproj b/Xcode/Maelstrom.xcodeproj/project.pbxproj
index ff16c606..a6c43670 100644
--- a/Xcode/Maelstrom.xcodeproj/project.pbxproj
+++ b/Xcode/Maelstrom.xcodeproj/project.pbxproj
@@ -60,6 +60,9 @@
 		AA928E512EDB9D830005200A /* Mac_Sound.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA928E4F2EDB9D830005200A /* Mac_Sound.cpp */; };
 		AA929E852EDBA1900005200A /* Docs in Resources */ = {isa = PBXBuildFile; fileRef = AA929E842EDBA1900005200A /* Docs */; };
 		AA929E872EDBA3B80005200A /* Data in Resources */ = {isa = PBXBuildFile; fileRef = AA929E862EDBA3B80005200A /* Data */; };
+		F3CC41422F60E6A10033BDFA /* steam.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F3CC41412F60E6A10033BDFA /* steam.cpp */; };
+		F3CC41582F610E2C0033BDFA /* libsteam_api.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = F3CC41572F610E2C0033BDFA /* libsteam_api.dylib */; platformFilters = (macos, ); };
+		F3CC415B2F610F110033BDFA /* libsteam_api.dylib in CopyFiles */ = {isa = PBXBuildFile; fileRef = F3CC41572F610E2C0033BDFA /* libsteam_api.dylib */; platformFilters = (macos, ); settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
 /* End PBXBuildFile section */
 
 /* Begin PBXCopyFilesBuildPhase section */
@@ -75,6 +78,16 @@
 			name = "Embed Frameworks";
 			runOnlyForDeploymentPostprocessing = 0;
 		};
+		F3CC415A2F610F080033BDFA /* CopyFiles */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 2147483647;
+			dstPath = "";
+			dstSubfolderSpec = 6;
+			files = (
+				F3CC415B2F610F110033BDFA /* libsteam_api.dylib in CopyFiles */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
 /* End PBXCopyFilesBuildPhase section */
 
 /* Begin PBXFileReference section */
@@ -196,6 +209,9 @@
 		AA928E4F2EDB9D830005200A /* Mac_Sound.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Mac_Sound.cpp; sourceTree = "<group>"; };
 		AA929E842EDBA1900005200A /* Docs */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Docs; path = ../Docs; sourceTree = "<group>"; };
 		AA929E862EDBA3B80005200A /* Data */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Data; path = ../Data; sourceTree = "<group>"; };
+		F3CC41402F60E6A10033BDFA /* steam.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = steam.h; sourceTree = "<group>"; };
+		F3CC41412F60E6A10033BDFA /* steam.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = steam.cpp; sourceTree = "<group>"; };
+		F3CC41572F610E2C0033BDFA /* libsteam_api.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsteam_api.dylib; path = ../external/SteamworksSDK/redistributable_bin/osx/libsteam_api.dylib; sourceTree = SOURCE_ROOT; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -203,6 +219,7 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				F3CC41582F610E2C0033BDFA /* libsteam_api.dylib in Frameworks */,
 				AA9285A42EDB9A6A0005200A /* SDL3.framework in Frameworks */,
 				AA9285A22EDB9A5D0005200A /* SDL3_net.framework in Frameworks */,
 			);
@@ -216,6 +233,7 @@
 			children = (
 				AA9284C72EDB8CEE0005200A /* SDL.xcodeproj */,
 				AA9285942EDB9A3D0005200A /* SDL_net.xcodeproj */,
+				F3CC41572F610E2C0033BDFA /* libsteam_api.dylib */,
 				AA929E862EDBA3B80005200A /* Data */,
 				AA929E842EDBA1900005200A /* Docs */,
 				AA928DB12EDB9C5F0005200A /* game */,
@@ -301,6 +319,8 @@
 				AA928DE22EDB9CA60005200A /* scores.h */,
 				AA928DE32EDB9CA60005200A /* scores.cpp */,
 				AA928DE42EDB9CA60005200A /* shinobi.h */,
+				F3CC41402F60E6A10033BDFA /* steam.h */,
+				F3CC41412F60E6A10033BDFA /* steam.cpp */,
 			);
 			name = game;
 			path = ../game;
@@ -421,6 +441,7 @@
 				AA9284B02EDB8BB30005200A /* Frameworks */,
 				AA92857A2EDB8EA00005200A /* Embed Frameworks */,
 				AA929E702EDBA0880005200A /* Resources */,
+				F3CC415A2F610F080033BDFA /* CopyFiles */,
 			);
 			buildRules = (
 			);
@@ -498,6 +519,7 @@
 				AA928DE62EDB9CA60005200A /* about.cpp in Sources */,
 				AA928DE72EDB9CA60005200A /* MaelstromUI.cpp in Sources */,
 				AA928DE82EDB9CA60005200A /* rect.cpp in Sources */,
+				F3CC41422F60E6A10033BDFA /* steam.cpp in Sources */,
 				AA928DE92EDB9CA60005200A /* netplay.cpp in Sources */,
 				AA928DEA2EDB9CA60005200A /* objects.cpp in Sources */,
 				AA928DEB2EDB9CA60005200A /* game.cpp in Sources */,
@@ -593,12 +615,19 @@
 					"DEBUG=1",
 					"$(inherited)",
 				);
+				"GCC_PREPROCESSOR_DEFINITIONS[sdk=macosx*]" = (
+					"DEBUG=1",
+					"$(inherited)",
+					ENABLE_STEAM,
+				);
 				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
 				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
 				GCC_WARN_UNDECLARED_SELECTOR = YES;
 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
 				GCC_WARN_UNUSED_FUNCTION = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
+				HEADER_SEARCH_PATHS = ../external/SteamworksSDK/public;
+				LIBRARY_SEARCH_PATHS = ../external/SteamworksSDK/redistributable_bin/osx;
 				LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
 				MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
 				MTL_FAST_MATH = YES;
@@ -648,12 +677,16 @@
 				ENABLE_USER_SCRIPT_SANDBOXING = YES;
 				GCC_C_LANGUAGE_STANDARD = gnu17;
 				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_PREPROCESSOR_DEFINITIONS = "";
+				"GCC_PREPROCESSOR_DEFINITIONS[sdk=macosx*]" = ENABLE_STEAM;
 				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
 				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
 				GCC_WARN_UNDECLARED_SELECTOR = YES;
 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
 				GCC_WARN_UNUSED_FUNCTION = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
+				HEADER_SEARCH_PATHS = ../external/SteamworksSDK/public;
+				LIBRARY_SEARCH_PATHS = ../external/SteamworksSDK/redistributable_bin/osx;
 				LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
 				MTL_ENABLE_DEBUG_INFO = NO;
 				MTL_FAST_MATH = YES;
diff --git a/external/SteamworksSDK b/external/SteamworksSDK
new file mode 160000
index 00000000..34d9338a
--- /dev/null
+++ b/external/SteamworksSDK
@@ -0,0 +1 @@
+Subproject commit 34d9338aa892213861bd9f84c4dd9c5b7fd23de7
diff --git a/game/main.cpp b/game/main.cpp
index f70c948f..4ae46bef 100644
--- a/game/main.cpp
+++ b/game/main.cpp
@@ -41,6 +41,7 @@
 #include "about.h"
 #include "game.h"
 #include "netplay.h"
+#include "steam.h"
 #include "main.h"
 
 #include "../utils/files.h"
@@ -201,6 +202,8 @@ int main(int argc, char *argv[])
 		}
 	}
 
+	InitSteam();
+
 	/* Initialize everything. :) */
 	if ( DoInitializations(window_flags) < 0 ) {
 		/* An error message was already printed */
@@ -232,10 +235,15 @@ int main(int argc, char *argv[])
 	while ( gRunning ) {
 		ShowFrame(0);
 
+		UpdateSteam();
+
 		DelayFrame();
 	}
 	CleanUp();
 #endif
+
+	QuitSteam();
+
 	return 0;
 
 }	/* -- main */
diff --git a/game/steam.cpp b/game/steam.cpp
new file mode 100644
index 00000000..27d8263e
--- /dev/null
+++ b/game/steam.cpp
@@ -0,0 +1,100 @@
+/*
+    Maelstrom: Open Source version of the classic game by Ambrosia Software
+    Copyright (C) 1997-2011  Sam Lantinga
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+
+#include "steam.h"
+
+#ifdef ENABLE_STEAM
+
+#include <SDL3/SDL.h>
+#define strncpy	SDL_strlcpy
+
+#include <steam/steam_api.h>
+
+class SteamCallbacks
+{
+public:
+	SteamCallbacks() { }
+	~SteamCallbacks() { }
+
+private:
+	STEAM_CALLBACK(SteamCallbacks, OnRemotePlaySessionConnected, SteamRemotePlaySessionConnected_t);
+	STEAM_CALLBACK(SteamCallbacks, OnRemotePlaySessionDisconnected, SteamRemotePlaySessionDisconnected_t);
+};
+static SteamCallbacks steam;
+
+void SteamCallbacks::OnRemotePlaySessionConnected(SteamRemotePlaySessionConnected_t *pParam)
+{
+}
+
+void SteamCallbacks::OnRemotePlaySessionDisconnected(SteamRemotePlaySessionDisconnected_t *pParam)
+{
+}
+
+
+bool InitSteam()
+{
+	SDL_setenv_unsafe("SteamAppId", "480", true);
+
+	SteamErrMsg error;
+	if (SteamAPI_InitEx(&error) != k_ESteamAPIInitResult_OK) {
+		SDL_Log("Couldn't initialize Steam: %s", error);
+		return false;
+	}
+
+    // Enable passing remote mouse and keyboard into our application
+    SteamRemotePlay()->BEnableRemotePlayTogetherDirectInput();
+
+	return true;
+}
+
+void UpdateSteam()
+{
+	SteamAPI_RunCallbacks();
+
+    uint32 count;
+    RemotePlayInput_t events[32];
+    while ((count = SteamRemotePlay()->GetInput(events, SDL_arraysize(events))) > 0) {
+        // Process remote input
+    }
+}
+
+void QuitSteam()
+{
+	SteamAPI_Shutdown();
+}
+
+#else
+
+bool InitSteam()
+{
+	return false;
+}
+
+void UpdateSteam()
+{
+}
+
+void QuitSteam()
+{
+}
+
+#endif // ENABLE_STEAM
diff --git a/game/steam.h b/game/steam.h
new file mode 100644
index 00000000..eccb40cf
--- /dev/null
+++ b/game/steam.h
@@ -0,0 +1,30 @@
+/*
+    Maelstrom: Open Source version of the classic game by Ambrosia Software
+    Copyright (C) 1997-2011  Sam Lantinga
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+
+#ifndef _steam_h
+#define _steam_h
+
+extern bool InitSteam();
+extern void UpdateSteam();
+extern void QuitSteam();
+
+#endif // _steam_h