mirror of
https://github.com/Facepunch/Facepunch.Steamworks.git
synced 2024-12-24 13:45:37 +03:00
Updates Lobby to work for both Lobby members and Lobby Owners
Uses a more rigurous approach to LobbyData and uses it as a cache for string-able values to be able to be retrieved by members and set only by the owner.
This commit is contained in:
parent
7e38750f2e
commit
e1c738fc8b
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 @@ public enum Type : int
|
||||
Private = SteamNative.LobbyType.Private,
|
||||
FriendsOnly = SteamNative.LobbyType.FriendsOnly,
|
||||
Public = SteamNative.LobbyType.Public,
|
||||
Invisible = SteamNative.LobbyType.Invisible
|
||||
Invisible = SteamNative.LobbyType.Invisible,
|
||||
None
|
||||
}
|
||||
|
||||
internal Client client;
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if we tried to create this lobby but it returned
|
||||
/// an error.
|
||||
/// </summary>
|
||||
public bool IsError { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this lobby is valid, ie, we've received
|
||||
/// a positive response from Steam about it.
|
||||
/// </summary>
|
||||
public bool IsValid => LobbyID != 0;
|
||||
|
||||
/// <summary>
|
||||
/// The CSteamID of the lobby that was created
|
||||
/// </summary>
|
||||
internal ulong LobbyID { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of the lobby as a property for easy getting/setting
|
||||
/// </summary>
|
||||
public string Name
|
||||
{
|
||||
get { return _name; }
|
||||
set { if (_name == value) return; SetLobbyData("name", value); }
|
||||
}
|
||||
string _name = "";
|
||||
|
||||
/// <summary>
|
||||
/// Callback for when lobby is created
|
||||
/// </summary>
|
||||
public Action OnLobbyCreated;
|
||||
|
||||
public Lobby(Client c, Type type)
|
||||
public Lobby(Client c)
|
||||
{
|
||||
client = c;
|
||||
LobbyType = type;
|
||||
SteamNative.LobbyDataUpdate_t.RegisterCallback(client, OnLobbyDataUpdated);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The CSteamID of the lobby we're currently in.
|
||||
/// </summary>
|
||||
public ulong CurrentLobby { get; private set; }
|
||||
|
||||
public LobbyData CurrentLobbyData { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this lobby is valid, ie, we've succesffuly created and/or joined a lobby.
|
||||
/// </summary>
|
||||
public bool IsValid => CurrentLobby != 0;
|
||||
|
||||
/// <summary>
|
||||
/// Join a Lobby through its LobbyID. LobbyJoined is called when the lobby has successfully been joined.
|
||||
/// </summary>
|
||||
/// <param name="lobbyID">CSteamID of lobby to join</param>
|
||||
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<bool> OnLobbyJoined;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a lobby and returns the created lobby. You auto join the created lobby. The lobby is stored in Client.CurrentLobby if successful.
|
||||
/// </summary>
|
||||
/// <param name="lobbyType">The Lobby.Type of Lobby to be created</param>
|
||||
/// <param name="maxMembers">The maximum amount of people you want to be able to be in this lobby, including yourself</param>
|
||||
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 @@ internal void OnLobbyCreatedAPI(LobbyCreated_t callback, bool error)
|
||||
//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<string, string> LobbyData = new Dictionary<string, string>();
|
||||
public void SetLobbyData(string key, string value)
|
||||
/// <summary>
|
||||
/// Callback for when lobby is created
|
||||
/// </summary>
|
||||
public Action<bool> OnLobbyCreated;
|
||||
|
||||
public class LobbyData
|
||||
{
|
||||
if (LobbyData.ContainsKey(key))
|
||||
{
|
||||
if (LobbyData[key] == value)
|
||||
return;
|
||||
internal Client client;
|
||||
internal ulong lobby;
|
||||
internal Dictionary<string, string> data;
|
||||
|
||||
LobbyData[key] = value;
|
||||
}
|
||||
else
|
||||
public LobbyData(Client c, ulong l)
|
||||
{
|
||||
LobbyData.Add(key, value);
|
||||
client = c;
|
||||
lobby = l;
|
||||
data = new Dictionary<string, string>();
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the LobbyData property to have the data for the current lobby, if any
|
||||
/// </summary>
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
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
|
||||
/// <summary>
|
||||
/// The Owner of the current lobby. Returns 0 if you are not in a valid lobby.
|
||||
/// </summary>
|
||||
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 @@ public void Dispose()
|
||||
}
|
||||
|
||||
/*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 @@ public void Dispose()
|
||||
//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
|
||||
*/
|
||||
|
@ -70,17 +70,32 @@ void OnLobbyList(LobbyMatchList_t callback, bool error)
|
||||
}
|
||||
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()
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user