diff --git a/Facepunch.Steamworks.Test/Client/Lobby.cs b/Facepunch.Steamworks.Test/Client/Lobby.cs
index 8f3e7b7..3319edb 100644
--- a/Facepunch.Steamworks.Test/Client/Lobby.cs
+++ b/Facepunch.Steamworks.Test/Client/Lobby.cs
@@ -1,32 +1,41 @@
using System;
+using System.Diagnostics;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Facepunch.Steamworks.Test
{
+ [TestClass]
[DeploymentItem("steam_api.dll")]
[DeploymentItem("steam_api64.dll")]
[DeploymentItem("steam_appid.txt")]
- [TestClass]
- class Lobby
+ public class Lobby
{
[TestMethod]
- public void FriendList()
+ public void CreateLobby()
{
- /*
using (var client = new Facepunch.Steamworks.Client(252490))
{
Assert.IsTrue(client.IsValid);
- client.Friends.Refresh();
+ client.Lobby.Create(Steamworks.Lobby.Type.Public, 10);
- Assert.IsNotNull(client.Friends.All);
-
- foreach (var friend in client.Friends.All)
+ client.Lobby.OnLobbyCreated = (success) =>
{
- Console.WriteLine("{0}: {1} (Friend:{2}) (Blocked:{3})", friend.Id, friend.Name, friend.IsFriend, friend.IsBlocked);
+ Assert.IsTrue(success);
+ Assert.IsTrue(client.Lobby.IsValid);
+ Console.WriteLine(client.Lobby.CurrentLobby);
+ client.Lobby.Leave();
+ };
+
+ var sw = Stopwatch.StartNew();
+
+ while (sw.Elapsed.TotalSeconds < 3)
+ {
+ client.Update();
+ System.Threading.Thread.Sleep(10);
}
+
}
- */
}
}
}
diff --git a/Facepunch.Steamworks/Client/Lobby.cs b/Facepunch.Steamworks/Client/Lobby.cs
index 5748672..0db6f79 100644
--- a/Facepunch.Steamworks/Client/Lobby.cs
+++ b/Facepunch.Steamworks/Client/Lobby.cs
@@ -8,22 +8,16 @@ namespace Facepunch.Steamworks
{
public partial class Client : IDisposable
{
- public void JoinLobby(ulong LobbyID)
- {
- native.matchmaking.JoinLobby(LobbyID, OnLobbyJoined);
- }
+ Lobby _lobby;
- void OnLobbyJoined(LobbyEnter_t callback, bool error)
+ public Lobby Lobby
{
- //TODO:
- }
-
- // Create a lobby, auto joins the created lobby
- public Lobby CreateLobby(Lobby.Type lobbyType, int maxMembers)
- {
- var lobby = new Lobby(this, lobbyType);
- native.matchmaking.CreateLobby((SteamNative.LobbyType)lobbyType, maxMembers, lobby.OnLobbyCreatedAPI);
- return lobby;
+ get
+ {
+ if (_lobby == null)
+ _lobby = new Steamworks.Lobby(this);
+ return _lobby;
+ }
}
}
public class Lobby : IDisposable
@@ -34,47 +28,63 @@ namespace Facepunch.Steamworks
Private = SteamNative.LobbyType.Private,
FriendsOnly = SteamNative.LobbyType.FriendsOnly,
Public = SteamNative.LobbyType.Public,
- Invisible = SteamNative.LobbyType.Invisible
+ Invisible = SteamNative.LobbyType.Invisible,
+ None
}
internal Client client;
- ///
- /// Returns true if we tried to create this lobby but it returned
- /// an error.
- ///
- public bool IsError { get; private set; }
-
- ///
- /// Returns true if this lobby is valid, ie, we've received
- /// a positive response from Steam about it.
- ///
- public bool IsValid => LobbyID != 0;
-
- ///
- /// The CSteamID of the lobby that was created
- ///
- internal ulong LobbyID { get; private set; }
-
- ///
- /// The name of the lobby as a property for easy getting/setting
- ///
- public string Name
- {
- get { return _name; }
- set { if (_name == value) return; SetLobbyData("name", value); }
- }
- string _name = "";
-
- ///
- /// Callback for when lobby is created
- ///
- public Action OnLobbyCreated;
-
- public Lobby(Client c, Type type)
+ public Lobby(Client c)
{
client = c;
- LobbyType = type;
+ SteamNative.LobbyDataUpdate_t.RegisterCallback(client, OnLobbyDataUpdated);
+ }
+
+ ///
+ /// The CSteamID of the lobby we're currently in.
+ ///
+ public ulong CurrentLobby { get; private set; }
+
+ public LobbyData CurrentLobbyData { get; private set; }
+
+ ///
+ /// Returns true if this lobby is valid, ie, we've succesffuly created and/or joined a lobby.
+ ///
+ public bool IsValid => CurrentLobby != 0;
+
+ ///
+ /// Join a Lobby through its LobbyID. LobbyJoined is called when the lobby has successfully been joined.
+ ///
+ /// CSteamID of lobby to join
+ public void Join(ulong lobbyID)
+ {
+ client.native.matchmaking.JoinLobby(lobbyID, OnLobbyJoinedAPI);
+ }
+
+ void OnLobbyJoinedAPI(LobbyEnter_t callback, bool error)
+ {
+ if (error || (callback.EChatRoomEnterResponse != (uint)(SteamNative.ChatRoomEnterResponse.Success)))
+ {
+ if (OnLobbyJoined != null) { OnLobbyJoined(false); }
+ return;
+ }
+
+ CurrentLobby = callback.SteamIDLobby;
+ UpdateLobbyData();
+ if (OnLobbyJoined != null) { OnLobbyJoined(true); }
+ }
+
+ public Action OnLobbyJoined;
+
+ ///
+ /// Creates a lobby and returns the created lobby. You auto join the created lobby. The lobby is stored in Client.CurrentLobby if successful.
+ ///
+ /// The Lobby.Type of Lobby to be created
+ /// The maximum amount of people you want to be able to be in this lobby, including yourself
+ public void Create(Lobby.Type lobbyType, int maxMembers)
+ {
+ client.native.matchmaking.CreateLobby((SteamNative.LobbyType)lobbyType, maxMembers, OnLobbyCreatedAPI);
+ LobbyType = lobbyType;
}
internal void OnLobbyCreatedAPI(LobbyCreated_t callback, bool error)
@@ -82,105 +92,239 @@ namespace Facepunch.Steamworks
//from SpaceWarClient.cpp 793
if (error || (callback.Result != Result.OK))
{
- IsError = true;
+ if ( OnLobbyCreated != null) { OnLobbyCreated(false); }
return;
}
- Owner = client.SteamId; //this is implicitly set on creation but need to cache it here
- LobbyID = callback.SteamIDLobby;
- MaxMembers = client.native.matchmaking.GetLobbyMemberLimit(LobbyID);
- SetLobbyData("appid", client.AppId.ToString());
-
- if (OnLobbyCreated != null) { OnLobbyCreated(); }
+ //set owner specific properties
+ Owner = client.SteamId;
+ CurrentLobby = callback.SteamIDLobby;
+ CurrentLobbyData = new LobbyData(client, CurrentLobby);
+ Name = client.Username + "'s Lobby";
+ CurrentLobbyData.SetData("appid", client.AppId.ToString());
+ CurrentLobbyData.SetData("lobbytype", LobbyType.ToString());
+ if (OnLobbyCreated != null) { OnLobbyCreated(true); }
}
- Dictionary LobbyData = new Dictionary();
- public void SetLobbyData(string key, string value)
+ ///
+ /// Callback for when lobby is created
+ ///
+ public Action OnLobbyCreated;
+
+ public class LobbyData
{
- if (LobbyData.ContainsKey(key))
- {
- if (LobbyData[key] == value)
- return;
+ internal Client client;
+ internal ulong lobby;
+ internal Dictionary data;
- LobbyData[key] = value;
- }
- else
+ public LobbyData(Client c, ulong l)
{
- LobbyData.Add(key, value);
+ client = c;
+ lobby = l;
+ data = new Dictionary();
+ }
+
+ public string GetData(string k)
+ {
+ if (data.ContainsKey(k))
+ {
+ return data[k];
+ }
+
+ return "ERROR: key not found";
+ }
+
+ public bool SetData(string k, string v)
+ {
+ if (data.ContainsKey(k))
+ {
+ if (data[k] == v) { return true; }
+ if (client.native.matchmaking.SetLobbyData(lobby, k, v))
+ {
+ data[k] = v;
+ return true;
+ }
+ }
+ else
+ {
+ if (client.native.matchmaking.SetLobbyData(lobby, k, v))
+ {
+ data.Add(k, v);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public bool RemoveData(string k)
+ {
+ if (data.ContainsKey(k))
+ {
+ if (client.native.matchmaking.DeleteLobbyData(lobby, k))
+ {
+ data.Remove(k);
+ return true;
+ }
+ }
+
+ return false;
}
- client.native.matchmaking.SetLobbyData(LobbyID, key, value);
}
- public void RemoveLobbyData(string key)
+ internal void OnLobbyDataUpdated(LobbyDataUpdate_t callback, bool error)
{
- if (LobbyData.ContainsKey(key))
+ if(error) { return; }
+ if(callback.SteamIDLobby == CurrentLobby) //actual lobby data was updated by owner
{
- LobbyData.Remove(key);
+ UpdateLobbyData();
}
- client.native.matchmaking.DeleteLobbyData(LobbyID, key);
+ //TODO: need to check and see if the updated member is in this lobby
+ }
+
+ ///
+ /// Updates the LobbyData property to have the data for the current lobby, if any
+ ///
+ internal void UpdateLobbyData()
+ {
+ int dataCount = client.native.matchmaking.GetLobbyDataCount(CurrentLobby);
+ CurrentLobbyData = new LobbyData(client, CurrentLobby);
+ for (int i = 0; i < dataCount; i++)
+ {
+ if (client.native.matchmaking.GetLobbyDataByIndex(CurrentLobby, i, out string key, out string value))
+ {
+ CurrentLobbyData.SetData(key, value);
+ }
+ }
}
public Type LobbyType
{
- get { return _lobbyType; }
+ get
+ {
+ if (!IsValid) { return Type.None; } //if we're currently in a valid server
+
+ //we know that we've set the lobby type via the lobbydata in the creation function
+ //ps this is important because steam doesn't have an easy way to get lobby type (why idk)
+ string lobbyType = CurrentLobbyData.GetData("lobbytype");
+ switch (lobbyType)
+ {
+ case "Private":
+ return Type.Private;
+ case "FriendsOnly":
+ return Type.FriendsOnly;
+ case "Invisible":
+ return Type.Invisible;
+ case "Public":
+ return Type.Public;
+ default:
+ return Type.None;
+ }
+ }
set
{
- if (_lobbyType == value) return;
- //only call the proper method if the lobby is valid, otherwise cache the value
- if(IsValid)
+ if(!IsValid) { return; }
+ if(client.native.matchmaking.SetLobbyType(CurrentLobby, (SteamNative.LobbyType)value))
{
- client.native.matchmaking.SetLobbyType(LobbyID, (SteamNative.LobbyType)value); //returns bool?
+ CurrentLobbyData.SetData("lobbytype", value.ToString());
}
- _lobbyType = value;
}
}
- Type _lobbyType;
+ ///
+ /// The name of the lobby as a property for easy getting/setting. Note that this is setting LobbyData, which you cannot do unless you are the Owner of the lobby
+ ///
+ public string Name
+ {
+ get
+ {
+ if (!IsValid) { return ""; }
+ return CurrentLobbyData.GetData("name");
+ }
+ set
+ {
+ if (!IsValid) { return; }
+ CurrentLobbyData.SetData("name", value);
+ }
+ }
- //Must be the owner to change the owner
+ ///
+ /// The Owner of the current lobby. Returns 0 if you are not in a valid lobby.
+ ///
public ulong Owner
{
get
{
- if (_owner == 0)
+ if (_owner == 0 && IsValid)
{
- _owner = client.native.matchmaking.GetLobbyOwner(LobbyID);
- return _owner;
+ _owner = client.native.matchmaking.GetLobbyOwner(CurrentLobby);
}
return _owner;
}
- private set { if (_owner == value) return; client.native.matchmaking.SetLobbyOwner(LobbyID, value); _owner = value; }
+ private set
+ {
+ if (_owner == value) return;
+ if (client.native.matchmaking.SetLobbyOwner(CurrentLobby, value)) { _owner = value; }
+ }
}
ulong _owner = 0;
// Can the lobby be joined by other people
public bool Joinable
{
- get { return _joinable; }
- set { if (_joinable == value) return; client.native.matchmaking.SetLobbyJoinable(LobbyID, value); _joinable = value; }
+ get
+ {
+ if (!IsValid) { return false; }
+ string joinable = CurrentLobbyData.GetData("joinable");
+ switch (joinable)
+ {
+ case "true":
+ return true;
+ case "false":
+ return false;
+ default:
+ return false;
+ }
+ }
+ set
+ {
+ if (!IsValid) { return; }
+ if (client.native.matchmaking.SetLobbyJoinable(CurrentLobby, value))
+ {
+ CurrentLobbyData.SetData("joinable", value.ToString());
+ }
+ }
}
- bool _joinable = true; //steam default
// How many people can be in the Lobby
public int MaxMembers
{
- get { return _maxMembers; }
- set { if (_maxMembers == value) return; client.native.matchmaking.SetLobbyMemberLimit(LobbyID, value); _maxMembers = value; }
+ get
+ {
+ if (!IsValid) { return 0; } //0 is default, but value is inited when lobby is created.
+ return client.native.matchmaking.GetLobbyMemberLimit(CurrentLobby);
+ }
+ set
+ {
+ if (!IsValid) { return; }
+ client.native.matchmaking.SetLobbyMemberLimit(CurrentLobby, value);
+ }
}
- int _maxMembers = 0;
//How many people are currently in the lobby
public int NumMembers
{
- get { return client.native.matchmaking.GetNumLobbyMembers(LobbyID);}
+ get { return client.native.matchmaking.GetNumLobbyMembers(CurrentLobby);}
}
//leave the current lobby
public void Leave()
{
- client.native.matchmaking.LeaveLobby(LobbyID);
+ client.native.matchmaking.LeaveLobby(CurrentLobby);
+ _owner = 0;
+ CurrentLobbyData = null;
}
public void Dispose()
@@ -189,8 +333,6 @@ namespace Facepunch.Steamworks
}
/*not implemented
- // returns a lobby metadata key/values pair by index
- client.native.matchmaking.GetLobbyDataByIndex;
//set the game server of the lobby
client.native.matchmaking.GetLobbyGameServer;
@@ -199,22 +341,15 @@ namespace Facepunch.Steamworks
//data for people in the actual lobby - scores/elo/characters/etc.
client.native.matchmaking.SetLobbyMemberData; //local user
client.native.matchmaking.GetLobbyMemberData; //any user in this lobby
-
// returns steamid of member
// note that the current user must be in a lobby to retrieve CSteamIDs of other users in that lobby
client.native.matchmaking.GetLobbyMemberByIndex;
- //for linking lobbies idk havent looked hard yet
- client.native.matchmaking.SetLinkedLobby;
-
//chat functions
client.native.matchmaking.SendLobbyChatMsg;
client.native.matchmaking.GetLobbyChatEntry;
- //get total data count (why?)
- client.native.matchmaking.GetLobbyDataCount
-
//invite your frans
client.native.matchmaking.InviteUserToLobby //this invites the user the current lobby the invitee is in
*/
diff --git a/Facepunch.Steamworks/Client/LobbyList.cs b/Facepunch.Steamworks/Client/LobbyList.cs
index 1019c4e..7dc9266 100644
--- a/Facepunch.Steamworks/Client/LobbyList.cs
+++ b/Facepunch.Steamworks/Client/LobbyList.cs
@@ -70,17 +70,32 @@ namespace Facepunch.Steamworks
}
else
{
- //need to sub the lobbyid to the request func
- //client.native.matchmaking.RequestLobbyData(lobby)
+ //need to get the info for the missing lobby
+ client.native.matchmaking.RequestLobbyData(lobby);
+ SteamNative.LobbyDataUpdate_t.RegisterCallback(client, OnLobbyDataUpdated);
}
}
- if (OnLobbiesRefreshed != null) { OnLobbiesRefreshed(); }
+ if (OnLobbiesUpdated != null) { OnLobbiesUpdated(); }
}
-
- public Action OnLobbiesRefreshed;
+ void OnLobbyDataUpdated(LobbyDataUpdate_t callback, bool error)
+ {
+ if (callback.Success == 1) //1 if success, 0 if failure
+ {
+ Lobby lobby = Lobbies.Find(x => x.LobbyID == callback.SteamIDLobby);
+ if (lobby == null) //need to add this lobby to the list
+ {
+ Lobbies.Add(lobby);
+ }
+
+ //otherwise lobby data in general was updated and you should listen to see what changed
+ if (OnLobbiesUpdated != null) { OnLobbiesUpdated(); }
+ }
+ }
+
+ public Action OnLobbiesUpdated;
public void Dispose()
{