Address map lag issue seen with non-avination viewers
parent
470019b52a
commit
d3b778ebbe
|
@ -86,90 +86,93 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||||
|
|
||||||
private void OnMapNameRequest(IClientAPI remoteClient, string mapName, uint flags)
|
private void OnMapNameRequest(IClientAPI remoteClient, string mapName, uint flags)
|
||||||
{
|
{
|
||||||
if (mapName.Length < 2)
|
Util.FireAndForget(x =>
|
||||||
{
|
{
|
||||||
remoteClient.SendAlertMessage("Use a search string with at least 2 characters");
|
if (mapName.Length < 2)
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//m_log.DebugFormat("MAP NAME=({0})", mapName);
|
|
||||||
|
|
||||||
// Hack to get around the fact that ll V3 now drops the port from the
|
|
||||||
// map name. See https://jira.secondlife.com/browse/VWR-28570
|
|
||||||
//
|
|
||||||
// Caller, use this magic form instead:
|
|
||||||
// secondlife://http|!!mygrid.com|8002|Region+Name/128/128
|
|
||||||
// or url encode if possible.
|
|
||||||
// the hacks we do with this viewer...
|
|
||||||
//
|
|
||||||
string mapNameOrig = mapName;
|
|
||||||
if (mapName.Contains("|"))
|
|
||||||
mapName = mapName.Replace('|', ':');
|
|
||||||
if (mapName.Contains("+"))
|
|
||||||
mapName = mapName.Replace('+', ' ');
|
|
||||||
if (mapName.Contains("!"))
|
|
||||||
mapName = mapName.Replace('!', '/');
|
|
||||||
|
|
||||||
// try to fetch from GridServer
|
|
||||||
List<GridRegion> regionInfos = m_scene.GridService.GetRegionsByName(m_scene.RegionInfo.ScopeID, mapName, 20);
|
|
||||||
// if (regionInfos.Count == 0)
|
|
||||||
// remoteClient.SendAlertMessage("Hyperlink could not be established.");
|
|
||||||
|
|
||||||
//m_log.DebugFormat("[MAPSEARCHMODULE]: search {0} returned {1} regions", mapName, regionInfos.Count);
|
|
||||||
List<MapBlockData> blocks = new List<MapBlockData>();
|
|
||||||
|
|
||||||
MapBlockData data;
|
|
||||||
if (regionInfos.Count > 0)
|
|
||||||
{
|
|
||||||
foreach (GridRegion info in regionInfos)
|
|
||||||
{
|
{
|
||||||
data = new MapBlockData();
|
remoteClient.SendAlertMessage("Use a search string with at least 2 characters");
|
||||||
data.Agents = 0;
|
return;
|
||||||
data.Access = info.Access;
|
|
||||||
if (flags == 2) // V2 sends this
|
|
||||||
data.MapImageId = UUID.Zero;
|
|
||||||
else
|
|
||||||
data.MapImageId = info.TerrainImage;
|
|
||||||
// ugh! V2-3 is very sensitive about the result being
|
|
||||||
// exactly the same as the requested name
|
|
||||||
if (regionInfos.Count == 1 && mapNameOrig.Contains("|") || mapNameOrig.Contains("+"))
|
|
||||||
data.Name = mapNameOrig;
|
|
||||||
else
|
|
||||||
data.Name = info.RegionName;
|
|
||||||
data.RegionFlags = 0; // TODO not used?
|
|
||||||
data.WaterHeight = 0; // not used
|
|
||||||
data.X = (ushort)(info.RegionLocX / Constants.RegionSize);
|
|
||||||
data.Y = (ushort)(info.RegionLocY / Constants.RegionSize);
|
|
||||||
blocks.Add(data);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// final block, closing the search result
|
//m_log.DebugFormat("MAP NAME=({0})", mapName);
|
||||||
data = new MapBlockData();
|
|
||||||
data.Agents = 0;
|
|
||||||
data.Access = 255;
|
|
||||||
data.MapImageId = UUID.Zero;
|
|
||||||
data.Name = mapName;
|
|
||||||
data.RegionFlags = 0;
|
|
||||||
data.WaterHeight = 0; // not used
|
|
||||||
data.X = 0;
|
|
||||||
data.Y = 0;
|
|
||||||
blocks.Add(data);
|
|
||||||
|
|
||||||
// flags are agent flags sent from the viewer.
|
// Hack to get around the fact that ll V3 now drops the port from the
|
||||||
// they have different values depending on different viewers, apparently
|
// map name. See https://jira.secondlife.com/browse/VWR-28570
|
||||||
remoteClient.SendMapBlock(blocks, flags);
|
//
|
||||||
|
// Caller, use this magic form instead:
|
||||||
|
// secondlife://http|!!mygrid.com|8002|Region+Name/128/128
|
||||||
|
// or url encode if possible.
|
||||||
|
// the hacks we do with this viewer...
|
||||||
|
//
|
||||||
|
string mapNameOrig = mapName;
|
||||||
|
if (mapName.Contains("|"))
|
||||||
|
mapName = mapName.Replace('|', ':');
|
||||||
|
if (mapName.Contains("+"))
|
||||||
|
mapName = mapName.Replace('+', ' ');
|
||||||
|
if (mapName.Contains("!"))
|
||||||
|
mapName = mapName.Replace('!', '/');
|
||||||
|
|
||||||
|
// try to fetch from GridServer
|
||||||
|
List<GridRegion> regionInfos = m_scene.GridService.GetRegionsByName(m_scene.RegionInfo.ScopeID, mapName, 20);
|
||||||
|
// if (regionInfos.Count == 0)
|
||||||
|
// remoteClient.SendAlertMessage("Hyperlink could not be established.");
|
||||||
|
|
||||||
// send extra user messages for V3
|
//m_log.DebugFormat("[MAPSEARCHMODULE]: search {0} returned {1} regions", mapName, regionInfos.Count);
|
||||||
// because the UI is very confusing
|
List<MapBlockData> blocks = new List<MapBlockData>();
|
||||||
// while we don't fix the hard-coded urls
|
|
||||||
if (flags == 2)
|
MapBlockData data;
|
||||||
{
|
if (regionInfos.Count > 0)
|
||||||
if (regionInfos.Count == 0)
|
{
|
||||||
remoteClient.SendAgentAlertMessage("No regions found with that name.", true);
|
foreach (GridRegion info in regionInfos)
|
||||||
else if (regionInfos.Count == 1)
|
{
|
||||||
remoteClient.SendAgentAlertMessage("Region found!", false);
|
data = new MapBlockData();
|
||||||
}
|
data.Agents = 0;
|
||||||
|
data.Access = info.Access;
|
||||||
|
if (flags == 2) // V2 sends this
|
||||||
|
data.MapImageId = UUID.Zero;
|
||||||
|
else
|
||||||
|
data.MapImageId = info.TerrainImage;
|
||||||
|
// ugh! V2-3 is very sensitive about the result being
|
||||||
|
// exactly the same as the requested name
|
||||||
|
if (regionInfos.Count == 1 && mapNameOrig.Contains("|") || mapNameOrig.Contains("+"))
|
||||||
|
data.Name = mapNameOrig;
|
||||||
|
else
|
||||||
|
data.Name = info.RegionName;
|
||||||
|
data.RegionFlags = 0; // TODO not used?
|
||||||
|
data.WaterHeight = 0; // not used
|
||||||
|
data.X = (ushort)(info.RegionLocX / Constants.RegionSize);
|
||||||
|
data.Y = (ushort)(info.RegionLocY / Constants.RegionSize);
|
||||||
|
blocks.Add(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// final block, closing the search result
|
||||||
|
data = new MapBlockData();
|
||||||
|
data.Agents = 0;
|
||||||
|
data.Access = 255;
|
||||||
|
data.MapImageId = UUID.Zero;
|
||||||
|
data.Name = mapName;
|
||||||
|
data.RegionFlags = 0;
|
||||||
|
data.WaterHeight = 0; // not used
|
||||||
|
data.X = 0;
|
||||||
|
data.Y = 0;
|
||||||
|
blocks.Add(data);
|
||||||
|
|
||||||
|
// flags are agent flags sent from the viewer.
|
||||||
|
// they have different values depending on different viewers, apparently
|
||||||
|
remoteClient.SendMapBlock(blocks, flags);
|
||||||
|
|
||||||
|
// send extra user messages for V3
|
||||||
|
// because the UI is very confusing
|
||||||
|
// while we don't fix the hard-coded urls
|
||||||
|
if (flags == 2)
|
||||||
|
{
|
||||||
|
if (regionInfos.Count == 0)
|
||||||
|
remoteClient.SendAgentAlertMessage("No regions found with that name.", true);
|
||||||
|
else if (regionInfos.Count == 1)
|
||||||
|
remoteClient.SendAgentAlertMessage("Region found!", false);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// private Scene GetClientScene(IClientAPI client)
|
// private Scene GetClientScene(IClientAPI client)
|
||||||
|
|
|
@ -63,7 +63,8 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||||
private static readonly UUID STOP_UUID = UUID.Random();
|
private static readonly UUID STOP_UUID = UUID.Random();
|
||||||
private static readonly string m_mapLayerPath = "0001/";
|
private static readonly string m_mapLayerPath = "0001/";
|
||||||
|
|
||||||
private OpenSim.Framework.BlockingQueue<MapRequestState> requests = new OpenSim.Framework.BlockingQueue<MapRequestState>();
|
private ManualResetEvent queueEvent = new ManualResetEvent(false);
|
||||||
|
private Queue<MapRequestState> requests = new Queue<MapRequestState>();
|
||||||
|
|
||||||
protected Scene m_scene;
|
protected Scene m_scene;
|
||||||
private List<MapBlockData> cachedMapBlocks = new List<MapBlockData>();
|
private List<MapBlockData> cachedMapBlocks = new List<MapBlockData>();
|
||||||
|
@ -71,7 +72,6 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||||
private int blacklistTimeout = 10*60*1000; // 10 minutes
|
private int blacklistTimeout = 10*60*1000; // 10 minutes
|
||||||
private byte[] myMapImageJPEG;
|
private byte[] myMapImageJPEG;
|
||||||
protected volatile bool m_Enabled = false;
|
protected volatile bool m_Enabled = false;
|
||||||
private Dictionary<UUID, MapRequestState> m_openRequests = new Dictionary<UUID, MapRequestState>();
|
|
||||||
private Dictionary<string, int> m_blacklistedurls = new Dictionary<string, int>();
|
private Dictionary<string, int> m_blacklistedurls = new Dictionary<string, int>();
|
||||||
private Dictionary<ulong, int> m_blacklistedregions = new Dictionary<ulong, int>();
|
private Dictionary<ulong, int> m_blacklistedregions = new Dictionary<ulong, int>();
|
||||||
private Dictionary<ulong, string> m_cachedRegionMapItemsAddress = new Dictionary<ulong, string>();
|
private Dictionary<ulong, string> m_cachedRegionMapItemsAddress = new Dictionary<ulong, string>();
|
||||||
|
@ -368,7 +368,11 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||||
st.itemtype=0;
|
st.itemtype=0;
|
||||||
st.regionhandle=0;
|
st.regionhandle=0;
|
||||||
|
|
||||||
requests.Enqueue(st);
|
lock (requests)
|
||||||
|
{
|
||||||
|
queueEvent.Set();
|
||||||
|
requests.Enqueue(st);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void HandleMapItemRequest(IClientAPI remoteClient, uint flags,
|
public virtual void HandleMapItemRequest(IClientAPI remoteClient, uint flags,
|
||||||
|
@ -519,12 +523,26 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void process()
|
public void process()
|
||||||
{
|
{
|
||||||
const int MAX_ASYNC_REQUESTS = 20;
|
const int MAX_ASYNC_REQUESTS = 5;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
MapRequestState st = requests.Dequeue(1000);
|
MapRequestState st = new MapRequestState();
|
||||||
|
bool valid = false;
|
||||||
|
queueEvent.WaitOne();
|
||||||
|
lock (requests)
|
||||||
|
{
|
||||||
|
if (requests.Count > 0)
|
||||||
|
{
|
||||||
|
st = requests.Dequeue();
|
||||||
|
valid = true;
|
||||||
|
}
|
||||||
|
if (requests.Count == 0)
|
||||||
|
queueEvent.Reset();
|
||||||
|
}
|
||||||
|
if (!valid)
|
||||||
|
continue;
|
||||||
|
|
||||||
// end gracefully
|
// end gracefully
|
||||||
if (st.agentID == STOP_UUID)
|
if (st.agentID == STOP_UUID)
|
||||||
|
@ -541,14 +559,11 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||||
|
|
||||||
if (dorequest && !m_blacklistedregions.ContainsKey(st.regionhandle))
|
if (dorequest && !m_blacklistedregions.ContainsKey(st.regionhandle))
|
||||||
{
|
{
|
||||||
while (nAsyncRequests >= MAX_ASYNC_REQUESTS) // hit the break
|
// while (nAsyncRequests >= MAX_ASYNC_REQUESTS) // hit the break
|
||||||
Thread.Sleep(80);
|
// Thread.Sleep(500);
|
||||||
|
|
||||||
RequestMapItemsDelegate d = RequestMapItemsAsync;
|
|
||||||
d.BeginInvoke(st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle, RequestMapItemsCompleted, null);
|
|
||||||
//OSDMap response = RequestMapItemsAsync(st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle);
|
|
||||||
//RequestMapItemsCompleted(response);
|
|
||||||
Interlocked.Increment(ref nAsyncRequests);
|
Interlocked.Increment(ref nAsyncRequests);
|
||||||
|
RequestMapItemsAsync(st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -570,110 +585,10 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||||
/// <param name="state"></param>
|
/// <param name="state"></param>
|
||||||
public void EnqueueMapItemRequest(MapRequestState state)
|
public void EnqueueMapItemRequest(MapRequestState state)
|
||||||
{
|
{
|
||||||
requests.Enqueue(state);
|
lock (requests)
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sends the mapitem response to the IClientAPI
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="response">The OSDMap Response for the mapitem</param>
|
|
||||||
private void RequestMapItemsCompleted(IAsyncResult iar)
|
|
||||||
{
|
|
||||||
AsyncResult result = (AsyncResult)iar;
|
|
||||||
RequestMapItemsDelegate icon = (RequestMapItemsDelegate)result.AsyncDelegate;
|
|
||||||
|
|
||||||
OSDMap response = (OSDMap)icon.EndInvoke(iar);
|
|
||||||
|
|
||||||
Interlocked.Decrement(ref nAsyncRequests);
|
|
||||||
|
|
||||||
if (!response.ContainsKey("requestID"))
|
|
||||||
return;
|
|
||||||
|
|
||||||
UUID requestID = response["requestID"].AsUUID();
|
|
||||||
|
|
||||||
if (requestID != UUID.Zero)
|
|
||||||
{
|
{
|
||||||
MapRequestState mrs = new MapRequestState();
|
queueEvent.Set();
|
||||||
mrs.agentID = UUID.Zero;
|
requests.Enqueue(state);
|
||||||
lock (m_openRequests)
|
|
||||||
{
|
|
||||||
if (m_openRequests.ContainsKey(requestID))
|
|
||||||
{
|
|
||||||
mrs = m_openRequests[requestID];
|
|
||||||
m_openRequests.Remove(requestID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mrs.agentID != UUID.Zero)
|
|
||||||
{
|
|
||||||
ScenePresence av = null;
|
|
||||||
m_scene.TryGetScenePresence(mrs.agentID, out av);
|
|
||||||
if (av != null)
|
|
||||||
{
|
|
||||||
if (response.ContainsKey(mrs.itemtype.ToString()))
|
|
||||||
{
|
|
||||||
List<mapItemReply> returnitems = new List<mapItemReply>();
|
|
||||||
OSDArray itemarray = (OSDArray)response[mrs.itemtype.ToString()];
|
|
||||||
for (int i = 0; i < itemarray.Count; i++)
|
|
||||||
{
|
|
||||||
OSDMap mapitem = (OSDMap)itemarray[i];
|
|
||||||
mapItemReply mi = new mapItemReply();
|
|
||||||
mi.x = (uint)mapitem["X"].AsInteger();
|
|
||||||
mi.y = (uint)mapitem["Y"].AsInteger();
|
|
||||||
mi.id = mapitem["ID"].AsUUID();
|
|
||||||
mi.Extra = mapitem["Extra"].AsInteger();
|
|
||||||
mi.Extra2 = mapitem["Extra2"].AsInteger();
|
|
||||||
mi.name = mapitem["Name"].AsString();
|
|
||||||
returnitems.Add(mi);
|
|
||||||
}
|
|
||||||
av.ControllingClient.SendMapItemReply(returnitems.ToArray(), mrs.itemtype, mrs.flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Service 7 (MAP_ITEM_LAND_FOR_SALE)
|
|
||||||
uint itemtype = 7;
|
|
||||||
|
|
||||||
if (response.ContainsKey(itemtype.ToString()))
|
|
||||||
{
|
|
||||||
List<mapItemReply> returnitems = new List<mapItemReply>();
|
|
||||||
OSDArray itemarray = (OSDArray)response[itemtype.ToString()];
|
|
||||||
for (int i = 0; i < itemarray.Count; i++)
|
|
||||||
{
|
|
||||||
OSDMap mapitem = (OSDMap)itemarray[i];
|
|
||||||
mapItemReply mi = new mapItemReply();
|
|
||||||
mi.x = (uint)mapitem["X"].AsInteger();
|
|
||||||
mi.y = (uint)mapitem["Y"].AsInteger();
|
|
||||||
mi.id = mapitem["ID"].AsUUID();
|
|
||||||
mi.Extra = mapitem["Extra"].AsInteger();
|
|
||||||
mi.Extra2 = mapitem["Extra2"].AsInteger();
|
|
||||||
mi.name = mapitem["Name"].AsString();
|
|
||||||
returnitems.Add(mi);
|
|
||||||
}
|
|
||||||
av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, mrs.flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Service 1 (MAP_ITEM_TELEHUB)
|
|
||||||
itemtype = 1;
|
|
||||||
|
|
||||||
if (response.ContainsKey(itemtype.ToString()))
|
|
||||||
{
|
|
||||||
List<mapItemReply> returnitems = new List<mapItemReply>();
|
|
||||||
OSDArray itemarray = (OSDArray)response[itemtype.ToString()];
|
|
||||||
for (int i = 0; i < itemarray.Count; i++)
|
|
||||||
{
|
|
||||||
OSDMap mapitem = (OSDMap)itemarray[i];
|
|
||||||
mapItemReply mi = new mapItemReply();
|
|
||||||
mi.x = (uint)mapitem["X"].AsInteger();
|
|
||||||
mi.y = (uint)mapitem["Y"].AsInteger();
|
|
||||||
mi.id = mapitem["ID"].AsUUID();
|
|
||||||
mi.Extra = mapitem["Extra"].AsInteger();
|
|
||||||
mi.Extra2 = mapitem["Extra2"].AsInteger();
|
|
||||||
mi.name = mapitem["Name"].AsString();
|
|
||||||
returnitems.Add(mi);
|
|
||||||
}
|
|
||||||
av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, mrs.flags);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -700,8 +615,6 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||||
EnqueueMapItemRequest(st);
|
EnqueueMapItemRequest(st);
|
||||||
}
|
}
|
||||||
|
|
||||||
private delegate OSDMap RequestMapItemsDelegate(UUID id, uint flags,
|
|
||||||
uint EstateID, bool godlike, uint itemtype, ulong regionhandle);
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Does the actual remote mapitem request
|
/// Does the actual remote mapitem request
|
||||||
/// This should be called from an asynchronous thread
|
/// This should be called from an asynchronous thread
|
||||||
|
@ -716,7 +629,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||||
/// <param name="itemtype">passed in from packet</param>
|
/// <param name="itemtype">passed in from packet</param>
|
||||||
/// <param name="regionhandle">Region we're looking up</param>
|
/// <param name="regionhandle">Region we're looking up</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private OSDMap RequestMapItemsAsync(UUID id, uint flags,
|
private void RequestMapItemsAsync(UUID id, uint flags,
|
||||||
uint EstateID, bool godlike, uint itemtype, ulong regionhandle)
|
uint EstateID, bool godlike, uint itemtype, ulong regionhandle)
|
||||||
{
|
{
|
||||||
// m_log.DebugFormat("[WORLDMAP]: RequestMapItemsAsync; region handle: {0} {1}", regionhandle, itemtype);
|
// m_log.DebugFormat("[WORLDMAP]: RequestMapItemsAsync; region handle: {0} {1}", regionhandle, itemtype);
|
||||||
|
@ -739,7 +652,10 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||||
}
|
}
|
||||||
|
|
||||||
if (blacklisted)
|
if (blacklisted)
|
||||||
return new OSDMap();
|
{
|
||||||
|
Interlocked.Decrement(ref nAsyncRequests);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
UUID requestID = UUID.Random();
|
UUID requestID = UUID.Random();
|
||||||
lock (m_cachedRegionMapItemsAddress)
|
lock (m_cachedRegionMapItemsAddress)
|
||||||
|
@ -747,6 +663,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||||
if (m_cachedRegionMapItemsAddress.ContainsKey(regionhandle))
|
if (m_cachedRegionMapItemsAddress.ContainsKey(regionhandle))
|
||||||
httpserver = m_cachedRegionMapItemsAddress[regionhandle];
|
httpserver = m_cachedRegionMapItemsAddress[regionhandle];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (httpserver.Length == 0)
|
if (httpserver.Length == 0)
|
||||||
{
|
{
|
||||||
uint x = 0, y = 0;
|
uint x = 0, y = 0;
|
||||||
|
@ -791,18 +708,10 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||||
|
|
||||||
// Can't find the http server
|
// Can't find the http server
|
||||||
if (httpserver.Length == 0 || blacklisted)
|
if (httpserver.Length == 0 || blacklisted)
|
||||||
return new OSDMap();
|
{
|
||||||
|
Interlocked.Decrement(ref nAsyncRequests);
|
||||||
MapRequestState mrs = new MapRequestState();
|
return;
|
||||||
mrs.agentID = id;
|
}
|
||||||
mrs.EstateID = EstateID;
|
|
||||||
mrs.flags = flags;
|
|
||||||
mrs.godlike = godlike;
|
|
||||||
mrs.itemtype=itemtype;
|
|
||||||
mrs.regionhandle = regionhandle;
|
|
||||||
|
|
||||||
lock (m_openRequests)
|
|
||||||
m_openRequests.Add(requestID, mrs);
|
|
||||||
|
|
||||||
WebRequest mapitemsrequest = null;
|
WebRequest mapitemsrequest = null;
|
||||||
try
|
try
|
||||||
|
@ -812,7 +721,8 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
m_log.DebugFormat("[WORLD MAP]: Access to {0} failed with {1}", httpserver, e);
|
m_log.DebugFormat("[WORLD MAP]: Access to {0} failed with {1}", httpserver, e);
|
||||||
return new OSDMap();
|
Interlocked.Decrement(ref nAsyncRequests);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mapitemsrequest.Method = "POST";
|
mapitemsrequest.Method = "POST";
|
||||||
|
@ -826,6 +736,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||||
OSDMap responseMap = new OSDMap();
|
OSDMap responseMap = new OSDMap();
|
||||||
responseMap["requestID"] = OSD.FromUUID(requestID);
|
responseMap["requestID"] = OSD.FromUUID(requestID);
|
||||||
|
|
||||||
|
return;
|
||||||
Stream os = null;
|
Stream os = null;
|
||||||
try
|
try
|
||||||
{ // send the Post
|
{ // send the Post
|
||||||
|
@ -837,7 +748,6 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||||
catch (WebException ex)
|
catch (WebException ex)
|
||||||
{
|
{
|
||||||
m_log.WarnFormat("[WORLD MAP]: Bad send on GetMapItems {0}", ex.Message);
|
m_log.WarnFormat("[WORLD MAP]: Bad send on GetMapItems {0}", ex.Message);
|
||||||
responseMap["connect"] = OSD.FromBoolean(false);
|
|
||||||
lock (m_blacklistedurls)
|
lock (m_blacklistedurls)
|
||||||
{
|
{
|
||||||
if (!m_blacklistedurls.ContainsKey(httpserver))
|
if (!m_blacklistedurls.ContainsKey(httpserver))
|
||||||
|
@ -846,13 +756,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||||
|
|
||||||
m_log.WarnFormat("[WORLD MAP]: Blacklisted {0}", httpserver);
|
m_log.WarnFormat("[WORLD MAP]: Blacklisted {0}", httpserver);
|
||||||
|
|
||||||
return responseMap;
|
Interlocked.Decrement(ref nAsyncRequests);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
m_log.DebugFormat("[WORLD MAP]: RequestMapItems failed for {0}", httpserver);
|
m_log.DebugFormat("[WORLD MAP]: RequestMapItems failed for {0}", httpserver);
|
||||||
responseMap["connect"] = OSD.FromBoolean(false);
|
Interlocked.Decrement(ref nAsyncRequests);
|
||||||
return responseMap;
|
return;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
@ -873,12 +784,12 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return new OSDMap();
|
Interlocked.Decrement(ref nAsyncRequests);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (WebException)
|
catch (WebException)
|
||||||
{
|
{
|
||||||
responseMap["connect"] = OSD.FromBoolean(false);
|
|
||||||
lock (m_blacklistedurls)
|
lock (m_blacklistedurls)
|
||||||
{
|
{
|
||||||
if (!m_blacklistedurls.ContainsKey(httpserver))
|
if (!m_blacklistedurls.ContainsKey(httpserver))
|
||||||
|
@ -887,19 +798,20 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||||
|
|
||||||
m_log.WarnFormat("[WORLD MAP]: Blacklisted {0}", httpserver);
|
m_log.WarnFormat("[WORLD MAP]: Blacklisted {0}", httpserver);
|
||||||
|
|
||||||
return responseMap;
|
Interlocked.Decrement(ref nAsyncRequests);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
m_log.DebugFormat("[WORLD MAP]: RequestMapItems failed for {0}", httpserver);
|
m_log.DebugFormat("[WORLD MAP]: RequestMapItems failed for {0}", httpserver);
|
||||||
responseMap["connect"] = OSD.FromBoolean(false);
|
|
||||||
lock (m_blacklistedregions)
|
lock (m_blacklistedregions)
|
||||||
{
|
{
|
||||||
if (!m_blacklistedregions.ContainsKey(regionhandle))
|
if (!m_blacklistedregions.ContainsKey(regionhandle))
|
||||||
m_blacklistedregions.Add(regionhandle, Environment.TickCount);
|
m_blacklistedregions.Add(regionhandle, Environment.TickCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
return responseMap;
|
Interlocked.Decrement(ref nAsyncRequests);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
@ -918,14 +830,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
m_log.InfoFormat("[WORLD MAP]: exception on parse of RequestMapItems reply from {0}: {1}", httpserver, ex.Message);
|
m_log.InfoFormat("[WORLD MAP]: exception on parse of RequestMapItems reply from {0}: {1}", httpserver, ex.Message);
|
||||||
responseMap["connect"] = OSD.FromBoolean(false);
|
|
||||||
lock (m_blacklistedregions)
|
lock (m_blacklistedregions)
|
||||||
{
|
{
|
||||||
if (!m_blacklistedregions.ContainsKey(regionhandle))
|
if (!m_blacklistedregions.ContainsKey(regionhandle))
|
||||||
m_blacklistedregions.Add(regionhandle, Environment.TickCount);
|
m_blacklistedregions.Add(regionhandle, Environment.TickCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
return responseMap;
|
Interlocked.Decrement(ref nAsyncRequests);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -939,7 +851,78 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return responseMap;
|
Interlocked.Decrement(ref nAsyncRequests);
|
||||||
|
|
||||||
|
if (id != UUID.Zero)
|
||||||
|
{
|
||||||
|
ScenePresence av = null;
|
||||||
|
m_scene.TryGetScenePresence(id, out av);
|
||||||
|
if (av != null)
|
||||||
|
{
|
||||||
|
if (responseMap.ContainsKey(itemtype.ToString()))
|
||||||
|
{
|
||||||
|
List<mapItemReply> returnitems = new List<mapItemReply>();
|
||||||
|
OSDArray itemarray = (OSDArray)responseMap[itemtype.ToString()];
|
||||||
|
for (int i = 0; i < itemarray.Count; i++)
|
||||||
|
{
|
||||||
|
OSDMap mapitem = (OSDMap)itemarray[i];
|
||||||
|
mapItemReply mi = new mapItemReply();
|
||||||
|
mi.x = (uint)mapitem["X"].AsInteger();
|
||||||
|
mi.y = (uint)mapitem["Y"].AsInteger();
|
||||||
|
mi.id = mapitem["ID"].AsUUID();
|
||||||
|
mi.Extra = mapitem["Extra"].AsInteger();
|
||||||
|
mi.Extra2 = mapitem["Extra2"].AsInteger();
|
||||||
|
mi.name = mapitem["Name"].AsString();
|
||||||
|
returnitems.Add(mi);
|
||||||
|
}
|
||||||
|
av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Service 7 (MAP_ITEM_LAND_FOR_SALE)
|
||||||
|
itemtype = 7;
|
||||||
|
|
||||||
|
if (responseMap.ContainsKey(itemtype.ToString()))
|
||||||
|
{
|
||||||
|
List<mapItemReply> returnitems = new List<mapItemReply>();
|
||||||
|
OSDArray itemarray = (OSDArray)responseMap[itemtype.ToString()];
|
||||||
|
for (int i = 0; i < itemarray.Count; i++)
|
||||||
|
{
|
||||||
|
OSDMap mapitem = (OSDMap)itemarray[i];
|
||||||
|
mapItemReply mi = new mapItemReply();
|
||||||
|
mi.x = (uint)mapitem["X"].AsInteger();
|
||||||
|
mi.y = (uint)mapitem["Y"].AsInteger();
|
||||||
|
mi.id = mapitem["ID"].AsUUID();
|
||||||
|
mi.Extra = mapitem["Extra"].AsInteger();
|
||||||
|
mi.Extra2 = mapitem["Extra2"].AsInteger();
|
||||||
|
mi.name = mapitem["Name"].AsString();
|
||||||
|
returnitems.Add(mi);
|
||||||
|
}
|
||||||
|
av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Service 1 (MAP_ITEM_TELEHUB)
|
||||||
|
itemtype = 1;
|
||||||
|
|
||||||
|
if (responseMap.ContainsKey(itemtype.ToString()))
|
||||||
|
{
|
||||||
|
List<mapItemReply> returnitems = new List<mapItemReply>();
|
||||||
|
OSDArray itemarray = (OSDArray)responseMap[itemtype.ToString()];
|
||||||
|
for (int i = 0; i < itemarray.Count; i++)
|
||||||
|
{
|
||||||
|
OSDMap mapitem = (OSDMap)itemarray[i];
|
||||||
|
mapItemReply mi = new mapItemReply();
|
||||||
|
mi.x = (uint)mapitem["X"].AsInteger();
|
||||||
|
mi.y = (uint)mapitem["Y"].AsInteger();
|
||||||
|
mi.id = mapitem["ID"].AsUUID();
|
||||||
|
mi.Extra = mapitem["Extra"].AsInteger();
|
||||||
|
mi.Extra2 = mapitem["Extra2"].AsInteger();
|
||||||
|
mi.name = mapitem["Name"].AsString();
|
||||||
|
returnitems.Add(mi);
|
||||||
|
}
|
||||||
|
av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -951,53 +934,56 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||||
/// <param name="maxY"></param>
|
/// <param name="maxY"></param>
|
||||||
public virtual void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag)
|
public virtual void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag)
|
||||||
{
|
{
|
||||||
//m_log.ErrorFormat("[YYY] RequestMapBlocks {0}={1}={2}={3} {4}", minX, minY, maxX, maxY, flag);
|
Util.FireAndForget(x =>
|
||||||
if ((flag & 0x10000) != 0) // user clicked on qthe map a tile that isn't visible
|
|
||||||
{
|
{
|
||||||
List<MapBlockData> response = new List<MapBlockData>();
|
//m_log.ErrorFormat("[YYY] RequestMapBlocks {0}={1}={2}={3} {4}", minX, minY, maxX, maxY, flag);
|
||||||
|
if ((flag & 0x10000) != 0) // user clicked on qthe map a tile that isn't visible
|
||||||
// this should return one mapblock at most. It is triggered by a click
|
|
||||||
// on an unloaded square.
|
|
||||||
// But make sure: Look whether the one we requested is in there
|
|
||||||
List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID,
|
|
||||||
minX * (int)Constants.RegionSize,
|
|
||||||
maxX * (int)Constants.RegionSize,
|
|
||||||
minY * (int)Constants.RegionSize,
|
|
||||||
maxY * (int)Constants.RegionSize);
|
|
||||||
|
|
||||||
if (regions != null)
|
|
||||||
{
|
{
|
||||||
foreach (GridRegion r in regions)
|
List<MapBlockData> response = new List<MapBlockData>();
|
||||||
|
|
||||||
|
// this should return one mapblock at most. It is triggered by a click
|
||||||
|
// on an unloaded square.
|
||||||
|
// But make sure: Look whether the one we requested is in there
|
||||||
|
List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID,
|
||||||
|
minX * (int)Constants.RegionSize,
|
||||||
|
maxX * (int)Constants.RegionSize,
|
||||||
|
minY * (int)Constants.RegionSize,
|
||||||
|
maxY * (int)Constants.RegionSize);
|
||||||
|
|
||||||
|
if (regions != null)
|
||||||
{
|
{
|
||||||
if ((r.RegionLocX == minX * (int)Constants.RegionSize) &&
|
foreach (GridRegion r in regions)
|
||||||
(r.RegionLocY == minY * (int)Constants.RegionSize))
|
|
||||||
{
|
{
|
||||||
// found it => add it to response
|
if ((r.RegionLocX == minX * (int)Constants.RegionSize) &&
|
||||||
MapBlockData block = new MapBlockData();
|
(r.RegionLocY == minY * (int)Constants.RegionSize))
|
||||||
MapBlockFromGridRegion(block, r, flag);
|
{
|
||||||
response.Add(block);
|
// found it => add it to response
|
||||||
break;
|
MapBlockData block = new MapBlockData();
|
||||||
|
MapBlockFromGridRegion(block, r, flag);
|
||||||
|
response.Add(block);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (response.Count == 0)
|
if (response.Count == 0)
|
||||||
{
|
{
|
||||||
// response still empty => couldn't find the map-tile the user clicked on => tell the client
|
// response still empty => couldn't find the map-tile the user clicked on => tell the client
|
||||||
MapBlockData block = new MapBlockData();
|
MapBlockData block = new MapBlockData();
|
||||||
block.X = (ushort)minX;
|
block.X = (ushort)minX;
|
||||||
block.Y = (ushort)minY;
|
block.Y = (ushort)minY;
|
||||||
block.Access = 254; // means 'simulator is offline'
|
block.Access = 254; // means 'simulator is offline'
|
||||||
response.Add(block);
|
response.Add(block);
|
||||||
|
}
|
||||||
|
// The lower 16 bits are an unsigned int16
|
||||||
|
remoteClient.SendMapBlock(response, flag & 0xffff);
|
||||||
}
|
}
|
||||||
// The lower 16 bits are an unsigned int16
|
else
|
||||||
remoteClient.SendMapBlock(response, flag & 0xffff);
|
{
|
||||||
}
|
// normal mapblock request. Use the provided values
|
||||||
else
|
GetAndSendBlocks(remoteClient, minX, minY, maxX, maxY, flag);
|
||||||
{
|
}
|
||||||
// normal mapblock request. Use the provided values
|
});
|
||||||
GetAndSendBlocks(remoteClient, minX, minY, maxX, maxY, flag);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual List<MapBlockData> GetAndSendBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag)
|
protected virtual List<MapBlockData> GetAndSendBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag)
|
||||||
|
@ -1013,8 +999,15 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||||
MapBlockData block = new MapBlockData();
|
MapBlockData block = new MapBlockData();
|
||||||
MapBlockFromGridRegion(block, r, flag);
|
MapBlockFromGridRegion(block, r, flag);
|
||||||
mapBlocks.Add(block);
|
mapBlocks.Add(block);
|
||||||
|
if (mapBlocks.Count >= 20)
|
||||||
|
{
|
||||||
|
remoteClient.SendMapBlock(mapBlocks, flag & 0xffff);
|
||||||
|
mapBlocks.Clear();
|
||||||
|
Thread.Sleep(1000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
remoteClient.SendMapBlock(mapBlocks, flag & 0xffff);
|
if (mapBlocks.Count > 0)
|
||||||
|
remoteClient.SendMapBlock(mapBlocks, flag & 0xffff);
|
||||||
|
|
||||||
return mapBlocks;
|
return mapBlocks;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
using Nini.Config;
|
using Nini.Config;
|
||||||
using log4net;
|
using log4net;
|
||||||
|
@ -70,6 +71,8 @@ namespace OpenSim.Server.Handlers.MapImage
|
||||||
|
|
||||||
class MapServerGetHandler : BaseStreamHandler
|
class MapServerGetHandler : BaseStreamHandler
|
||||||
{
|
{
|
||||||
|
public static ManualResetEvent ev = new ManualResetEvent(true);
|
||||||
|
|
||||||
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
private IMapImageService m_MapService;
|
private IMapImageService m_MapService;
|
||||||
|
@ -82,8 +85,13 @@ namespace OpenSim.Server.Handlers.MapImage
|
||||||
|
|
||||||
public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
|
public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
|
||||||
{
|
{
|
||||||
byte[] result = new byte[0];
|
ev.WaitOne();
|
||||||
|
lock (ev)
|
||||||
|
{
|
||||||
|
ev.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] result = new byte[0];
|
||||||
string format = string.Empty;
|
string format = string.Empty;
|
||||||
result = m_MapService.GetMapTile(path.Trim('/'), out format);
|
result = m_MapService.GetMapTile(path.Trim('/'), out format);
|
||||||
if (result.Length > 0)
|
if (result.Length > 0)
|
||||||
|
@ -100,6 +108,11 @@ namespace OpenSim.Server.Handlers.MapImage
|
||||||
httpResponse.ContentType = "text/plain";
|
httpResponse.ContentType = "text/plain";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lock (ev)
|
||||||
|
{
|
||||||
|
ev.Set();
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue