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 2c38e0f6a1..87ec99ef60 100644 --- a/OpenSim/Framework/IScene.cs +++ b/OpenSim/Framework/IScene.cs @@ -71,6 +71,14 @@ namespace OpenSim.Framework /// 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 8a0b4ab033..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,7 +1140,7 @@ namespace OpenSim cdt.AddColumn("Endpoint", 23); cdt.AddColumn("Active?", 7); - m_sceneManager.ForEachScene( + SceneManager.ForEachScene( s => s.ForEachClient( c => cdt.AddRow( s.Name, @@ -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..f3781534b7 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); } @@ -980,7 +982,7 @@ namespace OpenSim try { - m_sceneManager.Close(); + SceneManager.Close(); } catch (Exception e) { @@ -1005,7 +1007,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 +1016,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 098e4eb2af..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; diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 86d8f62a46..7042c9a228 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; 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/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/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/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 7ed13206f0..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,7 +144,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage lock (m_scenes) m_scenes[scene.RegionInfo.RegionID] = scene; - scene.EventManager.OnRegionReady += s => UploadMapTile(s); + scene.EventManager.OnRegionReadyStatusChange += s => { if (s.Ready) UploadMapTile(s); }; } /// 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/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/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/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs index 418904f65d..7cb3811483 100644 --- a/OpenSim/Region/Framework/Scenes/EventManager.cs +++ b/OpenSim/Region/Framework/Scenes/EventManager.cs @@ -517,8 +517,7 @@ namespace OpenSim.Region.Framework.Scenes /// A region is considered ready when startup operations such as loading of scripts already on the region /// have been completed. /// - public event RegionReady OnRegionReady; - public delegate void RegionReady(IScene scene); + public event Action OnRegionReadyStatusChange; public delegate void PrimsLoaded(Scene s); public event PrimsLoaded OnPrimsLoaded; @@ -2533,13 +2532,13 @@ namespace OpenSim.Region.Framework.Scenes } } - public void TriggerRegionReady(IScene scene) + public void TriggerRegionReadyStatusChange(IScene scene) { - RegionReady handler = OnRegionReady; + Action handler = OnRegionReadyStatusChange; if (handler != null) { - foreach (RegionReady d in handler.GetInvocationList()) + foreach (Action d in handler.GetInvocationList()) { try { @@ -2547,7 +2546,7 @@ namespace OpenSim.Region.Framework.Scenes } catch (Exception e) { - m_log.ErrorFormat("[EVENT MANAGER]: Delegate for OnRegionReady failed - continuing {0} - {1}", + 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 0bf2259b82..f7d74dbcb7 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; @@ -1232,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); @@ -1255,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); @@ -1553,8 +1565,8 @@ namespace OpenSim.Region.Framework.Scenes m_sceneGridService.InformNeighborsThatRegionisUp( RequestModuleInterface(), RegionInfo); - // Region ready should always be triggered whether logins are immediately enabled or not. - EventManager.TriggerRegionReady(this); + // Region ready should always be set + Ready = true; } else { diff --git a/OpenSim/Region/Framework/Scenes/SceneBase.cs b/OpenSim/Region/Framework/Scenes/SceneBase.cs index d55b08240d..7c8bd8840c 100644 --- a/OpenSim/Region/Framework/Scenes/SceneBase.cs +++ b/OpenSim/Region/Framework/Scenes/SceneBase.cs @@ -124,6 +124,24 @@ namespace OpenSim.Region.Framework.Scenes } 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/SceneManager.cs b/OpenSim/Region/Framework/Scenes/SceneManager.cs index e3fed493c4..a412414275 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.TrueForAll(s => s.Ready); + } + 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/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/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 ca9bd4ad07..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; 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/Scripting/RegionReadyModule/RegionReadyModule.cs b/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs index f459b8c610..fff3a32010 100644 --- a/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs +++ b/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs @@ -225,7 +225,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.RegionReady RRAlert("enabled"); } - m_scene.EventManager.TriggerRegionReady(m_scene); + m_scene.Ready = true; } public void OarLoadingAlert(string msg) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs new file mode 100755 index 0000000000..fbb9e21958 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs @@ -0,0 +1,115 @@ +/* + * 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)); + 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 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..a2650fbd36 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs @@ -0,0 +1,178 @@ +/* + * 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 the way we're using them. + 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; + } + + 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; + } + + 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/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs new file mode 100755 index 0000000000..3bc210084e --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs @@ -0,0 +1,308 @@ +/* + * 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. + // Undo all the physical linking and rebuild the physical linkset. + public bool RefreshLinkset(BSPrim requestor) + { + return true; + } + + + // 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); + 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); + + } + + // 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 a19d6d7f17..7590d936a4 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -66,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; @@ -89,14 +89,22 @@ public sealed class BSPrim : PhysicsActor private bool _kinematic; private float _buoyancy; - private BSPrim _parentPrim; - private List _childrenPrims; + // 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; } } + private BSDynamics _vehicle; private OMV.Vector3 _PIDTarget; @@ -130,14 +138,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(); _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)); }); } @@ -153,16 +165,8 @@ public sealed class BSPrim : PhysicsActor _scene.TaintedObject(delegate() { - // undo any dependance with/on other objects - if (_parentPrim != null) - { - // If I'm someone's child, tell them to forget about me. - _parentPrim.RemoveChildFromLinkset(this); - _parentPrim = null; - } - - // make sure there are no possible children depending on me - UnlinkAllChildren(); + // 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); @@ -179,7 +183,7 @@ public sealed class BSPrim : PhysicsActor _scene.TaintedObject(delegate() { _mass = CalculateMass(); // changing size changes the mass - BulletSimAPI.SetObjectScaleMass(_scene.WorldID, _localID, _scale, Mass, IsPhysical); + BulletSimAPI.SetObjectScaleMass(_scene.WorldID, _localID, _scale, (IsPhysical ? _mass : 0f), IsPhysical); RecreateGeomAndObject(); }); } @@ -218,32 +222,8 @@ public sealed class BSPrim : PhysicsActor BSPrim parent = obj as BSPrim; DebugLog("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, obj.LocalID); DetailLog("{0},link,parent={1}", 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}: link(): Reparenting a prim. ", LogHeader); - } - } - } + + _linkset = _linkset.AddMeToLinkset(this, parent); return; } @@ -252,92 +232,28 @@ public sealed class BSPrim : PhysicsActor // 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 DebugLog("{0}: delink {1}/{2}. Parent={3}", LogHeader, _avName, _localID, - (_parentPrim==null ? "NULL" : _parentPrim._avName+"/"+_parentPrim.LocalID.ToString())); - DetailLog("{0},delink,parent={1}", LocalID, (_parentPrim==null ? "NULL" : _parentPrim.LocalID.ToString())); - if (_parentPrim != null) - { - _parentPrim.RemoveChildFromLinkset(this); - } + _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)) - { - DebugLog("{0}: AddChildToLinkset: adding child {1} to {2}", LogHeader, child.LocalID, this.LocalID); - DetailLog("{0},AddChildToLinkset,child={1}", LocalID, pchild.LocalID); - _childrenPrims.Add(child); - child._parentPrim = this; // the child has gained a parent - // RecreateGeomAndObject(); // rebuild my shape with the new child added - LinkAChildToMe(pchild); // build the physical binding between me and the child - - _mass = CalculateMass(); - } - }); - 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)) - { - DebugLog("{0}: RemoveChildFromLinkset: Removing constraint to {1}", LogHeader, child.LocalID); - DetailLog("{0},RemoveChildFromLinkset,child={1}", LocalID, pchild.LocalID); - _childrenPrims.Remove(child); - child._parentPrim = null; // the child has lost its parent - if (_childrenPrims.Count == 0) - { - // if the linkset is empty, make sure all linkages have been removed - UnlinkAllChildren(); - } - else - { - // RecreateGeomAndObject(); // rebuild my shape with the child removed - UnlinkAChildFromMe(pchild); - } - - _mass = CalculateMass(); - } - else - { - m_log.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset"); - } - }); - return; - } - - // 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. // Called at taint time! - private void ZeroMotion() + public void ZeroMotion() { _velocity = OMV.Vector3.Zero; _acceleration = OMV.Vector3.Zero; _rotationalVelocity = OMV.Vector3.Zero; // Zero some other properties directly into the physics engine - IntPtr obj = BulletSimAPI.GetBodyHandleWorldID2(_scene.WorldID, LocalID); - BulletSimAPI.SetVelocity2(obj, OMV.Vector3.Zero); - BulletSimAPI.SetAngularVelocity2(obj, OMV.Vector3.Zero); - BulletSimAPI.SetInterpolation2(obj, OMV.Vector3.Zero, OMV.Vector3.Zero); - BulletSimAPI.ClearForces2(obj); + 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) @@ -348,9 +264,10 @@ public sealed class BSPrim : PhysicsActor public override OMV.Vector3 Position { get { - // child prims move around based on their parent. Need to get the latest location - if (_parentPrim != null) + 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; @@ -366,16 +283,31 @@ public sealed class BSPrim : PhysicsActor } } - // Return the effective mass of the object. Non-physical objects do not have mass. - public override float Mass { - get { - if (IsPhysical) - return _mass; - else - return 0f; + // 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 { @@ -383,7 +315,8 @@ public sealed class BSPrim : PhysicsActor _scene.TaintedObject(delegate() { DetailLog("{0},SetForce,taint,force={1}", LocalID, _force); - BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force); + // BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force); + BulletSimAPI.SetObjectForce2(Body.Ptr, _force); }); } } @@ -407,8 +340,7 @@ public sealed class BSPrim : PhysicsActor _scene.TaintedObject(delegate() { // Tell the physics engine to clear state - IntPtr obj = BulletSimAPI.GetBodyHandleWorldID2(_scene.WorldID, LocalID); - BulletSimAPI.ClearForces2(obj); + BulletSimAPI.ClearForces2(this.Body.Ptr); }); // make it so the scene will call us each tick to do vehicle things @@ -420,7 +352,6 @@ public sealed class BSPrim : PhysicsActor } public override void VehicleFloatParam(int param, float value) { - m_log.DebugFormat("{0} VehicleFloatParam. {1} <= {2}", LogHeader, param, value); _scene.TaintedObject(delegate() { _vehicle.ProcessFloatVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep); @@ -428,7 +359,6 @@ public sealed class BSPrim : PhysicsActor } public override void VehicleVectorParam(int param, OMV.Vector3 value) { - m_log.DebugFormat("{0} VehicleVectorParam. {1} <= {2}", LogHeader, param, value); _scene.TaintedObject(delegate() { _vehicle.ProcessVectorVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep); @@ -436,7 +366,6 @@ public sealed class BSPrim : PhysicsActor } public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { - m_log.DebugFormat("{0} VehicleRotationParam. {1} <= {2}", LogHeader, param, rotation); _scene.TaintedObject(delegate() { _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); @@ -444,7 +373,6 @@ public sealed class BSPrim : PhysicsActor } public override void VehicleFlags(int param, bool remove) { - m_log.DebugFormat("{0} VehicleFlags. {1}. Remove={2}", LogHeader, param, remove); _scene.TaintedObject(delegate() { _vehicle.ProcessVehicleFlags(param, remove); @@ -470,8 +398,6 @@ public sealed class BSPrim : PhysicsActor 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 { @@ -500,9 +426,9 @@ public sealed class BSPrim : PhysicsActor } public override OMV.Quaternion Orientation { get { - if (_parentPrim != null) + if (!_linkset.IsRoot(this)) { - // children move around because tied to parent. Get a fresh value. + // Children move around because tied to parent. Get a fresh value. _orientation = BulletSimAPI.GetObjectOrientation(_scene.WorldID, LocalID); } return _orientation; @@ -552,14 +478,16 @@ public sealed class BSPrim : PhysicsActor 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 = CalculateMass(); - RecreateGeomAndObject(); - } - DetailLog("{0},SetObjectDynamic,taint,static={1},solid={2},mass={3}", LocalID, IsStatic, IsSolid, Mass); - BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), Mass); + + RecreateGeomAndObject(); + + 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 @@ -1001,6 +929,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) @@ -1008,6 +939,7 @@ public sealed class BSPrim : PhysicsActor returnMass += prim.CalculateMass(); } } + */ if (returnMass <= 0) returnMass = 0.0001f; @@ -1023,9 +955,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) @@ -1033,18 +967,26 @@ 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; - DetailLog("{0},CreateGeom,sphere", LocalID); - // Bullet native objects are scaled by the Bullet engine so pass the size in - _scale = _size; + if (_shapeType != ShapeData.PhysicsShapeType.SHAPE_SPHERE) + { + DetailLog("{0},CreateGeom,sphere", LocalID); + _shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE; + ret = true; + // Bullet native objects are scaled by the Bullet engine so pass the size in + _scale = _size; + } } } else { // m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, size={2}", LogHeader, LocalID, _size); - DetailLog("{0},CreateGeom,box", LocalID); - _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX; - _scale = _size; + if (_shapeType != ShapeData.PhysicsShapeType.SHAPE_BOX) + { + DetailLog("{0},CreateGeom,box", LocalID); + _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX; + ret = true; + _scale = _size; + } } } else @@ -1056,6 +998,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 @@ -1064,9 +1007,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 @@ -1251,20 +1196,18 @@ public sealed class BSPrim : PhysicsActor // No locking here because this is done when the physics engine is not simulating private void CreateObject() { - if (IsRootOfLinkset) - { - // Create a linkset around this object - CreateLinkset(); - } - 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. + + // 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); + // the CreateObject() may have recreated the rigid body. Make sure we have the latest. + m_body.Ptr = BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID); + + // The root object could have been recreated. Make sure everything linksety is up to date. + _linkset.RefreshLinkset(this); } // Copy prim's info into the BulletSim shape description structure @@ -1276,7 +1219,7 @@ public sealed class BSPrim : PhysicsActor shape.Rotation = _orientation; shape.Velocity = _velocity; shape.Scale = _scale; - shape.Mass = Mass; + shape.Mass = _isPhysical ? _mass : 0f; shape.Buoyancy = _buoyancy; shape.HullKey = _hullKey; shape.MeshKey = _meshKey; @@ -1286,72 +1229,6 @@ public sealed class BSPrim : PhysicsActor shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue; } - #region Linkset creation and destruction - - // Create the linkset by putting constraints between the objects of the set so they cannot move - // relative to each other. - void CreateLinkset() - { - DebugLog("{0}: CreateLinkset. Root prim={1}, prims={2}", LogHeader, LocalID, _childrenPrims.Count+1); - - // remove any constraints that might be in place - DebugLog("{0}: CreateLinkset: RemoveConstraints between me and any children", LogHeader, LocalID); - BulletSimAPI.RemoveConstraintByID(_scene.WorldID, LocalID); - - // create constraints between the root prim and each of the children - foreach (BSPrim prim in _childrenPrims) - { - LinkAChildToMe(prim); - } - } - - // Create a constraint between me (root of linkset) and the passed prim (the child). - // Called at taint time! - private void LinkAChildToMe(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(this._orientation); - OMV.Vector3 childRelativePosition = (childPrim._position - this._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}", LocalID, LocalID, childPrim.LocalID); - BulletSimAPI.AddConstraint(_scene.WorldID, LocalID, childPrim.LocalID, - childRelativePosition, - childRelativeRotation, - OMV.Vector3.Zero, - OMV.Quaternion.Identity, - OMV.Vector3.Zero, OMV.Vector3.Zero, - OMV.Vector3.Zero, OMV.Vector3.Zero); - } - - // Remove linkage between myself and a particular child - // Called at taint time! - private void UnlinkAChildFromMe(BSPrim childPrim) - { - DebugLog("{0}: UnlinkAChildFromMe: RemoveConstraint between root prim {1} and child prim {2}", - LogHeader, LocalID, childPrim.LocalID); - DetailLog("{0},UnlinkAChildFromMe,taint,root={1},child={2}", LocalID, LocalID, childPrim.LocalID); - BulletSimAPI.RemoveConstraint(_scene.WorldID, LocalID, childPrim.LocalID); - } - - // Remove linkage between myself and any possible children I might have - // Called at taint time! - private void UnlinkAllChildren() - { - DebugLog("{0}: UnlinkAllChildren:", LogHeader); - DetailLog("{0},UnlinkAllChildren,taint", LocalID); - BulletSimAPI.RemoveConstraintByID(_scene.WorldID, LocalID); - } - - #endregion // Linkset creation and destruction // Rebuild the geometry and object. // This is called when the shape changes so we need to recreate the mesh/hull. @@ -1429,7 +1306,7 @@ public sealed class BSPrim : PhysicsActor // 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 (_parentPrim == null) + if (_linkset.IsRoot(this)) { // Assign to the local variables so the normal set action does not happen _position = entprop.Position; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 7cc3fe3ca5..c6d622b621 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -73,7 +73,7 @@ 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]"; - private void DebugLog(string mm, params Object[] xx) { if (shouldDebugLog) m_log.DebugFormat(mm, xx); } + public void DebugLog(string mm, params Object[] xx) { if (shouldDebugLog) m_log.DebugFormat(mm, xx); } public string BulletSimVersion = "?"; @@ -87,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; @@ -103,6 +106,17 @@ 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; @@ -229,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; } @@ -237,116 +256,17 @@ 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; - - shouldDebugLog = false; - m_detailedStatsStep = 0; // disabled - - m_maxSubSteps = 10; - m_fixedTimeStep = 1f / 60f; - m_maxCollisionsPerFrame = 2048; - m_maxUpdatesPerFrame = 2048; - m_maximumObjectMass = 10000.01f; - - PID_D = 2200f; - PID_P = 900f; - - 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); - - shouldDebugLog = pConfig.GetBoolean("ShouldDebugLog", shouldDebugLog); - 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); - - PID_D = pConfig.GetFloat("PIDDerivative", PID_D); - PID_P = pConfig.GetFloat("PIDProportional", PID_P); - - 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); + SetParameterConfigurationValues(pConfig); // Very detailed logging for physics debugging m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false); @@ -357,7 +277,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters 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 @@ -634,6 +553,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters // 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(); @@ -776,10 +701,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; @@ -853,61 +780,371 @@ 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. + // 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 + // + // To add a new variable, it is best to find an existing definition and copy it. + 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("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; } @@ -919,63 +1156,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); @@ -983,7 +1175,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); @@ -994,7 +1186,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) { @@ -1021,7 +1213,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(); @@ -1036,50 +1228,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 54a8cfde27..65e3145698 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 { @@ -142,6 +164,11 @@ public struct ConfigurationParameters public float shouldEnableFrictionCaching; public float numberOfSolverIterations; + public float linkConstraintUseFrameOffset; + public float linkConstraintEnableTransMotor; + public float linkConstraintTransMotorMaxVel; + public float linkConstraintTransMotorMaxForce; + public const float numericTrue = 1f; public const float numericFalse = 0f; } @@ -162,6 +189,7 @@ public enum CollisionFlags : uint PHYSICAL_OBJECT = 1 << 12, }; +// =============================================================================== static class BulletSimAPI { [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] @@ -211,6 +239,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); @@ -225,6 +254,7 @@ 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); @@ -350,8 +380,22 @@ 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, - Vector3 lowLinear, Vector3 hiLinear, Vector3 lowAngular, Vector3 hiAngular); + Vector3 frame2loc, Quaternion frame2rot); + +[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 DestroyConstraint2(IntPtr sim, IntPtr constrain); 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/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index bf77dc5c1a..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); @@ -3336,5 +3334,33 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api 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/Interface/IOSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs index 24bdf0cfc8..aba66d32b2 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs @@ -283,5 +283,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces /// /// 1 if thing is a valid UUID, 0 otherwise LSL_Integer osIsUUID(string thing); + + /// + /// Wraps to Math.Min() + /// + /// + /// + /// + LSL_Float osMin(double a, double b); + + /// + /// Wraps to Math.max() + /// + /// + /// + /// + LSL_Float osMax(double a, double b); } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs index 99995a7171..53daa13d49 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs @@ -935,5 +935,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase { return m_OSSL_Functions.osIsUUID(thing); } + + public LSL_Float osMin(double a, double b) + { + return m_OSSL_Functions.osMin(a, b); + } + + public LSL_Float osMax(double a, double b) + { + return m_OSSL_Functions.osMax(a, b); + } } } diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index 79a6e0951e..f6cb7dfa95 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs @@ -719,7 +719,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine // If region ready has been triggered, then the region had no scripts to compile and completed its other // work. - m_Scene.EventManager.OnRegionReady += s => m_InitialStartup = false; + m_Scene.EventManager.OnRegionReadyStatusChange += s => { if (s.Ready) m_InitialStartup = false; }; if (m_SleepTime > 0) { diff --git a/OpenSim/Region/UserStatistics/ActiveConnectionsAJAX.cs b/OpenSim/Region/UserStatistics/ActiveConnectionsAJAX.cs index dcbd7173d9..3243a9a952 100644 --- a/OpenSim/Region/UserStatistics/ActiveConnectionsAJAX.cs +++ b/OpenSim/Region/UserStatistics/ActiveConnectionsAJAX.cs @@ -34,7 +34,7 @@ using Mono.Data.SqliteClient; using OpenMetaverse; using OpenSim.Framework; using OpenSim.Region.Framework.Scenes; -using OpenSim.Framework.Statistics; +using OpenSim.Framework.Monitoring; namespace OpenSim.Region.UserStatistics { diff --git a/OpenSim/Region/UserStatistics/Default_Report.cs b/OpenSim/Region/UserStatistics/Default_Report.cs index 0e1763046d..cdc615caff 100644 --- a/OpenSim/Region/UserStatistics/Default_Report.cs +++ b/OpenSim/Region/UserStatistics/Default_Report.cs @@ -33,7 +33,7 @@ using System.Text; using Mono.Data.SqliteClient; using OpenMetaverse; using OpenSim.Region.Framework.Scenes; -using OpenSim.Framework.Statistics; +using OpenSim.Framework.Monitoring; namespace OpenSim.Region.UserStatistics diff --git a/OpenSim/Region/UserStatistics/LogLinesAJAX.cs b/OpenSim/Region/UserStatistics/LogLinesAJAX.cs index 811baba998..74de46b227 100644 --- a/OpenSim/Region/UserStatistics/LogLinesAJAX.cs +++ b/OpenSim/Region/UserStatistics/LogLinesAJAX.cs @@ -34,7 +34,7 @@ using System.Text.RegularExpressions; using Mono.Data.SqliteClient; using OpenMetaverse; using OpenSim.Region.Framework.Scenes; -using OpenSim.Framework.Statistics; +using OpenSim.Framework.Monitoring; namespace OpenSim.Region.UserStatistics { diff --git a/OpenSim/Region/UserStatistics/SimStatsAJAX.cs b/OpenSim/Region/UserStatistics/SimStatsAJAX.cs index 8c04e71a61..28051fb674 100644 --- a/OpenSim/Region/UserStatistics/SimStatsAJAX.cs +++ b/OpenSim/Region/UserStatistics/SimStatsAJAX.cs @@ -33,7 +33,7 @@ using System.Text; using Mono.Data.SqliteClient; using OpenMetaverse; using OpenSim.Region.Framework.Scenes; -using OpenSim.Framework.Statistics; +using OpenSim.Framework.Monitoring; namespace OpenSim.Region.UserStatistics { diff --git a/bin/Ionic.Zip.dll b/bin/Ionic.Zip.dll old mode 100644 new mode 100755 diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 6d699fd505..80d17d9da1 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -914,6 +914,12 @@ ShouldEnableFrictionCaching = False; NumberOfSolverIterations = 0; + ; Linkset constraint parameters + LinkConstraintUseFrameOffset = False; + LinkConstraintEnableTransMotor = True; + LinkConstraintTransMotorMaxVel = 5.0; + LinkConstraintTransMotorMaxForce = 0.1; + ; Whether to mesh sculpties MeshSculptedPrim = true @@ -931,7 +937,7 @@ FixedTimeStep = .01667 MaxCollisionsPerFrame = 2048 - MaxUpdatesPerFrame = 2048 + MaxUpdatesPerFrame = 8192 [RemoteAdmin] enabled = false diff --git a/bin/lib32/BulletSim.dll b/bin/lib32/BulletSim.dll index 322322a701..c6bb76af7f 100755 Binary files a/bin/lib32/BulletSim.dll and b/bin/lib32/BulletSim.dll differ diff --git a/bin/lib32/libBulletSim.so b/bin/lib32/libBulletSim.so index 493c8cbc84..6ca98cc8fe 100755 Binary files a/bin/lib32/libBulletSim.so and b/bin/lib32/libBulletSim.so differ diff --git a/bin/lib64/BulletSim.dll b/bin/lib64/BulletSim.dll index 2bd13b8644..0924dd01da 100755 Binary files a/bin/lib64/BulletSim.dll and b/bin/lib64/BulletSim.dll differ diff --git a/bin/lib64/libBulletSim.so b/bin/lib64/libBulletSim.so index af3a078bfe..70bcdb7983 100755 Binary files a/bin/lib64/libBulletSim.so and b/bin/lib64/libBulletSim.so differ diff --git a/prebuild.xml b/prebuild.xml index 52a91c3111..469ca99b95 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -112,7 +112,37 @@ +<<<<<<< HEAD:prebuild.xml +======= + + + + ../../../bin/ + + + + + ../../../bin/ + + + + ../../../bin/ + + + + + + + + + + + + + + +>>>>>>> master:prebuild.xml ../../../../bin/ @@ -130,6 +160,7 @@ + @@ -235,6 +266,7 @@ +<<<<<<< HEAD:prebuild.xml @@ -260,6 +292,9 @@ +======= + +>>>>>>> master:prebuild.xml ../../bin/ @@ -436,7 +471,7 @@ - + @@ -720,9 +755,9 @@ + - @@ -754,13 +789,13 @@ + - + + - - @@ -806,10 +841,10 @@ + - @@ -1525,10 +1560,10 @@ + - @@ -1616,11 +1651,11 @@ + + - - @@ -1653,15 +1688,15 @@ - - + + - + @@ -1744,9 +1779,9 @@ + - @@ -1882,15 +1917,15 @@ + - + - - + @@ -2403,10 +2438,11 @@ + + - @@ -2529,8 +2565,12 @@ +<<<<<<< HEAD:prebuild.xml +======= + +>>>>>>> master:prebuild.xml ../../../bin/ @@ -2558,9 +2598,9 @@ + - @@ -3044,9 +3084,9 @@ + - @@ -3116,9 +3156,9 @@ + - @@ -3175,8 +3215,8 @@ + - @@ -3232,9 +3272,9 @@ + - @@ -3269,7 +3309,7 @@ - + diff --git a/runprebuild.sh b/runprebuild.sh index b3b5c9d1d3..d276edbee4 100755 --- a/runprebuild.sh +++ b/runprebuild.sh @@ -1,4 +1,42 @@ #!/bin/sh -mono bin/Prebuild.exe /target nant -mono bin/Prebuild.exe /target vs2008 +case "$1" in + + 'clean') + + mono bin/Prebuild.exe /clean + + ;; + + + 'autoclean') + + echo y|mono bin/Prebuild.exe /clean + + ;; + + + 'vs2010') + + mono bin/Prebuild.exe /target vs2010 + + ;; + + + 'vs2008') + + mono bin/Prebuild.exe /target vs2008 + + ;; + + + *) + + mono bin/Prebuild.exe /target nant + mono bin/Prebuild.exe /target vs2008 + + ;; + + +esac +