Skip to content

Commit

Permalink
support inviting to game over steam friends
Browse files Browse the repository at this point in the history
  • Loading branch information
hylje authored and yancouto committed Jan 15, 2024
1 parent 92a555a commit 6f20a76
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 4 deletions.
17 changes: 16 additions & 1 deletion docs/apps.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,19 @@ Function Reference

if Steam.apps.isDlcInstalled(12345) then
-- Unlock game content
end
end

.. function:: apps.getLaunchCommandLineParam()

:returns: (`string`) The launch command line parameters
:SteamWorks: `GetLaunchCommandLine <https://partner.steamgames.com/doc/api/ISteamApps#GetLaunchCommandLine>`_

Gets the launch command line parameters. Use it to for example parse it for a connect string when implementing game invite functionality using :func:`friends.inviteUserToGame`.

**Example**::

local params = Steam.apps.getLaunchCommandLineParam()
local connect_string = tryParseConnectString(params)
if (connect_string) then
initiateJoinGame(connect_string)
end
44 changes: 44 additions & 0 deletions docs/friends.rst
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,30 @@ Function Reference
}
}

.. function:: friends.inviteUserToGame(steam_id, connect_string)

:param uint64 steam_id: The Steam ID of the other user.
:param string connect_string: Custom string that tells the joining player how to join the game
:returns: True if invite was sent successfully, false if not
:SteamWorks: `InviteUserToGame <https://partner.steamgames.com/doc/api/ISteamFriends#InviteUserToGame>`_

Invites the given user steam_id to the game identified by `connect_string`

The connect_string can be received by the application on the joining player in two ways depending on whether the game is already running or it is being launched.

You should implement the callback :func:`friends.onGameRichPresenceJoinRequested` to receive the `connect_string` on the invitee and ultimately establish the connection on an already running application.

You should also call :func:`apps.getLaunchCommandLineParams` on game launch and check if the game was launched with the `connect_string`, and immediately take steps to establish the connection.

To add UI elements to invite or join the game over the Steam overlay or friends menu, also set the rich presence key `connect` with the `connect_string` value and clear it when the game is no longer available to join.

**Example**::

local friend_id = getSteamIdSomehow()
local success = Steam.friends.inviteUserToGame(friend_id, 'serverID=birthday_party')

Callbacks Reference
-------------------

Expand All @@ -131,3 +155,23 @@ Callbacks Reference
function Steam.friends.onGameOverlayActivated(data)
print('Overlay active is', data.active)
end

.. function:: friends.onGameRichPresenceJoinRequested(data)

:param table data: A table similar to `GameRichPresenceJoinRequested_t <https://partner.steamgames.com/doc/api/ISteamFriends#GameRichPresenceJoinRequested_t>`_

* **data.steamIDFriend** (`uint64`) -- Steam ID of friend from through the invite was received
* **data.connectString** (`string`) -- custom connect string to parse for connection details

:returns: nothing


**Example**::

function Steam.friends.onGameRichPresenceJoinRequested(data)
if (game_state=='main_menu') then
initiateJoinGame(data.connectString)
else
showDialog("you can only join a game from the main menu")
end
end
14 changes: 13 additions & 1 deletion src/apps.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#include "apps.hpp"
#include <iomanip>


// ============================
// ======== SteamApps =========
Expand All @@ -17,12 +19,22 @@ EXTERN int luasteam_isDlcInstalled(lua_State *L) {
return 1;
}

// int GetLaunchCommandLine( char *pszCommandLine, int cubCommandLine );
EXTERN int luasteam_getLaunchCommandLine(lua_State *L) {
char *pCommandLine = (char*) malloc(1024);
SteamApps()->GetLaunchCommandLine(pCommandLine, 1024);
lua_pushstring(L, pCommandLine);
free(pCommandLine);
return 1;
}

namespace luasteam {

void add_apps(lua_State *L) {
lua_createtable(L, 0, 2);
lua_createtable(L, 0, 3);
add_func(L, "getCurrentGameLanguage", luasteam_getCurrentGameLanguage);
add_func(L, "isDlcInstalled", luasteam_isDlcInstalled);
add_func(L, "getLaunchCommandLine", luasteam_getLaunchCommandLine);
lua_setfield(L, -2, "apps");
}

Expand Down
42 changes: 40 additions & 2 deletions src/friends.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const char *dialog_types[] = {"friends", "community", "players", "settings", "of
class CallbackListener {
private:
STEAM_CALLBACK(CallbackListener, OnGameOverlayActivated, GameOverlayActivated_t);
STEAM_CALLBACK(CallbackListener, OnGameRichPresenceJoinRequested, GameRichPresenceJoinRequested_t);
};

void CallbackListener::OnGameOverlayActivated(GameOverlayActivated_t *data) {
Expand All @@ -38,6 +39,30 @@ void CallbackListener::OnGameOverlayActivated(GameOverlayActivated_t *data) {
}
}

void CallbackListener::OnGameRichPresenceJoinRequested(GameRichPresenceJoinRequested_t *data) {
if (data == nullptr) {
return;
}
lua_State *L = luasteam::global_lua_state;
if (!lua_checkstack(L, 4)) {
return;
}

lua_rawgeti(L, LUA_REGISTRYINDEX, friends_ref);
lua_getfield(L, -1, "onGameRichPresenceJoinRequested");
if (lua_isnil(L, -1)) {
lua_pop(L, 2);
} else {
lua_createtable(L, 0, 2);
luasteam::pushuint64(L, data->m_steamIDFriend.ConvertToUint64());
lua_setfield(L, -2, "steamIDFriend");
lua_pushstring(L, data->m_rgchConnect);
lua_setfield(L, -2, "connectString");
lua_call(L, 1, 0);
lua_pop(L, 1);
}
}

} // namespace

// void ActivateGameOverlay( const char *pchDialog );
Expand Down Expand Up @@ -71,20 +96,33 @@ EXTERN int luasteam_setRichPresence(lua_State *L) {
return 1;
}

// bool InviteUserToGame( CSteamID steamIDFriend, const char *pchConnectString );
EXTERN int luasteam_inviteUserToGame(lua_State *L) {
CSteamID id(luasteam::checkuint64(L, 1));
const char *connectString = luaL_checkstring(L, 2);

bool success = SteamFriends()->InviteUserToGame(id, connectString);
lua_pushboolean(L, success);
return 1;
}

namespace luasteam {

void add_friends(lua_State *L) {
lua_createtable(L, 0, 4);
lua_createtable(L, 0, 5);
add_func(L, "activateGameOverlay", luasteam_activateGameOverlay);
add_func(L, "activateGameOverlayToWebPage", luasteam_activateGameOverlayToWebPage);
add_func(L, "getFriendPersonaName", luasteam_getFriendPersonaName);
add_func(L, "setRichPresence", luasteam_setRichPresence);
add_func(L, "inviteUserToGame", luasteam_inviteUserToGame);
lua_pushvalue(L, -1);
friends_ref = luaL_ref(L, LUA_REGISTRYINDEX);
lua_setfield(L, -2, "friends");
}

void init_friends(lua_State *L) { friends_listener = new CallbackListener(); }
void init_friends(lua_State *L) {
friends_listener = new CallbackListener();
}

void shutdown_friends(lua_State *L) {
luaL_unref(L, LUA_REGISTRYINDEX, friends_ref);
Expand Down

0 comments on commit 6f20a76

Please sign in to comment.