1#include <base/dbg.h>
2#include <base/net.h>
3#include <base/str.h>
4
5#include <engine/shared/config.h>
6#include <engine/steam.h>
7
8#include <steam/steam_api_flat.h>
9
10class CSteam : public ISteam
11{
12 HSteamPipe m_SteamPipe;
13 ISteamApps *m_pSteamApps;
14 ISteamFriends *m_pSteamFriends;
15 char m_aPlayerName[16];
16 bool m_GotConnectAddr;
17 NETADDR m_ConnectAddr;
18
19public:
20 CSteam()
21 {
22 SteamAPI_ManualDispatch_Init();
23 m_SteamPipe = SteamAPI_GetHSteamPipe();
24 m_pSteamApps = SteamAPI_SteamApps_v008();
25 m_pSteamFriends = SteamAPI_SteamFriends_v017();
26
27 ReadLaunchCommandLine();
28 str_copy(dst&: m_aPlayerName, src: SteamAPI_ISteamFriends_GetPersonaName(pSelf: m_pSteamFriends));
29 }
30 ~CSteam() override
31 {
32 SteamAPI_Shutdown();
33 }
34
35 void ParseConnectString(const char *pConnect)
36 {
37 if(pConnect[0])
38 {
39 NETADDR Connect;
40 if(net_host_lookup(hostname: pConnect, addr: &Connect, types: NETTYPE_ALL) == 0)
41 {
42 m_ConnectAddr = Connect;
43 m_GotConnectAddr = true;
44 }
45 else
46 {
47 dbg_msg(sys: "steam", fmt: "got unparsable connect string: '%s'", pConnect);
48 }
49 }
50 }
51
52 void ReadLaunchCommandLine()
53 {
54 char aConnect[NETADDR_MAXSTRSIZE];
55 int ConnectSize = SteamAPI_ISteamApps_GetLaunchCommandLine(pSelf: m_pSteamApps, pBuffer: aConnect, BufferSize: sizeof(aConnect));
56 if(ConnectSize >= NETADDR_MAXSTRSIZE)
57 {
58 ConnectSize = NETADDR_MAXSTRSIZE - 1;
59 }
60 aConnect[ConnectSize] = 0;
61 m_GotConnectAddr = false;
62 ParseConnectString(pConnect: aConnect);
63 }
64
65 void OnGameRichPresenceJoinRequested(GameRichPresenceJoinRequested_t *pEvent)
66 {
67 ParseConnectString(pConnect: pEvent->m_aRGCHConnect);
68 }
69
70 const char *GetPlayerName() override
71 {
72 return m_aPlayerName;
73 }
74
75 const NETADDR *GetConnectAddress() override
76 {
77 if(m_GotConnectAddr)
78 {
79 return &m_ConnectAddr;
80 }
81 else
82 {
83 return nullptr;
84 }
85 }
86 void ClearConnectAddress() override
87 {
88 m_GotConnectAddr = false;
89 }
90
91 void Update() override
92 {
93 SteamAPI_ManualDispatch_RunFrame(SteamPipe: m_SteamPipe);
94 CallbackMsg_t Callback;
95 while(SteamAPI_ManualDispatch_GetNextCallback(SteamPipe: m_SteamPipe, pCallbackMsg: &Callback))
96 {
97 switch(Callback.m_iCallback)
98 {
99 case NewUrlLaunchParameters_t::k_iCallback:
100 ReadLaunchCommandLine();
101 break;
102 case GameRichPresenceJoinRequested_t::k_iCallback:
103 OnGameRichPresenceJoinRequested(pEvent: (GameRichPresenceJoinRequested_t *)Callback.m_pubParam);
104 break;
105 default:
106 if(g_Config.m_Debug)
107 {
108 dbg_msg(sys: "steam/dbg", fmt: "unhandled callback id=%d", Callback.m_iCallback);
109 }
110 }
111 SteamAPI_ManualDispatch_FreeLastCallback(SteamPipe: m_SteamPipe);
112 }
113 }
114 void ClearGameInfo() override
115 {
116 SteamAPI_ISteamFriends_ClearRichPresence(pSelf: m_pSteamFriends);
117 }
118 void SetGameInfo(const NETADDR &ServerAddr, const char *pMapName, bool AnnounceAddr) override
119 {
120 if(AnnounceAddr)
121 {
122 char aServerAddr[NETADDR_MAXSTRSIZE];
123 net_addr_str(addr: &ServerAddr, string: aServerAddr, max_length: sizeof(aServerAddr), add_port: true);
124 SteamAPI_ISteamFriends_SetRichPresence(pSelf: m_pSteamFriends, pKey: "connect", pValue: aServerAddr);
125 SteamAPI_ISteamFriends_SetRichPresence(pSelf: m_pSteamFriends, pKey: "steam_player_group", pValue: aServerAddr);
126 }
127
128 SteamAPI_ISteamFriends_SetRichPresence(pSelf: m_pSteamFriends, pKey: "map", pValue: pMapName);
129 SteamAPI_ISteamFriends_SetRichPresence(pSelf: m_pSteamFriends, pKey: "status", pValue: pMapName);
130 SteamAPI_ISteamFriends_SetRichPresence(pSelf: m_pSteamFriends, pKey: "steam_display", pValue: "#Status");
131 }
132};
133
134class CSteamStub : public ISteam
135{
136 const char *GetPlayerName() override { return nullptr; }
137 const NETADDR *GetConnectAddress() override { return nullptr; }
138 void ClearConnectAddress() override {}
139 void Update() override {}
140 void ClearGameInfo() override {}
141 void SetGameInfo(const NETADDR &ServerAddr, const char *pMapName, bool AnnounceAddr) override {}
142};
143
144ISteam *CreateSteam()
145{
146 if(!SteamAPI_Init())
147 {
148 return new CSteamStub();
149 }
150 return new CSteam();
151}
152