/* INFINITY CODE 2013-2019 */ /* http://www.infinity-code.com */ using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using Object = UnityEngine.Object; /// /// Manages map tiles /// public class OnlineMapsTileManager { /// /// The maximum number simultaneously downloading tiles. /// public static int maxTileDownloads = 5; public static Action OnLoadFromCache; /// /// The event occurs after generating buffer and before update control to preload tiles for tileset. /// public static Action OnPreloadTiles; public static Action OnPrepareDownloadTile; /// /// An event that occurs when loading the tile. Allows you to intercept of loading tile, and load it yourself. /// public static Action OnStartDownloadTile; /// /// This event is occurs when a tile is loaded. /// public static Action OnTileLoaded; private OnlineMapsTile[] downloadTiles; private Dictionary _dtiles; private OnlineMaps _map; private List _tiles; private List unusedTiles; public Dictionary dTiles { get { return _dtiles; } } public List tiles { get { return _tiles; } set { _tiles = value; } } public OnlineMaps map { get { return _map; } } public OnlineMapsTileManager(OnlineMaps map) { _map = map; unusedTiles = new List(); _tiles = new List(); _dtiles = new Dictionary(); } public void Add(OnlineMapsTile tile) { tiles.Add(tile); if (dTiles.ContainsKey(tile.key)) dTiles[tile.key] = tile; else dTiles.Add(tile.key, tile); } public void Dispose() { foreach (OnlineMapsTile tile in tiles) tile.Dispose(); _map = null; _dtiles = null; _tiles = null; } /// /// Gets a tile for zoom, x, y. /// /// Tile zoom /// Tile X /// Tile Y /// Tile or null public OnlineMapsTile GetTile(int zoom, int x, int y) { ulong key = GetTileKey(zoom, x, y); if (dTiles.ContainsKey(key)) { OnlineMapsTile tile = dTiles[key]; if (tile.status != OnlineMapsTileStatus.disposed) return tile; } return null; } /// /// Gets a tile for zoom, x, y. /// /// Tile zoom /// Tile X /// Tile Y /// Tile /// True - success, false - otherwise public bool GetTile(int zoom, int x, int y, out OnlineMapsTile tile) { tile = null; ulong key = GetTileKey(zoom, x, y); OnlineMapsTile t; if (dTiles.TryGetValue(key, out t)) { if (t.status != OnlineMapsTileStatus.disposed) { tile = t; return true; } } return false; } /// /// Gets a tile key for zoom, x, y. /// /// Tile zoom /// Tile X /// Tile Y /// Tile key public static ulong GetTileKey(int zoom, int x, int y) { return ((ulong)zoom << 58) + ((ulong)x << 29) + (ulong)y; } private static void OnTileWWWComplete(OnlineMapsWWW www) { OnlineMapsTile tile = www["tile"] as OnlineMapsTile; if (tile == null) return; tile.LoadFromWWW(www); } public static void OnTrafficWWWComplete(OnlineMapsWWW www) { OnlineMapsRasterTile tile = www["tile"] as OnlineMapsRasterTile; if (tile == null) return; if (tile.trafficWWW == null || !tile.trafficWWW.isDone) return; if (tile.status == OnlineMapsTileStatus.disposed) { tile.trafficWWW = null; return; } if (!www.hasError) { if (tile.map.control.resultIsTexture) { if (tile.OnLabelDownloadComplete()) tile.map.buffer.ApplyTile(tile); } else if (tile.trafficWWW != null && tile.map.traffic) { Texture2D trafficTexture = new Texture2D(256, 256, TextureFormat.ARGB32, false) { wrapMode = TextureWrapMode.Clamp }; if (tile.map.useSoftwareJPEGDecoder) OnlineMapsRasterTile.LoadTexture(trafficTexture, www.bytes); else tile.trafficWWW.LoadImageIntoTexture(trafficTexture); tile.trafficTexture = trafficTexture; } if (OnlineMapsTile.OnTrafficDownloaded != null) OnlineMapsTile.OnTrafficDownloaded(tile); tile.map.Redraw(); } tile.trafficWWW = null; } public void Remove(OnlineMapsTile tile) { unusedTiles.Add(tile); if (_dtiles.ContainsKey(tile.key)) _dtiles.Remove(tile.key); } public void Reset() { foreach (OnlineMapsTile tile in tiles) tile.Dispose(); tiles.Clear(); dTiles.Clear(); } public void StartDownloading() { if (tiles == null) return; float startTime = Time.realtimeSinceStartup; int countDownload = 0; int c = 0; lock (OnlineMapsTile.lockTiles) { for (int i = 0; i < tiles.Count; i++) { OnlineMapsTile tile = tiles[i]; if (tile.status == OnlineMapsTileStatus.loading && tile.www != null) { countDownload++; if (countDownload >= maxTileDownloads) return; } } int needDownload = maxTileDownloads - countDownload; if (downloadTiles == null) downloadTiles = new OnlineMapsTile[maxTileDownloads]; for (int i = 0; i < tiles.Count; i++) { OnlineMapsTile tile = tiles[i]; if (tile.status != OnlineMapsTileStatus.none) continue; if (c == 0) { downloadTiles[0] = tile; c++; } else { int index = c; int index2 = index - 1; while (index2 >= 0) { if (downloadTiles[index2].zoom <= tile.zoom) break; index2--; index--; } if (index < needDownload) { for (int j = needDownload - 1; j > index; j--) downloadTiles[j] = downloadTiles[j - 1]; downloadTiles[index] = tile; if (c < needDownload) c++; } } } } for (int i = 0; i < c; i++) { if (Time.realtimeSinceStartup - startTime > 0.02) break; OnlineMapsTile tile = downloadTiles[i]; countDownload++; if (countDownload > maxTileDownloads) break; if (OnPrepareDownloadTile != null) OnPrepareDownloadTile(tile); if (OnLoadFromCache != null) OnLoadFromCache(tile); else if (OnStartDownloadTile != null) OnStartDownloadTile(tile); else StartDownloadTile(tile); } } /// /// Starts dowloading of specified tile. /// /// Tile to be downloaded. public static void StartDownloadTile(OnlineMapsTile tile) { tile.status = OnlineMapsTileStatus.loading; tile.map.StartCoroutine(StartDownloadTileAsync(tile)); } private static IEnumerator StartDownloadTileAsync(OnlineMapsTile tile) { bool loadOnline = true; if (tile.map.source != OnlineMapsSource.Online) { ResourceRequest resourceRequest = Resources.LoadAsync(tile.resourcesPath); yield return resourceRequest; if (tile.map == null) { tile.MarkError(); yield break; } Object tileTexture = resourceRequest.asset; if (tileTexture != null) { tileTexture = Object.Instantiate(tileTexture); if (tile.map.control.resultIsTexture) { (tile as OnlineMapsRasterTile).ApplyTexture(tileTexture as Texture2D); tile.map.buffer.ApplyTile(tile); } else { tile.texture = tileTexture as Texture2D; tile.status = OnlineMapsTileStatus.loaded; } tile.MarkLoaded(); tile.map.Redraw(); loadOnline = false; } else if (tile.map.source == OnlineMapsSource.Resources) { tile.MarkError(); yield break; } } if (loadOnline) { if (tile.www != null) { Debug.Log("tile has www " + tile + " " + tile.status); yield break; } tile.www = new OnlineMapsWWW(tile.url); tile.www["tile"] = tile; tile.www.OnComplete += OnTileWWWComplete; tile.status = OnlineMapsTileStatus.loading; } OnlineMapsRasterTile rTile = tile as OnlineMapsRasterTile; if (tile.map.traffic && !string.IsNullOrEmpty(rTile.trafficURL)) { rTile.trafficWWW = new OnlineMapsWWW(rTile.trafficURL); rTile.trafficWWW["tile"] = tile; rTile.trafficWWW.OnComplete += OnTrafficWWWComplete; } } public void UnloadUnusedTiles() { if (unusedTiles == null) return; for (int i = 0; i < unusedTiles.Count; i++) unusedTiles[i].Destroy(); unusedTiles.Clear(); } }