Jump to content
gamecreator

Introduction to Steam Code in Leadwerks

Recommended Posts

Hi all! I spent the last few days, after work, learning how Steam code works and incorporating it into a small example project. I learned a bit and thought I'd share with the community, as I would personally have loved to use code like this as a starting point. I hope it helps someone.

 

Explanation of what this all does is after the code.

 

Simply start a new 3.1 C++ project and replace all the code in App.cpp with the below.

 

#include "App.h"
using namespace Leadwerks;
App::App() : window(NULL), context(NULL), world(NULL), camera(NULL) {}
App::~App() { delete world; delete window; }
bool App::Start()
{
window = Leadwerks::Window::Create("SteamTest");
context = Context::Create(window);
world = World::Create();
camera = Camera::Create();
window->HideMouse();
// Initialize Steamworks
Steamworks::Initialize();
return true;
}
bool App::Loop()
{
  if(!SteamAPI_IsSteamRunning())
  {
  MessageBoxA(0, "Steam not detected. Please run Steam before running this program.", "Error", 0);
  return false;
  }

  // Exit program if needed
  if(window->KeyHit(Key::Escape) || window->Closed()) return false;

  Leadwerks::Time::Update();
  world->Update();
  world->Render();
  context->SetBlendMode(Blend::Alpha);
  context->SetColor(1, 1, 1);

  // Go to a website using STEAM browser
  if(window->KeyHit(Key::W)) SteamFriends()->ActivateGameOverlayToWebPage("http://www.leadwerks.com/");

  // Send a message to the first friend on the list (index 0) using STEAM
  if(window->KeyHit(Key::M)) SteamFriends()->ReplyToFriendMessage(SteamFriends()->GetFriendByIndex(0, k_EFriendFlagImmediate), "Test from program");

  context->DrawText("Your user name: ", 10, 30);
  context->DrawText(SteamFriends()->GetFriendPersonaName(SteamUser()->GetSteamID()), 120, 30);

  FriendGameInfo_t friendgameinfo;
  context->DrawText("This game's SteamID: ", 10, 50);
  SteamFriends()->GetFriendGamePlayed(SteamUser()->GetSteamID(), &friendgameinfo);
  context->DrawText(String(friendgameinfo.m_gameID.AppID()), 140, 50);

  int steamfriends = SteamFriends()->GetFriendCount(k_EFriendFlagImmediate);
  context->DrawText("Friends: " + String(steamfriends), 10, 90);

  // Cycle through all of your Steam friends
  for (int i = 0; i < steamfriends; i++)
  {
     // Get friend ID
     CSteamID steamIDFriend = SteamFriends()->GetFriendByIndex(i, k_EFriendFlagImmediate);

     // Print friend name
     context->DrawText(SteamFriends()->GetFriendPersonaName(steamIDFriend), 10, 110 + i * 20);

     // Print friend's Steam status (Offline, Online, Away, etc.)
     if(SteamFriends()->GetFriendPersonaState(steamIDFriend) == k_EPersonaStateOffline) context->DrawText("Offline", 120, 110 + i * 20);
     if(SteamFriends()->GetFriendPersonaState(steamIDFriend) == k_EPersonaStateOnline) context->DrawText("Online", 120, 110 + i * 20);
     if(SteamFriends()->GetFriendPersonaState(steamIDFriend) == k_EPersonaStateBusy) context->DrawText("Busy", 120, 110 + i * 20);
     if(SteamFriends()->GetFriendPersonaState(steamIDFriend) == k_EPersonaStateAway) context->DrawText("Away", 120, 110 + i * 20);
     if(SteamFriends()->GetFriendPersonaState(steamIDFriend) == k_EPersonaStateSnooze) context->DrawText("Snooze", 120, 110 + i * 20);

     // Is friend playing a Steam game right now?
     if(SteamFriends()->GetFriendGamePlayed(steamIDFriend, &friendgameinfo))
         // SteamID of game they're playing, if they're in one
         context->DrawText(String(friendgameinfo.m_gameID.AppID()),220,110 + i * 20);
     else
 	   context->DrawText("Not in game", 200, 110 + i * 20);

     // Match a player by name
     if(strcmp("yourfriendssteamplayername",     SteamFriends()->GetFriendPersonaName(SteamFriends()->GetFriendByIndex(i, k_EFriendFlagImmediate))) == 0)
     {
        context->DrawText("Player name match", 300, 110 + i * 20);
        // Do something here like start sending him data...
     }
  }
  context->SetBlendMode(Blend::Solid);
  context->Sync(false);

  return true;
}

 

This code is an illustration of several things you can do with Steam:

 

If you hit M, it sends a message to the first person on your list (using index 0 in the function). If they're offline then they will receive the message(s) when they get online. I realize the function is called ReplyToFriendMessage but I couldn't find one that was just Send and this was tested and it works, even if it's not a reply (it's the first message sent).

 

If you hit W, it opens a browser inside your game and goes to the website specified.

 

It shows your own Steam name and the Steam AppID of your game (by default it's 480).

 

It shows the total count of your friends on your friends list.

 

Then it cycles through all your friends and displays their name, their Steam status and if they're in a game, the AppID of the game they're in. This is very useful in dealing with only friends that are online and only sending data to people who are already in the same game as you are, if you want to send data directly (not by lobby invite).

 

A lot of this was learned by simply seeing what functions existed but a lot more was by wading through the documentation here: https://partner.steamgames.com/home/steamworks

 

Next up: peer-to-peer networking. Will report back with any success.

Share this post


Link to post

I haven't looked at nor do I know how it's done with the steam API, but please do your steam checks exhaustively. I have many games on steam that simply will not run because the steam network went down or the steamworks API is undergoing maintenance. 7 Days to Die is one such game. You can have steam running, be online, but the game will not run because steam was having problems.

Share this post


Link to post

Completely agreed. This is an example that's as simple as I could make it to illustrate several Steam functions and be easy to understand. This is definitely not how you would code for public release. It's just a code snippet.

Share this post


Link to post

Nice work.

Couple of questions.

Does your game have to be greenlite before your code will work?

Can the same functions be called in LUA ( I don't have C++ yet ) ?

 

Share this post


Link to post

Panther, you can do this right now without being Greenlit. Except for the initialization function it's all done using the Steamworks SDK and I'm not sure if they support Lua (I don't believe so but I'd check their page to make sure).

 

I should also mention that before being Greenlit your game will always be AppID 480 and be called Spacewar. This can't be changed until you're Greenlit (per here).

Share this post


Link to post

Here is the data transfer code sample. It very directly just starts sending and receiving coordinates with a Steam friend and moves two names on screen accordingly.

 

As before, create a new project and replace everything in App.cpp with this code. Make sure to change yoursteamname and otherplayersteamname in friendstrings to your Steam name and your friend's Steam name. The program matches your Steam friend based on the exact name you specify.

 

#include "App.h"

using namespace Leadwerks;

App::App() : window(NULL), context(NULL), world(NULL), camera(NULL) {}

App::~App() { delete world; delete window; }

bool steamfriendfound = false;

// Change yoursteamname and otherplayersteamname to your and other player's actual Steam names
// Matching system depends on other player's name being spelled correctly
char *friendstrings[2] = { "yoursteamname", "otherplayersteamname" };
int thisplayerindex = 0;
CSteamID steamIDFriend;

struct posdatastruct
{
 float x, y;
} pos[2];

bool App::Start()
{
 window = Leadwerks::Window::Create("SteamTest");
 context = Context::Create(window);
 world = World::Create();
 camera = Camera::Create();
 window->HideMouse();

 Steamworks::Initialize();

 // Set initial positions of 2 players
 pos[0].x=200;
 pos[0].y=200;
 pos[1].x=400;
 pos[1].y=400;

 return true;
}
bool App::Loop()
{
 if(!SteamAPI_IsSteamRunning())
 {
   MessageBoxA(0, "Steam not detected. Please run Steam before running this program.", "Error", 0);
   return false;
 }

 // Compare current player's name
 // If it's the same as the second player (index 1), set it as such
 // (otherwise leave it index 0)
 if(strcmp(friendstrings[1],SteamFriends()->GetFriendPersonaName(SteamUser()->GetSteamID()))==0) thisplayerindex=1;

 // If we haven't found the friend we want to connect to yet...
 if(!steamfriendfound)
 {
   // Cycle through all of your Steam friends
   for(int i = 0; i < SteamFriends()->GetFriendCount(k_EFriendFlagImmediate); i++)
   {
     // Get friend ID
     steamIDFriend = SteamFriends()->GetFriendByIndex(i, k_EFriendFlagImmediate);

     // Match connecting player by Steam name
     if(strcmp(friendstrings[1-thisplayerindex], SteamFriends()->GetFriendPersonaName(steamIDFriend))==0)
     {
       steamfriendfound=true;
       break;
     }
   }
 }
 // ... otherwise play the game
 else
 {
   // Send data to friend
   SteamNetworking()->SendP2PPacket(steamIDFriend, &pos[thisplayerindex], sizeof(pos[0]), k_EP2PSendUnreliable);

   // Read any and all incoming packets
   uint32 msgSize = 0;
   while(SteamNetworking()->IsP2PPacketAvailable(&msgSize))
   {
     void *packet = malloc(msgSize);
     CSteamID steamIDRemote;
     uint32 bytesRead = 0;

     // At least make sure message is the right size
     if(msgSize==sizeof(pos[0]))
     {
       if(SteamNetworking()->ReadP2PPacket(&pos[1-thisplayerindex], msgSize, &bytesRead, &steamIDRemote))
       {
         // Any extra code to analyze the packet can go here
       }
     }
     free(packet);
   }
 }

 // Exit program if needed
 if(window->KeyHit(Key::Escape)||window->Closed()) return false;

 if(window->KeyDown(Key::Right)) pos[thisplayerindex].x+=2*Time::GetSpeed();
 if(window->KeyDown(Key::Left)) pos[thisplayerindex].x-=2*Time::GetSpeed();
 if(window->KeyDown(Key::Up)) pos[thisplayerindex].y-=2*Time::GetSpeed();
 if(window->KeyDown(Key::Down)) pos[thisplayerindex].y+=2*Time::GetSpeed();

 Leadwerks::Time::Update();
 world->Update();
 world->Render();
 context->SetBlendMode(Blend::Alpha);
 context->SetColor(1, 1, 1);
 context->DrawText("Use the arrow keys to move your name", 10, 10);
 context->DrawText(friendstrings[0], (int)pos[0].x, (int)pos[0].y);
 context->DrawText(friendstrings[1], (int)pos[1].x, (int)pos[1].y);
 context->SetBlendMode(Blend::Solid);
 context->Sync(false);

 // Sleep a bit to not spam connection
 Sleep(10);

 return true;
}

 

Interesting thing to note: I thought I was being clever by making sure both players are running Steam AppID 480 (our defaul pre-Greenlit game ID). This backfired when my friend was already in another game before running this program. The AppID didn't match because Steam returned the ID of his other game. (It also showed that game on my friend's list, not Spacewar.) As such, I removed that check and not too surprisingly, the program worked anyway. It seems Steam makes sure to send messages between the same games anyway, no matter what else you may have running, so you don't need to bother checking for it.

 

Enjoy!

Share this post


Link to post

Here is a Steam lobby example. Sadly, it's not very beginner friendly as it requires callbacks and call results to be used and Steam requires that you do this all within a class. That said, once you wrap your head around it, it's not too bad. As is my preference, I've made this as easy and short as I could.

 

Check out the Getting Started with Steam link to read more abotu callbacks and call results:

https://partner.steamgames.com/documentation/getting_started

 

Also, a lot of this was learned from here:

https://partner.steamgames.com/documentation/matchmaking

 

This program very simply creates a lobby, invites friends to join and shows you the results on either side (invitor or invitee).

 

#include "App.h"

using namespace Leadwerks;

App::App() : window(NULL), context(NULL), world(NULL), camera(NULL) {}

App::~App() { delete world; delete window; }

bool createdlobby = false;
bool joinedlobby = false;

CSteamID m_steamIDLobby;
CSteamID userjoiningorleavinglobby;

class LobbyManagerClass
{
 public:

 LobbyManagerClass();

 void createlobby();
 // Called when the lobby is created (it's not instant, as it has to run it by Steam first)

 void OnLobbyCreated(LobbyCreated_t *pCallback, bool bIOFailure);
 CCallResult<LobbyManagerClass, LobbyCreated_t> m_SteamCallResultLobbyCreated;

 // Called when invitee enters a lobby
 void OnLobbyEntered(LobbyEnter_t *pCallback, bool bIOFailure);

 CCallResult<LobbyManagerClass, LobbyEnter_t> m_SteamCallResultLobbyEntered;

 // Called every time someone joins or leaves a lobby
 STEAM_CALLBACK(LobbyManagerClass, OnLobbyChatUpdate, LobbyChatUpdate_t, m_CallbackChatDataUpdate);

 // Called when someone invites you to a lobby
 STEAM_CALLBACK(LobbyManagerClass, OnGameLobbyJoinRequested, GameLobbyJoinRequested_t, m_CallbackLobbyDataUpdate);
} lobbymanager;

LobbyManagerClass::LobbyManagerClass() : m_CallbackLobbyDataUpdate(this, &LobbyManagerClass::OnGameLobbyJoinRequested), m_CallbackChatDataUpdate(this, &LobbyManagerClass::OnLobbyChatUpdate) { }


void LobbyManagerClass::createlobby()
{
 SteamAPICall_t hSteamAPICall = SteamMatchmaking()->CreateLobby(k_ELobbyTypePublic, 16);

 // Set the call result for when Steam returns lobby creation results
 m_SteamCallResultLobbyCreated.Set(hSteamAPICall, this, &LobbyManagerClass::OnLobbyCreated);
}


void LobbyManagerClass::OnLobbyEntered(LobbyEnter_t *pCallback, bool bIOFailure)
{
 // If we didn't get a success confirmation, let joiner know
 if(pCallback->m_EChatRoomEnterResponse!=k_EChatRoomEnterResponseSuccess)
 {
   MessageBoxA(0, "Failed to enter lobby", "Error", 0);
   return;
 }

 // We succesfully entered someone else's lobby
 m_steamIDLobby = pCallback->m_ulSteamIDLobby;
 joinedlobby = true;
}


void LobbyManagerClass::OnLobbyCreated(LobbyCreated_t *pCallback, bool bIOFailure)
{
 // If lobby creation was successful
 if(pCallback->m_eResult==k_EResultOK)
 {
   // Get lobby info
   m_steamIDLobby = pCallback->m_ulSteamIDLobby;
   SteamMatchmaking()->SetLobbyData(m_steamIDLobby, "name", "Leadwerkslobby");
   createdlobby = true;
 }
 else MessageBoxA(0, "Could not create lobby.", "Error", 0);
}


// This gets called for both the invitor and invitees whenever someone joins or leaves a lobby
void LobbyManagerClass::OnLobbyChatUpdate(LobbyChatUpdate_t *pCallback)
{
 // Get the SteamID of the person joining or leaving the lobby
 userjoiningorleavinglobby = pCallback->m_ulSteamIDUserChanged;
}


// Called when you accept an invite
void LobbyManagerClass::OnGameLobbyJoinRequested(GameLobbyJoinRequested_t *pParam)
{
 // Join lobby
 SteamAPICall_t hSteamAPICall = SteamMatchmaking()->JoinLobby(pParam->m_steamIDLobby);

 // Set the call result for when player enters lobby
 m_SteamCallResultLobbyEntered.Set(hSteamAPICall, this, &LobbyManagerClass::OnLobbyEntered);
}

bool App::Start()
{
 window = Leadwerks::Window::Create("Steam Lobby Example");
 context = Context::Create(window);
 world = World::Create();
 camera = Camera::Create();
 window->HideMouse();

 Steamworks::Initialize();

 return true;
}


bool App::Loop()
{
 if(!SteamAPI_IsSteamRunning())
 {
   MessageBoxA(0, "Steam not detected. Please run Steam before running this program.", "Error", 0);
   return false;
 }

 // Exit program if needed
 if(window->KeyHit(Key::Escape) || window->Closed()) return false;

 // This must be called regularly for callbacks and call results to work
 SteamAPI_RunCallbacks();

 Leadwerks::Time::Update();
 world->Update();
 world->Render();

 context->SetBlendMode(Blend::Alpha);
 context->SetColor(1, 1, 1);

 // If no lobby is created or joined, give player option to create one
 if(!createdlobby && !joinedlobby)
 {
   if(window->KeyHit(Key::C)) lobbymanager.createlobby();
   context->DrawText("Press C to create a lobby or wait for a friend invite to join one", 10, 30);
 }

 // Once a lobby is created, give user option to invite others
 else if(createdlobby)
 {
   context->DrawText("Press I to invite a friend to your lobby.", 10, 10);
   if(window->KeyHit(Key::I)) SteamFriends()->ActivateGameOverlay("LobbyInvite");

   // ... or you can invite friends through the program with the following syntax
   // InviteUserToLobby(CSteamID steamIDLobby, CSteamID steamIDInvitee);
 }

 if(createdlobby) context->DrawText("You created a lobby. Lobby name:", 10, 30);
 if(joinedlobby) context->DrawText("You joined a lobby. Lobby name:", 10, 30);

 // Show lobby info
 if(createdlobby || joinedlobby)
 {
   context->DrawText(SteamMatchmaking()->GetLobbyData(m_steamIDLobby, "name"), 220, 30);

   context->DrawText("Number of lobby members:", 10, 50);
   context->DrawText(String(SteamMatchmaking()->GetNumLobbyMembers(m_steamIDLobby)), 170, 50);

   context->DrawText("Members in lobby:", 10, 90);

   for(int i=0; i<SteamMatchmaking()->GetNumLobbyMembers(m_steamIDLobby); i++)
   {
  CSteamID steamIDFriendinlobby = SteamMatchmaking()->GetLobbyMemberByIndex(m_steamIDLobby, i);
  context->DrawText(SteamFriends()->GetFriendPersonaName(steamIDFriendinlobby), 10, 110+20*i);
   }
 }

 context->SetBlendMode(Blend::Solid);
 context->Sync(false);

 Sleep(10); // Sleep a bit to not spam connection

 return true;
}

 

Thanks to Rick for his help in understanding C++ I haven't used before.

Share this post


Link to post

And here's how to create a lobby with a key that anyone in the world can find and join automatically. I added the requeststeamlobbylist function and the related OnLobbyMatchListCallback callback.

 

#include "App.h"

using namespace Leadwerks;

App::App() : window(NULL), context(NULL), world(NULL), camera(NULL) {}

App::~App() { delete world; delete window; }

bool createdlobby = false;
bool joinedlobby = false;

CSteamID steamIDLobby;
CSteamID userjoiningorleavinglobby;

class LobbyManagerClass
{
 public:

 LobbyManagerClass();

 void createlobby();
 void requeststeamlobbylist();

 // Called when the lobby is created (it's not instant, as it has to run it by Steam first)
 void OnLobbyCreated(LobbyCreated_t *pCallback, bool bIOFailure);
 CCallResult<LobbyManagerClass, LobbyCreated_t> m_SteamCallResultLobbyCreated;

 // Called when the lobby is created (it's not instant, as it has to run it by Steam first)
 void OnLobbyMatchListCallback(LobbyMatchList_t *pCallback, bool bIOFailure);
 CCallResult<LobbyManagerClass, LobbyMatchList_t> m_SteamCallResultLobbyMatchList;

 // Called when invitee enters a lobby
 void OnLobbyEntered(LobbyEnter_t *pCallback, bool bIOFailure);
 CCallResult<LobbyManagerClass, LobbyEnter_t> m_SteamCallResultLobbyEntered;

 // Called every time someone joins or leaves a lobby
 STEAM_CALLBACK(LobbyManagerClass, OnLobbyChatUpdate, LobbyChatUpdate_t, m_CallbackChatDataUpdate);
} lobbymanager;

LobbyManagerClass::LobbyManagerClass() : m_CallbackChatDataUpdate(this, &LobbyManagerClass::OnLobbyChatUpdate) { }

void LobbyManagerClass::createlobby()
{
 SteamAPICall_t hSteamAPICall = SteamMatchmaking()->CreateLobby(k_ELobbyTypePublic, 16);

 // Set the call result for when Steam returns lobby creation results
 m_SteamCallResultLobbyCreated.Set(hSteamAPICall, this, &LobbyManagerClass::OnLobbyCreated);
}


void LobbyManagerClass::requeststeamlobbylist()
{
 // You can limit the number of results to a specified amount, if you want
 // SteamMatchmaking()->AddRequestLobbyListResultCountFilter(15);

 // Steam returns closest results first by geographic IP location so search worldwide
 SteamMatchmaking()->AddRequestLobbyListDistanceFilter(k_ELobbyDistanceFilterWorldwide);

 // Let's only find lobbies which have a name of Leadwerks lobby
 SteamMatchmaking()->AddRequestLobbyListStringFilter("name", "Leadwerkslobby", k_ELobbyComparisonEqual);
 SteamAPICall_t hSteamAPICall = SteamMatchmaking()->RequestLobbyList();

 // Set the call result for when Steam returns a list of lobbies
 m_SteamCallResultLobbyMatchList.Set(hSteamAPICall, this, &LobbyManagerClass::OnLobbyMatchListCallback);
}


void LobbyManagerClass::OnLobbyCreated(LobbyCreated_t *pCallback, bool bIOFailure)
{
 // If lobby creation was successful
 if(pCallback->m_eResult==k_EResultOK)
 {
   // Get lobby info
   steamIDLobby = pCallback->m_ulSteamIDLobby;
   SteamMatchmaking()->SetLobbyData(steamIDLobby, "name", "Leadwerkslobby");
   createdlobby = true;
 }
 else MessageBoxA(0, "Could not create lobby.", "Error", 0);
}


void LobbyManagerClass::OnLobbyMatchListCallback(LobbyMatchList_t *pCallback, bool bIOFailure)
{
 if(!bIOFailure && pCallback->m_nLobbiesMatching>0)
 {
   // Join the first lobby on the list
   steamIDLobby = SteamMatchmaking()->GetLobbyByIndex(0);

   SteamAPICall_t hSteamAPICall = SteamMatchmaking()->JoinLobby(steamIDLobby);

   // Set the call result for when player enters lobby
   m_SteamCallResultLobbyEntered.Set(hSteamAPICall, this, &LobbyManagerClass::OnLobbyEntered);
 }
}


void LobbyManagerClass::OnLobbyEntered(LobbyEnter_t *pCallback, bool bIOFailure)
{
 // If we didn't get a success confirmation, let joiner know
 if(pCallback->m_EChatRoomEnterResponse!=k_EChatRoomEnterResponseSuccess)
 {
   MessageBoxA(0, "Failed to enter lobby", "Error", 0);
   return;
 }

 // We succesfully entered someone else's lobby
 steamIDLobby = pCallback->m_ulSteamIDLobby;
 joinedlobby = true;
}


// This gets called for both the invitor and invitees whenever someone joins or leaves a lobby
void LobbyManagerClass::OnLobbyChatUpdate(LobbyChatUpdate_t *pCallback)
{
 // Get the SteamID of the person joining or leaving the lobby
 userjoiningorleavinglobby = pCallback->m_ulSteamIDUserChanged;
}

bool App::Start()
{
 window = Leadwerks::Window::Create("Steam Lobby Example");
 context = Context::Create(window);
 world = World::Create();
 camera = Camera::Create();
 window->HideMouse();

 Steamworks::Initialize();

 return true;
}

bool App::Loop()
{
 if(!SteamAPI_IsSteamRunning())
 {
   MessageBoxA(0, "Steam not detected. Please run Steam before running this program.", "Error", 0);
   return false;
 }

 // Exit program if needed
 if(window->KeyHit(Key::Escape) || window->Closed()) return false;

 // This must be called regularly for callbacks and call results to work
 SteamAPI_RunCallbacks();

 Leadwerks::Time::Update();
 world->Update();
 world->Render();

 context->SetBlendMode(Blend::Alpha);
 context->SetColor(1, 1, 1);

 // If no lobby is created or joined, give player option to create one
 if(!createdlobby && !joinedlobby)
 {
   if(window->KeyHit(Key::C)) lobbymanager.createlobby();
   if(window->KeyHit(Key::R)) lobbymanager.requeststeamlobbylist();

   context->DrawText("Press C to create a lobby or R to refresh lobby list", 10, 30);
   context->DrawText("No lobby matches yet", 10, 50);
 }

 if(createdlobby) context->DrawText("You created a lobby. Lobby name:", 10, 30);
 if(joinedlobby) context->DrawText("You joined a lobby. Lobby name:", 10, 30);

 // Show lobby info
 if(createdlobby || joinedlobby)
 {
   context->DrawText(SteamMatchmaking()->GetLobbyData(steamIDLobby, "name"), 220, 30);
   context->DrawText("Members in lobby:", 10, 50);
   for(int i=0; i<SteamMatchmaking()->GetNumLobbyMembers(steamIDLobby); i++)
   {
     CSteamID steamIDFriendinlobby = SteamMatchmaking()->GetLobbyMemberByIndex(steamIDLobby, i);
     context->DrawText(SteamFriends()->GetFriendPersonaName(steamIDFriendinlobby), 10, 70+20*i);
   }
 }

 context->SetBlendMode(Blend::Solid);
 context->Sync(false);
 Sleep(10); // Sleep a bit to not spam connection

 return true;
}

Share this post


Link to post

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...