mirror of
https://github.com/RaindropViewer/RaindropViewer.git
synced 2026-07-27 22:11:39 +00:00
Refactor Maptile fetcher into MapService.cs
This commit is contained in:
+37
-16
@@ -5,36 +5,57 @@ using Raindrop.Map.Model;
|
||||
using Raindrop.ServiceLocator;
|
||||
using UnityEngine;
|
||||
|
||||
// a simple view to get a maptile from the map service.
|
||||
public class FetchMapTile : MonoBehaviour
|
||||
{
|
||||
public int Grid_X = 1000;
|
||||
public int Grid_Y = 1000;
|
||||
private bool modified = true;
|
||||
private bool _needsTextureRefresh = true;
|
||||
|
||||
public TexturePlane image;
|
||||
|
||||
public MapTile MapTile;
|
||||
|
||||
// Update is called once per frame
|
||||
void Start()
|
||||
{
|
||||
SyncMapTile_blocking(image, Grid_X, Grid_Y);
|
||||
modified = false;
|
||||
MapTile = RetrieveMapTile_blocking(image, Grid_X, Grid_Y);
|
||||
_needsTextureRefresh = true;
|
||||
}
|
||||
|
||||
// todo: refactor into a routine
|
||||
void update()
|
||||
{
|
||||
if (_needsTextureRefresh == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lock (MapTile)
|
||||
{
|
||||
if (MapTile.isReady)
|
||||
{
|
||||
image.ApplyTexture(MapTile.getTex());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//blocks until tex is successfully printed.
|
||||
private void SyncMapTile_blocking(TexturePlane texturePlane, int gridX, int gridY)
|
||||
private MapTile RetrieveMapTile_blocking(TexturePlane texturePlane, int gridX, int gridY)
|
||||
{
|
||||
MapFetcher mf = new MapFetcher();
|
||||
MapService mapService = new MapService();
|
||||
|
||||
MapTile mt = mf.GetRegionTileExternal(Utils.UIntsToLong(1000,1000), 1);
|
||||
while (mt.isReady == false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
lock (mt.getTex())
|
||||
{
|
||||
texturePlane.ApplyTexture(mt.getTex());
|
||||
}
|
||||
bool isReady;
|
||||
MapTile mt = mapService.GetMapTile(Utils.UIntsToLong(1000,1000), 1, out isReady);
|
||||
return mt;
|
||||
// while (mt.isReady == false)
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
//
|
||||
// lock (mt.getTex())
|
||||
// {
|
||||
// texturePlane.ApplyTexture(mt.getTex());
|
||||
// }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -385,8 +385,9 @@ namespace Raindrop.Rendering
|
||||
{
|
||||
if (state == TextureRequestState.Finished && assetTexture?.AssetData != null)
|
||||
{
|
||||
Texture2D img;
|
||||
img = T2D.LoadT2DWithoutMipMaps(assetTexture.AssetData);
|
||||
Texture2D img
|
||||
= new Texture2D(1, 1, TextureFormat.ARGB32, false);
|
||||
T2D.LoadT2DWithoutMipMaps(assetTexture.AssetData, img);
|
||||
detailTexture[i] = (Texture2D)img;
|
||||
}
|
||||
textureDone.Set();
|
||||
|
||||
@@ -30,10 +30,10 @@ namespace Raindrop.Services.Bootstrap
|
||||
private void Start()
|
||||
{
|
||||
//1. mapfetcher - logic, not ui. please refactor
|
||||
if (!ServiceLocator.ServiceLocator.Instance.IsRegistered<MapFetcher>())
|
||||
if (!ServiceLocator.ServiceLocator.Instance.IsRegistered<MapService>())
|
||||
{
|
||||
Debug.Log("UIBootstrapper creating and registering MapBackend.MapFetcher!");
|
||||
ServiceLocator.ServiceLocator.Instance.Register<MapFetcher>(new MapFetcher());
|
||||
ServiceLocator.ServiceLocator.Instance.Register<MapService>(new MapService());
|
||||
//return;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Raindrop.UI.Model
|
||||
class MapModel
|
||||
{
|
||||
// i fetch images.
|
||||
private MapFetcher mapFetcher;
|
||||
private MapService _mapService;
|
||||
// i cache images to disk.
|
||||
private MapCache mapCache;
|
||||
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
using OpenMetaverse;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using Raindrop.ServiceLocator;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Raindrop.Map.Model
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides the map textures on demand.
|
||||
///
|
||||
/// previously...:
|
||||
/// Contains logic to fetch and decode the map textures.
|
||||
/// </summary>
|
||||
public class MapService : IGameService
|
||||
{
|
||||
public static uint regionSize = 256;
|
||||
|
||||
// fixme: unused
|
||||
public class MapData
|
||||
{
|
||||
ulong gridLoc;
|
||||
byte[] dataJPG;
|
||||
|
||||
public MapData(ulong gridLoc, byte[] dataJPG)
|
||||
{
|
||||
this.gridLoc = gridLoc;
|
||||
this.dataJPG = dataJPG;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//a queue of map data that want to be decoded.
|
||||
// fixme: unused
|
||||
ConcurrentQueue<MapData> receivedDataQueue = new ConcurrentQueue<MapData>();
|
||||
|
||||
// fixme: unused
|
||||
UnityMainThreadDispatcher mainThreadInstance;
|
||||
private object mapDataQueue_lock = new object();
|
||||
|
||||
private MapTilesRAM _mapTilesRam;
|
||||
private MapTilesNetwork mapTilesNetwork;
|
||||
|
||||
public MapService()
|
||||
{
|
||||
mainThreadInstance = UnityMainThreadDispatcher.Instance();
|
||||
|
||||
//the cache.
|
||||
_mapTilesRam = new MapTilesRAM(10, receivedDataQueue);
|
||||
// the disk.
|
||||
// mapTilesDisk = new MapTilesDisk();
|
||||
// the network.
|
||||
mapTilesNetwork = new MapTilesNetwork(2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// API to Get the map tile at specific region handle and zoom level.
|
||||
/// - you will need to poll the ready flag in the Maptile until it is ready.
|
||||
/// Caveats:
|
||||
/// - Only zoom level 1 is supported.
|
||||
/// - if not present, a webrequest for the tile will be made.
|
||||
/// </summary>
|
||||
/// <param name="handle"></param>
|
||||
/// <param name="zoom"></param>
|
||||
/// <param name="isReady">if the returned MapTile is ready for display.</param>
|
||||
/// <returns></returns>
|
||||
public MapTile GetMapTile(ulong handle, int zoom, out bool isReady)
|
||||
{
|
||||
MapTile res = null;
|
||||
bool isTileAvailable = _mapTilesRam.tryGetTile_RAM(handle, out res);
|
||||
if (isTileAvailable)
|
||||
{
|
||||
isReady = true;
|
||||
return res;
|
||||
}
|
||||
//this call to network, returns a maptile that is empty inside for now.
|
||||
res = mapTilesNetwork.GetRegionTileExternal(handle, 1);
|
||||
isReady = false;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
+46
-85
@@ -1,81 +1,38 @@
|
||||
using OpenMetaverse;
|
||||
using Raindrop.Network;
|
||||
using Raindrop.UI;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Raindrop.ServiceLocator;
|
||||
using UniRx;
|
||||
using OpenMetaverse;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Raindrop.Map.Model
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains logic to fetch and decode the map textures.
|
||||
/// </summary>
|
||||
public class MapFetcher : IGameService
|
||||
// for you to get map tiles from the network.
|
||||
public class MapTilesNetwork
|
||||
{
|
||||
public class MapData
|
||||
{
|
||||
ulong gridLoc;
|
||||
byte[] dataJPG;
|
||||
|
||||
public MapData(ulong gridLoc, byte[] dataJPG)
|
||||
{
|
||||
gridLoc = this.gridLoc;
|
||||
dataJPG = this.dataJPG;
|
||||
}
|
||||
}
|
||||
|
||||
//MapTilesManager mapTilesManager;
|
||||
List<ulong> tileRequests = new List<ulong>(); // a list of pending fetch requests. the ulongs are the x and y world coordinates (gridX * 256), packed.
|
||||
uint regionSize = 256;
|
||||
private ParallelDownloader downloader;
|
||||
int poolSize = 10;
|
||||
|
||||
Queue<MapData> gottenData;
|
||||
|
||||
private DownloadManager downloader;
|
||||
UnityMainThreadDispatcher mainThreadInstance;
|
||||
private object mapDataQueue;
|
||||
|
||||
public MapFetcher()
|
||||
public MapTilesNetwork(int parallelDownloads)
|
||||
{
|
||||
//mapTilesManager = new MapTilesManager(10);
|
||||
|
||||
downloader = new ParallelDownloader();
|
||||
|
||||
downloader = new DownloadManager();
|
||||
downloader.ParallelDownloads = parallelDownloads;
|
||||
mainThreadInstance = UnityMainThreadDispatcher.Instance();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// API to Get the map tile at specific region handle and zoom level. Only zoom level 1 is supported.
|
||||
/// gets the map tile at handle if present.
|
||||
/// if not present, a webrequest for the tile will be made. a notification of download success will not be reported to the caller of this function.
|
||||
/// </summary>
|
||||
/// <param name="handle"></param>
|
||||
/// <param name="zoom"></param>
|
||||
/// <returns></returns>
|
||||
public MapTile tryGetMapTile(ulong handle, int zoom)
|
||||
{
|
||||
MapTile res = null;
|
||||
//res = mapTilesManager.tryGetTile(handle);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
//get region tile using SL map API -- JPEG images.
|
||||
// obtains the image from URL, decodes it in main thread, the stores data in the appropriate maptile.
|
||||
public MapTile GetRegionTileExternal(ulong handle, int zoom)
|
||||
{
|
||||
zoom = 1;
|
||||
|
||||
if (tryGetMapTile(handle, 1) != null)
|
||||
{
|
||||
return tryGetMapTile(handle, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// if (tryGetMapTile(handle, 1) != null)
|
||||
// {
|
||||
// //since tile is ready in the memory, return it.
|
||||
// return tryGetMapTile(handle, 1);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
lock (tileRequests)
|
||||
{
|
||||
if (tileRequests.Contains(handle)) return null;
|
||||
@@ -84,11 +41,11 @@ namespace Raindrop.Map.Model
|
||||
|
||||
uint regX, regY;
|
||||
OpenMetaverse.Utils.LongToUInts(handle, out regX, out regY);
|
||||
regX /= regionSize;
|
||||
regY /= regionSize;
|
||||
regX /= MapService.regionSize;
|
||||
regY /= MapService.regionSize;
|
||||
//int zoom = 1;
|
||||
MapTile res = new MapTile(256,256);
|
||||
downloader.QueueDownlad(
|
||||
downloader.QueueDownload(new DownloadRequest(
|
||||
new Uri(string.Format("http://map.secondlife.com/map-{0}-{1}-{2}-objects.jpg", zoom, regX, regY)),
|
||||
20 * 1000,
|
||||
null,
|
||||
@@ -100,31 +57,29 @@ namespace Raindrop.Map.Model
|
||||
try
|
||||
{
|
||||
//1. download is ready now.
|
||||
//2. decode the image.
|
||||
//3. add it to the hashtable in the model (memory)
|
||||
//3. add it to the hashtable in the model (memory)
|
||||
//2. decode the image on the main thread.
|
||||
//4. exit.
|
||||
|
||||
Debug.Log("fetching the texture was successful!");
|
||||
|
||||
//lock (mapData.sceneTiles)
|
||||
//{
|
||||
//decode http response data into texture2d
|
||||
//MapTile tex = mapData.getTile();
|
||||
lock (mapDataQueue)
|
||||
{
|
||||
gottenData.Enqueue(new MapData(handle, responseData));
|
||||
}
|
||||
// removed. reason: initially we wanted to push into a queue.
|
||||
// now realise want to simplify. just decode on main thread,
|
||||
// let the view keep polling the maptile object for ready flag.
|
||||
// lock (mapDataQueue_lock)
|
||||
// {
|
||||
// receivedDataQueue.Enqueue(new MapService.MapData(handle, responseData));
|
||||
// }
|
||||
|
||||
|
||||
//run jpeg decoding on the main thread, for now.
|
||||
//start to run jpeg decoding on the main thread.
|
||||
mainThreadInstance.Enqueue(DecodeDataToTexAsync(res, responseData));
|
||||
|
||||
|
||||
// remove from request list
|
||||
lock (tileRequests)
|
||||
{
|
||||
if (tileRequests.Contains(handle))
|
||||
tileRequests.Remove(handle);
|
||||
}
|
||||
//res = tile;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -132,28 +87,32 @@ namespace Raindrop.Map.Model
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
)
|
||||
);
|
||||
|
||||
return res; // inside res, it is notready.
|
||||
return res; // the tile is created. but inside the tile, it is not ready and the texture is the empty texture static
|
||||
|
||||
//lock (mapData.sceneTiles)
|
||||
//{
|
||||
// mapData.sceneTiles[handle] = mapData.acquireTile(); //wtf!
|
||||
//}
|
||||
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
private IEnumerator DecodeDataToTexAsync(MapTile output_tile, byte[] responseData)
|
||||
|
||||
// decode jpg bytes to texture2d.
|
||||
//must be run on the main thread as we are manipulating T2D
|
||||
// 1. decode JPEGbytes to texture2d
|
||||
// 2. replace the corresponding tiles's T2D
|
||||
private IEnumerator DecodeDataToTexAsync(MapTile tile, byte[] responseData)
|
||||
{
|
||||
try
|
||||
{
|
||||
lock (output_tile.getTex())
|
||||
lock (tile) //lock the tile that you want to write into.
|
||||
{
|
||||
Texture2D _tex = output_tile.getTex();
|
||||
bool success = _tex.LoadImage(responseData); //warn: main thread only.
|
||||
output_tile.isReady = true;
|
||||
Texture2D _tex = tile.getTex();
|
||||
bool success = _tex.LoadImage(responseData); //warn: main thread only. fixme.
|
||||
tile.isReady = true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -165,5 +124,7 @@ namespace Raindrop.Map.Model
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 551a208562ef49b1bf29bfac4b99f040
|
||||
timeCreated: 1642786871
|
||||
@@ -8,7 +8,7 @@ namespace Raindrop.Map.Model
|
||||
{
|
||||
private Queue<MapTile> tilePool;
|
||||
|
||||
public int count => tilePool.Count;
|
||||
public int Count => tilePool.Count;
|
||||
|
||||
|
||||
public MapTilesPool(int poolSize)
|
||||
@@ -23,7 +23,7 @@ namespace Raindrop.Map.Model
|
||||
// gets a unused maptile from pool.
|
||||
public MapTile acquireTile()
|
||||
{
|
||||
if (count <= 0)
|
||||
if (Count <= 0)
|
||||
{
|
||||
throw new Exception("ran out of memory in mapdatapool! Please implement data recycling logic.");
|
||||
}
|
||||
|
||||
+10
-6
@@ -1,5 +1,6 @@
|
||||
using OpenMetaverse;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Raindrop.Map.Model
|
||||
@@ -7,16 +8,19 @@ namespace Raindrop.Map.Model
|
||||
/// <summary>
|
||||
/// API to retrieve, delete, modify, create MapTiles in the scene
|
||||
/// </summary>
|
||||
public class MapTilesManager
|
||||
public class MapTilesRAM
|
||||
{
|
||||
//number of tiles that are in the scene.
|
||||
public int visibleCount => sceneTiles.Count;
|
||||
|
||||
int poolSize => pool.Count;
|
||||
|
||||
//tiles that are in the scene.
|
||||
private Dictionary<ulong, MapTile> sceneTiles = new Dictionary<ulong, MapTile>();
|
||||
|
||||
private MapTilesPool pool;
|
||||
public MapTilesManager(int poolSize)
|
||||
|
||||
private ConcurrentQueue<MapService.MapData> readyForDecode_DataQueue;
|
||||
public MapTilesRAM(int poolSize, ConcurrentQueue<MapService.MapData> receivedDataQueue)
|
||||
{
|
||||
pool = new MapTilesPool(poolSize);
|
||||
}
|
||||
@@ -36,11 +40,11 @@ namespace Raindrop.Map.Model
|
||||
/// </summary>
|
||||
/// <param name="handle">the region handle of the tile to get ; gridCoords * 256 and pack X&Y together.</param>
|
||||
/// <returns> Tile </returns>
|
||||
public MapTile tryGetTile(ulong handle)
|
||||
public bool tryGetTile_RAM(ulong handle, out MapTile tile)
|
||||
{
|
||||
MapTile tile = null;
|
||||
// MapTile tile = null;
|
||||
bool success = sceneTiles.TryGetValue(handle, out tile);
|
||||
return tile;
|
||||
return success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1,8 +0,0 @@
|
||||
namespace Raindrop
|
||||
{
|
||||
public interface SpawnableObject
|
||||
{
|
||||
void Spawn();
|
||||
void DeSpawn();
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: af6f4e5269f7aba4fa7a0d038cca70e4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -20,7 +20,7 @@ public class MapViewer_SingleStatic_NoZoom : MonoBehaviour
|
||||
{
|
||||
|
||||
[SerializeField]
|
||||
public MapFetcher mapFetcher;
|
||||
public MapService MapService;
|
||||
|
||||
[SerializeField]
|
||||
public GameObject mapTileGO;
|
||||
@@ -43,7 +43,7 @@ public class MapViewer_SingleStatic_NoZoom : MonoBehaviour
|
||||
System.Threading.Timer repaint;
|
||||
private void Awake()
|
||||
{
|
||||
mapFetcher = new MapFetcher();
|
||||
MapService = new MapService();
|
||||
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ public class MapViewer_SingleStatic_NoZoom : MonoBehaviour
|
||||
throw new System.Exception("mapMoverGO is fucked"); // fix exception type plz
|
||||
}
|
||||
|
||||
mapFetcher = new MapFetcher();
|
||||
MapService = new MapService();
|
||||
|
||||
|
||||
// for testing
|
||||
@@ -93,11 +93,13 @@ public class MapViewer_SingleStatic_NoZoom : MonoBehaviour
|
||||
ulong handle = mapMover.GetLookAt();
|
||||
int zoom = (int)zoomSlider.value;
|
||||
// how 2 convert look at floats into uints? (uints are gridpos * 256)
|
||||
if (mapFetcher.tryGetMapTile(handle, 1) == null) //hack for now.
|
||||
{
|
||||
mapFetcher.GetRegionTileExternal(handle, 1);
|
||||
}
|
||||
|
||||
MapTile mt = MapService.GetMapTile(handle, 1, out bool isReady);
|
||||
//
|
||||
// if (MapService.GetMapTile(handle, 1) == null) //hack for now.
|
||||
// {
|
||||
// MapService.GetMapTile(handle, 1, out bool isReady);
|
||||
// }
|
||||
//
|
||||
needRepaint = true;
|
||||
|
||||
Debug.Log("refreshed internal images. fetching images if any..");
|
||||
@@ -119,12 +121,13 @@ public class MapViewer_SingleStatic_NoZoom : MonoBehaviour
|
||||
return;
|
||||
}
|
||||
ulong handle = mapMover.GetLookAt();
|
||||
MapTile tex = mapFetcher.tryGetMapTile(handle, 1);
|
||||
|
||||
if (tex != null)
|
||||
{
|
||||
iv.setRawImage(tex.getTex());
|
||||
}
|
||||
Debug.Log("drew images.");
|
||||
// MapTile tex = MapService.GetMapTile(handle, 1);
|
||||
throw new NotImplementedException("we recently refactored the mapservice interface.");
|
||||
|
||||
// if (tex != null)
|
||||
// {
|
||||
// iv.setRawImage(tex.getTex());
|
||||
// }
|
||||
// Debug.Log("drew images.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,13 +17,13 @@ namespace Raindrop
|
||||
class TestTextureFetcher : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
public MapFetcher mapFetcher; //fetching logic + pooling data here
|
||||
public MapService MapService; //fetching logic + pooling data here
|
||||
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
MainThreadDispatcher.Initialize();
|
||||
mapFetcher = new MapFetcher();
|
||||
MapService = new MapService();
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,8 @@ namespace Raindrop
|
||||
|
||||
|
||||
var handle = Utils.UIntsToLong(256 * 1000, 256 * 1000);
|
||||
mapFetcher.GetRegionTileExternal(handle, 1);
|
||||
throw new NotImplementedException("we recently refactored the mapservice interface.");
|
||||
// MapService.GetRegionTileExternal(handle, 1);
|
||||
Debug.Log("end of initial fetch call.");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user