using System.Collections.Generic; using UnityEngine; using ExitGames.Client.Photon; namespace Photon.Pun.Demo.Procedural { /// /// The Cluster component has references to all Blocks that are part of this Cluster. /// It provides functions for modifying single Blocks inside this Cluster. /// It also handles modifications made to the world by other clients. /// public class Cluster : MonoBehaviourPunCallbacks { private string propertiesKey; private Dictionary propertiesValue; public int ClusterId { get; set; } public Dictionary Blocks { get; private set; } #region UNITY public void Awake() { Blocks = new Dictionary(); propertiesValue = new Dictionary(); } /// /// Sets the unique key of this Cluster used for storing modifications within the Custom Room Properties. /// private void Start() { propertiesKey = "Cluster " + ClusterId; } #endregion #region CLASS FUNCTIONS /// /// Adds a Block to the Cluster. /// This is called by the WorldGenerator while the generation process is running. /// In order to modify Blocks directly, we are storing the ID as well as a reference to the certain GameObject. /// public void AddBlock(int blockId, GameObject block) { Blocks.Add(blockId, block); } /// /// Gets called before a new world can be generated. /// Destroys each Block from this Cluster and removes the data stored in the Custom Room Properties. /// public void DestroyCluster() { foreach (GameObject block in Blocks.Values) { Destroy(block); } Blocks.Clear(); if (PhotonNetwork.IsMasterClient) { RemoveClusterFromRoomProperties(); } } /// /// Decreases a Block's height locally before applying the modification to the Custom Room Properties. /// public void DecreaseBlockHeight(int blockId) { float height = Blocks[blockId].transform.localScale.y; height = Mathf.Max((height - 1.0f), 0.0f); SetBlockHeightLocal(blockId, height); } /// /// Increases a Block's height locally before applying the modification to the Custom Room Properties. /// public void IncreaseBlockHeight(int blockId) { float height = Blocks[blockId].transform.localScale.y; height = Mathf.Min((height + 1.0f), 8.0f); SetBlockHeightLocal(blockId, height); } /// /// Gets called when a remote client has modified a certain Block within this Cluster. /// Called by the WorldGenerator or the Cluster itself after the Custom Room Properties have been updated. /// public void SetBlockHeightRemote(int blockId, float height) { GameObject block = Blocks[blockId]; Vector3 scale = block.transform.localScale; Vector3 position = block.transform.localPosition; block.transform.localScale = new Vector3(scale.x, height, scale.z); block.transform.localPosition = new Vector3(position.x, height / 2.0f, position.z); } /// /// Gets called whenever the local client modifies any Block within this Cluster. /// The modification will be applied to the Block first before it is published to the Custom Room Properties. /// private void SetBlockHeightLocal(int blockId, float height) { GameObject block = Blocks[blockId]; Vector3 scale = block.transform.localScale; Vector3 position = block.transform.localPosition; block.transform.localScale = new Vector3(scale.x, height, scale.z); block.transform.localPosition = new Vector3(position.x, height / 2.0f, position.z); UpdateRoomProperties(blockId, height); } /// /// Gets called in order to update the Custom Room Properties with the modification made by the local client. /// private void UpdateRoomProperties(int blockId, float height) { propertiesValue[blockId] = height; Hashtable properties = new Hashtable {{propertiesKey, propertiesValue}}; PhotonNetwork.CurrentRoom.SetCustomProperties(properties); } /// /// Removes the modifications of this Cluster from the Custom Room Properties. /// private void RemoveClusterFromRoomProperties() { Hashtable properties = new Hashtable {{propertiesKey, null}}; PhotonNetwork.CurrentRoom.SetCustomProperties(properties); } #endregion #region PUN CALLBACKS /// /// Gets called whenever the Custom Room Properties are updated. /// When the changed properties contain the previously set PropertiesKey (basically the Cluster ID), /// the Cluster and its Blocks will be updated accordingly. /// public override void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged) { if (propertiesThatChanged.ContainsKey(propertiesKey)) { if (propertiesThatChanged[propertiesKey] == null) { propertiesValue = new Dictionary(); return; } propertiesValue = (Dictionary) propertiesThatChanged[propertiesKey]; foreach (KeyValuePair pair in propertiesValue) { SetBlockHeightRemote(pair.Key, pair.Value); } } } #endregion } }