suck it unity collab
This commit is contained in:
parent
2630db1920
commit
dad44ef0cf
456 changed files with 1861 additions and 128 deletions
180
Assets/Code/Photon/PhotonLoadbalancingApi/Extensions.cs
Normal file
180
Assets/Code/Photon/PhotonLoadbalancingApi/Extensions.cs
Normal file
|
@ -0,0 +1,180 @@
|
|||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="Extensions.cs" company="Exit Games GmbH">
|
||||
// Photon Extensions - Copyright (C) 2017 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// Provides some helpful methods and extensions for Hashtables, etc.
|
||||
// </summary>
|
||||
// <author>developer@photonengine.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#if UNITY_4_7_OR_NEWER
|
||||
#define UNITY
|
||||
#endif
|
||||
|
||||
|
||||
namespace ExitGames.Client.Photon.LoadBalancing
|
||||
{
|
||||
using System.Collections;
|
||||
|
||||
#if UNITY
|
||||
using UnityEngine;
|
||||
using Debug = UnityEngine.Debug;
|
||||
#endif
|
||||
#if UNITY || NETFX_CORE
|
||||
using Hashtable = ExitGames.Client.Photon.Hashtable;
|
||||
using SupportClass = ExitGames.Client.Photon.SupportClass;
|
||||
#endif
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This static class defines some useful extension methods for several existing classes (e.g. Vector3, float and others).
|
||||
/// </summary>
|
||||
public static class Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Merges all keys from addHash into the target. Adds new keys and updates the values of existing keys in target.
|
||||
/// </summary>
|
||||
/// <param name="target">The IDictionary to update.</param>
|
||||
/// <param name="addHash">The IDictionary containing data to merge into target.</param>
|
||||
public static void Merge(this IDictionary target, IDictionary addHash)
|
||||
{
|
||||
if (addHash == null || target.Equals(addHash))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (object key in addHash.Keys)
|
||||
{
|
||||
target[key] = addHash[key];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Merges keys of type string to target Hashtable.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Does not remove keys from target (so non-string keys CAN be in target if they were before).
|
||||
/// </remarks>
|
||||
/// <param name="target">The target IDicitionary passed in plus all string-typed keys from the addHash.</param>
|
||||
/// <param name="addHash">A IDictionary that should be merged partly into target to update it.</param>
|
||||
public static void MergeStringKeys(this IDictionary target, IDictionary addHash)
|
||||
{
|
||||
if (addHash == null || target.Equals(addHash))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (object key in addHash.Keys)
|
||||
{
|
||||
// only merge keys of type string
|
||||
if (key is string)
|
||||
{
|
||||
target[key] = addHash[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Helper method for debugging of IDictionary content, inlcuding type-information. Using this is not performant.</summary>
|
||||
/// <remarks>Should only be used for debugging as necessary.</remarks>
|
||||
/// <param name="origin">Some Dictionary or Hashtable.</param>
|
||||
/// <returns>String of the content of the IDictionary.</returns>
|
||||
public static string ToStringFull(this IDictionary origin)
|
||||
{
|
||||
return SupportClass.DictionaryToString(origin, false);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>Helper method for debugging of object[] content. Using this is not performant.</summary>
|
||||
/// <remarks>Should only be used for debugging as necessary.</remarks>
|
||||
/// <param name="data">Any object[].</param>
|
||||
/// <returns>A comma-separated string containing each value's ToString().</returns>
|
||||
public static string ToStringFull(this object[] data)
|
||||
{
|
||||
if (data == null) return "null";
|
||||
|
||||
string[] sb = new string[data.Length];
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
{
|
||||
object o = data[i];
|
||||
sb[i] = (o != null) ? o.ToString() : "null";
|
||||
}
|
||||
|
||||
return string.Join(", ", sb);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This method copies all string-typed keys of the original into a new Hashtable.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Does not recurse (!) into hashes that might be values in the root-hash.
|
||||
/// This does not modify the original.
|
||||
/// </remarks>
|
||||
/// <param name="original">The original IDictonary to get string-typed keys from.</param>
|
||||
/// <returns>New Hashtable containing only string-typed keys of the original.</returns>
|
||||
public static Hashtable StripToStringKeys(this IDictionary original)
|
||||
{
|
||||
Hashtable target = new Hashtable();
|
||||
if (original != null)
|
||||
{
|
||||
foreach (object key in original.Keys)
|
||||
{
|
||||
if (key is string)
|
||||
{
|
||||
target[key] = original[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This removes all key-value pairs that have a null-reference as value.
|
||||
/// Photon properties are removed by setting their value to null.
|
||||
/// Changes the original passed IDictionary!
|
||||
/// </summary>
|
||||
/// <param name="original">The IDictionary to strip of keys with null-values.</param>
|
||||
public static void StripKeysWithNullValues(this IDictionary original)
|
||||
{
|
||||
object[] keys = new object[original.Count];
|
||||
original.Keys.CopyTo(keys, 0);
|
||||
|
||||
for (int index = 0; index < keys.Length; index++)
|
||||
{
|
||||
var key = keys[index];
|
||||
if (original[key] == null)
|
||||
{
|
||||
original.Remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a particular integer value is in an int-array.
|
||||
/// </summary>
|
||||
/// <remarks>This might be useful to look up if a particular actorNumber is in the list of players of a room.</remarks>
|
||||
/// <param name="target">The array of ints to check.</param>
|
||||
/// <param name="nr">The number to lookup in target.</param>
|
||||
/// <returns>True if nr was found in target.</returns>
|
||||
public static bool Contains(this int[] target, int nr)
|
||||
{
|
||||
if (target == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int index = 0; index < target.Length; index++)
|
||||
{
|
||||
if (target[index] == nr)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
11
Assets/Code/Photon/PhotonLoadbalancingApi/Extensions.cs.meta
Normal file
11
Assets/Code/Photon/PhotonLoadbalancingApi/Extensions.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ee1c48ab6ff903f4c823e7cf48b423e5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
45
Assets/Code/Photon/PhotonLoadbalancingApi/FriendInfo.cs
Normal file
45
Assets/Code/Photon/PhotonLoadbalancingApi/FriendInfo.cs
Normal file
|
@ -0,0 +1,45 @@
|
|||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="FriendInfo.cs" company="Exit Games GmbH">
|
||||
// Loadbalancing Framework for Photon - Copyright (C) 2013 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// Collection of values related to a user / friend.
|
||||
// </summary>
|
||||
// <author>developer@photonengine.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
#if UNITY_4_7_OR_NEWER
|
||||
#define UNITY
|
||||
#endif
|
||||
|
||||
|
||||
namespace ExitGames.Client.Photon.LoadBalancing
|
||||
{
|
||||
#if UNITY || NETFX_CORE
|
||||
using Hashtable = ExitGames.Client.Photon.Hashtable;
|
||||
using SupportClass = ExitGames.Client.Photon.SupportClass;
|
||||
#endif
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Used to store info about a friend's online state and in which room he/she is.
|
||||
/// </summary>
|
||||
public class FriendInfo
|
||||
{
|
||||
public string Name { get; internal protected set; }
|
||||
public bool IsOnline { get; internal protected set; }
|
||||
public string Room { get; internal protected set; }
|
||||
|
||||
public bool IsInRoom
|
||||
{
|
||||
get { return this.IsOnline && !string.IsNullOrEmpty(this.Room); }
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("{0}\t is: {1}", this.Name, (!this.IsOnline) ? "offline" : this.IsInRoom ? "playing" : "on master");
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Code/Photon/PhotonLoadbalancingApi/FriendInfo.cs.meta
Normal file
11
Assets/Code/Photon/PhotonLoadbalancingApi/FriendInfo.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 723f710efc79ee0469dbe94bf0cc9ddb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
2582
Assets/Code/Photon/PhotonLoadbalancingApi/LoadBalancingClient.cs
Normal file
2582
Assets/Code/Photon/PhotonLoadbalancingApi/LoadBalancingClient.cs
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f9a8ceffad89d164e8b5ba037f5d34f7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
1893
Assets/Code/Photon/PhotonLoadbalancingApi/LoadBalancingPeer.cs
Normal file
1893
Assets/Code/Photon/PhotonLoadbalancingApi/LoadBalancingPeer.cs
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a3aba55d840ae78459c990a41ed84f82
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
430
Assets/Code/Photon/PhotonLoadbalancingApi/Player.cs
Normal file
430
Assets/Code/Photon/PhotonLoadbalancingApi/Player.cs
Normal file
|
@ -0,0 +1,430 @@
|
|||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="Player.cs" company="Exit Games GmbH">
|
||||
// Loadbalancing Framework for Photon - Copyright (C) 2011 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// Per client in a room, a Player is created. This client's Player is also
|
||||
// known as PhotonClient.LocalPlayer and the only one you might change
|
||||
// properties for.
|
||||
// </summary>
|
||||
// <author>developer@photonengine.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#define UNITY
|
||||
|
||||
namespace ExitGames.Client.Photon.LoadBalancing
|
||||
{
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using ExitGames.Client.Photon;
|
||||
|
||||
#if UNITY
|
||||
using UnityEngine;
|
||||
#endif
|
||||
#if UNITY || NETFX_CORE
|
||||
using Hashtable = ExitGames.Client.Photon.Hashtable;
|
||||
using SupportClass = ExitGames.Client.Photon.SupportClass;
|
||||
#endif
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Summarizes a "player" within a room, identified (in that room) by ID (or "actorID").
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Each player has a actorID, valid for that room. It's -1 until assigned by server (and client logic).
|
||||
/// </remarks>
|
||||
public class Player
|
||||
{
|
||||
/// <summary>
|
||||
/// Used internally to identify the masterclient of a room.
|
||||
/// </summary>
|
||||
protected internal Room RoomReference { get; set; }
|
||||
|
||||
|
||||
/// <summary>Backing field for property.</summary>
|
||||
private int actorID = -1;
|
||||
|
||||
/// <summary>Identifier of this player in current room. Also known as: actorNumber or actorID. It's -1 outside of rooms.</summary>
|
||||
/// <remarks>The ID is assigned per room and only valid in that context. It will change even on leave and re-join. IDs are never re-used per room.</remarks>
|
||||
public int ID
|
||||
{
|
||||
get { return this.actorID; }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>Only one player is controlled by each client. Others are not local.</summary>
|
||||
public readonly bool IsLocal;
|
||||
|
||||
|
||||
/// <summary>Background field for nickName.</summary>
|
||||
private string nickName;
|
||||
|
||||
/// <summary>Non-unique nickname of this player. Synced automatically in a room.</summary>
|
||||
/// <remarks>
|
||||
/// A player might change his own playername in a room (it's only a property).
|
||||
/// Setting this value updates the server and other players (using an operation).
|
||||
/// </remarks>
|
||||
public string NickName
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.nickName;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (!string.IsNullOrEmpty(this.nickName) && this.nickName.Equals(value))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.nickName = value;
|
||||
|
||||
// update a room, if we changed our nickName (locally, while being in a room)
|
||||
if (this.IsLocal && this.RoomReference != null && this.RoomReference.IsLocalClientInside)
|
||||
{
|
||||
this.SetPlayerNameProperty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>UserId of the player, available when the room got created with RoomOptions.PublishUserId = true.</summary>
|
||||
/// <remarks>Useful for PhotonNetwork.FindFriends and blocking slots in a room for expected players (e.g. in PhotonNetwork.CreateRoom).</remarks>
|
||||
public string UserId { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if this player is the Master Client of the current room.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See also: PhotonNetwork.masterClient.
|
||||
/// </remarks>
|
||||
public bool IsMasterClient
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.RoomReference == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.ID == this.RoomReference.MasterClientId;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>If this player is active in the room (and getting events which are currently being sent).</summary>
|
||||
/// <remarks>
|
||||
/// Inactive players keep their spot in a room but otherwise behave as if offline (no matter what their actual connection status is).
|
||||
/// The room needs a PlayerTTL > 0. If a player is inactive for longer than PlayerTTL, the server will remove this player from the room.
|
||||
/// For a client "rejoining" a room, is the same as joining it: It gets properties, cached events and then the live events.
|
||||
/// </remarks>
|
||||
public bool IsInactive { get; set; }
|
||||
|
||||
/// <summary>Read-only cache for custom properties of player. Set via Player.SetCustomProperties.</summary>
|
||||
/// <remarks>
|
||||
/// Don't modify the content of this Hashtable. Use SetCustomProperties and the
|
||||
/// properties of this class to modify values. When you use those, the client will
|
||||
/// sync values with the server.
|
||||
/// </remarks>
|
||||
/// <see cref="SetCustomProperties"/>
|
||||
public Hashtable CustomProperties { get; private set; }
|
||||
|
||||
/// <summary>Creates a Hashtable with all properties (custom and "well known" ones).</summary>
|
||||
/// <remarks>Creates new Hashtables each time used, so if used more often, cache this.</remarks>
|
||||
public Hashtable AllProperties
|
||||
{
|
||||
get
|
||||
{
|
||||
Hashtable allProps = new Hashtable();
|
||||
allProps.Merge(this.CustomProperties);
|
||||
allProps[ActorProperties.PlayerName] = this.nickName;
|
||||
return allProps;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Can be used to store a reference that's useful to know "by player".</summary>
|
||||
/// <remarks>Example: Set a player's character as Tag by assigning the GameObject on Instantiate.</remarks>
|
||||
public object TagObject;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a player instance.
|
||||
/// To extend and replace this Player, override LoadBalancingPeer.CreatePlayer().
|
||||
/// </summary>
|
||||
/// <param name="nickName">NickName of the player (a "well known property").</param>
|
||||
/// <param name="actorID">ID or ActorNumber of this player in the current room (a shortcut to identify each player in room)</param>
|
||||
/// <param name="isLocal">If this is the local peer's player (or a remote one).</param>
|
||||
protected internal Player(string nickName, int actorID, bool isLocal) : this(nickName, actorID, isLocal, null)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a player instance.
|
||||
/// To extend and replace this Player, override LoadBalancingPeer.CreatePlayer().
|
||||
/// </summary>
|
||||
/// <param name="nickName">NickName of the player (a "well known property").</param>
|
||||
/// <param name="actorID">ID or ActorNumber of this player in the current room (a shortcut to identify each player in room)</param>
|
||||
/// <param name="isLocal">If this is the local peer's player (or a remote one).</param>
|
||||
/// <param name="playerProperties">A Hashtable of custom properties to be synced. Must use String-typed keys and serializable datatypes as values.</param>
|
||||
protected internal Player(string nickName, int actorID, bool isLocal, Hashtable playerProperties)
|
||||
{
|
||||
this.IsLocal = isLocal;
|
||||
this.actorID = actorID;
|
||||
this.NickName = nickName;
|
||||
|
||||
this.CustomProperties = new Hashtable();
|
||||
this.InternalCacheProperties(playerProperties);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get a Player by ActorNumber (Player.ID).
|
||||
/// </summary>
|
||||
/// <param name="id">ActorNumber of the a player in this room.</param>
|
||||
/// <returns>Player or null.</returns>
|
||||
public Player Get(int id)
|
||||
{
|
||||
if (this.RoomReference == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.RoomReference.GetPlayer(id);
|
||||
}
|
||||
|
||||
/// <summary>Gets this Player's next Player, as sorted by ActorNumber (Player.ID). Wraps around.</summary>
|
||||
/// <returns>Player or null.</returns>
|
||||
public Player GetNext()
|
||||
{
|
||||
return GetNextFor(this.ID);
|
||||
}
|
||||
|
||||
/// <summary>Gets a Player's next Player, as sorted by ActorNumber (Player.ID). Wraps around.</summary>
|
||||
/// <remarks>Useful when you pass something to the next player. For example: passing the turn to the next player.</remarks>
|
||||
/// <param name="currentPlayer">The Player for which the next is being needed.</param>
|
||||
/// <returns>Player or null.</returns>
|
||||
public Player GetNextFor(Player currentPlayer)
|
||||
{
|
||||
if (currentPlayer == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return GetNextFor(currentPlayer.ID);
|
||||
}
|
||||
|
||||
/// <summary>Gets a Player's next Player, as sorted by ActorNumber (Player.ID). Wraps around.</summary>
|
||||
/// <remarks>Useful when you pass something to the next player. For example: passing the turn to the next player.</remarks>
|
||||
/// <param name="currentPlayerId">The ActorNumber (Player.ID) for which the next is being needed.</param>
|
||||
/// <returns>Player or null.</returns>
|
||||
public Player GetNextFor(int currentPlayerId)
|
||||
{
|
||||
if (this.RoomReference == null || this.RoomReference.Players == null || this.RoomReference.Players.Count < 2)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Dictionary<int, Player> players = this.RoomReference.Players;
|
||||
int nextHigherId = int.MaxValue; // we look for the next higher ID
|
||||
int lowestId = currentPlayerId; // if we are the player with the highest ID, there is no higher and we return to the lowest player's id
|
||||
|
||||
foreach (int playerid in players.Keys)
|
||||
{
|
||||
if (playerid < lowestId)
|
||||
{
|
||||
lowestId = playerid; // less than any other ID (which must be at least less than this player's id).
|
||||
}
|
||||
else if (playerid > currentPlayerId && playerid < nextHigherId)
|
||||
{
|
||||
nextHigherId = playerid; // more than our ID and less than those found so far.
|
||||
}
|
||||
}
|
||||
|
||||
//UnityEngine.Debug.LogWarning("Debug. " + currentPlayerId + " lower: " + lowestId + " higher: " + nextHigherId + " ");
|
||||
//UnityEngine.Debug.LogWarning(this.RoomReference.GetPlayer(currentPlayerId));
|
||||
//UnityEngine.Debug.LogWarning(this.RoomReference.GetPlayer(lowestId));
|
||||
//if (nextHigherId != int.MaxValue) UnityEngine.Debug.LogWarning(this.RoomReference.GetPlayer(nextHigherId));
|
||||
return (nextHigherId != int.MaxValue) ? players[nextHigherId] : players[lowestId];
|
||||
}
|
||||
|
||||
|
||||
/// <summary>Caches properties for new Players or when updates of remote players are received. Use SetCustomProperties() for a synced update.</summary>
|
||||
/// <remarks>
|
||||
/// This only updates the CustomProperties and doesn't send them to the server.
|
||||
/// Mostly used when creating new remote players, where the server sends their properties.
|
||||
/// </remarks>
|
||||
public virtual void InternalCacheProperties(Hashtable properties)
|
||||
{
|
||||
if (properties == null || properties.Count == 0 || this.CustomProperties.Equals(properties))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (properties.ContainsKey(ActorProperties.PlayerName))
|
||||
{
|
||||
string nameInServersProperties = (string)properties[ActorProperties.PlayerName];
|
||||
if (nameInServersProperties != null)
|
||||
{
|
||||
if (this.IsLocal)
|
||||
{
|
||||
// the local playername is different than in the properties coming from the server
|
||||
// so the local nickName was changed and the server is outdated -> update server
|
||||
// update property instead of using the outdated nickName coming from server
|
||||
if (!nameInServersProperties.Equals(this.nickName))
|
||||
{
|
||||
this.SetPlayerNameProperty();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.NickName = nameInServersProperties;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (properties.ContainsKey(ActorProperties.UserId))
|
||||
{
|
||||
this.UserId = (string)properties[ActorProperties.UserId];
|
||||
}
|
||||
if (properties.ContainsKey(ActorProperties.IsInactive))
|
||||
{
|
||||
this.IsInactive = (bool)properties[ActorProperties.IsInactive]; //TURNBASED new well-known propery for players
|
||||
}
|
||||
|
||||
this.CustomProperties.MergeStringKeys(properties);
|
||||
this.CustomProperties.StripKeysWithNullValues();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Brief summary string of the Player. Includes name or player.ID and if it's the Master Client.
|
||||
/// </summary>
|
||||
public override string ToString()
|
||||
{
|
||||
return this.NickName + " " + SupportClass.DictionaryToString(this.CustomProperties);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// String summary of the Player: player.ID, name and all custom properties of this user.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Use with care and not every frame!
|
||||
/// Converts the customProperties to a String on every single call.
|
||||
/// </remarks>
|
||||
public string ToStringFull()
|
||||
{
|
||||
return string.Format("#{0:00} '{1}'{2} {3}", this.ID, this.NickName, this.IsInactive ? " (inactive)" : "", this.CustomProperties.ToStringFull());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If players are equal (by GetHasCode, which returns this.ID).
|
||||
/// </summary>
|
||||
public override bool Equals(object p)
|
||||
{
|
||||
Player pp = p as Player;
|
||||
return (pp != null && this.GetHashCode() == pp.GetHashCode());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Accompanies Equals, using the ID (actorNumber) as HashCode to return.
|
||||
/// </summary>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this.ID;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used internally, to update this client's playerID when assigned (doesn't change after assignment).
|
||||
/// </summary>
|
||||
protected internal void ChangeLocalID(int newID)
|
||||
{
|
||||
if (!this.IsLocal)
|
||||
{
|
||||
//Debug.LogError("ERROR You should never change Player IDs!");
|
||||
return;
|
||||
}
|
||||
|
||||
this.actorID = newID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Updates and synchronizes this Player's Custom Properties. Optionally, expectedProperties can be provided as condition.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Custom Properties are a set of string keys and arbitrary values which is synchronized
|
||||
/// for the players in a Room. They are available when the client enters the room, as
|
||||
/// they are in the response of OpJoin and OpCreate.
|
||||
///
|
||||
/// Custom Properties either relate to the (current) Room or a Player (in that Room).
|
||||
///
|
||||
/// Both classes locally cache the current key/values and make them available as
|
||||
/// property: CustomProperties. This is provided only to read them.
|
||||
/// You must use the method SetCustomProperties to set/modify them.
|
||||
///
|
||||
/// Any client can set any Custom Properties anytime (when in a room).
|
||||
/// It's up to the game logic to organize how they are best used.
|
||||
///
|
||||
/// You should call SetCustomProperties only with key/values that are new or changed. This reduces
|
||||
/// traffic and performance.
|
||||
///
|
||||
/// Unless you define some expectedProperties, setting key/values is always permitted.
|
||||
/// In this case, the property-setting client will not receive the new values from the server but
|
||||
/// instead update its local cache in SetCustomProperties.
|
||||
///
|
||||
/// If you define expectedProperties, the server will skip updates if the server property-cache
|
||||
/// does not contain all expectedProperties with the same values.
|
||||
/// In this case, the property-setting client will get an update from the server and update it's
|
||||
/// cached key/values at about the same time as everyone else.
|
||||
///
|
||||
/// The benefit of using expectedProperties can be only one client successfully sets a key from
|
||||
/// one known value to another.
|
||||
/// As example: Store who owns an item in a Custom Property "ownedBy". It's 0 initally.
|
||||
/// When multiple players reach the item, they all attempt to change "ownedBy" from 0 to their
|
||||
/// actorNumber. If you use expectedProperties {"ownedBy", 0} as condition, the first player to
|
||||
/// take the item will have it (and the others fail to set the ownership).
|
||||
///
|
||||
/// Properties get saved with the game state for Turnbased games (which use IsPersistent = true).
|
||||
/// </remarks>
|
||||
/// <param name="propertiesToSet">Hashtable of Custom Properties to be set. </param>
|
||||
/// <param name="expectedValues">If non-null, these are the property-values the server will check as condition for this update.</param>
|
||||
/// <param name="webFlags">Defines if this SetCustomProperties-operation gets forwarded to your WebHooks. Client must be in room.</param>
|
||||
public void SetCustomProperties(Hashtable propertiesToSet, Hashtable expectedValues = null, WebFlags webFlags = null)
|
||||
{
|
||||
if (propertiesToSet == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Hashtable customProps = propertiesToSet.StripToStringKeys() as Hashtable;
|
||||
Hashtable customPropsToCheck = expectedValues.StripToStringKeys() as Hashtable;
|
||||
|
||||
|
||||
// no expected values -> set and callback
|
||||
bool noCas = customPropsToCheck == null || customPropsToCheck.Count == 0;
|
||||
|
||||
|
||||
if (noCas)
|
||||
{
|
||||
this.CustomProperties.Merge(customProps);
|
||||
this.CustomProperties.StripKeysWithNullValues();
|
||||
}
|
||||
|
||||
// send (sync) these new values if in room
|
||||
if (this.RoomReference != null && this.RoomReference.IsLocalClientInside)
|
||||
{
|
||||
this.RoomReference.LoadBalancingClient.loadBalancingPeer.OpSetPropertiesOfActor(this.actorID, customProps, customPropsToCheck, webFlags);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>Uses OpSetPropertiesOfActor to sync this player's NickName (server is being updated with this.NickName).</summary>
|
||||
private void SetPlayerNameProperty()
|
||||
{
|
||||
if (this.RoomReference != null && this.RoomReference.IsLocalClientInside)
|
||||
{
|
||||
Hashtable properties = new Hashtable();
|
||||
properties[ActorProperties.PlayerName] = this.nickName;
|
||||
this.RoomReference.LoadBalancingClient.loadBalancingPeer.OpSetPropertiesOfActor(this.ID, properties);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Code/Photon/PhotonLoadbalancingApi/Player.cs.meta
Normal file
11
Assets/Code/Photon/PhotonLoadbalancingApi/Player.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0b0942472c9351047afc23b868b562f9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
474
Assets/Code/Photon/PhotonLoadbalancingApi/Room.cs
Normal file
474
Assets/Code/Photon/PhotonLoadbalancingApi/Room.cs
Normal file
|
@ -0,0 +1,474 @@
|
|||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="Room.cs" company="Exit Games GmbH">
|
||||
// Loadbalancing Framework for Photon - Copyright (C) 2011 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// The Room class resembles the properties known about the room in which
|
||||
// a game/match happens.
|
||||
// </summary>
|
||||
// <author>developer@photonengine.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#define UNITY
|
||||
|
||||
|
||||
namespace ExitGames.Client.Photon.LoadBalancing
|
||||
{
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using ExitGames.Client.Photon;
|
||||
|
||||
#if UNITY || NETFX_CORE
|
||||
using Hashtable = ExitGames.Client.Photon.Hashtable;
|
||||
using SupportClass = ExitGames.Client.Photon.SupportClass;
|
||||
#endif
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This class represents a room a client joins/joined.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Contains a list of current players, their properties and those of this room, too.
|
||||
/// A room instance has a number of "well known" properties like IsOpen, MaxPlayers which can be changed.
|
||||
/// Your own, custom properties can be set via SetCustomProperties() while being in the room.
|
||||
///
|
||||
/// Typically, this class should be extended by a game-specific implementation with logic and extra features.
|
||||
/// </remarks>
|
||||
public class Room : RoomInfo
|
||||
{
|
||||
protected internal int PlayerTTL;
|
||||
protected internal int RoomTTL;
|
||||
|
||||
/// <summary>
|
||||
/// A reference to the LoadbalancingClient which is currently keeping the connection and state.
|
||||
/// </summary>
|
||||
protected internal LoadBalancingClient LoadBalancingClient { get; set; }
|
||||
|
||||
/// <summary>The name of a room. Unique identifier (per Loadbalancing group) for a room/match.</summary>
|
||||
/// <remarks>The name can't be changed once it's set by the server.</remarks>
|
||||
public new string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.name;
|
||||
}
|
||||
|
||||
internal set
|
||||
{
|
||||
this.name = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines if the room can be joined.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This does not affect listing in a lobby but joining the room will fail if not open.
|
||||
/// If not open, the room is excluded from random matchmaking.
|
||||
/// Due to racing conditions, found matches might become closed while users are trying to join.
|
||||
/// Simply re-connect to master and find another.
|
||||
/// Use property "IsVisible" to not list the room.
|
||||
///
|
||||
/// As part of RoomInfo this can't be set.
|
||||
/// As part of a Room (which the player joined), the setter will update the server and all clients.
|
||||
/// </remarks>
|
||||
public new bool IsOpen
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.isOpen;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (!this.IsLocalClientInside)
|
||||
{
|
||||
LoadBalancingClient.DebugReturn(DebugLevel.WARNING, "Can't set room properties when not in that room.");
|
||||
}
|
||||
|
||||
if (value != this.isOpen)
|
||||
{
|
||||
LoadBalancingClient.OpSetPropertiesOfRoom(new Hashtable() { { GamePropertyKey.IsOpen, value } });
|
||||
}
|
||||
|
||||
this.isOpen = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines if the room is listed in its lobby.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Rooms can be created invisible, or changed to invisible.
|
||||
/// To change if a room can be joined, use property: open.
|
||||
///
|
||||
/// As part of RoomInfo this can't be set.
|
||||
/// As part of a Room (which the player joined), the setter will update the server and all clients.
|
||||
/// </remarks>
|
||||
public new bool IsVisible
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.isVisible;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (!this.IsLocalClientInside)
|
||||
{
|
||||
LoadBalancingClient.DebugReturn(DebugLevel.WARNING, "Can't set room properties when not in that room.");
|
||||
}
|
||||
|
||||
if (value != this.isVisible)
|
||||
{
|
||||
LoadBalancingClient.OpSetPropertiesOfRoom(new Hashtable() { { GamePropertyKey.IsVisible, value } });
|
||||
}
|
||||
|
||||
this.isVisible = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sets a limit of players to this room. This property is synced and shown in lobby, too.
|
||||
/// If the room is full (players count == maxplayers), joining this room will fail.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// As part of RoomInfo this can't be set.
|
||||
/// As part of a Room (which the player joined), the setter will update the server and all clients.
|
||||
/// </remarks>
|
||||
public new byte MaxPlayers
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.maxPlayers;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (!this.IsLocalClientInside)
|
||||
{
|
||||
LoadBalancingClient.DebugReturn(DebugLevel.WARNING, "Can't set room properties when not in that room.");
|
||||
}
|
||||
|
||||
if (value != this.maxPlayers)
|
||||
{
|
||||
LoadBalancingClient.OpSetPropertiesOfRoom(new Hashtable() { { GamePropertyKey.MaxPlayers, value } });
|
||||
}
|
||||
|
||||
this.maxPlayers = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>The count of players in this Room (using this.Players.Count).</summary>
|
||||
public new byte PlayerCount
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.Players == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (byte)this.Players.Count;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>While inside a Room, this is the list of players who are also in that room.</summary>
|
||||
private Dictionary<int, Player> players = new Dictionary<int, Player>();
|
||||
|
||||
/// <summary>While inside a Room, this is the list of players who are also in that room.</summary>
|
||||
public Dictionary<int, Player> Players
|
||||
{
|
||||
get
|
||||
{
|
||||
return players;
|
||||
}
|
||||
|
||||
private set
|
||||
{
|
||||
players = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List of users who are expected to join this room. In matchmaking, Photon blocks a slot for each of these UserIDs out of the MaxPlayers.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The corresponding feature in Photon is called "Slot Reservation" and can be found in the doc pages.
|
||||
/// Define expected players in the PhotonNetwork methods: CreateRoom, JoinRoom and JoinOrCreateRoom.
|
||||
/// </remarks>
|
||||
public string[] ExpectedUsers
|
||||
{
|
||||
get { return this.expectedUsers; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The ID (actorID, actorNumber) of the player who's the master of this Room.
|
||||
/// Note: This changes when the current master leaves the room.
|
||||
/// </summary>
|
||||
public int MasterClientId { get { return this.masterClientId; } }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of custom properties that are in the RoomInfo of the Lobby.
|
||||
/// This list is defined when creating the room and can't be changed afterwards. Compare: LoadBalancingClient.OpCreateRoom()
|
||||
/// </summary>
|
||||
/// <remarks>You could name properties that are not set from the beginning. Those will be synced with the lobby when added later on.</remarks>
|
||||
public string[] PropertiesListedInLobby
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.propertiesListedInLobby;
|
||||
}
|
||||
|
||||
private set
|
||||
{
|
||||
this.propertiesListedInLobby = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets if this room uses autoCleanUp to remove all (buffered) RPCs and instantiated GameObjects when a player leaves.
|
||||
/// </summary>
|
||||
public bool AutoCleanUp
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.autoCleanUp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>Creates a Room (representation) with given name and properties and the "listing options" as provided by parameters.</summary>
|
||||
/// <param name="roomName">Name of the room (can be null until it's actually created on server).</param>
|
||||
/// <param name="options">Room options.</param>
|
||||
protected internal Room(string roomName, RoomOptions options) : base(roomName, options != null ? options.CustomRoomProperties : null)
|
||||
{
|
||||
// base() sets name and (custom)properties. here we set "well known" properties
|
||||
if (options != null)
|
||||
{
|
||||
this.isVisible = options.IsVisible;
|
||||
this.isOpen = options.IsOpen;
|
||||
this.maxPlayers = options.MaxPlayers;
|
||||
this.propertiesListedInLobby = options.CustomRoomPropertiesForLobby;
|
||||
this.PlayerTTL = options.PlayerTtl;
|
||||
this.RoomTTL = options.EmptyRoomTtl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Updates and synchronizes this Room's Custom Properties. Optionally, expectedProperties can be provided as condition.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Custom Properties are a set of string keys and arbitrary values which is synchronized
|
||||
/// for the players in a Room. They are available when the client enters the room, as
|
||||
/// they are in the response of OpJoin and OpCreate.
|
||||
///
|
||||
/// Custom Properties either relate to the (current) Room or a Player (in that Room).
|
||||
///
|
||||
/// Both classes locally cache the current key/values and make them available as
|
||||
/// property: CustomProperties. This is provided only to read them.
|
||||
/// You must use the method SetCustomProperties to set/modify them.
|
||||
///
|
||||
/// Any client can set any Custom Properties anytime (when in a room).
|
||||
/// It's up to the game logic to organize how they are best used.
|
||||
///
|
||||
/// You should call SetCustomProperties only with key/values that are new or changed. This reduces
|
||||
/// traffic and performance.
|
||||
///
|
||||
/// Unless you define some expectedProperties, setting key/values is always permitted.
|
||||
/// In this case, the property-setting client will not receive the new values from the server but
|
||||
/// instead update its local cache in SetCustomProperties.
|
||||
///
|
||||
/// If you define expectedProperties, the server will skip updates if the server property-cache
|
||||
/// does not contain all expectedProperties with the same values.
|
||||
/// In this case, the property-setting client will get an update from the server and update it's
|
||||
/// cached key/values at about the same time as everyone else.
|
||||
///
|
||||
/// The benefit of using expectedProperties can be only one client successfully sets a key from
|
||||
/// one known value to another.
|
||||
/// As example: Store who owns an item in a Custom Property "ownedBy". It's 0 initally.
|
||||
/// When multiple players reach the item, they all attempt to change "ownedBy" from 0 to their
|
||||
/// actorNumber. If you use expectedProperties {"ownedBy", 0} as condition, the first player to
|
||||
/// take the item will have it (and the others fail to set the ownership).
|
||||
///
|
||||
/// Properties get saved with the game state for Turnbased games (which use IsPersistent = true).
|
||||
/// </remarks>
|
||||
/// <param name="propertiesToSet">Hashtable of Custom Properties that changes.</param>
|
||||
/// <param name="expectedProperties">Provide some keys/values to use as condition for setting the new values. Client must be in room.</param>
|
||||
/// <param name="webFlags">Defines if this SetCustomProperties-operation gets forwarded to your WebHooks. Client must be in room.</param>
|
||||
public virtual void SetCustomProperties(Hashtable propertiesToSet, Hashtable expectedProperties = null, WebFlags webFlags = null)
|
||||
{
|
||||
Hashtable customProps = propertiesToSet.StripToStringKeys() as Hashtable;
|
||||
|
||||
// merge (and delete null-values), unless we use CAS (expected props)
|
||||
if (expectedProperties == null || expectedProperties.Count == 0)
|
||||
{
|
||||
this.CustomProperties.Merge(customProps);
|
||||
this.CustomProperties.StripKeysWithNullValues();
|
||||
}
|
||||
|
||||
// send (sync) these new values if in room
|
||||
if (this.IsLocalClientInside)
|
||||
{
|
||||
this.LoadBalancingClient.loadBalancingPeer.OpSetPropertiesOfRoom(customProps, expectedProperties, webFlags);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enables you to define the properties available in the lobby if not all properties are needed to pick a room.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Limit the amount of properties sent to users in the lobby to improve speed and stability.
|
||||
/// </remarks>
|
||||
/// <param name="propertiesListedInLobby">An array of custom room property names to forward to the lobby.</param>
|
||||
public void SetPropertiesListedInLobby(string[] propertiesListedInLobby)
|
||||
{
|
||||
Hashtable customProps = new Hashtable();
|
||||
customProps[GamePropertyKey.PropsListedInLobby] = propertiesListedInLobby;
|
||||
|
||||
bool sent = this.LoadBalancingClient.OpSetPropertiesOfRoom(customProps);
|
||||
|
||||
if (sent)
|
||||
{
|
||||
this.propertiesListedInLobby = propertiesListedInLobby;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Removes a player from this room's Players Dictionary.
|
||||
/// This is internally used by the LoadBalancing API. There is usually no need to remove players yourself.
|
||||
/// This is not a way to "kick" players.
|
||||
/// </summary>
|
||||
protected internal virtual void RemovePlayer(Player player)
|
||||
{
|
||||
this.Players.Remove(player.ID);
|
||||
player.RoomReference = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a player from this room's Players Dictionary.
|
||||
/// </summary>
|
||||
protected internal virtual void RemovePlayer(int id)
|
||||
{
|
||||
this.RemovePlayer(this.GetPlayer(id));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asks the server to assign another player as Master Client of your current room.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// RaiseEvent has the option to send messages only to the Master Client of a room.
|
||||
/// SetMasterClient affects which client gets those messages.
|
||||
///
|
||||
/// This method calls an operation on the server to set a new Master Client, which takes a roundtrip.
|
||||
/// In case of success, this client and the others get the new Master Client from the server.
|
||||
///
|
||||
/// SetMasterClient tells the server which current Master Client should be replaced with the new one.
|
||||
/// It will fail, if anything switches the Master Client moments earlier. There is no callback for this
|
||||
/// error. All clients should get the new Master Client assigned by the server anyways.
|
||||
///
|
||||
/// See also: MasterClientId
|
||||
/// </remarks>
|
||||
/// <param name="masterClientPlayer">The player to become the next Master Client.</param>
|
||||
/// <returns>False when this operation couldn't be done currently. Requires a v4 Photon Server.</returns>
|
||||
public bool SetMasterClient(Player masterClientPlayer)
|
||||
{
|
||||
if (!this.IsLocalClientInside)
|
||||
{
|
||||
this.LoadBalancingClient.DebugReturn(DebugLevel.WARNING, "SetMasterClient can only be called for the current room (being in one).");
|
||||
return false;
|
||||
}
|
||||
|
||||
Hashtable newProps = new Hashtable() { { GamePropertyKey.MasterClientId, masterClientPlayer.ID } };
|
||||
Hashtable prevProps = new Hashtable() { { GamePropertyKey.MasterClientId, this.MasterClientId} };
|
||||
return this.LoadBalancingClient.OpSetPropertiesOfRoom(newProps, prevProps);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the player is in the room's list already and calls StorePlayer() if not.
|
||||
/// </summary>
|
||||
/// <param name="player">The new player - identified by ID.</param>
|
||||
/// <returns>False if the player could not be added (cause it was in the list already).</returns>
|
||||
public virtual bool AddPlayer(Player player)
|
||||
{
|
||||
if (!this.Players.ContainsKey(player.ID))
|
||||
{
|
||||
this.StorePlayer(player);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates a player reference in the Players dictionary (no matter if it existed before or not).
|
||||
/// </summary>
|
||||
/// <param name="player">The Player instance to insert into the room.</param>
|
||||
public virtual Player StorePlayer(Player player)
|
||||
{
|
||||
this.Players[player.ID] = player;
|
||||
player.RoomReference = this;
|
||||
|
||||
// while initializing the room, the players are not guaranteed to be added in-order
|
||||
if (this.MasterClientId == 0 || player.ID < this.MasterClientId)
|
||||
{
|
||||
this.masterClientId = player.ID;
|
||||
}
|
||||
|
||||
return player;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to find the player with given actorNumber (a.k.a. ID).
|
||||
/// Only useful when in a Room, as IDs are only valid per Room.
|
||||
/// </summary>
|
||||
/// <param name="id">ID to look for.</param>
|
||||
/// <returns>The player with the ID or null.</returns>
|
||||
public virtual Player GetPlayer(int id)
|
||||
{
|
||||
Player result = null;
|
||||
this.Players.TryGetValue(id, out result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to remove all current expected users from the server's Slot Reservation list.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Note that this operation can conflict with new/other users joining. They might be
|
||||
/// adding users to the list of expected users before or after this client called ClearExpectedUsers.
|
||||
///
|
||||
/// This room's expectedUsers value will update, when the server sends a successful update.
|
||||
///
|
||||
/// Internals: This methods wraps up setting the ExpectedUsers property of a room.
|
||||
/// </remarks>
|
||||
public void ClearExpectedUsers()
|
||||
{
|
||||
Hashtable props = new Hashtable();
|
||||
props[GamePropertyKey.ExpectedUsers] = new string[0];
|
||||
Hashtable expected = new Hashtable();
|
||||
expected[GamePropertyKey.ExpectedUsers] = this.ExpectedUsers;
|
||||
this.LoadBalancingClient.OpSetPropertiesOfRoom(props, expected);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>Returns a summary of this Room instance as string.</summary>
|
||||
/// <returns>Summary of this Room instance.</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("Room: '{0}' {1},{2} {4}/{3} players.", this.name, this.isVisible ? "visible" : "hidden", this.isOpen ? "open" : "closed", this.maxPlayers, this.PlayerCount);
|
||||
}
|
||||
|
||||
/// <summary>Returns a summary of this Room instance as longer string, including Custom Properties.</summary>
|
||||
/// <returns>Summary of this Room instance.</returns>
|
||||
public new string ToStringFull()
|
||||
{
|
||||
return string.Format("Room: '{0}' {1},{2} {4}/{3} players.\ncustomProps: {5}", this.name, this.isVisible ? "visible" : "hidden", this.isOpen ? "open" : "closed", this.maxPlayers, this.PlayerCount, this.CustomProperties.ToStringFull());
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Code/Photon/PhotonLoadbalancingApi/Room.cs.meta
Normal file
11
Assets/Code/Photon/PhotonLoadbalancingApi/Room.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7f05b351233593247979ece22db7a9f4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
261
Assets/Code/Photon/PhotonLoadbalancingApi/RoomInfo.cs
Normal file
261
Assets/Code/Photon/PhotonLoadbalancingApi/RoomInfo.cs
Normal file
|
@ -0,0 +1,261 @@
|
|||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="RoomInfo.cs" company="Exit Games GmbH">
|
||||
// Loadbalancing Framework for Photon - Copyright (C) 2011 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// This class resembles info about available rooms, as sent by the Master
|
||||
// server's lobby. Consider all values as readonly.
|
||||
// </summary>
|
||||
// <author>developer@photonengine.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#if UNITY_4_7_OR_NEWER
|
||||
#define UNITY
|
||||
#endif
|
||||
|
||||
namespace ExitGames.Client.Photon.LoadBalancing
|
||||
{
|
||||
using System.Collections;
|
||||
|
||||
#if UNITY || NETFX_CORE
|
||||
using Hashtable = ExitGames.Client.Photon.Hashtable;
|
||||
using SupportClass = ExitGames.Client.Photon.SupportClass;
|
||||
#endif
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A simplified room with just the info required to list and join, used for the room listing in the lobby.
|
||||
/// The properties are not settable (IsOpen, MaxPlayers, etc).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This class resembles info about available rooms, as sent by the Master server's lobby.
|
||||
/// Consider all values as readonly. None are synced (only updated by events by server).
|
||||
/// </remarks>
|
||||
public class RoomInfo
|
||||
{
|
||||
/// <summary>Used internally in lobby, to mark rooms that are no longer listed (for being full, closed or hidden).</summary>
|
||||
protected internal bool removedFromList;
|
||||
|
||||
/// <summary>Backing field for property.</summary>
|
||||
private Hashtable customProperties = new Hashtable();
|
||||
|
||||
/// <summary>Backing field for property.</summary>
|
||||
protected byte maxPlayers = 0;
|
||||
|
||||
/// <summary>Backing field for property.</summary>
|
||||
protected string[] expectedUsers;
|
||||
|
||||
/// <summary>Backing field for property.</summary>
|
||||
protected bool isOpen = true;
|
||||
|
||||
/// <summary>Backing field for property.</summary>
|
||||
protected bool isVisible = true;
|
||||
|
||||
/// <summary>Backing field for property. False unless the GameProperty is set to true (else it's not sent).</summary>
|
||||
protected bool autoCleanUp = true;
|
||||
|
||||
/// <summary>Backing field for property.</summary>
|
||||
protected string name;
|
||||
|
||||
/// <summary>Backing field for master client id (actorNumber). defined by server in room props and ev leave.</summary>
|
||||
protected internal int masterClientId;
|
||||
|
||||
/// <summary>Backing field for property.</summary>
|
||||
protected string[] propertiesListedInLobby;
|
||||
|
||||
/// <summary>Read-only "cache" of custom properties of a room. Set via Room.SetCustomProperties (not available for RoomInfo class!).</summary>
|
||||
/// <remarks>All keys are string-typed and the values depend on the game/application.</remarks>
|
||||
/// <see cref="Room.SetCustomProperties"/>
|
||||
public Hashtable CustomProperties
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.customProperties;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>The name of a room. Unique identifier for a room/match (per AppId + game-Version).</summary>
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Count of players currently in room. This property is overwritten by the Room class (used when you're in a Room).
|
||||
/// </summary>
|
||||
public int PlayerCount { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// State if the local client is already in the game or still going to join it on gameserver (in lobby: false).
|
||||
/// </summary>
|
||||
public bool IsLocalClientInside { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The limit of players for this room. This property is shown in lobby, too.
|
||||
/// If the room is full (players count == maxplayers), joining this room will fail.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// As part of RoomInfo this can't be set.
|
||||
/// As part of a Room (which the player joined), the setter will update the server and all clients.
|
||||
/// </remarks>
|
||||
public byte MaxPlayers
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.maxPlayers;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines if the room can be joined.
|
||||
/// This does not affect listing in a lobby but joining the room will fail if not open.
|
||||
/// If not open, the room is excluded from random matchmaking.
|
||||
/// Due to racing conditions, found matches might become closed even while you join them.
|
||||
/// Simply re-connect to master and find another.
|
||||
/// Use property "IsVisible" to not list the room.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// As part of RoomInfo this can't be set.
|
||||
/// As part of a Room (which the player joined), the setter will update the server and all clients.
|
||||
/// </remarks>
|
||||
public bool IsOpen
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.isOpen;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines if the room is listed in its lobby.
|
||||
/// Rooms can be created invisible, or changed to invisible.
|
||||
/// To change if a room can be joined, use property: open.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// As part of RoomInfo this can't be set.
|
||||
/// As part of a Room (which the player joined), the setter will update the server and all clients.
|
||||
/// </remarks>
|
||||
public bool IsVisible
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.isVisible;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a RoomInfo to be used in room listings in lobby.
|
||||
/// </summary>
|
||||
/// <param name="roomName">Name of the room and unique ID at the same time.</param>
|
||||
/// <param name="roomProperties">Properties for this room.</param>
|
||||
protected internal RoomInfo(string roomName, Hashtable roomProperties)
|
||||
{
|
||||
this.InternalCacheProperties(roomProperties);
|
||||
|
||||
this.name = roomName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes RoomInfo comparable (by name).
|
||||
/// </summary>
|
||||
public override bool Equals(object other)
|
||||
{
|
||||
RoomInfo otherRoomInfo = other as RoomInfo;
|
||||
return (otherRoomInfo != null && this.Name.Equals(otherRoomInfo.name));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Accompanies Equals, using the name's HashCode as return.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this.name.GetHashCode();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>Returns most interesting room values as string.</summary>
|
||||
/// <returns>Summary of this RoomInfo instance.</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("Room: '{0}' {1},{2} {4}/{3} players.", this.name, this.isVisible ? "visible" : "hidden", this.isOpen ? "open" : "closed", this.maxPlayers, this.PlayerCount);
|
||||
}
|
||||
|
||||
/// <summary>Returns most interesting room values as string, including custom properties.</summary>
|
||||
/// <returns>Summary of this RoomInfo instance.</returns>
|
||||
public string ToStringFull()
|
||||
{
|
||||
return string.Format("Room: '{0}' {1},{2} {4}/{3} players.\ncustomProps: {5}", this.name, this.isVisible ? "visible" : "hidden", this.isOpen ? "open" : "closed", this.maxPlayers, this.PlayerCount, this.customProperties.ToStringFull());
|
||||
}
|
||||
|
||||
/// <summary>Copies "well known" properties to fields (IsVisible, etc) and caches the custom properties (string-keys only) in a local hashtable.</summary>
|
||||
/// <param name="propertiesToCache">New or updated properties to store in this RoomInfo.</param>
|
||||
protected internal virtual void InternalCacheProperties(Hashtable propertiesToCache)
|
||||
{
|
||||
if (propertiesToCache == null || propertiesToCache.Count == 0 || this.customProperties.Equals(propertiesToCache))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// check of this game was removed from the list. in that case, we don't
|
||||
// need to read any further properties
|
||||
// list updates will remove this game from the game listing
|
||||
if (propertiesToCache.ContainsKey(GamePropertyKey.Removed))
|
||||
{
|
||||
this.removedFromList = (bool)propertiesToCache[GamePropertyKey.Removed];
|
||||
if (this.removedFromList)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// fetch the "well known" properties of the room, if available
|
||||
if (propertiesToCache.ContainsKey(GamePropertyKey.MaxPlayers))
|
||||
{
|
||||
this.maxPlayers = (byte)propertiesToCache[GamePropertyKey.MaxPlayers];
|
||||
}
|
||||
|
||||
if (propertiesToCache.ContainsKey(GamePropertyKey.IsOpen))
|
||||
{
|
||||
this.isOpen = (bool)propertiesToCache[GamePropertyKey.IsOpen];
|
||||
}
|
||||
|
||||
if (propertiesToCache.ContainsKey(GamePropertyKey.IsVisible))
|
||||
{
|
||||
this.isVisible = (bool)propertiesToCache[GamePropertyKey.IsVisible];
|
||||
}
|
||||
|
||||
if (propertiesToCache.ContainsKey(GamePropertyKey.PlayerCount))
|
||||
{
|
||||
this.PlayerCount = (int)((byte)propertiesToCache[GamePropertyKey.PlayerCount]);
|
||||
}
|
||||
|
||||
if (propertiesToCache.ContainsKey(GamePropertyKey.CleanupCacheOnLeave))
|
||||
{
|
||||
this.autoCleanUp = (bool)propertiesToCache[GamePropertyKey.CleanupCacheOnLeave];
|
||||
}
|
||||
|
||||
if (propertiesToCache.ContainsKey(GamePropertyKey.MasterClientId))
|
||||
{
|
||||
this.masterClientId = (int)propertiesToCache[GamePropertyKey.MasterClientId];
|
||||
}
|
||||
|
||||
if (propertiesToCache.ContainsKey(GamePropertyKey.PropsListedInLobby))
|
||||
{
|
||||
this.propertiesListedInLobby = propertiesToCache[GamePropertyKey.PropsListedInLobby] as string[];
|
||||
}
|
||||
|
||||
if (propertiesToCache.ContainsKey((byte)GamePropertyKey.ExpectedUsers))
|
||||
{
|
||||
this.expectedUsers = (string[])propertiesToCache[GamePropertyKey.ExpectedUsers];
|
||||
}
|
||||
|
||||
// merge the custom properties (from your application) to the cache (only string-typed keys will be kept)
|
||||
this.customProperties.MergeStringKeys(propertiesToCache);
|
||||
this.customProperties.StripKeysWithNullValues();
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Code/Photon/PhotonLoadbalancingApi/RoomInfo.cs.meta
Normal file
11
Assets/Code/Photon/PhotonLoadbalancingApi/RoomInfo.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 34e9ca7b04eb3424c915e47461a9ca43
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
167
Assets/Code/Photon/PhotonLoadbalancingApi/WebRpc.cs
Normal file
167
Assets/Code/Photon/PhotonLoadbalancingApi/WebRpc.cs
Normal file
|
@ -0,0 +1,167 @@
|
|||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="WebRpc.cs" company="Exit Games GmbH">
|
||||
// Loadbalancing Framework for Photon - Copyright (C) 2016 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// This class wraps responses of a Photon WebRPC call, coming from a
|
||||
// third party web service.
|
||||
// </summary>
|
||||
// <author>developer@photonengine.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#if UNITY_4_7_OR_NEWER
|
||||
#define UNITY
|
||||
#endif
|
||||
|
||||
|
||||
namespace ExitGames.Client.Photon.LoadBalancing
|
||||
{
|
||||
using ExitGames.Client.Photon;
|
||||
using System.Collections.Generic;
|
||||
|
||||
#if UNITY || NETFX_CORE
|
||||
using Hashtable = ExitGames.Client.Photon.Hashtable;
|
||||
using SupportClass = ExitGames.Client.Photon.SupportClass;
|
||||
#endif
|
||||
|
||||
|
||||
/// <summary>Reads an operation response of a WebRpc and provides convenient access to most common values.</summary>
|
||||
/// <remarks>
|
||||
/// See method PhotonNetwork.WebRpc.<br/>
|
||||
/// Create a WebRpcResponse to access common result values.<br/>
|
||||
/// The operationResponse.OperationCode should be: OperationCode.WebRpc.<br/>
|
||||
/// </remarks>
|
||||
public class WebRpcResponse
|
||||
{
|
||||
/// <summary>Name of the WebRpc that was called.</summary>
|
||||
public string Name { get; private set; }
|
||||
|
||||
/// <summary>ReturnCode of the WebService that answered the WebRpc.</summary>
|
||||
/// <remarks>
|
||||
/// 1 is: "OK" for WebRPCs.<br/>
|
||||
/// -1 is: No ReturnCode by WebRpc service (check OperationResponse.ReturnCode).<br/>
|
||||
/// Other ReturnCodes are defined by the individual WebRpc and service.
|
||||
/// </remarks>
|
||||
public int ReturnCode { get; private set; }
|
||||
|
||||
/// <summary>Might be empty or null.</summary>
|
||||
public string DebugMessage { get; private set; }
|
||||
|
||||
/// <summary>Other key/values returned by the webservice that answered the WebRpc.</summary>
|
||||
public Dictionary<string, object> Parameters { get; private set; }
|
||||
|
||||
/// <summary>An OperationResponse for a WebRpc is needed to read it's values.</summary>
|
||||
public WebRpcResponse(OperationResponse response)
|
||||
{
|
||||
object value;
|
||||
response.Parameters.TryGetValue(ParameterCode.UriPath, out value);
|
||||
this.Name = value as string;
|
||||
|
||||
response.Parameters.TryGetValue(ParameterCode.WebRpcReturnCode, out value);
|
||||
this.ReturnCode = (value != null) ? (byte)value : -1;
|
||||
|
||||
response.Parameters.TryGetValue(ParameterCode.WebRpcParameters, out value);
|
||||
this.Parameters = value as Dictionary<string, object>;
|
||||
|
||||
response.Parameters.TryGetValue(ParameterCode.WebRpcReturnMessage, out value);
|
||||
this.DebugMessage = value as string;
|
||||
}
|
||||
|
||||
/// <summary>Turns the response into an easier to read string.</summary>
|
||||
/// <returns>String resembling the result.</returns>
|
||||
public string ToStringFull()
|
||||
{
|
||||
return string.Format("{0}={2}: {1} \"{3}\"", this.Name, SupportClass.DictionaryToString(this.Parameters), this.ReturnCode, this.DebugMessage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Optional flags to be used in Photon client SDKs with Op RaiseEvent and Op SetProperties.
|
||||
/// Introduced mainly for webhooks 1.2 to control behavior of forwarded HTTP requests.
|
||||
/// </summary>
|
||||
public class WebFlags
|
||||
{
|
||||
|
||||
public readonly static WebFlags Default = new WebFlags(0);
|
||||
public byte WebhookFlags;
|
||||
/// <summary>
|
||||
/// Indicates whether to forward HTTP request to web service or not.
|
||||
/// </summary>
|
||||
public bool HttpForward
|
||||
{
|
||||
get { return (WebhookFlags & HttpForwardConst) != 0; }
|
||||
set {
|
||||
if (value)
|
||||
{
|
||||
WebhookFlags |= HttpForwardConst;
|
||||
}
|
||||
else
|
||||
{
|
||||
WebhookFlags = (byte) (WebhookFlags & ~(1 << 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
public const byte HttpForwardConst = 0x01;
|
||||
/// <summary>
|
||||
/// Indicates whether to send AuthCookie of actor in the HTTP request to web service or not.
|
||||
/// </summary>
|
||||
public bool SendAuthCookie
|
||||
{
|
||||
get { return (WebhookFlags & SendAuthCookieConst) != 0; }
|
||||
set {
|
||||
if (value)
|
||||
{
|
||||
WebhookFlags |= SendAuthCookieConst;
|
||||
}
|
||||
else
|
||||
{
|
||||
WebhookFlags = (byte)(WebhookFlags & ~(1 << 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
public const byte SendAuthCookieConst = 0x02;
|
||||
/// <summary>
|
||||
/// Indicates whether to send HTTP request synchronously or asynchronously to web service.
|
||||
/// </summary>
|
||||
public bool SendSync
|
||||
{
|
||||
get { return (WebhookFlags & SendSyncConst) != 0; }
|
||||
set {
|
||||
if (value)
|
||||
{
|
||||
WebhookFlags |= SendSyncConst;
|
||||
}
|
||||
else
|
||||
{
|
||||
WebhookFlags = (byte)(WebhookFlags & ~(1 << 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
public const byte SendSyncConst = 0x04;
|
||||
/// <summary>
|
||||
/// Indicates whether to send serialized game state in HTTP request to web service or not.
|
||||
/// </summary>
|
||||
public bool SendState
|
||||
{
|
||||
get { return (WebhookFlags & SendStateConst) != 0; }
|
||||
set {
|
||||
if (value)
|
||||
{
|
||||
WebhookFlags |= SendStateConst;
|
||||
}
|
||||
else
|
||||
{
|
||||
WebhookFlags = (byte)(WebhookFlags & ~(1 << 3));
|
||||
}
|
||||
}
|
||||
}
|
||||
public const byte SendStateConst = 0x08;
|
||||
|
||||
public WebFlags(byte webhookFlags)
|
||||
{
|
||||
WebhookFlags = webhookFlags;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
11
Assets/Code/Photon/PhotonLoadbalancingApi/WebRpc.cs.meta
Normal file
11
Assets/Code/Photon/PhotonLoadbalancingApi/WebRpc.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e82402aea03f000428f5ca11fec7ecfc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
Add table
Add a link
Reference in a new issue