first commit
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f1d46a1c486645945a3667d8bbe2d2e7
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,246 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="PhotonTeamsManagerEditor.cs" company="Exit Games GmbH">
|
||||
// Part of: Photon Unity Utilities,
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// Custom inspector for PhotonTeamsManager
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using Photon.Realtime;
|
||||
using UnityEditor;
|
||||
|
||||
namespace Photon.Pun.UtilityScripts
|
||||
{
|
||||
[CustomEditor(typeof(PhotonTeamsManager))]
|
||||
public class PhotonTeamsManagerEditor : Editor
|
||||
{
|
||||
private Dictionary<byte, bool> foldouts = new Dictionary<byte, bool>();
|
||||
private PhotonTeamsManager photonTeams;
|
||||
private SerializedProperty teamsListSp;
|
||||
private SerializedProperty listFoldIsOpenSp;
|
||||
|
||||
private const string proSkinString =
|
||||
"iVBORw0KGgoAAAANSUhEUgAAAAgAAAAECAYAAACzzX7wAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACJJREFUeNpi/P//PwM+wHL06FG8KpgYCABGZWVlvCYABBgA7/sHvGw+cz8AAAAASUVORK5CYII=";
|
||||
private const string lightSkinString = "iVBORw0KGgoAAAANSUhEUgAAAAgAAAACCAIAAADq9gq6AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAABVJREFUeNpiVFZWZsAGmBhwAIAAAwAURgBt4C03ZwAAAABJRU5ErkJggg==";
|
||||
private const string removeTextureName = "removeButton_generated";
|
||||
private Texture removeTexture;
|
||||
|
||||
private bool isOpen;
|
||||
|
||||
public override bool RequiresConstantRepaint()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
photonTeams = target as PhotonTeamsManager;
|
||||
teamsListSp = serializedObject.FindProperty("teamsList");
|
||||
listFoldIsOpenSp = serializedObject.FindProperty("listFoldIsOpen");
|
||||
isOpen = listFoldIsOpenSp.boolValue;
|
||||
removeTexture = LoadTexture(removeTextureName, proSkinString, lightSkinString);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read width and height if PNG file in pixels.
|
||||
/// </summary>
|
||||
/// <param name="imageData">PNG image data.</param>
|
||||
/// <param name="width">Width of image in pixels.</param>
|
||||
/// <param name="height">Height of image in pixels.</param>
|
||||
private static void GetImageSize( byte[] imageData, out int width, out int height )
|
||||
{
|
||||
width = ReadInt( imageData, 3 + 15 );
|
||||
height = ReadInt( imageData, 3 + 15 + 2 + 2 );
|
||||
}
|
||||
|
||||
private static int ReadInt( byte[] imageData, int offset )
|
||||
{
|
||||
return ( imageData[ offset ] << 8 ) | imageData[ offset + 1 ];
|
||||
}
|
||||
|
||||
private Texture LoadTexture(string textureName, string proSkin, string lightSkin)
|
||||
{
|
||||
string skin = EditorGUIUtility.isProSkin ? proSkin : lightSkin;
|
||||
// Get image data (PNG) from base64 encoded strings.
|
||||
byte[] imageData = Convert.FromBase64String( skin );
|
||||
// Gather image size from image data.
|
||||
int texWidth, texHeight;
|
||||
GetImageSize( imageData, out texWidth, out texHeight );
|
||||
// Generate texture asset.
|
||||
var tex = new Texture2D( texWidth, texHeight, TextureFormat.ARGB32, false, true );
|
||||
tex.hideFlags = HideFlags.HideAndDontSave;
|
||||
tex.name = textureName;
|
||||
tex.filterMode = FilterMode.Point;
|
||||
tex.LoadImage( imageData );
|
||||
return tex;
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
DrawTeamsList();
|
||||
return;
|
||||
}
|
||||
PhotonTeam[] availableTeams = photonTeams.GetAvailableTeams();
|
||||
if (availableTeams != null)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
foreach (var availableTeam in availableTeams)
|
||||
{
|
||||
if (!foldouts.ContainsKey(availableTeam.Code))
|
||||
{
|
||||
foldouts[availableTeam.Code] = true;
|
||||
}
|
||||
Player[] teamMembers;
|
||||
if (photonTeams.TryGetTeamMembers(availableTeam, out teamMembers) && teamMembers != null)
|
||||
{
|
||||
foldouts[availableTeam.Code] = EditorGUILayout.Foldout(foldouts[availableTeam.Code],
|
||||
string.Format("{0} ({1})", availableTeam.Name, teamMembers.Length));
|
||||
}
|
||||
else
|
||||
{
|
||||
foldouts[availableTeam.Code] = EditorGUILayout.Foldout(foldouts[availableTeam.Code],
|
||||
string.Format("{0} (0)", availableTeam.Name));
|
||||
}
|
||||
if (foldouts[availableTeam.Code] && teamMembers != null)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
foreach (var player in teamMembers)
|
||||
{
|
||||
EditorGUILayout.LabelField(string.Empty, string.Format("{0} {1}", player, player.IsLocal ? " - You -" : string.Empty));
|
||||
}
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
}
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawTeamsList()
|
||||
{
|
||||
GUILayout.Space(5);
|
||||
HashSet<byte> codes = new HashSet<byte>();
|
||||
HashSet<string> names = new HashSet<string>();
|
||||
for (int i = 0; i < teamsListSp.arraySize; i++)
|
||||
{
|
||||
SerializedProperty e = teamsListSp.GetArrayElementAtIndex(i);
|
||||
string name = e.FindPropertyRelative("Name").stringValue;
|
||||
byte code = (byte)e.FindPropertyRelative("Code").intValue;
|
||||
codes.Add(code);
|
||||
names.Add(name);
|
||||
}
|
||||
this.serializedObject.Update();
|
||||
EditorGUI.BeginChangeCheck();
|
||||
isOpen = PhotonGUI.ContainerHeaderFoldout(string.Format("Teams List ({0})", teamsListSp.arraySize), isOpen);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
listFoldIsOpenSp.boolValue = isOpen;
|
||||
}
|
||||
if (isOpen)
|
||||
{
|
||||
const float containerElementHeight = 22;
|
||||
const float propertyHeight = 16;
|
||||
const float paddingRight = 29;
|
||||
const float paddingLeft = 5;
|
||||
const float spacingY = 3;
|
||||
float containerHeight = (teamsListSp.arraySize + 1) * containerElementHeight;
|
||||
Rect containerRect = PhotonGUI.ContainerBody(containerHeight);
|
||||
float propertyWidth = containerRect.width - paddingRight;
|
||||
float codePropertyWidth = propertyWidth / 5;
|
||||
float namePropertyWidth = 4 * propertyWidth / 5;
|
||||
Rect elementRect = new Rect(containerRect.xMin, containerRect.yMin,
|
||||
containerRect.width, containerElementHeight);
|
||||
Rect propertyPosition = new Rect(elementRect.xMin + paddingLeft, elementRect.yMin + spacingY,
|
||||
codePropertyWidth, propertyHeight);
|
||||
EditorGUI.LabelField(propertyPosition, "Code");
|
||||
Rect secondPropertyPosition = new Rect(elementRect.xMin + paddingLeft + codePropertyWidth, elementRect.yMin + spacingY,
|
||||
namePropertyWidth, propertyHeight);
|
||||
EditorGUI.LabelField(secondPropertyPosition, "Name");
|
||||
for (int i = 0; i < teamsListSp.arraySize; ++i)
|
||||
{
|
||||
elementRect = new Rect(containerRect.xMin, containerRect.yMin + containerElementHeight * (i + 1),
|
||||
containerRect.width, containerElementHeight);
|
||||
propertyPosition = new Rect(elementRect.xMin + paddingLeft, elementRect.yMin + spacingY,
|
||||
codePropertyWidth, propertyHeight);
|
||||
SerializedProperty teamElementSp = teamsListSp.GetArrayElementAtIndex(i);
|
||||
SerializedProperty teamNameSp = teamElementSp.FindPropertyRelative("Name");
|
||||
SerializedProperty teamCodeSp = teamElementSp.FindPropertyRelative("Code");
|
||||
string oldName = teamNameSp.stringValue;
|
||||
byte oldCode = (byte)teamCodeSp.intValue;
|
||||
EditorGUI.BeginChangeCheck();
|
||||
EditorGUI.PropertyField(propertyPosition, teamCodeSp, GUIContent.none);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
byte newCode = (byte)teamCodeSp.intValue;
|
||||
if (codes.Contains(newCode))
|
||||
{
|
||||
Debug.LogWarningFormat("Team with the same code {0} already exists", newCode);
|
||||
teamCodeSp.intValue = oldCode;
|
||||
}
|
||||
}
|
||||
secondPropertyPosition = new Rect(elementRect.xMin + paddingLeft + codePropertyWidth, elementRect.yMin + spacingY,
|
||||
namePropertyWidth, propertyHeight);
|
||||
EditorGUI.BeginChangeCheck();
|
||||
EditorGUI.PropertyField(secondPropertyPosition, teamNameSp, GUIContent.none);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
string newName = teamNameSp.stringValue;
|
||||
if (string.IsNullOrEmpty(newName))
|
||||
{
|
||||
Debug.LogWarning("Team name cannot be null or empty");
|
||||
teamNameSp.stringValue = oldName;
|
||||
}
|
||||
else if (names.Contains(newName))
|
||||
{
|
||||
Debug.LogWarningFormat("Team with the same name \"{0}\" already exists", newName);
|
||||
teamNameSp.stringValue = oldName;
|
||||
}
|
||||
}
|
||||
Rect removeButtonRect = new Rect(
|
||||
elementRect.xMax - PhotonGUI.DefaultRemoveButtonStyle.fixedWidth,
|
||||
elementRect.yMin + 2,
|
||||
PhotonGUI.DefaultRemoveButtonStyle.fixedWidth,
|
||||
PhotonGUI.DefaultRemoveButtonStyle.fixedHeight);
|
||||
if (GUI.Button(removeButtonRect, new GUIContent(removeTexture), PhotonGUI.DefaultRemoveButtonStyle))
|
||||
{
|
||||
teamsListSp.DeleteArrayElementAtIndex(i);
|
||||
}
|
||||
if (i < teamsListSp.arraySize - 1)
|
||||
{
|
||||
Rect texturePosition = new Rect(elementRect.xMin + 2, elementRect.yMax, elementRect.width - 4,
|
||||
1);
|
||||
PhotonGUI.DrawSplitter(texturePosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (PhotonGUI.AddButton())
|
||||
{
|
||||
byte c = 0;
|
||||
while (codes.Contains(c) && c < byte.MaxValue)
|
||||
{
|
||||
c++;
|
||||
}
|
||||
this.teamsListSp.arraySize++;
|
||||
SerializedProperty teamElementSp = this.teamsListSp.GetArrayElementAtIndex(teamsListSp.arraySize - 1);
|
||||
SerializedProperty teamNameSp = teamElementSp.FindPropertyRelative("Name");
|
||||
SerializedProperty teamCodeSp = teamElementSp.FindPropertyRelative("Code");
|
||||
teamCodeSp.intValue = c;
|
||||
string n = "New Team";
|
||||
int o = 1;
|
||||
while (names.Contains(n))
|
||||
{
|
||||
n = string.Format("New Team {0}", o);
|
||||
o++;
|
||||
}
|
||||
teamNameSp.stringValue = n;
|
||||
}
|
||||
this.serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8cb74f08e3fc52942a0d8557772bf4dc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "PhotonUnityNetworking.Utilities.PhotonPlayer.Editor",
|
||||
"references": [
|
||||
"PhotonRealtime",
|
||||
"PhotonUnityNetworking",
|
||||
"PhotonUnityNetworking.Utilities",
|
||||
"PhotonUnityNetworking.Editor"
|
||||
],
|
||||
"optionalUnityReferences": [],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7024f760fc566cf45a16d2c838e22b2d
|
||||
timeCreated: 1537459565
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,67 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="PlayerNumberingInspector.cs" company="Exit Games GmbH">
|
||||
// Part of: Photon Unity Utilities,
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// Custom inspector for PlayerNumbering
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
|
||||
using Photon.Pun;
|
||||
using Photon.Realtime;
|
||||
|
||||
namespace Photon.Pun.UtilityScripts
|
||||
{
|
||||
[CustomEditor(typeof(PlayerNumbering))]
|
||||
public class PlayerNumberingInspector : Editor {
|
||||
|
||||
int localPlayerIndex;
|
||||
|
||||
void OnEnable () {
|
||||
PlayerNumbering.OnPlayerNumberingChanged += RefreshData;
|
||||
}
|
||||
|
||||
void OnDisable () {
|
||||
PlayerNumbering.OnPlayerNumberingChanged -= RefreshData;
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
DrawDefaultInspector();
|
||||
|
||||
PlayerNumbering.OnPlayerNumberingChanged += RefreshData;
|
||||
|
||||
if (PhotonNetwork.InRoom)
|
||||
{
|
||||
EditorGUILayout.LabelField("Player Index", "Player ID");
|
||||
if (PlayerNumbering.SortedPlayers != null)
|
||||
{
|
||||
foreach(Player punPlayer in PlayerNumbering.SortedPlayers)
|
||||
{
|
||||
GUI.enabled = punPlayer.ActorNumber > 0;
|
||||
EditorGUILayout.LabelField("Player " +punPlayer.GetPlayerNumber() + (punPlayer.IsLocal?" - You -":""), punPlayer.ActorNumber == 0?"n/a":punPlayer.ToStringFull());
|
||||
GUI.enabled = true;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
GUILayout.Label("PlayerNumbering only works when localPlayer is inside a room");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// force repaint fo the inspector, else we would not see the new data in the inspector.
|
||||
/// This is better then doing it in OnInspectorGUI too many times per frame for no need
|
||||
/// </summary>
|
||||
void RefreshData()
|
||||
{
|
||||
Repaint();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d6590f39353bf4efdb3b14691166135f
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
@@ -0,0 +1,64 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="PunTeamsInspector.cs" company="Exit Games GmbH">
|
||||
// Part of: Photon Unity Utilities,
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// Custom inspector for PunTeams
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
|
||||
using Photon.Pun;
|
||||
using Photon.Realtime;
|
||||
|
||||
namespace Photon.Pun.UtilityScripts
|
||||
{
|
||||
#pragma warning disable 0618
|
||||
[CustomEditor(typeof(PunTeams))]
|
||||
public class PunTeamsInspector : Editor {
|
||||
|
||||
|
||||
Dictionary<PunTeams.Team, bool> _Foldouts ;
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
if (_Foldouts==null)
|
||||
{
|
||||
_Foldouts = new Dictionary<PunTeams.Team, bool>();
|
||||
}
|
||||
|
||||
if (PunTeams.PlayersPerTeam!=null)
|
||||
{
|
||||
foreach (KeyValuePair<PunTeams.Team,List<Player>> _pair in PunTeams.PlayersPerTeam)
|
||||
{
|
||||
#pragma warning restore 0618
|
||||
if (!_Foldouts.ContainsKey(_pair.Key))
|
||||
{
|
||||
_Foldouts[_pair.Key] = true;
|
||||
}
|
||||
|
||||
_Foldouts[_pair.Key] = EditorGUILayout.Foldout(_Foldouts[_pair.Key],"Team "+_pair.Key +" ("+_pair.Value.Count+")");
|
||||
|
||||
if (_Foldouts[_pair.Key])
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
foreach(Player _player in _pair.Value)
|
||||
{
|
||||
EditorGUILayout.LabelField("",_player.ToString() + (PhotonNetwork.LocalPlayer==_player?" - You -":""));
|
||||
}
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7dcadaf22424c4f5d82f4d48c3b8097f
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
@@ -0,0 +1,628 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="PhotonTeamsManager.cs" company="Exit Games GmbH">
|
||||
// Part of: Photon Unity Utilities,
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// Implements teams in a room/game with help of player properties.
|
||||
// </summary>
|
||||
// <remarks>
|
||||
// Teams are defined by name and code. Change this to get more / different teams.
|
||||
// There are no rules when / if you can join a team. You could add this in JoinTeam or something.
|
||||
// </remarks>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
using Photon.Realtime;
|
||||
using Hashtable = ExitGames.Client.Photon.Hashtable;
|
||||
|
||||
namespace Photon.Pun.UtilityScripts
|
||||
{
|
||||
[Serializable]
|
||||
public class PhotonTeam
|
||||
{
|
||||
public string Name;
|
||||
public byte Code;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("{0} [{1}]", this.Name, this.Code);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements teams in a room/game with help of player properties. Access them by Player.GetTeam extension.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Teams are defined by enum Team. Change this to get more / different teams.
|
||||
/// There are no rules when / if you can join a team. You could add this in JoinTeam or something.
|
||||
/// </remarks>
|
||||
[DisallowMultipleComponent]
|
||||
public class PhotonTeamsManager : MonoBehaviour, IMatchmakingCallbacks, IInRoomCallbacks
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
#pragma warning disable 0414
|
||||
[SerializeField]
|
||||
private bool listFoldIsOpen = true;
|
||||
#pragma warning restore 0414
|
||||
#endif
|
||||
|
||||
[SerializeField]
|
||||
private List<PhotonTeam> teamsList = new List<PhotonTeam>
|
||||
{
|
||||
new PhotonTeam { Name = "Blue", Code = 1 },
|
||||
new PhotonTeam { Name = "Red", Code = 2 }
|
||||
};
|
||||
|
||||
private Dictionary<byte, PhotonTeam> teamsByCode;
|
||||
private Dictionary<string, PhotonTeam> teamsByName;
|
||||
|
||||
/// <summary>The main list of teams with their player-lists. Automatically kept up to date.</summary>
|
||||
private Dictionary<byte, HashSet<Player>> playersPerTeam;
|
||||
|
||||
/// <summary>Defines the player custom property name to use for team affinity of "this" player.</summary>
|
||||
public const string TeamPlayerProp = "_pt";
|
||||
|
||||
public static event Action<Player, PhotonTeam> PlayerJoinedTeam;
|
||||
public static event Action<Player, PhotonTeam> PlayerLeftTeam;
|
||||
|
||||
private static PhotonTeamsManager instance;
|
||||
public static PhotonTeamsManager Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
instance = FindObjectOfType<PhotonTeamsManager>();
|
||||
if (instance == null)
|
||||
{
|
||||
GameObject obj = new GameObject();
|
||||
obj.name = "PhotonTeamsManager";
|
||||
instance = obj.AddComponent<PhotonTeamsManager>();
|
||||
}
|
||||
instance.Init();
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
#region MonoBehaviour
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (instance == null || ReferenceEquals(this, instance))
|
||||
{
|
||||
this.Init();
|
||||
instance = this;
|
||||
}
|
||||
else
|
||||
{
|
||||
Destroy(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
PhotonNetwork.AddCallbackTarget(this);
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
PhotonNetwork.RemoveCallbackTarget(this);
|
||||
this.ClearTeams();
|
||||
}
|
||||
|
||||
private void Init()
|
||||
{
|
||||
teamsByCode = new Dictionary<byte, PhotonTeam>(teamsList.Count);
|
||||
teamsByName = new Dictionary<string, PhotonTeam>(teamsList.Count);
|
||||
playersPerTeam = new Dictionary<byte, HashSet<Player>>(teamsList.Count);
|
||||
for (int i = 0; i < teamsList.Count; i++)
|
||||
{
|
||||
teamsByCode[teamsList[i].Code] = teamsList[i];
|
||||
teamsByName[teamsList[i].Name] = teamsList[i];
|
||||
playersPerTeam[teamsList[i].Code] = new HashSet<Player>();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IMatchmakingCallbacks
|
||||
|
||||
void IMatchmakingCallbacks.OnJoinedRoom()
|
||||
{
|
||||
this.UpdateTeams();
|
||||
}
|
||||
|
||||
void IMatchmakingCallbacks.OnLeftRoom()
|
||||
{
|
||||
this.ClearTeams();
|
||||
}
|
||||
|
||||
void IInRoomCallbacks.OnPlayerPropertiesUpdate(Player targetPlayer, Hashtable changedProps)
|
||||
{
|
||||
object temp;
|
||||
if (changedProps.TryGetValue(TeamPlayerProp, out temp))
|
||||
{
|
||||
if (temp == null)
|
||||
{
|
||||
foreach (byte code in playersPerTeam.Keys)
|
||||
{
|
||||
if (playersPerTeam[code].Remove(targetPlayer))
|
||||
{
|
||||
if (PlayerLeftTeam != null)
|
||||
{
|
||||
PlayerLeftTeam(targetPlayer, teamsByCode[code]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (temp is byte)
|
||||
{
|
||||
byte teamCode = (byte) temp;
|
||||
// check if player switched teams, remove from previous team
|
||||
foreach (byte code in playersPerTeam.Keys)
|
||||
{
|
||||
if (code == teamCode)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (playersPerTeam[code].Remove(targetPlayer))
|
||||
{
|
||||
if (PlayerLeftTeam != null)
|
||||
{
|
||||
PlayerLeftTeam(targetPlayer, teamsByCode[code]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
PhotonTeam team = teamsByCode[teamCode];
|
||||
if (!playersPerTeam[teamCode].Add(targetPlayer))
|
||||
{
|
||||
Debug.LogWarningFormat("Unexpected situation while setting team {0} for player {1}, updating teams for all", team, targetPlayer);
|
||||
this.UpdateTeams();
|
||||
}
|
||||
if (PlayerJoinedTeam != null)
|
||||
{
|
||||
PlayerJoinedTeam(targetPlayer, team);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogErrorFormat("Unexpected: custom property key {0} should have of type byte, instead we got {1} of type {2}. Player: {3}",
|
||||
TeamPlayerProp, temp, temp.GetType(), targetPlayer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IInRoomCallbacks.OnPlayerLeftRoom(Player otherPlayer)
|
||||
{
|
||||
if (otherPlayer.IsInactive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
PhotonTeam team = otherPlayer.GetPhotonTeam();
|
||||
if (team != null && !playersPerTeam[team.Code].Remove(otherPlayer))
|
||||
{
|
||||
Debug.LogWarningFormat("Unexpected situation while removing player {0} who left from team {1}, updating teams for all", otherPlayer, team);
|
||||
// revert to 'brute force' in case of unexpected situation
|
||||
this.UpdateTeams();
|
||||
}
|
||||
}
|
||||
|
||||
void IInRoomCallbacks.OnPlayerEnteredRoom(Player newPlayer)
|
||||
{
|
||||
PhotonTeam team = newPlayer.GetPhotonTeam();
|
||||
if (team == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (playersPerTeam[team.Code].Contains(newPlayer))
|
||||
{
|
||||
// player rejoined w/ same team
|
||||
return;
|
||||
}
|
||||
// check if player rejoined w/ different team, remove from previous team
|
||||
foreach (var key in teamsByCode.Keys)
|
||||
{
|
||||
if (playersPerTeam[key].Remove(newPlayer))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!playersPerTeam[team.Code].Add(newPlayer))
|
||||
{
|
||||
Debug.LogWarningFormat("Unexpected situation while adding player {0} who joined to team {1}, updating teams for all", newPlayer, team);
|
||||
// revert to 'brute force' in case of unexpected situation
|
||||
this.UpdateTeams();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private methods
|
||||
|
||||
private void UpdateTeams()
|
||||
{
|
||||
this.ClearTeams();
|
||||
for (int i = 0; i < PhotonNetwork.PlayerList.Length; i++)
|
||||
{
|
||||
Player player = PhotonNetwork.PlayerList[i];
|
||||
PhotonTeam playerTeam = player.GetPhotonTeam();
|
||||
if (playerTeam != null)
|
||||
{
|
||||
playersPerTeam[playerTeam.Code].Add(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearTeams()
|
||||
{
|
||||
foreach (var key in playersPerTeam.Keys)
|
||||
{
|
||||
playersPerTeam[key].Clear();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public API
|
||||
|
||||
/// <summary>
|
||||
/// Find a PhotonTeam using a team code.
|
||||
/// </summary>
|
||||
/// <param name="code">The team code.</param>
|
||||
/// <param name="team">The team to be assigned if found.</param>
|
||||
/// <returns>If successful or not.</returns>
|
||||
public bool TryGetTeamByCode(byte code, out PhotonTeam team)
|
||||
{
|
||||
return teamsByCode.TryGetValue(code, out team);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find a PhotonTeam using a team name.
|
||||
/// </summary>
|
||||
/// <param name="teamName">The team name.</param>
|
||||
/// <param name="team">The team to be assigned if found.</param>
|
||||
/// <returns>If successful or not.</returns>
|
||||
public bool TryGetTeamByName(string teamName, out PhotonTeam team)
|
||||
{
|
||||
return teamsByName.TryGetValue(teamName, out team);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all teams available.
|
||||
/// </summary>
|
||||
/// <returns>Returns all teams available.</returns>
|
||||
public PhotonTeam[] GetAvailableTeams()
|
||||
{
|
||||
if (teamsList != null)
|
||||
{
|
||||
return teamsList.ToArray();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all players joined to a team using a team code.
|
||||
/// </summary>
|
||||
/// <param name="code">The code of the team.</param>
|
||||
/// <param name="members">The array of players to be filled.</param>
|
||||
/// <returns>If successful or not.</returns>
|
||||
public bool TryGetTeamMembers(byte code, out Player[] members)
|
||||
{
|
||||
members = null;
|
||||
HashSet<Player> players;
|
||||
if (this.playersPerTeam.TryGetValue(code, out players))
|
||||
{
|
||||
members = new Player[players.Count];
|
||||
int i = 0;
|
||||
foreach (var player in players)
|
||||
{
|
||||
members[i] = player;
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all players joined to a team using a team name.
|
||||
/// </summary>
|
||||
/// <param name="teamName">The name of the team.</param>
|
||||
/// <param name="members">The array of players to be filled.</param>
|
||||
/// <returns>If successful or not.</returns>
|
||||
public bool TryGetTeamMembers(string teamName, out Player[] members)
|
||||
{
|
||||
members = null;
|
||||
PhotonTeam team;
|
||||
if (this.TryGetTeamByName(teamName, out team))
|
||||
{
|
||||
return this.TryGetTeamMembers(team.Code, out members);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all players joined to a team.
|
||||
/// </summary>
|
||||
/// <param name="team">The team which will be used to find players.</param>
|
||||
/// <param name="members">The array of players to be filled.</param>
|
||||
/// <returns>If successful or not.</returns>
|
||||
public bool TryGetTeamMembers(PhotonTeam team, out Player[] members)
|
||||
{
|
||||
members = null;
|
||||
if (team != null)
|
||||
{
|
||||
return this.TryGetTeamMembers(team.Code, out members);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all team mates of a player.
|
||||
/// </summary>
|
||||
/// <param name="player">The player whose team mates will be searched.</param>
|
||||
/// <param name="teamMates">The array of players to be filled.</param>
|
||||
/// <returns>If successful or not.</returns>
|
||||
public bool TryGetTeamMatesOfPlayer(Player player, out Player[] teamMates)
|
||||
{
|
||||
teamMates = null;
|
||||
if (player == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
PhotonTeam team = player.GetPhotonTeam();
|
||||
if (team == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
HashSet<Player> players;
|
||||
if (this.playersPerTeam.TryGetValue(team.Code, out players))
|
||||
{
|
||||
if (!players.Contains(player))
|
||||
{
|
||||
Debug.LogWarningFormat("Unexpected situation while getting team mates of player {0} who is joined to team {1}, updating teams for all", player, team);
|
||||
// revert to 'brute force' in case of unexpected situation
|
||||
this.UpdateTeams();
|
||||
}
|
||||
teamMates = new Player[players.Count - 1];
|
||||
int i = 0;
|
||||
foreach (var p in players)
|
||||
{
|
||||
if (p.Equals(player))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
teamMates[i] = p;
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of players in a team by team code.
|
||||
/// </summary>
|
||||
/// <param name="code">Unique code of the team</param>
|
||||
/// <returns>Number of players joined to the team.</returns>
|
||||
public int GetTeamMembersCount(byte code)
|
||||
{
|
||||
PhotonTeam team;
|
||||
if (this.TryGetTeamByCode(code, out team))
|
||||
{
|
||||
return this.GetTeamMembersCount(team);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of players in a team by team name.
|
||||
/// </summary>
|
||||
/// <param name="name">Unique name of the team</param>
|
||||
/// <returns>Number of players joined to the team.</returns>
|
||||
public int GetTeamMembersCount(string name)
|
||||
{
|
||||
PhotonTeam team;
|
||||
if (this.TryGetTeamByName(name, out team))
|
||||
{
|
||||
return this.GetTeamMembersCount(team);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of players in a team.
|
||||
/// </summary>
|
||||
/// <param name="team">The team you want to know the size of</param>
|
||||
/// <returns>Number of players joined to the team.</returns>
|
||||
public int GetTeamMembersCount(PhotonTeam team)
|
||||
{
|
||||
HashSet<Player> players;
|
||||
if (team != null && this.playersPerTeam.TryGetValue(team.Code, out players) && players != null)
|
||||
{
|
||||
return players.Count;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unused methods
|
||||
|
||||
void IMatchmakingCallbacks.OnFriendListUpdate(List<FriendInfo> friendList)
|
||||
{
|
||||
}
|
||||
|
||||
void IMatchmakingCallbacks.OnCreatedRoom()
|
||||
{
|
||||
}
|
||||
|
||||
void IMatchmakingCallbacks.OnCreateRoomFailed(short returnCode, string message)
|
||||
{
|
||||
}
|
||||
|
||||
void IMatchmakingCallbacks.OnJoinRoomFailed(short returnCode, string message)
|
||||
{
|
||||
}
|
||||
|
||||
void IMatchmakingCallbacks.OnJoinRandomFailed(short returnCode, string message)
|
||||
{
|
||||
}
|
||||
|
||||
void IInRoomCallbacks.OnRoomPropertiesUpdate(Hashtable propertiesThatChanged)
|
||||
{
|
||||
}
|
||||
|
||||
void IInRoomCallbacks.OnMasterClientSwitched(Player newMasterClient)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>Extension methods for the Player class that make use of PhotonTeamsManager.</summary>
|
||||
public static class PhotonTeamExtensions
|
||||
{
|
||||
/// <summary>Gets the team the player is currently joined to. Null if none.</summary>
|
||||
/// <returns>The team the player is currently joined to. Null if none.</returns>
|
||||
public static PhotonTeam GetPhotonTeam(this Player player)
|
||||
{
|
||||
object teamId;
|
||||
PhotonTeam team;
|
||||
if (player.CustomProperties.TryGetValue(PhotonTeamsManager.TeamPlayerProp, out teamId) && PhotonTeamsManager.Instance.TryGetTeamByCode((byte)teamId, out team))
|
||||
{
|
||||
return team;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Join a team.
|
||||
/// </summary>
|
||||
/// <param name="player">The player who will join a team.</param>
|
||||
/// <param name="team">The team to be joined.</param>
|
||||
/// <returns></returns>
|
||||
public static bool JoinTeam(this Player player, PhotonTeam team)
|
||||
{
|
||||
if (team == null)
|
||||
{
|
||||
Debug.LogWarning("JoinTeam failed: PhotonTeam provided is null");
|
||||
return false;
|
||||
}
|
||||
PhotonTeam currentTeam = player.GetPhotonTeam();
|
||||
if (currentTeam != null)
|
||||
{
|
||||
Debug.LogWarningFormat("JoinTeam failed: player ({0}) is already joined to a team ({1}), call SwitchTeam instead", player, team);
|
||||
return false;
|
||||
}
|
||||
return player.SetCustomProperties(new Hashtable { { PhotonTeamsManager.TeamPlayerProp, team.Code } });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Join a team using team code.
|
||||
/// </summary>
|
||||
/// <param name="player">The player who will join the team.</param>
|
||||
/// <param name="teamCode">The code fo the team to be joined.</param>
|
||||
/// <returns></returns>
|
||||
public static bool JoinTeam(this Player player, byte teamCode)
|
||||
{
|
||||
PhotonTeam team;
|
||||
return PhotonTeamsManager.Instance.TryGetTeamByCode(teamCode, out team) && player.JoinTeam(team);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Join a team using team name.
|
||||
/// </summary>
|
||||
/// <param name="player">The player who will join the team.</param>
|
||||
/// <param name="teamName">The name of the team to be joined.</param>
|
||||
/// <returns></returns>
|
||||
public static bool JoinTeam(this Player player, string teamName)
|
||||
{
|
||||
PhotonTeam team;
|
||||
return PhotonTeamsManager.Instance.TryGetTeamByName(teamName, out team) && player.JoinTeam(team);
|
||||
}
|
||||
|
||||
/// <summary>Switch that player's team to the one you assign.</summary>
|
||||
/// <remarks>Internally checks if this player is in that team already or not. Only team switches are actually sent.</remarks>
|
||||
/// <param name="player"></param>
|
||||
/// <param name="team"></param>
|
||||
public static bool SwitchTeam(this Player player, PhotonTeam team)
|
||||
{
|
||||
if (team == null)
|
||||
{
|
||||
Debug.LogWarning("SwitchTeam failed: PhotonTeam provided is null");
|
||||
return false;
|
||||
}
|
||||
PhotonTeam currentTeam = player.GetPhotonTeam();
|
||||
if (currentTeam == null)
|
||||
{
|
||||
Debug.LogWarningFormat("SwitchTeam failed: player ({0}) was not joined to any team, call JoinTeam instead", player);
|
||||
return false;
|
||||
}
|
||||
if (currentTeam.Code == team.Code)
|
||||
{
|
||||
Debug.LogWarningFormat("SwitchTeam failed: player ({0}) is already joined to the same team {1}", player, team);
|
||||
return false;
|
||||
}
|
||||
return player.SetCustomProperties(new Hashtable { { PhotonTeamsManager.TeamPlayerProp, team.Code } },
|
||||
new Hashtable { { PhotonTeamsManager.TeamPlayerProp, currentTeam.Code }});
|
||||
}
|
||||
|
||||
/// <summary>Switch the player's team using a team code.</summary>
|
||||
/// <remarks>Internally checks if this player is in that team already or not.</remarks>
|
||||
/// <param name="player">The player that will switch teams.</param>
|
||||
/// <param name="teamCode">The code of the team to switch to.</param>
|
||||
/// <returns>If the team switch request is queued to be sent to the server or done in case offline or not joined to a room yet.</returns>
|
||||
public static bool SwitchTeam(this Player player, byte teamCode)
|
||||
{
|
||||
PhotonTeam team;
|
||||
return PhotonTeamsManager.Instance.TryGetTeamByCode(teamCode, out team) && player.SwitchTeam(team);
|
||||
}
|
||||
|
||||
/// <summary>Switch the player's team using a team name.</summary>
|
||||
/// <remarks>Internally checks if this player is in that team already or not.</remarks>
|
||||
/// <param name="player">The player that will switch teams.</param>
|
||||
/// <param name="teamName">The name of the team to switch to.</param>
|
||||
/// <returns>If the team switch request is queued to be sent to the server or done in case offline or not joined to a room yet.</returns>
|
||||
public static bool SwitchTeam(this Player player, string teamName)
|
||||
{
|
||||
PhotonTeam team;
|
||||
return PhotonTeamsManager.Instance.TryGetTeamByName(teamName, out team) && player.SwitchTeam(team);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Leave the current team if any.
|
||||
/// </summary>
|
||||
/// <param name="player"></param>
|
||||
/// <returns>If the leaving team request is queued to be sent to the server or done in case offline or not joined to a room yet.</returns>
|
||||
public static bool LeaveCurrentTeam(this Player player)
|
||||
{
|
||||
PhotonTeam currentTeam = player.GetPhotonTeam();
|
||||
if (currentTeam == null)
|
||||
{
|
||||
Debug.LogWarningFormat("LeaveCurrentTeam failed: player ({0}) was not joined to any team", player);
|
||||
return false;
|
||||
}
|
||||
return player.SetCustomProperties(new Hashtable {{PhotonTeamsManager.TeamPlayerProp, null}}, new Hashtable {{PhotonTeamsManager.TeamPlayerProp, currentTeam.Code}});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to get the team mates.
|
||||
/// </summary>
|
||||
/// <param name="player">The player to get the team mates of.</param>
|
||||
/// <param name="teamMates">The team mates array to fill.</param>
|
||||
/// <returns>If successful or not.</returns>
|
||||
public static bool TryGetTeamMates(this Player player, out Player[] teamMates)
|
||||
{
|
||||
return PhotonTeamsManager.Instance.TryGetTeamMatesOfPlayer(player, out teamMates);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8701526de72d8774fa165e66daf050ed
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,267 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="PlayerNumbering.cs" company="Exit Games GmbH">
|
||||
// Part of: Photon Unity Utilities,
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// Assign numbers to Players in a room. Uses Room custom Properties
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
using Photon.Pun;
|
||||
using Photon.Realtime;
|
||||
using Hashtable = ExitGames.Client.Photon.Hashtable;
|
||||
|
||||
namespace Photon.Pun.UtilityScripts
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements consistent numbering in a room/game with help of room properties. Access them by Player.GetPlayerNumber() extension.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// indexing ranges from 0 to the maximum number of Players.
|
||||
/// indexing remains for the player while in room.
|
||||
/// If a Player is numbered 2 and player numbered 1 leaves, numbered 1 become vacant and will assigned to the future player joining (the first available vacant number is assigned when joining)
|
||||
/// </remarks>
|
||||
public class PlayerNumbering : MonoBehaviourPunCallbacks
|
||||
{
|
||||
//TODO: Add a "numbers available" bool, to allow easy access to this?!
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// The instance. EntryPoint to query about Room Indexing.
|
||||
/// </summary>
|
||||
public static PlayerNumbering instance;
|
||||
|
||||
public static Player[] SortedPlayers;
|
||||
|
||||
/// <summary>
|
||||
/// OnPlayerNumberingChanged delegate. Use
|
||||
/// </summary>
|
||||
public delegate void PlayerNumberingChanged();
|
||||
/// <summary>
|
||||
/// Called everytime the room Indexing was updated. Use this for discrete updates. Always better than brute force calls every frame.
|
||||
/// </summary>
|
||||
public static event PlayerNumberingChanged OnPlayerNumberingChanged;
|
||||
|
||||
|
||||
/// <summary>Defines the room custom property name to use for room player indexing tracking.</summary>
|
||||
public const string RoomPlayerIndexedProp = "pNr";
|
||||
|
||||
/// <summary>
|
||||
/// dont destroy on load flag for this Component's GameObject to survive Level Loading.
|
||||
/// </summary>
|
||||
public bool dontDestroyOnLoad = false;
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region MonoBehaviours methods
|
||||
|
||||
public void Awake()
|
||||
{
|
||||
|
||||
if (instance != null && instance != this && instance.gameObject != null)
|
||||
{
|
||||
GameObject.DestroyImmediate(instance.gameObject);
|
||||
}
|
||||
|
||||
instance = this;
|
||||
if (dontDestroyOnLoad)
|
||||
{
|
||||
DontDestroyOnLoad(this.gameObject);
|
||||
}
|
||||
|
||||
this.RefreshData();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region PunBehavior Overrides
|
||||
|
||||
public override void OnJoinedRoom()
|
||||
{
|
||||
this.RefreshData();
|
||||
}
|
||||
|
||||
public override void OnLeftRoom()
|
||||
{
|
||||
PhotonNetwork.LocalPlayer.CustomProperties.Remove(PlayerNumbering.RoomPlayerIndexedProp);
|
||||
}
|
||||
|
||||
public override void OnPlayerEnteredRoom(Player newPlayer)
|
||||
{
|
||||
this.RefreshData();
|
||||
}
|
||||
|
||||
public override void OnPlayerLeftRoom(Player otherPlayer)
|
||||
{
|
||||
this.RefreshData();
|
||||
}
|
||||
|
||||
public override void OnPlayerPropertiesUpdate(Player targetPlayer, Hashtable changedProps)
|
||||
{
|
||||
if (changedProps != null && changedProps.ContainsKey(PlayerNumbering.RoomPlayerIndexedProp))
|
||||
{
|
||||
this.RefreshData();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
// each player can select it's own playernumber in a room, if all "older" players already selected theirs
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Internal call Refresh the cached data and call the OnPlayerNumberingChanged delegate.
|
||||
/// </summary>
|
||||
public void RefreshData()
|
||||
{
|
||||
if (PhotonNetwork.CurrentRoom == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (PhotonNetwork.LocalPlayer.GetPlayerNumber() >= 0)
|
||||
{
|
||||
SortedPlayers = PhotonNetwork.CurrentRoom.Players.Values.OrderBy((p) => p.GetPlayerNumber()).ToArray();
|
||||
if (OnPlayerNumberingChanged != null)
|
||||
{
|
||||
OnPlayerNumberingChanged();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
HashSet<int> usedInts = new HashSet<int>();
|
||||
Player[] sorted = PhotonNetwork.PlayerList.OrderBy((p) => p.ActorNumber).ToArray();
|
||||
|
||||
string allPlayers = "all players: ";
|
||||
foreach (Player player in sorted)
|
||||
{
|
||||
allPlayers += player.ActorNumber + "=pNr:"+player.GetPlayerNumber()+", ";
|
||||
|
||||
int number = player.GetPlayerNumber();
|
||||
|
||||
// if it's this user, select a number and break
|
||||
// else:
|
||||
// check if that user has a number
|
||||
// if not, break!
|
||||
// else remember used numbers
|
||||
|
||||
if (player.IsLocal)
|
||||
{
|
||||
Debug.Log ("PhotonNetwork.CurrentRoom.PlayerCount = " + PhotonNetwork.CurrentRoom.PlayerCount);
|
||||
|
||||
// select a number
|
||||
for (int i = 0; i < PhotonNetwork.CurrentRoom.PlayerCount; i++)
|
||||
{
|
||||
if (!usedInts.Contains(i))
|
||||
{
|
||||
player.SetPlayerNumber(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// then break
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (number < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
usedInts.Add(number);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Debug.Log(allPlayers);
|
||||
//Debug.Log(PhotonNetwork.LocalPlayer.ToStringFull() + " has PhotonNetwork.player.GetPlayerNumber(): " + PhotonNetwork.LocalPlayer.GetPlayerNumber());
|
||||
|
||||
SortedPlayers = PhotonNetwork.CurrentRoom.Players.Values.OrderBy((p) => p.GetPlayerNumber()).ToArray();
|
||||
if (OnPlayerNumberingChanged != null)
|
||||
{
|
||||
OnPlayerNumberingChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>Extension used for PlayerRoomIndexing and Player class.</summary>
|
||||
public static class PlayerNumberingExtensions
|
||||
{
|
||||
/// <summary>Extension for Player class to wrap up access to the player's custom property.
|
||||
/// Make sure you use the delegate 'OnPlayerNumberingChanged' to knoiw when you can query the PlayerNumber. Numbering can changes over time or not be yet assigned during the initial phase ( when player creates a room for example)
|
||||
/// </summary>
|
||||
/// <returns>persistent index in room. -1 for no indexing</returns>
|
||||
public static int GetPlayerNumber(this Player player)
|
||||
{
|
||||
if (player == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (PhotonNetwork.OfflineMode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (!PhotonNetwork.IsConnectedAndReady)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
object value;
|
||||
if (player.CustomProperties.TryGetValue (PlayerNumbering.RoomPlayerIndexedProp, out value)) {
|
||||
return (byte)value;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the player number.
|
||||
/// It's not recommanded to manually interfere with the playerNumbering, but possible.
|
||||
/// </summary>
|
||||
/// <param name="player">Player.</param>
|
||||
/// <param name="playerNumber">Player number.</param>
|
||||
public static void SetPlayerNumber(this Player player, int playerNumber)
|
||||
{
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (PhotonNetwork.OfflineMode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (playerNumber < 0)
|
||||
{
|
||||
Debug.LogWarning("Setting invalid playerNumber: " + playerNumber + " for: " + player.ToStringFull());
|
||||
}
|
||||
|
||||
if (!PhotonNetwork.IsConnectedAndReady)
|
||||
{
|
||||
Debug.LogWarning("SetPlayerNumber was called in state: " + PhotonNetwork.NetworkClientState + ". Not IsConnectedAndReady.");
|
||||
return;
|
||||
}
|
||||
|
||||
int current = player.GetPlayerNumber();
|
||||
if (current != playerNumber)
|
||||
{
|
||||
Debug.Log("PlayerNumbering: Set number "+playerNumber);
|
||||
player.SetCustomProperties(new Hashtable() { { PlayerNumbering.RoomPlayerIndexedProp, (byte)playerNumber } });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b28dd60f6abf16d4094cf0f642a043e2
|
||||
timeCreated: 1512563044
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,62 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="PunPlayerScores.cs" company="Exit Games GmbH">
|
||||
// Part of: Photon Unity Utilities,
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// Scoring system for PhotonPlayer
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
using Photon.Pun;
|
||||
using Photon.Realtime;
|
||||
using Hashtable = ExitGames.Client.Photon.Hashtable;
|
||||
|
||||
namespace Photon.Pun.UtilityScripts
|
||||
{
|
||||
/// <summary>
|
||||
/// Scoring system for PhotonPlayer
|
||||
/// </summary>
|
||||
public class PunPlayerScores : MonoBehaviour
|
||||
{
|
||||
public const string PlayerScoreProp = "score";
|
||||
}
|
||||
|
||||
public static class ScoreExtensions
|
||||
{
|
||||
public static void SetScore(this Player player, int newScore)
|
||||
{
|
||||
Hashtable score = new Hashtable(); // using PUN's implementation of Hashtable
|
||||
score[PunPlayerScores.PlayerScoreProp] = newScore;
|
||||
|
||||
player.SetCustomProperties(score); // this locally sets the score and will sync it in-game asap.
|
||||
}
|
||||
|
||||
public static void AddScore(this Player player, int scoreToAddToCurrent)
|
||||
{
|
||||
int current = player.GetScore();
|
||||
current = current + scoreToAddToCurrent;
|
||||
|
||||
Hashtable score = new Hashtable(); // using PUN's implementation of Hashtable
|
||||
score[PunPlayerScores.PlayerScoreProp] = current;
|
||||
|
||||
player.SetCustomProperties(score); // this locally sets the score and will sync it in-game asap.
|
||||
}
|
||||
|
||||
public static int GetScore(this Player player)
|
||||
{
|
||||
object score;
|
||||
if (player.CustomProperties.TryGetValue(PunPlayerScores.PlayerScoreProp, out score))
|
||||
{
|
||||
return (int)score;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6b4df3943860f1d45bfe232053a58d80
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
@@ -0,0 +1,156 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="PunTeams.cs" company="Exit Games GmbH">
|
||||
// Part of: Photon Unity Utilities,
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// Implements teams in a room/game with help of player properties. Access them by Player.GetTeam extension.
|
||||
// </summary>
|
||||
// <remarks>
|
||||
// Teams are defined by enum Team. Change this to get more / different teams.
|
||||
// There are no rules when / if you can join a team. You could add this in JoinTeam or something.
|
||||
// </remarks>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
using Photon.Pun;
|
||||
using Photon.Realtime;
|
||||
using ExitGames.Client.Photon;
|
||||
using Hashtable = ExitGames.Client.Photon.Hashtable;
|
||||
|
||||
namespace Photon.Pun.UtilityScripts
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements teams in a room/game with help of player properties. Access them by Player.GetTeam extension.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Teams are defined by enum Team. Change this to get more / different teams.
|
||||
/// There are no rules when / if you can join a team. You could add this in JoinTeam or something.
|
||||
/// </remarks>
|
||||
[Obsolete("do not use this or add it to the scene. use PhotonTeamsManager instead")]
|
||||
public class PunTeams : MonoBehaviourPunCallbacks
|
||||
{
|
||||
/// <summary>Enum defining the teams available. First team should be neutral (it's the default value any field of this enum gets).</summary>
|
||||
[Obsolete("use custom PhotonTeam instead")]
|
||||
public enum Team : byte { none, red, blue };
|
||||
|
||||
/// <summary>The main list of teams with their player-lists. Automatically kept up to date.</summary>
|
||||
/// <remarks>Note that this is static. Can be accessed by PunTeam.PlayersPerTeam. You should not modify this.</remarks>
|
||||
[Obsolete("use PhotonTeamsManager.Instance.TryGetTeamMembers instead")]
|
||||
public static Dictionary<Team, List<Player>> PlayersPerTeam;
|
||||
|
||||
/// <summary>Defines the player custom property name to use for team affinity of "this" player.</summary>
|
||||
[Obsolete("do not use this. PhotonTeamsManager.TeamPlayerProp is used internally instead.")]
|
||||
public const string TeamPlayerProp = "team";
|
||||
|
||||
|
||||
#region Events by Unity and Photon
|
||||
|
||||
public void Start()
|
||||
{
|
||||
PlayersPerTeam = new Dictionary<Team, List<Player>>();
|
||||
Array enumVals = Enum.GetValues(typeof(Team));
|
||||
foreach (var enumVal in enumVals)
|
||||
{
|
||||
PlayersPerTeam[(Team)enumVal] = new List<Player>();
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnDisable()
|
||||
{
|
||||
base.OnDisable();
|
||||
this.Start();
|
||||
}
|
||||
|
||||
/// <summary>Needed to update the team lists when joining a room.</summary>
|
||||
/// <remarks>Called by PUN. See enum MonoBehaviourPunCallbacks for an explanation.</remarks>
|
||||
public override void OnJoinedRoom()
|
||||
{
|
||||
|
||||
this.UpdateTeams();
|
||||
}
|
||||
|
||||
public override void OnLeftRoom()
|
||||
{
|
||||
Start();
|
||||
}
|
||||
|
||||
/// <summary>Refreshes the team lists. It could be a non-team related property change, too.</summary>
|
||||
/// <remarks>Called by PUN. See enum MonoBehaviourPunCallbacks for an explanation.</remarks>
|
||||
public override void OnPlayerPropertiesUpdate(Player targetPlayer, Hashtable changedProps)
|
||||
{
|
||||
this.UpdateTeams();
|
||||
}
|
||||
|
||||
public override void OnPlayerLeftRoom(Player otherPlayer)
|
||||
{
|
||||
this.UpdateTeams();
|
||||
}
|
||||
|
||||
public override void OnPlayerEnteredRoom(Player newPlayer)
|
||||
{
|
||||
this.UpdateTeams();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
[Obsolete("do not call this.")]
|
||||
public void UpdateTeams()
|
||||
{
|
||||
Array enumVals = Enum.GetValues(typeof(Team));
|
||||
foreach (var enumVal in enumVals)
|
||||
{
|
||||
PlayersPerTeam[(Team)enumVal].Clear();
|
||||
}
|
||||
|
||||
for (int i = 0; i < PhotonNetwork.PlayerList.Length; i++)
|
||||
{
|
||||
Player player = PhotonNetwork.PlayerList[i];
|
||||
Team playerTeam = player.GetTeam();
|
||||
PlayersPerTeam[playerTeam].Add(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Extension used for PunTeams and Player class. Wraps access to the player's custom property.</summary>
|
||||
public static class TeamExtensions
|
||||
{
|
||||
/// <summary>Extension for Player class to wrap up access to the player's custom property.</summary>
|
||||
/// <returns>PunTeam.Team.none if no team was found (yet).</returns>
|
||||
[Obsolete("Use player.GetPhotonTeam")]
|
||||
public static PunTeams.Team GetTeam(this Player player)
|
||||
{
|
||||
object teamId;
|
||||
if (player.CustomProperties.TryGetValue(PunTeams.TeamPlayerProp, out teamId))
|
||||
{
|
||||
return (PunTeams.Team)teamId;
|
||||
}
|
||||
|
||||
return PunTeams.Team.none;
|
||||
}
|
||||
|
||||
/// <summary>Switch that player's team to the one you assign.</summary>
|
||||
/// <remarks>Internally checks if this player is in that team already or not. Only team switches are actually sent.</remarks>
|
||||
/// <param name="player"></param>
|
||||
/// <param name="team"></param>
|
||||
[Obsolete("Use player.JoinTeam")]
|
||||
public static void SetTeam(this Player player, PunTeams.Team team)
|
||||
{
|
||||
if (!PhotonNetwork.IsConnectedAndReady)
|
||||
{
|
||||
Debug.LogWarning("JoinTeam was called in state: " + PhotonNetwork.NetworkClientState + ". Not IsConnectedAndReady.");
|
||||
return;
|
||||
}
|
||||
|
||||
PunTeams.Team currentTeam = player.GetTeam();
|
||||
if (currentTeam != team)
|
||||
{
|
||||
player.SetCustomProperties(new Hashtable() { { PunTeams.TeamPlayerProp, (byte)team } });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6587c8104d7524f4280d0a68dd779f27
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
Reference in New Issue
Block a user