summaryrefslogtreecommitdiff
path: root/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts
diff options
context:
space:
mode:
Diffstat (limited to 'Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts')
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling.meta9
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling/CullArea.cs501
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling/CullArea.cs.meta8
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling/CullingHandler.cs254
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling/CullingHandler.cs.meta8
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling/Editor.meta9
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling/Editor/CullAreaEditor.cs265
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling/Editor/CullAreaEditor.cs.meta8
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling/Editor/PhotonUnityNetworking.Utilities.Culling.Editor.asmdef12
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling/Editor/PhotonUnityNetworking.Utilities.Culling.Editor.asmdef.meta8
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Debugging.meta9
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Debugging/PhotonLagSimulationGui.cs109
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Debugging/PhotonLagSimulationGui.cs.meta12
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Debugging/PhotonStatsGui.cs170
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Debugging/PhotonStatsGui.cs.meta12
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Debugging/PointedAtGameObjectInfo.cs84
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Debugging/PointedAtGameObjectInfo.cs.meta7
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Debugging/StatesGui.cs212
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Debugging/StatesGui.cs.meta12
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer.meta7
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/Editor.meta7
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/Editor/PhotonTeamsManagerInspector.cs246
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/Editor/PhotonTeamsManagerInspector.cs.meta11
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/Editor/PhotonUnityNetworking.Utilities.PhotonPlayer.Editor.asmdef15
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/Editor/PhotonUnityNetworking.Utilities.PhotonPlayer.Editor.asmdef.meta8
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/Editor/PlayerNumberingInspector.cs67
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/Editor/PlayerNumberingInspector.cs.meta8
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/Editor/PunTeamsInspector.cs64
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/Editor/PunTeamsInspector.cs.meta8
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/PhotonTeamsManager.cs628
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/PhotonTeamsManager.cs.meta11
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/PlayerNumbering.cs267
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/PlayerNumbering.cs.meta12
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/PunPlayerScores.cs62
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/PunPlayerScores.cs.meta7
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/PunTeams.cs156
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/PunTeams.cs.meta7
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonUnityNetworking.Utilities.asmdef11
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonUnityNetworking.Utilities.asmdef.meta8
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonView.meta9
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonView/SmoothSyncMovement.cs72
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonView/SmoothSyncMovement.cs.meta7
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping.meta9
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/ConnectAndJoinRandom.cs136
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/ConnectAndJoinRandom.cs.meta7
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/MoveByKeys.cs111
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/MoveByKeys.cs.meta7
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnClickDestroy.cs72
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnClickDestroy.cs.meta7
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnClickInstantiate.cs56
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnClickInstantiate.cs.meta7
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnClickRpc.cs89
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnClickRpc.cs.meta12
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnEscapeQuit.cs32
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnEscapeQuit.cs.meta7
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnJoinedInstantiate.cs450
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnJoinedInstantiate.cs.meta7
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnStartDelete.cs24
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnStartDelete.cs.meta7
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Room.meta9
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Room/CountdownTimer.cs176
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Room/CountdownTimer.cs.meta12
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/TurnBased.meta9
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/TurnBased/PunTurnManager.cs430
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/TurnBased/PunTurnManager.cs.meta8
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI.meta7
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/ButtonInsideScrollList.cs53
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/ButtonInsideScrollList.cs.meta8
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/EventSystemSpawner.cs40
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/EventSystemSpawner.cs.meta12
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/GraphicToggleIsOnTransition.cs64
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/GraphicToggleIsOnTransition.cs.meta12
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/OnPointerOverTooltip.cs45
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/OnPointerOverTooltip.cs.meta12
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/TabViewManager.cs123
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/TabViewManager.cs.meta12
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/TextButtonTransition.cs70
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/TextButtonTransition.cs.meta8
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/TextToggleIsOnTransition.cs86
-rw-r--r--Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/TextToggleIsOnTransition.cs.meta8
80 files changed, 5651 insertions, 0 deletions
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling.meta
new file mode 100644
index 0000000..408aec2
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 404d7999c3b78454798028d2efcb9336
+folderAsset: yes
+timeCreated: 1529327267
+licenseType: Store
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling/CullArea.cs b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling/CullArea.cs
new file mode 100644
index 0000000..0af640f
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling/CullArea.cs
@@ -0,0 +1,501 @@
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="CullArea.cs" company="Exit Games GmbH">
+// Part of: Photon Unity Utilities,
+// </copyright>
+// <summary>
+// Represents the cull area used for network culling.
+// </summary>
+// <author>developer@exitgames.com</author>
+// --------------------------------------------------------------------------------------------------------------------
+
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace Photon.Pun.UtilityScripts
+{
+ using System;
+
+
+ /// <summary>
+ /// Represents the cull area used for network culling.
+ /// </summary>
+ public class CullArea : MonoBehaviour
+ {
+ private const int MAX_NUMBER_OF_ALLOWED_CELLS = 250;
+
+ public const int MAX_NUMBER_OF_SUBDIVISIONS = 3;
+
+ /// <summary>
+ /// This represents the first ID which is assigned to the first created cell.
+ /// If you already have some interest groups blocking this first ID, fell free to change it.
+ /// However increasing the first group ID decreases the maximum amount of allowed cells.
+ /// Allowed values are in range from 1 to 250.
+ /// </summary>
+ public readonly byte FIRST_GROUP_ID = 1;
+
+ /// <summary>
+ /// This represents the order in which updates are sent.
+ /// The number represents the subdivision of the cell hierarchy:
+ /// - 0: message is sent to all players
+ /// - 1: message is sent to players who are interested in the matching cell of the first subdivision
+ /// If there is only one subdivision we are sending one update to all players
+ /// before sending three consequent updates only to players who are in the same cell
+ /// or interested in updates of the current cell.
+ /// </summary>
+ public readonly int[] SUBDIVISION_FIRST_LEVEL_ORDER = new int[4] { 0, 1, 1, 1 };
+
+ /// <summary>
+ /// This represents the order in which updates are sent.
+ /// The number represents the subdivision of the cell hierarchy:
+ /// - 0: message is sent to all players
+ /// - 1: message is sent to players who are interested in the matching cell of the first subdivision
+ /// - 2: message is sent to players who are interested in the matching cell of the second subdivision
+ /// If there are two subdivisions we are sending every second update only to players
+ /// who are in the same cell or interested in updates of the current cell.
+ /// </summary>
+ public readonly int[] SUBDIVISION_SECOND_LEVEL_ORDER = new int[8] { 0, 2, 1, 2, 0, 2, 1, 2 };
+
+ /// <summary>
+ /// This represents the order in which updates are sent.
+ /// The number represents the subdivision of the cell hierarchy:
+ /// - 0: message is sent to all players
+ /// - 1: message is sent to players who are interested in the matching cell of the first subdivision
+ /// - 2: message is sent to players who are interested in the matching cell of the second subdivision
+ /// - 3: message is sent to players who are interested in the matching cell of the third subdivision
+ /// If there are two subdivisions we are sending every second update only to players
+ /// who are in the same cell or interested in updates of the current cell.
+ /// </summary>
+ public readonly int[] SUBDIVISION_THIRD_LEVEL_ORDER = new int[12] { 0, 3, 2, 3, 1, 3, 2, 3, 1, 3, 2, 3 };
+
+ public Vector2 Center;
+ public Vector2 Size = new Vector2(25.0f, 25.0f);
+
+ public Vector2[] Subdivisions = new Vector2[MAX_NUMBER_OF_SUBDIVISIONS];
+
+ public int NumberOfSubdivisions;
+
+ public int CellCount { get; private set; }
+
+ public CellTree CellTree { get; private set; }
+
+ public Dictionary<int, GameObject> Map { get; private set; }
+
+ public bool YIsUpAxis = false;
+ public bool RecreateCellHierarchy = false;
+
+ private byte idCounter;
+
+ /// <summary>
+ /// Creates the cell hierarchy at runtime.
+ /// </summary>
+ private void Awake()
+ {
+ this.idCounter = this.FIRST_GROUP_ID;
+
+ this.CreateCellHierarchy();
+ }
+
+ /// <summary>
+ /// Creates the cell hierarchy in editor and draws the cell view.
+ /// </summary>
+ public void OnDrawGizmos()
+ {
+ this.idCounter = this.FIRST_GROUP_ID;
+
+ if (this.RecreateCellHierarchy)
+ {
+ this.CreateCellHierarchy();
+ }
+
+ this.DrawCells();
+ }
+
+ /// <summary>
+ /// Creates the cell hierarchy.
+ /// </summary>
+ private void CreateCellHierarchy()
+ {
+ if (!this.IsCellCountAllowed())
+ {
+ if (Debug.isDebugBuild)
+ {
+ Debug.LogError("There are too many cells created by your subdivision options. Maximum allowed number of cells is " + (MAX_NUMBER_OF_ALLOWED_CELLS - this.FIRST_GROUP_ID) +
+ ". Current number of cells is " + this.CellCount + ".");
+ return;
+ }
+ else
+ {
+ Application.Quit();
+ }
+ }
+
+ CellTreeNode rootNode = new CellTreeNode(this.idCounter++, CellTreeNode.ENodeType.Root, null);
+
+ if (this.YIsUpAxis)
+ {
+ this.Center = new Vector2(transform.position.x, transform.position.y);
+ this.Size = new Vector2(transform.localScale.x, transform.localScale.y);
+
+ rootNode.Center = new Vector3(this.Center.x, this.Center.y, 0.0f);
+ rootNode.Size = new Vector3(this.Size.x, this.Size.y, 0.0f);
+ rootNode.TopLeft = new Vector3((this.Center.x - (this.Size.x / 2.0f)), (this.Center.y - (this.Size.y / 2.0f)), 0.0f);
+ rootNode.BottomRight = new Vector3((this.Center.x + (this.Size.x / 2.0f)), (this.Center.y + (this.Size.y / 2.0f)), 0.0f);
+ }
+ else
+ {
+ this.Center = new Vector2(transform.position.x, transform.position.z);
+ this.Size = new Vector2(transform.localScale.x, transform.localScale.z);
+
+ rootNode.Center = new Vector3(this.Center.x, 0.0f, this.Center.y);
+ rootNode.Size = new Vector3(this.Size.x, 0.0f, this.Size.y);
+ rootNode.TopLeft = new Vector3((this.Center.x - (this.Size.x / 2.0f)), 0.0f, (this.Center.y - (this.Size.y / 2.0f)));
+ rootNode.BottomRight = new Vector3((this.Center.x + (this.Size.x / 2.0f)), 0.0f, (this.Center.y + (this.Size.y / 2.0f)));
+ }
+
+ this.CreateChildCells(rootNode, 1);
+
+ this.CellTree = new CellTree(rootNode);
+
+ this.RecreateCellHierarchy = false;
+ }
+
+ /// <summary>
+ /// Creates all child cells.
+ /// </summary>
+ /// <param name="parent">The current parent node.</param>
+ /// <param name="cellLevelInHierarchy">The cell level within the current hierarchy.</param>
+ private void CreateChildCells(CellTreeNode parent, int cellLevelInHierarchy)
+ {
+ if (cellLevelInHierarchy > this.NumberOfSubdivisions)
+ {
+ return;
+ }
+
+ int rowCount = (int)this.Subdivisions[(cellLevelInHierarchy - 1)].x;
+ int columnCount = (int)this.Subdivisions[(cellLevelInHierarchy - 1)].y;
+
+ float startX = parent.Center.x - (parent.Size.x / 2.0f);
+ float width = parent.Size.x / rowCount;
+
+ for (int row = 0; row < rowCount; ++row)
+ {
+ for (int column = 0; column < columnCount; ++column)
+ {
+ float xPos = startX + (row * width) + (width / 2.0f);
+
+ CellTreeNode node = new CellTreeNode(this.idCounter++, (this.NumberOfSubdivisions == cellLevelInHierarchy) ? CellTreeNode.ENodeType.Leaf : CellTreeNode.ENodeType.Node, parent);
+
+ if (this.YIsUpAxis)
+ {
+ float startY = parent.Center.y - (parent.Size.y / 2.0f);
+ float height = parent.Size.y / columnCount;
+ float yPos = startY + (column * height) + (height / 2.0f);
+
+ node.Center = new Vector3(xPos, yPos, 0.0f);
+ node.Size = new Vector3(width, height, 0.0f);
+ node.TopLeft = new Vector3(xPos - (width / 2.0f), yPos - (height / 2.0f), 0.0f);
+ node.BottomRight = new Vector3(xPos + (width / 2.0f), yPos + (height / 2.0f), 0.0f);
+ }
+ else
+ {
+ float startZ = parent.Center.z - (parent.Size.z / 2.0f);
+ float depth = parent.Size.z / columnCount;
+ float zPos = startZ + (column * depth) + (depth / 2.0f);
+
+ node.Center = new Vector3(xPos, 0.0f, zPos);
+ node.Size = new Vector3(width, 0.0f, depth);
+ node.TopLeft = new Vector3(xPos - (width / 2.0f), 0.0f, zPos - (depth / 2.0f));
+ node.BottomRight = new Vector3(xPos + (width / 2.0f), 0.0f, zPos + (depth / 2.0f));
+ }
+
+ parent.AddChild(node);
+
+ this.CreateChildCells(node, (cellLevelInHierarchy + 1));
+ }
+ }
+ }
+
+ /// <summary>
+ /// Draws the cells.
+ /// </summary>
+ private void DrawCells()
+ {
+ if ((this.CellTree != null) && (this.CellTree.RootNode != null))
+ {
+ this.CellTree.RootNode.Draw();
+ }
+ else
+ {
+ this.RecreateCellHierarchy = true;
+ }
+ }
+
+ /// <summary>
+ /// Checks if the cell count is allowed.
+ /// </summary>
+ /// <returns>True if the cell count is allowed, false if the cell count is too large.</returns>
+ private bool IsCellCountAllowed()
+ {
+ int horizontalCells = 1;
+ int verticalCells = 1;
+
+ foreach (Vector2 v in this.Subdivisions)
+ {
+ horizontalCells *= (int)v.x;
+ verticalCells *= (int)v.y;
+ }
+
+ this.CellCount = horizontalCells * verticalCells;
+
+ return (this.CellCount <= (MAX_NUMBER_OF_ALLOWED_CELLS - this.FIRST_GROUP_ID));
+ }
+
+ /// <summary>
+ /// Gets a list of all cell IDs the player is currently inside or nearby.
+ /// </summary>
+ /// <param name="position">The current position of the player.</param>
+ /// <returns>A list containing all cell IDs the player is currently inside or nearby.</returns>
+ public List<byte> GetActiveCells(Vector3 position)
+ {
+ List<byte> activeCells = new List<byte>(0);
+ this.CellTree.RootNode.GetActiveCells(activeCells, this.YIsUpAxis, position);
+
+ // it makes sense to sort the "nearby" cells. those are in the list in positions after the subdivisions the point is inside. 2 subdivisions result in 3 areas the point is in.
+ int cellsActive = this.NumberOfSubdivisions + 1;
+ int cellsNearby = activeCells.Count - cellsActive;
+ if (cellsNearby > 0)
+ {
+ activeCells.Sort(cellsActive, cellsNearby, new ByteComparer());
+ }
+ return activeCells;
+ }
+ }
+
+ /// <summary>
+ /// Represents the tree accessible from its root node.
+ /// </summary>
+ public class CellTree
+ {
+ /// <summary>
+ /// Represents the root node of the cell tree.
+ /// </summary>
+ public CellTreeNode RootNode { get; private set; }
+
+ /// <summary>
+ /// Default constructor.
+ /// </summary>
+ public CellTree()
+ {
+ }
+
+ /// <summary>
+ /// Constructor to define the root node.
+ /// </summary>
+ /// <param name="root">The root node of the tree.</param>
+ public CellTree(CellTreeNode root)
+ {
+ this.RootNode = root;
+ }
+ }
+
+ /// <summary>
+ /// Represents a single node of the tree.
+ /// </summary>
+ public class CellTreeNode
+ {
+ public enum ENodeType : byte
+ {
+ Root = 0,
+ Node = 1,
+ Leaf = 2
+ }
+
+ /// <summary>
+ /// Represents the unique ID of the cell.
+ /// </summary>
+ public byte Id;
+
+ /// <summary>
+ /// Represents the center, top-left or bottom-right position of the cell
+ /// or the size of the cell.
+ /// </summary>
+ public Vector3 Center, Size, TopLeft, BottomRight;
+
+ /// <summary>
+ /// Describes the current node type of the cell tree node.
+ /// </summary>
+ public ENodeType NodeType;
+
+ /// <summary>
+ /// Reference to the parent node.
+ /// </summary>
+ public CellTreeNode Parent;
+
+ /// <summary>
+ /// A list containing all child nodes.
+ /// </summary>
+ public List<CellTreeNode> Childs;
+
+ /// <summary>
+ /// The max distance the player can have to the center of the cell for being 'nearby'.
+ /// This is calculated once at runtime.
+ /// </summary>
+ private float maxDistance;
+
+ /// <summary>
+ /// Default constructor.
+ /// </summary>
+ public CellTreeNode()
+ {
+ }
+
+ /// <summary>
+ /// Constructor to define the ID and the node type as well as setting a parent node.
+ /// </summary>
+ /// <param name="id">The ID of the cell is used as the interest group.</param>
+ /// <param name="nodeType">The node type of the cell tree node.</param>
+ /// <param name="parent">The parent node of the cell tree node.</param>
+ public CellTreeNode(byte id, ENodeType nodeType, CellTreeNode parent)
+ {
+ this.Id = id;
+
+ this.NodeType = nodeType;
+
+ this.Parent = parent;
+ }
+
+ /// <summary>
+ /// Adds the given child to the node.
+ /// </summary>
+ /// <param name="child">The child which is added to the node.</param>
+ public void AddChild(CellTreeNode child)
+ {
+ if (this.Childs == null)
+ {
+ this.Childs = new List<CellTreeNode>(1);
+ }
+
+ this.Childs.Add(child);
+ }
+
+ /// <summary>
+ /// Draws the cell in the editor.
+ /// </summary>
+ public void Draw()
+ {
+#if UNITY_EDITOR
+ if (this.Childs != null)
+ {
+ foreach (CellTreeNode node in this.Childs)
+ {
+ node.Draw();
+ }
+ }
+
+ Gizmos.color = new Color((this.NodeType == ENodeType.Root) ? 1 : 0, (this.NodeType == ENodeType.Node) ? 1 : 0, (this.NodeType == ENodeType.Leaf) ? 1 : 0);
+ Gizmos.DrawWireCube(this.Center, this.Size);
+
+ byte offset = (byte)this.NodeType;
+ GUIStyle gs = new GUIStyle() { fontStyle = FontStyle.Bold };
+ gs.normal.textColor = Gizmos.color;
+ UnityEditor.Handles.Label(this.Center+(Vector3.forward*offset*1f), this.Id.ToString(), gs);
+#endif
+ }
+
+ /// <summary>
+ /// Gathers all cell IDs the player is currently inside or nearby.
+ /// </summary>
+ /// <param name="activeCells">The list to add all cell IDs to the player is currently inside or nearby.</param>
+ /// <param name="yIsUpAxis">Describes if the y-axis is used as up-axis.</param>
+ /// <param name="position">The current position of the player.</param>
+ public void GetActiveCells(List<byte> activeCells, bool yIsUpAxis, Vector3 position)
+ {
+ if (this.NodeType != ENodeType.Leaf)
+ {
+ foreach (CellTreeNode node in this.Childs)
+ {
+ node.GetActiveCells(activeCells, yIsUpAxis, position);
+ }
+ }
+ else
+ {
+ if (this.IsPointNearCell(yIsUpAxis, position))
+ {
+ if (this.IsPointInsideCell(yIsUpAxis, position))
+ {
+ activeCells.Insert(0, this.Id);
+
+ CellTreeNode p = this.Parent;
+ while (p != null)
+ {
+ activeCells.Insert(0, p.Id);
+
+ p = p.Parent;
+ }
+ }
+ else
+ {
+ activeCells.Add(this.Id);
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Checks if the given point is inside the cell.
+ /// </summary>
+ /// <param name="yIsUpAxis">Describes if the y-axis is used as up-axis.</param>
+ /// <param name="point">The point to check.</param>
+ /// <returns>True if the point is inside the cell, false if the point is not inside the cell.</returns>
+ public bool IsPointInsideCell(bool yIsUpAxis, Vector3 point)
+ {
+ if ((point.x < this.TopLeft.x) || (point.x > this.BottomRight.x))
+ {
+ return false;
+ }
+
+ if (yIsUpAxis)
+ {
+ if ((point.y >= this.TopLeft.y) && (point.y <= this.BottomRight.y))
+ {
+ return true;
+ }
+ }
+ else
+ {
+ if ((point.z >= this.TopLeft.z) && (point.z <= this.BottomRight.z))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /// <summary>
+ /// Checks if the given point is near the cell.
+ /// </summary>
+ /// <param name="yIsUpAxis">Describes if the y-axis is used as up-axis.</param>
+ /// <param name="point">The point to check.</param>
+ /// <returns>True if the point is near the cell, false if the point is too far away.</returns>
+ public bool IsPointNearCell(bool yIsUpAxis, Vector3 point)
+ {
+ if (this.maxDistance == 0.0f)
+ {
+ this.maxDistance = (this.Size.x + this.Size.y + this.Size.z) / 2.0f;
+ }
+
+ return ((point - this.Center).sqrMagnitude <= (this.maxDistance * this.maxDistance));
+ }
+ }
+
+
+ public class ByteComparer : IComparer<byte>
+ {
+ /// <inheritdoc />
+ public int Compare(byte x, byte y)
+ {
+ return x == y ? 0 : x < y ? -1 : 1;
+ }
+ }
+} \ No newline at end of file
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling/CullArea.cs.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling/CullArea.cs.meta
new file mode 100644
index 0000000..9f081cd
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling/CullArea.cs.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: dfb1c264fdc576442b2f42c998bed4a2
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling/CullingHandler.cs b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling/CullingHandler.cs
new file mode 100644
index 0000000..eb90b22
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling/CullingHandler.cs
@@ -0,0 +1,254 @@
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="CullingHandler.cs" company="Exit Games GmbH">
+// Part of: Photon Unity Utilities,
+// </copyright>
+// <summary>
+// Handles the network culling.
+// </summary>
+// <author>developer@exitgames.com</author>
+// --------------------------------------------------------------------------------------------------------------------
+
+using System.Collections.Generic;
+
+using UnityEngine;
+
+using Photon.Pun;
+
+namespace Photon.Pun.UtilityScripts
+{
+ using ExitGames.Client.Photon;
+
+
+ /// <summary>
+ /// Handles the network culling.
+ /// </summary>
+ [RequireComponent(typeof(PhotonView))]
+ public class CullingHandler : MonoBehaviour, IPunObservable
+ {
+ #region VARIABLES
+
+ private int orderIndex;
+
+ private CullArea cullArea;
+
+ private List<byte> previousActiveCells, activeCells;
+
+ private PhotonView pView;
+
+ private Vector3 lastPosition, currentPosition;
+
+
+ // used to limit the number of UpdateInterestGroups calls per second (there is no use to change groups more than a few times per second, even if the Culling algorithm makes it look like that)
+ private float timeSinceUpdate;
+ // see timeSinceUpdate
+ private float timeBetweenUpdatesMin = 0.33f;
+
+
+ #endregion
+
+ #region UNITY_FUNCTIONS
+
+ /// <summary>
+ /// Gets references to the PhotonView component and the cull area game object.
+ /// </summary>
+ private void OnEnable()
+ {
+ if (this.pView == null)
+ {
+ this.pView = GetComponent<PhotonView>();
+
+ if (!this.pView.IsMine)
+ {
+ return;
+ }
+ }
+
+ if (this.cullArea == null)
+ {
+ this.cullArea = FindObjectOfType<CullArea>();
+ }
+
+ this.previousActiveCells = new List<byte>(0);
+ this.activeCells = new List<byte>(0);
+
+ this.currentPosition = this.lastPosition = transform.position;
+ }
+
+ /// <summary>
+ /// Initializes the right interest group or prepares the permanent change of the interest Group of the PhotonView component.
+ /// </summary>
+ private void Start()
+ {
+ if (!this.pView.IsMine)
+ {
+ return;
+ }
+
+ if (PhotonNetwork.InRoom)
+ {
+ if (this.cullArea.NumberOfSubdivisions == 0)
+ {
+ this.pView.Group = this.cullArea.FIRST_GROUP_ID;
+
+ PhotonNetwork.SetInterestGroups(this.cullArea.FIRST_GROUP_ID, true);
+ }
+ else
+ {
+ // This is used to continuously update the active group.
+ this.pView.ObservedComponents.Add(this);
+ }
+ }
+ }
+
+
+
+ /// <summary>
+ /// Checks if the player has moved previously and updates the interest groups if necessary.
+ /// </summary>
+ private void Update()
+ {
+ if (!this.pView.IsMine)
+ {
+ return;
+ }
+
+ // we'll limit how often this update may run at all (to avoid too frequent changes and flooding the server with SetInterestGroups calls)
+ this.timeSinceUpdate += Time.deltaTime;
+ if (this.timeSinceUpdate < this.timeBetweenUpdatesMin)
+ {
+ return;
+ }
+
+ this.lastPosition = this.currentPosition;
+ this.currentPosition = transform.position;
+
+ // This is a simple position comparison of the current and the previous position.
+ // When using Network Culling in a bigger project keep in mind that there might
+ // be more transform-related options, e.g. the rotation, or other options to check.
+ if (this.currentPosition != this.lastPosition)
+ {
+ if (this.HaveActiveCellsChanged())
+ {
+ this.UpdateInterestGroups();
+ this.timeSinceUpdate = 0;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Drawing informations.
+ /// </summary>
+ private void OnGUI()
+ {
+ if (!this.pView.IsMine)
+ {
+ return;
+ }
+
+ string subscribedAndActiveCells = "Inside cells:\n";
+ string subscribedCells = "Subscribed cells:\n";
+
+ for (int index = 0; index < this.activeCells.Count; ++index)
+ {
+ if (index <= this.cullArea.NumberOfSubdivisions)
+ {
+ subscribedAndActiveCells += this.activeCells[index] + " | ";
+ }
+
+ subscribedCells += this.activeCells[index] + " | ";
+ }
+ GUI.Label(new Rect(20.0f, Screen.height - 120.0f, 200.0f, 40.0f), "<color=white>PhotonView Group: " + this.pView.Group + "</color>", new GUIStyle() { alignment = TextAnchor.UpperLeft, fontSize = 16 });
+ GUI.Label(new Rect(20.0f, Screen.height - 100.0f, 200.0f, 40.0f), "<color=white>" + subscribedAndActiveCells + "</color>", new GUIStyle() { alignment = TextAnchor.UpperLeft, fontSize = 16 });
+ GUI.Label(new Rect(20.0f, Screen.height - 60.0f, 200.0f, 40.0f), "<color=white>" + subscribedCells + "</color>", new GUIStyle() { alignment = TextAnchor.UpperLeft, fontSize = 16 });
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Checks if the previously active cells have changed.
+ /// </summary>
+ /// <returns>True if the previously active cells have changed and false otherwise.</returns>
+ private bool HaveActiveCellsChanged()
+ {
+ if (this.cullArea.NumberOfSubdivisions == 0)
+ {
+ return false;
+ }
+
+ this.previousActiveCells = new List<byte>(this.activeCells);
+ this.activeCells = this.cullArea.GetActiveCells(transform.position);
+
+ // If the player leaves the area we insert the whole area itself as an active cell.
+ // This can be removed if it is sure that the player is not able to leave the area.
+ while (this.activeCells.Count <= this.cullArea.NumberOfSubdivisions)
+ {
+ this.activeCells.Add(this.cullArea.FIRST_GROUP_ID);
+ }
+
+ if (this.activeCells.Count != this.previousActiveCells.Count)
+ {
+ return true;
+ }
+
+ if (this.activeCells[this.cullArea.NumberOfSubdivisions] != this.previousActiveCells[this.cullArea.NumberOfSubdivisions])
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ /// <summary>
+ /// Unsubscribes from old and subscribes to new interest groups.
+ /// </summary>
+ private void UpdateInterestGroups()
+ {
+ List<byte> disable = new List<byte>(0);
+
+ foreach (byte groupId in this.previousActiveCells)
+ {
+ if (!this.activeCells.Contains(groupId))
+ {
+ disable.Add(groupId);
+ }
+ }
+
+ PhotonNetwork.SetInterestGroups(disable.ToArray(), this.activeCells.ToArray());
+ }
+
+ #region IPunObservable implementation
+
+ /// <summary>
+ /// This time OnPhotonSerializeView is not used to send or receive any kind of data.
+ /// It is used to change the currently active group of the PhotonView component, making it work together with PUN more directly.
+ /// Keep in mind that this function is only executed, when there is at least one more player in the room.
+ /// </summary>
+ public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
+ {
+ // If the player leaves the area we insert the whole area itself as an active cell.
+ // This can be removed if it is sure that the player is not able to leave the area.
+ while (this.activeCells.Count <= this.cullArea.NumberOfSubdivisions)
+ {
+ this.activeCells.Add(this.cullArea.FIRST_GROUP_ID);
+ }
+
+ if (this.cullArea.NumberOfSubdivisions == 1)
+ {
+ this.orderIndex = (++this.orderIndex % this.cullArea.SUBDIVISION_FIRST_LEVEL_ORDER.Length);
+ this.pView.Group = this.activeCells[this.cullArea.SUBDIVISION_FIRST_LEVEL_ORDER[this.orderIndex]];
+ }
+ else if (this.cullArea.NumberOfSubdivisions == 2)
+ {
+ this.orderIndex = (++this.orderIndex % this.cullArea.SUBDIVISION_SECOND_LEVEL_ORDER.Length);
+ this.pView.Group = this.activeCells[this.cullArea.SUBDIVISION_SECOND_LEVEL_ORDER[this.orderIndex]];
+ }
+ else if (this.cullArea.NumberOfSubdivisions == 3)
+ {
+ this.orderIndex = (++this.orderIndex % this.cullArea.SUBDIVISION_THIRD_LEVEL_ORDER.Length);
+ this.pView.Group = this.activeCells[this.cullArea.SUBDIVISION_THIRD_LEVEL_ORDER[this.orderIndex]];
+ }
+ }
+
+ #endregion
+ }
+} \ No newline at end of file
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling/CullingHandler.cs.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling/CullingHandler.cs.meta
new file mode 100644
index 0000000..74b7441
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling/CullingHandler.cs.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 84db789113d4b01418c1becb128c4561
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling/Editor.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling/Editor.meta
new file mode 100644
index 0000000..305366f
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling/Editor.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: fcede10f4c76b443483f21320fee20e5
+folderAsset: yes
+timeCreated: 1529329408
+licenseType: Store
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling/Editor/CullAreaEditor.cs b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling/Editor/CullAreaEditor.cs
new file mode 100644
index 0000000..b306eeb
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling/Editor/CullAreaEditor.cs
@@ -0,0 +1,265 @@
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="CullAreaEditor.cs" company="Exit Games GmbH">
+// Part of: Photon Unity Utilities,
+// </copyright>
+// <summary>
+// Custom inspector for CullArea
+// </summary>
+// <author>developer@exitgames.com</author>
+// --------------------------------------------------------------------------------------------------------------------
+
+using UnityEditor;
+using UnityEngine;
+
+namespace Photon.Pun.UtilityScripts
+{
+ [CanEditMultipleObjects]
+ [CustomEditor(typeof(CullArea))]
+ public class CullAreaEditor : Editor
+ {
+ private bool alignEditorCamera, showHelpEntries;
+
+ private CullArea cullArea;
+
+ private enum UP_AXIS_OPTIONS
+ {
+ SideScrollerMode = 0,
+ TopDownOr3DMode = 1
+ }
+
+ private UP_AXIS_OPTIONS upAxisOptions;
+
+ public void OnEnable()
+ {
+ cullArea = (CullArea)target;
+
+ // Destroying the newly created cull area if there is already one existing
+ if (FindObjectsOfType<CullArea>().Length > 1)
+ {
+ Debug.LogWarning("Destroying newly created cull area because there is already one existing in the scene.");
+
+ DestroyImmediate(cullArea);
+
+ return;
+ }
+
+ // Prevents the dropdown from resetting
+ if (cullArea != null)
+ {
+ upAxisOptions = cullArea.YIsUpAxis ? UP_AXIS_OPTIONS.SideScrollerMode : UP_AXIS_OPTIONS.TopDownOr3DMode;
+ }
+ }
+
+ public override void OnInspectorGUI()
+ {
+ EditorGUILayout.BeginVertical();
+
+ if (Application.isEditor && !Application.isPlaying)
+ {
+ OnInspectorGUIEditMode();
+ }
+ else
+ {
+ OnInspectorGUIPlayMode();
+ }
+
+ EditorGUILayout.EndVertical();
+ }
+
+ /// <summary>
+ /// Represents the inspector GUI when edit mode is active.
+ /// </summary>
+ private void OnInspectorGUIEditMode()
+ {
+ EditorGUI.BeginChangeCheck();
+
+ #region DEFINE_UP_AXIS
+
+ {
+ EditorGUILayout.BeginVertical();
+ EditorGUILayout.LabelField("Select game type", EditorStyles.boldLabel);
+ upAxisOptions = (UP_AXIS_OPTIONS)EditorGUILayout.EnumPopup("Game type", upAxisOptions);
+ cullArea.YIsUpAxis = (upAxisOptions == UP_AXIS_OPTIONS.SideScrollerMode);
+ EditorGUILayout.EndVertical();
+ }
+
+ #endregion
+
+ EditorGUILayout.Space();
+
+ #region SUBDIVISION
+
+ {
+ EditorGUILayout.BeginVertical();
+ EditorGUILayout.LabelField("Set the number of subdivisions", EditorStyles.boldLabel);
+ cullArea.NumberOfSubdivisions = EditorGUILayout.IntSlider("Number of subdivisions", cullArea.NumberOfSubdivisions, 0, CullArea.MAX_NUMBER_OF_SUBDIVISIONS);
+ EditorGUILayout.EndVertical();
+
+ EditorGUILayout.Space();
+
+ if (cullArea.NumberOfSubdivisions != 0)
+ {
+ for (int index = 0; index < cullArea.Subdivisions.Length; ++index)
+ {
+ if ((index + 1) <= cullArea.NumberOfSubdivisions)
+ {
+ string countMessage = (index + 1) + ". Subdivision: row / column count";
+
+ EditorGUILayout.BeginVertical();
+ cullArea.Subdivisions[index] = EditorGUILayout.Vector2Field(countMessage, cullArea.Subdivisions[index]);
+ EditorGUILayout.EndVertical();
+
+ EditorGUILayout.Space();
+ }
+ else
+ {
+ cullArea.Subdivisions[index] = new UnityEngine.Vector2(1, 1);
+ }
+ }
+ }
+ }
+
+ #endregion
+
+ EditorGUILayout.Space();
+
+ #region UPDATING_MAIN_CAMERA
+
+ {
+ EditorGUILayout.BeginVertical();
+
+ EditorGUILayout.LabelField("View and camera options", EditorStyles.boldLabel);
+ alignEditorCamera = EditorGUILayout.Toggle("Automatically align editor view with grid", alignEditorCamera);
+
+ if (Camera.main != null)
+ {
+ if (GUILayout.Button("Align main camera with grid"))
+ {
+ Undo.RecordObject(Camera.main.transform, "Align main camera with grid.");
+
+ float yCoord = cullArea.YIsUpAxis ? cullArea.Center.y : Mathf.Max(cullArea.Size.x, cullArea.Size.y);
+ float zCoord = cullArea.YIsUpAxis ? -Mathf.Max(cullArea.Size.x, cullArea.Size.y) : cullArea.Center.y;
+
+ Camera.main.transform.position = new Vector3(cullArea.Center.x, yCoord, zCoord);
+ Camera.main.transform.LookAt(cullArea.transform.position);
+ }
+
+ EditorGUILayout.LabelField("Current main camera position is " + Camera.main.transform.position.ToString());
+ }
+
+ EditorGUILayout.EndVertical();
+ }
+
+ #endregion
+
+ if (EditorGUI.EndChangeCheck())
+ {
+ cullArea.RecreateCellHierarchy = true;
+
+ AlignEditorView();
+ }
+
+ EditorGUILayout.Space();
+ EditorGUILayout.Space();
+ EditorGUILayout.Space();
+
+ showHelpEntries = EditorGUILayout.Foldout(showHelpEntries, "Need help with this component?");
+ if (showHelpEntries)
+ {
+ EditorGUILayout.HelpBox("To find help you can either follow the tutorial or have a look at the forums by clicking on the buttons below.", MessageType.Info);
+ EditorGUILayout.BeginHorizontal();
+ if (GUILayout.Button("Open the tutorial"))
+ {
+ Application.OpenURL("https://doc.photonengine.com/en-us/pun/v2/demos-and-tutorials/package-demos/culling-demo");
+ }
+ if (GUILayout.Button("Take me to the forums"))
+ {
+ Application.OpenURL("https://forum.photonengine.com/categories/unity-networking-plugin-pun");
+ }
+ EditorGUILayout.EndHorizontal();
+ }
+ }
+
+ /// <summary>
+ /// Represents the inspector GUI when play mode is active.
+ /// </summary>
+ private void OnInspectorGUIPlayMode()
+ {
+ EditorGUILayout.LabelField("No changes allowed when game is running. Please exit play mode first.", EditorStyles.boldLabel);
+ }
+
+ public void OnSceneGUI()
+ {
+ Handles.BeginGUI();
+ GUILayout.BeginArea(new Rect(Screen.width - 110, Screen.height - 90, 100, 60));
+
+ if (GUILayout.Button("Reset position"))
+ {
+ cullArea.transform.position = Vector3.zero;
+ }
+
+ if (GUILayout.Button("Reset scaling"))
+ {
+ cullArea.transform.localScale = new Vector3(25.0f, 25.0f, 25.0f);
+ }
+
+ GUILayout.EndArea();
+ Handles.EndGUI();
+
+ // Checking for changes of the transform
+ if (cullArea.transform.hasChanged)
+ {
+ // Resetting position
+ float posX = cullArea.transform.position.x;
+ float posY = cullArea.YIsUpAxis ? cullArea.transform.position.y : 0.0f;
+ float posZ = !cullArea.YIsUpAxis ? cullArea.transform.position.z : 0.0f;
+
+ cullArea.transform.position = new Vector3(posX, posY, posZ);
+
+ // Resetting scaling
+ if (cullArea.Size.x < 1.0f || cullArea.Size.y < 1.0f)
+ {
+ float scaleX = (cullArea.transform.localScale.x < 1.0f) ? 1.0f : cullArea.transform.localScale.x;
+ float scaleY = (cullArea.transform.localScale.y < 1.0f) ? 1.0f : cullArea.transform.localScale.y;
+ float scaleZ = (cullArea.transform.localScale.z < 1.0f) ? 1.0f : cullArea.transform.localScale.z;
+
+ cullArea.transform.localScale = new Vector3(scaleX, scaleY, scaleZ);
+
+ Debug.LogWarning("Scaling on a single axis can not be lower than 1. Resetting...");
+ }
+
+ cullArea.RecreateCellHierarchy = true;
+
+ AlignEditorView();
+ }
+ }
+
+ /// <summary>
+ /// Aligns the editor view with the created grid.
+ /// </summary>
+ private void AlignEditorView()
+ {
+ if (!alignEditorCamera)
+ {
+ return;
+ }
+
+ // This creates a temporary game object in order to align the editor view.
+ // The created game object is destroyed afterwards.
+ GameObject tmpGo = new GameObject();
+
+ float yCoord = cullArea.YIsUpAxis ? cullArea.Center.y : Mathf.Max(cullArea.Size.x, cullArea.Size.y);
+ float zCoord = cullArea.YIsUpAxis ? -Mathf.Max(cullArea.Size.x, cullArea.Size.y) : cullArea.Center.y;
+
+ tmpGo.transform.position = new Vector3(cullArea.Center.x, yCoord, zCoord);
+ tmpGo.transform.LookAt(cullArea.transform.position);
+
+ if (SceneView.lastActiveSceneView != null)
+ {
+ SceneView.lastActiveSceneView.AlignViewToObject(tmpGo.transform);
+ }
+
+ DestroyImmediate(tmpGo);
+ }
+ }
+} \ No newline at end of file
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling/Editor/CullAreaEditor.cs.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling/Editor/CullAreaEditor.cs.meta
new file mode 100644
index 0000000..7d72143
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling/Editor/CullAreaEditor.cs.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: abadaa451a7bff0489078ed9eec61133
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling/Editor/PhotonUnityNetworking.Utilities.Culling.Editor.asmdef b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling/Editor/PhotonUnityNetworking.Utilities.Culling.Editor.asmdef
new file mode 100644
index 0000000..2be9de1
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling/Editor/PhotonUnityNetworking.Utilities.Culling.Editor.asmdef
@@ -0,0 +1,12 @@
+{
+ "name": "PhotonUnityNetworking.Utilities.Culling.Editor",
+ "references": [
+ "PhotonUnityNetworking.Utilities"
+ ],
+ "optionalUnityReferences": [],
+ "includePlatforms": [
+ "Editor"
+ ],
+ "excludePlatforms": [],
+ "allowUnsafeCode": false
+} \ No newline at end of file
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling/Editor/PhotonUnityNetworking.Utilities.Culling.Editor.asmdef.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling/Editor/PhotonUnityNetworking.Utilities.Culling.Editor.asmdef.meta
new file mode 100644
index 0000000..b43d734
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Culling/Editor/PhotonUnityNetworking.Utilities.Culling.Editor.asmdef.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 06dafbbe6b7b3a84f84213f47aabe7f0
+timeCreated: 1537459565
+licenseType: Store
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Debugging.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Debugging.meta
new file mode 100644
index 0000000..ec00ddc
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Debugging.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 72b80dd954bc647c4a2a924b87762f92
+folderAsset: yes
+timeCreated: 1529327208
+licenseType: Store
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Debugging/PhotonLagSimulationGui.cs b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Debugging/PhotonLagSimulationGui.cs
new file mode 100644
index 0000000..52c29c6
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Debugging/PhotonLagSimulationGui.cs
@@ -0,0 +1,109 @@
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="PhotonLagSimulationGui.cs" company="Exit Games GmbH">
+// Part of: Photon Unity Utilities,
+// </copyright>
+// <summary>
+// This MonoBehaviour is a basic GUI for the Photon client's network-simulation feature.
+// It can modify lag (fixed delay), jitter (random lag) and packet loss.
+// Part of the [Optional GUI](@ref optionalGui).
+// </summary>
+// <author>developer@exitgames.com</author>
+// --------------------------------------------------------------------------------------------------------------------
+
+
+using UnityEngine;
+
+using Photon.Pun;
+using Photon.Realtime;
+using ExitGames.Client.Photon;
+
+namespace Photon.Pun.UtilityScripts
+{
+ /// <summary>
+ /// This MonoBehaviour is a basic GUI for the Photon client's network-simulation feature.
+ /// It can modify lag (fixed delay), jitter (random lag) and packet loss.
+ /// </summary>
+ /// \ingroup optionalGui
+ public class PhotonLagSimulationGui : MonoBehaviour
+ {
+ /// <summary>Positioning rect for window.</summary>
+ public Rect WindowRect = new Rect(0, 100, 120, 100);
+
+ /// <summary>Unity GUI Window ID (must be unique or will cause issues).</summary>
+ public int WindowId = 101;
+
+ /// <summary>Shows or hides GUI (does not affect settings).</summary>
+ public bool Visible = true;
+
+ /// <summary>The peer currently in use (to set the network simulation).</summary>
+ public PhotonPeer Peer { get; set; }
+
+ public void Start()
+ {
+ this.Peer = PhotonNetwork.NetworkingClient.LoadBalancingPeer;
+ }
+
+ public void OnGUI()
+ {
+ if (!this.Visible)
+ {
+ return;
+ }
+
+ if (this.Peer == null)
+ {
+ this.WindowRect = GUILayout.Window(this.WindowId, this.WindowRect, this.NetSimHasNoPeerWindow, "Netw. Sim.");
+ }
+ else
+ {
+ this.WindowRect = GUILayout.Window(this.WindowId, this.WindowRect, this.NetSimWindow, "Netw. Sim.");
+ }
+ }
+
+ private void NetSimHasNoPeerWindow(int windowId)
+ {
+ GUILayout.Label("No peer to communicate with. ");
+ }
+
+ private void NetSimWindow(int windowId)
+ {
+ GUILayout.Label(string.Format("Rtt:{0,4} +/-{1,3}", this.Peer.RoundTripTime, this.Peer.RoundTripTimeVariance));
+
+ bool simEnabled = this.Peer.IsSimulationEnabled;
+ bool newSimEnabled = GUILayout.Toggle(simEnabled, "Simulate");
+ if (newSimEnabled != simEnabled)
+ {
+ this.Peer.IsSimulationEnabled = newSimEnabled;
+ }
+
+ float inOutLag = this.Peer.NetworkSimulationSettings.IncomingLag;
+ GUILayout.Label("Lag " + inOutLag);
+ inOutLag = GUILayout.HorizontalSlider(inOutLag, 0, 500);
+
+ this.Peer.NetworkSimulationSettings.IncomingLag = (int)inOutLag;
+ this.Peer.NetworkSimulationSettings.OutgoingLag = (int)inOutLag;
+
+ float inOutJitter = this.Peer.NetworkSimulationSettings.IncomingJitter;
+ GUILayout.Label("Jit " + inOutJitter);
+ inOutJitter = GUILayout.HorizontalSlider(inOutJitter, 0, 100);
+
+ this.Peer.NetworkSimulationSettings.IncomingJitter = (int)inOutJitter;
+ this.Peer.NetworkSimulationSettings.OutgoingJitter = (int)inOutJitter;
+
+ float loss = this.Peer.NetworkSimulationSettings.IncomingLossPercentage;
+ GUILayout.Label("Loss " + loss);
+ loss = GUILayout.HorizontalSlider(loss, 0, 10);
+
+ this.Peer.NetworkSimulationSettings.IncomingLossPercentage = (int)loss;
+ this.Peer.NetworkSimulationSettings.OutgoingLossPercentage = (int)loss;
+
+ // if anything was clicked, the height of this window is likely changed. reduce it to be layouted again next frame
+ if (GUI.changed)
+ {
+ this.WindowRect.height = 100;
+ }
+
+ GUI.DragWindow();
+ }
+ }
+} \ No newline at end of file
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Debugging/PhotonLagSimulationGui.cs.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Debugging/PhotonLagSimulationGui.cs.meta
new file mode 100644
index 0000000..5a7173b
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Debugging/PhotonLagSimulationGui.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 5867a53c8db0e6745818285bb6b6e1b9
+labels:
+- ExitGames
+- PUN
+- Photon
+- Networking
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Debugging/PhotonStatsGui.cs b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Debugging/PhotonStatsGui.cs
new file mode 100644
index 0000000..c4c7c15
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Debugging/PhotonStatsGui.cs
@@ -0,0 +1,170 @@
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="PhotonStatsGui.cs" company="Exit Games GmbH">
+// Part of: Photon Unity Utilities,
+// </copyright>
+// <summary>
+// Basic GUI to show traffic and health statistics of the connection to Photon,
+// toggled by shift+tab.
+// Part of the [Optional GUI](@ref optionalGui).
+// </summary>
+// <author>developer@exitgames.com</author>
+// --------------------------------------------------------------------------------------------------------------------
+
+using UnityEngine;
+
+using Photon.Pun;
+using Photon.Realtime;
+using ExitGames.Client.Photon;
+
+namespace Photon.Pun.UtilityScripts
+{
+ /// <summary>
+ /// Basic GUI to show traffic and health statistics of the connection to Photon,
+ /// toggled by shift+tab.
+ /// </summary>
+ /// <remarks>
+ /// The shown health values can help identify problems with connection losses or performance.
+ /// Example:
+ /// If the time delta between two consecutive SendOutgoingCommands calls is a second or more,
+ /// chances rise for a disconnect being caused by this (because acknowledgements to the server
+ /// need to be sent in due time).
+ /// </remarks>
+ /// \ingroup optionalGui
+ public class PhotonStatsGui : MonoBehaviour
+ {
+ /// <summary>Shows or hides GUI (does not affect if stats are collected).</summary>
+ public bool statsWindowOn = true;
+
+ /// <summary>Option to turn collecting stats on or off (used in Update()).</summary>
+ public bool statsOn = true;
+
+ /// <summary>Shows additional "health" values of connection.</summary>
+ public bool healthStatsVisible;
+
+ /// <summary>Shows additional "lower level" traffic stats.</summary>
+ public bool trafficStatsOn;
+
+ /// <summary>Show buttons to control stats and reset them.</summary>
+ public bool buttonsOn;
+
+ /// <summary>Positioning rect for window.</summary>
+ public Rect statsRect = new Rect(0, 100, 200, 50);
+
+ /// <summary>Unity GUI Window ID (must be unique or will cause issues).</summary>
+ public int WindowId = 100;
+
+
+ public void Start()
+ {
+ if (this.statsRect.x <= 0)
+ {
+ this.statsRect.x = Screen.width - this.statsRect.width;
+ }
+ }
+
+ /// <summary>Checks for shift+tab input combination (to toggle statsOn).</summary>
+ public void Update()
+ {
+ if (Input.GetKeyDown(KeyCode.Tab) && Input.GetKey(KeyCode.LeftShift))
+ {
+ this.statsWindowOn = !this.statsWindowOn;
+ this.statsOn = true; // enable stats when showing the window
+ }
+ }
+
+ public void OnGUI()
+ {
+ if (PhotonNetwork.NetworkingClient.LoadBalancingPeer.TrafficStatsEnabled != statsOn)
+ {
+ PhotonNetwork.NetworkingClient.LoadBalancingPeer.TrafficStatsEnabled = this.statsOn;
+ }
+
+ if (!this.statsWindowOn)
+ {
+ return;
+ }
+
+ this.statsRect = GUILayout.Window(this.WindowId, this.statsRect, this.TrafficStatsWindow, "Messages (shift+tab)");
+ }
+
+ public void TrafficStatsWindow(int windowID)
+ {
+ bool statsToLog = false;
+ TrafficStatsGameLevel gls = PhotonNetwork.NetworkingClient.LoadBalancingPeer.TrafficStatsGameLevel;
+ long elapsedMs = PhotonNetwork.NetworkingClient.LoadBalancingPeer.TrafficStatsElapsedMs / 1000;
+ if (elapsedMs == 0)
+ {
+ elapsedMs = 1;
+ }
+
+ GUILayout.BeginHorizontal();
+ this.buttonsOn = GUILayout.Toggle(this.buttonsOn, "buttons");
+ this.healthStatsVisible = GUILayout.Toggle(this.healthStatsVisible, "health");
+ this.trafficStatsOn = GUILayout.Toggle(this.trafficStatsOn, "traffic");
+ GUILayout.EndHorizontal();
+
+ string total = string.Format("Out {0,4} | In {1,4} | Sum {2,4}", gls.TotalOutgoingMessageCount, gls.TotalIncomingMessageCount, gls.TotalMessageCount);
+ string elapsedTime = string.Format("{0}sec average:", elapsedMs);
+ string average = string.Format("Out {0,4} | In {1,4} | Sum {2,4}", gls.TotalOutgoingMessageCount / elapsedMs, gls.TotalIncomingMessageCount / elapsedMs, gls.TotalMessageCount / elapsedMs);
+ GUILayout.Label(total);
+ GUILayout.Label(elapsedTime);
+ GUILayout.Label(average);
+
+ if (this.buttonsOn)
+ {
+ GUILayout.BeginHorizontal();
+ this.statsOn = GUILayout.Toggle(this.statsOn, "stats on");
+ if (GUILayout.Button("Reset"))
+ {
+ PhotonNetwork.NetworkingClient.LoadBalancingPeer.TrafficStatsReset();
+ PhotonNetwork.NetworkingClient.LoadBalancingPeer.TrafficStatsEnabled = true;
+ }
+ statsToLog = GUILayout.Button("To Log");
+ GUILayout.EndHorizontal();
+ }
+
+ string trafficStatsIn = string.Empty;
+ string trafficStatsOut = string.Empty;
+ if (this.trafficStatsOn)
+ {
+ GUILayout.Box("Traffic Stats");
+ trafficStatsIn = "Incoming: \n" + PhotonNetwork.NetworkingClient.LoadBalancingPeer.TrafficStatsIncoming.ToString();
+ trafficStatsOut = "Outgoing: \n" + PhotonNetwork.NetworkingClient.LoadBalancingPeer.TrafficStatsOutgoing.ToString();
+ GUILayout.Label(trafficStatsIn);
+ GUILayout.Label(trafficStatsOut);
+ }
+
+ string healthStats = string.Empty;
+ if (this.healthStatsVisible)
+ {
+ GUILayout.Box("Health Stats");
+ healthStats = string.Format(
+ "ping: {6}[+/-{7}]ms resent:{8} \n\nmax ms between\nsend: {0,4} \ndispatch: {1,4} \n\nlongest dispatch for: \nev({3}):{2,3}ms \nop({5}):{4,3}ms",
+ gls.LongestDeltaBetweenSending,
+ gls.LongestDeltaBetweenDispatching,
+ gls.LongestEventCallback,
+ gls.LongestEventCallbackCode,
+ gls.LongestOpResponseCallback,
+ gls.LongestOpResponseCallbackOpCode,
+ PhotonNetwork.NetworkingClient.LoadBalancingPeer.RoundTripTime,
+ PhotonNetwork.NetworkingClient.LoadBalancingPeer.RoundTripTimeVariance,
+ PhotonNetwork.NetworkingClient.LoadBalancingPeer.ResentReliableCommands);
+ GUILayout.Label(healthStats);
+ }
+
+ if (statsToLog)
+ {
+ string complete = string.Format("{0}\n{1}\n{2}\n{3}\n{4}\n{5}", total, elapsedTime, average, trafficStatsIn, trafficStatsOut, healthStats);
+ Debug.Log(complete);
+ }
+
+ // if anything was clicked, the height of this window is likely changed. reduce it to be layouted again next frame
+ if (GUI.changed)
+ {
+ this.statsRect.height = 100;
+ }
+
+ GUI.DragWindow();
+ }
+ }
+} \ No newline at end of file
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Debugging/PhotonStatsGui.cs.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Debugging/PhotonStatsGui.cs.meta
new file mode 100644
index 0000000..dc1049b
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Debugging/PhotonStatsGui.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: d06466c03d263624786afa88b52928b6
+labels:
+- ExitGames
+- PUN
+- Photon
+- Networking
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Debugging/PointedAtGameObjectInfo.cs b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Debugging/PointedAtGameObjectInfo.cs
new file mode 100644
index 0000000..239111c
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Debugging/PointedAtGameObjectInfo.cs
@@ -0,0 +1,84 @@
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="PointedAtGameObjectInfo.cs" company="Exit Games GmbH">
+// </copyright>
+// <summary>
+// Display ViewId, OwnerActorNr, IsCeneView and IsMine when clicked using the old UI system
+// </summary>
+// <author>developer@exitgames.com</author>
+// --------------------------------------------------------------------------------------------------------------------
+
+using System;
+
+using UnityEngine;
+using UnityEngine.UI;
+using UnityEngine.EventSystems;
+
+using Photon.Pun;
+using Photon.Realtime;
+
+namespace Photon.Pun.UtilityScripts
+{
+ /// <summary>
+ /// Display ViewId, OwnerActorNr, IsCeneView and IsMine when clicked.
+ /// </summary>
+ public class PointedAtGameObjectInfo : MonoBehaviour
+ {
+ public static PointedAtGameObjectInfo Instance;
+
+ public Text text;
+
+ Transform focus;
+
+ void Start()
+ {
+ if (Instance != null)
+ {
+ Debug.LogWarning("PointedAtGameObjectInfo is already featured in the scene, gameobject is destroyed");
+ Destroy(this.gameObject);
+ }
+
+ Instance = this;
+ }
+
+ public void SetFocus(PhotonView pv)
+ {
+
+ focus = pv != null ? pv.transform : null;
+
+ if (pv != null)
+ {
+ text.text = string.Format("id {0} own: {1} {2}{3}", pv.ViewID, pv.OwnerActorNr, (pv.IsRoomView) ? "scn" : "", (pv.IsMine) ? " mine" : "");
+ //GUI.Label (new Rect (Input.mousePosition.x + 5, Screen.height - Input.mousePosition.y - 15, 300, 30), );
+ }
+ else
+ {
+ text.text = string.Empty;
+
+ }
+ }
+
+ public void RemoveFocus(PhotonView pv)
+ {
+ if (pv == null)
+ {
+ text.text = string.Empty;
+ return;
+ }
+
+ if (pv.transform == focus)
+ {
+ text.text = string.Empty;
+ return;
+ }
+
+ }
+
+ void LateUpdate()
+ {
+ if (focus != null)
+ {
+ this.transform.position = Camera.main.WorldToScreenPoint(focus.position);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Debugging/PointedAtGameObjectInfo.cs.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Debugging/PointedAtGameObjectInfo.cs.meta
new file mode 100644
index 0000000..9ffbb4f
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Debugging/PointedAtGameObjectInfo.cs.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: e6262dd9a9b078c4e8cbd47495aa6d23
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Debugging/StatesGui.cs b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Debugging/StatesGui.cs
new file mode 100644
index 0000000..7d09c0a
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Debugging/StatesGui.cs
@@ -0,0 +1,212 @@
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="TabViewManager.cs" company="Exit Games GmbH">
+// </copyright>
+// <summary>
+// Output detailed information about Pun Current states, using the old Unity UI framework.
+// </summary>
+// <author>developer@exitgames.com</author>
+// --------------------------------------------------------------------------------------------------------------------
+
+using UnityEngine;
+using Photon.Realtime;
+
+namespace Photon.Pun.UtilityScripts
+{
+ /// <summary>
+ /// Output detailed information about Pun Current states, using the old Unity UI framework.
+ /// </summary>
+ public class StatesGui : MonoBehaviour
+ {
+ public Rect GuiOffset = new Rect(250, 0, 300, 300);
+ public bool DontDestroy = true;
+ public bool ServerTimestamp;
+ public bool DetailedConnection;
+ public bool Server;
+ public bool AppVersion;
+ public bool UserId;
+ public bool Room;
+ public bool RoomProps;
+ public bool EventsIn;
+ public bool LocalPlayer;
+ public bool PlayerProps;
+ public bool Others;
+ public bool Buttons;
+ public bool ExpectedUsers;
+
+ private Rect GuiRect = new Rect();
+ private static StatesGui Instance;
+
+ void Awake()
+ {
+ if (Instance != null)
+ {
+ DestroyImmediate(this.gameObject);
+ return;
+ }
+ if (DontDestroy)
+ {
+ Instance = this;
+ DontDestroyOnLoad(this.gameObject);
+ }
+
+ if (EventsIn)
+ {
+ PhotonNetwork.NetworkingClient.LoadBalancingPeer.TrafficStatsEnabled = true;
+ }
+ }
+
+ void OnDisable()
+ {
+ if (DontDestroy && Instance == this)
+ {
+ Instance = null;
+ }
+
+ }
+
+ float native_width = 800;
+ float native_height = 480;
+ void OnGUI()
+ {
+ if (PhotonNetwork.NetworkingClient == null || PhotonNetwork.NetworkingClient.LoadBalancingPeer == null || PhotonNetwork.NetworkingClient.LoadBalancingPeer.TrafficStatsIncoming == null)
+ {
+ return;
+ }
+
+ //set up scaling
+ float rx = Screen.width / native_width;
+ float ry = Screen.height / native_height;
+ GUI.matrix = Matrix4x4.TRS (new Vector3(0, 0, 0), Quaternion.identity, new Vector3 (rx, ry, 1));
+
+ Rect GuiOffsetRuntime = new Rect(this.GuiOffset);
+
+ if (GuiOffsetRuntime.x < 0)
+ {
+ GuiOffsetRuntime.x = Screen.width - GuiOffsetRuntime.width;
+ }
+ GuiRect.xMin = GuiOffsetRuntime.x;
+ GuiRect.yMin = GuiOffsetRuntime.y;
+ GuiRect.xMax = GuiOffsetRuntime.x + GuiOffsetRuntime.width;
+ GuiRect.yMax = GuiOffsetRuntime.y + GuiOffsetRuntime.height;
+ GUILayout.BeginArea(GuiRect);
+
+ GUILayout.BeginHorizontal();
+ if (this.ServerTimestamp)
+ {
+ GUILayout.Label((((double)PhotonNetwork.ServerTimestamp) / 1000d).ToString("F3"));
+ }
+
+ if (Server)
+ {
+ GUILayout.Label(PhotonNetwork.ServerAddress + " " + PhotonNetwork.Server);
+ }
+ if (DetailedConnection)
+ {
+ GUILayout.Label(PhotonNetwork.NetworkClientState.ToString());
+ }
+ if (AppVersion)
+ {
+ GUILayout.Label(PhotonNetwork.NetworkingClient.AppVersion);
+ }
+ GUILayout.EndHorizontal();
+
+ GUILayout.BeginHorizontal();
+ if (UserId)
+ {
+ GUILayout.Label("UID: " + ((PhotonNetwork.AuthValues != null) ? PhotonNetwork.AuthValues.UserId : "no UserId"));
+ GUILayout.Label("UserId:" + PhotonNetwork.LocalPlayer.UserId);
+ }
+ GUILayout.EndHorizontal();
+
+ if (Room)
+ {
+ if (PhotonNetwork.InRoom)
+ {
+ GUILayout.Label(this.RoomProps ? PhotonNetwork.CurrentRoom.ToStringFull() : PhotonNetwork.CurrentRoom.ToString());
+ }
+ else
+ {
+ GUILayout.Label("not in room");
+ }
+ }
+
+ if (EventsIn)
+ {
+ int fragments = PhotonNetwork.NetworkingClient.LoadBalancingPeer.TrafficStatsIncoming.FragmentCommandCount;
+ GUILayout.Label("Events Received: "+PhotonNetwork.NetworkingClient.LoadBalancingPeer.TrafficStatsGameLevel.EventCount + " Fragments: "+fragments);
+ }
+
+
+ if (this.LocalPlayer)
+ {
+ GUILayout.Label(PlayerToString(PhotonNetwork.LocalPlayer));
+ }
+ if (Others)
+ {
+ foreach (Player player in PhotonNetwork.PlayerListOthers)
+ {
+ GUILayout.Label(PlayerToString(player));
+ }
+ }
+ if (ExpectedUsers)
+ {
+ if (PhotonNetwork.InRoom)
+ {
+ int countExpected = (PhotonNetwork.CurrentRoom.ExpectedUsers != null) ? PhotonNetwork.CurrentRoom.ExpectedUsers.Length : 0;
+
+ GUILayout.Label("Expected: " + countExpected + " " +
+ ((PhotonNetwork.CurrentRoom.ExpectedUsers != null) ? string.Join(",", PhotonNetwork.CurrentRoom.ExpectedUsers) : "")
+ );
+
+ }
+ }
+
+
+ if (Buttons)
+ {
+ if (!PhotonNetwork.IsConnected && GUILayout.Button("Connect"))
+ {
+ PhotonNetwork.ConnectUsingSettings();
+ }
+ GUILayout.BeginHorizontal();
+ if (PhotonNetwork.IsConnected && GUILayout.Button("Disconnect"))
+ {
+ PhotonNetwork.Disconnect();
+ }
+ if (PhotonNetwork.IsConnected && GUILayout.Button("Close Socket"))
+ {
+ PhotonNetwork.NetworkingClient.LoadBalancingPeer.StopThread();
+ }
+ GUILayout.EndHorizontal();
+ if (PhotonNetwork.IsConnected && PhotonNetwork.InRoom && GUILayout.Button("Leave"))
+ {
+ PhotonNetwork.LeaveRoom();
+ }
+ if (PhotonNetwork.IsConnected && PhotonNetwork.InRoom && PhotonNetwork.CurrentRoom.PlayerTtl>0 && GUILayout.Button("Leave(abandon)"))
+ {
+ PhotonNetwork.LeaveRoom(false);
+ }
+ if (PhotonNetwork.IsConnected && !PhotonNetwork.InRoom && GUILayout.Button("Join Random"))
+ {
+ PhotonNetwork.JoinRandomRoom();
+ }
+ if (PhotonNetwork.IsConnected && !PhotonNetwork.InRoom && GUILayout.Button("Create Room"))
+ {
+ PhotonNetwork.CreateRoom(null);
+ }
+ }
+
+ GUILayout.EndArea();
+ }
+
+ private string PlayerToString(Player player)
+ {
+ if (PhotonNetwork.NetworkingClient == null)
+ {
+ Debug.LogError("nwp is null");
+ return "";
+ }
+ return string.Format("#{0:00} '{1}'{5} {4}{2} {3} {6}", player.ActorNumber + "/userId:<" + player.UserId + ">", player.NickName, player.IsMasterClient ? "(master)" : "", this.PlayerProps ? player.CustomProperties.ToStringFull() : "", (PhotonNetwork.LocalPlayer.ActorNumber == player.ActorNumber) ? "(you)" : "", player.UserId, player.IsInactive ? " / Is Inactive" : "");
+ }
+ }
+} \ No newline at end of file
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Debugging/StatesGui.cs.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Debugging/StatesGui.cs.meta
new file mode 100644
index 0000000..303a404
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Debugging/StatesGui.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 62880f27e95abf2418fd79e9d9d568b4
+timeCreated: 1493998271
+licenseType: Store
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer.meta
new file mode 100644
index 0000000..f112b84
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 94d453efd58794348867b36584d05a1e
+folderAsset: yes
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/Editor.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/Editor.meta
new file mode 100644
index 0000000..70d9f8a
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/Editor.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: f1d46a1c486645945a3667d8bbe2d2e7
+folderAsset: yes
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/Editor/PhotonTeamsManagerInspector.cs b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/Editor/PhotonTeamsManagerInspector.cs
new file mode 100644
index 0000000..0b62397
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/Editor/PhotonTeamsManagerInspector.cs
@@ -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();
+ }
+ }
+} \ No newline at end of file
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/Editor/PhotonTeamsManagerInspector.cs.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/Editor/PhotonTeamsManagerInspector.cs.meta
new file mode 100644
index 0000000..4b3d3dd
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/Editor/PhotonTeamsManagerInspector.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8cb74f08e3fc52942a0d8557772bf4dc
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/Editor/PhotonUnityNetworking.Utilities.PhotonPlayer.Editor.asmdef b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/Editor/PhotonUnityNetworking.Utilities.PhotonPlayer.Editor.asmdef
new file mode 100644
index 0000000..6dcc4a0
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/Editor/PhotonUnityNetworking.Utilities.PhotonPlayer.Editor.asmdef
@@ -0,0 +1,15 @@
+{
+ "name": "PhotonUnityNetworking.Utilities.PhotonPlayer.Editor",
+ "references": [
+ "PhotonRealtime",
+ "PhotonUnityNetworking",
+ "PhotonUnityNetworking.Utilities",
+ "PhotonUnityNetworking.Editor"
+ ],
+ "optionalUnityReferences": [],
+ "includePlatforms": [
+ "Editor"
+ ],
+ "excludePlatforms": [],
+ "allowUnsafeCode": false
+} \ No newline at end of file
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/Editor/PhotonUnityNetworking.Utilities.PhotonPlayer.Editor.asmdef.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/Editor/PhotonUnityNetworking.Utilities.PhotonPlayer.Editor.asmdef.meta
new file mode 100644
index 0000000..de22c01
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/Editor/PhotonUnityNetworking.Utilities.PhotonPlayer.Editor.asmdef.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 7024f760fc566cf45a16d2c838e22b2d
+timeCreated: 1537459565
+licenseType: Store
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/Editor/PlayerNumberingInspector.cs b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/Editor/PlayerNumberingInspector.cs
new file mode 100644
index 0000000..f59568e
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/Editor/PlayerNumberingInspector.cs
@@ -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();
+ }
+
+ }
+} \ No newline at end of file
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/Editor/PlayerNumberingInspector.cs.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/Editor/PlayerNumberingInspector.cs.meta
new file mode 100644
index 0000000..4ed2ee0
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/Editor/PlayerNumberingInspector.cs.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: d6590f39353bf4efdb3b14691166135f
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/Editor/PunTeamsInspector.cs b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/Editor/PunTeamsInspector.cs
new file mode 100644
index 0000000..18c48a1
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/Editor/PunTeamsInspector.cs
@@ -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--;
+ }
+
+ }
+ }
+ }
+ }
+}
+
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/Editor/PunTeamsInspector.cs.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/Editor/PunTeamsInspector.cs.meta
new file mode 100644
index 0000000..ff6b7e0
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/Editor/PunTeamsInspector.cs.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 7dcadaf22424c4f5d82f4d48c3b8097f
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/PhotonTeamsManager.cs b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/PhotonTeamsManager.cs
new file mode 100644
index 0000000..792898f
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/PhotonTeamsManager.cs
@@ -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);
+ }
+ }
+} \ No newline at end of file
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/PhotonTeamsManager.cs.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/PhotonTeamsManager.cs.meta
new file mode 100644
index 0000000..640e2d9
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/PhotonTeamsManager.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8701526de72d8774fa165e66daf050ed
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/PlayerNumbering.cs b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/PlayerNumbering.cs
new file mode 100644
index 0000000..d51eccd
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/PlayerNumbering.cs
@@ -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 } });
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/PlayerNumbering.cs.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/PlayerNumbering.cs.meta
new file mode 100644
index 0000000..39220f0
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/PlayerNumbering.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: b28dd60f6abf16d4094cf0f642a043e2
+timeCreated: 1512563044
+licenseType: Store
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/PunPlayerScores.cs b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/PunPlayerScores.cs
new file mode 100644
index 0000000..8054edd
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/PunPlayerScores.cs
@@ -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;
+ }
+ }
+} \ No newline at end of file
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/PunPlayerScores.cs.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/PunPlayerScores.cs.meta
new file mode 100644
index 0000000..5904915
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/PunPlayerScores.cs.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 6b4df3943860f1d45bfe232053a58d80
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/PunTeams.cs b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/PunTeams.cs
new file mode 100644
index 0000000..bc06313
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/PunTeams.cs
@@ -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 } });
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/PunTeams.cs.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/PunTeams.cs.meta
new file mode 100644
index 0000000..9dffb8a
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonPlayer/PunTeams.cs.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 6587c8104d7524f4280d0a68dd779f27
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonUnityNetworking.Utilities.asmdef b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonUnityNetworking.Utilities.asmdef
new file mode 100644
index 0000000..5812232
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonUnityNetworking.Utilities.asmdef
@@ -0,0 +1,11 @@
+{
+ "name": "PhotonUnityNetworking.Utilities",
+ "references": [
+ "PhotonRealtime",
+ "PhotonUnityNetworking"
+ ],
+ "optionalUnityReferences": [],
+ "includePlatforms": [],
+ "excludePlatforms": [],
+ "allowUnsafeCode": false
+} \ No newline at end of file
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonUnityNetworking.Utilities.asmdef.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonUnityNetworking.Utilities.asmdef.meta
new file mode 100644
index 0000000..7e3157c
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonUnityNetworking.Utilities.asmdef.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: a738238285a7a8246af046cbf977522f
+timeCreated: 1537459565
+licenseType: Store
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonView.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonView.meta
new file mode 100644
index 0000000..07d3ae1
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonView.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 199121930ec5d4aa9bb53d836180b74f
+folderAsset: yes
+timeCreated: 1529327582
+licenseType: Store
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonView/SmoothSyncMovement.cs b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonView/SmoothSyncMovement.cs
new file mode 100644
index 0000000..2f3a75b
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonView/SmoothSyncMovement.cs
@@ -0,0 +1,72 @@
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="SmoothSyncMovement.cs" company="Exit Games GmbH">
+// Part of: Photon Unity Utilities,
+// </copyright>
+// <summary>
+// Smoothed out movement for network gameobjects
+// </summary>
+// <author>developer@exitgames.com</author>
+// --------------------------------------------------------------------------------------------------------------------
+
+using UnityEngine;
+
+using Photon.Pun;
+using Photon.Realtime;
+
+namespace Photon.Pun.UtilityScripts
+{
+ /// <summary>
+ /// Smoothed out movement for network gameobjects
+ /// </summary>
+ [RequireComponent(typeof(PhotonView))]
+ public class SmoothSyncMovement : Photon.Pun.MonoBehaviourPun, IPunObservable
+ {
+ public float SmoothingDelay = 5;
+ public void Awake()
+ {
+ bool observed = false;
+ foreach (Component observedComponent in this.photonView.ObservedComponents)
+ {
+ if (observedComponent == this)
+ {
+ observed = true;
+ break;
+ }
+ }
+ if (!observed)
+ {
+ Debug.LogWarning(this + " is not observed by this object's photonView! OnPhotonSerializeView() in this class won't be used.");
+ }
+ }
+
+ public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
+ {
+ if (stream.IsWriting)
+ {
+ //We own this player: send the others our data
+ stream.SendNext(transform.position);
+ stream.SendNext(transform.rotation);
+ }
+ else
+ {
+ //Network player, receive data
+ correctPlayerPos = (Vector3)stream.ReceiveNext();
+ correctPlayerRot = (Quaternion)stream.ReceiveNext();
+ }
+ }
+
+ private Vector3 correctPlayerPos = Vector3.zero; //We lerp towards this
+ private Quaternion correctPlayerRot = Quaternion.identity; //We lerp towards this
+
+ public void Update()
+ {
+ if (!photonView.IsMine)
+ {
+ //Update remote player (smooth this, this looks good, at the cost of some accuracy)
+ transform.position = Vector3.Lerp(transform.position, correctPlayerPos, Time.deltaTime * this.SmoothingDelay);
+ transform.rotation = Quaternion.Lerp(transform.rotation, correctPlayerRot, Time.deltaTime * this.SmoothingDelay);
+ }
+ }
+
+ }
+} \ No newline at end of file
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonView/SmoothSyncMovement.cs.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonView/SmoothSyncMovement.cs.meta
new file mode 100644
index 0000000..ed3764a
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/PhotonView/SmoothSyncMovement.cs.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 35144820bcc25444bb8f0fd767d9423e
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping.meta
new file mode 100644
index 0000000..99561c8
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: e10fe700b1a744ec78575843923fe6d7
+folderAsset: yes
+timeCreated: 1529327245
+licenseType: Store
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/ConnectAndJoinRandom.cs b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/ConnectAndJoinRandom.cs
new file mode 100644
index 0000000..8cfddfe
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/ConnectAndJoinRandom.cs
@@ -0,0 +1,136 @@
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="ConnectAndJoinRandom.cs" company="Exit Games GmbH">
+// Part of: Photon Unity Utilities,
+// </copyright>
+// <summary>
+// Simple component to call ConnectUsingSettings and to get into a PUN room easily.
+// </summary>
+// <remarks>
+// A custom inspector provides a button to connect in PlayMode, should AutoConnect be false.
+// </remarks>
+// <author>developer@exitgames.com</author>
+// --------------------------------------------------------------------------------------------------------------------
+
+//#if UNITY_EDITOR
+//using UnityEditor;
+//#endif
+
+using UnityEngine;
+
+//using Photon.Pun;
+using Photon.Realtime;
+
+namespace Photon.Pun.UtilityScripts
+{
+ /// <summary>Simple component to call ConnectUsingSettings and to get into a PUN room easily.</summary>
+ /// <remarks>A custom inspector provides a button to connect in PlayMode, should AutoConnect be false.</remarks>
+ public class ConnectAndJoinRandom : MonoBehaviourPunCallbacks
+ {
+ /// <summary>Connect automatically? If false you can set this to true later on or call ConnectUsingSettings in your own scripts.</summary>
+ public bool AutoConnect = true;
+
+ /// <summary>Used as PhotonNetwork.GameVersion.</summary>
+ public byte Version = 1;
+
+ /// <summary>Max number of players allowed in room. Once full, a new room will be created by the next connection attemping to join.</summary>
+ [Tooltip("The max number of players allowed in room. Once full, a new room will be created by the next connection attemping to join.")]
+ public byte MaxPlayers = 4;
+
+ public int playerTTL = -1;
+
+ public void Start()
+ {
+ if (this.AutoConnect)
+ {
+ this.ConnectNow();
+ }
+ }
+
+ public void ConnectNow()
+ {
+ Debug.Log("ConnectAndJoinRandom.ConnectNow() will now call: PhotonNetwork.ConnectUsingSettings().");
+
+
+ PhotonNetwork.ConnectUsingSettings();
+ PhotonNetwork.GameVersion = this.Version + "." + SceneManagerHelper.ActiveSceneBuildIndex;
+
+ }
+
+
+ // below, we implement some callbacks of the Photon Realtime API.
+ // Being a MonoBehaviourPunCallbacks means, we can override the few methods which are needed here.
+
+
+ public override void OnConnectedToMaster()
+ {
+ Debug.Log("OnConnectedToMaster() was called by PUN. This client is now connected to Master Server in region [" + PhotonNetwork.CloudRegion +
+ "] and can join a room. Calling: PhotonNetwork.JoinRandomRoom();");
+ PhotonNetwork.JoinRandomRoom();
+ }
+
+ public override void OnJoinedLobby()
+ {
+ Debug.Log("OnJoinedLobby(). This client is now connected to Relay in region [" + PhotonNetwork.CloudRegion + "]. This script now calls: PhotonNetwork.JoinRandomRoom();");
+ PhotonNetwork.JoinRandomRoom();
+ }
+
+ public override void OnJoinRandomFailed(short returnCode, string message)
+ {
+ Debug.Log("OnJoinRandomFailed() was called by PUN. No random room available in region [" + PhotonNetwork.CloudRegion + "], so we create one. Calling: PhotonNetwork.CreateRoom(null, new RoomOptions() {maxPlayers = 4}, null);");
+
+ RoomOptions roomOptions = new RoomOptions() { MaxPlayers = this.MaxPlayers };
+ if (playerTTL >= 0)
+ roomOptions.PlayerTtl = playerTTL;
+
+ PhotonNetwork.CreateRoom(null, roomOptions, null);
+ }
+
+ // the following methods are implemented to give you some context. re-implement them as needed.
+ public override void OnDisconnected(DisconnectCause cause)
+ {
+ Debug.Log("OnDisconnected(" + cause + ")");
+ }
+
+ public override void OnJoinedRoom()
+ {
+ Debug.Log("OnJoinedRoom() called by PUN. Now this client is in a room in region [" + PhotonNetwork.CloudRegion + "]. Game is now running.");
+ }
+ }
+
+
+ //#if UNITY_EDITOR
+ //[CanEditMultipleObjects]
+ //[CustomEditor(typeof(ConnectAndJoinRandom), true)]
+ //public class ConnectAndJoinRandomInspector : Editor
+ //{
+ // void OnEnable() { EditorApplication.update += Update; }
+ // void OnDisable() { EditorApplication.update -= Update; }
+
+ // bool isConnectedCache = false;
+
+ // void Update()
+ // {
+ // if (this.isConnectedCache != PhotonNetwork.IsConnected)
+ // {
+ // this.Repaint();
+ // }
+ // }
+
+ // public override void OnInspectorGUI()
+ // {
+ // this.isConnectedCache = !PhotonNetwork.IsConnected;
+
+
+ // this.DrawDefaultInspector(); // Draw the normal inspector
+
+ // if (Application.isPlaying && !PhotonNetwork.IsConnected)
+ // {
+ // if (GUILayout.Button("Connect"))
+ // {
+ // ((ConnectAndJoinRandom)this.target).ConnectNow();
+ // }
+ // }
+ // }
+ //}
+ //#endif
+}
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/ConnectAndJoinRandom.cs.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/ConnectAndJoinRandom.cs.meta
new file mode 100644
index 0000000..13f1494
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/ConnectAndJoinRandom.cs.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 5c1b84a427010e0469ce0df07ab64dbc
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/MoveByKeys.cs b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/MoveByKeys.cs
new file mode 100644
index 0000000..344cbe8
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/MoveByKeys.cs
@@ -0,0 +1,111 @@
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="OnJoinedInstantiate.cs" company="Exit Games GmbH">
+// Part of: Photon Unity Utilities,
+// </copyright>
+// <summary>
+// Very basic component to move a GameObject by WASD and Space.
+// </summary>
+// <remarks>
+// Requires a PhotonView.
+// Disables itself on GameObjects that are not owned on Start.
+//
+// Speed affects movement-speed.
+// JumpForce defines how high the object "jumps".
+// JumpTimeout defines after how many seconds you can jump again.
+// </remarks>
+// <author>developer@exitgames.com</author>
+// --------------------------------------------------------------------------------------------------------------------
+
+
+using UnityEngine;
+
+using Photon.Pun;
+using Photon.Realtime;
+
+namespace Photon.Pun.UtilityScripts
+{
+
+ /// <summary>
+ /// Very basic component to move a GameObject by WASD and Space.
+ /// </summary>
+ /// <remarks>
+ /// Requires a PhotonView.
+ /// Disables itself on GameObjects that are not owned on Start.
+ ///
+ /// Speed affects movement-speed.
+ /// JumpForce defines how high the object "jumps".
+ /// JumpTimeout defines after how many seconds you can jump again.
+ /// </remarks>
+ [RequireComponent(typeof(PhotonView))]
+ public class MoveByKeys : Photon.Pun.MonoBehaviourPun
+ {
+ public float Speed = 10f;
+ public float JumpForce = 200f;
+ public float JumpTimeout = 0.5f;
+
+ private bool isSprite;
+ private float jumpingTime;
+ private Rigidbody body;
+ private Rigidbody2D body2d;
+
+ public void Start()
+ {
+ //enabled = photonView.isMine;
+ this.isSprite = (GetComponent<SpriteRenderer>() != null);
+
+ this.body2d = GetComponent<Rigidbody2D>();
+ this.body = GetComponent<Rigidbody>();
+ }
+
+
+ // Update is called once per frame
+ public void FixedUpdate()
+ {
+ if (!photonView.IsMine)
+ {
+ return;
+ }
+
+ if ((Input.GetAxisRaw("Horizontal") < -0.1f) || (Input.GetAxisRaw("Horizontal") > 0.1f))
+ {
+ transform.position += Vector3.right * (Speed * Time.deltaTime) * Input.GetAxisRaw("Horizontal");
+ }
+
+ // jumping has a simple "cooldown" time but you could also jump in the air
+ if (this.jumpingTime <= 0.0f)
+ {
+ if (this.body != null || this.body2d != null)
+ {
+ // obj has a Rigidbody and can jump (AddForce)
+ if (Input.GetKey(KeyCode.Space))
+ {
+ this.jumpingTime = this.JumpTimeout;
+
+ Vector2 jump = Vector2.up * this.JumpForce;
+ if (this.body2d != null)
+ {
+ this.body2d.AddForce(jump);
+ }
+ else if (this.body != null)
+ {
+ this.body.AddForce(jump);
+ }
+ }
+ }
+ }
+ else
+ {
+ this.jumpingTime -= Time.deltaTime;
+ }
+
+ // 2d objects can't be moved in 3d "forward"
+ if (!this.isSprite)
+ {
+ if ((Input.GetAxisRaw("Vertical") < -0.1f) || (Input.GetAxisRaw("Vertical") > 0.1f))
+ {
+ transform.position += Vector3.forward * (Speed * Time.deltaTime) * Input.GetAxisRaw("Vertical");
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/MoveByKeys.cs.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/MoveByKeys.cs.meta
new file mode 100644
index 0000000..63447da
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/MoveByKeys.cs.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 99b4daedc5e674a429acdf1e77da6a55
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnClickDestroy.cs b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnClickDestroy.cs
new file mode 100644
index 0000000..fcd507a
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnClickDestroy.cs
@@ -0,0 +1,72 @@
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="OnClickDestroy.cs" company="Exit Games GmbH">
+// Part of: Photon Unity Utilities
+// </copyright>
+// <summary>A compact script for prototyping.</summary>
+// <author>developer@exitgames.com</author>
+// --------------------------------------------------------------------------------------------------------------------
+
+
+namespace Photon.Pun.UtilityScripts
+{
+ using System.Collections;
+ using UnityEngine;
+ using UnityEngine.EventSystems;
+
+ /// <summary>
+ /// Destroys the networked GameObject either by PhotonNetwork.Destroy or by sending an RPC which calls Object.Destroy().
+ /// </summary>
+ /// <remarks>
+ /// Using an RPC to Destroy a GameObject is typically a bad idea.
+ /// It allows any player to Destroy a GameObject and may cause errors.
+ ///
+ /// A client has to clean up the server's event-cache, which contains events for Instantiate and
+ /// buffered RPCs related to the GO.
+ ///
+ /// A buffered RPC gets cleaned up when the sending player leaves the room, so players joining later
+ /// won't get those buffered RPCs. This in turn, may mean they don't destroy the GO due to coming later.
+ ///
+ /// Vice versa, a GameObject Instantiate might get cleaned up when the creating player leaves a room.
+ /// This way, the GameObject that a RPC targets might become lost.
+ ///
+ /// It makes sense to test those cases. Many are not breaking errors and you just have to be aware of them.
+ ///
+ ///
+ /// Gets OnClick() calls by Unity's IPointerClickHandler. Needs a PhysicsRaycaster on the camera.
+ /// See: https://docs.unity3d.com/ScriptReference/EventSystems.IPointerClickHandler.html
+ /// </remarks>
+ public class OnClickDestroy : MonoBehaviourPun, IPointerClickHandler
+ {
+ public PointerEventData.InputButton Button;
+ public KeyCode ModifierKey;
+
+ public bool DestroyByRpc;
+
+
+ void IPointerClickHandler.OnPointerClick(PointerEventData eventData)
+ {
+ if (!PhotonNetwork.InRoom || (this.ModifierKey != KeyCode.None && !Input.GetKey(this.ModifierKey)) || eventData.button != this.Button )
+ {
+ return;
+ }
+
+
+ if (this.DestroyByRpc)
+ {
+ this.photonView.RPC("DestroyRpc", RpcTarget.AllBuffered);
+ }
+ else
+ {
+ PhotonNetwork.Destroy(this.gameObject);
+ }
+ }
+
+
+ [PunRPC]
+ public IEnumerator DestroyRpc()
+ {
+ Destroy(this.gameObject);
+ yield return 0; // if you allow 1 frame to pass, the object's OnDestroy() method gets called and cleans up references.
+ }
+ }
+} \ No newline at end of file
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnClickDestroy.cs.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnClickDestroy.cs.meta
new file mode 100644
index 0000000..f091f18
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnClickDestroy.cs.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 9dab7328ba500e944a99d62065fba6c0
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnClickInstantiate.cs b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnClickInstantiate.cs
new file mode 100644
index 0000000..4c8f865
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnClickInstantiate.cs
@@ -0,0 +1,56 @@
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="OnClickInstantiate.cs" company="Exit Games GmbH">
+// Part of: Photon Unity Utilities
+// </copyright>
+// <summary>A compact script for prototyping.</summary>
+// <author>developer@exitgames.com</author>
+// --------------------------------------------------------------------------------------------------------------------
+
+
+namespace Photon.Pun.UtilityScripts
+{
+ using UnityEngine;
+ using UnityEngine.EventSystems;
+
+
+ /// <summary>
+ /// Instantiates a networked GameObject on click.
+ /// </summary>
+ /// <remarks>
+ /// Gets OnClick() calls by Unity's IPointerClickHandler. Needs a PhysicsRaycaster on the camera.
+ /// See: https://docs.unity3d.com/ScriptReference/EventSystems.IPointerClickHandler.html
+ /// </remarks>
+ public class OnClickInstantiate : MonoBehaviour, IPointerClickHandler
+ {
+ public enum InstantiateOption { Mine, Scene }
+
+
+ public PointerEventData.InputButton Button;
+ public KeyCode ModifierKey;
+
+ public GameObject Prefab;
+
+ [SerializeField]
+ private InstantiateOption InstantiateType = InstantiateOption.Mine;
+
+
+ void IPointerClickHandler.OnPointerClick(PointerEventData eventData)
+ {
+ if (!PhotonNetwork.InRoom || (this.ModifierKey != KeyCode.None && !Input.GetKey(this.ModifierKey)) || eventData.button != this.Button)
+ {
+ return;
+ }
+
+
+ switch (this.InstantiateType)
+ {
+ case InstantiateOption.Mine:
+ PhotonNetwork.Instantiate(this.Prefab.name, eventData.pointerCurrentRaycast.worldPosition + new Vector3(0, 0.5f, 0), Quaternion.identity, 0);
+ break;
+ case InstantiateOption.Scene:
+ PhotonNetwork.InstantiateRoomObject(this.Prefab.name, eventData.pointerCurrentRaycast.worldPosition + new Vector3(0, 0.5f, 0), Quaternion.identity, 0, null);
+ break;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnClickInstantiate.cs.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnClickInstantiate.cs.meta
new file mode 100644
index 0000000..1150759
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnClickInstantiate.cs.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 9b79a9b62449de940a073364858c3f9b
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnClickRpc.cs b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnClickRpc.cs
new file mode 100644
index 0000000..c36c59c
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnClickRpc.cs
@@ -0,0 +1,89 @@
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="OnClickInstantiate.cs" company="Exit Games GmbH">
+// Part of: Photon Unity Utilities
+// </copyright>
+// <summary>A compact script for prototyping.</summary>
+// <author>developer@exitgames.com</author>
+// --------------------------------------------------------------------------------------------------------------------
+
+
+using System.Collections;
+
+
+namespace Photon.Pun.UtilityScripts
+{
+ using UnityEngine;
+ using UnityEngine.EventSystems;
+
+
+ /// <summary>
+ /// This component will instantiate a network GameObject when in a room and the user click on that component's GameObject.
+ /// Uses PhysicsRaycaster for positioning.
+ /// </summary>
+ public class OnClickRpc : MonoBehaviourPun, IPointerClickHandler
+ {
+ public PointerEventData.InputButton Button;
+ public KeyCode ModifierKey;
+
+ public RpcTarget Target;
+
+ void IPointerClickHandler.OnPointerClick(PointerEventData eventData)
+ {
+ if (!PhotonNetwork.InRoom || (this.ModifierKey != KeyCode.None && !Input.GetKey(this.ModifierKey)) || eventData.button != this.Button)
+ {
+ return;
+ }
+
+ this.photonView.RPC("ClickRpc", this.Target);
+ }
+
+
+ #region RPC Implementation
+
+ private Material originalMaterial;
+ private Color originalColor;
+ private bool isFlashing;
+
+ [PunRPC]
+ public void ClickRpc()
+ {
+ //Debug.Log("ClickRpc Called");
+ this.StartCoroutine(this.ClickFlash());
+ }
+
+ public IEnumerator ClickFlash()
+ {
+ if (isFlashing)
+ {
+ yield break;
+ }
+ isFlashing = true;
+
+ this.originalMaterial = GetComponent<Renderer>().material;
+ if (!this.originalMaterial.HasProperty("_EmissionColor"))
+ {
+ Debug.LogWarning("Doesn't have emission, can't flash " + gameObject);
+ yield break;
+ }
+
+ bool wasEmissive = this.originalMaterial.IsKeywordEnabled("_EMISSION");
+ this.originalMaterial.EnableKeyword("_EMISSION");
+
+ this.originalColor = this.originalMaterial.GetColor("_EmissionColor");
+ this.originalMaterial.SetColor("_EmissionColor", Color.white);
+
+ for (float f = 0.0f; f <= 1.0f; f += 0.08f)
+ {
+ Color lerped = Color.Lerp(Color.white, this.originalColor, f);
+ this.originalMaterial.SetColor("_EmissionColor", lerped);
+ yield return null;
+ }
+
+ this.originalMaterial.SetColor("_EmissionColor", this.originalColor);
+ if (!wasEmissive) this.originalMaterial.DisableKeyword("_EMISSION");
+ isFlashing = false;
+ }
+
+ #endregion
+ }
+} \ No newline at end of file
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnClickRpc.cs.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnClickRpc.cs.meta
new file mode 100644
index 0000000..8a7d1de
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnClickRpc.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 2cd0ed7420882554fa146aab6aeb2e80
+timeCreated: 1536748184
+licenseType: Store
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnEscapeQuit.cs b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnEscapeQuit.cs
new file mode 100644
index 0000000..599aec0
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnEscapeQuit.cs
@@ -0,0 +1,32 @@
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="OnJoinedInstantiate.cs" company="Exit Games GmbH">
+// Part of: Photon Unity Utilities,
+// </copyright>
+// <summary>
+// This component will quit the application when escape key is pressed
+// </summary>
+// <author>developer@exitgames.com</author>
+// --------------------------------------------------------------------------------------------------------------------
+
+using UnityEngine;
+using System.Collections;
+using System.Diagnostics;
+
+namespace Photon.Pun.UtilityScripts
+{
+ /// <summary>
+ /// This component will quit the application when escape key is pressed
+ /// </summary>
+ public class OnEscapeQuit : MonoBehaviour
+ {
+ [Conditional("UNITY_ANDROID"), Conditional("UNITY_IOS")]
+ public void Update()
+ {
+ // "back" button of phone equals "Escape". quit app if that's pressed
+ if (Input.GetKeyDown(KeyCode.Escape))
+ {
+ Application.Quit();
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnEscapeQuit.cs.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnEscapeQuit.cs.meta
new file mode 100644
index 0000000..6133070
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnEscapeQuit.cs.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 1fbabafd914a48f4eb6108d8d8f43d29
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnJoinedInstantiate.cs b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnJoinedInstantiate.cs
new file mode 100644
index 0000000..14c6843
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnJoinedInstantiate.cs
@@ -0,0 +1,450 @@
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="OnJoinedInstantiate.cs" company="Exit Games GmbH">
+// Part of: Photon Unity Utilities,
+// </copyright>
+// <summary>
+// This component will instantiate a network GameObject when a room is joined
+// </summary>
+// <author>developer@exitgames.com</author>
+// --------------------------------------------------------------------------------------------------------------------
+
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.Serialization;
+
+using Photon.Realtime;
+
+#if UNITY_EDITOR
+using UnityEditor;
+#endif
+
+namespace Photon.Pun.UtilityScripts
+{
+
+ /// <summary>
+ /// This component will instantiate a network GameObject when a room is joined
+ /// </summary>
+ public class OnJoinedInstantiate : MonoBehaviour
+ , IMatchmakingCallbacks
+ {
+ public enum SpawnSequence { Connection, Random, RoundRobin }
+
+ #region Inspector Items
+
+ // Old field, only here for backwards compat. Value copies over to SpawnPoints in OnValidate
+ [HideInInspector] private Transform SpawnPosition;
+
+ [HideInInspector] public SpawnSequence Sequence = SpawnSequence.Connection;
+
+ [HideInInspector] public List<Transform> SpawnPoints = new List<Transform>(1) { null };
+
+ [Tooltip("Add a random variance to a spawn point position. GetRandomOffset() can be overridden with your own method for producing offsets.")]
+ [HideInInspector] public bool UseRandomOffset = true;
+
+ [Tooltip("Radius of the RandomOffset.")]
+ [FormerlySerializedAs("PositionOffset")]
+ [HideInInspector] public float RandomOffset = 2.0f;
+
+ [Tooltip("Disables the Y axis of RandomOffset. The Y value of the spawn point will be used.")]
+ [HideInInspector] public bool ClampY = true;
+
+ [HideInInspector] public List<GameObject> PrefabsToInstantiate = new List<GameObject>(1) { null }; // set in inspector
+
+ [FormerlySerializedAs("autoSpawnObjects")]
+ [HideInInspector] public bool AutoSpawnObjects = true;
+
+ #endregion
+
+ // Record of spawned objects, used for Despawn All
+ public Stack<GameObject> SpawnedObjects = new Stack<GameObject>();
+ protected int spawnedAsActorId;
+
+
+
+#if UNITY_EDITOR
+
+ protected void OnValidate()
+ {
+ /// Check the prefab to make sure it is the actual resource, and not a scene object or other instance.
+ if (PrefabsToInstantiate != null)
+ for (int i = 0; i < PrefabsToInstantiate.Count; ++i)
+ {
+ var prefab = PrefabsToInstantiate[i];
+ if (prefab)
+ PrefabsToInstantiate[i] = ValidatePrefab(prefab);
+ }
+
+ /// Move any values from old SpawnPosition field to new SpawnPoints
+ if (SpawnPosition)
+ {
+ if (SpawnPoints == null)
+ SpawnPoints = new List<Transform>();
+
+ SpawnPoints.Add(SpawnPosition);
+ SpawnPosition = null;
+ }
+ }
+
+ /// <summary>
+ /// Validate, and if valid add this prefab to the first null element of the list, or create a new element. Returns true if the object was added.
+ /// </summary>
+ /// <param name="prefab"></param>
+ public bool AddPrefabToList(GameObject prefab)
+ {
+ var validated = ValidatePrefab(prefab);
+ if (validated)
+ {
+ // Don't add to list if this prefab already is on the list
+ if (PrefabsToInstantiate.Contains(validated))
+ return false;
+
+ // First try to use any null array slots to keep things tidy
+ if (PrefabsToInstantiate.Contains(null))
+ PrefabsToInstantiate[PrefabsToInstantiate.IndexOf(null)] = validated;
+ // Otherwise, just add this prefab.
+ else
+ PrefabsToInstantiate.Add(validated);
+ return true;
+ }
+
+ return false;
+
+ }
+
+ /// <summary>
+ /// Determines if the supplied GameObject is an instance of a prefab, or the actual source Asset,
+ /// and returns a best guess at the actual resource the dev intended to use.
+ /// </summary>
+ /// <returns></returns>
+ protected static GameObject ValidatePrefab(GameObject unvalidated)
+ {
+ if (unvalidated == null)
+ return null;
+
+ if (!unvalidated.GetComponent<PhotonView>())
+ return null;
+
+#if UNITY_2018_3_OR_NEWER
+
+ GameObject validated = null;
+
+ if (unvalidated != null)
+ {
+
+ if (PrefabUtility.IsPartOfPrefabAsset(unvalidated))
+ return unvalidated;
+
+ var prefabStatus = PrefabUtility.GetPrefabInstanceStatus(unvalidated);
+ var isValidPrefab = prefabStatus == PrefabInstanceStatus.Connected || prefabStatus == PrefabInstanceStatus.Disconnected;
+
+ if (isValidPrefab)
+ validated = PrefabUtility.GetCorrespondingObjectFromSource(unvalidated) as GameObject;
+ else
+ return null;
+
+ if (!PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(validated).Contains("/Resources"))
+ Debug.LogWarning("Player Prefab needs to be a Prefab in a Resource folder.");
+ }
+#else
+ GameObject validated = unvalidated;
+
+ if (unvalidated != null && PrefabUtility.GetPrefabType(unvalidated) != PrefabType.Prefab)
+ validated = PrefabUtility.GetPrefabParent(unvalidated) as GameObject;
+#endif
+ return validated;
+ }
+
+#endif
+
+
+ public virtual void OnEnable()
+ {
+ PhotonNetwork.AddCallbackTarget(this);
+ }
+
+ public virtual void OnDisable()
+ {
+ PhotonNetwork.RemoveCallbackTarget(this);
+ }
+
+
+ public virtual void OnJoinedRoom()
+ {
+ // Only AutoSpawn if we are a new ActorId. Rejoining should reproduce the objects by server instantiation.
+ if (AutoSpawnObjects && !PhotonNetwork.LocalPlayer.HasRejoined)
+ {
+ SpawnObjects();
+ }
+ }
+
+ public virtual void SpawnObjects()
+ {
+ if (this.PrefabsToInstantiate != null)
+ {
+ foreach (GameObject o in this.PrefabsToInstantiate)
+ {
+ if (o == null)
+ continue;
+#if UNITY_EDITOR
+ Debug.Log("Auto-Instantiating: " + o.name);
+#endif
+ Vector3 spawnPos; Quaternion spawnRot;
+ GetSpawnPoint(out spawnPos, out spawnRot);
+
+
+ var newobj = PhotonNetwork.Instantiate(o.name, spawnPos, spawnRot, 0);
+ SpawnedObjects.Push(newobj);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Destroy all objects that have been spawned by this component for this client.
+ /// </summary>
+ /// <param name="localOnly">Use Object.Destroy rather than PhotonNetwork.Destroy.</param>
+ public virtual void DespawnObjects(bool localOnly)
+ {
+
+ while (SpawnedObjects.Count > 0)
+ {
+ var go = SpawnedObjects.Pop();
+ if (go)
+ {
+ if (localOnly)
+ Object.Destroy(go);
+ else
+ PhotonNetwork.Destroy(go);
+
+ }
+ }
+ }
+
+ public virtual void OnFriendListUpdate(List<FriendInfo> friendList) { }
+ public virtual void OnCreatedRoom() { }
+ public virtual void OnCreateRoomFailed(short returnCode, string message) { }
+ public virtual void OnJoinRoomFailed(short returnCode, string message) { }
+ public virtual void OnJoinRandomFailed(short returnCode, string message) { }
+ public virtual void OnLeftRoom() { }
+
+ protected int lastUsedSpawnPointIndex = -1;
+
+ /// <summary>
+ /// Gets the next SpawnPoint from the list using the SpawnSequence, and applies RandomOffset (if used) to the transform matrix.
+ /// Override this method with any custom code for coming up with a spawn location. This method is used by AutoSpawn.
+ /// </summary>
+ public virtual void GetSpawnPoint(out Vector3 spawnPos, out Quaternion spawnRot)
+ {
+
+ // Fetch a point using the Sequence method indicated
+ Transform point = GetSpawnPoint();
+
+ if (point != null)
+ {
+ spawnPos = point.position;
+ spawnRot = point.rotation;
+ }
+ else
+ {
+ spawnPos = new Vector3(0, 0, 0);
+ spawnRot = new Quaternion(0, 0, 0, 1);
+ }
+
+ if (UseRandomOffset)
+ {
+ Random.InitState((int)(Time.time * 10000));
+ spawnPos += GetRandomOffset();
+ }
+ }
+
+
+ /// <summary>
+ /// Get the transform of the next SpawnPoint from the list, selected using the SpawnSequence setting.
+ /// RandomOffset is not applied, only the transform of the SpawnPoint is returned.
+ /// Override this method to change how Spawn Point transform is selected. Return the transform you want to use as a spawn point.
+ /// </summary>
+ /// <returns></returns>
+ protected virtual Transform GetSpawnPoint()
+ {
+ // Fetch a point using the Sequence method indicated
+ if (SpawnPoints == null || SpawnPoints.Count == 0)
+ {
+ return null;
+ }
+ else
+ {
+ switch (Sequence)
+ {
+ case SpawnSequence.Connection:
+ {
+ int id = PhotonNetwork.LocalPlayer.ActorNumber;
+ return SpawnPoints[(id == -1) ? 0 : id % SpawnPoints.Count];
+ }
+
+ case SpawnSequence.RoundRobin:
+ {
+ lastUsedSpawnPointIndex++;
+ if (lastUsedSpawnPointIndex >= SpawnPoints.Count)
+ lastUsedSpawnPointIndex = 0;
+
+ /// Use Vector.Zero and Quaternion.Identity if we are dealing with no or a null spawnpoint.
+ return SpawnPoints == null || SpawnPoints.Count == 0 ? null : SpawnPoints[lastUsedSpawnPointIndex];
+ }
+
+ case SpawnSequence.Random:
+ {
+ return SpawnPoints[Random.Range(0, SpawnPoints.Count)];
+ }
+
+ default:
+ return null;
+ }
+ }
+ }
+
+ /// <summary>
+ /// When UseRandomeOffset is enabled, this method is called to produce a Vector3 offset. The default implementation clamps the Y value to zero. You may override this with your own implementation.
+ /// </summary>
+ protected virtual Vector3 GetRandomOffset()
+ {
+ Vector3 random = Random.insideUnitSphere;
+ if (ClampY)
+ random.y = 0;
+ return RandomOffset * random.normalized;
+ }
+
+ }
+
+#if UNITY_EDITOR
+
+ [CustomEditor(typeof(OnJoinedInstantiate), true)]
+ [CanEditMultipleObjects]
+ public class OnJoinedInstantiateEditor : Editor
+ {
+
+ SerializedProperty SpawnPoints, PrefabsToInstantiate, UseRandomOffset, ClampY, RandomOffset, Sequence, autoSpawnObjects;
+ GUIStyle fieldBox;
+
+ private void OnEnable()
+ {
+ SpawnPoints = serializedObject.FindProperty("SpawnPoints");
+ PrefabsToInstantiate = serializedObject.FindProperty("PrefabsToInstantiate");
+ UseRandomOffset = serializedObject.FindProperty("UseRandomOffset");
+ ClampY = serializedObject.FindProperty("ClampY");
+ RandomOffset = serializedObject.FindProperty("RandomOffset");
+ Sequence = serializedObject.FindProperty("Sequence");
+
+ autoSpawnObjects = serializedObject.FindProperty("AutoSpawnObjects");
+ }
+
+ public override void OnInspectorGUI()
+ {
+ base.OnInspectorGUI();
+
+ const int PAD = 6;
+
+ if (fieldBox == null)
+ fieldBox = new GUIStyle("HelpBox") { padding = new RectOffset(PAD, PAD, PAD, PAD) };
+
+ EditorGUI.BeginChangeCheck();
+
+ EditableReferenceList(PrefabsToInstantiate, new GUIContent(PrefabsToInstantiate.displayName, PrefabsToInstantiate.tooltip), fieldBox);
+
+ EditableReferenceList(SpawnPoints, new GUIContent(SpawnPoints.displayName, SpawnPoints.tooltip), fieldBox);
+
+ /// Spawn Pattern
+ EditorGUILayout.BeginVertical(fieldBox);
+ EditorGUILayout.PropertyField(Sequence);
+ EditorGUILayout.PropertyField(UseRandomOffset);
+ if (UseRandomOffset.boolValue)
+ {
+ EditorGUILayout.PropertyField(RandomOffset);
+ EditorGUILayout.PropertyField(ClampY);
+ }
+ EditorGUILayout.EndVertical();
+
+ /// Auto/Manual Spawn
+ EditorGUILayout.BeginVertical(fieldBox);
+ EditorGUILayout.PropertyField(autoSpawnObjects);
+ EditorGUILayout.EndVertical();
+
+ if (EditorGUI.EndChangeCheck())
+ {
+ serializedObject.ApplyModifiedProperties();
+ }
+ }
+
+ /// <summary>
+ /// Create a basic rendered list of objects from a SerializedProperty list or array, with Add/Destroy buttons.
+ /// </summary>
+ /// <param name="list"></param>
+ /// <param name="gc"></param>
+ public void EditableReferenceList(SerializedProperty list, GUIContent gc, GUIStyle style = null)
+ {
+ EditorGUILayout.LabelField(gc);
+
+ if (style == null)
+ style = new GUIStyle("HelpBox") { padding = new RectOffset(6, 6, 6, 6) };
+
+ EditorGUILayout.BeginVertical(style);
+
+ int count = list.arraySize;
+
+ if (count == 0)
+ {
+ if (GUI.Button(EditorGUILayout.GetControlRect(GUILayout.MaxWidth(20)), "+", (GUIStyle)"minibutton"))
+ {
+ int newindex = list.arraySize;
+ list.InsertArrayElementAtIndex(0);
+ list.GetArrayElementAtIndex(0).objectReferenceValue = null;
+ }
+ }
+ else
+ {
+ // List Elements and Delete buttons
+ for (int i = 0; i < count; ++i)
+ {
+ EditorGUILayout.BeginHorizontal();
+ bool add = (GUI.Button(EditorGUILayout.GetControlRect(GUILayout.MaxWidth(20)), "+", (GUIStyle)"minibutton"));
+ EditorGUILayout.PropertyField(list.GetArrayElementAtIndex(i), GUIContent.none);
+ bool remove = (GUI.Button(EditorGUILayout.GetControlRect(GUILayout.MaxWidth(20)), "x", (GUIStyle)"minibutton"));
+
+ EditorGUILayout.EndHorizontal();
+
+ if (add)
+ {
+ Add(list, i);
+ break;
+ }
+
+ if (remove)
+ {
+ list.DeleteArrayElementAtIndex(i);
+ //EditorGUILayout.EndHorizontal();
+ break;
+ }
+ }
+
+ EditorGUILayout.GetControlRect(false, 4);
+
+ if (GUI.Button(EditorGUILayout.GetControlRect(), "Add", (GUIStyle)"minibutton"))
+ Add(list, count);
+
+ }
+
+
+ EditorGUILayout.EndVertical();
+ }
+
+ private void Add(SerializedProperty list, int i)
+ {
+ {
+ int newindex = list.arraySize;
+ list.InsertArrayElementAtIndex(i);
+ list.GetArrayElementAtIndex(i).objectReferenceValue = null;
+ }
+ }
+ }
+
+
+#endif
+}
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnJoinedInstantiate.cs.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnJoinedInstantiate.cs.meta
new file mode 100644
index 0000000..5b4fba0
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnJoinedInstantiate.cs.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: ed3b5dcba7bf9114cb13fc59e0a71f55
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnStartDelete.cs b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnStartDelete.cs
new file mode 100644
index 0000000..3fd3268
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnStartDelete.cs
@@ -0,0 +1,24 @@
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="OnStartDelete.cs" company="Exit Games GmbH">
+// Part of: Photon Unity Utilities,
+// </copyright>
+// <summary>
+// This component will destroy the GameObject it is attached to (in Start()).
+// </summary>
+// <author>developer@exitgames.com</author>
+// --------------------------------------------------------------------------------------------------------------------
+
+using UnityEngine;
+
+namespace Photon.Pun.UtilityScripts
+{
+ /// <summary>This component will destroy the GameObject it is attached to (in Start()).</summary>
+ public class OnStartDelete : MonoBehaviour
+ {
+ // Use this for initialization
+ private void Start()
+ {
+ Destroy(this.gameObject);
+ }
+ }
+} \ No newline at end of file
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnStartDelete.cs.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnStartDelete.cs.meta
new file mode 100644
index 0000000..4f4d47a
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Prototyping/OnStartDelete.cs.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: f8d56a54ae062da4a87516fb994f4e30
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Room.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Room.meta
new file mode 100644
index 0000000..667fcfb
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Room.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 7e3b3d6025e4b41fca914dca9dcc718d
+folderAsset: yes
+timeCreated: 1529328285
+licenseType: Store
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Room/CountdownTimer.cs b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Room/CountdownTimer.cs
new file mode 100644
index 0000000..a73da86
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Room/CountdownTimer.cs
@@ -0,0 +1,176 @@
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="CountdownTimer.cs" company="Exit Games GmbH">
+// Part of: Photon Unity Utilities,
+// </copyright>
+// <summary>
+// This is a basic CountdownTimer. In order to start the timer, the MasterClient can add a certain entry to the Custom Room Properties,
+// which contains the property's name 'StartTime' and the actual start time describing the moment, the timer has been started.
+// To have a synchronized timer, the best practice is to use PhotonNetwork.Time.
+// In order to subscribe to the CountdownTimerHasExpired event you can call CountdownTimer.OnCountdownTimerHasExpired += OnCountdownTimerIsExpired;
+// from Unity's OnEnable function for example. For unsubscribing simply call CountdownTimer.OnCountdownTimerHasExpired -= OnCountdownTimerIsExpired;.
+// You can do this from Unity's OnDisable function for example.
+// </summary>
+// <author>developer@exitgames.com</author>
+// --------------------------------------------------------------------------------------------------------------------
+
+using ExitGames.Client.Photon;
+using Photon.Realtime;
+using UnityEngine;
+using UnityEngine.UI;
+
+namespace Photon.Pun.UtilityScripts
+{
+ /// <summary>This is a basic, network-synced CountdownTimer based on properties.</summary>
+ /// <remarks>
+ /// In order to start the timer, the MasterClient can call SetStartTime() to set the timestamp for the start.
+ /// The property 'StartTime' then contains the server timestamp when the timer has been started.
+ ///
+ /// In order to subscribe to the CountdownTimerHasExpired event you can call CountdownTimer.OnCountdownTimerHasExpired
+ /// += OnCountdownTimerIsExpired;
+ /// from Unity's OnEnable function for example. For unsubscribing simply call CountdownTimer.OnCountdownTimerHasExpired
+ /// -= OnCountdownTimerIsExpired;.
+ ///
+ /// You can do this from Unity's OnEnable and OnDisable functions.
+ /// </remarks>
+ public class CountdownTimer : MonoBehaviourPunCallbacks
+ {
+ /// <summary>
+ /// OnCountdownTimerHasExpired delegate.
+ /// </summary>
+ public delegate void CountdownTimerHasExpired();
+
+ public const string CountdownStartTime = "StartTime";
+
+ [Header("Countdown time in seconds")]
+ public float Countdown = 5.0f;
+
+ private bool isTimerRunning;
+
+ private int startTime;
+
+ [Header("Reference to a Text component for visualizing the countdown")]
+ public Text Text;
+
+
+ /// <summary>
+ /// Called when the timer has expired.
+ /// </summary>
+ public static event CountdownTimerHasExpired OnCountdownTimerHasExpired;
+
+
+ public void Start()
+ {
+ if (this.Text == null) Debug.LogError("Reference to 'Text' is not set. Please set a valid reference.", this);
+ }
+
+ public override void OnEnable()
+ {
+ Debug.Log("OnEnable CountdownTimer");
+ base.OnEnable();
+
+ // the starttime may already be in the props. look it up.
+ Initialize();
+ }
+
+ public override void OnDisable()
+ {
+ base.OnDisable();
+ Debug.Log("OnDisable CountdownTimer");
+ }
+
+
+ public void Update()
+ {
+ if (!this.isTimerRunning) return;
+
+ float countdown = TimeRemaining();
+ this.Text.text = string.Format("Game starts in {0} seconds", countdown.ToString("n0"));
+
+ if (countdown > 0.0f) return;
+
+ OnTimerEnds();
+ }
+
+
+ private void OnTimerRuns()
+ {
+ this.isTimerRunning = true;
+ this.enabled = true;
+ }
+
+ private void OnTimerEnds()
+ {
+ this.isTimerRunning = false;
+ this.enabled = false;
+
+ Debug.Log("Emptying info text.", this.Text);
+ this.Text.text = string.Empty;
+
+ if (OnCountdownTimerHasExpired != null) OnCountdownTimerHasExpired();
+ }
+
+
+ public override void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged)
+ {
+ Debug.Log("CountdownTimer.OnRoomPropertiesUpdate " + propertiesThatChanged.ToStringFull());
+ Initialize();
+ }
+
+
+ private void Initialize()
+ {
+ int propStartTime;
+ if (TryGetStartTime(out propStartTime))
+ {
+ this.startTime = propStartTime;
+ Debug.Log("Initialize sets StartTime " + this.startTime + " server time now: " + PhotonNetwork.ServerTimestamp + " remain: " + TimeRemaining());
+
+
+ this.isTimerRunning = TimeRemaining() > 0;
+
+ if (this.isTimerRunning)
+ OnTimerRuns();
+ else
+ OnTimerEnds();
+ }
+ }
+
+
+ private float TimeRemaining()
+ {
+ int timer = PhotonNetwork.ServerTimestamp - this.startTime;
+ return this.Countdown - timer / 1000f;
+ }
+
+
+ public static bool TryGetStartTime(out int startTimestamp)
+ {
+ startTimestamp = PhotonNetwork.ServerTimestamp;
+
+ object startTimeFromProps;
+ if (PhotonNetwork.CurrentRoom.CustomProperties.TryGetValue(CountdownStartTime, out startTimeFromProps))
+ {
+ startTimestamp = (int)startTimeFromProps;
+ return true;
+ }
+
+ return false;
+ }
+
+
+ public static void SetStartTime()
+ {
+ int startTime = 0;
+ bool wasSet = TryGetStartTime(out startTime);
+
+ Hashtable props = new Hashtable
+ {
+ {CountdownTimer.CountdownStartTime, (int)PhotonNetwork.ServerTimestamp}
+ };
+ PhotonNetwork.CurrentRoom.SetCustomProperties(props);
+
+
+ Debug.Log("Set Custom Props for Time: "+ props.ToStringFull() + " wasSet: "+wasSet);
+ }
+ }
+} \ No newline at end of file
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Room/CountdownTimer.cs.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Room/CountdownTimer.cs.meta
new file mode 100644
index 0000000..f37edf5
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/Room/CountdownTimer.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: ffc398cf76e6d458caf303b5fceea504
+timeCreated: 1529327775
+licenseType: Store
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/TurnBased.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/TurnBased.meta
new file mode 100644
index 0000000..2e65237
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/TurnBased.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 2edc8c63e86d94f6990d3f7e7e90066a
+folderAsset: yes
+timeCreated: 1529327659
+licenseType: Store
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/TurnBased/PunTurnManager.cs b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/TurnBased/PunTurnManager.cs
new file mode 100644
index 0000000..6b23cba
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/TurnBased/PunTurnManager.cs
@@ -0,0 +1,430 @@
+// ----------------------------------------------------------------------------
+// <copyright file="PunTurnManager.cs" company="Exit Games GmbH">
+// PhotonNetwork Framework for Unity - Copyright (C) 2018 Exit Games GmbH
+// </copyright>
+// <summary>
+// Manager for Turn Based games, using PUN
+// </summary>
+// <author>developer@exitgames.com</author>
+// ----------------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+
+using UnityEngine;
+
+using Photon.Realtime;
+
+using ExitGames.Client.Photon;
+using Hashtable = ExitGames.Client.Photon.Hashtable;
+
+namespace Photon.Pun.UtilityScripts
+{
+ /// <summary>
+ /// Pun turnBased Game manager.
+ /// Provides an Interface (IPunTurnManagerCallbacks) for the typical turn flow and logic, between players
+ /// Provides Extensions for Player, Room and RoomInfo to feature dedicated api for TurnBased Needs
+ /// </summary>
+ public class PunTurnManager : MonoBehaviourPunCallbacks, IOnEventCallback
+ {
+
+ /// <summary>
+ /// External definition for better garbage collection management, used in ProcessEvent.
+ /// </summary>
+ Player sender;
+
+ /// <summary>
+ /// Wraps accessing the "turn" custom properties of a room.
+ /// </summary>
+ /// <value>The turn index</value>
+ public int Turn
+ {
+ get { return PhotonNetwork.CurrentRoom.GetTurn(); }
+ private set
+ {
+
+ _isOverCallProcessed = false;
+
+ PhotonNetwork.CurrentRoom.SetTurn(value, true);
+ }
+ }
+
+
+ /// <summary>
+ /// The duration of the turn in seconds.
+ /// </summary>
+ public float TurnDuration = 20f;
+
+ /// <summary>
+ /// Gets the elapsed time in the current turn in seconds
+ /// </summary>
+ /// <value>The elapsed time in the turn.</value>
+ public float ElapsedTimeInTurn
+ {
+ get { return ((float) (PhotonNetwork.ServerTimestamp - PhotonNetwork.CurrentRoom.GetTurnStart())) / 1000.0f; }
+ }
+
+
+ /// <summary>
+ /// Gets the remaining seconds for the current turn. Ranges from 0 to TurnDuration
+ /// </summary>
+ /// <value>The remaining seconds fo the current turn</value>
+ public float RemainingSecondsInTurn
+ {
+ get { return Mathf.Max(0f, this.TurnDuration - this.ElapsedTimeInTurn); }
+ }
+
+
+ /// <summary>
+ /// Gets a value indicating whether the turn is completed by all.
+ /// </summary>
+ /// <value><c>true</c> if this turn is completed by all; otherwise, <c>false</c>.</value>
+ public bool IsCompletedByAll
+ {
+ get { return PhotonNetwork.CurrentRoom != null && Turn > 0 && this.finishedPlayers.Count == PhotonNetwork.CurrentRoom.PlayerCount; }
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether the current turn is finished by me.
+ /// </summary>
+ /// <value><c>true</c> if the current turn is finished by me; otherwise, <c>false</c>.</value>
+ public bool IsFinishedByMe
+ {
+ get { return this.finishedPlayers.Contains(PhotonNetwork.LocalPlayer); }
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether the current turn is over. That is the ElapsedTimeinTurn is greater or equal to the TurnDuration
+ /// </summary>
+ /// <value><c>true</c> if the current turn is over; otherwise, <c>false</c>.</value>
+ public bool IsOver
+ {
+ get { return this.RemainingSecondsInTurn <= 0f; }
+ }
+
+ /// <summary>
+ /// The turn manager listener. Set this to your own script instance to catch Callbacks
+ /// </summary>
+ public IPunTurnManagerCallbacks TurnManagerListener;
+
+
+ /// <summary>
+ /// The finished players.
+ /// </summary>
+ private readonly HashSet<Player> finishedPlayers = new HashSet<Player>();
+
+ /// <summary>
+ /// The turn manager event offset event message byte. Used internaly for defining data in Room Custom Properties
+ /// </summary>
+ public const byte TurnManagerEventOffset = 0;
+
+ /// <summary>
+ /// The Move event message byte. Used internaly for saving data in Room Custom Properties
+ /// </summary>
+ public const byte EvMove = 1 + TurnManagerEventOffset;
+
+ /// <summary>
+ /// The Final Move event message byte. Used internaly for saving data in Room Custom Properties
+ /// </summary>
+ public const byte EvFinalMove = 2 + TurnManagerEventOffset;
+
+ // keep track of message calls
+ private bool _isOverCallProcessed = false;
+
+ #region MonoBehaviour CallBack
+
+
+ void Start(){}
+
+ void Update()
+ {
+ if (Turn > 0 && this.IsOver && !_isOverCallProcessed)
+ {
+ _isOverCallProcessed = true;
+ this.TurnManagerListener.OnTurnTimeEnds(this.Turn);
+ }
+
+ }
+
+ #endregion
+
+
+ /// <summary>
+ /// Tells the TurnManager to begins a new turn.
+ /// </summary>
+ public void BeginTurn()
+ {
+ Turn = this.Turn + 1; // note: this will set a property in the room, which is available to the other players.
+ }
+
+
+ /// <summary>
+ /// Call to send an action. Optionally finish the turn, too.
+ /// The move object can be anything. Try to optimize though and only send the strict minimum set of information to define the turn move.
+ /// </summary>
+ /// <param name="move"></param>
+ /// <param name="finished"></param>
+ public void SendMove(object move, bool finished)
+ {
+ if (IsFinishedByMe)
+ {
+ UnityEngine.Debug.LogWarning("Can't SendMove. Turn is finished by this player.");
+ return;
+ }
+
+ // along with the actual move, we have to send which turn this move belongs to
+ Hashtable moveHt = new Hashtable();
+ moveHt.Add("turn", Turn);
+ moveHt.Add("move", move);
+
+ byte evCode = (finished) ? EvFinalMove : EvMove;
+ PhotonNetwork.RaiseEvent(evCode, moveHt, new RaiseEventOptions() {CachingOption = EventCaching.AddToRoomCache}, SendOptions.SendReliable);
+ if (finished)
+ {
+ PhotonNetwork.LocalPlayer.SetFinishedTurn(Turn);
+ }
+
+ // the server won't send the event back to the origin (by default). to get the event, call it locally
+ // (note: the order of events might be mixed up as we do this locally)
+ ProcessOnEvent(evCode, moveHt, PhotonNetwork.LocalPlayer.ActorNumber);
+ }
+
+ /// <summary>
+ /// Gets if the player finished the current turn.
+ /// </summary>
+ /// <returns><c>true</c>, if player finished the current turn, <c>false</c> otherwise.</returns>
+ /// <param name="player">The Player to check for</param>
+ public bool GetPlayerFinishedTurn(Player player)
+ {
+ if (player != null && this.finishedPlayers != null && this.finishedPlayers.Contains(player))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ #region Callbacks
+
+ // called internally
+ void ProcessOnEvent(byte eventCode, object content, int senderId)
+ {
+ if (senderId == -1)
+ {
+ return;
+ }
+
+ sender = PhotonNetwork.CurrentRoom.GetPlayer(senderId);
+
+ switch (eventCode)
+ {
+ case EvMove:
+ {
+ Hashtable evTable = content as Hashtable;
+ int turn = (int)evTable["turn"];
+ object move = evTable["move"];
+ this.TurnManagerListener.OnPlayerMove(sender, turn, move);
+
+ break;
+ }
+ case EvFinalMove:
+ {
+ Hashtable evTable = content as Hashtable;
+ int turn = (int)evTable["turn"];
+ object move = evTable["move"];
+
+ if (turn == this.Turn)
+ {
+ this.finishedPlayers.Add(sender);
+
+ this.TurnManagerListener.OnPlayerFinished(sender, turn, move);
+
+ }
+
+ if (IsCompletedByAll)
+ {
+ this.TurnManagerListener.OnTurnCompleted(this.Turn);
+ }
+ break;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Called by PhotonNetwork.OnEventCall registration
+ /// </summary>
+ /// <param name="photonEvent">Photon event.</param>
+ public void OnEvent(EventData photonEvent)
+ {
+ this.ProcessOnEvent(photonEvent.Code, photonEvent.CustomData, photonEvent.Sender);
+ }
+
+ /// <summary>
+ /// Called by PhotonNetwork
+ /// </summary>
+ /// <param name="propertiesThatChanged">Properties that changed.</param>
+ public override void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged)
+ {
+
+ // Debug.Log("OnRoomPropertiesUpdate: "+propertiesThatChanged.ToStringFull());
+
+ if (propertiesThatChanged.ContainsKey("Turn"))
+ {
+ _isOverCallProcessed = false;
+ this.finishedPlayers.Clear();
+ this.TurnManagerListener.OnTurnBegins(this.Turn);
+ }
+ }
+
+ #endregion
+ }
+
+
+ public interface IPunTurnManagerCallbacks
+ {
+ /// <summary>
+ /// Called the turn begins event.
+ /// </summary>
+ /// <param name="turn">Turn Index</param>
+ void OnTurnBegins(int turn);
+
+ /// <summary>
+ /// Called when a turn is completed (finished by all players)
+ /// </summary>
+ /// <param name="turn">Turn Index</param>
+ void OnTurnCompleted(int turn);
+
+ /// <summary>
+ /// Called when a player moved (but did not finish the turn)
+ /// </summary>
+ /// <param name="player">Player reference</param>
+ /// <param name="turn">Turn Index</param>
+ /// <param name="move">Move Object data</param>
+ void OnPlayerMove(Player player, int turn, object move);
+
+ /// <summary>
+ /// When a player finishes a turn (includes the action/move of that player)
+ /// </summary>
+ /// <param name="player">Player reference</param>
+ /// <param name="turn">Turn index</param>
+ /// <param name="move">Move Object data</param>
+ void OnPlayerFinished(Player player, int turn, object move);
+
+
+ /// <summary>
+ /// Called when a turn completes due to a time constraint (timeout for a turn)
+ /// </summary>
+ /// <param name="turn">Turn index</param>
+ void OnTurnTimeEnds(int turn);
+ }
+
+
+ public static class TurnExtensions
+ {
+ /// <summary>
+ /// currently ongoing turn number
+ /// </summary>
+ public static readonly string TurnPropKey = "Turn";
+
+ /// <summary>
+ /// start (server) time for currently ongoing turn (used to calculate end)
+ /// </summary>
+ public static readonly string TurnStartPropKey = "TStart";
+
+ /// <summary>
+ /// Finished Turn of Actor (followed by number)
+ /// </summary>
+ public static readonly string FinishedTurnPropKey = "FToA";
+
+ /// <summary>
+ /// Sets the turn.
+ /// </summary>
+ /// <param name="room">Room reference</param>
+ /// <param name="turn">Turn index</param>
+ /// <param name="setStartTime">If set to <c>true</c> set start time.</param>
+ public static void SetTurn(this Room room, int turn, bool setStartTime = false)
+ {
+ if (room == null || room.CustomProperties == null)
+ {
+ return;
+ }
+
+ Hashtable turnProps = new Hashtable();
+ turnProps[TurnPropKey] = turn;
+ if (setStartTime)
+ {
+ turnProps[TurnStartPropKey] = PhotonNetwork.ServerTimestamp;
+ }
+
+ room.SetCustomProperties(turnProps);
+ }
+
+ /// <summary>
+ /// Gets the current turn from a RoomInfo
+ /// </summary>
+ /// <returns>The turn index </returns>
+ /// <param name="room">RoomInfo reference</param>
+ public static int GetTurn(this RoomInfo room)
+ {
+ if (room == null || room.CustomProperties == null || !room.CustomProperties.ContainsKey(TurnPropKey))
+ {
+ return 0;
+ }
+
+ return (int) room.CustomProperties[TurnPropKey];
+ }
+
+
+ /// <summary>
+ /// Returns the start time when the turn began. This can be used to calculate how long it's going on.
+ /// </summary>
+ /// <returns>The turn start.</returns>
+ /// <param name="room">Room.</param>
+ public static int GetTurnStart(this RoomInfo room)
+ {
+ if (room == null || room.CustomProperties == null || !room.CustomProperties.ContainsKey(TurnStartPropKey))
+ {
+ return 0;
+ }
+
+ return (int) room.CustomProperties[TurnStartPropKey];
+ }
+
+ /// <summary>
+ /// gets the player's finished turn (from the ROOM properties)
+ /// </summary>
+ /// <returns>The finished turn index</returns>
+ /// <param name="player">Player reference</param>
+ public static int GetFinishedTurn(this Player player)
+ {
+ Room room = PhotonNetwork.CurrentRoom;
+ if (room == null || room.CustomProperties == null || !room.CustomProperties.ContainsKey(TurnPropKey))
+ {
+ return 0;
+ }
+
+ string propKey = FinishedTurnPropKey + player.ActorNumber;
+ return (int) room.CustomProperties[propKey];
+ }
+
+ /// <summary>
+ /// Sets the player's finished turn (in the ROOM properties)
+ /// </summary>
+ /// <param name="player">Player Reference</param>
+ /// <param name="turn">Turn Index</param>
+ public static void SetFinishedTurn(this Player player, int turn)
+ {
+ Room room = PhotonNetwork.CurrentRoom;
+ if (room == null || room.CustomProperties == null)
+ {
+ return;
+ }
+
+ string propKey = FinishedTurnPropKey + player.ActorNumber;
+ Hashtable finishedTurnProp = new Hashtable();
+ finishedTurnProp[propKey] = turn;
+
+ room.SetCustomProperties(finishedTurnProp);
+ }
+ }
+} \ No newline at end of file
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/TurnBased/PunTurnManager.cs.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/TurnBased/PunTurnManager.cs.meta
new file mode 100644
index 0000000..0076919
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/TurnBased/PunTurnManager.cs.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 1a1b3bda60e9e804f87fd1e5d20a885a
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI.meta
new file mode 100644
index 0000000..b1a3ce4
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 665e986f9b37c294d96c166a76e618d3
+folderAsset: yes
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/ButtonInsideScrollList.cs b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/ButtonInsideScrollList.cs
new file mode 100644
index 0000000..bb02097
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/ButtonInsideScrollList.cs
@@ -0,0 +1,53 @@
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="ButtonInsideScrollList.cs" company="Exit Games GmbH">
+// Part of: Photon Unity Utilities,
+// </copyright>
+// <summary>
+// Used on Buttons inside UI lists to prevent scrollRect parent to scroll when down on buttons.
+// </summary>
+// <author>developer@exitgames.com</author>
+// --------------------------------------------------------------------------------------------------------------------
+
+using UnityEngine;
+using UnityEngine.EventSystems;
+using UnityEngine.UI;
+
+namespace Photon.Pun.UtilityScripts
+{
+ /// <summary>
+ /// Button inside scroll list will stop scrolling ability of scrollRect container, so that when pressing down on a button and draggin up and down will not affect scrolling.
+ /// this doesn't do anything if no scrollRect component found in Parent Hierarchy.
+ /// </summary>
+ public class ButtonInsideScrollList : MonoBehaviour, IPointerDownHandler, IPointerUpHandler {
+
+ ScrollRect scrollRect;
+
+ // Use this for initialization
+ void Start () {
+ scrollRect = GetComponentInParent<ScrollRect>();
+ }
+
+ #region IPointerDownHandler implementation
+ void IPointerDownHandler.OnPointerDown (PointerEventData eventData)
+ {
+ if (scrollRect !=null)
+ {
+ scrollRect.StopMovement();
+ scrollRect.enabled = false;
+ }
+ }
+ #endregion
+
+ #region IPointerUpHandler implementation
+
+ void IPointerUpHandler.OnPointerUp (PointerEventData eventData)
+ {
+ if (scrollRect !=null && !scrollRect.enabled)
+ {
+ scrollRect.enabled = true;
+ }
+ }
+
+ #endregion
+ }
+} \ No newline at end of file
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/ButtonInsideScrollList.cs.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/ButtonInsideScrollList.cs.meta
new file mode 100644
index 0000000..9e18870
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/ButtonInsideScrollList.cs.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: e0e8b381f2c05442ca5c01638958156a
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/EventSystemSpawner.cs b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/EventSystemSpawner.cs
new file mode 100644
index 0000000..3689bef
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/EventSystemSpawner.cs
@@ -0,0 +1,40 @@
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="EventSystemSpawner.cs" company="Exit Games GmbH">
+// </copyright>
+// <summary>
+// For additive Scene Loading context, eventSystem can't be added to each scene and instead should be instantiated only if necessary.
+// https://answers.unity.com/questions/1403002/multiple-eventsystem-in-scene-this-is-not-supporte.html
+// </summary>
+// <author>developer@exitgames.com</author>
+// --------------------------------------------------------------------------------------------------------------------
+
+using UnityEngine;
+using UnityEngine.EventSystems;
+
+namespace Photon.Pun.UtilityScripts
+{
+ /// <summary>
+ /// Event system spawner. Will add an EventSystem GameObject with an EventSystem component and a StandaloneInputModule component.
+ /// Use this in additive scene loading context where you would otherwise get a "Multiple EventSystem in scene... this is not supported" error from Unity.
+ /// </summary>
+ public class EventSystemSpawner : MonoBehaviour
+ {
+ void OnEnable()
+ {
+ #if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
+ Debug.LogError("PUN Demos are not compatible with the New Input System, unless you enable \"Both\" in: Edit > Project Settings > Player > Active Input Handling. Pausing App.");
+ Debug.Break();
+ return;
+ #endif
+
+ EventSystem sceneEventSystem = FindObjectOfType<EventSystem>();
+ if (sceneEventSystem == null)
+ {
+ GameObject eventSystem = new GameObject("EventSystem");
+
+ eventSystem.AddComponent<EventSystem>();
+ eventSystem.AddComponent<StandaloneInputModule>();
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/EventSystemSpawner.cs.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/EventSystemSpawner.cs.meta
new file mode 100644
index 0000000..a7fc376
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/EventSystemSpawner.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 68187d3cf4c8746aaa64930f1a766a38
+timeCreated: 1529319867
+licenseType: Store
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/GraphicToggleIsOnTransition.cs b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/GraphicToggleIsOnTransition.cs
new file mode 100644
index 0000000..b2ee446
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/GraphicToggleIsOnTransition.cs
@@ -0,0 +1,64 @@
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="ImageToggleIsOnTransition.cs" company="Exit Games GmbH">
+// </copyright>
+// <summary>
+// Use this on Toggle graphics to have some color transition as well without corrupting toggle's behaviour.
+// </summary>
+// <author>developer@exitgames.com</author>
+// --------------------------------------------------------------------------------------------------------------------
+
+using UnityEngine;
+using UnityEngine.EventSystems;
+using UnityEngine.UI;
+
+namespace Photon.Pun.UtilityScripts
+{
+ /// <summary>
+ /// Use this on toggles texts to have some color transition on the text depending on the isOn State.
+ /// </summary>
+ [RequireComponent(typeof(Graphic))]
+ public class GraphicToggleIsOnTransition : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
+ {
+ public Toggle toggle;
+
+ private Graphic _graphic;
+
+ public Color NormalOnColor = Color.white;
+ public Color NormalOffColor = Color.black;
+ public Color HoverOnColor = Color.black;
+ public Color HoverOffColor = Color.black;
+
+ private bool isHover;
+
+ public void OnPointerEnter(PointerEventData eventData)
+ {
+ this.isHover = true;
+ this._graphic.color = this.toggle.isOn ? this.HoverOnColor : this.HoverOffColor;
+ }
+
+ public void OnPointerExit(PointerEventData eventData)
+ {
+ this.isHover = false;
+ this._graphic.color = this.toggle.isOn ? this.NormalOnColor : this.NormalOffColor;
+ }
+
+ public void OnEnable()
+ {
+ this._graphic = this.GetComponent<Graphic>();
+
+ this.OnValueChanged(this.toggle.isOn);
+
+ this.toggle.onValueChanged.AddListener(this.OnValueChanged);
+ }
+
+ public void OnDisable()
+ {
+ this.toggle.onValueChanged.RemoveListener(this.OnValueChanged);
+ }
+
+ public void OnValueChanged(bool isOn)
+ {
+ this._graphic.color = isOn ? (this.isHover ? this.HoverOnColor : this.HoverOnColor) : (this.isHover ? this.NormalOffColor : this.NormalOffColor);
+ }
+ }
+} \ No newline at end of file
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/GraphicToggleIsOnTransition.cs.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/GraphicToggleIsOnTransition.cs.meta
new file mode 100644
index 0000000..c8c16c9
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/GraphicToggleIsOnTransition.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 195602a009c4b42b6a62e0bdf601b70d
+timeCreated: 1524059610
+licenseType: Store
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/OnPointerOverTooltip.cs b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/OnPointerOverTooltip.cs
new file mode 100644
index 0000000..0f53fae
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/OnPointerOverTooltip.cs
@@ -0,0 +1,45 @@
+// <copyright file="OnPointerOverTooltip.cs" company="Exit Games GmbH">
+// </copyright>
+// <summary>
+// Set focus to a given photonView when pointed is over
+// </summary>
+// <author>developer@exitgames.com</author>
+// --------------------------------------------------------------------------------------------------------------------
+
+using UnityEngine;
+using UnityEngine.EventSystems;
+
+namespace Photon.Pun.UtilityScripts
+{
+ /// <summary>
+ /// Set focus to a given photonView when pointed is over
+ /// </summary>
+ public class OnPointerOverTooltip : MonoBehaviour,IPointerEnterHandler,IPointerExitHandler
+ {
+
+ void OnDestroy()
+ {
+ PointedAtGameObjectInfo.Instance.RemoveFocus(this.GetComponent<PhotonView>());
+ }
+
+ #region IPointerExitHandler implementation
+
+ void IPointerExitHandler.OnPointerExit (PointerEventData eventData)
+ {
+ PointedAtGameObjectInfo.Instance.RemoveFocus (this.GetComponent<PhotonView>());
+
+ }
+
+ #endregion
+
+ #region IPointerEnterHandler implementation
+
+ void IPointerEnterHandler.OnPointerEnter (PointerEventData eventData)
+ {
+ PointedAtGameObjectInfo.Instance.SetFocus (this.GetComponent<PhotonView>());
+ }
+
+ #endregion
+
+ }
+} \ No newline at end of file
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/OnPointerOverTooltip.cs.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/OnPointerOverTooltip.cs.meta
new file mode 100644
index 0000000..bf2483c
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/OnPointerOverTooltip.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: ff93154db96e843fbbc5e816ec0d2b48
+timeCreated: 1495545560
+licenseType: Store
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/TabViewManager.cs b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/TabViewManager.cs
new file mode 100644
index 0000000..630ab98
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/TabViewManager.cs
@@ -0,0 +1,123 @@
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="TabViewManager.cs" company="Exit Games GmbH">
+// Part of: PunCockpit
+// </copyright>
+// <summary>
+// Simple Management for Tabs, it requires a ToggleGroup, and then for each Tab, a Unique Name, the related Toggle and its associated RectTransform View
+// this manager handles Tab views activation and deactivation, and provides a Unity Event Callback when a tab was selected.
+// </summary>
+// <author>developer@exitgames.com</author>
+// --------------------------------------------------------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+using UnityEngine;
+using UnityEngine.UI;
+using UnityEngine.Events;
+
+namespace Photon.Pun.UtilityScripts
+{
+ /// <summary>
+ /// Tab view manager. Handles Tab views activation and deactivation, and provides a Unity Event Callback when a tab was selected.
+ /// </summary>
+ public class TabViewManager : MonoBehaviour
+ {
+
+ /// <summary>
+ /// Tab change event.
+ /// </summary>
+ [System.Serializable]
+ public class TabChangeEvent : UnityEvent<string> { }
+
+ [Serializable]
+ public class Tab
+ {
+ public string ID = "";
+ public Toggle Toggle;
+ public RectTransform View;
+ }
+
+ /// <summary>
+ /// The toggle group component target.
+ /// </summary>
+ public ToggleGroup ToggleGroup;
+
+ /// <summary>
+ /// all the tabs for this group
+ /// </summary>
+ public Tab[] Tabs;
+
+ /// <summary>
+ /// The on tab changed Event.
+ /// </summary>
+ public TabChangeEvent OnTabChanged;
+
+ protected Tab CurrentTab;
+
+ Dictionary<Toggle, Tab> Tab_lut;
+
+ void Start()
+ {
+
+ Tab_lut = new Dictionary<Toggle, Tab>();
+
+ foreach (Tab _tab in this.Tabs)
+ {
+
+ Tab_lut[_tab.Toggle] = _tab;
+
+ _tab.View.gameObject.SetActive(_tab.Toggle.isOn);
+
+ if (_tab.Toggle.isOn)
+ {
+ CurrentTab = _tab;
+ }
+ _tab.Toggle.onValueChanged.AddListener((isSelected) =>
+ {
+ if (!isSelected)
+ {
+ return;
+ }
+ OnTabSelected(_tab);
+ });
+ }
+
+
+ }
+
+ /// <summary>
+ /// Selects a given tab.
+ /// </summary>
+ /// <param name="id">Tab Id</param>
+ public void SelectTab(string id)
+ {
+ foreach (Tab _t in Tabs)
+ {
+ if (_t.ID == id)
+ {
+ _t.Toggle.isOn = true;
+ return;
+ }
+ }
+ }
+
+
+ /// <summary>
+ /// final method for a tab selection routine
+ /// </summary>
+ /// <param name="tab">Tab.</param>
+ void OnTabSelected(Tab tab)
+ {
+ CurrentTab.View.gameObject.SetActive(false);
+
+ CurrentTab = Tab_lut[ToggleGroup.ActiveToggles().FirstOrDefault()];
+
+ CurrentTab.View.gameObject.SetActive(true);
+
+ OnTabChanged.Invoke(CurrentTab.ID);
+
+ }
+ }
+} \ No newline at end of file
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/TabViewManager.cs.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/TabViewManager.cs.meta
new file mode 100644
index 0000000..eae6657
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/TabViewManager.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: c94485733838d40fda441b2c0fbbec10
+timeCreated: 1521118118
+licenseType: Store
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/TextButtonTransition.cs b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/TextButtonTransition.cs
new file mode 100644
index 0000000..277da25
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/TextButtonTransition.cs
@@ -0,0 +1,70 @@
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="TextButtonTransition.cs" company="Exit Games GmbH">
+// </copyright>
+// <summary>
+// Use this on Button texts to have some color transition on the text as well without corrupting button's behaviour.
+// </summary>
+// <author>developer@exitgames.com</author>
+// --------------------------------------------------------------------------------------------------------------------
+
+using UnityEngine;
+using UnityEngine.EventSystems;
+using UnityEngine.UI;
+
+namespace Photon.Pun.UtilityScripts
+{
+
+ /// <summary>
+ /// Use this on Button texts to have some color transition on the text as well without corrupting button's behaviour.
+ /// </summary>
+ [RequireComponent(typeof(Text))]
+ public class TextButtonTransition : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
+ {
+
+ Text _text;
+
+ /// <summary>
+ /// The selectable Component.
+ /// </summary>
+ public Selectable Selectable;
+
+ /// <summary>
+ /// The color of the normal of the transition state.
+ /// </summary>
+ public Color NormalColor= Color.white;
+
+ /// <summary>
+ /// The color of the hover of the transition state.
+ /// </summary>
+ public Color HoverColor = Color.black;
+
+ public void Awake()
+ {
+ _text = GetComponent<Text>();
+ }
+
+ public void OnEnable()
+ {
+ _text.color = NormalColor;
+ }
+
+ public void OnDisable()
+ {
+ _text.color = NormalColor;
+ }
+
+ public void OnPointerEnter(PointerEventData eventData)
+ {
+ if (Selectable == null || Selectable.IsInteractable()) {
+ _text.color = HoverColor;
+ }
+ }
+
+ public void OnPointerExit(PointerEventData eventData)
+ {
+ if (Selectable == null || Selectable.IsInteractable()) {
+ _text.color = NormalColor;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/TextButtonTransition.cs.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/TextButtonTransition.cs.meta
new file mode 100644
index 0000000..43cf251
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/TextButtonTransition.cs.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 9d234639538a34b8d9e3cc6362a7afd0
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/TextToggleIsOnTransition.cs b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/TextToggleIsOnTransition.cs
new file mode 100644
index 0000000..8ffbb54
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/TextToggleIsOnTransition.cs
@@ -0,0 +1,86 @@
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="TextToggleIsOnTransition.cs" company="Exit Games GmbH">
+// </copyright>
+// <summary>
+// Use this on Button texts to have some color transition on the text as well without corrupting button's behaviour.
+// </summary>
+// <author>developer@exitgames.com</author>
+// --------------------------------------------------------------------------------------------------------------------
+
+using UnityEngine;
+using UnityEngine.EventSystems;
+using UnityEngine.UI;
+
+namespace Photon.Pun.UtilityScripts
+{
+
+ /// <summary>
+ /// Use this on toggles texts to have some color transition on the text depending on the isOn State.
+ /// </summary>
+ [RequireComponent(typeof(Text))]
+ public class TextToggleIsOnTransition : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
+ {
+
+ /// <summary>
+ /// The toggle Component.
+ /// </summary>
+ public Toggle toggle;
+
+ Text _text;
+
+ /// <summary>
+ /// The color of the normal on transition state.
+ /// </summary>
+ public Color NormalOnColor= Color.white;
+
+ /// <summary>
+ /// The color of the normal off transition state.
+ /// </summary>
+ public Color NormalOffColor = Color.black;
+
+ /// <summary>
+ /// The color of the hover on transition state.
+ /// </summary>
+ public Color HoverOnColor= Color.black;
+
+ /// <summary>
+ /// The color of the hover off transition state.
+ /// </summary>
+ public Color HoverOffColor = Color.black;
+
+ bool isHover;
+
+ public void OnEnable()
+ {
+ _text = GetComponent<Text>();
+
+ OnValueChanged (toggle.isOn);
+
+ toggle.onValueChanged.AddListener(OnValueChanged);
+
+ }
+
+ public void OnDisable()
+ {
+ toggle.onValueChanged.RemoveListener(OnValueChanged);
+ }
+
+ public void OnValueChanged(bool isOn)
+ {
+ _text.color = isOn? (isHover?HoverOnColor:HoverOnColor) : (isHover?NormalOffColor:NormalOffColor) ;
+ }
+
+ public void OnPointerEnter(PointerEventData eventData)
+ {
+ isHover = true;
+ _text.color = toggle.isOn?HoverOnColor:HoverOffColor;
+ }
+
+ public void OnPointerExit(PointerEventData eventData)
+ {
+ isHover = false;
+ _text.color = toggle.isOn?NormalOnColor:NormalOffColor;
+ }
+
+ }
+} \ No newline at end of file
diff --git a/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/TextToggleIsOnTransition.cs.meta b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/TextToggleIsOnTransition.cs.meta
new file mode 100644
index 0000000..a2ae161
--- /dev/null
+++ b/Mage/Assets/ThirdParty/Photon/PhotonUnityNetworking/UtilityScripts/UI/TextToggleIsOnTransition.cs.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: ec99d371d7c8e44899ce4b834dfd4d6a
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData: