diff --git a/.gitignore b/.gitignore
index c8990d2f67..e04c219d90 100644
--- a/.gitignore
+++ b/.gitignore
@@ -44,6 +44,8 @@ bin/Physics*
bin/Terrain*
bin/Regions/*
bin/UserAssets
+bin/assetcache
+bin/maptiles
bin/estate_settings.xml
bin/config-include/CenomeCache.ini
bin/config-include/FlotsamCache.ini
diff --git a/OpenSim/Framework/IScene.cs b/OpenSim/Framework/IScene.cs
index a9432c2df3..87ec99ef60 100644
--- a/OpenSim/Framework/IScene.cs
+++ b/OpenSim/Framework/IScene.cs
@@ -66,6 +66,19 @@ namespace OpenSim.Framework
IConfigSource Config { get; }
+ ///
+ /// Are logins enabled on this simulator?
+ ///
+ bool LoginsEnabled { get; set; }
+
+ ///
+ /// Is this region ready for use?
+ ///
+ ///
+ /// This does not mean that logins are enabled, merely that they can be.
+ ///
+ bool Ready { get; set; }
+
float TimeDilation { get; }
bool AllowScriptCrossings { get; }
diff --git a/OpenSim/Framework/Statistics/AssetStatsCollector.cs b/OpenSim/Framework/Monitoring/AssetStatsCollector.cs
similarity index 99%
rename from OpenSim/Framework/Statistics/AssetStatsCollector.cs
rename to OpenSim/Framework/Monitoring/AssetStatsCollector.cs
index 7082ef3c3c..2a4d45bf0c 100644
--- a/OpenSim/Framework/Statistics/AssetStatsCollector.cs
+++ b/OpenSim/Framework/Monitoring/AssetStatsCollector.cs
@@ -28,7 +28,7 @@
using System;
using System.Timers;
-namespace OpenSim.Framework.Statistics
+namespace OpenSim.Framework.Monitoring
{
///
/// Asset service statistics collection
diff --git a/OpenSim/Framework/Statistics/BaseStatsCollector.cs b/OpenSim/Framework/Monitoring/BaseStatsCollector.cs
similarity index 98%
rename from OpenSim/Framework/Statistics/BaseStatsCollector.cs
rename to OpenSim/Framework/Monitoring/BaseStatsCollector.cs
index 3f918f3bd9..9ee087694b 100644
--- a/OpenSim/Framework/Statistics/BaseStatsCollector.cs
+++ b/OpenSim/Framework/Monitoring/BaseStatsCollector.cs
@@ -31,8 +31,7 @@ using System.Text;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
-
-namespace OpenSim.Framework.Statistics
+namespace OpenSim.Framework.Monitoring
{
///
/// Statistics which all collectors are interested in reporting
diff --git a/OpenSim/Framework/Statistics/Interfaces/IPullStatsProvider.cs b/OpenSim/Framework/Monitoring/Interfaces/IPullStatsProvider.cs
similarity index 97%
rename from OpenSim/Framework/Statistics/Interfaces/IPullStatsProvider.cs
rename to OpenSim/Framework/Monitoring/Interfaces/IPullStatsProvider.cs
index 430e580e1a..86a66207f6 100644
--- a/OpenSim/Framework/Statistics/Interfaces/IPullStatsProvider.cs
+++ b/OpenSim/Framework/Monitoring/Interfaces/IPullStatsProvider.cs
@@ -25,7 +25,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-namespace OpenSim.Framework.Statistics.Interfaces
+namespace OpenSim.Framework.Monitoring.Interfaces
{
///
/// Implemented by objects which allow statistical information to be pulled from them.
diff --git a/OpenSim/Framework/Statistics/Interfaces/IStatsCollector.cs b/OpenSim/Framework/Monitoring/Interfaces/IStatsCollector.cs
similarity index 98%
rename from OpenSim/Framework/Statistics/Interfaces/IStatsCollector.cs
rename to OpenSim/Framework/Monitoring/Interfaces/IStatsCollector.cs
index 477bbb364e..99f75e34b1 100644
--- a/OpenSim/Framework/Statistics/Interfaces/IStatsCollector.cs
+++ b/OpenSim/Framework/Monitoring/Interfaces/IStatsCollector.cs
@@ -25,7 +25,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-namespace OpenSim.Framework.Statistics
+namespace OpenSim.Framework.Monitoring
{
///
/// Implemented by classes which collect up non-viewer statistical information
diff --git a/OpenSim/Framework/Monitoring/MemoryWatchdog.cs b/OpenSim/Framework/Monitoring/MemoryWatchdog.cs
new file mode 100644
index 0000000000..a23cf1fea8
--- /dev/null
+++ b/OpenSim/Framework/Monitoring/MemoryWatchdog.cs
@@ -0,0 +1,129 @@
+/*
+ * 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.Linq;
+using System.Reflection;
+using System.Threading;
+using log4net;
+
+namespace OpenSim.Framework.Monitoring
+{
+ ///
+ /// Experimental watchdog for memory usage.
+ ///
+ public static class MemoryWatchdog
+ {
+// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
+ ///
+ /// Is this watchdog active?
+ ///
+ public static bool Enabled
+ {
+ get { return m_enabled; }
+ set
+ {
+// m_log.DebugFormat("[MEMORY WATCHDOG]: Setting MemoryWatchdog.Enabled to {0}", value);
+
+ if (value && !m_enabled)
+ UpdateLastRecord(GC.GetTotalMemory(false), Util.EnvironmentTickCount());
+
+ m_enabled = value;
+ }
+ }
+ private static bool m_enabled;
+
+ ///
+ /// Average memory churn in bytes per millisecond.
+ ///
+ public static double AverageMemoryChurn
+ {
+ get { if (m_samples.Count > 0) return m_samples.Average(); else return 0; }
+ }
+
+ ///
+ /// Maximum number of statistical samples.
+ ///
+ ///
+ /// At the moment this corresponds to 1 minute since the sampling rate is every 2.5 seconds as triggered from
+ /// the main Watchdog.
+ ///
+ private static int m_maxSamples = 24;
+
+ ///
+ /// Time when the watchdog was last updated.
+ ///
+ private static int m_lastUpdateTick;
+
+ ///
+ /// Memory used at time of last watchdog update.
+ ///
+ private static long m_lastUpdateMemory;
+
+ ///
+ /// Memory churn rate per millisecond.
+ ///
+// private static double m_churnRatePerMillisecond;
+
+ ///
+ /// Historical samples for calculating moving average.
+ ///
+ private static Queue m_samples = new Queue(m_maxSamples);
+
+ public static void Update()
+ {
+ int now = Util.EnvironmentTickCount();
+ long memoryNow = GC.GetTotalMemory(false);
+ long memoryDiff = memoryNow - m_lastUpdateMemory;
+
+ if (memoryDiff >= 0)
+ {
+ if (m_samples.Count >= m_maxSamples)
+ m_samples.Dequeue();
+
+ double elapsed = Util.EnvironmentTickCountSubtract(now, m_lastUpdateTick);
+
+ // This should never happen since it's not useful for updates to occur with no time elapsed, but
+ // protect ourselves from a divide-by-zero just in case.
+ if (elapsed == 0)
+ return;
+
+ m_samples.Enqueue(memoryDiff / (double)elapsed);
+ }
+
+ UpdateLastRecord(memoryNow, now);
+ }
+
+ private static void UpdateLastRecord(long memoryNow, int timeNow)
+ {
+ m_lastUpdateMemory = memoryNow;
+ m_lastUpdateTick = timeNow;
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenSim/Framework/Statistics/SimExtraStatsCollector.cs b/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs
similarity index 99%
rename from OpenSim/Framework/Statistics/SimExtraStatsCollector.cs
rename to OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs
index a506e3ba4d..cdd7cc711e 100644
--- a/OpenSim/Framework/Statistics/SimExtraStatsCollector.cs
+++ b/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs
@@ -28,12 +28,11 @@
using System;
using System.Collections.Generic;
using System.Text;
-
using OpenMetaverse;
-using OpenSim.Framework.Statistics.Interfaces;
using OpenMetaverse.StructuredData;
+using OpenSim.Framework.Monitoring.Interfaces;
-namespace OpenSim.Framework.Statistics
+namespace OpenSim.Framework.Monitoring
{
///
/// Collects sim statistics which aren't already being collected for the linden viewer's statistics pane
diff --git a/OpenSim/Framework/Statistics/StatsManager.cs b/OpenSim/Framework/Monitoring/StatsManager.cs
similarity index 98%
rename from OpenSim/Framework/Statistics/StatsManager.cs
rename to OpenSim/Framework/Monitoring/StatsManager.cs
index 436ce2fa04..d78fa6a1f0 100644
--- a/OpenSim/Framework/Statistics/StatsManager.cs
+++ b/OpenSim/Framework/Monitoring/StatsManager.cs
@@ -25,7 +25,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-namespace OpenSim.Framework.Statistics
+namespace OpenSim.Framework.Monitoring
{
///
/// Singleton used to provide access to statistics reporters
diff --git a/OpenSim/Framework/Statistics/UserStatsCollector.cs b/OpenSim/Framework/Monitoring/UserStatsCollector.cs
similarity index 98%
rename from OpenSim/Framework/Statistics/UserStatsCollector.cs
rename to OpenSim/Framework/Monitoring/UserStatsCollector.cs
index fd2a9bf198..e89c8e6344 100644
--- a/OpenSim/Framework/Statistics/UserStatsCollector.cs
+++ b/OpenSim/Framework/Monitoring/UserStatsCollector.cs
@@ -27,7 +27,7 @@
using System.Timers;
-namespace OpenSim.Framework.Statistics
+namespace OpenSim.Framework.Monitoring
{
///
/// Collects user service statistics
diff --git a/OpenSim/Framework/Watchdog.cs b/OpenSim/Framework/Monitoring/Watchdog.cs
similarity index 99%
rename from OpenSim/Framework/Watchdog.cs
rename to OpenSim/Framework/Monitoring/Watchdog.cs
index 449d014590..e4db964dba 100644
--- a/OpenSim/Framework/Watchdog.cs
+++ b/OpenSim/Framework/Monitoring/Watchdog.cs
@@ -31,7 +31,7 @@ using System.Linq;
using System.Threading;
using log4net;
-namespace OpenSim.Framework
+namespace OpenSim.Framework.Monitoring
{
///
/// Manages launching threads and keeping watch over them for timeouts
@@ -325,6 +325,9 @@ namespace OpenSim.Framework
callback(callbackInfo);
}
+ if (MemoryWatchdog.Enabled)
+ MemoryWatchdog.Update();
+
m_watchdogTimer.Start();
}
}
diff --git a/OpenSim/Framework/RegionInfo.cs b/OpenSim/Framework/RegionInfo.cs
index 1b2f6818c1..4bde7be2e1 100644
--- a/OpenSim/Framework/RegionInfo.cs
+++ b/OpenSim/Framework/RegionInfo.cs
@@ -482,9 +482,16 @@ namespace OpenSim.Framework
MainConsole.Instance.Output("=====================================\n");
if (name == String.Empty)
- name = MainConsole.Instance.CmdPrompt("New region name", name);
- if (name == String.Empty)
- throw new Exception("Cannot interactively create region with no name");
+ {
+ while (name.Trim() == string.Empty)
+ {
+ name = MainConsole.Instance.CmdPrompt("New region name", name);
+ if (name.Trim() == string.Empty)
+ {
+ MainConsole.Instance.Output("Cannot interactively create region with no name");
+ }
+ }
+ }
source.AddConfig(name);
@@ -515,15 +522,20 @@ namespace OpenSim.Framework
//
allKeys.Remove("RegionUUID");
string regionUUID = config.GetString("RegionUUID", string.Empty);
- if (regionUUID == String.Empty)
+ if (!UUID.TryParse(regionUUID.Trim(), out RegionID))
{
UUID newID = UUID.Random();
-
- regionUUID = MainConsole.Instance.CmdPrompt("RegionUUID", newID.ToString());
+ while (RegionID == UUID.Zero)
+ {
+ regionUUID = MainConsole.Instance.CmdPrompt("RegionUUID", newID.ToString());
+ if (!UUID.TryParse(regionUUID.Trim(), out RegionID))
+ {
+ MainConsole.Instance.Output("RegionUUID must be a valid UUID");
+ }
+ }
config.Set("RegionUUID", regionUUID);
}
- RegionID = new UUID(regionUUID);
originRegionID = RegionID; // What IS this?! (Needed for RegionCombinerModule?)
// Location
diff --git a/OpenSim/Framework/Servers/BaseOpenSimServer.cs b/OpenSim/Framework/Servers/BaseOpenSimServer.cs
index 9a2cd0e56c..cf19002baf 100644
--- a/OpenSim/Framework/Servers/BaseOpenSimServer.cs
+++ b/OpenSim/Framework/Servers/BaseOpenSimServer.cs
@@ -40,9 +40,9 @@ using log4net.Core;
using log4net.Repository;
using OpenSim.Framework;
using OpenSim.Framework.Console;
+using OpenSim.Framework.Monitoring;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Servers.HttpServer;
-using OpenSim.Framework.Statistics;
using Timer=System.Timers.Timer;
using OpenMetaverse;
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
index 24f986a756..e45cb895f7 100644
--- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
+++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
@@ -45,6 +45,7 @@ using OpenMetaverse.StructuredData;
using CoolHTTPListener = HttpServer.HttpListener;
using HttpListener=System.Net.HttpListener;
using LogPrio=HttpServer.LogPrio;
+using OpenSim.Framework.Monitoring;
namespace OpenSim.Framework.Servers.HttpServer
{
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
index a3bd330fb8..a385110b53 100644
--- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
+++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
@@ -32,6 +32,7 @@ using System.Reflection;
using log4net;
using HttpServer;
using OpenSim.Framework;
+using OpenSim.Framework.Monitoring;
/*
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceWorkerThread.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceWorkerThread.cs
index 1e3fbf0db5..1c529b6e93 100644
--- a/OpenSim/Framework/Servers/HttpServer/PollServiceWorkerThread.cs
+++ b/OpenSim/Framework/Servers/HttpServer/PollServiceWorkerThread.cs
@@ -36,6 +36,7 @@ using HttpServer;
using OpenMetaverse;
using System.Reflection;
using log4net;
+using OpenSim.Framework.Monitoring;
namespace OpenSim.Framework.Servers.HttpServer
{
diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs
index e6b57c2ecc..ba8aa9f98c 100644
--- a/OpenSim/Region/Application/OpenSim.cs
+++ b/OpenSim/Region/Application/OpenSim.cs
@@ -40,7 +40,7 @@ using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Framework.Console;
using OpenSim.Framework.Servers;
-using OpenSim.Framework.Statistics;
+using OpenSim.Framework.Monitoring;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
@@ -200,9 +200,9 @@ namespace OpenSim
PrintFileToConsole("startuplogo.txt");
// For now, start at the 'root' level by default
- if (m_sceneManager.Scenes.Count == 1) // If there is only one region, select it
+ if (SceneManager.Scenes.Count == 1) // If there is only one region, select it
ChangeSelectedRegion("region",
- new string[] {"change", "region", m_sceneManager.Scenes[0].RegionInfo.RegionName});
+ new string[] {"change", "region", SceneManager.Scenes[0].RegionInfo.RegionName});
else
ChangeSelectedRegion("region", new string[] {"change", "region", "root"});
@@ -461,7 +461,7 @@ namespace OpenSim
if (cmdparams.Length > 4)
alert = String.Format("\n{0}\n", String.Join(" ", cmdparams, 4, cmdparams.Length - 4));
- IList agents = m_sceneManager.GetCurrentSceneAvatars();
+ IList agents = SceneManager.GetCurrentSceneAvatars();
foreach (ScenePresence presence in agents)
{
@@ -542,7 +542,7 @@ namespace OpenSim
private void HandleForceUpdate(string module, string[] args)
{
MainConsole.Instance.Output("Updating all clients");
- m_sceneManager.ForceCurrentSceneClientUpdate();
+ SceneManager.ForceCurrentSceneClientUpdate();
}
///
@@ -554,7 +554,7 @@ namespace OpenSim
{
if (args.Length == 6)
{
- m_sceneManager.HandleEditCommandOnCurrentScene(args);
+ SceneManager.HandleEditCommandOnCurrentScene(args);
}
else
{
@@ -765,7 +765,7 @@ namespace OpenSim
case "load":
if (cmdparams.Length > 1)
{
- foreach (Scene s in new ArrayList(m_sceneManager.Scenes))
+ foreach (Scene s in new ArrayList(SceneManager.Scenes))
{
MainConsole.Instance.Output(String.Format("Loading module: {0}", cmdparams[1]));
m_moduleLoader.LoadRegionModules(cmdparams[1], s);
@@ -803,14 +803,14 @@ namespace OpenSim
case "backup":
MainConsole.Instance.Output("Triggering save of pending object updates to persistent store");
- m_sceneManager.BackupCurrentScene();
+ SceneManager.BackupCurrentScene();
break;
case "remove-region":
string regRemoveName = CombineParams(cmdparams, 0);
Scene removeScene;
- if (m_sceneManager.TryGetScene(regRemoveName, out removeScene))
+ if (SceneManager.TryGetScene(regRemoveName, out removeScene))
RemoveRegion(removeScene, false);
else
MainConsole.Instance.Output("No region with that name");
@@ -820,14 +820,14 @@ namespace OpenSim
string regDeleteName = CombineParams(cmdparams, 0);
Scene killScene;
- if (m_sceneManager.TryGetScene(regDeleteName, out killScene))
+ if (SceneManager.TryGetScene(regDeleteName, out killScene))
RemoveRegion(killScene, true);
else
MainConsole.Instance.Output("no region with that name");
break;
case "restart":
- m_sceneManager.RestartCurrentScene();
+ SceneManager.RestartCurrentScene();
break;
}
}
@@ -842,7 +842,7 @@ namespace OpenSim
{
string newRegionName = CombineParams(cmdparams, 2);
- if (!m_sceneManager.TrySetCurrentScene(newRegionName))
+ if (!SceneManager.TrySetCurrentScene(newRegionName))
MainConsole.Instance.Output(String.Format("Couldn't select region {0}", newRegionName));
}
else
@@ -850,7 +850,7 @@ namespace OpenSim
MainConsole.Instance.Output("Usage: change region ");
}
- string regionName = (m_sceneManager.CurrentScene == null ? "root" : m_sceneManager.CurrentScene.RegionInfo.RegionName);
+ string regionName = (SceneManager.CurrentScene == null ? "root" : SceneManager.CurrentScene.RegionInfo.RegionName);
MainConsole.Instance.Output(String.Format("Currently selected region is {0}", regionName));
// m_log.DebugFormat("Original prompt is {0}", m_consolePrompt);
@@ -868,7 +868,7 @@ namespace OpenSim
});
m_console.DefaultPrompt = prompt;
- m_console.ConsoleScene = m_sceneManager.CurrentScene;
+ m_console.ConsoleScene = SceneManager.CurrentScene;
}
///
@@ -892,7 +892,7 @@ namespace OpenSim
int newDebug;
if (int.TryParse(args[2], out newDebug))
{
- m_sceneManager.SetDebugPacketLevelOnCurrentScene(newDebug, name);
+ SceneManager.SetDebugPacketLevelOnCurrentScene(newDebug, name);
// We provide user information elsewhere if any clients had their debug level set.
// MainConsole.Instance.OutputFormat("Debug packet level set to {0}", newDebug);
}
@@ -907,7 +907,7 @@ namespace OpenSim
case "scene":
if (args.Length == 4)
{
- if (m_sceneManager.CurrentScene == null)
+ if (SceneManager.CurrentScene == null)
{
MainConsole.Instance.Output("Please use 'change region ' first");
}
@@ -915,7 +915,7 @@ namespace OpenSim
{
string key = args[2];
string value = args[3];
- m_sceneManager.CurrentScene.SetSceneCoreDebug(
+ SceneManager.CurrentScene.SetSceneCoreDebug(
new Dictionary() { { key, value } });
MainConsole.Instance.OutputFormat("Set debug scene {0} = {1}", key, value);
@@ -954,10 +954,10 @@ namespace OpenSim
IList agents;
if (showParams.Length > 1 && showParams[1] == "full")
{
- agents = m_sceneManager.GetCurrentScenePresences();
+ agents = SceneManager.GetCurrentScenePresences();
} else
{
- agents = m_sceneManager.GetCurrentSceneAvatars();
+ agents = SceneManager.GetCurrentSceneAvatars();
}
MainConsole.Instance.Output(String.Format("\nAgents connected: {0}\n", agents.Count));
@@ -1037,7 +1037,7 @@ namespace OpenSim
MainConsole.Instance.Output("Shared Module: " + module.Name);
}
- m_sceneManager.ForEachScene(
+ SceneManager.ForEachScene(
delegate(Scene scene) {
m_log.Error("The currently loaded modules in " + scene.RegionInfo.RegionName + " are:");
foreach (IRegionModule module in scene.Modules.Values)
@@ -1050,7 +1050,7 @@ namespace OpenSim
}
);
- m_sceneManager.ForEachScene(
+ SceneManager.ForEachScene(
delegate(Scene scene) {
MainConsole.Instance.Output("Loaded new region modules in" + scene.RegionInfo.RegionName + " are:");
foreach (IRegionModuleBase module in scene.RegionModules.Values)
@@ -1066,7 +1066,7 @@ namespace OpenSim
break;
case "regions":
- m_sceneManager.ForEachScene(
+ SceneManager.ForEachScene(
delegate(Scene scene)
{
MainConsole.Instance.Output(String.Format(
@@ -1080,7 +1080,7 @@ namespace OpenSim
break;
case "ratings":
- m_sceneManager.ForEachScene(
+ SceneManager.ForEachScene(
delegate(Scene scene)
{
string rating = "";
@@ -1115,7 +1115,7 @@ namespace OpenSim
cdt.AddColumn("IP", 16);
cdt.AddColumn("Viewer Name", 24);
- m_sceneManager.ForEachScene(
+ SceneManager.ForEachScene(
s =>
{
foreach (AgentCircuitData aCircuit in s.AuthenticateHandler.GetAgentCircuits().Values)
@@ -1140,13 +1140,13 @@ namespace OpenSim
cdt.AddColumn("Endpoint", 23);
cdt.AddColumn("Active?", 7);
- m_sceneManager.ForEachScene(
+ SceneManager.ForEachScene(
s => s.ForEachClient(
c => cdt.AddRow(
s.Name,
c.Name,
- c.RemoteEndPoint.ToString(),
c.CircuitCode.ToString(),
+ c.RemoteEndPoint.ToString(),
c.IsActive.ToString())));
MainConsole.Instance.Output(cdt.ToString());
@@ -1161,11 +1161,11 @@ namespace OpenSim
{
if (cmdparams.Length > 5)
{
- m_sceneManager.SaveNamedPrimsToXml2(cmdparams[3], cmdparams[4]);
+ SceneManager.SaveNamedPrimsToXml2(cmdparams[3], cmdparams[4]);
}
else
{
- m_sceneManager.SaveNamedPrimsToXml2("Primitive", DEFAULT_PRIM_BACKUP_FILENAME);
+ SceneManager.SaveNamedPrimsToXml2("Primitive", DEFAULT_PRIM_BACKUP_FILENAME);
}
}
@@ -1180,11 +1180,11 @@ namespace OpenSim
if (cmdparams.Length > 0)
{
- m_sceneManager.SaveCurrentSceneToXml(cmdparams[2]);
+ SceneManager.SaveCurrentSceneToXml(cmdparams[2]);
}
else
{
- m_sceneManager.SaveCurrentSceneToXml(DEFAULT_PRIM_BACKUP_FILENAME);
+ SceneManager.SaveCurrentSceneToXml(DEFAULT_PRIM_BACKUP_FILENAME);
}
}
@@ -1221,13 +1221,13 @@ namespace OpenSim
MainConsole.Instance.Output(String.Format("loadOffsets = <{0},{1},{2}>",loadOffset.X,loadOffset.Y,loadOffset.Z));
}
}
- m_sceneManager.LoadCurrentSceneFromXml(cmdparams[0], generateNewIDS, loadOffset);
+ SceneManager.LoadCurrentSceneFromXml(cmdparams[2], generateNewIDS, loadOffset);
}
else
{
try
{
- m_sceneManager.LoadCurrentSceneFromXml(DEFAULT_PRIM_BACKUP_FILENAME, false, loadOffset);
+ SceneManager.LoadCurrentSceneFromXml(DEFAULT_PRIM_BACKUP_FILENAME, false, loadOffset);
}
catch (FileNotFoundException)
{
@@ -1244,11 +1244,11 @@ namespace OpenSim
{
if (cmdparams.Length > 2)
{
- m_sceneManager.SaveCurrentSceneToXml2(cmdparams[2]);
+ SceneManager.SaveCurrentSceneToXml2(cmdparams[2]);
}
else
{
- m_sceneManager.SaveCurrentSceneToXml2(DEFAULT_PRIM_BACKUP_FILENAME);
+ SceneManager.SaveCurrentSceneToXml2(DEFAULT_PRIM_BACKUP_FILENAME);
}
}
@@ -1263,7 +1263,7 @@ namespace OpenSim
{
try
{
- m_sceneManager.LoadCurrentSceneFromXml2(cmdparams[2]);
+ SceneManager.LoadCurrentSceneFromXml2(cmdparams[2]);
}
catch (FileNotFoundException)
{
@@ -1274,7 +1274,7 @@ namespace OpenSim
{
try
{
- m_sceneManager.LoadCurrentSceneFromXml2(DEFAULT_PRIM_BACKUP_FILENAME);
+ SceneManager.LoadCurrentSceneFromXml2(DEFAULT_PRIM_BACKUP_FILENAME);
}
catch (FileNotFoundException)
{
@@ -1291,7 +1291,7 @@ namespace OpenSim
{
try
{
- m_sceneManager.LoadArchiveToCurrentScene(cmdparams);
+ SceneManager.LoadArchiveToCurrentScene(cmdparams);
}
catch (Exception e)
{
@@ -1305,7 +1305,7 @@ namespace OpenSim
///
protected void SaveOar(string module, string[] cmdparams)
{
- m_sceneManager.SaveCurrentSceneToArchive(cmdparams);
+ SceneManager.SaveCurrentSceneToArchive(cmdparams);
}
private static string CombineParams(string[] commandParams, int pos)
diff --git a/OpenSim/Region/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs
index 76ac246caa..aed10f60a2 100644
--- a/OpenSim/Region/Application/OpenSimBase.cs
+++ b/OpenSim/Region/Application/OpenSimBase.cs
@@ -40,7 +40,7 @@ using OpenSim.Framework.Communications;
using OpenSim.Framework.Console;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Servers.HttpServer;
-using OpenSim.Framework.Statistics;
+using OpenSim.Framework.Monitoring;
using OpenSim.Region.ClientStack;
using OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts;
using OpenSim.Region.Framework;
@@ -300,7 +300,7 @@ namespace OpenSim
private void HandleCommanderCommand(string module, string[] cmd)
{
- m_sceneManager.SendCommandToPluginModules(cmd);
+ SceneManager.SendCommandToPluginModules(cmd);
}
private void HandleCommanderHelp(string module, string[] cmd)
@@ -318,7 +318,10 @@ namespace OpenSim
// Called from base.StartUp()
m_httpServerPort = m_networkServersInfo.HttpListenerPort;
- m_sceneManager.OnRestartSim += handleRestartRegion;
+ SceneManager.OnRestartSim += handleRestartRegion;
+
+ // Only start the memory watchdog once all regions are ready
+ SceneManager.OnRegionsReadyStatusChange += sm => MemoryWatchdog.Enabled = sm.AllRegionsReady;
}
///
@@ -480,7 +483,7 @@ namespace OpenSim
scene.SnmpService.BootInfo("ScriptEngine started", scene);
}
- m_sceneManager.Add(scene);
+ SceneManager.Add(scene);
if (m_autoCreateClientStack)
{
@@ -510,7 +513,6 @@ namespace OpenSim
}
scene.Start();
-
scene.StartScripts();
return clientServer;
@@ -644,14 +646,14 @@ namespace OpenSim
{
// only need to check this if we are not at the
// root level
- if ((m_sceneManager.CurrentScene != null) &&
- (m_sceneManager.CurrentScene.RegionInfo.RegionID == scene.RegionInfo.RegionID))
+ if ((SceneManager.CurrentScene != null) &&
+ (SceneManager.CurrentScene.RegionInfo.RegionID == scene.RegionInfo.RegionID))
{
- m_sceneManager.TrySetCurrentScene("..");
+ SceneManager.TrySetCurrentScene("..");
}
scene.DeleteAllSceneObjects();
- m_sceneManager.CloseScene(scene);
+ SceneManager.CloseScene(scene);
ShutdownClientServer(scene.RegionInfo);
if (!cleanup)
@@ -693,7 +695,7 @@ namespace OpenSim
public void RemoveRegion(string name, bool cleanUp)
{
Scene target;
- if (m_sceneManager.TryGetScene(name, out target))
+ if (SceneManager.TryGetScene(name, out target))
RemoveRegion(target, cleanUp);
}
@@ -706,13 +708,13 @@ namespace OpenSim
{
// only need to check this if we are not at the
// root level
- if ((m_sceneManager.CurrentScene != null) &&
- (m_sceneManager.CurrentScene.RegionInfo.RegionID == scene.RegionInfo.RegionID))
+ if ((SceneManager.CurrentScene != null) &&
+ (SceneManager.CurrentScene.RegionInfo.RegionID == scene.RegionInfo.RegionID))
{
- m_sceneManager.TrySetCurrentScene("..");
+ SceneManager.TrySetCurrentScene("..");
}
- m_sceneManager.CloseScene(scene);
+ SceneManager.CloseScene(scene);
ShutdownClientServer(scene.RegionInfo);
}
@@ -724,7 +726,7 @@ namespace OpenSim
public void CloseRegion(string name)
{
Scene target;
- if (m_sceneManager.TryGetScene(name, out target))
+ if (SceneManager.TryGetScene(name, out target))
CloseRegion(target);
}
@@ -781,6 +783,7 @@ namespace OpenSim
scene.LoadWorldMap();
scene.PhysicsScene = GetPhysicsScene(scene.RegionInfo.RegionName);
+ scene.PhysicsScene.RequestAssetMethod = scene.PhysicsRequestAsset;
scene.PhysicsScene.SetTerrain(scene.Heightmap.GetFloatsSerialised());
scene.PhysicsScene.SetWaterLevel((float) regionInfo.RegionSettings.WaterHeight);
@@ -980,7 +983,7 @@ namespace OpenSim
try
{
- m_sceneManager.Close();
+ SceneManager.Close();
}
catch (Exception e)
{
@@ -1005,7 +1008,7 @@ namespace OpenSim
/// The first out parameter describing the number of all the avatars in the Region server
public void GetAvatarNumber(out int usernum)
{
- usernum = m_sceneManager.GetCurrentSceneAvatars().Count;
+ usernum = SceneManager.GetCurrentSceneAvatars().Count;
}
///
@@ -1014,7 +1017,7 @@ namespace OpenSim
/// The first out parameter describing the number of regions
public void GetRegionNumber(out int regionnum)
{
- regionnum = m_sceneManager.Scenes.Count;
+ regionnum = SceneManager.Scenes.Count;
}
///
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index ad9074cde4..f7bb817644 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -41,7 +41,7 @@ using OpenMetaverse.Messages.Linden;
using OpenMetaverse.StructuredData;
using OpenSim.Framework;
using OpenSim.Framework.Client;
-using OpenSim.Framework.Statistics;
+using OpenSim.Framework.Monitoring;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Services.Interfaces;
@@ -355,8 +355,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
private int m_animationSequenceNumber = 1;
private bool m_SendLogoutPacketWhenClosing = true;
private AgentUpdateArgs lastarg;
- private bool m_IsActive = true;
- private bool m_IsLoggingOut = false;
protected Dictionary m_packetHandlers = new Dictionary();
protected Dictionary m_genericPacketHandlers = new Dictionary(); //PauPaw:Local Generic Message handlers
@@ -428,16 +426,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
public uint CircuitCode { get { return m_circuitCode; } }
public int MoneyBalance { get { return m_moneyBalance; } }
public int NextAnimationSequenceNumber { get { return m_animationSequenceNumber++; } }
- public bool IsActive
- {
- get { return m_IsActive; }
- set { m_IsActive = value; }
- }
- public bool IsLoggingOut
- {
- get { return m_IsLoggingOut; }
- set { m_IsLoggingOut = value; }
- }
+
+ ///
+ /// As well as it's function in IClientAPI, in LLClientView we are locking on this property in order to
+ /// prevent race conditions by different threads calling Close().
+ ///
+ public bool IsActive { get; set; }
+
+ ///
+ /// Used to synchronise threads when client is being closed.
+ ///
+ public Object CloseSyncLock { get; private set; }
+
+ public bool IsLoggingOut { get; set; }
public bool DisableFacelights
{
@@ -462,6 +463,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{
// DebugPacketLevel = 1;
+ CloseSyncLock = new Object();
+
RegisterInterface(this);
RegisterInterface(this);
RegisterInterface(this);
@@ -494,13 +497,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_prioritizer = new Prioritizer(m_scene);
RegisterLocalPacketHandlers();
+
+ IsActive = true;
}
#region Client Methods
///
- /// Shut down the client view
+ /// Close down the client view
///
public void Close()
{
@@ -513,7 +518,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP
public void Close(bool sendStop)
{
IsActive = false;
+ // We lock here to prevent race conditions between two threads calling close simultaneously (e.g.
+ // a simultaneous relog just as a client is being closed out due to no packet ack from the old connection.
+ lock (CloseSyncLock)
+ {
+ if (!IsActive)
+ return;
+ IsActive = false;
+ CloseWithoutChecks(sendStop);
+ }
+ }
+
+ ///
+ /// Closes down the client view without first checking whether it is active.
+ ///
+ ///
+ /// This exists because LLUDPServer has to set IsActive = false in earlier synchronous code before calling
+ /// CloseWithoutIsActiveCheck asynchronously.
+ ///
+ /// Callers must lock ClosingSyncLock before calling.
+ ///
+ public void CloseWithoutChecks(bool sendStop)
+ {
m_log.DebugFormat(
"[CLIENT]: Close has been called for {0} attached to scene {1}",
Name, m_scene.RegionInfo.RegionName);
@@ -3634,7 +3661,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
public void SendCoarseLocationUpdate(List users, List CoarseLocations)
{
- if (!IsActive) return; // We don't need to update inactive clients.
+ // We don't need to update inactive clients.
+ if (!IsActive)
+ return;
CoarseLocationUpdatePacket loc = (CoarseLocationUpdatePacket)PacketPool.Instance.GetPacket(PacketType.CoarseLocationUpdate);
loc.Header.Reliable = false;
@@ -5267,7 +5296,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
AddLocalPacketHandler(PacketType.ChatFromViewer, HandleChatFromViewer);
AddLocalPacketHandler(PacketType.AvatarPropertiesUpdate, HandlerAvatarPropertiesUpdate);
AddLocalPacketHandler(PacketType.ScriptDialogReply, HandlerScriptDialogReply);
- AddLocalPacketHandler(PacketType.ImprovedInstantMessage, HandlerImprovedInstantMessage, false);
+ AddLocalPacketHandler(PacketType.ImprovedInstantMessage, HandlerImprovedInstantMessage);
AddLocalPacketHandler(PacketType.AcceptFriendship, HandlerAcceptFriendship);
AddLocalPacketHandler(PacketType.DeclineFriendship, HandlerDeclineFriendship);
AddLocalPacketHandler(PacketType.TerminateFriendship, HandlerTerminateFriendship);
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
index ae721757b0..c472176933 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
@@ -279,7 +279,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
public string GetStats()
{
return string.Format(
- "{0,7} {1,7} {2,7} {3,9} {4,7} {5,7} {6,7} {7,7} {8,7} {9,8} {10,7} {11,7}",
+ "{0,7} {1,7} {2,7} {3,9} {4,7} {5,7} {6,7} {7,7} {8,7} {9,8} {10,7} {11,7} {12,7}",
+ Util.EnvironmentTickCountSubtract(TickLastPacketReceived),
PacketsReceived,
PacketsSent,
PacketsResent,
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index b09f607b49..6c2e71b9ea 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -37,7 +37,7 @@ using log4net;
using Nini.Config;
using OpenMetaverse.Packets;
using OpenSim.Framework;
-using OpenSim.Framework.Statistics;
+using OpenSim.Framework.Monitoring;
using OpenSim.Region.Framework.Scenes;
using OpenMetaverse;
@@ -1181,22 +1181,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// regular client pings.
///
///
- private void DeactivateClientDueToTimeout(IClientAPI client)
+ private void DeactivateClientDueToTimeout(LLClientView client)
{
- // We must set IsActive synchronously so that we can stop the packet loop reinvoking this method, even
- // though it's set later on by LLClientView.Close()
- client.IsActive = false;
-
- m_log.WarnFormat(
- "[LLUDPSERVER]: Ack timeout, disconnecting {0} agent for {1} in {2}",
- client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, m_scene.RegionInfo.RegionName);
-
- StatsManager.SimExtraStats.AddAbnormalClientThreadTermination();
-
- if (!client.SceneAgent.IsChildAgent)
- client.Kick("Simulator logged you out due to connection timeout");
-
- Util.FireAndForget(o => client.Close());
+ lock (client.CloseSyncLock)
+ {
+ m_log.WarnFormat(
+ "[LLUDPSERVER]: Ack timeout, disconnecting {0} agent for {1} in {2}",
+ client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, m_scene.RegionInfo.RegionName);
+
+ StatsManager.SimExtraStats.AddAbnormalClientThreadTermination();
+
+ if (!client.SceneAgent.IsChildAgent)
+ client.Kick("Simulator logged you out due to connection timeout");
+
+ client.CloseWithoutChecks(true);
+ }
}
private void IncomingPacketHandler()
diff --git a/OpenSim/Region/ClientStack/RegionApplicationBase.cs b/OpenSim/Region/ClientStack/RegionApplicationBase.cs
index c4324e8592..4672f8aa8a 100644
--- a/OpenSim/Region/ClientStack/RegionApplicationBase.cs
+++ b/OpenSim/Region/ClientStack/RegionApplicationBase.cs
@@ -53,9 +53,8 @@ namespace OpenSim.Region.ClientStack
protected ISimulationDataService m_simulationDataService;
protected IEstateDataService m_estateDataService;
protected ClientStackManager m_clientStackManager;
- protected SceneManager m_sceneManager = new SceneManager();
- public SceneManager SceneManager { get { return m_sceneManager; } }
+ public SceneManager SceneManager { get; protected set; }
public NetworkServersInfo NetServersInfo { get { return m_networkServersInfo; } }
public ISimulationDataService SimulationDataService { get { return m_simulationDataService; } }
public IEstateDataService EstateDataService { get { return m_estateDataService; } }
@@ -77,6 +76,7 @@ namespace OpenSim.Region.ClientStack
protected override void StartupSpecific()
{
+ SceneManager = new SceneManager();
m_clientStackManager = CreateClientStackManager();
Initialize();
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
index 31e8a2e4cd..b58870434d 100644
--- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
@@ -626,10 +626,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
m_scene.InventoryService.UpdateItem(item);
- // this gets called when the agent logs off!
+ // If the name of the object has been changed whilst attached then we want to update the inventory
+ // item in the viewer.
if (sp.ControllingClient != null)
sp.ControllingClient.SendInventoryItemCreateUpdate(item, 0);
}
+
grp.HasGroupChanged = false; // Prevent it being saved over and over
}
// else
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs
index cd1e1c19d7..273e290d0f 100644
--- a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs
@@ -47,6 +47,7 @@ using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation;
using OpenSim.Region.CoreModules.World.Serialiser;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Region.Framework.Interfaces;
+using OpenSim.Region.ScriptEngine.Interfaces;
using OpenSim.Region.ScriptEngine.XEngine;
using OpenSim.Services.Interfaces;
using OpenSim.Tests.Common;
@@ -289,21 +290,37 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
{
TestHelpers.InMethod();
- Scene scene = CreateTestScene();
+ Scene scene = CreateScriptingEnabledTestScene();
UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
- ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1.PrincipalID);
+ ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1);
SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, sp.UUID, "att-name", 0x10);
- TaskInventoryHelpers.AddScript(scene, so.RootPart);
+ TaskInventoryItem scriptItem
+ = TaskInventoryHelpers.AddScript(
+ scene,
+ so.RootPart,
+ "scriptItem",
+ "default { attach(key id) { if (id != NULL_KEY) { llSay(0, \"Hello World\"); } } }");
+
InventoryItemBase userItem = UserInventoryHelpers.AddInventoryItem(scene, so, 0x100, 0x1000);
+ // FIXME: Right now, we have to do a tricksy chat listen to make sure we know when the script is running.
+ // In the future, we need to be able to do this programatically more predicably.
+ scene.EventManager.OnChatFromWorld += OnChatFromWorld;
+
scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, userItem.ID, (uint)AttachmentPoint.Chest);
+ m_chatEvent.WaitOne(60000);
+
// TODO: Need to have a test that checks the script is actually started but this involves a lot more
// plumbing of the script engine and either pausing for events or more infrastructure to turn off various
// script engine delays/asychronicity that isn't helpful in an automated regression testing context.
SceneObjectGroup attSo = scene.GetSceneObjectGroup(so.Name);
Assert.That(attSo.ContainsScripts(), Is.True);
+
+ TaskInventoryItem reRezzedScriptItem = attSo.RootPart.Inventory.GetInventoryItem(scriptItem.Name);
+ IScriptModule xengine = scene.RequestModuleInterface();
+ Assert.That(xengine.GetScriptState(reRezzedScriptItem.ItemID), Is.True);
}
[Test]
@@ -379,29 +396,49 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1);
SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, sp.UUID, "att-name", 0x10);
- TaskInventoryHelpers.AddScript(scene, so.RootPart);
+ TaskInventoryItem scriptTaskItem
+ = TaskInventoryHelpers.AddScript(
+ scene,
+ so.RootPart,
+ "scriptItem",
+ "default { attach(key id) { if (id != NULL_KEY) { llSay(0, \"Hello World\"); } } }");
+
InventoryItemBase userItem = UserInventoryHelpers.AddInventoryItem(scene, so, 0x100, 0x1000);
// FIXME: Right now, we have to do a tricksy chat listen to make sure we know when the script is running.
// In the future, we need to be able to do this programatically more predicably.
scene.EventManager.OnChatFromWorld += OnChatFromWorld;
- SceneObjectGroup soRezzed
- = (SceneObjectGroup)scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, userItem.ID, (uint)AttachmentPoint.Chest);
+ SceneObjectGroup rezzedSo
+ = (SceneObjectGroup)(scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, userItem.ID, (uint)AttachmentPoint.Chest));
// Wait for chat to signal rezzed script has been started.
m_chatEvent.WaitOne(60000);
- scene.AttachmentsModule.DetachSingleAttachmentToInv(sp, soRezzed);
+ scene.AttachmentsModule.DetachSingleAttachmentToInv(sp, rezzedSo);
InventoryItemBase userItemUpdated = scene.InventoryService.GetItem(userItem);
AssetBase asset = scene.AssetService.Get(userItemUpdated.AssetID.ToString());
+ // TODO: It would probably be better here to check script state via the saving and retrieval of state
+ // information at a higher level, rather than having to inspect the serialization.
XmlDocument soXml = new XmlDocument();
soXml.LoadXml(Encoding.UTF8.GetString(asset.Data));
XmlNodeList scriptStateNodes = soXml.GetElementsByTagName("ScriptState");
Assert.That(scriptStateNodes.Count, Is.EqualTo(1));
+
+ // Re-rez the attachment to check script running state
+ SceneObjectGroup reRezzedSo = (SceneObjectGroup)(scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, userItem.ID, (uint)AttachmentPoint.Chest));
+
+ // Wait for chat to signal rezzed script has been started.
+ m_chatEvent.WaitOne(60000);
+
+ TaskInventoryItem reRezzedScriptItem = reRezzedSo.RootPart.Inventory.GetInventoryItem(scriptTaskItem.Name);
+ IScriptModule xengine = scene.RequestModuleInterface();
+ Assert.That(xengine.GetScriptState(reRezzedScriptItem.ItemID), Is.True);
+
+// Console.WriteLine(soXml.OuterXml);
}
///
diff --git a/OpenSim/Region/CoreModules/Avatar/Commands/UserCommandsModule.cs b/OpenSim/Region/CoreModules/Avatar/Commands/UserCommandsModule.cs
index 4bcd2ac499..764adf9401 100644
--- a/OpenSim/Region/CoreModules/Avatar/Commands/UserCommandsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Commands/UserCommandsModule.cs
@@ -37,7 +37,7 @@ using Nini.Config;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Framework.Console;
-using OpenSim.Framework.Statistics;
+using OpenSim.Framework.Monitoring;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
diff --git a/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs b/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs
index 31363e5705..b258e13dce 100644
--- a/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs
@@ -96,7 +96,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Groups
scene.EventManager.OnNewClient += OnNewClient;
scene.EventManager.OnClientClosed += OnClientClosed;
- scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage;
+// scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage;
}
public void PostInitialise()
@@ -133,7 +133,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Groups
private void OnNewClient(IClientAPI client)
{
// Subscribe to instant messages
- client.OnInstantMessage += OnInstantMessage;
+// client.OnInstantMessage += OnInstantMessage;
client.OnAgentDataUpdateRequest += OnAgentDataUpdateRequest;
client.OnUUIDGroupNameRequest += HandleUUIDGroupNameRequest;
lock (m_ClientMap)
@@ -171,15 +171,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Groups
ActiveGroupTitle);
}
- private void OnInstantMessage(IClientAPI client, GridInstantMessage im)
- {
- }
+// private void OnInstantMessage(IClientAPI client, GridInstantMessage im)
+// {
+// }
- private void OnGridInstantMessage(GridInstantMessage msg)
- {
- // Trigger the above event handler
- OnInstantMessage(null, msg);
- }
+// private void OnGridInstantMessage(GridInstantMessage msg)
+// {
+// // Trigger the above event handler
+// OnInstantMessage(null, msg);
+// }
private void HandleUUIDGroupNameRequest(UUID id,IClientAPI remote_client)
{
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs
index 6064ddc426..1406aaec25 100644
--- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs
@@ -141,13 +141,15 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
foreach (Scene scene in m_Scenes)
{
// m_log.DebugFormat(
-// "[INSTANT MESSAGE]: Looking for root agent {0} in {1}",
+// "[INSTANT MESSAGE]: Looking for root agent {0} in {1}",
// toAgentID.ToString(), scene.RegionInfo.RegionName);
+
ScenePresence sp = scene.GetScenePresence(toAgentID);
if (sp != null && !sp.IsChildAgent)
{
// Local message
-// m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to root agent {0} {1}", user.Name, toAgentID);
+ m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to root agent {0} {1}", sp.Name, toAgentID);
+
sp.ControllingClient.SendInstantMessage(im);
// Message sent
@@ -159,13 +161,15 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
// try child avatar second
foreach (Scene scene in m_Scenes)
{
-// m_log.DebugFormat(
-// "[INSTANT MESSAGE]: Looking for child of {0} in {1}", toAgentID, scene.RegionInfo.RegionName);
+ m_log.DebugFormat(
+ "[INSTANT MESSAGE]: Looking for child of {0} in {1}", toAgentID, scene.RegionInfo.RegionName);
+
ScenePresence sp = scene.GetScenePresence(toAgentID);
if (sp != null)
{
// Local message
-// m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to child agent {0} {1}", user.Name, toAgentID);
+ m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to child agent {0} {1}", sp.Name, toAgentID);
+
sp.ControllingClient.SendInstantMessage(im);
// Message sent
@@ -174,10 +178,9 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
}
}
-// m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to {0} via XMLRPC", im.toAgentID);
- SendGridInstantMessageViaXMLRPC(im, result);
+ m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to {0} via XMLRPC", im.toAgentID);
- return;
+ SendGridInstantMessageViaXMLRPC(im, result);
}
private void HandleUndeliveredMessage(GridInstantMessage im, MessageResultNotification result)
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
index 80554fb3aa..81de29c108 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
@@ -313,8 +313,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
m_TransferModule.SendInstantMessage(im, delegate(bool success) {});
}
}
- else if (im.dialog == (byte) InstantMessageDialog.InventoryDeclined ||
- im.dialog == (byte) InstantMessageDialog.TaskInventoryDeclined)
+ else if (
+ im.dialog == (byte)InstantMessageDialog.InventoryDeclined
+ || im.dialog == (byte)InstantMessageDialog.TaskInventoryDeclined)
{
// Here, the recipient is local and we can assume that the
// inventory is loaded. Courtesy of the above bulk update,
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
index d30c2e2d4c..9a56f42567 100644
--- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
@@ -204,8 +204,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
AssetBase asset = m_Scene.CreateAsset(name, description, assetType, data, remoteClient.AgentId);
m_Scene.AssetService.Store(asset);
-
- m_Scene.CreateNewInventoryItem(remoteClient, remoteClient.AgentId.ToString(), string.Empty, folderID, asset.Name, 0, callbackID, asset, invType, nextOwnerMask, creationDate);
+ m_Scene.CreateNewInventoryItem(
+ remoteClient, remoteClient.AgentId.ToString(), string.Empty, folderID,
+ name, description, 0, callbackID, asset, invType, nextOwnerMask, creationDate);
}
else
{
diff --git a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs
index a75ff6234e..fb74cc6d72 100644
--- a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs
@@ -39,7 +39,7 @@ using OpenSim.Region.Framework;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
-namespace OpenSim.Region.CoreModules.Avatar.Attachments
+namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging
{
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "BinaryLoggingModule")]
public class BinaryLoggingModule : INonSharedRegionModule
diff --git a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs
new file mode 100755
index 0000000000..65e4c90ba5
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs
@@ -0,0 +1,161 @@
+/*
+ * 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.Text;
+using log4net;
+
+namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging
+{
+ ///
+ /// Class for writing a high performance, high volume log file.
+ /// Sometimes, to debug, one has a high volume logging to do and the regular
+ /// log file output is not appropriate.
+ /// Create a new instance with the parameters needed and
+ /// call Write() to output a line. Call Close() when finished.
+ /// If created with no parameters, it will not log anything.
+ ///
+ public class LogWriter : IDisposable
+ {
+ public bool Enabled { get; private set; }
+
+ private string m_logDirectory = ".";
+ private int m_logMaxFileTimeMin = 5; // 5 minutes
+ public String LogFileHeader { get; set; }
+
+ private StreamWriter m_logFile = null;
+ private TimeSpan m_logFileLife;
+ private DateTime m_logFileEndTime;
+ private Object m_logFileWriteLock = new Object();
+
+ // set externally when debugging. If let 'null', this does not write any error messages.
+ public ILog ErrorLogger = null;
+ private string LogHeader = "[LOG WRITER]";
+
+ ///
+ /// Create a log writer that will not write anything. Good for when not enabled
+ /// but the write statements are still in the code.
+ ///
+ public LogWriter()
+ {
+ Enabled = false;
+ m_logFile = null;
+ }
+
+ ///
+ /// Create a log writer instance.
+ ///
+ /// The directory to create the log file in. May be 'null' for default.
+ /// The characters that begin the log file name. May be 'null' for default.
+ /// Maximum age of a log file in minutes. If zero, will set default.
+ public LogWriter(string dir, string headr, int maxFileTime)
+ {
+ m_logDirectory = dir == null ? "." : dir;
+
+ LogFileHeader = headr == null ? "log-" : headr;
+
+ m_logMaxFileTimeMin = maxFileTime;
+ if (m_logMaxFileTimeMin < 1)
+ m_logMaxFileTimeMin = 5;
+
+ m_logFileLife = new TimeSpan(0, m_logMaxFileTimeMin, 0);
+ m_logFileEndTime = DateTime.Now + m_logFileLife;
+
+ Enabled = true;
+ }
+
+ public void Dispose()
+ {
+ this.Close();
+ }
+
+ public void Close()
+ {
+ Enabled = false;
+ if (m_logFile != null)
+ {
+ m_logFile.Close();
+ m_logFile.Dispose();
+ m_logFile = null;
+ }
+ }
+
+ public void Write(string line, params object[] args)
+ {
+ if (!Enabled) return;
+ Write(String.Format(line, args));
+ }
+
+ public void Write(string line)
+ {
+ if (!Enabled) return;
+ try
+ {
+ lock (m_logFileWriteLock)
+ {
+ DateTime now = DateTime.Now;
+ if (m_logFile == null || now > m_logFileEndTime)
+ {
+ if (m_logFile != null)
+ {
+ m_logFile.Close();
+ m_logFile.Dispose();
+ m_logFile = null;
+ }
+
+ // First log file or time has expired, start writing to a new log file
+ m_logFileEndTime = now + m_logFileLife;
+ string path = (m_logDirectory.Length > 0 ? m_logDirectory
+ + System.IO.Path.DirectorySeparatorChar.ToString() : "")
+ + String.Format("{0}{1}.log", LogFileHeader, now.ToString("yyyyMMddHHmmss"));
+ m_logFile = new StreamWriter(File.Open(path, FileMode.Append, FileAccess.Write));
+ }
+ if (m_logFile != null)
+ {
+ StringBuilder buff = new StringBuilder(line.Length + 25);
+ buff.Append(now.ToString("yyyyMMddHHmmssfff"));
+ // buff.Append(now.ToString("yyyyMMddHHmmss"));
+ buff.Append(",");
+ buff.Append(line);
+ buff.Append("\r\n");
+ m_logFile.Write(buff.ToString());
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ if (ErrorLogger != null)
+ {
+ ErrorLogger.ErrorFormat("{0}: FAILURE WRITING TO LOGFILE: {1}", LogHeader, e);
+ }
+ Enabled = false;
+ }
+ return;
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/InterGrid/OpenGridProtocolModule.cs b/OpenSim/Region/CoreModules/InterGrid/OpenGridProtocolModule.cs
index a6e2548406..4a76b00467 100644
--- a/OpenSim/Region/CoreModules/InterGrid/OpenGridProtocolModule.cs
+++ b/OpenSim/Region/CoreModules/InterGrid/OpenGridProtocolModule.cs
@@ -40,6 +40,7 @@ using OpenMetaverse;
using OpenMetaverse.StructuredData;
using OpenSim.Framework;
using OpenSim.Framework.Capabilities;
+using OpenSim.Framework.Monitoring;
using OpenSim.Framework.Servers;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs
index 990dffb61a..11e0150083 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs
@@ -31,7 +31,7 @@ using System.Collections.Generic;
using System.Reflection;
using Nini.Config;
using OpenSim.Framework;
-using OpenSim.Framework.Statistics;
+using OpenSim.Framework.Monitoring;
using OpenSim.Services.Connectors;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs
index 6cd077a47a..e4c6c1ad76 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs
@@ -131,11 +131,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage
m_enabled = true;
}
- ///
- ///
- ///
-
-
///
///
///
@@ -149,10 +144,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage
lock (m_scenes)
m_scenes[scene.RegionInfo.RegionID] = scene;
- scene.EventManager.OnLoginsEnabled += OnLoginsEnabled;
+ scene.EventManager.OnRegionReadyStatusChange += s => { if (s.Ready) UploadMapTile(s); };
}
-
///
///
///
@@ -166,21 +160,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage
}
#endregion ISharedRegionModule
-
- void OnLoginsEnabled(string regionName)
- {
- Scene scene = null;
- foreach (Scene s in m_scenes.Values)
- if (s.RegionInfo.RegionName == regionName)
- {
- scene = s;
- break;
- }
- if (scene != null)
- UploadMapTile(scene);
- }
-
-
+
///
///
///
diff --git a/OpenSim/Region/CoreModules/World/Access/AccessModule.cs b/OpenSim/Region/CoreModules/World/Access/AccessModule.cs
index 553a32d3bd..e7b14547f4 100644
--- a/OpenSim/Region/CoreModules/World/Access/AccessModule.cs
+++ b/OpenSim/Region/CoreModules/World/Access/AccessModule.cs
@@ -129,18 +129,18 @@ namespace OpenSim.Region.CoreModules.World
switch (cmd[1])
{
case "enable":
- scene.LoginsDisabled = false;
+ scene.LoginsEnabled = true;
MainConsole.Instance.Output(String.Format("Logins are enabled for region {0}", scene.RegionInfo.RegionName));
break;
case "disable":
- scene.LoginsDisabled = true;
+ scene.LoginsEnabled = false;
MainConsole.Instance.Output(String.Format("Logins are disabled for region {0}", scene.RegionInfo.RegionName));
break;
case "status":
- if (scene.LoginsDisabled)
- MainConsole.Instance.Output(String.Format("Login in {0} are disabled", scene.RegionInfo.RegionName));
- else
+ if (scene.LoginsEnabled)
MainConsole.Instance.Output(String.Format("Login in {0} are enabled", scene.RegionInfo.RegionName));
+ else
+ MainConsole.Instance.Output(String.Format("Login in {0} are disabled", scene.RegionInfo.RegionName));
break;
default:
MainConsole.Instance.Output("Syntax: login enable|disable|status");
diff --git a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs
index e5cd3e2133..09f6758ba4 100644
--- a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs
+++ b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs
@@ -37,7 +37,7 @@ using Nini.Config;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Framework.Console;
-using OpenSim.Framework.Statistics;
+using OpenSim.Framework.Monitoring;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
diff --git a/OpenSim/Region/CoreModules/World/Region/RegionCommandsModule.cs b/OpenSim/Region/CoreModules/World/Region/RegionCommandsModule.cs
index 2838e0c356..7d3547322f 100644
--- a/OpenSim/Region/CoreModules/World/Region/RegionCommandsModule.cs
+++ b/OpenSim/Region/CoreModules/World/Region/RegionCommandsModule.cs
@@ -37,7 +37,7 @@ using Nini.Config;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Framework.Console;
-using OpenSim.Framework.Statistics;
+using OpenSim.Framework.Monitoring;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
diff --git a/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs b/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs
index d768a1ac16..14c1a3947e 100644
--- a/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs
+++ b/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs
@@ -119,17 +119,20 @@ namespace OpenSim.Region.CoreModules.World.Sound
m_scene.ForEachRootScenePresence(delegate(ScenePresence sp)
{
double dis = Util.GetDistanceTo(sp.AbsolutePosition, position);
+
if (dis > 100.0) // Max audio distance
return;
+ float thisSpGain;
+
// Scale by distance
if (radius == 0)
- gain = (float)((double)gain * ((100.0 - dis) / 100.0));
+ thisSpGain = (float)((double)gain * ((100.0 - dis) / 100.0));
else
- gain = (float)((double)gain * ((radius - dis) / radius));
+ thisSpGain = (float)((double)gain * ((radius - dis) / radius));
sp.ControllingClient.SendTriggeredSound(
- soundId, ownerID, objectID, parentID, handle, position, (float)gain);
+ soundId, ownerID, objectID, parentID, handle, position, thisSpGain);
});
}
}
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs
index 309856f542..26b406e35a 100644
--- a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs
+++ b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs
@@ -42,6 +42,7 @@ using OpenMetaverse.Imaging;
using OpenMetaverse.StructuredData;
using OpenSim.Framework;
using OpenSim.Framework.Capabilities;
+using OpenSim.Framework.Monitoring;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Servers.HttpServer;
using OpenSim.Region.Framework.Interfaces;
diff --git a/OpenSim/Region/Framework/Interfaces/IRegionReadyModule.cs b/OpenSim/Region/Framework/Interfaces/IRegionReadyModule.cs
index aa4a757420..136ca9261b 100644
--- a/OpenSim/Region/Framework/Interfaces/IRegionReadyModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/IRegionReadyModule.cs
@@ -25,14 +25,23 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-
using System;
+using OpenSim.Framework;
namespace OpenSim.Region.Framework.Interfaces
{
public interface IRegionReadyModule
{
void OarLoadingAlert(string msg);
+
+ ///
+ /// Trigger region ready status manually.
+ ///
+ ///
+ /// This should be called by the scene if the IRegionReadyModule has set Scene.LoginLock == true
+ ///
+ ///
+ void TriggerRegionReady(IScene scene);
}
}
diff --git a/OpenSim/Region/Framework/Interfaces/IScenePresence.cs b/OpenSim/Region/Framework/Interfaces/IScenePresence.cs
index 3f68ee02ec..0fe681fb63 100644
--- a/OpenSim/Region/Framework/Interfaces/IScenePresence.cs
+++ b/OpenSim/Region/Framework/Interfaces/IScenePresence.cs
@@ -40,8 +40,6 @@ namespace OpenSim.Region.Framework.Interfaces
///
public interface IScenePresence : ISceneAgent
{
- PresenceType PresenceType { get; }
-
///
/// Copy of the script states while the agent is in transit. This state may
/// need to be placed back in case of transfer fail.
diff --git a/OpenSim/Region/Framework/Interfaces/IScriptModuleComms.cs b/OpenSim/Region/Framework/Interfaces/IScriptModuleComms.cs
index bfe1e8dc33..ed71a951cb 100644
--- a/OpenSim/Region/Framework/Interfaces/IScriptModuleComms.cs
+++ b/OpenSim/Region/Framework/Interfaces/IScriptModuleComms.cs
@@ -67,6 +67,10 @@ namespace OpenSim.Region.Framework.Interfaces
///
void DispatchReply(UUID scriptId, int code, string text, string key);
+ /// For constants
+ void RegisterConstant(string cname, object value);
+ object LookupModConstant(string cname);
+
// For use ONLY by the script API
void RaiseEvent(UUID script, string id, string module, string command, string key);
}
diff --git a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs
index 9ddac1950a..50a176bcfc 100644
--- a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs
+++ b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs
@@ -551,11 +551,5 @@ namespace OpenSim.Region.Framework.Scenes.Animation
SendAnimPack(animIDs, sequenceNums, objectIDs);
}
-
- public void Close()
- {
- m_animations = null;
- m_scenePresence = null;
- }
}
-}
+}
\ No newline at end of file
diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs
index d783e57620..7cb3811483 100644
--- a/OpenSim/Region/Framework/Scenes/EventManager.cs
+++ b/OpenSim/Region/Framework/Scenes/EventManager.cs
@@ -500,15 +500,24 @@ namespace OpenSim.Region.Framework.Scenes
public delegate void RegionHeartbeatEnd(Scene scene);
public event RegionHeartbeatEnd OnRegionHeartbeatEnd;
- public delegate void LoginsEnabled(string regionName);
-
///
- /// This should only fire in all circumstances if the RegionReady module is active.
+ /// Fired when logins to a region are enabled or disabled.
///
///
- /// TODO: Fire this even when the RegionReady module is not active.
+ ///
///
- public event LoginsEnabled OnLoginsEnabled;
+ /// Fired
+ public event RegionLoginsStatusChange OnRegionLoginsStatusChange;
+ public delegate void RegionLoginsStatusChange(IScene scene);
+
+ ///
+ /// Fired when a region is considered ready for use.
+ ///
+ ///
+ /// A region is considered ready when startup operations such as loading of scripts already on the region
+ /// have been completed.
+ ///
+ public event Action OnRegionReadyStatusChange;
public delegate void PrimsLoaded(Scene s);
public event PrimsLoaded OnPrimsLoaded;
@@ -2502,21 +2511,42 @@ namespace OpenSim.Region.Framework.Scenes
}
}
- public void TriggerLoginsEnabled (string regionName)
+ public void TriggerRegionLoginsStatusChange(IScene scene)
{
- LoginsEnabled handler = OnLoginsEnabled;
+ RegionLoginsStatusChange handler = OnRegionLoginsStatusChange;
- if ( handler != null)
+ if (handler != null)
{
- foreach (LoginsEnabled d in handler.GetInvocationList())
+ foreach (RegionLoginsStatusChange d in handler.GetInvocationList())
{
try
{
- d(regionName);
+ d(scene);
}
catch (Exception e)
{
- m_log.ErrorFormat("[EVENT MANAGER]: Delegate for LoginsEnabled failed - continuing {0} - {1}",
+ m_log.ErrorFormat("[EVENT MANAGER]: Delegate for OnRegionLoginsStatusChange failed - continuing {0} - {1}",
+ e.Message, e.StackTrace);
+ }
+ }
+ }
+ }
+
+ public void TriggerRegionReadyStatusChange(IScene scene)
+ {
+ Action handler = OnRegionReadyStatusChange;
+
+ if (handler != null)
+ {
+ foreach (Action d in handler.GetInvocationList())
+ {
+ try
+ {
+ d(scene);
+ }
+ catch (Exception e)
+ {
+ m_log.ErrorFormat("[EVENT MANAGER]: Delegate for OnRegionReadyStatusChange failed - continuing {0} - {1}",
e.Message, e.StackTrace);
}
}
diff --git a/OpenSim/Region/Framework/Scenes/RegionStatsHandler.cs b/OpenSim/Region/Framework/Scenes/RegionStatsHandler.cs
index 1365831779..c11174dc4e 100644
--- a/OpenSim/Region/Framework/Scenes/RegionStatsHandler.cs
+++ b/OpenSim/Region/Framework/Scenes/RegionStatsHandler.cs
@@ -39,7 +39,7 @@ using OpenSim.Framework.Communications;
using OpenSim.Framework.Console;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Servers.HttpServer;
-using OpenSim.Framework.Statistics;
+using OpenSim.Framework.Monitoring;
using OpenSim.Region.Framework;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
index 98b8fccb4a..672d95a724 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
@@ -811,16 +811,20 @@ namespace OpenSim.Region.Framework.Scenes
&& oldAgentID == LibraryService.LibraryRootFolder.Owner))
{
CreateNewInventoryItem(
- remoteClient, item.CreatorId, item.CreatorData, newFolderID, newName, item.Flags, callbackID, asset, (sbyte)item.InvType,
- item.BasePermissions, item.CurrentPermissions, item.EveryOnePermissions, item.NextPermissions, item.GroupPermissions, Util.UnixTimeSinceEpoch());
+ remoteClient, item.CreatorId, item.CreatorData, newFolderID,
+ newName, item.Description, item.Flags, callbackID, asset, (sbyte)item.InvType,
+ item.BasePermissions, item.CurrentPermissions, item.EveryOnePermissions,
+ item.NextPermissions, item.GroupPermissions, Util.UnixTimeSinceEpoch());
}
else
{
// If item is transfer or permissions are off or calling agent is allowed to copy item owner's inventory item.
- if (((item.CurrentPermissions & (uint)PermissionMask.Transfer) != 0) && (m_permissions.BypassPermissions() || m_permissions.CanCopyUserInventory(remoteClient.AgentId, oldItemID)))
+ if (((item.CurrentPermissions & (uint)PermissionMask.Transfer) != 0)
+ && (m_permissions.BypassPermissions()
+ || m_permissions.CanCopyUserInventory(remoteClient.AgentId, oldItemID)))
{
CreateNewInventoryItem(
- remoteClient, item.CreatorId, item.CreatorData, newFolderID, newName, item.Flags, callbackID,
+ remoteClient, item.CreatorId, item.CreatorData, newFolderID, newName, item.Description, item.Flags, callbackID,
asset, (sbyte) item.InvType,
item.NextPermissions, item.NextPermissions, item.EveryOnePermissions & item.NextPermissions,
item.NextPermissions, item.GroupPermissions, Util.UnixTimeSinceEpoch());
@@ -885,32 +889,50 @@ namespace OpenSim.Region.Framework.Scenes
///
/// Create a new inventory item.
///
- ///
- ///
- ///
- ///
- ///
- ///
- public void CreateNewInventoryItem(IClientAPI remoteClient, string creatorID, string creatorData, UUID folderID, string name, uint flags, uint callbackID,
- AssetBase asset, sbyte invType, uint nextOwnerMask, int creationDate)
+ /// Client creating this inventory item.
+ ///
+ ///
+ /// UUID of folder in which this item should be placed.
+ /// Item name.
+ /// Item description.
+ /// Item flags
+ /// Generated by the client.
+ /// Asset to which this item refers.
+ /// Type of inventory item.
+ /// Next owner pemrissions mask.
+ /// Unix timestamp at which this item was created.
+ public void CreateNewInventoryItem(
+ IClientAPI remoteClient, string creatorID, string creatorData, UUID folderID,
+ string name, string description, uint flags, uint callbackID,
+ AssetBase asset, sbyte invType, uint nextOwnerMask, int creationDate)
{
CreateNewInventoryItem(
- remoteClient, creatorID, creatorData, folderID, name, flags, callbackID, asset, invType,
+ remoteClient, creatorID, creatorData, folderID, name, description, flags, callbackID, asset, invType,
(uint)PermissionMask.All, (uint)PermissionMask.All, 0, nextOwnerMask, 0, creationDate);
}
///
/// Create a new Inventory Item
///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
+ /// Client creating this inventory item.
+ ///
+ ///
+ /// UUID of folder in which this item should be placed.
+ /// Item name.
+ /// Item description.
+ /// Item flags
+ /// Generated by the client.
+ /// Asset to which this item refers.
+ /// Type of inventory item.
+ /// Base permissions mask.
+ /// Current permissions mask.
+ /// Everyone permissions mask.
+ /// Next owner pemrissions mask.
+ /// Group permissions mask.
+ /// Unix timestamp at which this item was created.
private void CreateNewInventoryItem(
- IClientAPI remoteClient, string creatorID, string creatorData, UUID folderID, string name, uint flags, uint callbackID, AssetBase asset, sbyte invType,
+ IClientAPI remoteClient, string creatorID, string creatorData, UUID folderID,
+ string name, string description, uint flags, uint callbackID, AssetBase asset, sbyte invType,
uint baseMask, uint currentMask, uint everyoneMask, uint nextOwnerMask, uint groupMask, int creationDate)
{
InventoryItemBase item = new InventoryItemBase();
@@ -919,8 +941,8 @@ namespace OpenSim.Region.Framework.Scenes
item.CreatorData = creatorData;
item.ID = UUID.Random();
item.AssetID = asset.FullID;
- item.Description = asset.Description;
item.Name = name;
+ item.Description = description;
item.Flags = flags;
item.AssetType = asset.Type;
item.InvType = invType;
@@ -1002,7 +1024,8 @@ namespace OpenSim.Region.Framework.Scenes
asset.Description = description;
CreateNewInventoryItem(
- remoteClient, remoteClient.AgentId.ToString(), string.Empty, folderID, name, 0, callbackID, asset, invType,
+ remoteClient, remoteClient.AgentId.ToString(), string.Empty, folderID,
+ name, description, 0, callbackID, asset, invType,
(uint)PermissionMask.All, (uint)PermissionMask.All, (uint)PermissionMask.All,
(uint)PermissionMask.All, (uint)PermissionMask.All, Util.UnixTimeSinceEpoch());
}
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index ad9e91d7b9..3a28d42092 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -40,6 +40,7 @@ using OpenMetaverse;
using OpenMetaverse.Packets;
using OpenMetaverse.Imaging;
using OpenSim.Framework;
+using OpenSim.Framework.Monitoring;
using OpenSim.Services.Interfaces;
using OpenSim.Framework.Communications;
using OpenSim.Framework.Console;
@@ -129,9 +130,10 @@ namespace OpenSim.Region.Framework.Scenes
public bool m_strictAccessControl = true;
public bool m_seeIntoBannedRegion = false;
public int MaxUndoCount = 5;
+
// Using this for RegionReady module to prevent LoginsDisabled from changing under our feet;
public bool LoginLock = false;
- public bool LoginsDisabled = true;
+
public bool StartDisabled = false;
public bool LoadingPrims;
public IXfer XferManager;
@@ -727,6 +729,8 @@ namespace OpenSim.Region.Framework.Scenes
{
IConfig startupConfig = m_config.Configs["Startup"];
+ StartDisabled = startupConfig.GetBoolean("StartDisabled", false);
+
m_defaultDrawDistance = startupConfig.GetFloat("DefaultDrawDistance",m_defaultDrawDistance);
m_useBackup = startupConfig.GetBoolean("UseSceneBackup", m_useBackup);
if (!m_useBackup)
@@ -1229,15 +1233,17 @@ namespace OpenSim.Region.Framework.Scenes
avatar.ControllingClient.SendShutdownConnectionNotice();
});
+ // Stop updating the scene objects and agents.
+ m_shuttingDown = true;
+
// Wait here, or the kick messages won't actually get to the agents before the scene terminates.
+ // We also need to wait to avoid a race condition with the scene update loop which might not yet
+ // have checked ShuttingDown.
Thread.Sleep(500);
// Stop all client threads.
ForEachScenePresence(delegate(ScenePresence avatar) { avatar.ControllingClient.Close(); });
- // Stop updating the scene objects and agents.
- m_shuttingDown = true;
-
m_log.Debug("[SCENE]: Persisting changed objects");
EventManager.TriggerSceneShuttingDown(this);
@@ -1252,6 +1258,15 @@ namespace OpenSim.Region.Framework.Scenes
m_sceneGraph.Close();
+ if (PhysicsScene != null)
+ {
+ PhysicsScene phys = PhysicsScene;
+ // remove the physics engine from both Scene and SceneGraph
+ PhysicsScene = null;
+ phys.Dispose();
+ phys = null;
+ }
+
if (!GridService.DeregisterRegion(RegionInfo.RegionID))
m_log.WarnFormat("[SCENE]: Deregister from grid failed for region {0}", Name);
@@ -1530,7 +1545,7 @@ namespace OpenSim.Region.Framework.Scenes
// landMS = Util.EnvironmentTickCountSubtract(ldMS);
//}
- if (LoginsDisabled && Frame == 20)
+ if (!LoginsEnabled && Frame == 20)
{
// m_log.DebugFormat("{0} {1} {2}", LoginsDisabled, m_sceneGraph.GetActiveScriptsCount(), LoginLock);
@@ -1538,31 +1553,34 @@ namespace OpenSim.Region.Framework.Scenes
// this is a rare case where we know we have just went through a long cycle of heap
// allocations, and there is no more work to be done until someone logs in
GC.Collect();
-
- IConfig startupConfig = m_config.Configs["Startup"];
- if (startupConfig == null || !startupConfig.GetBoolean("StartDisabled", false))
+
+ if (!LoginLock)
+ {
+ if (!StartDisabled)
+ {
+ m_log.InfoFormat("[REGION]: Enabling logins for {0}", RegionInfo.RegionName);
+ LoginsEnabled = true;
+ }
+
+ m_sceneGridService.InformNeighborsThatRegionisUp(
+ RequestModuleInterface(), RegionInfo);
+
+ // Region ready should always be set
+ Ready = true;
+ }
+ else
{
// This handles a case of a region having no scripts for the RegionReady module
if (m_sceneGraph.GetActiveScriptsCount() == 0)
{
- // need to be able to tell these have changed in RegionReady
- LoginLock = false;
- EventManager.TriggerLoginsEnabled(RegionInfo.RegionName);
+ // In this case, we leave it to the IRegionReadyModule to enable logins
+
+ // LoginLock can currently only be set by a region module implementation.
+ // If somehow this hasn't been done then the quickest way to bugfix is to see the
+ // NullReferenceException
+ IRegionReadyModule rrm = RequestModuleInterface();
+ rrm.TriggerRegionReady(this);
}
-
- // For RegionReady lockouts
- if (!LoginLock)
- {
- m_log.InfoFormat("[REGION]: Enabling logins for {0}", RegionInfo.RegionName);
- LoginsDisabled = false;
- }
-
- m_sceneGridService.InformNeighborsThatRegionisUp(RequestModuleInterface(), RegionInfo);
- }
- else
- {
- StartDisabled = true;
- LoginsDisabled = true;
}
}
}
@@ -3477,25 +3495,31 @@ namespace OpenSim.Region.Framework.Scenes
if (AgentTransactionsModule != null)
AgentTransactionsModule.RemoveAgentAssetTransactions(agentID);
- avatar.Close();
-
m_authenticateHandler.RemoveCircuit(avatar.ControllingClient.CircuitCode);
m_log.Debug("[Scene] The avatar has left the building");
}
catch (Exception e)
{
m_log.Error(
- string.Format("[SCENE]: Exception removing {0} from {1}, ", avatar.Name, RegionInfo.RegionName), e);
+ string.Format("[SCENE]: Exception removing {0} from {1}. Cleaning up. Exception ", avatar.Name, Name), e);
}
finally
{
- // Always clean these structures up so that any failure above doesn't cause them to remain in the
- // scene with possibly bad effects (e.g. continually timing out on unacked packets and triggering
- // the same cleanup exception continually.
- // TODO: This should probably extend to the whole method, but we don't want to also catch the NRE
- // since this would hide the underlying failure and other associated problems.
- m_sceneGraph.RemoveScenePresence(agentID);
- m_clientManager.Remove(agentID);
+ try
+ {
+ // Always clean these structures up so that any failure above doesn't cause them to remain in the
+ // scene with possibly bad effects (e.g. continually timing out on unacked packets and triggering
+ // the same cleanup exception continually.
+ m_sceneGraph.RemoveScenePresence(agentID);
+ m_clientManager.Remove(agentID);
+
+ avatar.Close();
+ }
+ catch (Exception e)
+ {
+ m_log.Error(
+ string.Format("[SCENE]: Exception in final clean up of {0} in {1}. Exception ", avatar.Name, Name), e);
+ }
}
//m_log.InfoFormat("[SCENE] Memory pre GC {0}", System.GC.GetTotalMemory(false));
@@ -3609,7 +3633,7 @@ namespace OpenSim.Region.Framework.Scenes
agent.startpos
);
- if (LoginsDisabled)
+ if (!LoginsEnabled)
{
reason = "Logins Disabled";
return false;
@@ -3666,8 +3690,8 @@ namespace OpenSim.Region.Framework.Scenes
// We have a zombie from a crashed session.
// Or the same user is trying to be root twice here, won't work.
// Kill it.
- m_log.DebugFormat(
- "[SCENE]: Zombie scene presence detected for {0} {1} in {2}",
+ m_log.WarnFormat(
+ "[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.",
sp.Name, sp.UUID, RegionInfo.RegionName);
sp.ControllingClient.Close();
@@ -4657,6 +4681,23 @@ namespace OpenSim.Region.Framework.Scenes
return m_sceneGraph.GetScenePresence(localID);
}
+ ///
+ /// Gets all the scene presences in this scene.
+ ///
+ ///
+ /// This method will return both root and child scene presences.
+ ///
+ /// Consider using ForEachScenePresence() or ForEachRootScenePresence() if possible since these will not
+ /// involving creating a new List object.
+ ///
+ ///
+ /// A list of the scene presences. Adding or removing from the list will not affect the presences in the scene.
+ ///
+ public List GetScenePresences()
+ {
+ return new List(m_sceneGraph.GetScenePresences());
+ }
+
///
/// Performs action on all avatars in the scene (root scene presences)
/// Avatars may be an NPC or a 'real' client.
@@ -5775,5 +5816,21 @@ Environment.Exit(1);
{
GC.Collect();
}
+
+ // Wrappers to get physics modules retrieve assets. Has to be done this way
+ // because we can't assign the asset service to physics directly - at the
+ // time physics are instantiated it's not registered but it will be by
+ // the time the first prim exists.
+ public void PhysicsRequestAsset(UUID assetID, AssetReceivedDelegate callback)
+ {
+ AssetService.Get(assetID.ToString(), callback, PhysicsAssetReceived);
+ }
+
+ private void PhysicsAssetReceived(string id, Object sender, AssetBase asset)
+ {
+ AssetReceivedDelegate callback = (AssetReceivedDelegate)sender;
+
+ callback(asset);
+ }
}
}
diff --git a/OpenSim/Region/Framework/Scenes/SceneBase.cs b/OpenSim/Region/Framework/Scenes/SceneBase.cs
index 8db439720c..7c8bd8840c 100644
--- a/OpenSim/Region/Framework/Scenes/SceneBase.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneBase.cs
@@ -106,6 +106,42 @@ namespace OpenSim.Region.Framework.Scenes
protected readonly ClientManager m_clientManager = new ClientManager();
+ public bool LoginsEnabled
+ {
+ get
+ {
+ return m_loginsEnabled;
+ }
+
+ set
+ {
+ if (m_loginsEnabled != value)
+ {
+ m_loginsEnabled = value;
+ EventManager.TriggerRegionLoginsStatusChange(this);
+ }
+ }
+ }
+ private bool m_loginsEnabled;
+
+ public bool Ready
+ {
+ get
+ {
+ return m_ready;
+ }
+
+ set
+ {
+ if (m_ready != value)
+ {
+ m_ready = value;
+ EventManager.TriggerRegionReadyStatusChange(this);
+ }
+ }
+ }
+ private bool m_ready;
+
public float TimeDilation
{
get { return 1.0f; }
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
index c3d66eb466..e0260e22d1 100644
--- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
@@ -848,7 +848,7 @@ namespace OpenSim.Region.Framework.Scenes
/// pass a delegate to ForEachScenePresence.
///
///
- private List GetScenePresences()
+ protected internal List GetScenePresences()
{
return m_scenePresenceArray;
}
diff --git a/OpenSim/Region/Framework/Scenes/SceneManager.cs b/OpenSim/Region/Framework/Scenes/SceneManager.cs
index e3fed493c4..f1b09cac37 100644
--- a/OpenSim/Region/Framework/Scenes/SceneManager.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneManager.cs
@@ -47,6 +47,48 @@ namespace OpenSim.Region.Framework.Scenes
public event RestartSim OnRestartSim;
+ ///
+ /// Fired when either all regions are ready for use or at least one region has become unready for use where
+ /// previously all regions were ready.
+ ///
+ public event Action OnRegionsReadyStatusChange;
+
+ ///
+ /// Are all regions ready for use?
+ ///
+ public bool AllRegionsReady
+ {
+ get
+ {
+ return m_allRegionsReady;
+ }
+
+ private set
+ {
+ if (m_allRegionsReady != value)
+ {
+ m_allRegionsReady = value;
+ Action handler = OnRegionsReadyStatusChange;
+ if (handler != null)
+ {
+ foreach (Action d in handler.GetInvocationList())
+ {
+ try
+ {
+ d(this);
+ }
+ catch (Exception e)
+ {
+ m_log.ErrorFormat("[SCENE MANAGER]: Delegate for OnRegionsReadyStatusChange failed - continuing {0} - {1}",
+ e.Message, e.StackTrace);
+ }
+ }
+ }
+ }
+ }
+ }
+ private bool m_allRegionsReady;
+
private static SceneManager m_instance = null;
public static SceneManager Instance
{
@@ -128,9 +170,11 @@ namespace OpenSim.Region.Framework.Scenes
public void Add(Scene scene)
{
- scene.OnRestart += HandleRestart;
+ lock (m_localScenes)
+ m_localScenes.Add(scene.RegionInfo.RegionID, scene.RegionInfo.RegionName, scene);
- m_localScenes.Add(scene.RegionInfo.RegionID, scene.RegionInfo.RegionName, scene);
+ scene.OnRestart += HandleRestart;
+ scene.EventManager.OnRegionReadyStatusChange += HandleRegionReadyStatusChange;
}
public void HandleRestart(RegionInfo rdata)
@@ -138,12 +182,19 @@ namespace OpenSim.Region.Framework.Scenes
m_log.Error("[SCENEMANAGER]: Got Restart message for region:" + rdata.RegionName + " Sending up to main");
int RegionSceneElement = -1;
- m_localScenes.Remove(rdata.RegionID);
+ lock (m_localScenes)
+ m_localScenes.Remove(rdata.RegionID);
// Send signal to main that we're restarting this sim.
OnRestartSim(rdata);
}
+ private void HandleRegionReadyStatusChange(IScene scene)
+ {
+ lock (m_localScenes)
+ AllRegionsReady = m_localScenes.FindAll(s => !s.Ready).Count == 0;
+ }
+
public void SendSimOnlineNotification(ulong regionHandle)
{
RegionInfo Result = null;
@@ -483,7 +534,8 @@ namespace OpenSim.Region.Framework.Scenes
public void CloseScene(Scene scene)
{
- m_localScenes.Remove(scene.RegionInfo.RegionID);
+ lock (m_localScenes)
+ m_localScenes.Remove(scene.RegionInfo.RegionID);
scene.Close();
}
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 6ab0027d7e..08c7a58519 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -1991,7 +1991,7 @@ namespace OpenSim.Region.Framework.Scenes
try
{
if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
- m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things
+ !m_scene.LoginsEnabled || // We're starting up or doing maintenance, don't mess with things
m_scene.LoadingPrims) // Land may not be valid yet
{
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index cdabd45d66..4d3ab517cb 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -110,15 +110,10 @@ namespace OpenSim.Region.Framework.Scenes
public UUID currentParcelUUID = UUID.Zero;
- protected ScenePresenceAnimator m_animator;
///
/// The animator for this avatar
///
- public ScenePresenceAnimator Animator
- {
- get { return m_animator; }
- private set { m_animator = value; }
- }
+ public ScenePresenceAnimator Animator { get; private set; }
///
/// Attachments recorded on this avatar.
@@ -2763,8 +2758,7 @@ namespace OpenSim.Region.Framework.Scenes
//m_log.DebugFormat("[SCENE PRESENCE] SendAvatarDataToAgent from {0} ({1}) to {2} ({3})", Name, UUID, avatar.Name, avatar.UUID);
avatar.ControllingClient.SendAvatarDataImmediate(this);
- if (Animator != null)
- Animator.SendAnimPackToClient(avatar.ControllingClient);
+ Animator.SendAnimPackToClient(avatar.ControllingClient);
}
///
@@ -3440,6 +3434,16 @@ namespace OpenSim.Region.Framework.Scenes
if (IsChildAgent)
return;
+ //if ((Math.Abs(Velocity.X) > 0.1e-9f) || (Math.Abs(Velocity.Y) > 0.1e-9f))
+ // The Physics Scene will send updates every 500 ms grep: PhysicsActor.SubscribeEvents(
+ // as of this comment the interval is set in AddToPhysicalScene
+
+// if (m_updateCount > 0)
+// {
+ Animator.UpdateMovementAnimations();
+// m_updateCount--;
+// }
+
CollisionEventUpdate collisionData = (CollisionEventUpdate)e;
Dictionary coldata = collisionData.m_objCollisionList;
@@ -3453,7 +3457,7 @@ namespace OpenSim.Region.Framework.Scenes
// m_lastColCount = coldata.Count;
// }
- if (coldata.Count != 0 && Animator != null)
+ if (coldata.Count != 0)
{
switch (Animator.CurrentMovementAnimation)
{
@@ -3565,7 +3569,7 @@ namespace OpenSim.Region.Framework.Scenes
ControllingClient.SendHealth(Health);
}
- public void Close()
+ protected internal void Close()
{
// Clear known regions
KnownRegions = new Dictionary();
@@ -3581,9 +3585,6 @@ namespace OpenSim.Region.Framework.Scenes
// m_reprioritizationTimer.Dispose();
RemoveFromPhysicalScene();
- if(Animator != null)
- Animator.Close();
- Animator = null;
}
public void AddAttachment(SceneObjectGroup gobj)
diff --git a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
index d6ff5a2890..20919a1982 100644
--- a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
+++ b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
@@ -30,7 +30,7 @@ using System.Collections.Generic;
using System.Timers;
using OpenMetaverse.Packets;
using OpenSim.Framework;
-using OpenSim.Framework.Statistics;
+using OpenSim.Framework.Monitoring;
using OpenSim.Region.Framework.Interfaces;
namespace OpenSim.Region.Framework.Scenes
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs
index 02c45ef11c..5758869e7a 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs
@@ -53,48 +53,83 @@ namespace OpenSim.Region.Framework.Scenes.Tests
/// Scene presence tests
///
[TestFixture]
- public class ScenePresenceAgentTests
+ public class ScenePresenceAgentTests : OpenSimTestCase
{
- public Scene scene, scene2, scene3;
- public UUID agent1, agent2, agent3;
- public static Random random;
- public ulong region1,region2,region3;
- public AgentCircuitData acd1;
- public SceneObjectGroup sog1, sog2, sog3;
- public TestClient testclient;
+// public Scene scene, scene2, scene3;
+// public UUID agent1, agent2, agent3;
+// public static Random random;
+// public ulong region1, region2, region3;
+// public AgentCircuitData acd1;
+// public TestClient testclient;
- [TestFixtureSetUp]
- public void Init()
+// [TestFixtureSetUp]
+// public void Init()
+// {
+//// TestHelpers.InMethod();
+////
+//// SceneHelpers sh = new SceneHelpers();
+////
+//// scene = sh.SetupScene("Neighbour x", UUID.Random(), 1000, 1000);
+//// scene2 = sh.SetupScene("Neighbour x+1", UUID.Random(), 1001, 1000);
+//// scene3 = sh.SetupScene("Neighbour x-1", UUID.Random(), 999, 1000);
+////
+//// ISharedRegionModule interregionComms = new LocalSimulationConnectorModule();
+//// interregionComms.Initialise(new IniConfigSource());
+//// interregionComms.PostInitialise();
+//// SceneHelpers.SetupSceneModules(scene, new IniConfigSource(), interregionComms);
+//// SceneHelpers.SetupSceneModules(scene2, new IniConfigSource(), interregionComms);
+//// SceneHelpers.SetupSceneModules(scene3, new IniConfigSource(), interregionComms);
+//
+//// agent1 = UUID.Random();
+//// agent2 = UUID.Random();
+//// agent3 = UUID.Random();
+//
+//// region1 = scene.RegionInfo.RegionHandle;
+//// region2 = scene2.RegionInfo.RegionHandle;
+//// region3 = scene3.RegionInfo.RegionHandle;
+// }
+
+ [Test]
+ public void TestCreateRootScenePresence()
{
TestHelpers.InMethod();
+// TestHelpers.EnableLogging();
- SceneHelpers sh = new SceneHelpers();
+ UUID spUuid = TestHelpers.ParseTail(0x1);
- scene = sh.SetupScene("Neighbour x", UUID.Random(), 1000, 1000);
- scene2 = sh.SetupScene("Neighbour x+1", UUID.Random(), 1001, 1000);
- scene3 = sh.SetupScene("Neighbour x-1", UUID.Random(), 999, 1000);
+ TestScene scene = new SceneHelpers().SetupScene();
+ SceneHelpers.AddScenePresence(scene, spUuid);
- ISharedRegionModule interregionComms = new LocalSimulationConnectorModule();
- interregionComms.Initialise(new IniConfigSource());
- interregionComms.PostInitialise();
- SceneHelpers.SetupSceneModules(scene, new IniConfigSource(), interregionComms);
- SceneHelpers.SetupSceneModules(scene2, new IniConfigSource(), interregionComms);
- SceneHelpers.SetupSceneModules(scene3, new IniConfigSource(), interregionComms);
+ Assert.That(scene.AuthenticateHandler.GetAgentCircuitData(spUuid), Is.Not.Null);
+ Assert.That(scene.AuthenticateHandler.GetAgentCircuits().Count, Is.EqualTo(1));
- agent1 = UUID.Random();
- agent2 = UUID.Random();
- agent3 = UUID.Random();
- random = new Random();
- sog1 = SceneHelpers.CreateSceneObject(1, agent1);
- scene.AddSceneObject(sog1);
- sog2 = SceneHelpers.CreateSceneObject(1, agent1);
- scene.AddSceneObject(sog2);
- sog3 = SceneHelpers.CreateSceneObject(1, agent1);
- scene.AddSceneObject(sog3);
+ ScenePresence sp = scene.GetScenePresence(spUuid);
+ Assert.That(sp, Is.Not.Null);
+ Assert.That(sp.IsChildAgent, Is.False);
+ Assert.That(sp.UUID, Is.EqualTo(spUuid));
- region1 = scene.RegionInfo.RegionHandle;
- region2 = scene2.RegionInfo.RegionHandle;
- region3 = scene3.RegionInfo.RegionHandle;
+ Assert.That(scene.GetScenePresences().Count, Is.EqualTo(1));
+ }
+
+ [Test]
+ public void TestCreateDuplicateRootScenePresence()
+ {
+ TestHelpers.InMethod();
+// TestHelpers.EnableLogging();
+
+ UUID spUuid = TestHelpers.ParseTail(0x1);
+
+ TestScene scene = new SceneHelpers().SetupScene();
+ SceneHelpers.AddScenePresence(scene, spUuid);
+ SceneHelpers.AddScenePresence(scene, spUuid);
+
+ Assert.That(scene.AuthenticateHandler.GetAgentCircuitData(spUuid), Is.Not.Null);
+ Assert.That(scene.AuthenticateHandler.GetAgentCircuits().Count, Is.EqualTo(1));
+
+ ScenePresence sp = scene.GetScenePresence(spUuid);
+ Assert.That(sp, Is.Not.Null);
+ Assert.That(sp.IsChildAgent, Is.False);
+ Assert.That(sp.UUID, Is.EqualTo(spUuid));
}
[Test]
@@ -106,9 +141,6 @@ namespace OpenSim.Region.Framework.Scenes.Tests
TestScene scene = new SceneHelpers().SetupScene();
ScenePresence sp = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x1));
- Assert.That(scene.AuthenticateHandler.GetAgentCircuitData(sp.UUID), Is.Not.Null);
- Assert.That(scene.AuthenticateHandler.GetAgentCircuits().Count, Is.EqualTo(1));
-
scene.IncomingCloseAgent(sp.UUID);
Assert.That(scene.GetScenePresence(sp.UUID), Is.Null);
@@ -266,99 +298,99 @@ namespace OpenSim.Region.Framework.Scenes.Tests
// but things are synchronous among them. So there should be
// 3 threads in here.
//[Test]
- public void T021_TestCrossToNewRegion()
- {
- TestHelpers.InMethod();
-
- scene.RegisterRegionWithGrid();
- scene2.RegisterRegionWithGrid();
-
- // Adding child agent to region 1001
- string reason;
- scene2.NewUserConnection(acd1,0, out reason);
- scene2.AddNewClient(testclient, PresenceType.User);
-
- ScenePresence presence = scene.GetScenePresence(agent1);
- presence.MakeRootAgent(new Vector3(0,unchecked(Constants.RegionSize-1),0), true);
-
- ScenePresence presence2 = scene2.GetScenePresence(agent1);
-
- // Adding neighbour region caps info to presence2
-
- string cap = presence.ControllingClient.RequestClientInfo().CapsPath;
- presence2.AddNeighbourRegion(region1, cap);
-
- Assert.That(presence.IsChildAgent, Is.False, "Did not start root in origin region.");
- Assert.That(presence2.IsChildAgent, Is.True, "Is not a child on destination region.");
-
- // Cross to x+1
- presence.AbsolutePosition = new Vector3(Constants.RegionSize+1,3,100);
- presence.Update();
-
- EventWaitHandle wh = new EventWaitHandle (false, EventResetMode.AutoReset, "Crossing");
-
- // Mimicking communication between client and server, by waiting OK from client
- // sent by TestClient.CrossRegion call. Originally, this is network comm.
- if (!wh.WaitOne(5000,false))
- {
- presence.Update();
- if (!wh.WaitOne(8000,false))
- throw new ArgumentException("1 - Timeout waiting for signal/variable.");
- }
-
- // This is a TestClient specific method that fires OnCompleteMovementToRegion event, which
- // would normally be fired after receiving the reply packet from comm. done on the last line.
- testclient.CompleteMovement();
-
- // Crossings are asynchronous
- int timer = 10;
-
- // Make sure cross hasn't already finished
- if (!presence.IsInTransit && !presence.IsChildAgent)
- {
- // If not and not in transit yet, give it some more time
- Thread.Sleep(5000);
- }
-
- // Enough time, should at least be in transit by now.
- while (presence.IsInTransit && timer > 0)
- {
- Thread.Sleep(1000);
- timer-=1;
- }
-
- Assert.That(timer,Is.GreaterThan(0),"Timed out waiting to cross 2->1.");
- Assert.That(presence.IsChildAgent, Is.True, "Did not complete region cross as expected.");
- Assert.That(presence2.IsChildAgent, Is.False, "Did not receive root status after receiving agent.");
-
- // Cross Back
- presence2.AbsolutePosition = new Vector3(-10, 3, 100);
- presence2.Update();
-
- if (!wh.WaitOne(5000,false))
- {
- presence2.Update();
- if (!wh.WaitOne(8000,false))
- throw new ArgumentException("2 - Timeout waiting for signal/variable.");
- }
- testclient.CompleteMovement();
-
- if (!presence2.IsInTransit && !presence2.IsChildAgent)
- {
- // If not and not in transit yet, give it some more time
- Thread.Sleep(5000);
- }
-
- // Enough time, should at least be in transit by now.
- while (presence2.IsInTransit && timer > 0)
- {
- Thread.Sleep(1000);
- timer-=1;
- }
-
- Assert.That(timer,Is.GreaterThan(0),"Timed out waiting to cross 1->2.");
- Assert.That(presence2.IsChildAgent, Is.True, "Did not return from region as expected.");
- Assert.That(presence.IsChildAgent, Is.False, "Presence was not made root in old region again.");
- }
+// public void T021_TestCrossToNewRegion()
+// {
+// TestHelpers.InMethod();
+//
+// scene.RegisterRegionWithGrid();
+// scene2.RegisterRegionWithGrid();
+//
+// // Adding child agent to region 1001
+// string reason;
+// scene2.NewUserConnection(acd1,0, out reason);
+// scene2.AddNewClient(testclient, PresenceType.User);
+//
+// ScenePresence presence = scene.GetScenePresence(agent1);
+// presence.MakeRootAgent(new Vector3(0,unchecked(Constants.RegionSize-1),0), true);
+//
+// ScenePresence presence2 = scene2.GetScenePresence(agent1);
+//
+// // Adding neighbour region caps info to presence2
+//
+// string cap = presence.ControllingClient.RequestClientInfo().CapsPath;
+// presence2.AddNeighbourRegion(region1, cap);
+//
+// Assert.That(presence.IsChildAgent, Is.False, "Did not start root in origin region.");
+// Assert.That(presence2.IsChildAgent, Is.True, "Is not a child on destination region.");
+//
+// // Cross to x+1
+// presence.AbsolutePosition = new Vector3(Constants.RegionSize+1,3,100);
+// presence.Update();
+//
+// EventWaitHandle wh = new EventWaitHandle (false, EventResetMode.AutoReset, "Crossing");
+//
+// // Mimicking communication between client and server, by waiting OK from client
+// // sent by TestClient.CrossRegion call. Originally, this is network comm.
+// if (!wh.WaitOne(5000,false))
+// {
+// presence.Update();
+// if (!wh.WaitOne(8000,false))
+// throw new ArgumentException("1 - Timeout waiting for signal/variable.");
+// }
+//
+// // This is a TestClient specific method that fires OnCompleteMovementToRegion event, which
+// // would normally be fired after receiving the reply packet from comm. done on the last line.
+// testclient.CompleteMovement();
+//
+// // Crossings are asynchronous
+// int timer = 10;
+//
+// // Make sure cross hasn't already finished
+// if (!presence.IsInTransit && !presence.IsChildAgent)
+// {
+// // If not and not in transit yet, give it some more time
+// Thread.Sleep(5000);
+// }
+//
+// // Enough time, should at least be in transit by now.
+// while (presence.IsInTransit && timer > 0)
+// {
+// Thread.Sleep(1000);
+// timer-=1;
+// }
+//
+// Assert.That(timer,Is.GreaterThan(0),"Timed out waiting to cross 2->1.");
+// Assert.That(presence.IsChildAgent, Is.True, "Did not complete region cross as expected.");
+// Assert.That(presence2.IsChildAgent, Is.False, "Did not receive root status after receiving agent.");
+//
+// // Cross Back
+// presence2.AbsolutePosition = new Vector3(-10, 3, 100);
+// presence2.Update();
+//
+// if (!wh.WaitOne(5000,false))
+// {
+// presence2.Update();
+// if (!wh.WaitOne(8000,false))
+// throw new ArgumentException("2 - Timeout waiting for signal/variable.");
+// }
+// testclient.CompleteMovement();
+//
+// if (!presence2.IsInTransit && !presence2.IsChildAgent)
+// {
+// // If not and not in transit yet, give it some more time
+// Thread.Sleep(5000);
+// }
+//
+// // Enough time, should at least be in transit by now.
+// while (presence2.IsInTransit && timer > 0)
+// {
+// Thread.Sleep(1000);
+// timer-=1;
+// }
+//
+// Assert.That(timer,Is.GreaterThan(0),"Timed out waiting to cross 1->2.");
+// Assert.That(presence2.IsChildAgent, Is.True, "Did not return from region as expected.");
+// Assert.That(presence.IsChildAgent, Is.False, "Presence was not made root in old region again.");
+// }
}
}
\ No newline at end of file
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs
index a407f01d63..37b5184715 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs
@@ -301,7 +301,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
sp.AbsolutePosition = preTeleportPosition;
// Make sceneB refuse CreateAgent
- sceneB.LoginsDisabled = true;
+ sceneB.LoginsEnabled = false;
sceneA.RequestTeleportLocation(
sp.ControllingClient,
diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
index 86f33eb463..3b83e58933 100644
--- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
+++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
@@ -38,6 +38,7 @@ using OpenMetaverse;
using OpenMetaverse.Packets;
using OpenSim.Framework;
using OpenSim.Framework.Client;
+using OpenSim.Framework.Monitoring;
using OpenSim.Region.Framework.Scenes;
namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCServer.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCServer.cs
index a7c5020eb6..9d27386a5a 100644
--- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCServer.cs
+++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCServer.cs
@@ -34,6 +34,7 @@ using System.Text;
using System.Threading;
using log4net;
using OpenSim.Framework;
+using OpenSim.Framework.Monitoring;
using OpenSim.Region.Framework.Scenes;
namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
diff --git a/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs b/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs
index a7ebeccdc9..5fe594860d 100644
--- a/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs
+++ b/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs
@@ -35,7 +35,7 @@ using Nini.Config;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Framework.Console;
-using OpenSim.Framework.Statistics;
+using OpenSim.Framework.Monitoring;
using OpenSim.Region.ClientStack.LindenUDP;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
@@ -81,18 +81,6 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
lock (m_scenes)
m_scenes[scene.RegionInfo.RegionID] = scene;
- scene.AddCommand(
- "Comms", this, "image queues clear",
- "image queues clear ",
- "Clear the image queues (textures downloaded via UDP) for a particular client.",
- (mod, cmd) => MainConsole.Instance.Output(HandleImageQueuesClear(cmd)));
-
- scene.AddCommand(
- "Comms", this, "image queues show",
- "image queues show ",
- "Show the image queues (textures downloaded via UDP) for a particular client.",
- (mod, cmd) => MainConsole.Instance.Output(GetImageQueuesReport(cmd)));
-
scene.AddCommand(
"Comms", this, "show pqueues",
"show pqueues [full]",
@@ -105,8 +93,15 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
"Comms", this, "show queues",
"show queues [full]",
"Show queue data for each client",
- "Without the 'full' option, only root agents are shown."
- + " With the 'full' option child agents are also shown.",
+ "Without the 'full' option, only root agents are shown.\n"
+ + "With the 'full' option child agents are also shown.\n\n"
+ + "Type - Rt is a root (avatar) client whilst cd is a child (neighbour interacting) client.\n"
+ + "Since Last In - Time in milliseconds since last packet received.\n"
+ + "Pkts In - Number of packets processed from the client.\n"
+ + "Pkts Out - Number of packets sent to the client.\n"
+ + "Pkts Resent - Number of packets resent to the client.\n"
+ + "Bytes Unacked - Number of bytes transferred to the client that are awaiting acknowledgement.\n"
+ + "Q Pkts * - Number of packets of various types (land, wind, etc.) to be sent to the client that are waiting for available bandwidth.\n",
(mod, cmd) => MainConsole.Instance.Output(GetQueuesReport(cmd)));
scene.AddCommand(
@@ -114,6 +109,12 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
"show image queues ",
"Show the image queues (textures downloaded via UDP) for a particular client.",
(mod, cmd) => MainConsole.Instance.Output(GetImageQueuesReport(cmd)));
+
+ scene.AddCommand(
+ "Comms", this, "clear image queues",
+ "clear image queues ",
+ "Clear the image queues (textures downloaded via UDP) for a particular client.",
+ (mod, cmd) => MainConsole.Instance.Output(HandleImageQueuesClear(cmd)));
scene.AddCommand(
"Comms", this, "show throttles",
@@ -373,17 +374,22 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
int maxNameLength = 18;
int maxRegionNameLength = 14;
int maxTypeLength = 4;
- int totalInfoFieldsLength = maxNameLength + columnPadding + maxRegionNameLength + columnPadding + maxTypeLength + columnPadding;
+
+ int totalInfoFieldsLength
+ = maxNameLength + columnPadding
+ + maxRegionNameLength + columnPadding
+ + maxTypeLength + columnPadding;
report.Append(GetColumnEntry("User", maxNameLength, columnPadding));
report.Append(GetColumnEntry("Region", maxRegionNameLength, columnPadding));
report.Append(GetColumnEntry("Type", maxTypeLength, columnPadding));
report.AppendFormat(
- "{0,7} {1,7} {2,7} {3,9} {4,7} {5,7} {6,7} {7,7} {8,7} {9,8} {10,7} {11,7}\n",
+ "{0,7} {1,7} {2,7} {3,7} {4,9} {5,7} {6,7} {7,7} {8,7} {9,7} {10,8} {11,7} {12,7}\n",
+ "Since",
+ "Pkts",
"Pkts",
"Pkts",
- "Pkts",
"Bytes",
"Q Pkts",
"Q Pkts",
@@ -396,7 +402,8 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
report.AppendFormat("{0,-" + totalInfoFieldsLength + "}", "");
report.AppendFormat(
- "{0,7} {1,7} {2,7} {3,9} {4,7} {5,7} {6,7} {7,7} {8,7} {9,8} {10,7} {11,7}\n",
+ "{0,7} {1,7} {2,7} {3,7} {4,9} {5,7} {6,7} {7,7} {8,7} {9,7} {10,8} {11,7} {12,7}\n",
+ "Last In",
"In",
"Out",
"Resent",
@@ -417,22 +424,22 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
scene.ForEachClient(
delegate(IClientAPI client)
{
+ bool isChild = client.SceneAgent.IsChildAgent;
+ if (isChild && !showChildren)
+ return;
+
+ string name = client.Name;
+ if (pname != "" && name != pname)
+ return;
+
+ string regionName = scene.RegionInfo.RegionName;
+
+ report.Append(GetColumnEntry(name, maxNameLength, columnPadding));
+ report.Append(GetColumnEntry(regionName, maxRegionNameLength, columnPadding));
+ report.Append(GetColumnEntry(isChild ? "Cd" : "Rt", maxTypeLength, columnPadding));
+
if (client is IStatsCollector)
{
- bool isChild = client.SceneAgent.IsChildAgent;
- if (isChild && !showChildren)
- return;
-
- string name = client.Name;
- if (pname != "" && name != pname)
- return;
-
- string regionName = scene.RegionInfo.RegionName;
-
- report.Append(GetColumnEntry(name, maxNameLength, columnPadding));
- report.Append(GetColumnEntry(regionName, maxRegionNameLength, columnPadding));
- report.Append(GetColumnEntry(isChild ? "Cd" : "Rt", maxTypeLength, columnPadding));
-
IStatsCollector stats = (IStatsCollector)client;
report.AppendLine(stats.Report());
diff --git a/OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs b/OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs
index 6bb6729c83..d718a2f052 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs
@@ -36,7 +36,7 @@ using Nini.Config;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Framework.Console;
-using OpenSim.Framework.Statistics;
+using OpenSim.Framework.Monitoring;
using OpenSim.Region.ClientStack.LindenUDP;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
diff --git a/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs b/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs
index 1b9e3ace5c..d68aabc5ca 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs
@@ -36,7 +36,7 @@ using Nini.Config;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Framework.Console;
-using OpenSim.Framework.Statistics;
+using OpenSim.Framework.Monitoring;
using OpenSim.Region.ClientStack.LindenUDP;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
diff --git a/OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs b/OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs
index cd401a6096..ca956fbe91 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs
@@ -37,6 +37,7 @@ using OpenMetaverse;
using log4net;
using Nini.Config;
using OpenSim.Framework;
+using OpenSim.Framework.Monitoring;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
diff --git a/OpenSim/Region/OptionalModules/Avatar/Friends/FriendsCommandsModule.cs b/OpenSim/Region/OptionalModules/Avatar/Friends/FriendsCommandsModule.cs
index 2602050de4..4e84364dd3 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Friends/FriendsCommandsModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Friends/FriendsCommandsModule.cs
@@ -37,7 +37,7 @@ using Nini.Config;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Framework.Console;
-using OpenSim.Framework.Statistics;
+using OpenSim.Framework.Monitoring;
using OpenSim.Region.ClientStack.LindenUDP;
using OpenSim.Region.CoreModules.Avatar.Friends;
using OpenSim.Region.Framework.Interfaces;
diff --git a/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs b/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs
index e45212444d..40f7fbc59a 100755
--- a/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs
+++ b/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs
@@ -47,7 +47,7 @@ namespace OpenSim.Region.OptionalModules.PhysicsParameters
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "PhysicsParameters")]
public class PhysicsParameters : ISharedRegionModule
{
- private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
// private static string LogHeader = "[PHYSICS PARAMETERS]";
private List m_scenes = new List();
diff --git a/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs b/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs
index 600cafb7c4..fff3a32010 100644
--- a/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs
@@ -31,16 +31,14 @@ using System.Reflection;
using System.Net;
using System.IO;
using System.Text;
-
using log4net;
using Nini.Config;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
-using OpenSim.Services.Interfaces;
-
using OpenSim.Framework;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
+using OpenSim.Services.Interfaces;
namespace OpenSim.Region.OptionalModules.Scripting.RegionReady
{
@@ -50,16 +48,15 @@ namespace OpenSim.Region.OptionalModules.Scripting.RegionReady
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private IConfig m_config = null;
- private bool m_ScriptRez;
private bool m_firstEmptyCompileQueue;
private bool m_oarFileLoading;
private bool m_lastOarLoadedOk;
private int m_channelNotify = -1000;
private bool m_enabled = false;
- private bool m_disable_logins = false;
+ private bool m_disable_logins;
private string m_uri = string.Empty;
- Scene m_scene = null;
+ Scene m_scene;
#region INonSharedRegionModule interface
@@ -93,53 +90,40 @@ namespace OpenSim.Region.OptionalModules.Scripting.RegionReady
m_scene.RegisterModuleInterface(this);
- m_ScriptRez = false;
m_firstEmptyCompileQueue = true;
m_oarFileLoading = false;
m_lastOarLoadedOk = true;
m_scene.EventManager.OnOarFileLoaded += OnOarFileLoaded;
- m_scene.EventManager.OnRezScript += OnRezScript;
- m_scene.EventManager.OnLoginsEnabled += OnLoginsEnabled;
m_log.DebugFormat("[RegionReady]: Enabled for region {0}", scene.RegionInfo.RegionName);
- if (m_disable_logins == true)
+ if (m_disable_logins)
{
- scene.LoginLock = true;
- scene.LoginsDisabled = true;
- m_log.InfoFormat("[RegionReady]: Region {0} - logins disabled during initialization.",m_scene.RegionInfo.RegionName);
+ m_scene.LoginLock = true;
+ m_scene.EventManager.OnEmptyScriptCompileQueue += OnEmptyScriptCompileQueue;
- if(m_uri != string.Empty)
+ m_log.InfoFormat("[RegionReady]: Region {0} - LOGINS DISABLED DURING INITIALIZATION.", m_scene.Name);
+
+ if (m_uri != string.Empty)
{
RRAlert("disabled");
}
}
}
- void OnRezScript (uint localID, UUID itemID, string script, int startParam, bool postOnRez, string engine, int stateSource)
- {
- if (!m_ScriptRez)
- {
- m_ScriptRez = true;
- m_scene.EventManager.OnEmptyScriptCompileQueue += OnEmptyScriptCompileQueue;
- m_scene.EventManager.OnRezScript -= OnRezScript;
- }
- }
-
public void RemoveRegion(Scene scene)
{
if (!m_enabled)
return;
- m_scene.EventManager.OnEmptyScriptCompileQueue -= OnEmptyScriptCompileQueue;
m_scene.EventManager.OnOarFileLoaded -= OnOarFileLoaded;
- m_scene.EventManager.OnLoginsEnabled -= OnLoginsEnabled;
- if(m_uri != string.Empty)
- {
+ if (m_disable_logins)
+ m_scene.EventManager.OnEmptyScriptCompileQueue -= OnEmptyScriptCompileQueue;
+
+ if (m_uri != string.Empty)
RRAlert("shutdown");
- }
m_scene = null;
}
@@ -159,7 +143,6 @@ namespace OpenSim.Region.OptionalModules.Scripting.RegionReady
#endregion
-
void OnEmptyScriptCompileQueue(int numScriptsFailed, string message)
{
m_log.DebugFormat("[RegionReady]: Script compile queue empty!");
@@ -193,75 +176,80 @@ namespace OpenSim.Region.OptionalModules.Scripting.RegionReady
m_scene.RegionInfo.RegionName, c.Message, m_channelNotify);
m_scene.EventManager.TriggerOnChatBroadcast(this, c);
- m_scene.EventManager.TriggerLoginsEnabled(m_scene.RegionInfo.RegionName);
- m_scene.SceneGridService.InformNeighborsThatRegionisUp(m_scene.RequestModuleInterface(), m_scene.RegionInfo);
+
+ TriggerRegionReady(m_scene);
}
}
void OnOarFileLoaded(Guid requestId, string message)
{
m_oarFileLoading = true;
+
if (message==String.Empty)
{
m_lastOarLoadedOk = true;
- } else {
+ }
+ else
+ {
m_log.WarnFormat("[RegionReady]: Oar file load errors: {0}", message);
m_lastOarLoadedOk = false;
}
}
- // This will be triggerd by Scene if we have no scripts
- // m_ScriptsRezzing will be false if there were none
- // else it will be true and we should wait on the
- // empty compile queue
- void OnLoginsEnabled(string regionName)
+ ///
+ /// This will be triggered by Scene directly if it contains no scripts on startup. Otherwise it is triggered
+ /// when the script compile queue is empty after initial region startup.
+ ///
+ ///
+ public void TriggerRegionReady(IScene scene)
{
- if (m_disable_logins == true)
+ m_scene.EventManager.OnEmptyScriptCompileQueue -= OnEmptyScriptCompileQueue;
+ m_scene.LoginLock = false;
+
+ if (!m_scene.StartDisabled)
{
- if (m_scene.StartDisabled == false)
- {
- m_scene.LoginsDisabled = false;
- m_scene.LoginLock = false;
+ m_scene.LoginsEnabled = true;
- m_scene.EventManager.OnEmptyScriptCompileQueue -= OnEmptyScriptCompileQueue;
+ // m_log.InfoFormat("[RegionReady]: Logins enabled for {0}, Oar {1}",
+ // m_scene.RegionInfo.RegionName, m_oarFileLoading.ToString());
- // m_log.InfoFormat("[RegionReady]: Logins enabled for {0}, Oar {1}",
- // m_scene.RegionInfo.RegionName, m_oarFileLoading.ToString());
-
- m_log.InfoFormat(
- "[RegionReady]: INITIALIZATION COMPLETE FOR {0} - LOGINS ENABLED", m_scene.Name);
-
- if (m_uri != string.Empty)
- {
- RRAlert("enabled");
- }
- }
+ m_log.InfoFormat(
+ "[RegionReady]: INITIALIZATION COMPLETE FOR {0} - LOGINS ENABLED", m_scene.Name);
}
+
+ m_scene.SceneGridService.InformNeighborsThatRegionisUp(
+ m_scene.RequestModuleInterface(), m_scene.RegionInfo);
+
+ if (m_uri != string.Empty)
+ {
+ RRAlert("enabled");
+ }
+
+ m_scene.Ready = true;
}
public void OarLoadingAlert(string msg)
{
// Let's bypass this for now until some better feedback can be established
//
- return;
- if (msg == "load")
- {
- m_scene.EventManager.OnEmptyScriptCompileQueue += OnEmptyScriptCompileQueue;
- m_scene.EventManager.OnOarFileLoaded += OnOarFileLoaded;
- m_scene.EventManager.OnLoginsEnabled += OnLoginsEnabled;
- m_scene.EventManager.OnRezScript += OnRezScript;
- m_oarFileLoading = true;
- m_firstEmptyCompileQueue = true;
-
- m_scene.LoginsDisabled = true;
- m_scene.LoginLock = true;
- if ( m_uri != string.Empty )
- {
- RRAlert("loading oar");
- RRAlert("disabled");
- }
- }
+// if (msg == "load")
+// {
+// m_scene.EventManager.OnEmptyScriptCompileQueue += OnEmptyScriptCompileQueue;
+// m_scene.EventManager.OnOarFileLoaded += OnOarFileLoaded;
+// m_scene.EventManager.OnLoginsEnabled += OnLoginsEnabled;
+// m_scene.EventManager.OnRezScript += OnRezScript;
+// m_oarFileLoading = true;
+// m_firstEmptyCompileQueue = true;
+//
+// m_scene.LoginsDisabled = true;
+// m_scene.LoginLock = true;
+// if ( m_uri != string.Empty )
+// {
+// RRAlert("loading oar");
+// RRAlert("disabled");
+// }
+// }
}
public void RRAlert(string status)
diff --git a/OpenSim/Region/OptionalModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs b/OpenSim/Region/OptionalModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs
index 74a85e2cd5..705a84700d 100644
--- a/OpenSim/Region/OptionalModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs
@@ -46,6 +46,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.ScriptModuleComms
private static readonly ILog m_log =
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+ private Dictionary m_constants = new Dictionary();
+
#region ScriptInvocation
protected class ScriptInvocationData
{
@@ -269,6 +271,37 @@ namespace OpenSim.Region.OptionalModules.Scripting.ScriptModuleComms
Delegate fn = LookupScriptInvocation(fname);
return fn.DynamicInvoke(olist.ToArray());
}
+
+ ///
+ /// Operation to for a region module to register a constant to be used
+ /// by the script engine
+ ///
+ public void RegisterConstant(string cname, object value)
+ {
+ m_log.DebugFormat("[MODULE COMMANDS] register constant <{0}> with value {1}",cname,value.ToString());
+ lock (m_constants)
+ {
+ m_constants.Add(cname,value);
+ }
+ }
+
+ ///
+ /// Operation to check for a registered constant
+ ///
+ public object LookupModConstant(string cname)
+ {
+ // m_log.DebugFormat("[MODULE COMMANDS] lookup constant <{0}>",cname);
+
+ lock (m_constants)
+ {
+ object value = null;
+ if (m_constants.TryGetValue(cname,out value))
+ return value;
+ }
+
+ return null;
+ }
+
#endregion
}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index dc0c0083f8..09e1f0c022 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -41,7 +41,7 @@ public class BSCharacter : PhysicsActor
private BSScene _scene;
private String _avName;
- private bool _stopped;
+ // private bool _stopped;
private Vector3 _size;
private Vector3 _scale;
private PrimitiveBaseShape _pbs;
@@ -134,9 +134,9 @@ public class BSCharacter : PhysicsActor
{
base.RequestPhysicsterseUpdate();
}
-
+ // No one calls this method so I don't know what it could possibly mean
public override bool Stopped {
- get { return _stopped; }
+ get { return false; }
}
public override Vector3 Size {
get { return _size; }
@@ -391,52 +391,47 @@ public class BSCharacter : PhysicsActor
_mass = _density * _avatarVolume;
}
- // Set to 'true' if the individual changed items should be checked
- // (someday RequestPhysicsTerseUpdate() will take a bitmap of changed properties)
- const bool SHOULD_CHECK_FOR_INDIVIDUAL_CHANGES = false;
-
// The physics engine says that properties have updated. Update same and inform
// the world that things have changed.
public void UpdateProperties(EntityProperties entprop)
{
+ /*
bool changed = false;
- if (SHOULD_CHECK_FOR_INDIVIDUAL_CHANGES) {
- // we assign to the local variables so the normal set action does not happen
- if (_position != entprop.Position) {
- _position = entprop.Position;
- changed = true;
- }
- if (_orientation != entprop.Rotation) {
- _orientation = entprop.Rotation;
- changed = true;
- }
- if (_velocity != entprop.Velocity) {
- _velocity = entprop.Velocity;
- changed = true;
- }
- if (_acceleration != entprop.Acceleration) {
- _acceleration = entprop.Acceleration;
- changed = true;
- }
- if (_rotationalVelocity != entprop.RotationalVelocity) {
- _rotationalVelocity = entprop.RotationalVelocity;
- changed = true;
- }
- if (changed) {
- // m_log.DebugFormat("{0}: UpdateProperties: id={1}, c={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation);
- // Avatar movement is not done by generating this event. There is code in the heartbeat
- // loop that updates avatars.
- // base.RequestPhysicsterseUpdate();
- }
- }
- else {
+ // we assign to the local variables so the normal set action does not happen
+ if (_position != entprop.Position) {
_position = entprop.Position;
+ changed = true;
+ }
+ if (_orientation != entprop.Rotation) {
_orientation = entprop.Rotation;
+ changed = true;
+ }
+ if (_velocity != entprop.Velocity) {
_velocity = entprop.Velocity;
+ changed = true;
+ }
+ if (_acceleration != entprop.Acceleration) {
_acceleration = entprop.Acceleration;
+ changed = true;
+ }
+ if (_rotationalVelocity != entprop.RotationalVelocity) {
_rotationalVelocity = entprop.RotationalVelocity;
+ changed = true;
+ }
+ if (changed) {
+ // m_log.DebugFormat("{0}: UpdateProperties: id={1}, c={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation);
+ // Avatar movement is not done by generating this event. There is code in the heartbeat
+ // loop that updates avatars.
// base.RequestPhysicsterseUpdate();
}
+ */
+ _position = entprop.Position;
+ _orientation = entprop.Rotation;
+ _velocity = entprop.Velocity;
+ _acceleration = entprop.Acceleration;
+ _rotationalVelocity = entprop.RotationalVelocity;
+ // Avatars don't report theirr changes the usual way. Changes are checked for in the heartbeat loop.
+ // base.RequestPhysicsterseUpdate();
}
// Called by the scene when a collision with this object is reported
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
new file mode 100755
index 0000000000..ea3093a96b
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
@@ -0,0 +1,125 @@
+/*
+ * 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 copyrightD
+ * 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.Text;
+using OpenMetaverse;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+
+public class BSConstraint : IDisposable
+{
+ private BulletSim m_world;
+ private BulletBody m_body1;
+ private BulletBody m_body2;
+ private BulletConstraint m_constraint;
+ private bool m_enabled = false;
+
+ public BSConstraint(BulletSim world, BulletBody obj1, BulletBody obj2,
+ Vector3 frame1, Quaternion frame1rot,
+ Vector3 frame2, Quaternion frame2rot
+ )
+ {
+ m_world = world;
+ m_body1 = obj1;
+ m_body2 = obj2;
+ m_constraint = new BulletConstraint(BulletSimAPI.CreateConstraint2(m_world.Ptr, m_body1.Ptr, m_body2.Ptr,
+ frame1, frame1rot,
+ frame2, frame2rot,
+ true /*useLinearReferenceFrameA*/, true /*disableCollisionsBetweenLinkedBodies*/));
+ m_enabled = true;
+ }
+
+ public void Dispose()
+ {
+ if (m_enabled)
+ {
+ // BulletSimAPI.RemoveConstraint(m_world.ID, m_body1.ID, m_body2.ID);
+ BulletSimAPI.DestroyConstraint2(m_world.Ptr, m_constraint.Ptr);
+ m_enabled = false;
+ }
+ }
+
+ public BulletBody Body1 { get { return m_body1; } }
+ public BulletBody Body2 { get { return m_body2; } }
+
+ public bool SetLinearLimits(Vector3 low, Vector3 high)
+ {
+ bool ret = false;
+ if (m_enabled)
+ ret = BulletSimAPI.SetLinearLimits2(m_constraint.Ptr, low, high);
+ return ret;
+ }
+
+ public bool SetAngularLimits(Vector3 low, Vector3 high)
+ {
+ bool ret = false;
+ if (m_enabled)
+ ret = BulletSimAPI.SetAngularLimits2(m_constraint.Ptr, low, high);
+ return ret;
+ }
+
+ public bool SetCFMAndERP(float cfm, float erp)
+ {
+ bool ret = true;
+ BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
+ BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL);
+ BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
+ return ret;
+ }
+
+ public bool UseFrameOffset(bool useOffset)
+ {
+ bool ret = false;
+ float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
+ if (m_enabled)
+ ret = BulletSimAPI.UseFrameOffset2(m_constraint.Ptr, onOff);
+ return ret;
+ }
+
+ public bool TranslationalLimitMotor(bool enable, float targetVelocity, float maxMotorForce)
+ {
+ bool ret = false;
+ float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
+ if (m_enabled)
+ ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.Ptr, onOff, targetVelocity, maxMotorForce);
+ return ret;
+ }
+
+ public bool CalculateTransforms()
+ {
+ bool ret = false;
+ if (m_enabled)
+ {
+ BulletSimAPI.CalculateTransforms2(m_constraint.Ptr);
+ ret = true;
+ }
+ return ret;
+ }
+}
+}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs
new file mode 100755
index 0000000000..c88e6455b9
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs
@@ -0,0 +1,184 @@
+/*
+ * 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 copyrightD
+ * 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.Text;
+using log4net;
+using OpenMetaverse;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+
+public class BSConstraintCollection : IDisposable
+{
+ // private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
+ // private static readonly string LogHeader = "[CONSTRAINT COLLECTION]";
+
+ delegate bool ConstraintAction(BSConstraint constrain);
+
+ private List m_constraints;
+ private BulletSim m_world;
+
+ public BSConstraintCollection(BulletSim world)
+ {
+ m_world = world;
+ m_constraints = new List();
+ }
+
+ public void Dispose()
+ {
+ this.Clear();
+ }
+
+ public void Clear()
+ {
+ foreach (BSConstraint cons in m_constraints)
+ {
+ cons.Dispose();
+ }
+ m_constraints.Clear();
+ }
+
+ public BSConstraint CreateConstraint(BulletSim world, BulletBody obj1, BulletBody obj2,
+ Vector3 frame1, Quaternion frame1rot,
+ Vector3 frame2, Quaternion frame2rot)
+ {
+ BSConstraint constrain = new BSConstraint(world, obj1, obj2, frame1, frame1rot, frame2, frame2rot);
+
+ this.AddConstraint(constrain);
+ return constrain;
+ }
+
+ public bool AddConstraint(BSConstraint cons)
+ {
+ // There is only one constraint between any bodies. Remove any old just to make sure.
+ RemoveAndDestroyConstraint(cons.Body1, cons.Body2);
+
+ m_constraints.Add(cons);
+
+ return true;
+ }
+
+ // Get the constraint between two bodies. There can be only one.
+ // Return 'true' if a constraint was found.
+ public bool TryGetConstraint(BulletBody body1, BulletBody body2, out BSConstraint returnConstraint)
+ {
+ bool found = false;
+ BSConstraint foundConstraint = null;
+
+ uint lookingID1 = body1.ID;
+ uint lookingID2 = body2.ID;
+ ForEachConstraint(delegate(BSConstraint constrain)
+ {
+ if ((constrain.Body1.ID == lookingID1 && constrain.Body2.ID == lookingID2)
+ || (constrain.Body1.ID == lookingID2 && constrain.Body2.ID == lookingID1))
+ {
+ foundConstraint = constrain;
+ found = true;
+ }
+ return found;
+ });
+ returnConstraint = foundConstraint;
+ return found;
+ }
+
+ // Remove any constraint between the passed bodies.
+ // Presumed there is only one such constraint possible.
+ // Return 'true' if a constraint was found and destroyed.
+ public bool RemoveAndDestroyConstraint(BulletBody body1, BulletBody body2)
+ {
+ // return BulletSimAPI.RemoveConstraint(m_world.ID, obj1.ID, obj2.ID);
+
+ bool ret = false;
+ BSConstraint constrain;
+
+ if (this.TryGetConstraint(body1, body2, out constrain))
+ {
+ // remove the constraint from our collection
+ m_constraints.Remove(constrain);
+ // tell the engine that all its structures need to be freed
+ constrain.Dispose();
+ // we destroyed something
+ ret = true;
+ }
+
+ return ret;
+ }
+
+ // Remove all constraints that reference the passed body.
+ // Return 'true' if any constraints were destroyed.
+ public bool RemoveAndDestroyConstraint(BulletBody body1)
+ {
+ // return BulletSimAPI.RemoveConstraintByID(m_world.ID, obj.ID);
+
+ List toRemove = new List();
+ uint lookingID = body1.ID;
+ ForEachConstraint(delegate(BSConstraint constrain)
+ {
+ if (constrain.Body1.ID == lookingID || constrain.Body2.ID == lookingID)
+ {
+ toRemove.Add(constrain);
+ }
+ return false;
+ });
+ lock (m_constraints)
+ {
+ foreach (BSConstraint constrain in toRemove)
+ {
+ m_constraints.Remove(constrain);
+ constrain.Dispose();
+ }
+ }
+ return (toRemove.Count > 0);
+ }
+
+ public bool RecalculateAllConstraints()
+ {
+ foreach (BSConstraint constrain in m_constraints)
+ {
+ constrain.CalculateTransforms();
+ }
+ return true;
+ }
+
+ // Lock the constraint list and loop through it.
+ // The constraint action returns 'true' if it wants the loop aborted.
+ private void ForEachConstraint(ConstraintAction action)
+ {
+ lock (m_constraints)
+ {
+ foreach (BSConstraint constrain in m_constraints)
+ {
+ if (action(constrain))
+ break;
+ }
+ }
+ }
+
+
+}
+}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index eb20eb3daa..c197e61ee8 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -57,7 +57,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin
private int frcount = 0; // Used to limit dynamics debug output to
// every 100th frame
- // private BSScene m_parentScene = null;
private BSPrim m_prim; // the prim this dynamic controller belongs to
// Vehicle properties
@@ -131,8 +130,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_type = Vehicle.TYPE_NONE;
}
- internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
+ internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue, float timestep)
{
+ DetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue);
switch (pParam)
{
case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
@@ -229,8 +229,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin
}
}//end ProcessFloatVehicleParam
- internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue)
+ internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue, float timestep)
{
+ DetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue);
switch (pParam)
{
case Vehicle.ANGULAR_FRICTION_TIMESCALE:
@@ -265,6 +266,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue)
{
+ DetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue);
switch (pParam)
{
case Vehicle.REFERENCE_FRAME:
@@ -278,6 +280,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
internal void ProcessVehicleFlags(int pParam, bool remove)
{
+ DetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", m_prim.LocalID, pParam, remove);
if (remove)
{
if (pParam == -1)
@@ -434,6 +437,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
internal void ProcessTypeChange(Vehicle pType)
{
+ DetailLog("{0},ProcessTypeChange,type={1}", m_prim.LocalID, pType);
// Set Defaults For Type
m_type = pType;
switch (pType)
@@ -594,11 +598,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY);
m_Hoverflags |= (VehicleFlag.HOVER_GLOBAL_HEIGHT);
break;
-
}
}//end SetDefaultsForType
- internal void Step(float pTimestep, BSScene pParentScene)
+ internal void Step(float pTimestep)
{
if (m_type == Vehicle.TYPE_NONE) return;
@@ -606,21 +609,34 @@ namespace OpenSim.Region.Physics.BulletSPlugin
if (frcount > 100)
frcount = 0;
- MoveLinear(pTimestep, pParentScene);
+ MoveLinear(pTimestep);
MoveAngular(pTimestep);
LimitRotation(pTimestep);
+
+ DetailLog("{0},Dynamics,done,pos={1},force={2},velocity={3},angvel={4}",
+ m_prim.LocalID, m_prim.Position, m_prim.Force, m_prim.Velocity, m_prim.RotationalVelocity);
}// end Step
- private void MoveLinear(float pTimestep, BSScene _pParentScene)
+ private void MoveLinear(float pTimestep)
{
- if (!m_linearMotorDirection.ApproxEquals(Vector3.Zero, 0.01f)) // requested m_linearMotorDirection is significant
+ // requested m_linearMotorDirection is significant
+ // if (!m_linearMotorDirection.ApproxEquals(Vector3.Zero, 0.01f))
+ if (m_linearMotorDirection.LengthSquared() > 0.0001f)
{
+ Vector3 origDir = m_linearMotorDirection;
+ Vector3 origVel = m_lastLinearVelocityVector;
+
// add drive to body
- Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale/pTimestep);
- m_lastLinearVelocityVector += (addAmount*10); // lastLinearVelocityVector is the current body velocity vector?
+ // Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale/pTimestep);
+ Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale);
+ // lastLinearVelocityVector is the current body velocity vector?
+ // RA: Not sure what the *10 is for. A correction for pTimestep?
+ // m_lastLinearVelocityVector += (addAmount*10);
+ m_lastLinearVelocityVector += addAmount;
// This will work temporarily, but we really need to compare speed on an axis
// KF: Limit body velocity to applied velocity?
+ // Limit the velocity vector to less than the last set linear motor direction
if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X))
m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X;
if (Math.Abs(m_lastLinearVelocityVector.Y) > Math.Abs(m_linearMotorDirectionLASTSET.Y))
@@ -630,76 +646,93 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// decay applied velocity
Vector3 decayfraction = ((Vector3.One/(m_linearMotorDecayTimescale/pTimestep)));
- //Console.WriteLine("decay: " + decayfraction);
m_linearMotorDirection -= m_linearMotorDirection * decayfraction * 0.5f;
- //Console.WriteLine("actual: " + m_linearMotorDirection);
+
+ /*
+ Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/m_linearMotorTimescale;
+ m_lastLinearVelocityVector += addAmount;
+
+ float decayfraction = (1.0f - 1.0f / m_linearMotorDecayTimescale);
+ m_linearMotorDirection *= decayfraction;
+
+ */
+
+ DetailLog("{0},MoveLinear,nonZero,origdir={1},origvel={2},add={3},decay={4},dir={5},vel={6}",
+ m_prim.LocalID, origDir, origVel, addAmount, decayfraction, m_linearMotorDirection, m_lastLinearVelocityVector);
}
else
- { // requested is not significant
- // if what remains of applied is small, zero it.
- if (m_lastLinearVelocityVector.ApproxEquals(Vector3.Zero, 0.01f))
- m_lastLinearVelocityVector = Vector3.Zero;
+ {
+ // if what remains of applied is small, zero it.
+ // if (m_lastLinearVelocityVector.ApproxEquals(Vector3.Zero, 0.01f))
+ // m_lastLinearVelocityVector = Vector3.Zero;
+ m_linearMotorDirection = Vector3.Zero;
+ m_lastLinearVelocityVector = Vector3.Zero;
}
// convert requested object velocity to world-referenced vector
- m_dir = m_lastLinearVelocityVector;
- Quaternion rot = m_prim.Orientation;
- Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object
- m_dir *= rotq; // apply obj rotation to velocity vector
+ Quaternion rotq = m_prim.Orientation;
+ m_dir = m_lastLinearVelocityVector * rotq;
- // add Gravity andBuoyancy
+ // Add the various forces into m_dir which will be our new direction vector (velocity)
+
+ // add Gravity and Buoyancy
// KF: So far I have found no good method to combine a script-requested
// .Z velocity and gravity. Therefore only 0g will used script-requested
// .Z velocity. >0g (m_VehicleBuoyancy < 1) will used modified gravity only.
Vector3 grav = Vector3.Zero;
- // There is some gravity, make a gravity force vector
- // that is applied after object velocity.
- float objMass = m_prim.Mass;
+ // There is some gravity, make a gravity force vector that is applied after object velocity.
// m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
- grav.Z = _pParentScene.DefaultGravity.Z * objMass * (1f - m_VehicleBuoyancy);
+ grav.Z = m_prim.Scene.DefaultGravity.Z * m_prim.Mass * (1f - m_VehicleBuoyancy);
// Preserve the current Z velocity
Vector3 vel_now = m_prim.Velocity;
m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity
Vector3 pos = m_prim.Position;
+ Vector3 posChange = pos;
// Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f);
- Vector3 posChange = new Vector3();
- posChange.X = pos.X - m_lastPositionVector.X;
- posChange.Y = pos.Y - m_lastPositionVector.Y;
- posChange.Z = pos.Z - m_lastPositionVector.Z;
double Zchange = Math.Abs(posChange.Z);
if (m_BlockingEndPoint != Vector3.Zero)
{
+ bool changed = false;
if (pos.X >= (m_BlockingEndPoint.X - (float)1))
{
pos.X -= posChange.X + 1;
- m_prim.Position = pos;
+ changed = true;
}
if (pos.Y >= (m_BlockingEndPoint.Y - (float)1))
{
pos.Y -= posChange.Y + 1;
- m_prim.Position = pos;
+ changed = true;
}
if (pos.Z >= (m_BlockingEndPoint.Z - (float)1))
{
pos.Z -= posChange.Z + 1;
- m_prim.Position = pos;
+ changed = true;
}
if (pos.X <= 0)
{
pos.X += posChange.X + 1;
- m_prim.Position = pos;
+ changed = true;
}
if (pos.Y <= 0)
{
pos.Y += posChange.Y + 1;
+ changed = true;
+ }
+ if (changed)
+ {
m_prim.Position = pos;
+ DetailLog("{0},MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}",
+ m_prim.LocalID, m_BlockingEndPoint, posChange, pos);
}
}
- if (pos.Z < _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y))
+
+ // If below the terrain, move us above the ground a little.
+ if (pos.Z < m_prim.Scene.GetTerrainHeightAtXYZ(pos))
{
- pos.Z = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y) + 2;
+ pos.Z = m_prim.Scene.GetTerrainHeightAtXYZ(pos) + 2;
m_prim.Position = pos;
+ DetailLog("{0},MoveLinear,terrainHeight,pos={1}", m_prim.LocalID, pos);
}
// Check if hovering
@@ -708,11 +741,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// We should hover, get the target height
if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != 0)
{
- m_VhoverTargetHeight = _pParentScene.GetWaterLevel() + m_VhoverHeight;
+ m_VhoverTargetHeight = m_prim.Scene.GetWaterLevel() + m_VhoverHeight;
}
if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
{
- m_VhoverTargetHeight = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight;
+ m_VhoverTargetHeight = m_prim.Scene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight;
}
if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0)
{
@@ -746,6 +779,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
}
}
+ DetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", m_prim.LocalID, pos, m_dir, m_VhoverHeight, m_VhoverTargetHeight);
+
// m_VhoverEfficiency = 0f; // 0=boucy, 1=Crit.damped
// m_VhoverTimescale = 0f; // time to acheive height
// pTimestep is time since last frame,in secs
@@ -774,12 +809,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
{
grav.Z = (float)(grav.Z * 1.125);
}
- float terraintemp = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y);
+ float terraintemp = m_prim.Scene.GetTerrainHeightAtXYZ(pos);
float postemp = (pos.Z - terraintemp);
if (postemp > 2.5f)
{
grav.Z = (float)(grav.Z * 1.037125);
}
+ DetailLog("{0},MoveLinear,limitMotorUp,grav={1}", m_prim.LocalID, grav);
//End Experimental Values
}
if ((m_flags & (VehicleFlag.NO_X)) != 0)
@@ -800,32 +836,39 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// Apply velocity
m_prim.Velocity = m_dir;
// apply gravity force
- m_prim.Force = grav;
+ // Why is this set here? The physics engine already does gravity.
+ // m_prim.AddForce(grav, false);
+ // m_prim.Force = grav;
-
- // apply friction
+ // Apply friction
Vector3 decayamount = Vector3.One / (m_linearFrictionTimescale / pTimestep);
m_lastLinearVelocityVector -= m_lastLinearVelocityVector * decayamount;
+
+ DetailLog("{0},MoveLinear,done,pos={1},vel={2},force={3},decay={4}",
+ m_prim.LocalID, m_lastPositionVector, m_dir, grav, decayamount);
+
} // end MoveLinear()
private void MoveAngular(float pTimestep)
{
- /*
- private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
- private int m_angularMotorApply = 0; // application frame counter
- private float m_angularMotorVelocity = 0; // current angular motor velocity (ramps up and down)
- private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate
- private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate
- private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate
- private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body
- */
+ // m_angularMotorDirection // angular velocity requested by LSL motor
+ // m_angularMotorApply // application frame counter
+ // m_angularMotorVelocity // current angular motor velocity (ramps up and down)
+ // m_angularMotorTimescale // motor angular velocity ramp up rate
+ // m_angularMotorDecayTimescale // motor angular velocity decay rate
+ // m_angularFrictionTimescale // body angular velocity decay rate
+ // m_lastAngularVelocity // what was last applied to body
// Get what the body is doing, this includes 'external' influences
Vector3 angularVelocity = m_prim.RotationalVelocity;
- // Vector3 angularVelocity = Vector3.Zero;
if (m_angularMotorApply > 0)
{
+ // Rather than snapping the angular motor velocity from the old value to
+ // a newly set velocity, this routine steps the value from the previous
+ // value (m_angularMotorVelocity) to the requested value (m_angularMotorDirection).
+ // There are m_angularMotorApply steps.
+ Vector3 origAngularVelocity = m_angularMotorVelocity;
// ramp up to new value
// current velocity += error / (time to get there / step interval)
// requested speed - last motor speed
@@ -833,23 +876,21 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_angularMotorVelocity.Y += (m_angularMotorDirection.Y - m_angularMotorVelocity.Y) / (m_angularMotorTimescale / pTimestep);
m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep);
+ DetailLog("{0},MoveAngular,angularMotorApply,apply={1},origvel={2},dir={3},vel={4}",
+ m_prim.LocalID,m_angularMotorApply,origAngularVelocity, m_angularMotorDirection, m_angularMotorVelocity);
+
m_angularMotorApply--; // This is done so that if script request rate is less than phys frame rate the expected
// velocity may still be acheived.
}
else
{
- // no motor recently applied, keep the body velocity
- /* m_angularMotorVelocity.X = angularVelocity.X;
- m_angularMotorVelocity.Y = angularVelocity.Y;
- m_angularMotorVelocity.Z = angularVelocity.Z; */
-
+ // No motor recently applied, keep the body velocity
// and decay the velocity
m_angularMotorVelocity -= m_angularMotorVelocity / (m_angularMotorDecayTimescale / pTimestep);
} // end motor section
// Vertical attractor section
Vector3 vertattr = Vector3.Zero;
-
if (m_verticalAttractionTimescale < 300)
{
float VAservo = 0.2f / (m_verticalAttractionTimescale * pTimestep);
@@ -871,7 +912,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// Error is 0 (no error) to +/- 2 (max error)
// scale it by VAservo
verterr = verterr * VAservo;
-//if (frcount == 0) Console.WriteLine("VAerr=" + verterr);
// As the body rotates around the X axis, then verterr.Y increases; Rotated around Y then .X increases, so
// Change Body angular velocity X based on Y, and Y based on X. Z is not changed.
@@ -884,11 +924,15 @@ namespace OpenSim.Region.Physics.BulletSPlugin
vertattr.X += bounce * angularVelocity.X;
vertattr.Y += bounce * angularVelocity.Y;
+ DetailLog("{0},MoveAngular,verticalAttraction,verterr={1},bounce={2},vertattr={3}",
+ m_prim.LocalID, verterr, bounce, vertattr);
+
} // else vertical attractor is off
- // m_lastVertAttractor = vertattr;
+ // m_lastVertAttractor = vertattr;
// Bank section tba
+
// Deflection section tba
// Sum velocities
@@ -898,11 +942,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
{
m_lastAngularVelocity.X = 0;
m_lastAngularVelocity.Y = 0;
+ DetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", m_prim.LocalID, m_lastAngularVelocity);
}
if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
{
m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero.
+ DetailLog("{0},MoveAngular,zeroSmallValues,lastAngular={1}", m_prim.LocalID, m_lastAngularVelocity);
}
// apply friction
@@ -912,10 +958,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// Apply to the body
m_prim.RotationalVelocity = m_lastAngularVelocity;
+ DetailLog("{0},MoveAngular,done,decay={1},lastAngular={2}", m_prim.LocalID, decayamount, m_lastAngularVelocity);
} //end MoveAngular
+
internal void LimitRotation(float timestep)
{
- Quaternion rotq = m_prim.Orientation; // rotq = rotation of object
+ Quaternion rotq = m_prim.Orientation;
Quaternion m_rot = rotq;
bool changed = false;
if (m_RollreferenceFrame != Quaternion.Identity)
@@ -923,18 +971,22 @@ namespace OpenSim.Region.Physics.BulletSPlugin
if (rotq.X >= m_RollreferenceFrame.X)
{
m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2);
+ changed = true;
}
if (rotq.Y >= m_RollreferenceFrame.Y)
{
m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2);
+ changed = true;
}
if (rotq.X <= -m_RollreferenceFrame.X)
{
m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2);
+ changed = true;
}
if (rotq.Y <= -m_RollreferenceFrame.Y)
{
m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2);
+ changed = true;
}
changed = true;
}
@@ -944,8 +996,23 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_rot.Y = 0;
changed = true;
}
+ if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0)
+ {
+ m_rot.X = 0;
+ m_rot.Y = 0;
+ changed = true;
+ }
if (changed)
m_prim.Orientation = m_rot;
+
+ DetailLog("{0},LimitRotation,done,changed={1},orig={2},new={3}", m_prim.LocalID, changed, rotq, m_rot);
+ }
+
+ // Invoke the detailed logger and output something if it's enabled.
+ private void DetailLog(string msg, params Object[] args)
+ {
+ if (m_prim.Scene.VehicleLoggingEnabled)
+ m_prim.Scene.PhysicsLogging.Write(msg, args);
}
}
}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
new file mode 100755
index 0000000000..6f8430c8cc
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
@@ -0,0 +1,352 @@
+/*
+ * 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 copyrightD
+ * 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.Text;
+
+using OMV = OpenMetaverse;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+public class BSLinkset
+{
+ private static string LogHeader = "[BULLETSIM LINKSET]";
+
+ private BSPrim m_linksetRoot;
+ public BSPrim Root { get { return m_linksetRoot; } }
+
+ private BSScene m_scene;
+
+ private List m_children;
+
+ // We lock the diddling of linkset classes to prevent any badness.
+ // This locks the modification of the instances of this class. Changes
+ // to the physical representation is done via the tainting mechenism.
+ private object m_linksetActivityLock = new Object();
+
+ // We keep the prim's mass in the linkset structure since it could be dependent on other prims
+ private float m_mass;
+ public float LinksetMass
+ {
+ get
+ {
+ m_mass = ComputeLinksetMass();
+ return m_mass;
+ }
+ }
+
+ public OMV.Vector3 CenterOfMass
+ {
+ get { return ComputeLinksetCenterOfMass(); }
+ }
+
+ public OMV.Vector3 GeometricCenter
+ {
+ get { return ComputeLinksetGeometricCenter(); }
+ }
+
+ public BSLinkset(BSScene scene, BSPrim parent)
+ {
+ // A simple linkset of one (no children)
+ m_scene = scene;
+ m_linksetRoot = parent;
+ m_children = new List();
+ m_mass = parent.MassRaw;
+ }
+
+ // Link to a linkset where the child knows the parent.
+ // Parent changing should not happen so do some sanity checking.
+ // We return the parent's linkset so the child can track it's membership.
+ public BSLinkset AddMeToLinkset(BSPrim child, BSPrim parent)
+ {
+ lock (m_linksetActivityLock)
+ {
+ parent.Linkset.AddChildToLinkset(child);
+ }
+ return parent.Linkset;
+ }
+
+ public BSLinkset RemoveMeFromLinkset(BSPrim child)
+ {
+ lock (m_linksetActivityLock)
+ {
+ if (IsRoot(child))
+ {
+ // if root of linkset, take the linkset apart
+ while (m_children.Count > 0)
+ {
+ // Note that we don't do a foreach because the remove routine
+ // takes it out of the list.
+ RemoveChildFromLinkset(m_children[0]);
+ }
+ m_children.Clear(); // just to make sure
+ }
+ else
+ {
+ // Just removing a child from an existing linkset
+ RemoveChildFromLinkset(child);
+ }
+ }
+
+ // The child is down to a linkset of just itself
+ return new BSLinkset(m_scene, child);
+ }
+
+ // An existing linkset had one of its members rebuilt or something.
+ // Go through the linkset and rebuild the pointers to the bodies of the linkset members.
+ public BSLinkset RefreshLinkset(BSPrim requestor)
+ {
+ BSLinkset ret = requestor.Linkset;
+
+ lock (m_linksetActivityLock)
+ {
+ System.IntPtr aPtr = BulletSimAPI.GetBodyHandle2(m_scene.World.Ptr, m_linksetRoot.LocalID);
+ if (aPtr == System.IntPtr.Zero)
+ {
+ // That's odd. We can't find the root of the linkset.
+ // The linkset is somehow dead. The requestor is now a member of a linkset of one.
+ DetailLog("{0},RefreshLinkset.RemoveRoot,child={1}", m_linksetRoot.LocalID, m_linksetRoot.LocalID);
+ ret = RemoveMeFromLinkset(m_linksetRoot);
+ }
+ else
+ {
+ // Reconstruct the pointer to the body of the linkset root.
+ DetailLog("{0},RefreshLinkset.RebuildRoot,rootID={1},ptr={2}", m_linksetRoot.LocalID, m_linksetRoot.LocalID, aPtr);
+ m_linksetRoot.Body = new BulletBody(m_linksetRoot.LocalID, aPtr);
+
+ List toRemove = new List();
+ foreach (BSPrim bsp in m_children)
+ {
+ aPtr = BulletSimAPI.GetBodyHandle2(m_scene.World.Ptr, bsp.LocalID);
+ if (aPtr == System.IntPtr.Zero)
+ {
+ toRemove.Add(bsp);
+ }
+ else
+ {
+ // Reconstruct the pointer to the body of the linkset root.
+ DetailLog("{0},RefreshLinkset.RebuildChild,rootID={1},ptr={2}", bsp.LocalID, m_linksetRoot.LocalID, aPtr);
+ bsp.Body = new BulletBody(bsp.LocalID, aPtr);
+ }
+ }
+ foreach (BSPrim bsp in toRemove)
+ {
+ RemoveChildFromLinkset(bsp);
+ }
+ }
+ }
+
+ return ret;
+ }
+
+
+ // Return 'true' if the passed object is the root object of this linkset
+ public bool IsRoot(BSPrim requestor)
+ {
+ return (requestor.LocalID == m_linksetRoot.LocalID);
+ }
+
+ // Return 'true' if this linkset has any children (more than the root member)
+ public bool HasAnyChildren { get { return (m_children.Count > 0); } }
+
+ // Return 'true' if this child is in this linkset
+ public bool HasChild(BSPrim child)
+ {
+ bool ret = false;
+ foreach (BSPrim bp in m_children)
+ {
+ if (child.LocalID == bp.LocalID)
+ {
+ ret = true;
+ break;
+ }
+ }
+ return ret;
+ }
+
+ private float ComputeLinksetMass()
+ {
+ float mass = m_linksetRoot.MassRaw;
+ foreach (BSPrim bp in m_children)
+ {
+ mass += bp.MassRaw;
+ }
+ return mass;
+ }
+
+ private OMV.Vector3 ComputeLinksetCenterOfMass()
+ {
+ OMV.Vector3 com = m_linksetRoot.Position * m_linksetRoot.MassRaw;
+ float totalMass = m_linksetRoot.MassRaw;
+
+ foreach (BSPrim bp in m_children)
+ {
+ com += bp.Position * bp.MassRaw;
+ totalMass += bp.MassRaw;
+ }
+ com /= totalMass;
+
+ return com;
+ }
+
+ private OMV.Vector3 ComputeLinksetGeometricCenter()
+ {
+ OMV.Vector3 com = m_linksetRoot.Position;
+
+ foreach (BSPrim bp in m_children)
+ {
+ com += bp.Position * bp.MassRaw;
+ }
+ com /= m_children.Count + 1;
+
+ return com;
+ }
+
+ // I am the root of a linkset and a new child is being added
+ public void AddChildToLinkset(BSPrim pchild)
+ {
+ BSPrim child = pchild;
+ if (!HasChild(child))
+ {
+ m_children.Add(child);
+
+ m_scene.TaintedObject(delegate()
+ {
+ DebugLog("{0}: AddChildToLinkset: adding child {1} to {2}", LogHeader, child.LocalID, m_linksetRoot.LocalID);
+ DetailLog("{0},AddChildToLinkset,child={1}", m_linksetRoot.LocalID, pchild.LocalID);
+ PhysicallyLinkAChildToRoot(pchild); // build the physical binding between me and the child
+ });
+ }
+ return;
+ }
+
+ // I am the root of a linkset and one of my children is being removed.
+ // Safe to call even if the child is not really in my linkset.
+ public void RemoveChildFromLinkset(BSPrim pchild)
+ {
+ BSPrim child = pchild;
+
+ if (m_children.Remove(child))
+ {
+ m_scene.TaintedObject(delegate()
+ {
+ DebugLog("{0}: RemoveChildFromLinkset: Removing constraint to {1}", LogHeader, child.LocalID);
+ DetailLog("{0},RemoveChildFromLinkset,child={1}", m_linksetRoot.LocalID, pchild.LocalID);
+
+ if (m_children.Count == 0)
+ {
+ // if the linkset is empty, make sure all linkages have been removed
+ PhysicallyUnlinkAllChildrenFromRoot();
+ }
+ else
+ {
+ PhysicallyUnlinkAChildFromRoot(pchild);
+ }
+ });
+ }
+ else
+ {
+ // This will happen if we remove the root of the linkset first. Non-fatal occurance.
+ // m_scene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader);
+ }
+ return;
+ }
+
+ // Create a constraint between me (root of linkset) and the passed prim (the child).
+ // Called at taint time!
+ private void PhysicallyLinkAChildToRoot(BSPrim childPrim)
+ {
+ // Zero motion for children so they don't interpolate
+ childPrim.ZeroMotion();
+
+ // relative position normalized to the root prim
+ OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(m_linksetRoot.Orientation);
+ OMV.Vector3 childRelativePosition = (childPrim.Position - m_linksetRoot.Position) * invThisOrientation;
+
+ // relative rotation of the child to the parent
+ OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
+
+ // create a constraint that allows no freedom of movement between the two objects
+ // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
+ // DebugLog("{0}: CreateLinkset: Adding a constraint between root prim {1} and child prim {2}", LogHeader, LocalID, childPrim.LocalID);
+ DetailLog("{0},LinkAChildToMe,taint,root={1},child={2}", m_linksetRoot.LocalID, m_linksetRoot.LocalID, childPrim.LocalID);
+ BSConstraint constrain = m_scene.Constraints.CreateConstraint(
+ m_scene.World, m_linksetRoot.Body, childPrim.Body,
+ // childRelativePosition,
+ // childRelativeRotation,
+ OMV.Vector3.Zero,
+ OMV.Quaternion.Identity,
+ OMV.Vector3.Zero,
+ OMV.Quaternion.Identity
+ );
+ constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
+ constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
+
+ // tweek the constraint to increase stability
+ constrain.UseFrameOffset(m_scene.BoolNumeric(m_scene.Params.linkConstraintUseFrameOffset));
+ constrain.TranslationalLimitMotor(m_scene.BoolNumeric(m_scene.Params.linkConstraintEnableTransMotor),
+ m_scene.Params.linkConstraintTransMotorMaxVel,
+ m_scene.Params.linkConstraintTransMotorMaxForce);
+ constrain.SetCFMAndERP(m_scene.Params.linkConstraintCFM, m_scene.Params.linkConstraintERP);
+
+ }
+
+ // Remove linkage between myself and a particular child
+ // Called at taint time!
+ private void PhysicallyUnlinkAChildFromRoot(BSPrim childPrim)
+ {
+ DebugLog("{0}: PhysicallyUnlinkAChildFromRoot: RemoveConstraint between root prim {1} and child prim {2}",
+ LogHeader, m_linksetRoot.LocalID, childPrim.LocalID);
+ DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},child={2}", m_linksetRoot.LocalID, m_linksetRoot.LocalID, childPrim.LocalID);
+ // BulletSimAPI.RemoveConstraint(_scene.WorldID, LocalID, childPrim.LocalID);
+ m_scene.Constraints.RemoveAndDestroyConstraint(m_linksetRoot.Body, childPrim.Body);
+ }
+
+ // Remove linkage between myself and any possible children I might have
+ // Called at taint time!
+ private void PhysicallyUnlinkAllChildrenFromRoot()
+ {
+ // DebugLog("{0}: PhysicallyUnlinkAllChildren:", LogHeader);
+ DetailLog("{0},PhysicallyUnlinkAllChildren,taint", m_linksetRoot.LocalID);
+ m_scene.Constraints.RemoveAndDestroyConstraint(m_linksetRoot.Body);
+ // BulletSimAPI.RemoveConstraintByID(_scene.WorldID, LocalID);
+ }
+
+ // Invoke the detailed logger and output something if it's enabled.
+ private void DebugLog(string msg, params Object[] args)
+ {
+ m_scene.Logger.DebugFormat(msg, args);
+ }
+
+ // Invoke the detailed logger and output something if it's enabled.
+ private void DetailLog(string msg, params Object[] args)
+ {
+ m_scene.PhysicsLogging.Write(msg, args);
+ }
+
+}
+}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 130f1ca145..a4ab702f60 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -42,6 +42,8 @@ public sealed class BSPrim : PhysicsActor
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static readonly string LogHeader = "[BULLETS PRIM]";
+ private void DebugLog(string mm, params Object[] xx) { if (_scene.shouldDebugLog) m_log.DebugFormat(mm, xx); }
+
private IMesh _mesh;
private PrimitiveBaseShape _pbs;
private ShapeData.PhysicsShapeType _shapeType;
@@ -50,6 +52,7 @@ public sealed class BSPrim : PhysicsActor
private List _hulls;
private BSScene _scene;
+ public BSScene Scene { get { return _scene; } }
private String _avName;
private uint _localID = 0;
@@ -63,7 +66,7 @@ public sealed class BSPrim : PhysicsActor
private bool _isSelected;
private bool _isVolumeDetect;
private OMV.Vector3 _position;
- private float _mass;
+ private float _mass; // the mass of this object
private float _density;
private OMV.Vector3 _force;
private OMV.Vector3 _velocity;
@@ -86,14 +89,25 @@ public sealed class BSPrim : PhysicsActor
private bool _kinematic;
private float _buoyancy;
- private List _childrenPrims;
- private BSPrim _parentPrim;
+ // Membership in a linkset is controlled by this class.
+ private BSLinkset _linkset;
+ public BSLinkset Linkset
+ {
+ get { return _linkset; }
+ set { _linkset = value; }
+ }
private int _subscribedEventsMs = 0;
private int _nextCollisionOkTime = 0;
long _collidingStep;
long _collidingGroundStep;
+ private BulletBody m_body;
+ public BulletBody Body {
+ get { return m_body; }
+ set { m_body = value; }
+ }
+
private BSDynamics _vehicle;
private OMV.Vector3 _PIDTarget;
@@ -127,17 +141,18 @@ public sealed class BSPrim : PhysicsActor
_friction = _scene.Params.defaultFriction; // TODO: compute based on object material
_density = _scene.Params.defaultDensity; // TODO: compute based on object material
_restitution = _scene.Params.defaultRestitution;
- _parentPrim = null; // not a child or a parent
+ _linkset = new BSLinkset(_scene, this); // a linkset of one
_vehicle = new BSDynamics(this); // add vehicleness
- _childrenPrims = new List();
- if (_isPhysical)
- _mass = CalculateMass();
- else
- _mass = 0f;
+ _mass = CalculateMass();
// do the actual object creation at taint time
_scene.TaintedObject(delegate()
{
RecreateGeomAndObject();
+
+ // Get the pointer to the physical body for this object.
+ // At the moment, we're still letting BulletSim manage the creation and destruction
+ // of the object. Someday we'll move that into the C# code.
+ m_body = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID));
});
}
@@ -145,13 +160,19 @@ public sealed class BSPrim : PhysicsActor
public void Destroy()
{
// m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
+ // DetailLog("{0},Destroy", LocalID);
+
// Undo any vehicle properties
_vehicle.ProcessTypeChange(Vehicle.TYPE_NONE);
_scene.RemoveVehiclePrim(this); // just to make sure
+
_scene.TaintedObject(delegate()
{
+ // Undo any links between me and any other object
+ _linkset = _linkset.RemoveMeFromLinkset(this);
+
// everything in the C# world will get garbage collected. Tell the C++ world to free stuff.
- BulletSimAPI.DestroyObject(_scene.WorldID, _localID);
+ BulletSimAPI.DestroyObject(_scene.WorldID, LocalID);
});
}
@@ -164,8 +185,9 @@ public sealed class BSPrim : PhysicsActor
_size = value;
_scene.TaintedObject(delegate()
{
- if (_isPhysical) _mass = CalculateMass(); // changing size changes the mass
- BulletSimAPI.SetObjectScaleMass(_scene.WorldID, _localID, _scale, _mass, _isPhysical);
+ _mass = CalculateMass(); // changing size changes the mass
+ BulletSimAPI.SetObjectScaleMass(_scene.WorldID, _localID, _scale, (IsPhysical ? _mass : 0f), IsPhysical);
+ DetailLog("{0}: setSize: size={1}, mass={2}, physical={3}", LocalID, _size, _mass, IsPhysical);
RecreateGeomAndObject();
});
}
@@ -175,7 +197,7 @@ public sealed class BSPrim : PhysicsActor
_pbs = value;
_scene.TaintedObject(delegate()
{
- if (_isPhysical) _mass = CalculateMass(); // changing the shape changes the mass
+ _mass = CalculateMass(); // changing the shape changes the mass
RecreateGeomAndObject();
});
}
@@ -202,33 +224,10 @@ public sealed class BSPrim : PhysicsActor
// link me to the specified parent
public override void link(PhysicsActor obj) {
BSPrim parent = obj as BSPrim;
- // m_log.DebugFormat("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, obj.LocalID);
- // TODO: decide if this parent checking needs to happen at taint time
- if (_parentPrim == null)
- {
- if (parent != null)
- {
- // I don't have a parent so I am joining a linkset
- parent.AddChildToLinkset(this);
- }
- }
- else
- {
- // I already have a parent, is parenting changing?
- if (parent != _parentPrim)
- {
- if (parent == null)
- {
- // we are being removed from a linkset
- _parentPrim.RemoveChildFromLinkset(this);
- }
- else
- {
- // asking to reparent a prim should not happen
- m_log.ErrorFormat("{0}: Reparenting a prim. ", LogHeader);
- }
- }
- }
+ DebugLog("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, obj.LocalID);
+ DetailLog("{0},link,parent={1}", LocalID, obj.LocalID);
+
+ _linkset = _linkset.AddMeToLinkset(this, parent);
return;
}
@@ -236,101 +235,92 @@ public sealed class BSPrim : PhysicsActor
public override void delink() {
// TODO: decide if this parent checking needs to happen at taint time
// Race condition here: if link() and delink() in same simulation tick, the delink will not happen
- // m_log.DebugFormat("{0}: delink {1}/{2}", LogHeader, _avName, _localID);
- if (_parentPrim != null)
- {
- _parentPrim.RemoveChildFromLinkset(this);
- }
+ DebugLog("{0}: delink {1}/{2}. Parent={3}", LogHeader, _avName, _localID,
+ _linkset.Root._avName+"/"+_linkset.Root.LocalID.ToString());
+ DetailLog("{0},delink,parent={1}", LocalID, _linkset.Root.LocalID.ToString());
+
+ _linkset.RemoveMeFromLinkset(this);
return;
}
- // I am the root of a linkset and a new child is being added
- public void AddChildToLinkset(BSPrim pchild)
- {
- BSPrim child = pchild;
- _scene.TaintedObject(delegate()
- {
- if (!_childrenPrims.Contains(child))
- {
- _childrenPrims.Add(child);
- child.ParentPrim = this; // the child has gained a parent
- RecreateGeomAndObject(); // rebuild my shape with the new child added
- }
- });
- return;
- }
-
- // I am the root of a linkset and one of my children is being removed.
- // Safe to call even if the child is not really in my linkset.
- public void RemoveChildFromLinkset(BSPrim pchild)
- {
- BSPrim child = pchild;
- _scene.TaintedObject(delegate()
- {
- if (_childrenPrims.Contains(child))
- {
- BulletSimAPI.RemoveConstraint(_scene.WorldID, child.LocalID, this.LocalID);
- _childrenPrims.Remove(child);
- child.ParentPrim = null; // the child has lost its parent
- RecreateGeomAndObject(); // rebuild my shape with the child removed
- }
- else
- {
- m_log.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset");
- }
- });
- return;
- }
-
- public BSPrim ParentPrim
- {
- set { _parentPrim = value; }
- }
-
- // return true if we are the root of a linkset (there are children to manage)
- public bool IsRootOfLinkset
- {
- get { return (_parentPrim == null && _childrenPrims.Count != 0); }
- }
-
// Set motion values to zero.
// Do it to the properties so the values get set in the physics engine.
// Push the setting of the values to the viewer.
- private void ZeroMotion()
+ // Called at taint time!
+ public void ZeroMotion()
{
- Velocity = OMV.Vector3.Zero;
+ _velocity = OMV.Vector3.Zero;
_acceleration = OMV.Vector3.Zero;
- RotationalVelocity = OMV.Vector3.Zero;
- base.RequestPhysicsterseUpdate();
+ _rotationalVelocity = OMV.Vector3.Zero;
+
+ // Zero some other properties directly into the physics engine
+ BulletSimAPI.SetVelocity2(Body.Ptr, OMV.Vector3.Zero);
+ BulletSimAPI.SetAngularVelocity2(Body.Ptr, OMV.Vector3.Zero);
+ BulletSimAPI.SetInterpolation2(Body.Ptr, OMV.Vector3.Zero, OMV.Vector3.Zero);
+ BulletSimAPI.ClearForces2(Body.Ptr);
}
- public override void LockAngularMotion(OMV.Vector3 axis) { return; }
+ public override void LockAngularMotion(OMV.Vector3 axis)
+ {
+ DetailLog("{0},LockAngularMotion,call,axis={1}", LocalID, axis);
+ return;
+ }
public override OMV.Vector3 Position {
get {
- // don't do the following GetObjectPosition because this function is called a zillion times
+ if (!_linkset.IsRoot(this))
+ // child prims move around based on their parent. Need to get the latest location
+ _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
+
+ // don't do the GetObjectPosition for root elements because this function is called a zillion times
// _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
return _position;
}
set {
_position = value;
+ // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint?
_scene.TaintedObject(delegate()
{
+ DetailLog("{0},SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
- // m_log.DebugFormat("{0}: setPosition: id={1}, position={2}", LogHeader, _localID, _position);
});
}
}
- public override float Mass {
- get { return _mass; }
+
+ // Return the effective mass of the object.
+ // If there are multiple items in the linkset, add them together for the root
+ public override float Mass
+ {
+ get
+ {
+ return _linkset.LinksetMass;
+ }
}
+
+ // used when we only want this prim's mass and not the linkset thing
+ public float MassRaw { get { return _mass; } }
+
+ // Is this used?
+ public override OMV.Vector3 CenterOfMass
+ {
+ get { return _linkset.CenterOfMass; }
+ }
+
+ // Is this used?
+ public override OMV.Vector3 GeometricCenter
+ {
+ get { return _linkset.GeometricCenter; }
+ }
+
public override OMV.Vector3 Force {
get { return _force; }
set {
_force = value;
_scene.TaintedObject(delegate()
{
- BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force);
+ DetailLog("{0},SetForce,taint,force={1}", LocalID, _force);
+ // BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force);
+ BulletSimAPI.SetObjectForce2(Body.Ptr, _force);
});
}
}
@@ -341,15 +331,22 @@ public sealed class BSPrim : PhysicsActor
}
set {
Vehicle type = (Vehicle)value;
- _vehicle.ProcessTypeChange(type);
_scene.TaintedObject(delegate()
{
+ DetailLog("{0},SetVehicleType,taint,type={1}", LocalID, type);
+ _vehicle.ProcessTypeChange(type);
if (type == Vehicle.TYPE_NONE)
{
_scene.RemoveVehiclePrim(this);
}
else
{
+ _scene.TaintedObject(delegate()
+ {
+ // Tell the physics engine to clear state
+ BulletSimAPI.ClearForces2(this.Body.Ptr);
+ });
+
// make it so the scene will call us each tick to do vehicle things
_scene.AddVehiclePrim(this);
}
@@ -359,47 +356,59 @@ public sealed class BSPrim : PhysicsActor
}
public override void VehicleFloatParam(int param, float value)
{
- _vehicle.ProcessFloatVehicleParam((Vehicle)param, value);
+ _scene.TaintedObject(delegate()
+ {
+ _vehicle.ProcessFloatVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep);
+ });
}
public override void VehicleVectorParam(int param, OMV.Vector3 value)
{
- _vehicle.ProcessVectorVehicleParam((Vehicle)param, value);
+ _scene.TaintedObject(delegate()
+ {
+ _vehicle.ProcessVectorVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep);
+ });
}
public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
{
- _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation);
+ _scene.TaintedObject(delegate()
+ {
+ _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation);
+ });
}
public override void VehicleFlags(int param, bool remove)
{
- _vehicle.ProcessVehicleFlags(param, remove);
+ _scene.TaintedObject(delegate()
+ {
+ _vehicle.ProcessVehicleFlags(param, remove);
+ });
}
- // Called each simulation step to advance vehicle characteristics
+
+ // Called each simulation step to advance vehicle characteristics.
+ // Called from Scene when doing simulation step so we're in taint processing time.
public void StepVehicle(float timeStep)
{
- _vehicle.Step(timeStep, _scene);
+ if (IsPhysical)
+ _vehicle.Step(timeStep);
}
// Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
public override void SetVolumeDetect(int param) {
bool newValue = (param != 0);
- if (_isVolumeDetect != newValue)
+ _isVolumeDetect = newValue;
+ _scene.TaintedObject(delegate()
{
- _isVolumeDetect = newValue;
- _scene.TaintedObject(delegate()
- {
- SetObjectDynamic();
- });
- }
+ SetObjectDynamic();
+ });
return;
}
- public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
- public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
public override OMV.Vector3 Velocity {
get { return _velocity; }
- set { _velocity = value;
+ set {
+ _velocity = value;
_scene.TaintedObject(delegate()
{
+ DetailLog("{0},SetVelocity,taint,vel={1}", LocalID, _velocity);
BulletSimAPI.SetObjectVelocity(_scene.WorldID, LocalID, _velocity);
});
}
@@ -407,6 +416,7 @@ public sealed class BSPrim : PhysicsActor
public override OMV.Vector3 Torque {
get { return _torque; }
set { _torque = value;
+ DetailLog("{0},SetTorque,call,torque={1}", LocalID, _torque);
}
}
public override float CollisionScore {
@@ -419,13 +429,21 @@ public sealed class BSPrim : PhysicsActor
set { _acceleration = value; }
}
public override OMV.Quaternion Orientation {
- get { return _orientation; }
+ get {
+ if (!_linkset.IsRoot(this))
+ {
+ // Children move around because tied to parent. Get a fresh value.
+ _orientation = BulletSimAPI.GetObjectOrientation(_scene.WorldID, LocalID);
+ }
+ return _orientation;
+ }
set {
_orientation = value;
- // m_log.DebugFormat("{0}: set orientation: id={1}, ori={2}", LogHeader, LocalID, _orientation);
+ // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint?
_scene.TaintedObject(delegate()
{
// _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
+ DetailLog("{0},SetOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation);
BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
});
}
@@ -458,25 +476,24 @@ public sealed class BSPrim : PhysicsActor
get { return !IsPhantom && !_isVolumeDetect; }
}
- // make gravity work if the object is physical and not selected
- // no locking here because only called when it is safe
+ // Make gravity work if the object is physical and not selected
+ // No locking here because only called when it is safe
+ // Only called at taint time so it is save to call into Bullet.
private void SetObjectDynamic()
{
- // m_log.DebugFormat("{0}: ID={1}, SetObjectDynamic: IsStatic={2}, IsSolid={3}", LogHeader, _localID, IsStatic, IsSolid);
- // non-physical things work best with a mass of zero
- if (IsStatic)
- {
- _mass = 0f;
- }
- else
- {
- _mass = CalculateMass();
- // If it's dynamic, make sure the hull has been created for it
- // This shouldn't do much work if the object had previously been built
- RecreateGeomAndObject();
+ // RA: remove this for the moment.
+ // The problem is that dynamic objects are hulls so if we are becoming physical
+ // the shape has to be checked and possibly built.
+ // Maybe a VerifyCorrectPhysicalShape() routine?
+ // RecreateGeomAndObject();
- }
- BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), _mass);
+ float mass = _mass;
+ // Bullet wants static objects have a mass of zero
+ if (IsStatic)
+ mass = 0f;
+
+ DetailLog("{0},SetObjectDynamic,taint,static={1},solid={2},mass={3}", LocalID, IsStatic, IsSolid, mass);
+ BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), mass);
}
// prims don't fly
@@ -516,11 +533,24 @@ public sealed class BSPrim : PhysicsActor
set { _floatOnWater = value; }
}
public override OMV.Vector3 RotationalVelocity {
- get { return _rotationalVelocity; }
- set { _rotationalVelocity = value;
+ get {
+ /*
+ OMV.Vector3 pv = OMV.Vector3.Zero;
+ // if close to zero, report zero
+ // This is copied from ODE but I'm not sure why it returns zero but doesn't
+ // zero the property in the physics engine.
+ if (_rotationalVelocity.ApproxEquals(pv, 0.2f))
+ return pv;
+ */
+
+ return _rotationalVelocity;
+ }
+ set {
+ _rotationalVelocity = value;
// m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
_scene.TaintedObject(delegate()
{
+ DetailLog("{0},SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
BulletSimAPI.SetObjectAngularVelocity(_scene.WorldID, LocalID, _rotationalVelocity);
});
}
@@ -533,11 +563,13 @@ public sealed class BSPrim : PhysicsActor
}
public override float Buoyancy {
get { return _buoyancy; }
- set { _buoyancy = value;
- _scene.TaintedObject(delegate()
- {
- BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, _localID, _buoyancy);
- });
+ set {
+ _buoyancy = value;
+ _scene.TaintedObject(delegate()
+ {
+ DetailLog("{0},SetBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
+ BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, _localID, _buoyancy);
+ });
}
}
@@ -573,27 +605,45 @@ public sealed class BSPrim : PhysicsActor
public override float APIDStrength { set { return; } }
public override float APIDDamping { set { return; } }
+ private List m_accumulatedForces = new List();
public override void AddForce(OMV.Vector3 force, bool pushforce) {
if (force.IsFinite())
{
- _force.X += force.X;
- _force.Y += force.Y;
- _force.Z += force.Z;
+ // _force += force;
+ lock (m_accumulatedForces)
+ m_accumulatedForces.Add(new OMV.Vector3(force));
}
else
{
m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader);
+ return;
}
_scene.TaintedObject(delegate()
{
- BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force);
+ lock (m_accumulatedForces)
+ {
+ if (m_accumulatedForces.Count > 0)
+ {
+ OMV.Vector3 fSum = OMV.Vector3.Zero;
+ foreach (OMV.Vector3 v in m_accumulatedForces)
+ {
+ fSum += v;
+ }
+ m_accumulatedForces.Clear();
+
+ DetailLog("{0},SetObjectForce,taint,force={1}", LocalID, fSum);
+ BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, fSum);
+ }
+ }
});
}
public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
+ DetailLog("{0},AddAngularForce,call,angForce={1},push={2}", LocalID, force, pushforce);
// m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce);
}
public override void SetMomentum(OMV.Vector3 momentum) {
+ DetailLog("{0},SetMomentum,call,mom={1}", LocalID, momentum);
}
public override void SubscribeEvents(int ms) {
_subscribedEventsMs = ms;
@@ -885,6 +935,9 @@ public sealed class BSPrim : PhysicsActor
returnMass = _density * volume;
+ /*
+ * This change means each object keeps its own mass and the Mass property
+ * will return the sum if we're part of a linkset.
if (IsRootOfLinkset)
{
foreach (BSPrim prim in _childrenPrims)
@@ -892,6 +945,7 @@ public sealed class BSPrim : PhysicsActor
returnMass += prim.CalculateMass();
}
}
+ */
if (returnMass <= 0)
returnMass = 0.0001f;
@@ -907,9 +961,11 @@ public sealed class BSPrim : PhysicsActor
// The objects needs a hull if it's physical otherwise a mesh is enough
// No locking here because this is done when we know physics is not simulating
// if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used
- private void CreateGeom(bool forceRebuild)
+ // Returns 'true' if the geometry was rebuilt
+ private bool CreateGeom(bool forceRebuild)
{
// the mesher thought this was too simple to mesh. Use a native Bullet collision shape.
+ bool ret = false;
if (!_scene.NeedsMeshing(_pbs))
{
if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1)
@@ -917,16 +973,28 @@ public sealed class BSPrim : PhysicsActor
if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z)
{
// m_log.DebugFormat("{0}: CreateGeom: Defaulting to sphere of size {1}", LogHeader, _size);
- _shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE;
- // Bullet native objects are scaled by the Bullet engine so pass the size in
- _scale = _size;
+ if (forceRebuild || (_shapeType != ShapeData.PhysicsShapeType.SHAPE_SPHERE))
+ {
+ DetailLog("{0},CreateGeom,sphere", LocalID);
+ _shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE;
+ // Bullet native objects are scaled by the Bullet engine so pass the size in
+ _scale = _size;
+ // TODO: do we need to check for and destroy a mesh or hull that might have been left from before?
+ ret = true;
+ }
}
}
else
{
- // m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, size={2}", LogHeader, LocalID, _size);
- _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX;
- _scale = _size;
+ // m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, type={2}, size={3}", LogHeader, LocalID, _shapeType, _size);
+ if (forceRebuild || (_shapeType != ShapeData.PhysicsShapeType.SHAPE_BOX))
+ {
+ DetailLog("{0},CreateGeom,box", LocalID);
+ _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX;
+ _scale = _size;
+ // TODO: do we need to check for and destroy a mesh or hull that might have been left from before?
+ ret = true;
+ }
}
}
else
@@ -938,6 +1006,7 @@ public sealed class BSPrim : PhysicsActor
// physical objects require a hull for interaction.
// This will create the mesh if it doesn't already exist
CreateGeomHull();
+ ret = true;
}
}
else
@@ -946,9 +1015,11 @@ public sealed class BSPrim : PhysicsActor
{
// Static (non-physical) objects only need a mesh for bumping into
CreateGeomMesh();
+ ret = true;
}
}
}
+ return ret;
}
// No locking here because this is done when we know physics is not simulating
@@ -961,10 +1032,12 @@ public sealed class BSPrim : PhysicsActor
// if this new shape is the same as last time, don't recreate the mesh
if (_meshKey == newMeshKey) return;
+ DetailLog("{0},CreateGeomMesh,create,key={1}", LocalID, _meshKey);
// Since we're recreating new, get rid of any previously generated shape
if (_meshKey != 0)
{
// m_log.DebugFormat("{0}: CreateGeom: deleting old mesh. lID={1}, Key={2}", LogHeader, _localID, _meshKey);
+ DetailLog("{0},CreateGeomMesh,deleteOld,key={1}", LocalID, _meshKey);
BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey);
_mesh = null;
_meshKey = 0;
@@ -981,7 +1054,6 @@ public sealed class BSPrim : PhysicsActor
int vi = 0;
foreach (OMV.Vector3 vv in vertices)
{
- // m_log.DebugFormat("{0}: {1}: <{2:0.00}, {3:0.00}, {4:0.00}>", LogHeader, vi / 3, vv.X, vv.Y, vv.Z);
verticesAsFloats[vi++] = vv.X;
verticesAsFloats[vi++] = vv.Y;
verticesAsFloats[vi++] = vv.Z;
@@ -995,6 +1067,7 @@ public sealed class BSPrim : PhysicsActor
_shapeType = ShapeData.PhysicsShapeType.SHAPE_MESH;
// meshes are already scaled by the meshmerizer
_scale = new OMV.Vector3(1f, 1f, 1f);
+ DetailLog("{0},CreateGeomMesh,done", LocalID);
return;
}
@@ -1008,13 +1081,17 @@ public sealed class BSPrim : PhysicsActor
// if the hull hasn't changed, don't rebuild it
if (newHullKey == _hullKey) return;
+ DetailLog("{0},CreateGeomHull,create,key={1}", LocalID, _meshKey);
+
// Since we're recreating new, get rid of any previously generated shape
if (_hullKey != 0)
{
// m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey);
+ DetailLog("{0},CreateGeomHull,deleteOldHull,key={1}", LocalID, _meshKey);
BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey);
_hullKey = 0;
_hulls.Clear();
+ DetailLog("{0},CreateGeomHull,deleteOldMesh,key={1}", LocalID, _meshKey);
BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey);
_mesh = null; // the mesh cannot match either
_meshKey = 0;
@@ -1111,6 +1188,7 @@ public sealed class BSPrim : PhysicsActor
_shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL;
// meshes are already scaled by the meshmerizer
_scale = new OMV.Vector3(1f, 1f, 1f);
+ DetailLog("{0},CreateGeomHull,done", LocalID);
return;
}
@@ -1124,47 +1202,21 @@ public sealed class BSPrim : PhysicsActor
// Create an object in Bullet if it has not already been created
// No locking here because this is done when the physics engine is not simulating
- private void CreateObject()
+ // Returns 'true' if an object was actually created.
+ private bool CreateObject()
{
- if (IsRootOfLinkset)
- {
- // Create a linkset around this object
- // CreateLinksetWithCompoundHull();
- CreateLinksetWithConstraints();
- }
- else
- {
- // simple object
- // the mesh or hull must have already been created in Bullet
- ShapeData shape;
- FillShapeInfo(out shape);
- // m_log.DebugFormat("{0}: CreateObject: lID={1}, shape={2}", LogHeader, _localID, shape.Type);
- BulletSimAPI.CreateObject(_scene.WorldID, shape);
- }
- }
+ // this routine is called when objects are rebuilt.
- // Create a linkset by creating a compound hull at the root prim that consists of all
- // the children.
- // NOTE: This does not allow proper collisions with the children prims so it is not a workable solution
- void CreateLinksetWithCompoundHull()
- {
- // If I am the root prim of a linkset, replace my physical shape with all the
- // pieces of the children.
- // All of the children should have called CreateGeom so they have a hull
- // in the physics engine already. Here we pull together all of those hulls
- // into one shape.
- int totalPrimsInLinkset = _childrenPrims.Count + 1;
- // m_log.DebugFormat("{0}: CreateLinkset. Root prim={1}, prims={2}", LogHeader, LocalID, totalPrimsInLinkset);
- ShapeData[] shapes = new ShapeData[totalPrimsInLinkset];
- FillShapeInfo(out shapes[0]);
- int ii = 1;
- foreach (BSPrim prim in _childrenPrims)
- {
- // m_log.DebugFormat("{0}: CreateLinkset: adding prim {1}", LogHeader, prim.LocalID);
- prim.FillShapeInfo(out shapes[ii]);
- ii++;
- }
- BulletSimAPI.CreateLinkset(_scene.WorldID, totalPrimsInLinkset, shapes);
+ // the mesh or hull must have already been created in Bullet
+ ShapeData shape;
+ FillShapeInfo(out shape);
+ // m_log.DebugFormat("{0}: CreateObject: lID={1}, shape={2}", LogHeader, _localID, shape.Type);
+ bool ret = BulletSimAPI.CreateObject(_scene.WorldID, shape);
+
+ // the CreateObject() may have recreated the rigid body. Make sure we have the latest.
+ m_body.Ptr = BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID);
+
+ return ret;
}
// Copy prim's info into the BulletSim shape description structure
@@ -1186,44 +1238,6 @@ public sealed class BSPrim : PhysicsActor
shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue;
}
- // Create the linkset by putting constraints between the objects of the set so they cannot move
- // relative to each other.
- // TODO: make this more effeicient: a large linkset gets rebuilt over and over and prims are added
- void CreateLinksetWithConstraints()
- {
- // m_log.DebugFormat("{0}: CreateLinkset. Root prim={1}, prims={2}", LogHeader, LocalID, _childrenPrims.Count+1);
-
- // remove any constraints that might be in place
- foreach (BSPrim prim in _childrenPrims)
- {
- // m_log.DebugFormat("{0}: CreateLinkset: RemoveConstraint between root prim {1} and child prim {2}", LogHeader, LocalID, prim.LocalID);
- BulletSimAPI.RemoveConstraint(_scene.WorldID, LocalID, prim.LocalID);
- }
- // create constraints between the root prim and each of the children
- foreach (BSPrim prim in _childrenPrims)
- {
- // m_log.DebugFormat("{0}: CreateLinkset: AddConstraint between root prim {1} and child prim {2}", LogHeader, LocalID, prim.LocalID);
-
- // Zero motion for children so they don't interpolate
- prim.ZeroMotion();
-
- // relative position normalized to the root prim
- OMV.Vector3 childRelativePosition = (prim._position - this._position) * OMV.Quaternion.Inverse(this._orientation);
-
- // relative rotation of the child to the parent
- OMV.Quaternion relativeRotation = OMV.Quaternion.Inverse(prim._orientation) * this._orientation;
-
- // this is a constraint that allows no freedom of movement between the two objects
- // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
- BulletSimAPI.AddConstraint(_scene.WorldID, LocalID, prim.LocalID,
- childRelativePosition,
- relativeRotation,
- OMV.Vector3.Zero,
- OMV.Quaternion.Identity,
- OMV.Vector3.Zero, OMV.Vector3.Zero,
- OMV.Vector3.Zero, OMV.Vector3.Zero);
- }
- }
// Rebuild the geometry and object.
// This is called when the shape changes so we need to recreate the mesh/hull.
@@ -1231,8 +1245,8 @@ public sealed class BSPrim : PhysicsActor
private void RecreateGeomAndObject()
{
// m_log.DebugFormat("{0}: RecreateGeomAndObject. lID={1}", LogHeader, _localID);
- CreateGeom(true);
- CreateObject();
+ if (CreateGeom(true))
+ CreateObject();
return;
}
@@ -1252,77 +1266,77 @@ public sealed class BSPrim : PhysicsActor
const float POSITION_TOLERANCE = 0.05f;
const float ACCELERATION_TOLERANCE = 0.01f;
const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f;
- const bool SHOULD_DAMP_UPDATES = false;
public void UpdateProperties(EntityProperties entprop)
{
+ /*
UpdatedProperties changed = 0;
- if (SHOULD_DAMP_UPDATES)
+ // assign to the local variables so the normal set action does not happen
+ // if (_position != entprop.Position)
+ if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE))
{
- // assign to the local variables so the normal set action does not happen
- // if (_position != entprop.Position)
- if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE))
+ _position = entprop.Position;
+ changed |= UpdatedProperties.Position;
+ }
+ // if (_orientation != entprop.Rotation)
+ if (!_orientation.ApproxEquals(entprop.Rotation, ROTATION_TOLERANCE))
+ {
+ _orientation = entprop.Rotation;
+ changed |= UpdatedProperties.Rotation;
+ }
+ // if (_velocity != entprop.Velocity)
+ if (!_velocity.ApproxEquals(entprop.Velocity, VELOCITY_TOLERANCE))
+ {
+ _velocity = entprop.Velocity;
+ changed |= UpdatedProperties.Velocity;
+ }
+ // if (_acceleration != entprop.Acceleration)
+ if (!_acceleration.ApproxEquals(entprop.Acceleration, ACCELERATION_TOLERANCE))
+ {
+ _acceleration = entprop.Acceleration;
+ changed |= UpdatedProperties.Acceleration;
+ }
+ // if (_rotationalVelocity != entprop.RotationalVelocity)
+ if (!_rotationalVelocity.ApproxEquals(entprop.RotationalVelocity, ROTATIONAL_VELOCITY_TOLERANCE))
+ {
+ _rotationalVelocity = entprop.RotationalVelocity;
+ changed |= UpdatedProperties.RotationalVel;
+ }
+ if (changed != 0)
+ {
+ // Only update the position of single objects and linkset roots
+ if (this._parentPrim == null)
{
- _position = entprop.Position;
- // m_log.DebugFormat("{0}: UpdateProperties: id={1}, pos = {2}", LogHeader, LocalID, _position);
- changed |= UpdatedProperties.Position;
- }
- // if (_orientation != entprop.Rotation)
- if (!_orientation.ApproxEquals(entprop.Rotation, ROTATION_TOLERANCE))
- {
- _orientation = entprop.Rotation;
- // m_log.DebugFormat("{0}: UpdateProperties: id={1}, rot = {2}", LogHeader, LocalID, _orientation);
- changed |= UpdatedProperties.Rotation;
- }
- // if (_velocity != entprop.Velocity)
- if (!_velocity.ApproxEquals(entprop.Velocity, VELOCITY_TOLERANCE))
- {
- _velocity = entprop.Velocity;
- // m_log.DebugFormat("{0}: UpdateProperties: velocity = {1}", LogHeader, _velocity);
- changed |= UpdatedProperties.Velocity;
- }
- // if (_acceleration != entprop.Acceleration)
- if (!_acceleration.ApproxEquals(entprop.Acceleration, ACCELERATION_TOLERANCE))
- {
- _acceleration = entprop.Acceleration;
- // m_log.DebugFormat("{0}: UpdateProperties: acceleration = {1}", LogHeader, _acceleration);
- changed |= UpdatedProperties.Acceleration;
- }
- // if (_rotationalVelocity != entprop.RotationalVelocity)
- if (!_rotationalVelocity.ApproxEquals(entprop.RotationalVelocity, ROTATIONAL_VELOCITY_TOLERANCE))
- {
- _rotationalVelocity = entprop.RotationalVelocity;
- // m_log.DebugFormat("{0}: UpdateProperties: rotationalVelocity = {1}", LogHeader, _rotationalVelocity);
- changed |= UpdatedProperties.RotationalVel;
- }
- if (changed != 0)
- {
- // m_log.DebugFormat("{0}: UpdateProperties: id={1}, c={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation);
- // Only update the position of single objects and linkset roots
- if (this._parentPrim == null)
- {
- // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation);
- base.RequestPhysicsterseUpdate();
- }
+ base.RequestPhysicsterseUpdate();
}
}
+ */
+
+ // Don't check for damping here -- it's done in BulletSim and SceneObjectPart.
+
+ // Updates only for individual prims and for the root object of a linkset.
+ if (_linkset.IsRoot(this))
+ {
+ // Assign to the local variables so the normal set action does not happen
+ _position = entprop.Position;
+ _orientation = entprop.Rotation;
+ _velocity = entprop.Velocity;
+ _acceleration = entprop.Acceleration;
+ _rotationalVelocity = entprop.RotationalVelocity;
+
+ // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}, vel={5}, acc={6}, rvel={7}",
+ // LogHeader, LocalID, changed, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
+ DetailLog("{0},UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
+ LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
+
+ base.RequestPhysicsterseUpdate();
+ }
else
{
- // Don't check for damping here -- it's done in BulletSim and SceneObjectPart.
-
- // Only updates only for individual prims and for the root object of a linkset.
- if (this._parentPrim == null)
- {
- // Assign to the local variables so the normal set action does not happen
- _position = entprop.Position;
- _orientation = entprop.Rotation;
- _velocity = entprop.Velocity;
- _acceleration = entprop.Acceleration;
- _rotationalVelocity = entprop.RotationalVelocity;
- // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}, vel={5}, acc={6}, rvel={7}",
- // LogHeader, LocalID, changed, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
- base.RequestPhysicsterseUpdate();
- }
+ // For debugging, we can also report the movement of children
+ DetailLog("{0},UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
+ LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
+ entprop.Acceleration, entprop.RotationalVelocity);
}
}
@@ -1362,5 +1376,11 @@ public sealed class BSPrim : PhysicsActor
collisionCollection.Clear();
}
}
+
+ // Invoke the detailed logger and output something if it's enabled.
+ private void DetailLog(string msg, params Object[] args)
+ {
+ Scene.PhysicsLogging.Write(msg, args);
+ }
}
}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index 417cb5f3f0..28d5cb5b62 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -29,12 +29,14 @@ using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
+using OpenSim.Framework;
+using OpenSim.Region.Framework;
+using OpenSim.Region.CoreModules;
+using Logging = OpenSim.Region.CoreModules.Framework.Statistics.Logging;
+using OpenSim.Region.Physics.Manager;
using Nini.Config;
using log4net;
-using OpenSim.Framework;
-using OpenSim.Region.Physics.Manager;
using OpenMetaverse;
-using OpenSim.Region.Framework;
// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim)
// Debug linkset
@@ -44,15 +46,17 @@ using OpenSim.Region.Framework;
// Compute physics FPS reasonably
// Based on material, set density and friction
// More efficient memory usage when passing hull information from BSPrim to BulletSim
+// Move all logic out of the C++ code and into the C# code for easier future modifications.
// Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly?
// In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground)
// At the moment, physical and phantom causes object to drop through the terrain
// Physical phantom objects and related typing (collision options )
+// Use collision masks for collision with terrain and phantom objects
// Check out llVolumeDetect. Must do something for that.
// Should prim.link() and prim.delink() membership checking happen at taint time?
+// changing the position and orientation of a linked prim must rebuild the constraint with the root.
// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once
// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect
-// Use collision masks for collision with terrain and phantom objects
// Implement the genCollisions feature in BulletSim::SetObjectProperties (don't pass up unneeded collisions)
// Implement LockAngularMotion
// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation)
@@ -60,9 +64,6 @@ using OpenSim.Region.Framework;
// Remove mesh and Hull stuff. Use mesh passed to bullet and use convexdecom from bullet.
// Add PID movement operations. What does ScenePresence.MoveToTarget do?
// Check terrain size. 128 or 127?
-// Multiple contact points on collision?
-// See code in ode::near... calls to collision_accounting_events()
-// (This might not be a problem. ODE collects all the collisions with one object in one tick.)
// Raycast
//
namespace OpenSim.Region.Physics.BulletSPlugin
@@ -72,6 +73,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private static readonly string LogHeader = "[BULLETS SCENE]";
+ public void DebugLog(string mm, params Object[] xx) { if (shouldDebugLog) m_log.DebugFormat(mm, xx); }
+
public string BulletSimVersion = "?";
private Dictionary m_avatars = new Dictionary();
@@ -84,6 +87,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
private uint m_worldID;
public uint WorldID { get { return m_worldID; } }
+ // let my minuions use my logger
+ public ILog Logger { get { return m_log; } }
+
private bool m_initialized = false;
private int m_detailedStatsStep = 0;
@@ -100,11 +106,24 @@ public class BSScene : PhysicsScene, IPhysicsParameters
get { return m_sculptLOD; }
}
+ private BulletSim m_worldSim;
+ public BulletSim World
+ {
+ get { return m_worldSim; }
+ }
+ private BSConstraintCollection m_constraintCollection;
+ public BSConstraintCollection Constraints
+ {
+ get { return m_constraintCollection; }
+ }
+
private int m_maxSubSteps;
private float m_fixedTimeStep;
private long m_simulationStep = 0;
public long SimulationStep { get { return m_simulationStep; } }
+ public float LastSimulatedTimestep { get; private set; }
+
// A value of the time now so all the collision and update routines do not have to get their own
// Set to 'now' just before all the prims and actors are called for collisions and updates
private int m_simulationNowTime;
@@ -121,6 +140,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
private bool _meshSculptedPrim = true; // cause scuplted prims to get meshed
private bool _forceSimplePrimMeshing = false; // if a cube or sphere, let Bullet do internal shapes
+ public float PID_D { get; private set; } // derivative
+ public float PID_P { get; private set; } // proportional
+
public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero
public const uint GROUNDPLANE_ID = 1;
@@ -147,8 +169,20 @@ public class BSScene : PhysicsScene, IPhysicsParameters
ConfigurationParameters[] m_params;
GCHandle m_paramsHandle;
+ public bool shouldDebugLog { get; private set; }
+
private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle;
+ // Sometimes you just have to log everything.
+ public Logging.LogWriter PhysicsLogging;
+ private bool m_physicsLoggingEnabled;
+ private string m_physicsLoggingDir;
+ private string m_physicsLoggingPrefix;
+ private int m_physicsLoggingFileMinutes;
+
+ private bool m_vehicleLoggingEnabled;
+ public bool VehicleLoggingEnabled { get { return m_vehicleLoggingEnabled; } }
+
public BSScene(string identifier)
{
m_initialized = false;
@@ -169,17 +203,32 @@ public class BSScene : PhysicsScene, IPhysicsParameters
m_updateArray = new EntityProperties[m_maxUpdatesPerFrame];
m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned);
+ // Enable very detailed logging.
+ // By creating an empty logger when not logging, the log message invocation code
+ // can be left in and every call doesn't have to check for null.
+ if (m_physicsLoggingEnabled)
+ {
+ PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes);
+ }
+ else
+ {
+ PhysicsLogging = new Logging.LogWriter();
+ }
+
// Get the version of the DLL
// TODO: this doesn't work yet. Something wrong with marshaling the returned string.
// BulletSimVersion = BulletSimAPI.GetVersion();
// m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion);
// if Debug, enable logging from the unmanaged code
- if (m_log.IsDebugEnabled)
+ if (m_log.IsDebugEnabled || PhysicsLogging.Enabled)
{
m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader);
- // the handle is saved to it doesn't get freed after this call
- m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger);
+ if (PhysicsLogging.Enabled)
+ m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLoggerPhysLog);
+ else
+ m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger);
+ // the handle is saved in a variable to make sure it doesn't get freed after this call
BulletSimAPI.SetDebugLogCallback(m_DebugLogCallbackHandle);
}
@@ -194,6 +243,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(),
m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject());
+ // Initialization to support the transition to a new API which puts most of the logic
+ // into the C# code so it is easier to modify and add to.
+ m_worldSim = new BulletSim(m_worldID, BulletSimAPI.GetSimHandle2(m_worldID));
+ m_constraintCollection = new BSConstraintCollection(World);
+
m_initialized = true;
}
@@ -202,110 +256,27 @@ public class BSScene : PhysicsScene, IPhysicsParameters
private void GetInitialParameterValues(IConfigSource config)
{
ConfigurationParameters parms = new ConfigurationParameters();
+ m_params[0] = parms;
- _meshSculptedPrim = true; // mesh sculpted prims
- _forceSimplePrimMeshing = false; // use complex meshing if called for
-
- m_meshLOD = 8f;
- m_sculptLOD = 32f;
-
- m_detailedStatsStep = 0; // disabled
-
- m_maxSubSteps = 10;
- m_fixedTimeStep = 1f / 60f;
- m_maxCollisionsPerFrame = 2048;
- m_maxUpdatesPerFrame = 2048;
- m_maximumObjectMass = 10000.01f;
-
- parms.defaultFriction = 0.5f;
- parms.defaultDensity = 10.000006836f; // Aluminum g/cm3
- parms.defaultRestitution = 0f;
- parms.collisionMargin = 0.0f;
- parms.gravity = -9.80665f;
-
- parms.linearDamping = 0.0f;
- parms.angularDamping = 0.0f;
- parms.deactivationTime = 0.2f;
- parms.linearSleepingThreshold = 0.8f;
- parms.angularSleepingThreshold = 1.0f;
- parms.ccdMotionThreshold = 0.0f; // set to zero to disable
- parms.ccdSweptSphereRadius = 0.0f;
- parms.contactProcessingThreshold = 0.1f;
-
- parms.terrainFriction = 0.5f;
- parms.terrainHitFraction = 0.8f;
- parms.terrainRestitution = 0f;
- parms.avatarFriction = 0.5f;
- parms.avatarRestitution = 0.0f;
- parms.avatarDensity = 60f;
- parms.avatarCapsuleRadius = 0.37f;
- parms.avatarCapsuleHeight = 1.5f; // 2.140599f
- parms.avatarContactProcessingThreshold = 0.1f;
-
- parms.maxPersistantManifoldPoolSize = 0f;
- parms.shouldDisableContactPoolDynamicAllocation = ConfigurationParameters.numericTrue;
- parms.shouldForceUpdateAllAabbs = ConfigurationParameters.numericFalse;
- parms.shouldRandomizeSolverOrder = ConfigurationParameters.numericFalse;
- parms.shouldSplitSimulationIslands = ConfigurationParameters.numericFalse;
- parms.shouldEnableFrictionCaching = ConfigurationParameters.numericFalse;
- parms.numberOfSolverIterations = 0f; // means use default
+ SetParameterDefaultValues();
if (config != null)
{
// If there are specifications in the ini file, use those values
- // WHEN ADDING OR UPDATING THIS SECTION, BE SURE TO UPDATE OpenSimDefaults.ini
- // ALSO REMEMBER TO UPDATE THE RUNTIME SETTING OF THE PARAMETERS.
IConfig pConfig = config.Configs["BulletSim"];
if (pConfig != null)
{
- _meshSculptedPrim = pConfig.GetBoolean("MeshSculptedPrim", _meshSculptedPrim);
- _forceSimplePrimMeshing = pConfig.GetBoolean("ForceSimplePrimMeshing", _forceSimplePrimMeshing);
+ SetParameterConfigurationValues(pConfig);
- m_detailedStatsStep = pConfig.GetInt("DetailedStatsStep", m_detailedStatsStep);
- m_meshLOD = pConfig.GetFloat("MeshLevelOfDetail", m_meshLOD);
- m_sculptLOD = pConfig.GetFloat("SculptLevelOfDetail", m_sculptLOD);
-
- m_maxSubSteps = pConfig.GetInt("MaxSubSteps", m_maxSubSteps);
- m_fixedTimeStep = pConfig.GetFloat("FixedTimeStep", m_fixedTimeStep);
- m_maxCollisionsPerFrame = pConfig.GetInt("MaxCollisionsPerFrame", m_maxCollisionsPerFrame);
- m_maxUpdatesPerFrame = pConfig.GetInt("MaxUpdatesPerFrame", m_maxUpdatesPerFrame);
- m_maximumObjectMass = pConfig.GetFloat("MaxObjectMass", m_maximumObjectMass);
-
- parms.defaultFriction = pConfig.GetFloat("DefaultFriction", parms.defaultFriction);
- parms.defaultDensity = pConfig.GetFloat("DefaultDensity", parms.defaultDensity);
- parms.defaultRestitution = pConfig.GetFloat("DefaultRestitution", parms.defaultRestitution);
- parms.collisionMargin = pConfig.GetFloat("CollisionMargin", parms.collisionMargin);
- parms.gravity = pConfig.GetFloat("Gravity", parms.gravity);
-
- parms.linearDamping = pConfig.GetFloat("LinearDamping", parms.linearDamping);
- parms.angularDamping = pConfig.GetFloat("AngularDamping", parms.angularDamping);
- parms.deactivationTime = pConfig.GetFloat("DeactivationTime", parms.deactivationTime);
- parms.linearSleepingThreshold = pConfig.GetFloat("LinearSleepingThreshold", parms.linearSleepingThreshold);
- parms.angularSleepingThreshold = pConfig.GetFloat("AngularSleepingThreshold", parms.angularSleepingThreshold);
- parms.ccdMotionThreshold = pConfig.GetFloat("CcdMotionThreshold", parms.ccdMotionThreshold);
- parms.ccdSweptSphereRadius = pConfig.GetFloat("CcdSweptSphereRadius", parms.ccdSweptSphereRadius);
- parms.contactProcessingThreshold = pConfig.GetFloat("ContactProcessingThreshold", parms.contactProcessingThreshold);
-
- parms.terrainFriction = pConfig.GetFloat("TerrainFriction", parms.terrainFriction);
- parms.terrainHitFraction = pConfig.GetFloat("TerrainHitFraction", parms.terrainHitFraction);
- parms.terrainRestitution = pConfig.GetFloat("TerrainRestitution", parms.terrainRestitution);
- parms.avatarFriction = pConfig.GetFloat("AvatarFriction", parms.avatarFriction);
- parms.avatarRestitution = pConfig.GetFloat("AvatarRestitution", parms.avatarRestitution);
- parms.avatarDensity = pConfig.GetFloat("AvatarDensity", parms.avatarDensity);
- parms.avatarCapsuleRadius = pConfig.GetFloat("AvatarCapsuleRadius", parms.avatarCapsuleRadius);
- parms.avatarCapsuleHeight = pConfig.GetFloat("AvatarCapsuleHeight", parms.avatarCapsuleHeight);
- parms.avatarContactProcessingThreshold = pConfig.GetFloat("AvatarContactProcessingThreshold", parms.avatarContactProcessingThreshold);
-
- parms.maxPersistantManifoldPoolSize = pConfig.GetFloat("MaxPersistantManifoldPoolSize", parms.maxPersistantManifoldPoolSize);
- parms.shouldDisableContactPoolDynamicAllocation = ParamBoolean(pConfig, "ShouldDisableContactPoolDynamicAllocation", parms.shouldDisableContactPoolDynamicAllocation);
- parms.shouldForceUpdateAllAabbs = ParamBoolean(pConfig, "ShouldForceUpdateAllAabbs", parms.shouldForceUpdateAllAabbs);
- parms.shouldRandomizeSolverOrder = ParamBoolean(pConfig, "ShouldRandomizeSolverOrder", parms.shouldRandomizeSolverOrder);
- parms.shouldSplitSimulationIslands = ParamBoolean(pConfig, "ShouldSplitSimulationIslands", parms.shouldSplitSimulationIslands);
- parms.shouldEnableFrictionCaching = ParamBoolean(pConfig, "ShouldEnableFrictionCaching", parms.shouldEnableFrictionCaching);
- parms.numberOfSolverIterations = pConfig.GetFloat("NumberOfSolverIterations", parms.numberOfSolverIterations);
+ // Very detailed logging for physics debugging
+ m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false);
+ m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", ".");
+ m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-");
+ m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5);
+ // Very detailed logging for vehicle debugging
+ m_vehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
}
}
- m_params[0] = parms;
}
// A helper function that handles a true/false parameter and returns the proper float number encoding
@@ -323,12 +294,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
return ret;
}
-
// Called directly from unmanaged code so don't do much
private void BulletLogger(string msg)
{
m_log.Debug("[BULLETS UNMANAGED]:" + msg);
}
+
+ // Called directly from unmanaged code so don't do much
+ private void BulletLoggerPhysLog(string msg)
+ {
+ PhysicsLogging.Write("[BULLETS UNMANAGED]:" + msg);
+ }
public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
{
@@ -339,6 +315,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
public override PhysicsActor AddAvatar(uint localID, string avName, Vector3 position, Vector3 size, bool isFlying)
{
// m_log.DebugFormat("{0}: AddAvatar: {1}", LogHeader, avName);
+
+ if (!m_initialized) return null;
+
BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying);
lock (m_avatars) m_avatars.Add(localID, actor);
return actor;
@@ -347,34 +326,47 @@ public class BSScene : PhysicsScene, IPhysicsParameters
public override void RemoveAvatar(PhysicsActor actor)
{
// m_log.DebugFormat("{0}: RemoveAvatar", LogHeader);
- if (actor is BSCharacter)
+
+ if (!m_initialized) return;
+
+ BSCharacter bsactor = actor as BSCharacter;
+ if (bsactor != null)
{
- ((BSCharacter)actor).Destroy();
- }
- try
- {
- lock (m_avatars) m_avatars.Remove(actor.LocalID);
- }
- catch (Exception e)
- {
- m_log.WarnFormat("{0}: Attempt to remove avatar that is not in physics scene: {1}", LogHeader, e);
+ try
+ {
+ lock (m_avatars) m_avatars.Remove(actor.LocalID);
+ }
+ catch (Exception e)
+ {
+ m_log.WarnFormat("{0}: Attempt to remove avatar that is not in physics scene: {1}", LogHeader, e);
+ }
+ bsactor.Destroy();
+ // bsactor.dispose();
}
}
public override void RemovePrim(PhysicsActor prim)
{
- // m_log.DebugFormat("{0}: RemovePrim", LogHeader);
- if (prim is BSPrim)
+ if (!m_initialized) return;
+
+ BSPrim bsprim = prim as BSPrim;
+ if (bsprim != null)
{
- ((BSPrim)prim).Destroy();
+ m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID);
+ try
+ {
+ lock (m_prims) m_prims.Remove(bsprim.LocalID);
+ }
+ catch (Exception e)
+ {
+ m_log.ErrorFormat("{0}: Attempt to remove prim that is not in physics scene: {1}", LogHeader, e);
+ }
+ bsprim.Destroy();
+ // bsprim.dispose();
}
- try
+ else
{
- lock (m_prims) m_prims.Remove(prim.LocalID);
- }
- catch (Exception e)
- {
- m_log.WarnFormat("{0}: Attempt to remove prim that is not in physics scene: {1}", LogHeader, e);
+ m_log.ErrorFormat("{0}: Attempt to remove prim that is not a BSPrim type.", LogHeader);
}
}
@@ -382,6 +374,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
Vector3 size, Quaternion rotation, bool isPhysical, uint localID)
{
// m_log.DebugFormat("{0}: AddPrimShape2: {1}", LogHeader, primName);
+
+ if (!m_initialized) return null;
+
BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical);
lock (m_prims) m_prims.Add(localID, prim);
return prim;
@@ -400,6 +395,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
int collidersCount;
IntPtr collidersPtr;
+ LastSimulatedTimestep = timeStep;
+
// prevent simulation until we've been initialized
if (!m_initialized) return 10.0f;
@@ -459,7 +456,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters
for (int ii = 0; ii < updatedEntityCount; ii++)
{
EntityProperties entprop = m_updateArray[ii];
- // m_log.DebugFormat("{0}: entprop[{1}]: id={2}, pos={3}", LogHeader, ii, entprop.ID, entprop.Position);
BSPrim prim;
if (m_prims.TryGetValue(entprop.ID, out prim))
{
@@ -532,8 +528,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
});
}
+ // Someday we will have complex terrain with caves and tunnels
+ // For the moment, it's flat and convex
+ public float GetTerrainHeightAtXYZ(Vector3 loc)
+ {
+ return GetTerrainHeightAtXY(loc.X, loc.Y);
+ }
+
public float GetTerrainHeightAtXY(float tX, float tY)
{
+ if (tX < 0 || tX >= Constants.RegionSize || tY < 0 || tY >= Constants.RegionSize)
+ return 30;
return m_heightMap[((int)tX) * Constants.RegionSize + ((int)tY)];
}
@@ -555,6 +560,33 @@ public class BSScene : PhysicsScene, IPhysicsParameters
public override void Dispose()
{
// m_log.DebugFormat("{0}: Dispose()", LogHeader);
+
+ // make sure no stepping happens while we're deleting stuff
+ m_initialized = false;
+
+ if (m_constraintCollection != null)
+ {
+ m_constraintCollection.Dispose();
+ m_constraintCollection = null;
+ }
+
+ foreach (KeyValuePair kvp in m_avatars)
+ {
+ kvp.Value.Destroy();
+ }
+ m_avatars.Clear();
+
+ foreach (KeyValuePair kvp in m_prims)
+ {
+ kvp.Value.Destroy();
+ }
+ m_prims.Clear();
+
+ // Anything left in the unmanaged code should be cleaned out
+ BulletSimAPI.Shutdown(WorldID);
+
+ // Not logging any more
+ PhysicsLogging.Close();
}
public override Dictionary GetTopColliders()
@@ -680,10 +712,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
}
// The calls to the PhysicsActors can't directly call into the physics engine
- // because it might be busy. We we delay changes to a known time.
+ // because it might be busy. We delay changes to a known time.
// We rely on C#'s closure to save and restore the context for the delegate.
public void TaintedObject(TaintCallback callback)
{
+ if (!m_initialized) return;
+
lock (_taintLock)
_taintedObjects.Add(callback);
return;
@@ -757,61 +791,392 @@ public class BSScene : PhysicsScene, IPhysicsParameters
}
#endregion Vehicles
- #region Runtime settable parameters
- public static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[]
+ #region Parameters
+
+ delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val);
+ delegate float ParamGet(BSScene scene);
+ delegate void ParamSet(BSScene scene, string paramName, uint localID, float val);
+
+ private struct ParameterDefn
{
- new PhysParameterEntry("MeshLOD", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)"),
- new PhysParameterEntry("SculptLOD", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)"),
- new PhysParameterEntry("MaxSubStep", "In simulation step, maximum number of substeps"),
- new PhysParameterEntry("FixedTimeStep", "In simulation step, seconds of one substep (1/60)"),
- new PhysParameterEntry("MaxObjectMass", "Maximum object mass (10000.01)"),
- new PhysParameterEntry("DetailedStats", "Frames between outputting detailed phys stats. Zero is off"),
+ public string name;
+ public string desc;
+ public float defaultValue;
+ public ParamUser userParam;
+ public ParamGet getter;
+ public ParamSet setter;
+ public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s)
+ {
+ name = n;
+ desc = d;
+ defaultValue = v;
+ userParam = u;
+ getter = g;
+ setter = s;
+ }
+ }
- new PhysParameterEntry("DefaultFriction", "Friction factor used on new objects"),
- new PhysParameterEntry("DefaultDensity", "Density for new objects" ),
- new PhysParameterEntry("DefaultRestitution", "Bouncyness of an object" ),
- // new PhysParameterEntry("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!!)" ),
- new PhysParameterEntry("Gravity", "Vertical force of gravity (negative means down)" ),
+ // List of all of the externally visible parameters.
+ // For each parameter, this table maps a text name to getter and setters.
+ // To add a new externally referencable/settable parameter, add the paramter storage
+ // location somewhere in the program and make an entry in this table with the
+ // getters and setters.
+ // To add a new variable, it is easiest to find an existing definition and copy it.
+ // Parameter values are floats. Booleans are converted to a floating value.
+ //
+ // A ParameterDefn() takes the following parameters:
+ // -- the text name of the parameter. This is used for console input and ini file.
+ // -- a short text description of the parameter. This shows up in the console listing.
+ // -- a delegate for fetching the parameter from the ini file.
+ // Should handle fetching the right type from the ini file and converting it.
+ // -- a delegate for getting the value as a float
+ // -- a delegate for setting the value from a float
+ //
+ // The single letter parameters for the delegates are:
+ // s = BSScene
+ // p = string parameter name
+ // l = localID of referenced object
+ // v = float value
+ // cf = parameter configuration class (for fetching values from ini file)
+ private ParameterDefn[] ParameterDefinitions =
+ {
+ new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties",
+ ConfigurationParameters.numericTrue,
+ (s,cf,p,v) => { s._meshSculptedPrim = cf.GetBoolean(p, s.BoolNumeric(v)); },
+ (s) => { return s.NumericBool(s._meshSculptedPrim); },
+ (s,p,l,v) => { s._meshSculptedPrim = s.BoolNumeric(v); } ),
+ new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects",
+ ConfigurationParameters.numericFalse,
+ (s,cf,p,v) => { s._forceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); },
+ (s) => { return s.NumericBool(s._forceSimplePrimMeshing); },
+ (s,p,l,v) => { s._forceSimplePrimMeshing = s.BoolNumeric(v); } ),
- new PhysParameterEntry("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)" ),
- new PhysParameterEntry("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)" ),
- new PhysParameterEntry("DeactivationTime", "Seconds before considering an object potentially static" ),
- new PhysParameterEntry("LinearSleepingThreshold", "Seconds to measure linear movement before considering static" ),
- new PhysParameterEntry("AngularSleepingThreshold", "Seconds to measure angular movement before considering static" ),
- new PhysParameterEntry("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ),
- new PhysParameterEntry("CcdSweptSphereRadius", "Continuious collision detection test radius" ),
- new PhysParameterEntry("ContactProcessingThreshold", "Distance between contacts before doing collision check" ),
- // Can only change the following at initialization time. Change the INI file and reboot.
- new PhysParameterEntry("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default)"),
- new PhysParameterEntry("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count"),
- new PhysParameterEntry("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step"),
- new PhysParameterEntry("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction"),
- new PhysParameterEntry("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands"),
- new PhysParameterEntry("ShouldEnableFrictionCaching", "Enable friction computation caching"),
- new PhysParameterEntry("NumberOfSolverIterations", "Number of internal iterations (0 means default)"),
+ new ParameterDefn("MeshLOD", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
+ 8f,
+ (s,cf,p,v) => { s.m_meshLOD = cf.GetInt(p, (int)v); },
+ (s) => { return (float)s.m_meshLOD; },
+ (s,p,l,v) => { s.m_meshLOD = (int)v; } ),
+ new ParameterDefn("SculptLOD", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)",
+ 32,
+ (s,cf,p,v) => { s.m_sculptLOD = cf.GetInt(p, (int)v); },
+ (s) => { return (float)s.m_sculptLOD; },
+ (s,p,l,v) => { s.m_sculptLOD = (int)v; } ),
- new PhysParameterEntry("Friction", "Set friction parameter for a specific object" ),
- new PhysParameterEntry("Restitution", "Set restitution parameter for a specific object" ),
+ new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps",
+ 10f,
+ (s,cf,p,v) => { s.m_maxSubSteps = cf.GetInt(p, (int)v); },
+ (s) => { return (float)s.m_maxSubSteps; },
+ (s,p,l,v) => { s.m_maxSubSteps = (int)v; } ),
+ new ParameterDefn("FixedTimeStep", "In simulation step, seconds of one substep (1/60)",
+ 1f / 60f,
+ (s,cf,p,v) => { s.m_fixedTimeStep = cf.GetFloat(p, v); },
+ (s) => { return (float)s.m_fixedTimeStep; },
+ (s,p,l,v) => { s.m_fixedTimeStep = v; } ),
+ new ParameterDefn("MaxCollisionsPerFrame", "Max collisions returned at end of each frame",
+ 2048f,
+ (s,cf,p,v) => { s.m_maxCollisionsPerFrame = cf.GetInt(p, (int)v); },
+ (s) => { return (float)s.m_maxCollisionsPerFrame; },
+ (s,p,l,v) => { s.m_maxCollisionsPerFrame = (int)v; } ),
+ new ParameterDefn("MaxUpdatesPerFrame", "Max updates returned at end of each frame",
+ 8000f,
+ (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); },
+ (s) => { return (float)s.m_maxUpdatesPerFrame; },
+ (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
+ new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
+ 10000.01f,
+ (s,cf,p,v) => { s.m_maximumObjectMass = cf.GetFloat(p, v); },
+ (s) => { return (float)s.m_maximumObjectMass; },
+ (s,p,l,v) => { s.m_maximumObjectMass = v; } ),
- new PhysParameterEntry("Friction", "Set friction parameter for a specific object" ),
- new PhysParameterEntry("Restitution", "Set restitution parameter for a specific object" ),
+ new ParameterDefn("PID_D", "Derivitive factor for motion smoothing",
+ 2200f,
+ (s,cf,p,v) => { s.PID_D = cf.GetFloat(p, v); },
+ (s) => { return (float)s.PID_D; },
+ (s,p,l,v) => { s.PID_D = v; } ),
+ new ParameterDefn("PID_P", "Parameteric factor for motion smoothing",
+ 900f,
+ (s,cf,p,v) => { s.PID_P = cf.GetFloat(p, v); },
+ (s) => { return (float)s.PID_P; },
+ (s,p,l,v) => { s.PID_P = v; } ),
- new PhysParameterEntry("TerrainFriction", "Factor to reduce movement against terrain surface" ),
- new PhysParameterEntry("TerrainHitFraction", "Distance to measure hit collisions" ),
- new PhysParameterEntry("TerrainRestitution", "Bouncyness" ),
- new PhysParameterEntry("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation." ),
- new PhysParameterEntry("AvatarDensity", "Density of an avatar. Changed on avatar recreation." ),
- new PhysParameterEntry("AvatarRestitution", "Bouncyness. Changed on avatar recreation." ),
- new PhysParameterEntry("AvatarCapsuleRadius", "Radius of space around an avatar" ),
- new PhysParameterEntry("AvatarCapsuleHeight", "Default height of space around avatar" ),
- new PhysParameterEntry("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions")
+ new ParameterDefn("DefaultFriction", "Friction factor used on new objects",
+ 0.5f,
+ (s,cf,p,v) => { s.m_params[0].defaultFriction = cf.GetFloat(p, v); },
+ (s) => { return s.m_params[0].defaultFriction; },
+ (s,p,l,v) => { s.m_params[0].defaultFriction = v; } ),
+ new ParameterDefn("DefaultDensity", "Density for new objects" ,
+ 10.000006836f, // Aluminum g/cm3
+ (s,cf,p,v) => { s.m_params[0].defaultDensity = cf.GetFloat(p, v); },
+ (s) => { return s.m_params[0].defaultDensity; },
+ (s,p,l,v) => { s.m_params[0].defaultDensity = v; } ),
+ new ParameterDefn("DefaultRestitution", "Bouncyness of an object" ,
+ 0f,
+ (s,cf,p,v) => { s.m_params[0].defaultRestitution = cf.GetFloat(p, v); },
+ (s) => { return s.m_params[0].defaultRestitution; },
+ (s,p,l,v) => { s.m_params[0].defaultRestitution = v; } ),
+ new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)",
+ 0f,
+ (s,cf,p,v) => { s.m_params[0].collisionMargin = cf.GetFloat(p, v); },
+ (s) => { return s.m_params[0].collisionMargin; },
+ (s,p,l,v) => { s.m_params[0].collisionMargin = v; } ),
+ new ParameterDefn("Gravity", "Vertical force of gravity (negative means down)",
+ -9.80665f,
+ (s,cf,p,v) => { s.m_params[0].gravity = cf.GetFloat(p, v); },
+ (s) => { return s.m_params[0].gravity; },
+ (s,p,l,v) => { s.m_params[0].gravity = v; s.TaintedUpdateParameter(p,l,v); } ),
+
+
+ new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)",
+ 0f,
+ (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); },
+ (s) => { return s.m_params[0].linearDamping; },
+ (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].linearDamping, p, l, v); } ),
+ new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
+ 0f,
+ (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); },
+ (s) => { return s.m_params[0].angularDamping; },
+ (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].angularDamping, p, l, v); } ),
+ new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
+ 0.2f,
+ (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); },
+ (s) => { return s.m_params[0].deactivationTime; },
+ (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].deactivationTime, p, l, v); } ),
+ new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
+ 0.8f,
+ (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); },
+ (s) => { return s.m_params[0].linearSleepingThreshold; },
+ (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].linearSleepingThreshold, p, l, v); } ),
+ new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
+ 1.0f,
+ (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); },
+ (s) => { return s.m_params[0].angularSleepingThreshold; },
+ (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].angularSleepingThreshold, p, l, v); } ),
+ new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
+ 0f, // set to zero to disable
+ (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); },
+ (s) => { return s.m_params[0].ccdMotionThreshold; },
+ (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].ccdMotionThreshold, p, l, v); } ),
+ new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
+ 0f,
+ (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); },
+ (s) => { return s.m_params[0].ccdSweptSphereRadius; },
+ (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); } ),
+ new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" ,
+ 0.1f,
+ (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); },
+ (s) => { return s.m_params[0].contactProcessingThreshold; },
+ (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].contactProcessingThreshold, p, l, v); } ),
+
+ new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
+ 0.5f,
+ (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); },
+ (s) => { return s.m_params[0].terrainFriction; },
+ (s,p,l,v) => { s.m_params[0].terrainFriction = v; s.TaintedUpdateParameter(p,l,v); } ),
+ new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" ,
+ 0.8f,
+ (s,cf,p,v) => { s.m_params[0].terrainHitFraction = cf.GetFloat(p, v); },
+ (s) => { return s.m_params[0].terrainHitFraction; },
+ (s,p,l,v) => { s.m_params[0].terrainHitFraction = v; s.TaintedUpdateParameter(p,l,v); } ),
+ new ParameterDefn("TerrainRestitution", "Bouncyness" ,
+ 0f,
+ (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); },
+ (s) => { return s.m_params[0].terrainRestitution; },
+ (s,p,l,v) => { s.m_params[0].terrainRestitution = v; s.TaintedUpdateParameter(p,l,v); } ),
+ new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
+ 0.5f,
+ (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); },
+ (s) => { return s.m_params[0].avatarFriction; },
+ (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarFriction, p, l, v); } ),
+ new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.",
+ 60f,
+ (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); },
+ (s) => { return s.m_params[0].avatarDensity; },
+ (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarDensity, p, l, v); } ),
+ new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.",
+ 0f,
+ (s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); },
+ (s) => { return s.m_params[0].avatarRestitution; },
+ (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarRestitution, p, l, v); } ),
+ new ParameterDefn("AvatarCapsuleRadius", "Radius of space around an avatar",
+ 0.37f,
+ (s,cf,p,v) => { s.m_params[0].avatarCapsuleRadius = cf.GetFloat(p, v); },
+ (s) => { return s.m_params[0].avatarCapsuleRadius; },
+ (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarCapsuleRadius, p, l, v); } ),
+ new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar",
+ 1.5f,
+ (s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); },
+ (s) => { return s.m_params[0].avatarCapsuleHeight; },
+ (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarCapsuleHeight, p, l, v); } ),
+ new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
+ 0.1f,
+ (s,cf,p,v) => { s.m_params[0].avatarContactProcessingThreshold = cf.GetFloat(p, v); },
+ (s) => { return s.m_params[0].avatarContactProcessingThreshold; },
+ (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ),
+
+
+ new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default)",
+ 0f, // zero to disable
+ (s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); },
+ (s) => { return s.m_params[0].maxPersistantManifoldPoolSize; },
+ (s,p,l,v) => { s.m_params[0].maxPersistantManifoldPoolSize = v; } ),
+ new ParameterDefn("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count",
+ ConfigurationParameters.numericTrue,
+ (s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
+ (s) => { return s.m_params[0].shouldDisableContactPoolDynamicAllocation; },
+ (s,p,l,v) => { s.m_params[0].shouldDisableContactPoolDynamicAllocation = v; } ),
+ new ParameterDefn("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step",
+ ConfigurationParameters.numericFalse,
+ (s,cf,p,v) => { s.m_params[0].shouldForceUpdateAllAabbs = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
+ (s) => { return s.m_params[0].shouldForceUpdateAllAabbs; },
+ (s,p,l,v) => { s.m_params[0].shouldForceUpdateAllAabbs = v; } ),
+ new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction",
+ ConfigurationParameters.numericFalse,
+ (s,cf,p,v) => { s.m_params[0].shouldRandomizeSolverOrder = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
+ (s) => { return s.m_params[0].shouldRandomizeSolverOrder; },
+ (s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ),
+ new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands",
+ ConfigurationParameters.numericFalse,
+ (s,cf,p,v) => { s.m_params[0].shouldSplitSimulationIslands = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
+ (s) => { return s.m_params[0].shouldSplitSimulationIslands; },
+ (s,p,l,v) => { s.m_params[0].shouldSplitSimulationIslands = v; } ),
+ new ParameterDefn("ShouldEnableFrictionCaching", "Enable friction computation caching",
+ ConfigurationParameters.numericFalse,
+ (s,cf,p,v) => { s.m_params[0].shouldEnableFrictionCaching = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
+ (s) => { return s.m_params[0].shouldEnableFrictionCaching; },
+ (s,p,l,v) => { s.m_params[0].shouldEnableFrictionCaching = v; } ),
+ new ParameterDefn("NumberOfSolverIterations", "Number of internal iterations (0 means default)",
+ 0f, // zero says use Bullet default
+ (s,cf,p,v) => { s.m_params[0].numberOfSolverIterations = cf.GetFloat(p, v); },
+ (s) => { return s.m_params[0].numberOfSolverIterations; },
+ (s,p,l,v) => { s.m_params[0].numberOfSolverIterations = v; } ),
+
+ new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
+ ConfigurationParameters.numericFalse,
+ (s,cf,p,v) => { s.m_params[0].linkConstraintUseFrameOffset = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
+ (s) => { return s.m_params[0].linkConstraintUseFrameOffset; },
+ (s,p,l,v) => { s.m_params[0].linkConstraintUseFrameOffset = v; } ),
+ new ParameterDefn("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints",
+ ConfigurationParameters.numericTrue,
+ (s,cf,p,v) => { s.m_params[0].linkConstraintEnableTransMotor = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
+ (s) => { return s.m_params[0].linkConstraintEnableTransMotor; },
+ (s,p,l,v) => { s.m_params[0].linkConstraintEnableTransMotor = v; } ),
+ new ParameterDefn("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints",
+ 5.0f,
+ (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxVel = cf.GetFloat(p, v); },
+ (s) => { return s.m_params[0].linkConstraintTransMotorMaxVel; },
+ (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxVel = v; } ),
+ new ParameterDefn("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints",
+ 0.1f,
+ (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = cf.GetFloat(p, v); },
+ (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; },
+ (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ),
+ new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=none, 1=all. Default=0",
+ 0.0f,
+ (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); },
+ (s) => { return s.m_params[0].linkConstraintCFM; },
+ (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ),
+ new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2",
+ 0.2f,
+ (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); },
+ (s) => { return s.m_params[0].linkConstraintERP; },
+ (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ),
+
+ new ParameterDefn("DetailedStats", "Frames between outputting detailed phys stats. (0 is off)",
+ 0f,
+ (s,cf,p,v) => { s.m_detailedStatsStep = cf.GetInt(p, (int)v); },
+ (s) => { return (float)s.m_detailedStatsStep; },
+ (s,p,l,v) => { s.m_detailedStatsStep = (int)v; } ),
+ new ParameterDefn("ShouldDebugLog", "Enables detailed DEBUG log statements",
+ ConfigurationParameters.numericFalse,
+ (s,cf,p,v) => { s.shouldDebugLog = cf.GetBoolean(p, s.BoolNumeric(v)); },
+ (s) => { return s.NumericBool(s.shouldDebugLog); },
+ (s,p,l,v) => { s.shouldDebugLog = s.BoolNumeric(v); } ),
};
+ // Convert a boolean to our numeric true and false values
+ public float NumericBool(bool b)
+ {
+ return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse);
+ }
+
+ // Convert numeric true and false values to a boolean
+ public bool BoolNumeric(float b)
+ {
+ return (b == ConfigurationParameters.numericTrue ? true : false);
+ }
+
+ // Search through the parameter definitions and return the matching
+ // ParameterDefn structure.
+ // Case does not matter as names are compared after converting to lower case.
+ // Returns 'false' if the parameter is not found.
+ private bool TryGetParameter(string paramName, out ParameterDefn defn)
+ {
+ bool ret = false;
+ ParameterDefn foundDefn = new ParameterDefn();
+ string pName = paramName.ToLower();
+
+ foreach (ParameterDefn parm in ParameterDefinitions)
+ {
+ if (pName == parm.name.ToLower())
+ {
+ foundDefn = parm;
+ ret = true;
+ break;
+ }
+ }
+ defn = foundDefn;
+ return ret;
+ }
+
+ // Pass through the settable parameters and set the default values
+ private void SetParameterDefaultValues()
+ {
+ foreach (ParameterDefn parm in ParameterDefinitions)
+ {
+ parm.setter(this, parm.name, PhysParameterEntry.APPLY_TO_NONE, parm.defaultValue);
+ }
+ }
+
+ // Get user set values out of the ini file.
+ private void SetParameterConfigurationValues(IConfig cfg)
+ {
+ foreach (ParameterDefn parm in ParameterDefinitions)
+ {
+ parm.userParam(this, cfg, parm.name, parm.defaultValue);
+ }
+ }
+
+ private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1];
+
+ private void BuildParameterTable()
+ {
+ if (SettableParameters.Length < ParameterDefinitions.Length)
+ {
+
+ List entries = new List();
+ for (int ii = 0; ii < ParameterDefinitions.Length; ii++)
+ {
+ ParameterDefn pd = ParameterDefinitions[ii];
+ entries.Add(new PhysParameterEntry(pd.name, pd.desc));
+ }
+
+ // make the list in alphabetical order for estetic reasons
+ entries.Sort(delegate(PhysParameterEntry ppe1, PhysParameterEntry ppe2)
+ {
+ return ppe1.name.CompareTo(ppe2.name);
+ });
+
+ SettableParameters = entries.ToArray();
+ }
+ }
+
+
#region IPhysicsParameters
// Get the list of parameters this physics engine supports
public PhysParameterEntry[] GetParameterList()
{
+ BuildParameterTable();
return SettableParameters;
}
@@ -823,63 +1188,18 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// value activated ('terrainFriction' for instance).
public bool SetPhysicsParameter(string parm, float val, uint localID)
{
- bool ret = true;
- string lparm = parm.ToLower();
- switch (lparm)
+ bool ret = false;
+ ParameterDefn theParam;
+ if (TryGetParameter(parm, out theParam))
{
- case "detailedstats": m_detailedStatsStep = (int)val; break;
-
- case "meshlod": m_meshLOD = (int)val; break;
- case "sculptlod": m_sculptLOD = (int)val; break;
- case "maxsubstep": m_maxSubSteps = (int)val; break;
- case "fixedtimestep": m_fixedTimeStep = val; break;
- case "maxobjectmass": m_maximumObjectMass = val; break;
-
- case "defaultfriction": m_params[0].defaultFriction = val; break;
- case "defaultdensity": m_params[0].defaultDensity = val; break;
- case "defaultrestitution": m_params[0].defaultRestitution = val; break;
- case "collisionmargin": m_params[0].collisionMargin = val; break;
- case "gravity": m_params[0].gravity = val; TaintedUpdateParameter(lparm, localID, val); break;
-
- case "lineardamping": UpdateParameterPrims(ref m_params[0].linearDamping, lparm, localID, val); break;
- case "angulardamping": UpdateParameterPrims(ref m_params[0].angularDamping, lparm, localID, val); break;
- case "deactivationtime": UpdateParameterPrims(ref m_params[0].deactivationTime, lparm, localID, val); break;
- case "linearsleepingthreshold": UpdateParameterPrims(ref m_params[0].linearSleepingThreshold, lparm, localID, val); break;
- case "angularsleepingthreshold": UpdateParameterPrims(ref m_params[0].angularDamping, lparm, localID, val); break;
- case "ccdmotionthreshold": UpdateParameterPrims(ref m_params[0].ccdMotionThreshold, lparm, localID, val); break;
- case "ccdsweptsphereradius": UpdateParameterPrims(ref m_params[0].ccdSweptSphereRadius, lparm, localID, val); break;
- case "contactprocessingthreshold": UpdateParameterPrims(ref m_params[0].contactProcessingThreshold, lparm, localID, val); break;
- // the following are used only at initialization time so setting them makes no sense
- // case "maxPersistantmanifoldpoolSize": m_params[0].maxPersistantManifoldPoolSize = val; break;
- // case "shoulddisablecontactpooldynamicallocation": m_params[0].shouldDisableContactPoolDynamicAllocation = val; break;
- // case "shouldforceupdateallaabbs": m_params[0].shouldForceUpdateAllAabbs = val; break;
- // case "shouldrandomizesolverorder": m_params[0].shouldRandomizeSolverOrder = val; break;
- // case "shouldsplitsimulationislands": m_params[0].shouldSplitSimulationIslands = val; break;
- // case "shouldenablefrictioncaching": m_params[0].shouldEnableFrictionCaching = val; break;
- // case "numberofsolveriterations": m_params[0].numberOfSolverIterations = val; break;
-
- case "friction": TaintedUpdateParameter(lparm, localID, val); break;
- case "restitution": TaintedUpdateParameter(lparm, localID, val); break;
-
- // set a terrain physical feature and cause terrain to be recalculated
- case "terrainfriction": m_params[0].terrainFriction = val; TaintedUpdateParameter("terrain", 0, val); break;
- case "terrainhitfraction": m_params[0].terrainHitFraction = val; TaintedUpdateParameter("terrain", 0, val); break;
- case "terrainrestitution": m_params[0].terrainRestitution = val; TaintedUpdateParameter("terrain", 0, val); break;
- // set an avatar physical feature and cause avatar(s) to be recalculated
- case "avatarfriction": UpdateParameterAvatars(ref m_params[0].avatarFriction, "avatar", localID, val); break;
- case "avatardensity": UpdateParameterAvatars(ref m_params[0].avatarDensity, "avatar", localID, val); break;
- case "avatarrestitution": UpdateParameterAvatars(ref m_params[0].avatarRestitution, "avatar", localID, val); break;
- case "avatarcapsuleradius": UpdateParameterAvatars(ref m_params[0].avatarCapsuleRadius, "avatar", localID, val); break;
- case "avatarcapsuleheight": UpdateParameterAvatars(ref m_params[0].avatarCapsuleHeight, "avatar", localID, val); break;
- case "avatarcontactprocessingthreshold": UpdateParameterAvatars(ref m_params[0].avatarContactProcessingThreshold, "avatar", localID, val); break;
-
- default: ret = false; break;
+ theParam.setter(this, parm, localID, val);
+ ret = true;
}
return ret;
}
// check to see if we are updating a parameter for a particular or all of the prims
- private void UpdateParameterPrims(ref float loc, string parm, uint localID, float val)
+ protected void UpdateParameterPrims(ref float loc, string parm, uint localID, float val)
{
List operateOn;
lock (m_prims) operateOn = new List(m_prims.Keys);
@@ -887,7 +1207,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
}
// check to see if we are updating a parameter for a particular or all of the avatars
- private void UpdateParameterAvatars(ref float loc, string parm, uint localID, float val)
+ protected void UpdateParameterAvatars(ref float loc, string parm, uint localID, float val)
{
List operateOn;
lock (m_avatars) operateOn = new List(m_avatars.Keys);
@@ -898,7 +1218,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// If the local ID is APPLY_TO_NONE, just change the default value
// If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs
// If the localID is a specific object, apply the parameter change to only that object
- private void UpdateParameterSet(List lIDs, ref float defaultLoc, string parm, uint localID, float val)
+ protected void UpdateParameterSet(List lIDs, ref float defaultLoc, string parm, uint localID, float val)
{
switch (localID)
{
@@ -925,7 +1245,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
}
// schedule the actual updating of the paramter to when the phys engine is not busy
- private void TaintedUpdateParameter(string parm, uint localID, float val)
+ protected void TaintedUpdateParameter(string parm, uint localID, float val)
{
uint xlocalID = localID;
string xparm = parm.ToLower();
@@ -940,50 +1260,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
public bool GetPhysicsParameter(string parm, out float value)
{
float val = 0f;
- bool ret = true;
- switch (parm.ToLower())
+ bool ret = false;
+ ParameterDefn theParam;
+ if (TryGetParameter(parm, out theParam))
{
- case "detailedstats": val = (int)m_detailedStatsStep; break;
- case "meshlod": val = (float)m_meshLOD; break;
- case "sculptlod": val = (float)m_sculptLOD; break;
- case "maxsubstep": val = (float)m_maxSubSteps; break;
- case "fixedtimestep": val = m_fixedTimeStep; break;
- case "maxobjectmass": val = m_maximumObjectMass; break;
-
- case "defaultfriction": val = m_params[0].defaultFriction; break;
- case "defaultdensity": val = m_params[0].defaultDensity; break;
- case "defaultrestitution": val = m_params[0].defaultRestitution; break;
- case "collisionmargin": val = m_params[0].collisionMargin; break;
- case "gravity": val = m_params[0].gravity; break;
-
- case "lineardamping": val = m_params[0].linearDamping; break;
- case "angulardamping": val = m_params[0].angularDamping; break;
- case "deactivationtime": val = m_params[0].deactivationTime; break;
- case "linearsleepingthreshold": val = m_params[0].linearSleepingThreshold; break;
- case "angularsleepingthreshold": val = m_params[0].angularDamping; break;
- case "ccdmotionthreshold": val = m_params[0].ccdMotionThreshold; break;
- case "ccdsweptsphereradius": val = m_params[0].ccdSweptSphereRadius; break;
- case "contactprocessingthreshold": val = m_params[0].contactProcessingThreshold; break;
- case "maxPersistantmanifoldpoolSize": val = m_params[0].maxPersistantManifoldPoolSize; break;
- case "shoulddisablecontactpooldynamicallocation": val = m_params[0].shouldDisableContactPoolDynamicAllocation; break;
- case "shouldforceupdateallaabbs": val = m_params[0].shouldForceUpdateAllAabbs; break;
- case "shouldrandomizesolverorder": val = m_params[0].shouldRandomizeSolverOrder; break;
- case "shouldsplitsimulationislands": val = m_params[0].shouldSplitSimulationIslands; break;
- case "shouldenablefrictioncaching": val = m_params[0].shouldEnableFrictionCaching; break;
- case "numberofsolveriterations": val = m_params[0].numberOfSolverIterations; break;
-
- case "terrainfriction": val = m_params[0].terrainFriction; break;
- case "terrainhitfraction": val = m_params[0].terrainHitFraction; break;
- case "terrainrestitution": val = m_params[0].terrainRestitution; break;
-
- case "avatarfriction": val = m_params[0].avatarFriction; break;
- case "avatardensity": val = m_params[0].avatarDensity; break;
- case "avatarrestitution": val = m_params[0].avatarRestitution; break;
- case "avatarcapsuleradius": val = m_params[0].avatarCapsuleRadius; break;
- case "avatarcapsuleheight": val = m_params[0].avatarCapsuleHeight; break;
- case "avatarcontactprocessingthreshold": val = m_params[0].avatarContactProcessingThreshold; break;
- default: ret = false; break;
-
+ val = theParam.getter(this);
+ ret = true;
}
value = val;
return ret;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
index 086f0dc9d7..0ffbc94040 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
@@ -32,6 +32,28 @@ using OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin {
+// Classes to allow some type checking for the API
+public struct BulletSim
+{
+ public BulletSim(uint id, IntPtr xx) { ID = id; Ptr = xx; }
+ public IntPtr Ptr;
+ public uint ID;
+}
+
+public struct BulletBody
+{
+ public BulletBody(uint id, IntPtr xx) { ID = id; Ptr = xx; }
+ public IntPtr Ptr;
+ public uint ID;
+}
+
+public struct BulletConstraint
+{
+ public BulletConstraint(IntPtr xx) { Ptr = xx; }
+ public IntPtr Ptr;
+}
+
+// ===============================================================================
[StructLayout(LayoutKind.Sequential)]
public struct ConvexHull
{
@@ -44,13 +66,14 @@ public struct ShapeData
{
public enum PhysicsShapeType
{
- SHAPE_AVATAR = 0,
- SHAPE_BOX = 1,
- SHAPE_CONE = 2,
- SHAPE_CYLINDER = 3,
- SHAPE_SPHERE = 4,
- SHAPE_MESH = 5,
- SHAPE_HULL = 6
+ SHAPE_UNKNOWN = 0,
+ SHAPE_AVATAR = 1,
+ SHAPE_BOX = 2,
+ SHAPE_CONE = 3,
+ SHAPE_CYLINDER = 4,
+ SHAPE_SPHERE = 5,
+ SHAPE_MESH = 6,
+ SHAPE_HULL = 7
};
public uint ID;
public PhysicsShapeType Type;
@@ -64,12 +87,12 @@ public struct ShapeData
public System.UInt64 MeshKey;
public float Friction;
public float Restitution;
- public int Collidable;
- public int Static; // true if a static object. Otherwise gravity, etc.
+ public float Collidable; // true of things bump into this
+ public float Static; // true if a static object. Otherwise gravity, etc.
- // note that bools are passed as ints since bool size changes by language and architecture
- public const int numericTrue = 1;
- public const int numericFalse = 0;
+ // note that bools are passed as floats since bool size changes by language and architecture
+ public const float numericTrue = 1f;
+ public const float numericFalse = 0f;
}
[StructLayout(LayoutKind.Sequential)]
public struct SweepHit
@@ -142,10 +165,56 @@ public struct ConfigurationParameters
public float shouldEnableFrictionCaching;
public float numberOfSolverIterations;
+ public float linkConstraintUseFrameOffset;
+ public float linkConstraintEnableTransMotor;
+ public float linkConstraintTransMotorMaxVel;
+ public float linkConstraintTransMotorMaxForce;
+ public float linkConstraintERP;
+ public float linkConstraintCFM;
+
public const float numericTrue = 1f;
public const float numericFalse = 0f;
}
+// Values used by Bullet and BulletSim to control collisions
+public enum CollisionFlags : uint
+{
+ STATIC_OBJECT = 1 << 0,
+ KINEMATIC_OBJECT = 1 << 1,
+ NO_CONTACT_RESPONSE = 1 << 2,
+ CUSTOM_MATERIAL_CALLBACK = 1 << 3,
+ CHARACTER_OBJECT = 1 << 4,
+ DISABLE_VISUALIZE_OBJECT = 1 << 5,
+ DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
+ // Following used by BulletSim to control collisions
+ VOLUME_DETECT_OBJECT = 1 << 10,
+ PHANTOM_OBJECT = 1 << 11,
+ PHYSICAL_OBJECT = 1 << 12,
+};
+
+// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0
+// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2.
+public enum ConstraintParams : int
+{
+ BT_CONSTRAINT_ERP = 1, // this one is not used in Bullet as of 20120730
+ BT_CONSTRAINT_STOP_ERP,
+ BT_CONSTRAINT_CFM,
+ BT_CONSTRAINT_STOP_CFM,
+};
+public enum ConstraintParamAxis : int
+{
+ AXIS_LINEAR_X = 0,
+ AXIS_LINEAR_Y,
+ AXIS_LINEAR_Z,
+ AXIS_ANGULAR_X,
+ AXIS_ANGULAR_Y,
+ AXIS_ANGULAR_Z,
+ AXIS_LINEAR_ALL = 20, // these last three added by BulletSim so we don't have to do zillions of calls
+ AXIS_ANGULAR_ALL,
+ AXIS_ALL
+};
+
+// ===============================================================================
static class BulletSimAPI {
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
@@ -195,6 +264,7 @@ public static extern bool DestroyMesh(uint worldID, System.UInt64 meshKey);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool CreateObject(uint worldID, ShapeData shapeData);
+/* Remove old functionality
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void CreateLinkset(uint worldID, int objectCount, ShapeData[] shapeDatas);
@@ -209,10 +279,14 @@ public static extern bool RemoveConstraintByID(uint worldID, uint id1);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool RemoveConstraint(uint worldID, uint id1, uint id2);
+ */
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern Vector3 GetObjectPosition(uint WorldID, uint id);
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern Quaternion GetObjectOrientation(uint WorldID, uint id);
+
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool SetObjectTranslation(uint worldID, uint id, Vector3 position, Quaternion rotation);
@@ -268,5 +342,179 @@ public static extern void DumpBulletStatistics();
public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void SetDebugLogCallback(DebugLogCallback callback);
+
+// ===============================================================================
+// ===============================================================================
+// ===============================================================================
+// A new version of the API that enables moving all the logic out of the C++ code and into
+// the C# code. This will make modifications easier for the next person.
+// This interface passes the actual pointers to the objects in the unmanaged
+// address space. All the management (calls for creation/destruction/lookup)
+// is done in the C# code.
+// The names have a "2" tacked on. This will be removed as the C# code gets rebuilt
+// and the old code is removed.
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr GetSimHandle2(uint worldID);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr GetBodyHandleWorldID2(uint worldID, uint id);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr GetBodyHandle2(IntPtr sim, uint id);
+
+// ===============================================================================
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms,
+ int maxCollisions, IntPtr collisionArray,
+ int maxUpdates, IntPtr updateArray);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool UpdateParameter2(IntPtr sim, uint localID, String parm, float value);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetHeightmap2(IntPtr sim, float[] heightmap);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void Shutdown2(IntPtr sim);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern int PhysicsStep2(IntPtr sim, float timeStep, int maxSubSteps, float fixedTimeStep,
+ out int updatedEntityCount,
+ out IntPtr updatedEntitiesPtr,
+ out int collidersCount,
+ out IntPtr collidersPtr);
+
+/*
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr CreateMesh2(IntPtr sim, int indicesCount, int* indices, int verticesCount, float* vertices );
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool BuildHull2(IntPtr sim, IntPtr mesh);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool ReleaseHull2(IntPtr sim, IntPtr mesh);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool DestroyMesh2(IntPtr sim, IntPtr mesh);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr CreateObject2(IntPtr sim, ShapeData shapeData);
+*/
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr CreateConstraint2(IntPtr sim, IntPtr obj1, IntPtr obj2,
+ Vector3 frame1loc, Quaternion frame1rot,
+ Vector3 frame2loc, Quaternion frame2rot,
+ bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool SetLinearLimits2(IntPtr constrain, Vector3 low, Vector3 hi);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool SetAngularLimits2(IntPtr constrain, Vector3 low, Vector3 hi);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool UseFrameOffset2(IntPtr constrain, float enable);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool TranslationalLimitMotor2(IntPtr constrain, float enable, float targetVel, float maxMotorForce);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool CalculateTransforms2(IntPtr constrain);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool SetConstraintParam2(IntPtr constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool DestroyConstraint2(IntPtr sim, IntPtr constrain);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern Vector3 GetPosition2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern Quaternion GetOrientation2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool SetVelocity2(IntPtr obj, Vector3 velocity);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool SetAngularVelocity2(IntPtr obj, Vector3 angularVelocity);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool SetObjectForce2(IntPtr obj, Vector3 force);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool SetCcdMotionThreshold2(IntPtr obj, float val);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool SetCcdSweepSphereRadius2(IntPtr obj, float val);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool SetDamping2(IntPtr obj, float lin_damping, float ang_damping);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool SetDeactivationTime2(IntPtr obj, float val);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool SetSleepingThresholds2(IntPtr obj, float lin_threshold, float ang_threshold);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool SetContactProcessingThreshold2(IntPtr obj, float val);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool SetFriction2(IntPtr obj, float val);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool SetRestitution2(IntPtr obj, float val);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool SetLinearVelocity2(IntPtr obj, Vector3 val);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool SetInterpolation2(IntPtr obj, Vector3 lin, Vector3 ang);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr SetCollisionFlags2(IntPtr obj, uint flags);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr AddToCollisionFlags2(IntPtr obj, uint flags);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr RemoveFromCollisionFlags2(IntPtr obj, uint flags);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool SetMassProps2(IntPtr obj, float mass, Vector3 inertia);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool UpdateInertiaTensor2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool SetGravity2(IntPtr obj, Vector3 val);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr ClearForces2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool SetMargin2(IntPtr obj, float val);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool UpdateSingleAabb2(IntPtr world, IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool DestroyObject2(IntPtr world, uint id);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void DumpPhysicsStatistics2(IntPtr sim);
+
}
}
diff --git a/OpenSim/Region/Physics/Manager/PhysicsScene.cs b/OpenSim/Region/Physics/Manager/PhysicsScene.cs
index cfede557fc..5274f3b471 100644
--- a/OpenSim/Region/Physics/Manager/PhysicsScene.cs
+++ b/OpenSim/Region/Physics/Manager/PhysicsScene.cs
@@ -71,6 +71,9 @@ namespace OpenSim.Region.Physics.Manager
All = 0x3f
}
+ public delegate void RequestAssetDelegate(UUID assetID, AssetReceivedDelegate callback);
+ public delegate void AssetReceivedDelegate(AssetBase asset);
+
///
/// Contact result from a raycast.
///
@@ -103,6 +106,8 @@ namespace OpenSim.Region.Physics.Manager
get { return new NullPhysicsScene(); }
}
+ public RequestAssetDelegate RequestAssetMethod { private get; set; }
+
public virtual void TriggerPhysicsBasedRestart()
{
physicsCrash handler = OnPhysicsCrash;
diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
index 32e81e2ea1..929b019ecf 100644
--- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
+++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
@@ -290,7 +290,6 @@ namespace OpenSim.Region.Physics.OdePlugin
private readonly IntPtr contactgroup;
- internal IntPtr LandGeom;
internal IntPtr WaterGeom;
private float nmTerrainContactFriction = 255.0f;
@@ -489,6 +488,8 @@ namespace OpenSim.Region.Physics.OdePlugin
///
internal Object OdeLock = new Object();
+ private bool _worldInitialized = false;
+
public IMesher mesher;
private IConfigSource m_config;
@@ -875,6 +876,8 @@ namespace OpenSim.Region.Physics.OdePlugin
staticPrimspace[i, j] = IntPtr.Zero;
}
}
+
+ _worldInitialized = true;
}
// internal void waitForSpaceUnlock(IntPtr space)
@@ -1508,8 +1511,7 @@ namespace OpenSim.Region.Physics.OdePlugin
{
if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f)
&& (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f)
- && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f))
- && contactGeom.g1 != LandGeom && contactGeom.g2 != LandGeom)
+ && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)))
{
if (Math.Abs(contact.depth - contactGeom.depth) < 0.052f)
{
@@ -1538,7 +1540,7 @@ namespace OpenSim.Region.Physics.OdePlugin
//d.GeomGetAABB(contactGeom.g2, out aabb2);
//d.GeomGetAABB(contactGeom.g1, out aabb1);
//aabb1.
- if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)) && contactGeom.g1 != LandGeom && contactGeom.g2 != LandGeom)
+ if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)))
{
if (contactGeom.normal.X == contact.normal.X && contactGeom.normal.Y == contact.normal.Y && contactGeom.normal.Z == contact.normal.Z)
{
@@ -2896,6 +2898,8 @@ namespace OpenSim.Region.Physics.OdePlugin
/// The number of frames simulated over that period.
public override float Simulate(float timeStep)
{
+ if (!_worldInitialized) return 11f;
+
int startFrameTick = CollectStats ? Util.EnvironmentTickCount() : 0;
int tempTick = 0, tempTick2 = 0;
@@ -4017,6 +4021,8 @@ namespace OpenSim.Region.Physics.OdePlugin
public override void Dispose()
{
+ _worldInitialized = false;
+
m_rayCastManager.Dispose();
m_rayCastManager = null;
@@ -4037,6 +4043,7 @@ namespace OpenSim.Region.Physics.OdePlugin
d.WorldDestroy(world);
//d.CloseODE();
}
+
}
public override Dictionary GetTopColliders()
diff --git a/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs b/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs
index 204c4ff5fb..3144d76432 100644
--- a/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs
+++ b/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs
@@ -99,6 +99,8 @@ namespace OpenSim.Region.RegionCombinerModule
public void RemoveRegion(Scene scene)
{
+ lock (m_startingScenes)
+ m_startingScenes.Remove(scene.RegionInfo.originRegionID);
}
public void RegionLoaded(Scene scene)
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs
index 693992afe4..94fd940dc1 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs
@@ -31,6 +31,7 @@ using System.Collections.Generic;
using System.Threading;
using OpenMetaverse;
using OpenSim.Framework;
+using OpenSim.Framework.Monitoring;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.ScriptEngine.Interfaces;
using OpenSim.Region.ScriptEngine.Shared;
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
index cd72dc2d4b..ce1c36470c 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
@@ -6885,22 +6885,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
if (folderID == UUID.Zero)
return;
- byte[] bucket = new byte[1];
- bucket[0] = (byte)AssetType.Folder;
- //byte[] objBytes = folderID.GetBytes();
- //Array.Copy(objBytes, 0, bucket, 1, 16);
-
- GridInstantMessage msg = new GridInstantMessage(World,
- m_host.OwnerID, m_host.Name, destID,
- (byte)InstantMessageDialog.TaskInventoryOffered,
- false, category+". "+m_host.Name+" is located at "+
- World.RegionInfo.RegionName+" "+
- m_host.AbsolutePosition.ToString(),
- folderID, true, m_host.AbsolutePosition,
- bucket);
-
if (m_TransferModule != null)
+ {
+ byte[] bucket = new byte[] { (byte)AssetType.Folder };
+
+ GridInstantMessage msg = new GridInstantMessage(World,
+ m_host.UUID, m_host.Name + ", an object owned by " +
+ resolveName(m_host.OwnerID) + ",", destID,
+ (byte)InstantMessageDialog.TaskInventoryOffered,
+ false, category + "\n" + m_host.Name + " is located at " +
+ World.RegionInfo.RegionName + " " +
+ m_host.AbsolutePosition.ToString(),
+ folderID, true, m_host.AbsolutePosition,
+ bucket);
+
m_TransferModule.SendInstantMessage(msg, delegate(bool success) {});
+ }
}
public void llSetVehicleType(int type)
@@ -11847,7 +11847,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
break;
case ScriptBaseClass.OBJECT_ROT:
{
- Quaternion rot = Quaternion.Identity;
+ Quaternion rot = Quaternion.Identity;
if (obj.ParentGroup.RootPart == obj)
rot = obj.ParentGroup.GroupRotation;
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs
index 4bd3dffd30..7844c75155 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs
@@ -200,24 +200,34 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
for (int i = 0; i < result.Length; i++)
{
if (result[i] is string)
+ {
llist[i] = new LSL_String((string)result[i]);
+ }
else if (result[i] is int)
+ {
llist[i] = new LSL_Integer((int)result[i]);
+ }
else if (result[i] is float)
+ {
llist[i] = new LSL_Float((float)result[i]);
+ }
+ else if (result[i] is UUID)
+ {
+ llist[i] = new LSL_Key(result[i].ToString());
+ }
else if (result[i] is OpenMetaverse.Vector3)
{
OpenMetaverse.Vector3 vresult = (OpenMetaverse.Vector3)result[i];
- llist[i] = new LSL_Vector(vresult.X,vresult.Y,vresult.Z);
+ llist[i] = new LSL_Vector(vresult.X, vresult.Y, vresult.Z);
}
else if (result[i] is OpenMetaverse.Quaternion)
{
OpenMetaverse.Quaternion qresult = (OpenMetaverse.Quaternion)result[i];
- llist[i] = new LSL_Rotation(qresult.X,qresult.Y,qresult.Z,qresult.W);
+ llist[i] = new LSL_Rotation(qresult.X, qresult.Y, qresult.Z, qresult.W);
}
else
{
- MODError(String.Format("unknown list element returned by {0}",fname));
+ MODError(String.Format("unknown list element {1} returned by {0}", fname, result[i].GetType().Name));
}
}
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
index 29d0342d60..1181c105a1 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
@@ -3290,8 +3290,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
((LSL_Api)m_LSL_Api).llSay(0, string.Format("Unable to attach, item '{0}' is not an object.", itemName));
throw new Exception(String.Format("The inventory item '{0}' is not an object", itemName));
-
- return;
}
ScenePresence sp = World.GetScenePresence(avatarId);
@@ -3322,5 +3320,47 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
InitLSL();
((LSL_Api)m_LSL_Api).DetachFromAvatar();
}
+
+ ///
+ /// Checks if thing is a UUID.
+ ///
+ ///
+ /// 1 if thing is a valid UUID, 0 otherwise
+ public LSL_Integer osIsUUID(string thing)
+ {
+ CheckThreatLevel(ThreatLevel.None, "osIsUUID");
+ m_host.AddScriptLPS(1);
+
+ UUID test;
+ return UUID.TryParse(thing, out test) ? 1 : 0;
+ }
+
+ ///
+ /// Wraps to Math.Min()
+ ///
+ ///
+ ///
+ ///
+ public LSL_Float osMin(double a, double b)
+ {
+ CheckThreatLevel(ThreatLevel.None, "osMin");
+ m_host.AddScriptLPS(1);
+
+ return Math.Min(a, b);
+ }
+
+ ///
+ /// Wraps to Math.max()
+ ///
+ ///
+ ///
+ ///
+ public LSL_Float osMax(double a, double b)
+ {
+ CheckThreatLevel(ThreatLevel.None, "osMax");
+ m_host.AddScriptLPS(1);
+
+ return Math.Max(a, b);
+ }
}
}
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs
index 19f3ce191c..678f9d54fe 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs
@@ -51,8 +51,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
{
get
{
- lock (SenseRepeatListLock)
- return SenseRepeaters.Count;
+ return SenseRepeaters.Count;
}
}
@@ -61,8 +60,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
m_CmdManager = CmdManager;
maximumRange = CmdManager.m_ScriptEngine.Config.GetDouble("SensorMaxRange", 96.0d);
maximumToReturn = CmdManager.m_ScriptEngine.Config.GetInt("SensorMaxResults", 16);
+ m_npcModule = m_CmdManager.m_ScriptEngine.World.RequestModuleInterface();
}
+ private INPCModule m_npcModule;
+
private Object SenseLock = new Object();
private const int AGENT = 1;
@@ -115,6 +117,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
public double distance;
}
+ ///
+ /// Sensors to process.
+ ///
+ ///
+ /// Do not add or remove sensors from this list directly. Instead, copy the list and substitute the updated
+ /// copy. This is to avoid locking the list for the duration of the sensor sweep, which increases the danger
+ /// of deadlocks with future code updates.
+ ///
+ /// Always lock SenseRepeatListLock when updating this list.
+ ///
private List SenseRepeaters = new List();
private object SenseRepeatListLock = new object();
@@ -124,6 +136,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
{
// Always remove first, in case this is a re-set
UnSetSenseRepeaterEvents(m_localID, m_itemID);
+
if (sec == 0) // Disabling timer
return;
@@ -143,9 +156,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
ts.host = host;
ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval);
+
+ AddSenseRepeater(ts);
+ }
+
+ private void AddSenseRepeater(SenseRepeatClass senseRepeater)
+ {
lock (SenseRepeatListLock)
{
- SenseRepeaters.Add(ts);
+ List newSenseRepeaters = new List(SenseRepeaters);
+ newSenseRepeaters.Add(senseRepeater);
+ SenseRepeaters = newSenseRepeaters;
}
}
@@ -154,39 +175,32 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
// Remove from timer
lock (SenseRepeatListLock)
{
- List NewSensors = new List();
+ List newSenseRepeaters = new List();
foreach (SenseRepeatClass ts in SenseRepeaters)
{
if (ts.localID != m_localID || ts.itemID != m_itemID)
{
- NewSensors.Add(ts);
+ newSenseRepeaters.Add(ts);
}
}
- SenseRepeaters.Clear();
- SenseRepeaters = NewSensors;
+
+ SenseRepeaters = newSenseRepeaters;
}
}
public void CheckSenseRepeaterEvents()
{
- lock (SenseRepeatListLock)
+ // Go through all timers
+ foreach (SenseRepeatClass ts in SenseRepeaters)
{
- // Nothing to do here?
- if (SenseRepeaters.Count == 0)
- return;
-
- // Go through all timers
- foreach (SenseRepeatClass ts in SenseRepeaters)
+ // Time has passed?
+ if (ts.next.ToUniversalTime() < DateTime.Now.ToUniversalTime())
{
- // Time has passed?
- if (ts.next.ToUniversalTime() < DateTime.Now.ToUniversalTime())
- {
- SensorSweep(ts);
- // set next interval
- ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval);
- }
+ SensorSweep(ts);
+ // set next interval
+ ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval);
}
- } // lock
+ }
}
public void SenseOnce(uint m_localID, UUID m_itemID,
@@ -440,8 +454,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
private List doAgentSensor(SenseRepeatClass ts)
{
- INPCModule npcModule = m_CmdManager.m_ScriptEngine.World.RequestModuleInterface();
-
List sensedEntities = new List();
// If nobody about quit fast
@@ -477,7 +489,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
bool attached = (SensePoint.ParentGroup.AttachmentPoint != 0);
Vector3 toRegionPos;
double dis;
-
+
Action senseEntity = new Action(presence =>
{
// m_log.DebugFormat(
@@ -486,7 +498,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
if ((ts.type & NPC) == 0 && presence.PresenceType == PresenceType.Npc)
{
- INPC npcData = npcModule.GetNPC(presence.UUID, presence.Scene);
+ INPC npcData = m_npcModule.GetNPC(presence.UUID, presence.Scene);
if (npcData == null || !npcData.SenseAsAgent)
{
// m_log.DebugFormat(
@@ -504,7 +516,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
}
else
{
- INPC npcData = npcModule.GetNPC(presence.UUID, presence.Scene);
+ INPC npcData = m_npcModule.GetNPC(presence.UUID, presence.Scene);
if (npcData != null && npcData.SenseAsAgent)
{
// m_log.DebugFormat(
@@ -619,21 +631,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
{
List