using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using UnityEngine; using Framework.Services; using Debug = UnityEngine.Debug; namespace Framework.Layers { /// Manages named layer masks throughout the game /// /// In order to keep layer masks consistent across multiple scenes and to ensure /// this data is stored in one place only, the layer mask manager loads layer /// masks from the resource file and lets you access them by name. /// [ServiceScope(Scope.Global)] public class LayerMaskManager : Service, ILayerMaskService { /// Called when the component gets loaded into a game object protected override void Awake() { this.defaultMaskBuilt = new bool[32]; this.defaultMask = new int[32]; this.namedMasks = new Dictionary(); LoadLayerMaskList("DefaultLayerMasks"); LoadLayerMaskList("LayerMasks"); } /// Loads named layer masks from the specified resource /// /// Path of the resource containing named layer mask definitions /// public void LoadLayerMaskList(string resourcePath) { TextAsset layerMaskList = Resources.Load(resourcePath, typeof(TextAsset)) as TextAsset; if(layerMaskList == null) { Debug.LogWarning( "Layer mask list not found at path '" + resourcePath + "'" ); } else { using(var reader = new StringReader(layerMaskList.text)) { LayerMaskListParser.Read(this.namedMasks, reader); } } } /// Builds a layer mask for the specified layers /// Layers that should be part of the mask /// The layer mask for the specified layers /// /// Builds a mask from the named layers. /// public static int BuildMask(params string[] layers) { int mask = 0; for(int index = 0; index < layers.Length; ++index) { int layerIndex = LayerMask.NameToLayer(layers[index]); mask |= 1 << layerIndex; } return mask; } /// /// Looks up the default collision mask for the layer with the specified name /// /// /// Name of the layer whose collision mask will be looked up /// /// The default collision mask for the layer with the specified name public int GetDefaultMask(string layerName) { return GetDefaultMask(LayerMask.NameToLayer(layerName)); } /// /// Looks up the default collision mask for the layer with the specified index /// /// /// Index of the layer whose collision mask will be looked up /// /// The default collision mask for the layer with the specified index public int GetDefaultMask(int layerIndex) { enforceValidLayerIndex(layerIndex); if(!this.defaultMaskBuilt[layerIndex]) { int mask = 0; for(int index = 0; index < 32; ++index) { if(!Physics.GetIgnoreLayerCollision(layerIndex, index)) { mask |= (1 << index); } } this.defaultMask[layerIndex] = mask; this.defaultMaskBuilt[layerIndex] = true; } return this.defaultMask[layerIndex]; } /// /// Invalidates the cache for the default layer mask with the specified name /// /// /// Name of the default layer mask that will be invalidated /// public void InvalidateDefaultMask(string layerName) { InvalidateDefaultMask(LayerMask.NameToLayer(layerName)); } /// /// Invalidates the cache for the default layer mask with the specified index /// /// /// Index of the default layer mask that will be invalidated /// public void InvalidateDefaultMask(int layerIndex) { enforceValidLayerIndex(layerIndex); this.defaultMaskBuilt[layerIndex] = false; } /// Retrieves one of the configured layer masks by its name /// Name of the layer mask that will be retrieved /// The layer mask with the specified name public int GetMask(string layerMaskName) { return this.namedMasks[layerMaskName]; } /// Changes one of the configured layer masks /// Name of the layer mask that will be changed /// New layer mask to store under that given name public void SetMask(string layerMaskName, int mask) { this.namedMasks[layerMaskName] = mask; } /// Throws an exception if the layer index is not valid /// Layer index that will be checked [Conditional("DEBUG")] private static void enforceValidLayerIndex(int layerIndex) { if((layerIndex < 0) || (layerIndex >= 32)) { throw new ArgumentException("Layer index must be in the 0-31 range", "layerIndex"); } } /// Named collision masks that have been defined project-wide private IDictionary namedMasks; /// Keeps track of which layer masks have already been queried private bool[/*32*/] defaultMaskBuilt; /// Stores the collision masks for each of the 32 possible layers private int[/*32*/] defaultMask; } } // namespace Framework.Layers