using System; using System.Collections.Generic; using System.Linq; using UnityEngine.ResourceManagement; using UnityEngine.ResourceManagement.ResourceLocations; namespace UnityEngine.AddressableAssets.ResourceLocators { /// <summary> /// Simple implementation of an IResourceLocator /// </summary> public class ResourceLocationMap : IResourceLocator { /// <summary> /// Construct a new ResourceLocationMap object. /// </summary> /// <param name="id">The locator id.</param> /// <param name="capacity">The expected number of items.</param> public ResourceLocationMap(string id, int capacity = 0) { LocatorId = id; locations = new Dictionary<object, IList<IResourceLocation>>(capacity == 0 ? 100 : capacity); } /// <summary> /// Stores the resource locator id. /// </summary> public string LocatorId { get; private set; } /// <summary> /// Construct a new ResourceLocationMap object with a list of locations. /// </summary> /// <param name="id">The locator id.</param> /// <param name="locations">The list of locations to initialize with.</param> public ResourceLocationMap(string id, IList<ResourceLocationData> locations) { LocatorId = id; if (locations == null) return; this.locations = new Dictionary<object, IList<IResourceLocation>>(locations.Count * 2); var locMap = new Dictionary<string, ResourceLocationBase>(); var dataMap = new Dictionary<string, ResourceLocationData>(); //create and collect locations for (int i = 0; i < locations.Count; i++) { var rlData = locations[i]; if (rlData.Keys == null || rlData.Keys.Length < 1) { Addressables.LogErrorFormat("Address with id '{0}' does not have any valid keys, skipping...", rlData.InternalId); continue; } if (locMap.ContainsKey(rlData.Keys[0])) { Addressables.LogErrorFormat("Duplicate address '{0}' with id '{1}' found, skipping...", rlData.Keys[0], rlData.InternalId); continue; } var loc = new ResourceLocationBase(rlData.Keys[0], Addressables.ResolveInternalId(rlData.InternalId), rlData.Provider, rlData.ResourceType); loc.Data = rlData.Data; locMap.Add(rlData.Keys[0], loc); dataMap.Add(rlData.Keys[0], rlData); } //fix up dependencies between them foreach (var kvp in locMap) { var data = dataMap[kvp.Key]; if (data.Dependencies != null) { foreach (var d in data.Dependencies) kvp.Value.Dependencies.Add(locMap[d]); kvp.Value.ComputeDependencyHash(); } } foreach (KeyValuePair<string, ResourceLocationBase> kvp in locMap) { ResourceLocationData rlData = dataMap[kvp.Key]; foreach (var k in rlData.Keys) Add(k, kvp.Value); } } /// <summary> /// The mapping of key to location lists. /// </summary> Dictionary<object, IList<IResourceLocation>> locations; #if ENABLE_BINARY_CATALOG /// <summary> /// Enumeration of all locations for this locator. /// </summary> public IEnumerable<IResourceLocation> AllLocations => locations.SelectMany(k => k.Value); #endif /// <summary> /// Map of all locations for this locator. /// </summary> public Dictionary<object, IList<IResourceLocation>> Locations => locations; /// <summary> /// The keys available in this locator. /// </summary> public IEnumerable<object> Keys { get { return locations.Keys; } } /// <summary> /// Locate all of the locations that match the given key. /// </summary> /// <param name="key">The key used to locate the locations.</param> /// <param name="type">The resource type.</param> /// <param name="locations">The list of found locations. This list is shared so it should not be modified.</param> /// <returns>Returns true if a location was found. Returns false otherwise.</returns> public bool Locate(object key, Type type, out IList<IResourceLocation> locations) { IList<IResourceLocation> locs = null; if (!this.locations.TryGetValue(key, out locs)) { locations = null; return false; } if (type == null) { locations = locs; return true; } var validTypeCount = 0; foreach (var l in locs) if (type.IsAssignableFrom(l.ResourceType)) validTypeCount++; if (validTypeCount == 0) { locations = null; return false; } if (validTypeCount == locs.Count) { locations = locs; return true; } locations = new List<IResourceLocation>(); foreach (var l in locs) { if (type.IsAssignableFrom(l.ResourceType)) locations.Add(l); } return true; } /// <summary> /// Add a new location. /// </summary> /// <param name="key">The key to reference the location.</param> /// <param name="location">The location to add.</param> public void Add(object key, IResourceLocation location) { IList<IResourceLocation> locations; if (!this.locations.TryGetValue(key, out locations)) this.locations.Add(key, locations = new List<IResourceLocation>()); locations.Add(location); } /// <summary> /// Add a list of locations. /// </summary> /// <param name="key">The key to reference the locations with.</param> /// <param name="locations">The list of locations to store at the given key.</param> public void Add(object key, IList<IResourceLocation> locations) { this.locations.Add(key, locations); } } }