First pass at making the V2 map work. Standalones only for now. There are some issues with the zoom level -- TBD.

bulletsim
Diva Canto 2011-06-12 15:37:42 -07:00
parent 06e254c392
commit fd57c91b4a
13 changed files with 1021 additions and 10 deletions

View File

@ -412,7 +412,7 @@ namespace OpenSim.Framework.Servers.HttpServer
// OpenSim.Framework.WebUtil.OSHeaderRequestID // OpenSim.Framework.WebUtil.OSHeaderRequestID
if (request.Headers["opensim-request-id"] != null) if (request.Headers["opensim-request-id"] != null)
reqnum = String.Format("{0}:{1}",request.RemoteIPEndPoint,request.Headers["opensim-request-id"]); reqnum = String.Format("{0}:{1}",request.RemoteIPEndPoint,request.Headers["opensim-request-id"]);
// m_log.DebugFormat("[BASE HTTP SERVER]: <{0}> handle request for {1}",reqnum,request.RawUrl); //m_log.DebugFormat("[BASE HTTP SERVER]: <{0}> handle request for {1}",reqnum,request.RawUrl);
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US", true); Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US", true);
@ -440,7 +440,7 @@ namespace OpenSim.Framework.Servers.HttpServer
string path = request.RawUrl; string path = request.RawUrl;
string handlerKey = GetHandlerKey(request.HttpMethod, path); string handlerKey = GetHandlerKey(request.HttpMethod, path);
// m_log.DebugFormat("[BASE HTTP SERVER]: Handling {0} request for {1}", request.HttpMethod, path); //m_log.DebugFormat("[BASE HTTP SERVER]: Handling {0} request for {1}", request.HttpMethod, path);
if (TryGetStreamHandler(handlerKey, out requestHandler)) if (TryGetStreamHandler(handlerKey, out requestHandler))
{ {

View File

@ -0,0 +1,111 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Reflection;
using System.Collections.Generic;
using log4net;
using Mono.Addins;
using Nini.Config;
using OpenSim.Framework;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Server.Base;
using OpenSim.Server.Handlers.Base;
using OpenSim.Server.Handlers.MapImage;
using OpenSim.Services.Interfaces;
namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.MapImage
{
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
public class MapImageServiceInConnectorModule : ISharedRegionModule
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static bool m_Enabled = false;
private IConfigSource m_Config;
bool m_Registered = false;
#region IRegionModule interface
public void Initialise(IConfigSource config)
{
m_Config = config;
IConfig moduleConfig = config.Configs["Modules"];
if (moduleConfig != null)
{
m_Enabled = moduleConfig.GetBoolean("MapImageServiceInConnector", false);
if (m_Enabled)
{
m_log.Info("[MAP SERVICE IN CONNECTOR]: MapImage Service In Connector enabled");
new MapGetServiceConnector(m_Config, MainServer.Instance, "MapImageService");
}
}
}
public void PostInitialise()
{
}
public void Close()
{
}
public Type ReplaceableInterface
{
get { return null; }
}
public string Name
{
get { return "MapImageServiceIn"; }
}
public void AddRegion(Scene scene)
{
if (!m_Enabled)
return;
}
public void RemoveRegion(Scene scene)
{
if (!m_Enabled)
return;
}
public void RegionLoaded(Scene scene)
{
if (!m_Enabled)
return;
}
#endregion
}
}

View File

@ -0,0 +1,232 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Net;
using System.IO;
using System.Timers;
using System.Drawing;
using System.Drawing.Imaging;
using log4net;
using Mono.Addins;
using Nini.Config;
using OpenSim.Framework;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Services.Interfaces;
using OpenSim.Server.Base;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage
{
/// <summary>
/// </summary>
/// <remarks>
/// </remarks>
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
public class MapImageServiceModule : ISharedRegionModule
{
private static readonly ILog m_log =
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private bool m_enabled = false;
private IMapImageService m_MapService;
private string m_serverUrl = String.Empty;
private Dictionary<UUID, Scene> m_scenes = new Dictionary<UUID, Scene>();
private int m_refreshtime = 0;
private int m_lastrefresh = 0;
private System.Timers.Timer m_refreshTimer = new System.Timers.Timer();
#region ISharedRegionModule
public Type ReplaceableInterface { get { return null; } }
public string Name { get { return "MapImageServiceModule"; } }
public void RegionLoaded(Scene scene) { }
public void Close() { }
public void PostInitialise() { }
///<summary>
///
///</summary>
public void Initialise(IConfigSource source)
{
IConfig moduleConfig = source.Configs["Modules"];
if (moduleConfig != null)
{
string name = moduleConfig.GetString("MapImageService", "");
if (name != Name)
return;
}
IConfig config = source.Configs["MapImageService"];
if (config == null)
return;
int refreshminutes = Convert.ToInt32(config.GetString("RefreshTime"));
if (refreshminutes <= 0)
{
m_log.WarnFormat("[MAP IMAGE SERVICE MODULE]: No refresh time given in config. Module disabled.");
return;
}
m_refreshtime = refreshminutes * 60 * 1000; // convert from minutes to ms
string service = config.GetString("LocalServiceModule", string.Empty);
if (service == string.Empty)
{
m_log.WarnFormat("[MAP IMAGE SERVICE MODULE]: No service dll given in config. Unable to proceed.");
return;
}
Object[] args = new Object[] { source };
m_MapService = ServerUtils.LoadPlugin<IMapImageService>(service, args);
m_refreshTimer.Enabled = true;
m_refreshTimer.AutoReset = true;
m_refreshTimer.Interval = m_refreshtime;
m_refreshTimer.Elapsed += new ElapsedEventHandler(HandleMaptileRefresh);
m_log.InfoFormat("[MAP IMAGE SERVICE MODULE]: enabled with refresh time {0}min and service object {1}",
refreshminutes, service);
m_enabled = true;
}
///<summary>
///
///</summary>
///<summary>
///
///</summary>
public void AddRegion(Scene scene)
{
if (! m_enabled)
return;
// Every shared region module has to maintain an indepedent list of
// currently running regions
lock (m_scenes)
m_scenes[scene.RegionInfo.RegionID] = scene;
scene.EventManager.OnPrimsLoaded += new EventManager.PrimsLoaded(EventManager_OnPrimsLoaded);
}
///<summary>
///
///</summary>
public void RemoveRegion(Scene scene)
{
if (! m_enabled)
return;
lock (m_scenes)
m_scenes.Remove(scene.RegionInfo.RegionID);
}
#endregion ISharedRegionModule
void EventManager_OnPrimsLoaded(Scene s)
{
UploadMapTile(s);
}
///<summary>
///
///</summary>
private void HandleMaptileRefresh(object sender, EventArgs ea)
{
// this approach is a bit convoluted becase we want to wait for the
// first upload to happen on startup but after all the objects are
// loaded and initialized
if (m_lastrefresh > 0 && Util.EnvironmentTickCountSubtract(m_lastrefresh) < m_refreshtime)
return;
m_log.DebugFormat("[MAP IMAGE SERVICE MODULE]: map refresh!");
lock (m_scenes)
{
foreach (IScene scene in m_scenes.Values)
{
try
{
UploadMapTile(scene);
}
catch (Exception ex)
{
m_log.WarnFormat("[MAP IMAGE SERVICE MODULE]: something bad happened {0}", ex.Message);
}
}
}
m_lastrefresh = Util.EnvironmentTickCount();
}
///<summary>
///
///</summary>
private void UploadMapTile(IScene scene)
{
m_log.DebugFormat("[MAP IMAGE SERVICE MODULE]: upload maptile for {0}", scene.RegionInfo.RegionName);
// Create a PNG map tile and upload it to the AddMapTile API
byte[] jpgData = Utils.EmptyBytes;
IMapImageGenerator tileGenerator = scene.RequestModuleInterface<IMapImageGenerator>();
if (tileGenerator == null)
{
m_log.Warn("[MAP IMAGE SERVICE MODULE]: Cannot upload PNG map tile without an ImageGenerator");
return;
}
using (Image mapTile = tileGenerator.CreateMapTile())
{
using (MemoryStream stream = new MemoryStream())
{
mapTile.Save(stream, ImageFormat.Jpeg);
jpgData = stream.ToArray();
}
}
string reason = string.Empty;
if (!m_MapService.AddMapTile((int)scene.RegionInfo.RegionLocX, (int)scene.RegionInfo.RegionLocY, jpgData, out reason))
{
m_log.DebugFormat("[MAP IMAGE SERVICE MODULE]: Unable to upload tile image for {0} at {1}-{2}: {3}",
scene.RegionInfo.RegionName, scene.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY, reason);
}
}
}
}

View File

@ -849,10 +849,10 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
{ {
List<MapBlockData> mapBlocks = new List<MapBlockData>(); List<MapBlockData> mapBlocks = new List<MapBlockData>();
List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID,
(minX - 4) * (int)Constants.RegionSize, (minX - 8) * (int)Constants.RegionSize,
(maxX + 4) * (int)Constants.RegionSize, (maxX + 8) * (int)Constants.RegionSize,
(minY - 4) * (int)Constants.RegionSize, (minY - 8) * (int)Constants.RegionSize,
(maxY + 4) * (int)Constants.RegionSize); (maxY + 8) * (int)Constants.RegionSize);
foreach (GridRegion r in regions) foreach (GridRegion r in regions)
{ {
MapBlockData block = new MapBlockData(); MapBlockData block = new MapBlockData();

View File

@ -0,0 +1,61 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using Nini.Config;
using OpenSim.Server.Base;
using OpenSim.Services.Interfaces;
using OpenSim.Framework.Servers.HttpServer;
using OpenSim.Server.Handlers.Base;
namespace OpenSim.Server.Handlers.MapImage
{
public class MapAddServiceConnector : ServiceConnector
{
private IMapImageService m_MapService;
private string m_ConfigName = "MapImageService";
public MapAddServiceConnector(IConfigSource config, IHttpServer server, string configName) :
base(config, server, configName)
{
IConfig serverConfig = config.Configs[m_ConfigName];
if (serverConfig == null)
throw new Exception(String.Format("No section {0} in config file", m_ConfigName));
string gridService = serverConfig.GetString("LocalServiceModule",
String.Empty);
if (gridService == String.Empty)
throw new Exception("No LocalServiceModule in config file");
Object[] args = new Object[] { config };
m_MapService = ServerUtils.LoadPlugin<IMapImageService>(gridService, args);
//server.AddStreamHandler(new PresenceServerPostHandler(m_PresenceService));
}
}
}

View File

@ -0,0 +1,105 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.IO;
using System.Net;
using System.Reflection;
using Nini.Config;
using log4net;
using OpenSim.Server.Base;
using OpenSim.Services.Interfaces;
using OpenSim.Framework.Servers.HttpServer;
using OpenSim.Server.Handlers.Base;
namespace OpenSim.Server.Handlers.MapImage
{
public class MapGetServiceConnector : ServiceConnector
{
private IMapImageService m_MapService;
private string m_ConfigName = "MapImageService";
public MapGetServiceConnector(IConfigSource config, IHttpServer server, string configName) :
base(config, server, configName)
{
IConfig serverConfig = config.Configs[m_ConfigName];
if (serverConfig == null)
throw new Exception(String.Format("No section {0} in config file", m_ConfigName));
string gridService = serverConfig.GetString("LocalServiceModule",
String.Empty);
if (gridService == String.Empty)
throw new Exception("No LocalServiceModule in config file");
Object[] args = new Object[] { config };
m_MapService = ServerUtils.LoadPlugin<IMapImageService>(gridService, args);
server.AddStreamHandler(new MapServerGetHandler(m_MapService));
}
}
class MapServerGetHandler : BaseStreamHandler
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private IMapImageService m_MapService;
public MapServerGetHandler(IMapImageService service) :
base("GET", "/map")
{
m_MapService = service;
}
public override byte[] Handle(string path, Stream request, OSHttpRequest httpRequest, OSHttpResponse httpResponse)
{
m_log.DebugFormat("[MAP SERVICE IMAGE HANDLER]: retrieving {0}", path);
byte[] result = new byte[0];
string format = string.Empty;
result = m_MapService.GetMapTile(path.Trim('/'), out format);
if (result.Length > 0)
{
httpResponse.StatusCode = (int)HttpStatusCode.OK;
if (format.Equals("png"))
httpResponse.ContentType = "image/png";
else if (format.Equals("jpg") || format.Equals("jpeg"))
httpResponse.ContentType = "image/jpeg";
}
else
{
httpResponse.StatusCode = (int)HttpStatusCode.NotFound;
httpResponse.ContentType = "text/plain";
}
return result;
}
}
}

View File

@ -0,0 +1,158 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using log4net;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Reflection;
using Nini.Config;
using OpenSim.Framework;
using OpenSim.Framework.Console;
using OpenSim.Framework.Communications;
using OpenSim.Services.Interfaces;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
namespace OpenSim.Services.Connectors
{
public class MapImageServicesConnector : IMapImageService
{
private static readonly ILog m_log =
LogManager.GetLogger(
MethodBase.GetCurrentMethod().DeclaringType);
private string m_ServerURI = String.Empty;
private IImprovedAssetCache m_Cache = null;
public MapImageServicesConnector()
{
}
public MapImageServicesConnector(string serverURI)
{
m_ServerURI = serverURI.TrimEnd('/');
}
public MapImageServicesConnector(IConfigSource source)
{
Initialise(source);
}
public virtual void Initialise(IConfigSource source)
{
IConfig config = source.Configs["MapImageService"];
if (config == null)
{
m_log.Error("[MAP IMAGE CONNECTOR]: MapImageService missing");
throw new Exception("MapImage connector init error");
}
string serviceURI = config.GetString("MapImageServerURI",
String.Empty);
if (serviceURI == String.Empty)
{
m_log.Error("[MAP IMAGE CONNECTOR]: No Server URI named in section MapImageService");
throw new Exception("MapImage connector init error");
}
m_ServerURI = serviceURI;
}
public bool AddMapTile(int x, int y, byte[] pngData, out string reason)
{
List<MultipartForm.Element> postParameters = new List<MultipartForm.Element>()
{
new MultipartForm.Parameter("X", x.ToString()),
new MultipartForm.Parameter("Y", y.ToString()),
new MultipartForm.File("Tile", "tile.png", "image/png", pngData)
};
reason = string.Empty;
int tickstart = Util.EnvironmentTickCount();
// Make the remote storage request
try
{
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(m_ServerURI);
request.Timeout = 20000;
request.ReadWriteTimeout = 5000;
using (HttpWebResponse response = MultipartForm.Post(request, postParameters))
{
using (Stream responseStream = response.GetResponseStream())
{
string responseStr = responseStream.GetStreamString();
OSD responseOSD = OSDParser.Deserialize(responseStr);
if (responseOSD.Type == OSDType.Map)
{
OSDMap responseMap = (OSDMap)responseOSD;
if (responseMap["Success"].AsBoolean())
return true;
reason = "Upload failed: " + responseMap["Message"].AsString();
}
else
{
reason = "Response format was invalid:\n" + responseStr;
}
}
}
}
catch (WebException we)
{
reason = we.Message;
if (we.Status == WebExceptionStatus.ProtocolError)
{
HttpWebResponse webResponse = (HttpWebResponse)we.Response;
reason = String.Format("[{0}] {1}", webResponse.StatusCode, webResponse.StatusDescription);
}
}
catch (Exception ex)
{
reason = ex.Message;
}
finally
{
// This just dumps a warning for any operation that takes more than 100 ms
int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
m_log.DebugFormat("[MAP IMAGE CONNECTOR]: map tile uploaded in {0}ms", tickdiff);
}
return false;
}
public byte[] GetMapTile(string fileName, out string format)
{
format = string.Empty;
new Exception("GetMapTile method not Implemented");
return null;
}
}
}

View File

@ -31,8 +31,10 @@ using OpenMetaverse;
namespace OpenSim.Services.Interfaces namespace OpenSim.Services.Interfaces
{ {
public interface IMapService public interface IMapImageService
{ {
List<MapBlockData> GetMapBlocks(UUID scopeID, int minX, int minY, int maxX, int maxY); //List<MapBlockData> GetMapBlocks(UUID scopeID, int minX, int minY, int maxX, int maxY);
bool AddMapTile(int x, int y, byte[] imageData, out string reason);
byte[] GetMapTile(string fileName, out string format);
} }
} }

View File

@ -0,0 +1,295 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Net;
using System.Reflection;
using Nini.Config;
using log4net;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Framework.Console;
using OpenSim.Services.Interfaces;
namespace OpenSim.Services.MapImageService
{
public class MapImageService : IMapImageService
{
private static readonly ILog m_log =
LogManager.GetLogger(
MethodBase.GetCurrentMethod().DeclaringType);
private const int ZOOM_LEVELS = 8;
private const int IMAGE_WIDTH = 256;
private const int HALF_WIDTH = 128;
private const int JPEG_QUALITY = 80;
private static string m_TilesStoragePath = "maptiles";
private static object m_Sync = new object();
private static bool m_Initialized = false;
private static string m_WaterTileFile = string.Empty;
private static Color m_Watercolor = Color.FromArgb(29, 71, 95);
public MapImageService(IConfigSource config)
{
if (!m_Initialized)
{
m_Initialized = true;
m_log.Debug("[MAP IMAGE SERVICE]: Starting MapImage service");
IConfig serviceConfig = config.Configs["MapImageService"];
if (serviceConfig != null)
{
m_TilesStoragePath = serviceConfig.GetString("TilesStoragePath", m_TilesStoragePath);
if (!Directory.Exists(m_TilesStoragePath))
Directory.CreateDirectory(m_TilesStoragePath);
m_WaterTileFile = Path.Combine(m_TilesStoragePath, "water.jpg");
if (!File.Exists(m_WaterTileFile))
{
Bitmap waterTile = new Bitmap(IMAGE_WIDTH, IMAGE_WIDTH);
FillImage(waterTile, m_Watercolor);
waterTile.Save(m_WaterTileFile);
}
}
}
}
#region IMapImageService
public bool AddMapTile(int x, int y, byte[] imageData, out string reason)
{
reason = string.Empty;
string fileName = GetFileName(1, x, y);
lock (m_Sync)
{
try
{
using (FileStream f = File.Open(fileName, FileMode.OpenOrCreate, FileAccess.Write))
f.Write(imageData, 0, imageData.Length);
}
catch (Exception e)
{
m_log.WarnFormat("[MAP IMAGE SERVICE]: Unable to save image file {0}: {1}", fileName, e);
reason = e.Message;
return false;
}
// Also save in png format?
// Stitch seven more aggregate tiles together
for (uint zoomLevel = 2; zoomLevel <= ZOOM_LEVELS; zoomLevel++)
{
// Calculate the width (in full resolution tiles) and bottom-left
// corner of the current zoom level
int width = (int)Math.Pow(2, (double)(zoomLevel - 1));
int x1 = x - (x % width);
int y1 = y - (y % width);
if (!CreateTile(zoomLevel, x1, y1))
{
m_log.WarnFormat("[MAP IMAGE SERVICE]: Unable to create tile for {0} at zoom level {1}", fileName, zoomLevel);
reason = string.Format("Map tile at zoom level {0} failed", zoomLevel);
return false;
}
}
}
return true;
}
public byte[] GetMapTile(string fileName, out string format)
{
format = "jpg";
string fullName = Path.Combine(m_TilesStoragePath, fileName);
if (File.Exists(fullName))
{
format = Path.GetExtension(fileName).ToLower();
m_log.DebugFormat("[MAP IMAGE SERVICE]: Found file {0}, extension {1}", fileName, format);
return File.ReadAllBytes(fullName);
}
else if (File.Exists(m_WaterTileFile))
{
m_log.DebugFormat("[MAP IMAGE SERVICE]: File not found {0}, sending water", fileName);
return File.ReadAllBytes(m_WaterTileFile);
}
else
{
m_log.DebugFormat("[MAP IMAGE SERVICE]: unable to get file {0}", fileName);
return new byte[0];
}
}
#endregion
private string GetFileName(uint zoomLevel, int x, int y)
{
string extension = "jpg";
return Path.Combine(m_TilesStoragePath, string.Format("map-{0}-{1}-{2}-objects.{3}", zoomLevel, x, y, extension));
}
private Bitmap GetInputTileImage(string fileName)
{
try
{
if (File.Exists(fileName))
return new Bitmap(fileName);
}
catch (Exception e)
{
m_log.WarnFormat("[MAP IMAGE SERVICE]: Unable to read image data from {0}: {1}", fileName, e);
}
return null;
}
private Bitmap GetOutputTileImage(string fileName)
{
try
{
if (File.Exists(fileName))
return new Bitmap(fileName);
else
{
// Create a new output tile with a transparent background
Bitmap bm = new Bitmap(IMAGE_WIDTH, IMAGE_WIDTH);
bm.MakeTransparent();
return bm;
}
}
catch (Exception e)
{
m_log.WarnFormat("[MAP IMAGE SERVICE]: Unable to read image data from {0}: {1}", fileName, e);
}
return null;
}
private bool CreateTile(uint zoomLevel, int x, int y)
{
m_log.DebugFormat("[MAP IMAGE SERVICE]: Create tile for {0} {1}, zoom {2}", x, y, zoomLevel);
int prevWidth = (int)Math.Pow(2, (double)zoomLevel - 2);
int thisWidth = (int)Math.Pow(2, (double)zoomLevel - 1);
// Convert x and y to the bottom left tile for this zoom level
int xIn = x - (x % prevWidth);
int yIn = y - (y % prevWidth);
// Convert x and y to the bottom left tile for the next zoom level
int xOut = x - (x % thisWidth);
int yOut = y - (y % thisWidth);
// Try to open the four input tiles from the previous zoom level
Bitmap inputBL = GetInputTileImage(GetFileName(zoomLevel - 1, xIn, yIn));
Bitmap inputBR = GetInputTileImage(GetFileName(zoomLevel - 1, xIn + prevWidth, yIn));
Bitmap inputTL = GetInputTileImage(GetFileName(zoomLevel - 1, xIn, yIn + prevWidth));
Bitmap inputTR = GetInputTileImage(GetFileName(zoomLevel - 1, xIn + prevWidth, yIn + prevWidth));
// Open the output tile (current zoom level)
string outputFile = GetFileName(zoomLevel, xOut, yOut);
Bitmap output = GetOutputTileImage(outputFile);
if (output == null)
return false;
FillImage(output, m_Watercolor);
if (inputBL != null)
{
ImageCopyResampled(output, inputBL, 0, HALF_WIDTH, 0, 0);
inputBL.Dispose();
}
if (inputBR != null)
{
ImageCopyResampled(output, inputBR, HALF_WIDTH, HALF_WIDTH, 0, 0);
inputBR.Dispose();
}
if (inputTL != null)
{
ImageCopyResampled(output, inputTL, 0, 0, 0, 0);
inputTL.Dispose();
}
if (inputTR != null)
{
ImageCopyResampled(output, inputTR, HALF_WIDTH, 0, 0, 0);
inputTR.Dispose();
}
// Write the modified output
try
{
using (Bitmap final = new Bitmap(output))
{
output.Dispose();
final.Save(outputFile);
}
}
catch (Exception e)
{
m_log.WarnFormat("[MAP IMAGE SERVICE]: Oops on saving {0} {1}", outputFile, e);
}
// Save also as png?
return true;
}
#region Image utilities
private void FillImage(Bitmap bm, Color c)
{
for (int x = 0; x < bm.Width; x++)
for (int y = 0; y < bm.Height; y++)
bm.SetPixel(x, y, c);
}
private void ImageCopyResampled(Bitmap output, Bitmap input, int destX, int destY, int srcX, int srcY)
{
int resamplingRateX = 2; // (input.Width - srcX) / (output.Width - destX);
int resamplingRateY = 2; // (input.Height - srcY) / (output.Height - destY);
for (int x = destX; x < destX + HALF_WIDTH; x++)
for (int y = destY; y < destY + HALF_WIDTH; y++)
{
Color p = input.GetPixel(srcX + (x - destX) * resamplingRateX, srcY + (y - destY) * resamplingRateY);
output.SetPixel(x, y, p);
}
}
#endregion
}
}

View File

@ -17,10 +17,12 @@
AvatarServices = "LocalAvatarServicesConnector" AvatarServices = "LocalAvatarServicesConnector"
EntityTransferModule = "BasicEntityTransferModule" EntityTransferModule = "BasicEntityTransferModule"
InventoryAccessModule = "BasicInventoryAccessModule" InventoryAccessModule = "BasicInventoryAccessModule"
MapImageService = "MapImageServiceModule"
LibraryModule = true LibraryModule = true
LLLoginServiceInConnector = true LLLoginServiceInConnector = true
GridInfoServiceInConnector = true GridInfoServiceInConnector = true
MapImageServiceInConnector = true
[Profile] [Profile]
Module = "BasicProfileModule" Module = "BasicProfileModule"
@ -91,6 +93,11 @@
WelcomeMessage = "Welcome, Avatar!" WelcomeMessage = "Welcome, Avatar!"
[MapImageService]
LocalServiceModule = "OpenSim.Services.MapImageService.dll:MapImageService"
; in minutes
RefreshTime = 60
;; This should always be the very last thing on this file ;; This should always be the very last thing on this file
[Includes] [Includes]
Include-Common = "config-include/StandaloneCommon.ini" Include-Common = "config-include/StandaloneCommon.ini"

View File

@ -99,6 +99,9 @@
SRV_FriendsServerURI = "http://127.0.0.1:9000" SRV_FriendsServerURI = "http://127.0.0.1:9000"
SRV_IMServerURI = "http://127.0.0.1:9000" SRV_IMServerURI = "http://127.0.0.1:9000"
;; For Viewer 2
MapTileURL = "http://127.0.0.1:9000"
;; Regular expressions for controlling which client versions are accepted/denied. ;; Regular expressions for controlling which client versions are accepted/denied.
;; An empty string means nothing is checked. ;; An empty string means nothing is checked.
;; ;;

View File

@ -18,9 +18,10 @@
GridUserServices = "LocalGridUserServicesConnector" GridUserServices = "LocalGridUserServicesConnector"
SimulationServices = "RemoteSimulationConnectorModule" SimulationServices = "RemoteSimulationConnectorModule"
AvatarServices = "LocalAvatarServicesConnector" AvatarServices = "LocalAvatarServicesConnector"
MapImageService = "MapImageServiceModule"
EntityTransferModule = "HGEntityTransferModule" EntityTransferModule = "HGEntityTransferModule"
InventoryAccessModule = "HGInventoryAccessModule" InventoryAccessModule = "HGInventoryAccessModule"
FriendsModule = "HGFriendsModule" FriendsModule = "HGFriendsModule"
InventoryServiceInConnector = true InventoryServiceInConnector = true
AssetServiceInConnector = true AssetServiceInConnector = true
@ -31,6 +32,7 @@
GridInfoServiceInConnector = true GridInfoServiceInConnector = true
AuthenticationServiceInConnector = true AuthenticationServiceInConnector = true
SimulationServiceInConnector = true SimulationServiceInConnector = true
MapImageServiceInConnector = true
[Profile] [Profile]
Module = "BasicProfileModule" Module = "BasicProfileModule"
@ -116,7 +118,12 @@
GridService = "OpenSim.Services.GridService.dll:GridService" GridService = "OpenSim.Services.GridService.dll:GridService"
AvatarService = "OpenSim.Services.AvatarService.dll:AvatarService" AvatarService = "OpenSim.Services.AvatarService.dll:AvatarService"
FriendsService = "OpenSim.Services.FriendsService.dll:FriendsService" FriendsService = "OpenSim.Services.FriendsService.dll:FriendsService"
[MapImageService]
LocalServiceModule = "OpenSim.Services.MapImageService.dll:MapImageService"
; in minutes
RefreshTime = 60
[GatekeeperService] [GatekeeperService]
LocalServiceModule = "OpenSim.Services.HypergridService.dll:GatekeeperService" LocalServiceModule = "OpenSim.Services.HypergridService.dll:GatekeeperService"
;; for the service ;; for the service

View File

@ -1269,6 +1269,36 @@
</Files> </Files>
</Project> </Project>
<Project frameworkVersion="v3_5" name="OpenSim.Services.MapImageService" path="OpenSim/Services/MapImageService" type="Library">
<Configuration name="Debug">
<Options>
<OutputPath>../../../bin/</OutputPath>
</Options>
</Configuration>
<Configuration name="Release">
<Options>
<OutputPath>../../../bin/</OutputPath>
</Options>
</Configuration>
<ReferencePath>../../../bin/</ReferencePath>
<Reference name="System"/>
<Reference name="System.Drawing"/>
<Reference name="OpenMetaverseTypes" path="../../../bin/"/>
<Reference name="OpenMetaverse" path="../../../bin/"/>
<Reference name="OpenSim.Framework"/>
<Reference name="OpenSim.Framework.Console"/>
<Reference name="OpenSim.Framework.Servers.HttpServer"/>
<Reference name="OpenSim.Services.Interfaces"/>
<Reference name="OpenSim.Services.Base"/>
<Reference name="Nini" path="../../../bin/"/>
<Reference name="log4net" path="../../../bin/"/>
<Files>
<Match pattern="*.cs" recurse="true"/>
</Files>
</Project>
<Project frameworkVersion="v3_5" name="OpenSim.Server.Handlers" path="OpenSim/Server/Handlers" type="Library"> <Project frameworkVersion="v3_5" name="OpenSim.Server.Handlers" path="OpenSim/Server/Handlers" type="Library">
<Configuration name="Debug"> <Configuration name="Debug">
<Options> <Options>