From bf86addf3d55aba81985c0f68aea9ee7063da403 Mon Sep 17 00:00:00 2001
From: Justin Clark-Casey (justincc)
Date: Thu, 16 Jan 2014 20:23:31 +0000
Subject: Prevent duplicate invocations or race dontision in
SP.CompleteMovement()
This can happen under poor network conditions if a viewer repeats the message send
If this happens, physics actors can get orphaned, which unecessarily raises physics frame times
---
OpenSim/Region/Framework/Scenes/ScenePresence.cs | 29 ++++++-
.../Scenes/Tests/ScenePresenceAgentTests.cs | 92 +++++++++-------------
2 files changed, 65 insertions(+), 56 deletions(-)
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index 7243db1..d7511d3 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -108,6 +108,16 @@ namespace OpenSim.Region.Framework.Scenes
}
}
+ ///
+ /// This exists to prevent race conditions between two CompleteMovement threads if the simulator is slow and
+ /// the viewer fires these in quick succession.
+ ///
+ ///
+ /// TODO: The child -> agent transition should be folded into LifecycleState and the CompleteMovement
+ /// regulation done there.
+ ///
+ private object m_completeMovementLock = new object();
+
// private static readonly byte[] DEFAULT_TEXTURE = AvatarAppearance.GetDefaultTexture().GetBytes();
private static readonly Array DIR_CONTROL_FLAGS = Enum.GetValues(typeof(Dir_ControlFlags));
private static readonly Vector3 HEAD_ADJUSTMENT = new Vector3(0f, 0f, 0.3f);
@@ -904,6 +914,7 @@ namespace OpenSim.Region.Framework.Scenes
///
/// Turns a child agent into a root agent.
///
+ ///
/// Child agents are logged into neighbouring sims largely to observe changes. Root agents exist when the
/// avatar is actual in the sim. They can perform all actions.
/// This change is made whenever an avatar enters a region, whether by crossing over from a neighbouring sim,
@@ -911,8 +922,8 @@ namespace OpenSim.Region.Framework.Scenes
///
/// This method is on the critical path for transferring an avatar from one region to another. Delay here
/// delays that crossing.
- ///
- private void MakeRootAgent(Vector3 pos, bool isFlying)
+ ///
+ private bool MakeRootAgent(Vector3 pos, bool isFlying)
{
// m_log.InfoFormat(
// "[SCENE]: Upgrading child to root agent for {0} in {1}",
@@ -920,6 +931,10 @@ namespace OpenSim.Region.Framework.Scenes
//m_log.DebugFormat("[SCENE]: known regions in {0}: {1}", Scene.RegionInfo.RegionName, KnownChildRegionHandles.Count);
+ lock (m_completeMovementLock)
+ if (!IsChildAgent)
+ return false;
+
IsChildAgent = false;
// Must reset this here so that a teleport to a region next to an existing region does not keep the flag
@@ -1069,6 +1084,7 @@ namespace OpenSim.Region.Framework.Scenes
m_scene.EventManager.TriggerOnMakeRootAgent(this);
+ return true;
}
public int GetStateSource()
@@ -1442,7 +1458,14 @@ namespace OpenSim.Region.Framework.Scenes
}
bool flying = ((m_AgentControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0);
- MakeRootAgent(AbsolutePosition, flying);
+ if (!MakeRootAgent(AbsolutePosition, flying))
+ {
+ m_log.DebugFormat(
+ "[SCENE PRESENCE]: Aborting CompleteMovement call for {0} in {1} as they are already root",
+ Name, Scene.Name);
+
+ return;
+ }
// Tell the client that we're totally ready
ControllingClient.MoveAgentIntoRegion(m_scene.RegionInfo, AbsolutePosition, look);
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs
index d1aeaee..1ff1329 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs
@@ -111,6 +111,45 @@ namespace OpenSim.Region.Framework.Scenes.Tests
Assert.That(scene.GetScenePresences().Count, Is.EqualTo(1));
}
+ ///
+ /// Test that duplicate complete movement calls are ignored.
+ ///
+ ///
+ /// If duplicate calls are not ignored then there is a risk of race conditions or other unexpected effects.
+ ///
+ [Test]
+ public void TestDupeCompleteMovementCalls()
+ {
+ TestHelpers.InMethod();
+// TestHelpers.EnableLogging();
+
+ UUID spUuid = TestHelpers.ParseTail(0x1);
+
+ TestScene scene = new SceneHelpers().SetupScene();
+
+ int makeRootAgentEvents = 0;
+ scene.EventManager.OnMakeRootAgent += spi => makeRootAgentEvents++;
+
+ ScenePresence sp = SceneHelpers.AddScenePresence(scene, spUuid);
+
+ Assert.That(makeRootAgentEvents, Is.EqualTo(1));
+
+ // Normally these would be invoked by a CompleteMovement message coming in to the UDP stack. But for
+ // convenience, here we will invoke it manually.
+ sp.CompleteMovement(sp.ControllingClient, true);
+
+ Assert.That(makeRootAgentEvents, Is.EqualTo(1));
+
+ // Check rest of exepcted parameters.
+ Assert.That(scene.AuthenticateHandler.GetAgentCircuitData(spUuid), Is.Not.Null);
+ Assert.That(scene.AuthenticateHandler.GetAgentCircuits().Count, Is.EqualTo(1));
+
+ Assert.That(sp.IsChildAgent, Is.False);
+ Assert.That(sp.UUID, Is.EqualTo(spUuid));
+
+ Assert.That(scene.GetScenePresences().Count, Is.EqualTo(1));
+ }
+
[Test]
public void TestCreateDuplicateRootScenePresence()
{
@@ -249,58 +288,5 @@ namespace OpenSim.Region.Framework.Scenes.Tests
// Assert.That(childPresence, Is.Not.Null);
// Assert.That(childPresence.IsChildAgent, Is.True);
}
-
-// ///
-// /// Test adding a root agent to a scene. Doesn't yet actually complete crossing the agent into the scene.
-// ///
-// [Test]
-// public void T010_TestAddRootAgent()
-// {
-// TestHelpers.InMethod();
-//
-// string firstName = "testfirstname";
-//
-// AgentCircuitData agent = new AgentCircuitData();
-// agent.AgentID = agent1;
-// agent.firstname = firstName;
-// agent.lastname = "testlastname";
-// agent.SessionID = UUID.Random();
-// agent.SecureSessionID = UUID.Random();
-// agent.circuitcode = 123;
-// agent.BaseFolder = UUID.Zero;
-// agent.InventoryFolder = UUID.Zero;
-// agent.startpos = Vector3.Zero;
-// agent.CapsPath = GetRandomCapsObjectPath();
-// agent.ChildrenCapSeeds = new Dictionary();
-// agent.child = true;
-//
-// scene.PresenceService.LoginAgent(agent.AgentID.ToString(), agent.SessionID, agent.SecureSessionID);
-//
-// string reason;
-// scene.NewUserConnection(agent, (uint)TeleportFlags.ViaLogin, out reason);
-// testclient = new TestClient(agent, scene);
-// scene.AddNewAgent(testclient);
-//
-// ScenePresence presence = scene.GetScenePresence(agent1);
-//
-// Assert.That(presence, Is.Not.Null, "presence is null");
-// Assert.That(presence.Firstname, Is.EqualTo(firstName), "First name not same");
-// acd1 = agent;
-// }
-//
-// ///
-// /// Test removing an uncrossed root agent from a scene.
-// ///
-// [Test]
-// public void T011_TestRemoveRootAgent()
-// {
-// TestHelpers.InMethod();
-//
-// scene.RemoveClient(agent1);
-//
-// ScenePresence presence = scene.GetScenePresence(agent1);
-//
-// Assert.That(presence, Is.Null, "presence is not null");
-// }
}
}
\ No newline at end of file
--
cgit v1.1
From d88c9756a778bda8b71cc772746df962825968e4 Mon Sep 17 00:00:00 2001
From: Justin Clark-Casey (justincc)
Date: Thu, 16 Jan 2014 23:31:50 +0000
Subject: Actually put IsChildAgent = true inside the lock, otherwise there is
still a small window for race conditions on duplicate CompleteMovement calls
---
OpenSim/Region/Framework/Scenes/ScenePresence.cs | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index d7511d3..c2554d8 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -932,10 +932,12 @@ namespace OpenSim.Region.Framework.Scenes
//m_log.DebugFormat("[SCENE]: known regions in {0}: {1}", Scene.RegionInfo.RegionName, KnownChildRegionHandles.Count);
lock (m_completeMovementLock)
+ {
if (!IsChildAgent)
return false;
- IsChildAgent = false;
+ IsChildAgent = false;
+ }
// Must reset this here so that a teleport to a region next to an existing region does not keep the flag
// set and prevent the close of the connection on a subsequent re-teleport.
--
cgit v1.1
From 27abe040bddc11feb78757467c5e330f4cda840b Mon Sep 17 00:00:00 2001
From: Justin Clark-Casey (justincc)
Date: Mon, 20 Jan 2014 19:16:19 +0000
Subject: Stop exceptions being generated on agent connection if a telehub
object has been deleted or has no spawn points.
---
OpenSim/Framework/RegionSettings.cs | 21 ++--
.../World/Estate/EstateManagementCommands.cs | 2 +-
.../World/Estate/EstateManagementModule.cs | 8 +-
OpenSim/Region/Framework/Scenes/Scene.cs | 50 ++++++---
.../Framework/Scenes/Tests/SceneTelehubTests.cs | 119 +++++++++++++++++++++
OpenSim/Tests/Common/Mock/TestClient.cs | 5 -
OpenSim/Tests/Common/TestHelpers.cs | 21 +++-
7 files changed, 186 insertions(+), 40 deletions(-)
create mode 100644 OpenSim/Region/Framework/Scenes/Tests/SceneTelehubTests.cs
diff --git a/OpenSim/Framework/RegionSettings.cs b/OpenSim/Framework/RegionSettings.cs
index db8c53e..a895c40 100644
--- a/OpenSim/Framework/RegionSettings.cs
+++ b/OpenSim/Framework/RegionSettings.cs
@@ -482,21 +482,14 @@ namespace OpenSim.Framework
set { m_LoadedCreationID = value; }
}
- // Connected Telehub object
- private UUID m_TelehubObject = UUID.Zero;
- public UUID TelehubObject
- {
- get
- {
- return m_TelehubObject;
- }
- set
- {
- m_TelehubObject = value;
- }
- }
+ ///
+ /// Connected Telehub object
+ ///
+ public UUID TelehubObject { get; set; }
- // Our Connected Telehub's SpawnPoints
+ ///
+ /// Our connected Telehub's SpawnPoints
+ ///
public List l_SpawnPoints = new List();
// Add a SpawnPoint
diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs
index 173b603..1659493 100644
--- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs
+++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs
@@ -60,7 +60,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
public void Initialise()
{
- m_log.DebugFormat("[ESTATE MODULE]: Setting up estate commands for region {0}", m_module.Scene.RegionInfo.RegionName);
+// m_log.DebugFormat("[ESTATE MODULE]: Setting up estate commands for region {0}", m_module.Scene.RegionInfo.RegionName);
m_module.Scene.AddCommand("Regions", m_module, "set terrain texture",
"set terrain texture [] []",
diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs
index 42db1cf..cf74350 100644
--- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs
+++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs
@@ -702,7 +702,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
}
}
- public void handleOnEstateManageTelehub(IClientAPI client, UUID invoice, UUID senderID, string cmd, uint param1)
+ public void HandleOnEstateManageTelehub(IClientAPI client, UUID invoice, UUID senderID, string cmd, uint param1)
{
SceneObjectPart part;
@@ -742,7 +742,9 @@ namespace OpenSim.Region.CoreModules.World.Estate
default:
break;
}
- SendTelehubInfo(client);
+
+ if (client != null)
+ SendTelehubInfo(client);
}
private void SendSimulatorBlueBoxMessage(
@@ -1207,7 +1209,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
client.OnEstateRestartSimRequest += handleEstateRestartSimRequest;
client.OnEstateChangeCovenantRequest += handleChangeEstateCovenantRequest;
client.OnEstateChangeInfo += handleEstateChangeInfo;
- client.OnEstateManageTelehub += handleOnEstateManageTelehub;
+ client.OnEstateManageTelehub += HandleOnEstateManageTelehub;
client.OnUpdateEstateAccessDeltaRequest += handleEstateAccessDeltaRequest;
client.OnSimulatorBlueBoxMessageRequest += SendSimulatorBlueBoxMessage;
client.OnEstateBlueBoxMessageRequest += SendEstateBlueBoxMessage;
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index 7772f94..420c0b5 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -3946,32 +3946,52 @@ namespace OpenSim.Region.Framework.Scenes
}
}
+// m_log.DebugFormat(
+// "[SCENE]: Found telehub object {0} for new user connection {1} to {2}",
+// RegionInfo.RegionSettings.TelehubObject, acd.Name, Name);
+
// Honor Estate teleport routing via Telehubs excluding ViaHome and GodLike TeleportFlags
if (RegionInfo.RegionSettings.TelehubObject != UUID.Zero &&
RegionInfo.EstateSettings.AllowDirectTeleport == false &&
!viahome && !godlike)
{
SceneObjectGroup telehub = GetSceneObjectGroup(RegionInfo.RegionSettings.TelehubObject);
- // Can have multiple SpawnPoints
- List spawnpoints = RegionInfo.RegionSettings.SpawnPoints();
- if (spawnpoints.Count > 1)
+
+ if (telehub != null)
{
- // We have multiple SpawnPoints, Route the agent to a random or sequential one
- if (SpawnPointRouting == "random")
- acd.startpos = spawnpoints[Util.RandomClass.Next(spawnpoints.Count) - 1].GetLocation(
- telehub.AbsolutePosition,
- telehub.GroupRotation
- );
+ // Can have multiple SpawnPoints
+ List spawnpoints = RegionInfo.RegionSettings.SpawnPoints();
+ if (spawnpoints.Count > 1)
+ {
+ // We have multiple SpawnPoints, Route the agent to a random or sequential one
+ if (SpawnPointRouting == "random")
+ acd.startpos = spawnpoints[Util.RandomClass.Next(spawnpoints.Count) - 1].GetLocation(
+ telehub.AbsolutePosition,
+ telehub.GroupRotation
+ );
+ else
+ acd.startpos = spawnpoints[SpawnPoint()].GetLocation(
+ telehub.AbsolutePosition,
+ telehub.GroupRotation
+ );
+ }
+ else if (spawnpoints.Count == 1)
+ {
+ // We have a single SpawnPoint and will route the agent to it
+ acd.startpos = spawnpoints[0].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation);
+ }
else
- acd.startpos = spawnpoints[SpawnPoint()].GetLocation(
- telehub.AbsolutePosition,
- telehub.GroupRotation
- );
+ {
+ m_log.DebugFormat(
+ "[SCENE]: No spawnpoints defined for telehub {0} for {1} in {2}. Continuing.",
+ RegionInfo.RegionSettings.TelehubObject, acd.Name, Name);
+ }
}
else
{
- // We have a single SpawnPoint and will route the agent to it
- acd.startpos = spawnpoints[0].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation);
+ m_log.DebugFormat(
+ "[SCENE]: No telehub {0} found to direct {1} in {2}. Continuing.",
+ RegionInfo.RegionSettings.TelehubObject, acd.Name, Name);
}
return true;
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneTelehubTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneTelehubTests.cs
new file mode 100644
index 0000000..9a97acc
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneTelehubTests.cs
@@ -0,0 +1,119 @@
+/*
+ * 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 NUnit.Framework;
+using OpenMetaverse;
+using OpenSim.Framework;
+using OpenSim.Region.CoreModules.World.Estate;
+using OpenSim.Region.Framework.Scenes;
+using OpenSim.Region.Framework.Interfaces;
+using OpenSim.Services.Interfaces;
+using OpenSim.Tests.Common;
+using OpenSim.Tests.Common.Mock;
+
+namespace OpenSim.Region.Framework.Scenes.Tests
+{
+ ///
+ /// Scene telehub tests
+ ///
+ ///
+ /// TODO: Tests which run through normal functionality. Currently, the only test is one that checks behaviour
+ /// in the case of an error condition
+ ///
+ [TestFixture]
+ public class SceneTelehubTests : OpenSimTestCase
+ {
+ ///
+ /// Test for desired behaviour when a telehub has no spawn points
+ ///
+ [Test]
+ public void TestNoTelehubSpawnPoints()
+ {
+ TestHelpers.InMethod();
+// TestHelpers.EnableLogging();
+
+ EstateManagementModule emm = new EstateManagementModule();
+
+ SceneHelpers sh = new SceneHelpers();
+ Scene scene = sh.SetupScene();
+ SceneHelpers.SetupSceneModules(scene, emm);
+
+ UUID telehubSceneObjectOwner = TestHelpers.ParseTail(0x1);
+
+ SceneObjectGroup telehubSo = SceneHelpers.AddSceneObject(scene, "telehubObject", telehubSceneObjectOwner);
+
+ emm.HandleOnEstateManageTelehub(null, UUID.Zero, UUID.Zero, "connect", telehubSo.LocalId);
+ scene.RegionInfo.EstateSettings.AllowDirectTeleport = false;
+
+ // Must still be possible to successfully log in
+ UUID loggingInUserId = TestHelpers.ParseTail(0x2);
+
+ UserAccount ua
+ = UserAccountHelpers.CreateUserWithInventory(scene, "Test", "User", loggingInUserId, "password");
+
+ SceneHelpers.AddScenePresence(scene, ua);
+
+ Assert.That(scene.GetScenePresence(loggingInUserId), Is.Not.Null);
+ }
+
+ ///
+ /// Test for desired behaviour when the scene object nominated as a telehub object does not exist.
+ ///
+ [Test]
+ public void TestNoTelehubSceneObject()
+ {
+ TestHelpers.InMethod();
+// TestHelpers.EnableLogging();
+
+ EstateManagementModule emm = new EstateManagementModule();
+
+ SceneHelpers sh = new SceneHelpers();
+ Scene scene = sh.SetupScene();
+ SceneHelpers.SetupSceneModules(scene, emm);
+
+ UUID telehubSceneObjectOwner = TestHelpers.ParseTail(0x1);
+
+ SceneObjectGroup telehubSo = SceneHelpers.AddSceneObject(scene, "telehubObject", telehubSceneObjectOwner);
+ SceneObjectGroup spawnPointSo = SceneHelpers.AddSceneObject(scene, "spawnpointObject", telehubSceneObjectOwner);
+
+ emm.HandleOnEstateManageTelehub(null, UUID.Zero, UUID.Zero, "connect", telehubSo.LocalId);
+ emm.HandleOnEstateManageTelehub(null, UUID.Zero, UUID.Zero, "spawnpoint add", spawnPointSo.LocalId);
+ scene.RegionInfo.EstateSettings.AllowDirectTeleport = false;
+
+ scene.DeleteSceneObject(telehubSo, false);
+
+ // Must still be possible to successfully log in
+ UUID loggingInUserId = TestHelpers.ParseTail(0x2);
+
+ UserAccount ua
+ = UserAccountHelpers.CreateUserWithInventory(scene, "Test", "User", loggingInUserId, "password");
+
+ SceneHelpers.AddScenePresence(scene, ua);
+
+ Assert.That(scene.GetScenePresence(loggingInUserId), Is.Not.Null);
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs
index 9370102..a4247e3 100644
--- a/OpenSim/Tests/Common/Mock/TestClient.cs
+++ b/OpenSim/Tests/Common/Mock/TestClient.cs
@@ -788,11 +788,6 @@ namespace OpenSim.Tests.Common.Mock
{
OnRegionHandShakeReply(this);
}
-
- if (OnCompleteMovementToRegion != null)
- {
- OnCompleteMovementToRegion(this, true);
- }
}
public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID)
diff --git a/OpenSim/Tests/Common/TestHelpers.cs b/OpenSim/Tests/Common/TestHelpers.cs
index a684d72..6bf23f8 100644
--- a/OpenSim/Tests/Common/TestHelpers.cs
+++ b/OpenSim/Tests/Common/TestHelpers.cs
@@ -117,8 +117,6 @@ namespace OpenSim.Tests.Common
/// Parse a UUID stem into a full UUID.
///
///
- /// Yes, this is completely inconsistent with ParseTail but this is probably a better way to do it,
- /// UUIDs are conceptually not hexadecmial numbers.
/// The fragment will come at the start of the UUID. The rest will be 0s
///
///
@@ -143,5 +141,24 @@ namespace OpenSim.Tests.Common
{
return new UUID(string.Format("00000000-0000-0000-0000-{0:X12}", tail));
}
+
+ ///
+ /// Parse a UUID tail section into a full UUID.
+ ///
+ ///
+ /// The fragment will come at the end of the UUID. The rest will be 0s
+ ///
+ ///
+ ///
+ /// A UUID fragment that will be parsed into a full UUID. Therefore, it can only contain
+ /// cahracters which are valid in a UUID, except for "-" which is currently only allowed if a full UUID is
+ /// given as the 'fragment'.
+ ///
+ public static UUID ParseTail(string stem)
+ {
+ string rawUuid = stem.PadLeft(32, '0');
+
+ return UUID.Parse(rawUuid);
+ }
}
}
--
cgit v1.1
From 099975dec2a566d5b804f0c3fd43c6d17ea23d52 Mon Sep 17 00:00:00 2001
From: Justin Clark-Casey (justincc)
Date: Thu, 23 Jan 2014 23:44:21 +0000
Subject: Add "generate map" console command to allow manual regeneration and
storage of maptiles
Primarily for test purposes though could be useful if one prefers to manually update the map tile
---
.../Region/CoreModules/World/LegacyMap/MapImageModule.cs | 5 ++++-
.../Region/CoreModules/World/WorldMap/WorldMapModule.cs | 15 +++++++++++++++
2 files changed, 19 insertions(+), 1 deletion(-)
diff --git a/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs b/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs
index 40638f8..61ba5f3 100644
--- a/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs
+++ b/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs
@@ -127,7 +127,10 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
try
{
using (Bitmap mapbmp = CreateMapTile())
- return OpenJPEG.EncodeFromImage(mapbmp, true);
+ {
+ if (mapbmp != null)
+ return OpenJPEG.EncodeFromImage(mapbmp, true);
+ }
}
catch (Exception e) // LEGIT: Catching problems caused by OpenJPEG p/invoke
{
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs
index a26a5f0..8df9623 100644
--- a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs
+++ b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs
@@ -114,6 +114,11 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
"export-map []",
"Save an image of the world map", HandleExportWorldMapConsoleCommand);
+ m_scene.AddCommand(
+ "Regions", this, "generate map",
+ "generate map",
+ "Generates and stores a new maptile.", HandleGenerateMapConsoleCommand);
+
AddHandlers();
}
}
@@ -1255,6 +1260,16 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
m_scene.RegionInfo.RegionName, exportPath);
}
+ public void HandleGenerateMapConsoleCommand(string module, string[] cmdparams)
+ {
+ Scene consoleScene = m_scene.ConsoleScene();
+
+ if (consoleScene != null && consoleScene != m_scene)
+ return;
+
+ GenerateMaptile();
+ }
+
public OSD HandleRemoteMapItemRequest(string path, OSD request, string endpoint)
{
uint xstart = 0;
--
cgit v1.1
From 04e6c68242db78200aa5d96315e5d7bffb2f9155 Mon Sep 17 00:00:00 2001
From: Justin Clark-Casey (justincc)
Date: Fri, 24 Jan 2014 00:14:58 +0000
Subject: Properly dispose of drawing objects to reduce/stop memory leakage on
generating map tiles with the MapImageModule and TexturedMapTileRenderer (the
current defaults)
---
.../CoreModules/World/LegacyMap/MapImageModule.cs | 533 +++++++++++----------
.../World/LegacyMap/ShadedMapTileRenderer.cs | 11 +-
.../World/LegacyMap/TexturedMapTileRenderer.cs | 27 +-
.../CoreModules/World/WorldMap/WorldMapModule.cs | 91 ++--
4 files changed, 343 insertions(+), 319 deletions(-)
diff --git a/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs b/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs
index 61ba5f3..bc52a43 100644
--- a/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs
+++ b/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs
@@ -55,7 +55,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
public struct DrawStruct
{
public DrawRoutine dr;
- public Rectangle rect;
+// public Rectangle rect;
public SolidBrush brush;
public face[] trns;
}
@@ -119,6 +119,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
{
mapbmp = FetchTexture(m_scene.RegionInfo.RegionSettings.TerrainImageID);
}
+
return mapbmp;
}
@@ -280,321 +281,331 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
tc = Environment.TickCount;
m_log.Debug("[MAPTILE]: Generating Maptile Step 2: Object Volume Profile");
EntityBase[] objs = whichScene.GetEntities();
- Dictionary z_sort = new Dictionary();
- //SortedList z_sort = new SortedList();
List z_sortheights = new List();
List z_localIDs = new List();
+ Dictionary z_sort = new Dictionary();
- lock (objs)
+ try
{
- foreach (EntityBase obj in objs)
+ //SortedList z_sort = new SortedList();
+
+ lock (objs)
{
- // Only draw the contents of SceneObjectGroup
- if (obj is SceneObjectGroup)
+ foreach (EntityBase obj in objs)
{
- SceneObjectGroup mapdot = (SceneObjectGroup)obj;
- Color mapdotspot = Color.Gray; // Default color when prim color is white
-
- // Loop over prim in group
- foreach (SceneObjectPart part in mapdot.Parts)
+ // Only draw the contents of SceneObjectGroup
+ if (obj is SceneObjectGroup)
{
- if (part == null)
- continue;
-
- // Draw if the object is at least 1 meter wide in any direction
- if (part.Scale.X > 1f || part.Scale.Y > 1f || part.Scale.Z > 1f)
+ SceneObjectGroup mapdot = (SceneObjectGroup)obj;
+ Color mapdotspot = Color.Gray; // Default color when prim color is white
+
+ // Loop over prim in group
+ foreach (SceneObjectPart part in mapdot.Parts)
{
- // Try to get the RGBA of the default texture entry..
- //
- try
+ if (part == null)
+ continue;
+
+ // Draw if the object is at least 1 meter wide in any direction
+ if (part.Scale.X > 1f || part.Scale.Y > 1f || part.Scale.Z > 1f)
{
- // get the null checks out of the way
- // skip the ones that break
- if (part == null)
- continue;
+ // Try to get the RGBA of the default texture entry..
+ //
+ try
+ {
+ // get the null checks out of the way
+ // skip the ones that break
+ if (part == null)
+ continue;
- if (part.Shape == null)
- continue;
+ if (part.Shape == null)
+ continue;
- if (part.Shape.PCode == (byte)PCode.Tree || part.Shape.PCode == (byte)PCode.NewTree || part.Shape.PCode == (byte)PCode.Grass)
- continue; // eliminates trees from this since we don't really have a good tree representation
- // if you want tree blocks on the map comment the above line and uncomment the below line
- //mapdotspot = Color.PaleGreen;
+ if (part.Shape.PCode == (byte)PCode.Tree || part.Shape.PCode == (byte)PCode.NewTree || part.Shape.PCode == (byte)PCode.Grass)
+ continue; // eliminates trees from this since we don't really have a good tree representation
+ // if you want tree blocks on the map comment the above line and uncomment the below line
+ //mapdotspot = Color.PaleGreen;
- Primitive.TextureEntry textureEntry = part.Shape.Textures;
+ Primitive.TextureEntry textureEntry = part.Shape.Textures;
- if (textureEntry == null || textureEntry.DefaultTexture == null)
- continue;
+ if (textureEntry == null || textureEntry.DefaultTexture == null)
+ continue;
- Color4 texcolor = textureEntry.DefaultTexture.RGBA;
+ Color4 texcolor = textureEntry.DefaultTexture.RGBA;
- // Not sure why some of these are null, oh well.
+ // Not sure why some of these are null, oh well.
- int colorr = 255 - (int)(texcolor.R * 255f);
- int colorg = 255 - (int)(texcolor.G * 255f);
- int colorb = 255 - (int)(texcolor.B * 255f);
+ int colorr = 255 - (int)(texcolor.R * 255f);
+ int colorg = 255 - (int)(texcolor.G * 255f);
+ int colorb = 255 - (int)(texcolor.B * 255f);
- if (!(colorr == 255 && colorg == 255 && colorb == 255))
- {
- //Try to set the map spot color
- try
- {
- // If the color gets goofy somehow, skip it *shakes fist at Color4
- mapdotspot = Color.FromArgb(colorr, colorg, colorb);
- }
- catch (ArgumentException)
+ if (!(colorr == 255 && colorg == 255 && colorb == 255))
{
+ //Try to set the map spot color
+ try
+ {
+ // If the color gets goofy somehow, skip it *shakes fist at Color4
+ mapdotspot = Color.FromArgb(colorr, colorg, colorb);
+ }
+ catch (ArgumentException)
+ {
+ }
}
}
- }
- catch (IndexOutOfRangeException)
- {
- // Windows Array
- }
- catch (ArgumentOutOfRangeException)
- {
- // Mono Array
- }
-
- Vector3 pos = part.GetWorldPosition();
-
- // skip prim outside of retion
- if (pos.X < 0f || pos.X > 256f || pos.Y < 0f || pos.Y > 256f)
- continue;
-
- // skip prim in non-finite position
- if (Single.IsNaN(pos.X) || Single.IsNaN(pos.Y) ||
- Single.IsInfinity(pos.X) || Single.IsInfinity(pos.Y))
- continue;
+ catch (IndexOutOfRangeException)
+ {
+ // Windows Array
+ }
+ catch (ArgumentOutOfRangeException)
+ {
+ // Mono Array
+ }
- // Figure out if object is under 256m above the height of the terrain
- bool isBelow256AboveTerrain = false;
+ Vector3 pos = part.GetWorldPosition();
- try
- {
- isBelow256AboveTerrain = (pos.Z < ((float)hm[(int)pos.X, (int)pos.Y] + 256f));
- }
- catch (Exception)
- {
- }
-
- if (isBelow256AboveTerrain)
- {
- // Translate scale by rotation so scale is represented properly when object is rotated
- Vector3 lscale = new Vector3(part.Shape.Scale.X, part.Shape.Scale.Y, part.Shape.Scale.Z);
- Vector3 scale = new Vector3();
- Vector3 tScale = new Vector3();
- Vector3 axPos = new Vector3(pos.X,pos.Y,pos.Z);
-
- Quaternion llrot = part.GetWorldRotation();
- Quaternion rot = new Quaternion(llrot.W, llrot.X, llrot.Y, llrot.Z);
- scale = lscale * rot;
-
- // negative scales don't work in this situation
- scale.X = Math.Abs(scale.X);
- scale.Y = Math.Abs(scale.Y);
- scale.Z = Math.Abs(scale.Z);
-
- // This scaling isn't very accurate and doesn't take into account the face rotation :P
- int mapdrawstartX = (int)(pos.X - scale.X);
- int mapdrawstartY = (int)(pos.Y - scale.Y);
- int mapdrawendX = (int)(pos.X + scale.X);
- int mapdrawendY = (int)(pos.Y + scale.Y);
-
- // If object is beyond the edge of the map, don't draw it to avoid errors
- if (mapdrawstartX < 0 || mapdrawstartX > ((int)Constants.RegionSize - 1) || mapdrawendX < 0 || mapdrawendX > ((int)Constants.RegionSize - 1)
- || mapdrawstartY < 0 || mapdrawstartY > ((int)Constants.RegionSize - 1) || mapdrawendY < 0
- || mapdrawendY > ((int)Constants.RegionSize - 1))
+ // skip prim outside of retion
+ if (pos.X < 0f || pos.X > 256f || pos.Y < 0f || pos.Y > 256f)
continue;
-#region obb face reconstruction part duex
- Vector3[] vertexes = new Vector3[8];
-
- // float[] distance = new float[6];
- Vector3[] FaceA = new Vector3[6]; // vertex A for Facei
- Vector3[] FaceB = new Vector3[6]; // vertex B for Facei
- Vector3[] FaceC = new Vector3[6]; // vertex C for Facei
- Vector3[] FaceD = new Vector3[6]; // vertex D for Facei
-
- tScale = new Vector3(lscale.X, -lscale.Y, lscale.Z);
- scale = ((tScale * rot));
- vertexes[0] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
- // vertexes[0].x = pos.X + vertexes[0].x;
- //vertexes[0].y = pos.Y + vertexes[0].y;
- //vertexes[0].z = pos.Z + vertexes[0].z;
-
- FaceA[0] = vertexes[0];
- FaceB[3] = vertexes[0];
- FaceA[4] = vertexes[0];
-
- tScale = lscale;
- scale = ((tScale * rot));
- vertexes[1] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
-
- // vertexes[1].x = pos.X + vertexes[1].x;
- // vertexes[1].y = pos.Y + vertexes[1].y;
- //vertexes[1].z = pos.Z + vertexes[1].z;
-
- FaceB[0] = vertexes[1];
- FaceA[1] = vertexes[1];
- FaceC[4] = vertexes[1];
-
- tScale = new Vector3(lscale.X, -lscale.Y, -lscale.Z);
- scale = ((tScale * rot));
-
- vertexes[2] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
-
- //vertexes[2].x = pos.X + vertexes[2].x;
- //vertexes[2].y = pos.Y + vertexes[2].y;
- //vertexes[2].z = pos.Z + vertexes[2].z;
-
- FaceC[0] = vertexes[2];
- FaceD[3] = vertexes[2];
- FaceC[5] = vertexes[2];
-
- tScale = new Vector3(lscale.X, lscale.Y, -lscale.Z);
- scale = ((tScale * rot));
- vertexes[3] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
-
- //vertexes[3].x = pos.X + vertexes[3].x;
- // vertexes[3].y = pos.Y + vertexes[3].y;
- // vertexes[3].z = pos.Z + vertexes[3].z;
-
- FaceD[0] = vertexes[3];
- FaceC[1] = vertexes[3];
- FaceA[5] = vertexes[3];
-
- tScale = new Vector3(-lscale.X, lscale.Y, lscale.Z);
- scale = ((tScale * rot));
- vertexes[4] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
-
- // vertexes[4].x = pos.X + vertexes[4].x;
- // vertexes[4].y = pos.Y + vertexes[4].y;
- // vertexes[4].z = pos.Z + vertexes[4].z;
-
- FaceB[1] = vertexes[4];
- FaceA[2] = vertexes[4];
- FaceD[4] = vertexes[4];
-
- tScale = new Vector3(-lscale.X, lscale.Y, -lscale.Z);
- scale = ((tScale * rot));
- vertexes[5] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
-
- // vertexes[5].x = pos.X + vertexes[5].x;
- // vertexes[5].y = pos.Y + vertexes[5].y;
- // vertexes[5].z = pos.Z + vertexes[5].z;
-
- FaceD[1] = vertexes[5];
- FaceC[2] = vertexes[5];
- FaceB[5] = vertexes[5];
+ // skip prim in non-finite position
+ if (Single.IsNaN(pos.X) || Single.IsNaN(pos.Y) ||
+ Single.IsInfinity(pos.X) || Single.IsInfinity(pos.Y))
+ continue;
- tScale = new Vector3(-lscale.X, -lscale.Y, lscale.Z);
- scale = ((tScale * rot));
- vertexes[6] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
+ // Figure out if object is under 256m above the height of the terrain
+ bool isBelow256AboveTerrain = false;
- // vertexes[6].x = pos.X + vertexes[6].x;
- // vertexes[6].y = pos.Y + vertexes[6].y;
- // vertexes[6].z = pos.Z + vertexes[6].z;
+ try
+ {
+ isBelow256AboveTerrain = (pos.Z < ((float)hm[(int)pos.X, (int)pos.Y] + 256f));
+ }
+ catch (Exception)
+ {
+ }
- FaceB[2] = vertexes[6];
- FaceA[3] = vertexes[6];
- FaceB[4] = vertexes[6];
+ if (isBelow256AboveTerrain)
+ {
+ // Translate scale by rotation so scale is represented properly when object is rotated
+ Vector3 lscale = new Vector3(part.Shape.Scale.X, part.Shape.Scale.Y, part.Shape.Scale.Z);
+ Vector3 scale = new Vector3();
+ Vector3 tScale = new Vector3();
+ Vector3 axPos = new Vector3(pos.X,pos.Y,pos.Z);
+
+ Quaternion llrot = part.GetWorldRotation();
+ Quaternion rot = new Quaternion(llrot.W, llrot.X, llrot.Y, llrot.Z);
+ scale = lscale * rot;
+
+ // negative scales don't work in this situation
+ scale.X = Math.Abs(scale.X);
+ scale.Y = Math.Abs(scale.Y);
+ scale.Z = Math.Abs(scale.Z);
+
+ // This scaling isn't very accurate and doesn't take into account the face rotation :P
+ int mapdrawstartX = (int)(pos.X - scale.X);
+ int mapdrawstartY = (int)(pos.Y - scale.Y);
+ int mapdrawendX = (int)(pos.X + scale.X);
+ int mapdrawendY = (int)(pos.Y + scale.Y);
+
+ // If object is beyond the edge of the map, don't draw it to avoid errors
+ if (mapdrawstartX < 0 || mapdrawstartX > ((int)Constants.RegionSize - 1) || mapdrawendX < 0 || mapdrawendX > ((int)Constants.RegionSize - 1)
+ || mapdrawstartY < 0 || mapdrawstartY > ((int)Constants.RegionSize - 1) || mapdrawendY < 0
+ || mapdrawendY > ((int)Constants.RegionSize - 1))
+ continue;
+
+ #region obb face reconstruction part duex
+ Vector3[] vertexes = new Vector3[8];
+
+ // float[] distance = new float[6];
+ Vector3[] FaceA = new Vector3[6]; // vertex A for Facei
+ Vector3[] FaceB = new Vector3[6]; // vertex B for Facei
+ Vector3[] FaceC = new Vector3[6]; // vertex C for Facei
+ Vector3[] FaceD = new Vector3[6]; // vertex D for Facei
+
+ tScale = new Vector3(lscale.X, -lscale.Y, lscale.Z);
+ scale = ((tScale * rot));
+ vertexes[0] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
+ // vertexes[0].x = pos.X + vertexes[0].x;
+ //vertexes[0].y = pos.Y + vertexes[0].y;
+ //vertexes[0].z = pos.Z + vertexes[0].z;
+
+ FaceA[0] = vertexes[0];
+ FaceB[3] = vertexes[0];
+ FaceA[4] = vertexes[0];
+
+ tScale = lscale;
+ scale = ((tScale * rot));
+ vertexes[1] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
+
+ // vertexes[1].x = pos.X + vertexes[1].x;
+ // vertexes[1].y = pos.Y + vertexes[1].y;
+ //vertexes[1].z = pos.Z + vertexes[1].z;
+
+ FaceB[0] = vertexes[1];
+ FaceA[1] = vertexes[1];
+ FaceC[4] = vertexes[1];
+
+ tScale = new Vector3(lscale.X, -lscale.Y, -lscale.Z);
+ scale = ((tScale * rot));
+
+ vertexes[2] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
+
+ //vertexes[2].x = pos.X + vertexes[2].x;
+ //vertexes[2].y = pos.Y + vertexes[2].y;
+ //vertexes[2].z = pos.Z + vertexes[2].z;
+
+ FaceC[0] = vertexes[2];
+ FaceD[3] = vertexes[2];
+ FaceC[5] = vertexes[2];
+
+ tScale = new Vector3(lscale.X, lscale.Y, -lscale.Z);
+ scale = ((tScale * rot));
+ vertexes[3] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
+
+ //vertexes[3].x = pos.X + vertexes[3].x;
+ // vertexes[3].y = pos.Y + vertexes[3].y;
+ // vertexes[3].z = pos.Z + vertexes[3].z;
+
+ FaceD[0] = vertexes[3];
+ FaceC[1] = vertexes[3];
+ FaceA[5] = vertexes[3];
+
+ tScale = new Vector3(-lscale.X, lscale.Y, lscale.Z);
+ scale = ((tScale * rot));
+ vertexes[4] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
+
+ // vertexes[4].x = pos.X + vertexes[4].x;
+ // vertexes[4].y = pos.Y + vertexes[4].y;
+ // vertexes[4].z = pos.Z + vertexes[4].z;
+
+ FaceB[1] = vertexes[4];
+ FaceA[2] = vertexes[4];
+ FaceD[4] = vertexes[4];
+
+ tScale = new Vector3(-lscale.X, lscale.Y, -lscale.Z);
+ scale = ((tScale * rot));
+ vertexes[5] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
+
+ // vertexes[5].x = pos.X + vertexes[5].x;
+ // vertexes[5].y = pos.Y + vertexes[5].y;
+ // vertexes[5].z = pos.Z + vertexes[5].z;
+
+ FaceD[1] = vertexes[5];
+ FaceC[2] = vertexes[5];
+ FaceB[5] = vertexes[5];
+
+ tScale = new Vector3(-lscale.X, -lscale.Y, lscale.Z);
+ scale = ((tScale * rot));
+ vertexes[6] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
+
+ // vertexes[6].x = pos.X + vertexes[6].x;
+ // vertexes[6].y = pos.Y + vertexes[6].y;
+ // vertexes[6].z = pos.Z + vertexes[6].z;
+
+ FaceB[2] = vertexes[6];
+ FaceA[3] = vertexes[6];
+ FaceB[4] = vertexes[6];
- tScale = new Vector3(-lscale.X, -lscale.Y, -lscale.Z);
- scale = ((tScale * rot));
- vertexes[7] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
+ tScale = new Vector3(-lscale.X, -lscale.Y, -lscale.Z);
+ scale = ((tScale * rot));
+ vertexes[7] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
- // vertexes[7].x = pos.X + vertexes[7].x;
- // vertexes[7].y = pos.Y + vertexes[7].y;
- // vertexes[7].z = pos.Z + vertexes[7].z;
+ // vertexes[7].x = pos.X + vertexes[7].x;
+ // vertexes[7].y = pos.Y + vertexes[7].y;
+ // vertexes[7].z = pos.Z + vertexes[7].z;
- FaceD[2] = vertexes[7];
- FaceC[3] = vertexes[7];
- FaceD[5] = vertexes[7];
-#endregion
+ FaceD[2] = vertexes[7];
+ FaceC[3] = vertexes[7];
+ FaceD[5] = vertexes[7];
+ #endregion
- //int wy = 0;
+ //int wy = 0;
- //bool breakYN = false; // If we run into an error drawing, break out of the
- // loop so we don't lag to death on error handling
- DrawStruct ds = new DrawStruct();
- ds.brush = new SolidBrush(mapdotspot);
- //ds.rect = new Rectangle(mapdrawstartX, (255 - mapdrawstartY), mapdrawendX - mapdrawstartX, mapdrawendY - mapdrawstartY);
+ //bool breakYN = false; // If we run into an error drawing, break out of the
+ // loop so we don't lag to death on error handling
+ DrawStruct ds = new DrawStruct();
+ ds.brush = new SolidBrush(mapdotspot);
+ //ds.rect = new Rectangle(mapdrawstartX, (255 - mapdrawstartY), mapdrawendX - mapdrawstartX, mapdrawendY - mapdrawstartY);
- ds.trns = new face[FaceA.Length];
+ ds.trns = new face[FaceA.Length];
- for (int i = 0; i < FaceA.Length; i++)
- {
- Point[] working = new Point[5];
- working[0] = project(FaceA[i], axPos);
- working[1] = project(FaceB[i], axPos);
- working[2] = project(FaceD[i], axPos);
- working[3] = project(FaceC[i], axPos);
- working[4] = project(FaceA[i], axPos);
+ for (int i = 0; i < FaceA.Length; i++)
+ {
+ Point[] working = new Point[5];
+ working[0] = project(FaceA[i], axPos);
+ working[1] = project(FaceB[i], axPos);
+ working[2] = project(FaceD[i], axPos);
+ working[3] = project(FaceC[i], axPos);
+ working[4] = project(FaceA[i], axPos);
- face workingface = new face();
- workingface.pts = working;
+ face workingface = new face();
+ workingface.pts = working;
- ds.trns[i] = workingface;
- }
+ ds.trns[i] = workingface;
+ }
- z_sort.Add(part.LocalId, ds);
- z_localIDs.Add(part.LocalId);
- z_sortheights.Add(pos.Z);
+ z_sort.Add(part.LocalId, ds);
+ z_localIDs.Add(part.LocalId);
+ z_sortheights.Add(pos.Z);
- //for (int wx = mapdrawstartX; wx < mapdrawendX; wx++)
- //{
- //for (wy = mapdrawstartY; wy < mapdrawendY; wy++)
+ //for (int wx = mapdrawstartX; wx < mapdrawendX; wx++)
//{
- //m_log.InfoFormat("[MAPDEBUG]: {0},{1}({2})", wx, (255 - wy),wy);
- //try
- //{
- // Remember, flip the y!
- // mapbmp.SetPixel(wx, (255 - wy), mapdotspot);
- //}
- //catch (ArgumentException)
+ //for (wy = mapdrawstartY; wy < mapdrawendY; wy++)
//{
- // breakYN = true;
+ //m_log.InfoFormat("[MAPDEBUG]: {0},{1}({2})", wx, (255 - wy),wy);
+ //try
+ //{
+ // Remember, flip the y!
+ // mapbmp.SetPixel(wx, (255 - wy), mapdotspot);
+ //}
+ //catch (ArgumentException)
+ //{
+ // breakYN = true;
+ //}
+
+ //if (breakYN)
+ // break;
//}
//if (breakYN)
// break;
//}
+ } // Object is within 256m Z of terrain
+ } // object is at least a meter wide
+ } // loop over group children
+ } // entitybase is sceneobject group
+ } // foreach loop over entities
- //if (breakYN)
- // break;
- //}
- } // Object is within 256m Z of terrain
- } // object is at least a meter wide
- } // loop over group children
- } // entitybase is sceneobject group
- } // foreach loop over entities
-
- float[] sortedZHeights = z_sortheights.ToArray();
- uint[] sortedlocalIds = z_localIDs.ToArray();
-
- // Sort prim by Z position
- Array.Sort(sortedZHeights, sortedlocalIds);
+ float[] sortedZHeights = z_sortheights.ToArray();
+ uint[] sortedlocalIds = z_localIDs.ToArray();
- Graphics g = Graphics.FromImage(mapbmp);
+ // Sort prim by Z position
+ Array.Sort(sortedZHeights, sortedlocalIds);
- for (int s = 0; s < sortedZHeights.Length; s++)
- {
- if (z_sort.ContainsKey(sortedlocalIds[s]))
+ using (Graphics g = Graphics.FromImage(mapbmp))
{
- DrawStruct rectDrawStruct = z_sort[sortedlocalIds[s]];
- for (int r = 0; r < rectDrawStruct.trns.Length; r++)
+ for (int s = 0; s < sortedZHeights.Length; s++)
{
- g.FillPolygon(rectDrawStruct.brush,rectDrawStruct.trns[r].pts);
+ if (z_sort.ContainsKey(sortedlocalIds[s]))
+ {
+ DrawStruct rectDrawStruct = z_sort[sortedlocalIds[s]];
+ for (int r = 0; r < rectDrawStruct.trns.Length; r++)
+ {
+ g.FillPolygon(rectDrawStruct.brush,rectDrawStruct.trns[r].pts);
+ }
+ //g.FillRectangle(rectDrawStruct.brush , rectDrawStruct.rect);
+ }
}
- //g.FillRectangle(rectDrawStruct.brush , rectDrawStruct.rect);
}
- }
+ } // lock entities objs
- g.Dispose();
- } // lock entities objs
+ }
+ finally
+ {
+ foreach (DrawStruct ds in z_sort.Values)
+ ds.brush.Dispose();
+ }
m_log.Debug("[MAPTILE]: Generating Maptile Step 2: Done in " + (Environment.TickCount - tc) + " ms");
+
return mapbmp;
}
diff --git a/OpenSim/Region/CoreModules/World/LegacyMap/ShadedMapTileRenderer.cs b/OpenSim/Region/CoreModules/World/LegacyMap/ShadedMapTileRenderer.cs
index 992bff3..cb06fd4 100644
--- a/OpenSim/Region/CoreModules/World/LegacyMap/ShadedMapTileRenderer.cs
+++ b/OpenSim/Region/CoreModules/World/LegacyMap/ShadedMapTileRenderer.cs
@@ -54,7 +54,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
public void TerrainToBitmap(Bitmap mapbmp)
{
int tc = Environment.TickCount;
- m_log.Debug("[MAPTILE]: Generating Maptile Step 1: Terrain");
+ m_log.Debug("[SHADED MAP TILE RENDERER]: Generating Maptile Step 1: Terrain");
double[,] hm = m_scene.Heightmap.GetDoubles();
bool ShadowDebugContinue = true;
@@ -199,7 +199,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
{
if (!terraincorruptedwarningsaid)
{
- m_log.WarnFormat("[MAPIMAGE]: Your terrain is corrupted in region {0}, it might take a few minutes to generate the map image depending on the corruption level", m_scene.RegionInfo.RegionName);
+ m_log.WarnFormat("[SHADED MAP TILE RENDERER]: Your terrain is corrupted in region {0}, it might take a few minutes to generate the map image depending on the corruption level", m_scene.RegionInfo.RegionName);
terraincorruptedwarningsaid = true;
}
color = Color.Black;
@@ -229,7 +229,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
{
if (!terraincorruptedwarningsaid)
{
- m_log.WarnFormat("[MAPIMAGE]: Your terrain is corrupted in region {0}, it might take a few minutes to generate the map image depending on the corruption level", m_scene.RegionInfo.RegionName);
+ m_log.WarnFormat("[SHADED MAP TILE RENDERER]: Your terrain is corrupted in region {0}, it might take a few minutes to generate the map image depending on the corruption level", m_scene.RegionInfo.RegionName);
terraincorruptedwarningsaid = true;
}
Color black = Color.Black;
@@ -238,7 +238,8 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
}
}
}
- m_log.Debug("[MAPTILE]: Generating Maptile Step 1: Done in " + (Environment.TickCount - tc) + " ms");
+
+ m_log.Debug("[SHADED MAP TILE RENDERER]: Generating Maptile Step 1: Done in " + (Environment.TickCount - tc) + " ms");
}
}
-}
+}
\ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/World/LegacyMap/TexturedMapTileRenderer.cs b/OpenSim/Region/CoreModules/World/LegacyMap/TexturedMapTileRenderer.cs
index d13c2ef..e895178 100644
--- a/OpenSim/Region/CoreModules/World/LegacyMap/TexturedMapTileRenderer.cs
+++ b/OpenSim/Region/CoreModules/World/LegacyMap/TexturedMapTileRenderer.cs
@@ -173,7 +173,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
private Bitmap fetchTexture(UUID id)
{
AssetBase asset = m_scene.AssetService.Get(id.ToString());
- m_log.DebugFormat("[TexturedMapTileRenderer]: Fetched texture {0}, found: {1}", id, asset != null);
+ m_log.DebugFormat("[TEXTURED MAP TILE RENDERER]: Fetched texture {0}, found: {1}", id, asset != null);
if (asset == null) return null;
ManagedImage managedImage;
@@ -188,17 +188,17 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
}
catch (DllNotFoundException)
{
- m_log.ErrorFormat("[TexturedMapTileRenderer]: OpenJpeg is not installed correctly on this system. Asset Data is empty for {0}", id);
+ m_log.ErrorFormat("[TEXTURED MAP TILE RENDERER]: OpenJpeg is not installed correctly on this system. Asset Data is empty for {0}", id);
}
catch (IndexOutOfRangeException)
{
- m_log.ErrorFormat("[TexturedMapTileRenderer]: OpenJpeg was unable to encode this. Asset Data is empty for {0}", id);
+ m_log.ErrorFormat("[TEXTURED MAP TILE RENDERER]: OpenJpeg was unable to encode this. Asset Data is empty for {0}", id);
}
catch (Exception)
{
- m_log.ErrorFormat("[TexturedMapTileRenderer]: OpenJpeg was unable to encode this. Asset Data is empty for {0}", id);
+ m_log.ErrorFormat("[TEXTURED MAP TILE RENDERER]: OpenJpeg was unable to encode this. Asset Data is empty for {0}", id);
}
return null;
@@ -233,10 +233,14 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
if (textureID == UUID.Zero) return defaultColor; // not set
if (m_mapping.ContainsKey(textureID)) return m_mapping[textureID]; // one of the predefined textures
- Bitmap bmp = fetchTexture(textureID);
- Color color = bmp == null ? defaultColor : computeAverageColor(bmp);
- // store it for future reference
- m_mapping[textureID] = color;
+ Color color;
+
+ using (Bitmap bmp = fetchTexture(textureID))
+ {
+ color = bmp == null ? defaultColor : computeAverageColor(bmp);
+ // store it for future reference
+ m_mapping[textureID] = color;
+ }
return color;
}
@@ -278,7 +282,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
public void TerrainToBitmap(Bitmap mapbmp)
{
int tc = Environment.TickCount;
- m_log.Debug("[MAPTILE]: Generating Maptile Step 1: Terrain");
+ m_log.Debug("[TEXTURED MAP TILE RENDERER]: Generating Maptile Step 1: Terrain");
// These textures should be in the AssetCache anyway, as every client conneting to this
// region needs them. Except on start, when the map is recreated (before anyone connected),
@@ -412,7 +416,8 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
}
}
}
- m_log.Debug("[MAPTILE]: Generating Maptile Step 1: Done in " + (Environment.TickCount - tc) + " ms");
+
+ m_log.Debug("[TEXTURED MAP TILE RENDERER]: Generating Maptile Step 1: Done in " + (Environment.TickCount - tc) + " ms");
}
}
-}
+}
\ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs
index 8df9623..ddaf9fb 100644
--- a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs
+++ b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs
@@ -1501,62 +1501,69 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
private Byte[] GenerateOverlay()
{
- Bitmap overlay = new Bitmap(256, 256);
-
- bool[,] saleBitmap = new bool[64, 64];
- for (int x = 0 ; x < 64 ; x++)
+ using (Bitmap overlay = new Bitmap(256, 256))
{
- for (int y = 0 ; y < 64 ; y++)
- saleBitmap[x, y] = false;
- }
-
- bool landForSale = false;
+ bool[,] saleBitmap = new bool[64, 64];
+ for (int x = 0 ; x < 64 ; x++)
+ {
+ for (int y = 0 ; y < 64 ; y++)
+ saleBitmap[x, y] = false;
+ }
- List parcels = m_scene.LandChannel.AllParcels();
+ bool landForSale = false;
- Color background = Color.FromArgb(0, 0, 0, 0);
- SolidBrush transparent = new SolidBrush(background);
- Graphics g = Graphics.FromImage(overlay);
- g.FillRectangle(transparent, 0, 0, 256, 256);
+ List parcels = m_scene.LandChannel.AllParcels();
- SolidBrush yellow = new SolidBrush(Color.FromArgb(255, 249, 223, 9));
+ Color background = Color.FromArgb(0, 0, 0, 0);
- foreach (ILandObject land in parcels)
- {
- // m_log.DebugFormat("[WORLD MAP]: Parcel {0} flags {1}", land.LandData.Name, land.LandData.Flags);
- if ((land.LandData.Flags & (uint)ParcelFlags.ForSale) != 0)
+ using (Graphics g = Graphics.FromImage(overlay))
{
- landForSale = true;
+ using (SolidBrush transparent = new SolidBrush(background))
+ g.FillRectangle(transparent, 0, 0, 256, 256);
- saleBitmap = land.MergeLandBitmaps(saleBitmap, land.GetLandBitmap());
- }
- }
- if (!landForSale)
- {
- m_log.DebugFormat("[WORLD MAP]: Region {0} has no parcels for sale, not generating overlay", m_scene.RegionInfo.RegionName);
- return null;
- }
+ foreach (ILandObject land in parcels)
+ {
+ // m_log.DebugFormat("[WORLD MAP]: Parcel {0} flags {1}", land.LandData.Name, land.LandData.Flags);
+ if ((land.LandData.Flags & (uint)ParcelFlags.ForSale) != 0)
+ {
+ landForSale = true;
- m_log.DebugFormat("[WORLD MAP]: Region {0} has parcels for sale, generating overlay", m_scene.RegionInfo.RegionName);
+ saleBitmap = land.MergeLandBitmaps(saleBitmap, land.GetLandBitmap());
+ }
+ }
- for (int x = 0 ; x < 64 ; x++)
- {
- for (int y = 0 ; y < 64 ; y++)
+ if (!landForSale)
+ {
+ m_log.DebugFormat("[WORLD MAP]: Region {0} has no parcels for sale, not generating overlay", m_scene.RegionInfo.RegionName);
+ return null;
+ }
+
+ m_log.DebugFormat("[WORLD MAP]: Region {0} has parcels for sale, generating overlay", m_scene.RegionInfo.RegionName);
+
+ using (SolidBrush yellow = new SolidBrush(Color.FromArgb(255, 249, 223, 9)))
+ {
+ for (int x = 0 ; x < 64 ; x++)
+ {
+ for (int y = 0 ; y < 64 ; y++)
+ {
+ if (saleBitmap[x, y])
+ g.FillRectangle(yellow, x * 4, 252 - (y * 4), 4, 4);
+ }
+ }
+ }
+ }
+
+ try
+ {
+ return OpenJPEG.EncodeFromImage(overlay, true);
+ }
+ catch (Exception e)
{
- if (saleBitmap[x, y])
- g.FillRectangle(yellow, x * 4, 252 - (y * 4), 4, 4);
+ m_log.DebugFormat("[WORLD MAP]: Error creating parcel overlay: " + e.ToString());
}
}
- try
- {
- return OpenJPEG.EncodeFromImage(overlay, true);
- }
- catch (Exception e)
- {
- m_log.DebugFormat("[WORLD MAP]: Error creating parcel overlay: " + e.ToString());
- }
return null;
}
}
--
cgit v1.1