History

Make Steamworks a plugin

Atlante45 committed 9 years ago

Commit 0dec97f1 parent 1829f5418 files · +299 −160Browse files

Showing the changes to plugins/steamClient/src/SteamAPIPlugin.cpp (1 of 18 files). Show all

Unified · Split

plugins/steamClient/src/SteamAPIPlugin.cpp+342−0
@@ -0,0 +1,342 @@
1+//
2+// SteamAPIPlugin.cpp
3+// plugins/steamClient/src
4+//
5+// Created by Clement Brisset on 6/8/16.
6+// Copyright 2016 High Fidelity, Inc.
7+//
8+// Distributed under the Apache License, Version 2.0.
9+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10+//
11+
12+#include "SteamAPIPlugin.h"
13+
14+#include <atomic>
15+
16+#include <QtCore/QCoreApplication>
17+#include <QtCore/QDebug>
18+#include <QtCore/QMimeData>
19+#include <QtCore/QString>
20+#include <QtCore/QUrl>
21+#include <QtGui/qevent.h>
22+
23+#if defined(__GNUC__) && !defined(__clang__)
24+#pragma GCC diagnostic push
25+#pragma GCC diagnostic ignored "-Woverloaded-virtual"
26+#if __GNUC__ >= 5 && __GNUC_MINOR__ >= 1
27+#pragma GCC diagnostic ignored "-Wsuggest-override"
28+#endif
29+#endif
30+
31+#include <steam/steam_api.h>
32+
33+#if defined(__GNUC__) && !defined(__clang__)
34+#pragma GCC diagnostic pop
35+#endif
36+
37+
38+static const Ticket INVALID_TICKET = Ticket();
39+
40+class SteamTicketRequests {
41+public:
42+ SteamTicketRequests();
43+ ~SteamTicketRequests();
44+
45+ HAuthTicket startRequest(TicketRequestCallback callback);
46+ void stopRequest(HAuthTicket authTicket);
47+ void stopAll();
48+
49+ STEAM_CALLBACK(SteamTicketRequests, onGetAuthSessionTicketResponse,
50+ GetAuthSessionTicketResponse_t, _getAuthSessionTicketResponse);
51+
52+private:
53+ struct PendingTicket {
54+ HAuthTicket authTicket;
55+ Ticket ticket;
56+ TicketRequestCallback callback;
57+ };
58+
59+ std::vector<PendingTicket> _pendingTickets;
60+};
61+
62+SteamTicketRequests::SteamTicketRequests() :
63+ _getAuthSessionTicketResponse(this, &SteamTicketRequests::onGetAuthSessionTicketResponse)
64+{
65+}
66+
67+SteamTicketRequests::~SteamTicketRequests() {
68+ stopAll();
69+}
70+
71+HAuthTicket SteamTicketRequests::startRequest(TicketRequestCallback callback) {
72+ static const uint32 MAX_TICKET_SIZE { 1024 };
73+ uint32 ticketSize { 0 };
74+ char ticket[MAX_TICKET_SIZE];
75+
76+ auto authTicket = SteamUser()->GetAuthSessionTicket(ticket, MAX_TICKET_SIZE, &ticketSize);
77+ qDebug() << "Got Steam auth session ticket:" << authTicket;
78+
79+ if (authTicket == k_HAuthTicketInvalid) {
80+ qWarning() << "Auth session ticket is invalid.";
81+ callback(INVALID_TICKET);
82+ } else {
83+ PendingTicket pendingTicket{ authTicket, QByteArray(ticket, ticketSize).toHex(), callback };
84+ _pendingTickets.push_back(pendingTicket);
85+ }
86+
87+ return authTicket;
88+}
89+
90+void SteamTicketRequests::stopRequest(HAuthTicket authTicket) {
91+ auto it = std::find_if(_pendingTickets.begin(), _pendingTickets.end(), [&authTicket](const PendingTicket& pendingTicket) {
92+ return pendingTicket.authTicket == authTicket;
93+ });
94+
95+ if (it != _pendingTickets.end()) {
96+ SteamUser()->CancelAuthTicket(it->authTicket);
97+ it->callback(INVALID_TICKET);
98+ _pendingTickets.erase(it);
99+ }
100+}
101+
102+void SteamTicketRequests::stopAll() {
103+ auto steamUser = SteamUser();
104+ if (steamUser) {
105+ for (const auto& pendingTicket : _pendingTickets) {
106+ steamUser->CancelAuthTicket(pendingTicket.authTicket);
107+ pendingTicket.callback(INVALID_TICKET);
108+ }
109+ }
110+ _pendingTickets.clear();
111+}
112+
113+void SteamTicketRequests::onGetAuthSessionTicketResponse(GetAuthSessionTicketResponse_t* pCallback) {
114+ auto authTicket = pCallback->m_hAuthTicket;
115+
116+ auto it = std::find_if(_pendingTickets.begin(), _pendingTickets.end(), [&authTicket](const PendingTicket& pendingTicket) {
117+ return pendingTicket.authTicket == authTicket;
118+ });
119+
120+
121+ if (it != _pendingTickets.end()) {
122+
123+ if (pCallback->m_eResult == k_EResultOK) {
124+ qDebug() << "Got steam callback, auth session ticket is valid. Send it." << authTicket;
125+ it->callback(it->ticket);
126+ } else {
127+ qWarning() << "Steam auth session ticket callback encountered an error:" << pCallback->m_eResult;
128+ it->callback(INVALID_TICKET);
129+ }
130+
131+ _pendingTickets.erase(it);
132+ } else {
133+ qWarning() << "Could not find steam auth session ticket in list of pending tickets:" << authTicket;
134+ }
135+}
136+
137+
138+const QString CONNECT_PREFIX = "--url \"";
139+const QString CONNECT_SUFFIX = "\"";
140+
141+class SteamCallbackManager {
142+public:
143+ SteamCallbackManager();
144+
145+ STEAM_CALLBACK(SteamCallbackManager, onGameRichPresenceJoinRequested,
146+ GameRichPresenceJoinRequested_t, _gameRichPresenceJoinRequestedResponse);
147+
148+ STEAM_CALLBACK(SteamCallbackManager, onLobbyCreated,
149+ LobbyCreated_t, _lobbyCreatedResponse);
150+
151+ STEAM_CALLBACK(SteamCallbackManager, onGameLobbyJoinRequested,
152+ GameLobbyJoinRequested_t, _gameLobbyJoinRequestedResponse);
153+
154+ STEAM_CALLBACK(SteamCallbackManager, onLobbyEnter,
155+ LobbyEnter_t, _lobbyEnterResponse);
156+
157+ SteamTicketRequests& getTicketRequests() { return _steamTicketRequests; }
158+
159+private:
160+ SteamTicketRequests _steamTicketRequests;
161+};
162+
163+SteamCallbackManager::SteamCallbackManager() :
164+ _gameRichPresenceJoinRequestedResponse(this, &SteamCallbackManager::onGameRichPresenceJoinRequested),
165+ _lobbyCreatedResponse(this, &SteamCallbackManager::onLobbyCreated),
166+ _gameLobbyJoinRequestedResponse(this, &SteamCallbackManager::onGameLobbyJoinRequested),
167+ _lobbyEnterResponse(this, &SteamCallbackManager::onLobbyEnter)
168+{
169+}
170+
171+void parseUrlAndGo(QString url) {
172+ if (url.startsWith(CONNECT_PREFIX) && url.endsWith(CONNECT_SUFFIX)) {
173+ url.remove(0, CONNECT_PREFIX.size());
174+ url.remove(-CONNECT_SUFFIX.size(), CONNECT_SUFFIX.size());
175+ }
176+
177+ qDebug() << "Joining Steam Friend at:" << url;
178+ auto mimeData = new QMimeData();
179+ mimeData->setUrls(QList<QUrl>() << QUrl(url));
180+ auto event = new QDropEvent(QPointF(0, 0), Qt::MoveAction, mimeData, Qt::LeftButton, Qt::NoModifier);
181+
182+ QCoreApplication::postEvent(qApp, event);
183+}
184+
185+void SteamCallbackManager::onGameRichPresenceJoinRequested(GameRichPresenceJoinRequested_t* pCallback) {
186+ auto url = QString::fromLocal8Bit(pCallback->m_rgchConnect);
187+
188+ parseUrlAndGo(url);
189+}
190+
191+
192+
193+void SteamCallbackManager::onLobbyCreated(LobbyCreated_t* pCallback) {
194+ if (pCallback->m_eResult == k_EResultOK) {
195+ qDebug() << "Inviting steam friends" << pCallback->m_ulSteamIDLobby;
196+
197+ auto url = SteamFriends()->GetFriendRichPresence(SteamUser()->GetSteamID(), "connect");
198+ SteamMatchmaking()->SetLobbyData(pCallback->m_ulSteamIDLobby, "connect", url);
199+ SteamFriends()->ActivateGameOverlayInviteDialog(pCallback->m_ulSteamIDLobby);
200+ }
201+}
202+
203+void SteamCallbackManager::onGameLobbyJoinRequested(GameLobbyJoinRequested_t* pCallback) {
204+ qDebug() << "Joining Steam lobby" << pCallback->m_steamIDLobby.ConvertToUint64();
205+ SteamMatchmaking()->JoinLobby(pCallback->m_steamIDLobby);
206+}
207+
208+void SteamCallbackManager::onLobbyEnter(LobbyEnter_t* pCallback) {
209+ if (pCallback->m_EChatRoomEnterResponse != k_EChatRoomEnterResponseSuccess) {
210+ qWarning() << "An error occured while joing the Steam lobby:" << pCallback->m_EChatRoomEnterResponse;
211+ return;
212+ }
213+
214+ qDebug() << "Entered Steam lobby" << pCallback->m_ulSteamIDLobby;
215+
216+ if (SteamMatchmaking()->GetLobbyOwner(pCallback->m_ulSteamIDLobby) != SteamUser()->GetSteamID()) {
217+ auto url = SteamMatchmaking()->GetLobbyData(pCallback->m_ulSteamIDLobby, "connect");
218+ qDebug() << "Jumping to" << url;
219+ parseUrlAndGo(url);
220+ SteamMatchmaking()->LeaveLobby(pCallback->m_ulSteamIDLobby);
221+ }
222+}
223+
224+
225+static std::atomic_bool initialized { false };
226+static SteamCallbackManager steamCallbackManager;
227+
228+
229+bool SteamAPIPlugin::isRunning() {
230+ return initialized;
231+}
232+
233+bool SteamAPIPlugin::init() {
234+ if (SteamAPI_IsSteamRunning() && !initialized) {
235+ initialized = SteamAPI_Init();
236+ }
237+ return initialized;
238+}
239+
240+void SteamAPIPlugin::shutdown() {
241+ if (initialized) {
242+ SteamAPI_Shutdown();
243+ }
244+
245+ steamCallbackManager.getTicketRequests().stopAll();
246+}
247+
248+int SteamAPIPlugin::getSteamVRBuildID() {
249+ if (initialized) {
250+ static const int MAX_PATH_SIZE = 512;
251+ static const int STEAMVR_APPID = 250820;
252+ char rawPath[MAX_PATH_SIZE];
253+ SteamApps()->GetAppInstallDir(STEAMVR_APPID, rawPath, MAX_PATH_SIZE);
254+
255+ QString path(rawPath);
256+ path += "\\bin\\version.txt";
257+ qDebug() << "SteamVR version file path:" << path;
258+
259+ QFile file(path);
260+ if (file.open(QIODevice::ReadOnly)) {
261+ QString buildIDString = file.readLine();
262+
263+ bool ok = false;
264+ int buildID = buildIDString.toInt(&ok);
265+ if (ok) {
266+ return buildID;
267+ }
268+ }
269+ }
270+ return 0;
271+}
272+
273+
274+void SteamAPIPlugin::runCallbacks() {
275+ if (!initialized) {
276+ return;
277+ }
278+
279+ auto steamPipe = SteamAPI_GetHSteamPipe();
280+ if (!steamPipe) {
281+ qDebug() << "Could not get SteamPipe";
282+ return;
283+ }
284+
285+ Steam_RunCallbacks(steamPipe, false);
286+}
287+
288+void SteamAPIPlugin::requestTicket(TicketRequestCallback callback) {
289+ if (!initialized) {
290+ if (SteamAPI_IsSteamRunning()) {
291+ init();
292+ } else {
293+ qWarning() << "Steam is not running";
294+ callback(INVALID_TICKET);
295+ return;
296+ }
297+ }
298+
299+ if (!initialized) {
300+ qDebug() << "Steam not initialized";
301+ return;
302+ }
303+
304+ steamCallbackManager.getTicketRequests().startRequest(callback);
305+}
306+
307+void SteamAPIPlugin::updateLocation(QString status, QUrl locationUrl) {
308+ if (!initialized) {
309+ return;
310+ }
311+
312+ auto connectStr = locationUrl.isEmpty() ? "" : CONNECT_PREFIX + locationUrl.toString() + CONNECT_SUFFIX;
313+
314+ SteamFriends()->SetRichPresence("status", status.toLocal8Bit().data());
315+ SteamFriends()->SetRichPresence("connect", connectStr.toLocal8Bit().data());
316+}
317+
318+void SteamAPIPlugin::openInviteOverlay() {
319+ if (!initialized) {
320+ return;
321+ }
322+
323+ qDebug() << "Creating Steam lobby";
324+ static const int MAX_LOBBY_SIZE = 20;
325+ SteamMatchmaking()->CreateLobby(k_ELobbyTypePrivate, MAX_LOBBY_SIZE);
326+}
327+
328+
329+void SteamAPIPlugin::joinLobby(QString lobbyIdStr) {
330+ if (!initialized) {
331+ if (SteamAPI_IsSteamRunning()) {
332+ init();
333+ } else {
334+ qWarning() << "Steam is not running";
335+ return;
336+ }
337+ }
338+
339+ qDebug() << "Trying to join Steam lobby:" << lobbyIdStr;
340+ CSteamID lobbyId(lobbyIdStr.toULongLong());
341+ SteamMatchmaking()->JoinLobby(lobbyId);
342+}