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
38static const Ticket INVALID_TICKET = Ticket();
39
40class SteamTicketRequests {
41public:
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
52private:
53 struct PendingTicket {
54 HAuthTicket authTicket;
55 Ticket ticket;
56 TicketRequestCallback callback;
57 };
58
59 std::vector<PendingTicket> _pendingTickets;
60};
61
62SteamTicketRequests::SteamTicketRequests() :
63 _getAuthSessionTicketResponse(this, &SteamTicketRequests::onGetAuthSessionTicketResponse)
64{
65}
66
67SteamTicketRequests::~SteamTicketRequests() {
68 stopAll();
69}
70
71HAuthTicket 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
90void 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
102void 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
113void 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
138const QString CONNECT_PREFIX = "--url \"";
139const QString CONNECT_SUFFIX = "\"";
140
141class SteamCallbackManager {
142public:
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
159private:
160 SteamTicketRequests _steamTicketRequests;
161};
162
163SteamCallbackManager::SteamCallbackManager() :
164 _gameRichPresenceJoinRequestedResponse(this, &SteamCallbackManager::onGameRichPresenceJoinRequested),
165 _lobbyCreatedResponse(this, &SteamCallbackManager::onLobbyCreated),
166 _gameLobbyJoinRequestedResponse(this, &SteamCallbackManager::onGameLobbyJoinRequested),
167 _lobbyEnterResponse(this, &SteamCallbackManager::onLobbyEnter)
168{
169}
170
171void 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
185void SteamCallbackManager::onGameRichPresenceJoinRequested(GameRichPresenceJoinRequested_t* pCallback) {
186 auto url = QString::fromLocal8Bit(pCallback->m_rgchConnect);
187
188 parseUrlAndGo(url);
189}
190
191
192
193void 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
203void SteamCallbackManager::onGameLobbyJoinRequested(GameLobbyJoinRequested_t* pCallback) {
204 qDebug() << "Joining Steam lobby" << pCallback->m_steamIDLobby.ConvertToUint64();
205 SteamMatchmaking()->JoinLobby(pCallback->m_steamIDLobby);
206}
207
208void 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
225static std::atomic_bool initialized { false };
226static SteamCallbackManager steamCallbackManager;
227
228
229bool SteamAPIPlugin::isRunning() {
230 return initialized;
231}
232
233bool SteamAPIPlugin::init() {
234 if (SteamAPI_IsSteamRunning() && !initialized) {
235 initialized = SteamAPI_Init();
236 }
237 return initialized;
238}
239
240void SteamAPIPlugin::shutdown() {
241 if (initialized) {
242 SteamAPI_Shutdown();
243 }
244
245 steamCallbackManager.getTicketRequests().stopAll();
246}
247
248int 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
274void 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
288void 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
307void 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
318void 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
329void 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}