From 441a7a3cf52566b445fd166dcff1c3af4ca584b8 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Tue, 2 Dec 2025 09:47:33 -0800
Subject: [PATCH] Added support for Steam Remote Play Together input
---
Data/Images/control1.png | Bin 2496 -> 0 bytes
Data/Images/{control31.png => control15.png} | Bin
Data/Images/control16.png | Bin 0 -> 1340 bytes
Data/Images/control32.png | Bin 3167 -> 1353 bytes
Data/Images/control64.png | Bin 0 -> 3167 bytes
Data/UI/lobby.xml | 4 +-
external/SDL | 2 +-
game/Maelstrom_Globals.h | 1 +
game/controls.cpp | 150 ++++----
game/game.cpp | 7 +-
game/gameinfo.cpp | 2 +-
game/gameinfo.h | 10 +-
game/lobby.cpp | 24 +-
game/main.cpp | 6 +-
game/scores.cpp | 2 +-
game/steam.cpp | 358 +++++++++++++++++--
game/steam.h | 11 +
utils/array.h | 16 +-
18 files changed, 488 insertions(+), 105 deletions(-)
delete mode 100644 Data/Images/control1.png
rename Data/Images/{control31.png => control15.png} (100%)
create mode 100755 Data/Images/control16.png
mode change 100644 => 100755 Data/Images/control32.png
create mode 100644 Data/Images/control64.png
diff --git a/Data/Images/control1.png b/Data/Images/control1.png
deleted file mode 100644
index b482ebb41a84075e449cc67cf41ffc035c81cb04..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 2496
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
KMNUMnLSTXyajw|_
diff --git a/Data/Images/control31.png b/Data/Images/control15.png
similarity index 100%
rename from Data/Images/control31.png
rename to Data/Images/control15.png
diff --git a/Data/Images/control16.png b/Data/Images/control16.png
new file mode 100755
index 0000000000000000000000000000000000000000..c0561b6b1ee77ddc24f3dd6500b9cfd2e31f7e3b
GIT binary patch
literal 1340
zcmV-C1;hG@P)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ00001b5ch_0olnc
ze*gdg1ZP1_K>z@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF*
zm;eA5aGbhPJOBUy32;bRa{vGf6951U69E94oEQKA00(qQO+^Rk3<d`o0~$iS5C8xK
zl1W5CR9M69n9EDDTNK70yTAuspau;h8W;!#H7Eihf@l`uAp8@WL<47vMOP}ijG9D5
zMMPy}QiBqM1_cc&3JS?213`@pGt#omte$UhjxW8(`&Wn4;4Ih!*Iw`1Kh|aM?Us-v
zevo9~hslov%1UNH5?-$tE|&{FpAVr>D7^);vXGyjkK*ED6c-mGGcz;kf^o&|c2lKN
z5x}<$rBccB^YcVYGA_{L<0D&ITD}b?GGsCtola-^K+DU^QO@*wJ&%r#I504f(&AH7
zQ`G5nluD%{eMd(}dO)wQuawK>Q46@;Zj$82#zs<@!NEbnpI)zzn!mojjtLaA%bZRp
z4h{~!)GdKP0Ff>3>FFtI-fFd`-esSSx3{-ZR#pZ8C@d@l0Mymh!EUz$05&%_p;D;?
z`>ClZ6ciLdtJOjxk)WWU02+-3)6>()&CP{ct;W^W6^@RM(Ae0RT9;|HS|PM9mn&gc
zm`o<YwyUd4(66kl2>Sm1enG#uxJUr3s;Xi*9FFoA6`^1-h>3{_;rH(DE=o&F0RS~M
zHOR@yfy3c|!{Gn`93CEu()981fsBj{JU>4R`cNnYl8{Iwg5GR4!|8NFDwQUV(An8p
z+(L~MqS0uKYopa_IW{&%0GyqjrNLmJOeSMjR~JV{MntwoqcM4xnayVQ_V%*2w)T&J
zB4cQ1NbtG3x*F4_v$HdKmsM6)qOY$H2L}gmxm;LYUPePh0|4Oo_!wrh85WBrX_xu^
zexb|!et%4xnVA^`gTdG-J2^RFU0og9+uJ!gImw-!9p2sD3H#F4))uR)tJB(*)oL||
zhK3T_SS*&<DLXkiiTOcKPY*9HE=ZF1_xBtg9{$#&M6cJ!uc2@_%-h>rS}YbWEiF-@
zPzWE6j*imj^YQ)tooj1r-v-py)|T2?76IJf-=|WkBmg!vG|*<Vkt97H58ZBe(s6uz
zoD|CE^Q8t9k>}@U&dkgZ082_rXf~Ufj_7o{gg~GD2|yl?hx_~cyu7?*C=`n6czb(W
zxI)<N_LPA_p%7bJTjK(qo}MNyYMD&Nxw$!dz23M-g;J?xAP`6y%IS2nq@*MYroO(O
zkB^VhKyJ62dcB^5gM%z8Dk1<@R8(+pZ%^d-<Ku(l<KqOtxw*NtQg?QCCe$MUYBZXt
zvl8)ciw1*%d3kvRK$FQNntynBpj<9zUS6JXM@m(~;V^G*ZbXHga+ld`HeoaToM)2U
z+}tDpE-WnYI|ZqP833D`oB8zgB<THqKZ}ZrD3{A)UL%q&{CC<C0{MJCTCLWoE}NX3
zBmnO0?1=PzeSHML%gf6@f{6u`@%b=RC=@6!FGqKGx9GfUZf*tutgo+&^tH9M!j(52
zN%-$QLT0sEMdZO?P(<F;)I<QH=$)RP5&-At=f5pwLWHDJDKr`l06?eH;n%NUBJi4;
z8UVn<!-Js9$;pY*eN`m?eEoQNd5MCFTu<NL-jJJ{i>$1_ZoY4CZwLee$j;6d;8I>#
yB8izk$$#}66A$SB=a?@)$NXCouTp+ognk2eGNvPE-EY?b0000<MNUMnLSTZJTwmk>
literal 0
HcmV?d00001
diff --git a/Data/Images/control32.png b/Data/Images/control32.png
old mode 100644
new mode 100755
index 1f0858ded0de399ed4d2710a1c0b560b0c584c41..ad1cad6b88dc1da17323a4e7131e13ecbbc5c783
GIT binary patch
delta 1273
zcmV<V1P1%x7|9BdBpLy8Qb$4o*~u(_00004XF*Lt006O%3;baPks&XUVibP>2XskI
zMF;5&1_v1ycb{1M000D^Nkl<ZSi{Yj%S&=y6viLBzzbc#1`R?Q7zhP5C;}mZXcp2S
z{1ci)180dvS1P)UnnXlJL}g@Ag9?KN1q~_+3ehA3L5++qq-B{|J>THNL#N~Qef!?8
z1$*E+>#Y5A?X~t^XUj+uKS+Pl@WbTC0c9jIAc@=CTX;Mk_<TNuLZQ?q$jCr$ZY~N6
z3Q$l`fb{hAgcHUTuh&bRPDcRWGPGJPPft(dP05%*kB^URXlVF0n8;A6RCK%DsRJ!6
zEJ&Q0OeP*49<sN$H>t_T$H!?j8mUw&Mf%p(*3^JrUtg(Kt0fb7y<UHk<l5R=LYTh3
zKEa>KWRg6;yu6GG6t&9SZa4P#_y4F`0)YS`TinyrljOPGZco0-J{xasZK0^B2mp|m
zmj?i-s;Yw1=>!0*udhR=(+T$D<KvLa<uDiwkjZ3_%jMAP^_ZBLKz4RET3T9gadCme
z!$Z{8)+SeF27^Het;c`kiCYzBvstihZ*Ld$i;IhbzNe>0(9g}y5dh1|$`}rZCH^E4
z3I>B19UT>Z@9gZLu&@vSP*G8VtgI}!TrRj=E&#y6!GUO*K0ZE>mX?O+=Vw753WY!t
zGMP-!TPzm1-EJtA%J>noTCFh?HIj%M8yhig3<d*-hldG(Q&WFaTwY$LN~L0ZdpidQ
z2Sv6U8yktM%wn;ytE-EZm6g8*6dC>f{esV>rKPAgZEbCdtE{xN6y4q3*x%oW$K%1m
z!UAe)Y5)L7M@O(&EU?*Z39HQS_X}0#_xq#TOioTB7z{>Vvg6}pR#jE8xw)BRV`JRj
z-sauiov<%$Zf<|Fyu3W6UAd*Dh5h~gacyiiTl6J6K0c26LT6_u&(6+BlK1!b92gk*
z)}zE^GR4lJa5&7Hn;Y6}HqOt_v%bDwcyVZGh(4c>@9*ziSy}lupr)p#<j%4P;NIRI
zwOTC!u%@Pl4u^vzd3}9Nuh*M!9334cg!1`($pJ;=`T2jDlarGKK!rj<i^alJ#Ar0e
z1^Vny0J^@u=HA{O&(F^p3WcIN-rCv{S_r4pnKV!+6k=mzV@#lvlau&Ktx~BtJw46a
z+uN8&g;uL&AP`6z%I$Vjp-@O*s;jH{`1mLV@_M~AnM~~K>tlX?J^`?#q=dV>yCTOQ
zA0HeU86kfFPESv#v~*UhRmevG)a&(<vl6ko#pUH?=H%oM0L^Bz==sCL1J!CZb8>Qo
z9w}J~hr_(Ox)LRF(pBbgIE2mc^E#8{`uaKnaCUZ<-zi8Y%mAp-X!!K>B<THqKlAhR
zsaC6_wh?hB{gOv9fqXt6?RLAQ%ErdV2!Pw$+aiB`cXu}d@cjHdC75V%lEc;S_oKeP
z9>vAQ=;-JWop&0I1^}?Sx+>CFR#plvZ?cl`%RNG7x7$Tw3<iUue^OUhM*yPeot&Hy
z0B2@qem`eoMM$YsLa)~Y0E|W>e*O9-0<Wm3002BZJP5k1tSpHx6_LqglBmhP-hRBi
zyhu@CBJJth+Z(d8vyqYUZ|D2=_J%+pfXvKH0q##=q5}O5i3Rh&+<wG^N$U3FzXtnS
jeSaM&QHK1u3#)$s(iy2M5C+yz00000NkvXXu0mjfq$_N2
delta 3121
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
LNkvXXu0mjfJsvDS
diff --git a/Data/Images/control64.png b/Data/Images/control64.png
new file mode 100644
index 0000000000000000000000000000000000000000..1f0858ded0de399ed4d2710a1c0b560b0c584c41
GIT binary patch
literal 3167
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
FV1fe5ERz5L
literal 0
HcmV?d00001
diff --git a/Data/UI/lobby.xml b/Data/UI/lobby.xml
index 191dbf90..ba830640 100644
--- a/Data/UI/lobby.xml
+++ b/Data/UI/lobby.xml
@@ -263,12 +263,14 @@
<DialogContainer name="control_dropdown" border="true" show="false">
<Elements>
<Button name="control0" image="control0"/>
- <Button name="control31" image="control31"/>
+ <Button name="control15" image="control15"/>
<Button name="control1" image="control1"/>
<Button name="control2" image="control2"/>
<Button name="control4" image="control4"/>
<Button name="control8" image="control8"/>
+ <Button name="control16" image="control16"/>
<Button name="control32" image="control32"/>
+ <Button name="control64" image="control64"/>
</Elements>
</DialogContainer>
diff --git a/external/SDL b/external/SDL
index 61bf7087..d780fa14 160000
--- a/external/SDL
+++ b/external/SDL
@@ -1 +1 @@
-Subproject commit 61bf7087f5ad4f1fdd418e58adc023fd8252e678
+Subproject commit d780fa144a58d76328edd52bd9bef73a4469044a
diff --git a/game/Maelstrom_Globals.h b/game/Maelstrom_Globals.h
index 129e53c6..1d471c44 100644
--- a/game/Maelstrom_Globals.h
+++ b/game/Maelstrom_Globals.h
@@ -42,6 +42,7 @@
#include "scores.h"
#include "controls.h"
#include "gameinfo.h"
+#include "steam.h"
// Preferences keys
#define PREFERENCES_RESOLUTION "Resolution"
diff --git a/game/controls.cpp b/game/controls.cpp
index 21e22de0..1dd2a4d3 100644
--- a/game/controls.cpp
+++ b/game/controls.cpp
@@ -241,29 +241,34 @@ static Uint8 joystickMasks[MAX_JOYSTICKS] = {
CONTROL_JOYSTICK2,
CONTROL_JOYSTICK3
};
-static SDL_Gamepad *joysticks[MAX_JOYSTICKS];
-static SDL_JoystickID joystickIDs[MAX_JOYSTICKS];
+struct Gamepad {
+ SDL_JoystickID id;
+ SDL_Gamepad *gamepad;
+ RemotePlaySessionID_t sessionID;
+};
+static array<Gamepad> gamepads;
-static void OpenJoystick(SDL_JoystickID id)
+static void OpenGamepad(SDL_JoystickID id)
{
- for (int i = 0; i < MAX_JOYSTICKS; ++i) {
- if (joysticks[i] == NULL) {
- joysticks[i] = SDL_OpenGamepad(id);
- if (joysticks[i]) {
- joystickIDs[i] = id;
- }
- break;
- }
+ Gamepad gamepad;
+
+ gamepad.id = id;
+ gamepad.gamepad = SDL_OpenGamepad(id);
+ if (!gamepad.gamepad) {
+ return;
}
+ gamepad.sessionID = GetRemoteSessionForGamepad(gamepad.gamepad);
+
+ gamepads.add(gamepad);
}
-static void CloseJoystick(SDL_JoystickID id)
+static void CloseGamepad(SDL_JoystickID id)
{
- for (int i = 0; i < MAX_JOYSTICKS; ++i) {
- if (joystickIDs[i] == id) {
- SDL_CloseGamepad(joysticks[i]);
- joysticks[i] = NULL;
- joystickIDs[i] = 0;
+ for (unsigned int i = 0; i < gamepads.length(); ++i) {
+ Gamepad *gamepad = &gamepads[i];
+ if (gamepad->id == id) {
+ SDL_CloseGamepad(gamepad->gamepad);
+ gamepads.removeAt(i);
break;
}
}
@@ -271,9 +276,19 @@ static void CloseJoystick(SDL_JoystickID id)
static Player *GetJoystickPlayer(SDL_JoystickID id)
{
- for (int i = 0; i < MAX_JOYSTICKS; ++i) {
- if (id == joystickIDs[i]) {
- return GetControlPlayer(joystickMasks[i]);
+ int joystick_index = 0;
+ for (unsigned int i = 0; i < gamepads.length(); ++i) {
+ Gamepad *gamepad = &gamepads[i];
+ if (gamepad->id == id) {
+ if (gamepad->sessionID) {
+ return GetControlPlayer(GetRemoteSessionControl(gamepad->sessionID));
+ } else {
+ return GetControlPlayer(joystickMasks[joystick_index]);
+ }
+ }
+
+ if (!gamepad->sessionID) {
+ ++joystick_index;
}
}
return NULL;
@@ -281,51 +296,57 @@ static Player *GetJoystickPlayer(SDL_JoystickID id)
static void UpdateControl(Player *player)
{
+ const Uint8 controlType = player->GetControlType();
bool keys[FIRE_KEY+1];
SDL_zeroa(keys);
- for (int i = 0; i < MAX_JOYSTICKS; ++i) {
- SDL_Gamepad *gamepad = joysticks[i];
- if (!gamepad) {
- continue;
- }
- if (!(player->GetControlType() & joystickMasks[i])) {
- continue;
- }
+ int joystick_index = 0;
+ for (unsigned int i = 0; i < gamepads.length(); ++i) {
+ Gamepad *gamepad = &gamepads[i];
+ if ((gamepad->sessionID && (controlType & GetRemoteSessionControl(gamepad->sessionID))) ||
+ (!gamepad->sessionID && (controlType & joystickMasks[joystick_index]))) {
+ if (SDL_GetGamepadButton(gamepad->gamepad, SDL_GAMEPAD_BUTTON_SOUTH) ||
+ SDL_GetGamepadAxis(gamepad->gamepad, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER) >= 8000) {
+ keys[FIRE_KEY] = true;
+ }
- if (SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_SOUTH) ||
- SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER) >= 8000) {
- keys[FIRE_KEY] = true;
- }
+ if (SDL_GetGamepadButton(gamepad->gamepad, SDL_GAMEPAD_BUTTON_EAST) ||
+ SDL_GetGamepadAxis(gamepad->gamepad, SDL_GAMEPAD_AXIS_LEFT_TRIGGER) >= 8000) {
+ keys[SHIELD_KEY] = true;
+ }
- if (SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_EAST) ||
- SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFT_TRIGGER) >= 8000) {
- keys[SHIELD_KEY] = true;
- }
+ if (SDL_GetGamepadButton(gamepad->gamepad, SDL_GAMEPAD_BUTTON_DPAD_LEFT) ||
+ SDL_GetGamepadAxis(gamepad->gamepad, SDL_GAMEPAD_AXIS_LEFTX) <= -16000 ||
+ SDL_GetGamepadAxis(gamepad->gamepad, SDL_GAMEPAD_AXIS_RIGHTX) <= -16000) {
+ keys[LEFT_KEY] = true;
+ }
- if (SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_DPAD_LEFT) ||
- SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFTX) <= -16000 ||
- SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHTX) <= -16000) {
- keys[LEFT_KEY] = true;
- }
+ if (SDL_GetGamepadButton(gamepad->gamepad, SDL_GAMEPAD_BUTTON_DPAD_RIGHT) ||
+ SDL_GetGamepadAxis(gamepad->gamepad, SDL_GAMEPAD_AXIS_LEFTX) >= 16000 ||
+ SDL_GetGamepadAxis(gamepad->gamepad, SDL_GAMEPAD_AXIS_RIGHTX) >= 16000) {
+ keys[RIGHT_KEY] = true;
+ }
- if (SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_DPAD_RIGHT) ||
- SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFTX) >= 16000 ||
- SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHTX) >= 16000) {
- keys[RIGHT_KEY] = true;
+ if (SDL_GetGamepadButton(gamepad->gamepad, SDL_GAMEPAD_BUTTON_DPAD_UP) ||
+ SDL_GetGamepadAxis(gamepad->gamepad, SDL_GAMEPAD_AXIS_LEFTY) <= -16000 ||
+ SDL_GetGamepadAxis(gamepad->gamepad, SDL_GAMEPAD_AXIS_RIGHTY) <= -16000) {
+ keys[THRUST_KEY] = true;
+ }
}
- if (SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_DPAD_UP) ||
- SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFTY) <= -16000 ||
- SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHTY) <= -16000) {
- keys[THRUST_KEY] = true;
+ if (!gamepad->sessionID) {
+ ++joystick_index;
}
}
- if (player->GetControlType() & CONTROL_KEYBOARD) {
- const bool *keystate = SDL_GetKeyboardState(nullptr);
-
+ const bool *keystate;
+ if (controlType & CONTROL_KEYBOARD) {
+ keystate = SDL_GetKeyboardState(nullptr);
+ } else {
+ keystate = GetRemotePlayerKeyboardState(controlType);
+ }
+ if (keystate) {
if (keystate[SDL_GetScancodeFromKey(controls.gFireControl, SDL_KMOD_NONE)]) {
keys[FIRE_KEY] = true;
}
@@ -362,12 +383,12 @@ static void HandleEvent(SDL_Event *event)
switch (event->type) {
/* -- Handle joystick added */
case SDL_EVENT_GAMEPAD_ADDED:
- OpenJoystick(event->gdevice.which);
+ OpenGamepad(event->gdevice.which);
break;
/* -- Handle joystick removed */
case SDL_EVENT_GAMEPAD_REMOVED:
- CloseJoystick(event->gdevice.which);
+ CloseGamepad(event->gdevice.which);
break;
/* -- Handle joystick axis motion */
@@ -457,6 +478,16 @@ static void HandleEvent(SDL_Event *event)
UpdateControl(player);
break;
+ case SDL_EVENT_REMOTE_INPUT:
+ player = GetControlPlayer(event->user.code);
+ if (!player) {
+ break;
+ }
+
+ /* Update control key status */
+ UpdateControl(player);
+ break;
+
case SDL_EVENT_WINDOW_MINIMIZED:
gGameInfo.SetLocalState(STATE_MINIMIZE, true);
break;
@@ -476,7 +507,7 @@ void InitPlayerControls(void)
SDL_JoystickID *ids = SDL_GetJoysticks(nullptr);
if (ids) {
for (int i = 0; ids[i]; ++i) {
- OpenJoystick(ids[i]);
+ OpenGamepad(ids[i]);
}
SDL_free(ids);
}
@@ -484,12 +515,11 @@ void InitPlayerControls(void)
void QuitPlayerControls(void)
{
- for (int i = 0; i < MAX_JOYSTICKS; ++i) {
- if (joysticks[i]) {
- SDL_CloseGamepad(joysticks[i]);
- joysticks[i] = NULL;
- }
+ for (unsigned int i = 0; i < gamepads.length(); ++i) {
+ Gamepad *gamepad = &gamepads[i];
+ SDL_CloseGamepad(gamepad->gamepad);
}
+ gamepads.clear();
}
/* This function gives a good way to delay a specified amount of time
diff --git a/game/game.cpp b/game/game.cpp
index 14acd2a3..892d4ec4 100644
--- a/game/game.cpp
+++ b/game/game.cpp
@@ -100,6 +100,9 @@ static bool SetupPlayers(void)
gPlayers[i]->SetControlType(CONTROL_NONE);
}
}
+
+ EnableRemoteInput();
+
return true;
}
@@ -498,7 +501,7 @@ GamePanelDelegate::OnAction(UIBaseElement *sender, const char *action)
}
}
} else {
- Player *player = GetControlPlayer(CONTROL_TOUCH);
+ Player *player = GetControlPlayer(CONTROL_KEYBOARD);
if (player) {
player->SetControl(control, down);
}
@@ -1061,6 +1064,8 @@ GamePanelDelegate::GameOver()
QuitPlayerControls();
+ DisableRemoteInput();
+
ui->ShowPanel(PANEL_GAMEOVER);
}
diff --git a/game/gameinfo.cpp b/game/gameinfo.cpp
index a9e95def..282f89ad 100644
--- a/game/gameinfo.cpp
+++ b/game/gameinfo.cpp
@@ -78,7 +78,7 @@ GameInfo::SetPlayerSlot(int slot, const char *name, Uint8 controlMask)
SDL_strlcpy(player->name, name ? name : "", sizeof(player->name));
- if (IS_LOCAL_CONTROL(controlMask)) {
+ if (IS_LOCAL_CONTROL(controlMask) || IS_REMOTE_CONTROL(controlMask)) {
player->nodeID = localID;
} else {
player->nodeID = 0;
diff --git a/game/gameinfo.h b/game/gameinfo.h
index 07e4d57f..dd8a009a 100644
--- a/game/gameinfo.h
+++ b/game/gameinfo.h
@@ -37,10 +37,11 @@ enum PLAYER_CONTROL {
CONTROL_JOYSTICK1 = 0x02,
CONTROL_JOYSTICK2 = 0x04,
CONTROL_JOYSTICK3 = 0x08,
- CONTROL_TOUCH = 0x10,
- CONTROL_NETWORK = 0x20,
- CONTROL_REPLAY = 0x40,
- CONTROL_LOCAL = (CONTROL_KEYBOARD|CONTROL_JOYSTICK1|CONTROL_JOYSTICK2|CONTROL_JOYSTICK3|CONTROL_TOUCH)
+ CONTROL_REMOTE1 = 0x10,
+ CONTROL_REMOTE2 = 0x20,
+ CONTROL_NETWORK = 0x40,
+ CONTROL_REPLAY = 0x80,
+ CONTROL_LOCAL = (CONTROL_KEYBOARD|CONTROL_JOYSTICK1|CONTROL_JOYSTICK2|CONTROL_JOYSTICK3)
};
enum GAME_MODE {
@@ -48,6 +49,7 @@ enum GAME_MODE {
};
#define IS_LOCAL_CONTROL(X) (X & CONTROL_LOCAL)
+#define IS_REMOTE_CONTROL(X) (X & (CONTROL_REMOTE1 | CONTROL_REMOTE2))
enum NODE_STATE_FLAG {
STATE_NONE = 0x00,
diff --git a/game/lobby.cpp b/game/lobby.cpp
index 5d442f55..e86c2a1e 100644
--- a/game/lobby.cpp
+++ b/game/lobby.cpp
@@ -86,14 +86,14 @@ class ControlClickCallback : public UIClickCallback
}
// Show the control dialog
- int num_gamepads = 0;
- SDL_free(SDL_GetGamepads(&num_gamepads));
+ int num_gamepads = GetNumGamepads();
SetControl(CONTROL_NONE, (m_index > 0) && m_game.IsHosting());
SetControl(CONTROL_LOCAL, !m_game.OtherPlayerHasControl(m_index, CONTROL_LOCAL));
- SetControl(CONTROL_KEYBOARD, SDL_HasKeyboard() && !m_game.OtherPlayerHasControl(m_index, CONTROL_KEYBOARD));
SetControl(CONTROL_JOYSTICK1, num_gamepads > 0 && !m_game.OtherPlayerHasControl(m_index, CONTROL_JOYSTICK1));
SetControl(CONTROL_JOYSTICK2, num_gamepads > 1 && !m_game.OtherPlayerHasControl(m_index, CONTROL_JOYSTICK2));
SetControl(CONTROL_JOYSTICK3, num_gamepads > 2 && !m_game.OtherPlayerHasControl(m_index, CONTROL_JOYSTICK3));
+ SetControl(CONTROL_REMOTE1, (m_index > 0) && m_game.IsHosting() && GetRemotePlayerName(CONTROL_REMOTE1) && !m_game.OtherPlayerHasControl(m_index, CONTROL_REMOTE1));
+ SetControl(CONTROL_REMOTE2, (m_index > 0) && m_game.IsHosting() && GetRemotePlayerName(CONTROL_REMOTE2) && !m_game.OtherPlayerHasControl(m_index, CONTROL_REMOTE2));
SetControl(CONTROL_NETWORK, (m_index > 0) && m_game.IsHosting());
m_dialog->SetAnchor(LEFT, RIGHT, m_button, -4, 0);
@@ -101,6 +101,24 @@ class ControlClickCallback : public UIClickCallback
}
private:
+ int GetNumGamepads()
+ {
+ int num_gamepads = 0;
+ SDL_JoystickID* gamepads = SDL_GetGamepads(nullptr);
+ if (gamepads) {
+ for (int i = 0; gamepads[i]; ++i) {
+ SDL_Gamepad* gamepad = SDL_OpenGamepad(gamepads[i]);
+ if (gamepad) {
+ if (!GetRemoteSessionForGamepad(gamepad)) {
+ ++num_gamepads;
+ }
+ SDL_CloseGamepad(gamepad);
+ }
+ }
+ SDL_free(gamepads);
+ }
+ return num_gamepads;
+ }
void SetControl(Uint8 control, bool enabled) {
char name[128];
UIElement *element;
diff --git a/game/main.cpp b/game/main.cpp
index 4ae46bef..5c904191 100644
--- a/game/main.cpp
+++ b/game/main.cpp
@@ -41,7 +41,6 @@
#include "about.h"
#include "game.h"
#include "netplay.h"
-#include "steam.h"
#include "main.h"
#include "../utils/files.h"
@@ -174,6 +173,9 @@ int main(int argc, char *argv[])
/* Command line flags */
Uint32 window_flags = SDL_WINDOW_FULLSCREEN | SDL_WINDOW_RESIZABLE;
+ /* Initializing Steam can set up environment variables, so do this first */
+ InitSteam();
+
if ( !InitFilesystem(MAELSTROM_ORGANIZATION, MAELSTROM_NAME) ) {
exit(1);
}
@@ -202,8 +204,6 @@ int main(int argc, char *argv[])
}
}
- InitSteam();
-
/* Initialize everything. :) */
if ( DoInitializations(window_flags) < 0 ) {
/* An error message was already printed */
diff --git a/game/scores.cpp b/game/scores.cpp
index d3d9218d..4a20d14b 100644
--- a/game/scores.cpp
+++ b/game/scores.cpp
@@ -117,7 +117,7 @@ static SDL_EnumerationResult SDLCALL DeleteScoresCallback(void *userdata, const
SDL_Storage *storage = (SDL_Storage *)userdata;
char path[256];
- SDL_snprintf(path, sizeof(path), "%s/%s", dirname, fname);
+ SDL_snprintf(path, sizeof(path), "%s%s", dirname, fname);
SDL_RemoveStoragePath(storage, path);
return SDL_ENUM_CONTINUE;
}
diff --git a/game/steam.cpp b/game/steam.cpp
index 27d8263e..0bf600bc 100644
--- a/game/steam.cpp
+++ b/game/steam.cpp
@@ -20,66 +20,346 @@
slouken@libsdl.org
*/
+#include <SDL3/SDL.h>
+
#include "steam.h"
#ifdef ENABLE_STEAM
-#include <SDL3/SDL.h>
#define strncpy SDL_strlcpy
#include <steam/steam_api.h>
-class SteamCallbacks
+#include "../utils/array.h"
+
+#include "gameinfo.h"
+
+
+class SteamInterface
{
public:
- SteamCallbacks() { }
- ~SteamCallbacks() { }
+
(Patch may be truncated, please check the link at the top of this post.)