Merge branch 'master' of /home/opensim/var/repo/opensim
commit
2602a48738
|
@ -28,6 +28,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
@ -138,7 +139,7 @@ namespace OpenSim
|
||||||
m_log.Info("====================================================================");
|
m_log.Info("====================================================================");
|
||||||
m_log.Info("========================= STARTING OPENSIM =========================");
|
m_log.Info("========================= STARTING OPENSIM =========================");
|
||||||
m_log.Info("====================================================================");
|
m_log.Info("====================================================================");
|
||||||
|
|
||||||
//m_log.InfoFormat("[OPENSIM MAIN]: GC Is Server GC: {0}", GCSettings.IsServerGC.ToString());
|
//m_log.InfoFormat("[OPENSIM MAIN]: GC Is Server GC: {0}", GCSettings.IsServerGC.ToString());
|
||||||
// http://msdn.microsoft.com/en-us/library/bb384202.aspx
|
// http://msdn.microsoft.com/en-us/library/bb384202.aspx
|
||||||
//GCSettings.LatencyMode = GCLatencyMode.Batch;
|
//GCSettings.LatencyMode = GCLatencyMode.Batch;
|
||||||
|
|
|
@ -0,0 +1,189 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Contributors, http://opensimulator.org/
|
||||||
|
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the OpenSimulator Project nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using log4net;
|
||||||
|
using Mono.Addins;
|
||||||
|
using NDesk.Options;
|
||||||
|
using Nini.Config;
|
||||||
|
using OpenMetaverse;
|
||||||
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Framework.Console;
|
||||||
|
using OpenSim.Framework.Statistics;
|
||||||
|
using OpenSim.Region.Framework.Interfaces;
|
||||||
|
using OpenSim.Region.Framework.Scenes;
|
||||||
|
|
||||||
|
namespace OpenSim.Region.CoreModules.Avatars.Commands
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A module that holds commands for manipulating objects in the scene.
|
||||||
|
/// </summary>
|
||||||
|
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UserCommandsModule")]
|
||||||
|
public class UserCommandsModule : ISharedRegionModule
|
||||||
|
{
|
||||||
|
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
|
public const string TeleportUserCommandSyntax = "teleport user <first-name> <last-name> <destination>";
|
||||||
|
|
||||||
|
public static Regex InterRegionDestinationRegex
|
||||||
|
= new Regex(@"^(?<regionName>.+)/(?<x>\d+)/(?<y>\d+)/(?<z>\d+)$", RegexOptions.Compiled);
|
||||||
|
|
||||||
|
public static Regex WithinRegionDestinationRegex
|
||||||
|
= new Regex(@"^(?<x>\d+)/(?<y>\d+)/(?<z>\d+)$", RegexOptions.Compiled);
|
||||||
|
|
||||||
|
private Dictionary<UUID, Scene> m_scenes = new Dictionary<UUID, Scene>();
|
||||||
|
|
||||||
|
public string Name { get { return "User Commands Module"; } }
|
||||||
|
|
||||||
|
public Type ReplaceableInterface { get { return null; } }
|
||||||
|
|
||||||
|
public void Initialise(IConfigSource source)
|
||||||
|
{
|
||||||
|
// m_log.DebugFormat("[USER COMMANDS MODULE]: INITIALIZED MODULE");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PostInitialise()
|
||||||
|
{
|
||||||
|
// m_log.DebugFormat("[USER COMMANDS MODULE]: POST INITIALIZED MODULE");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Close()
|
||||||
|
{
|
||||||
|
// m_log.DebugFormat("[USER COMMANDS MODULE]: CLOSED MODULE");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddRegion(Scene scene)
|
||||||
|
{
|
||||||
|
// m_log.DebugFormat("[USER COMMANDS MODULE]: REGION {0} ADDED", scene.RegionInfo.RegionName);
|
||||||
|
|
||||||
|
lock (m_scenes)
|
||||||
|
m_scenes[scene.RegionInfo.RegionID] = scene;
|
||||||
|
|
||||||
|
scene.AddCommand(
|
||||||
|
"Users",
|
||||||
|
this,
|
||||||
|
"teleport user",
|
||||||
|
TeleportUserCommandSyntax,
|
||||||
|
"Teleport a user in this simulator to the given destination",
|
||||||
|
"<destination> is in format [<region-name>]/<x>/<y>/<z>, e.g. regionone/20/30/40 or just 20/30/40 to teleport within same region."
|
||||||
|
+ "\nIf the region contains a space then the whole destination must be in quotes, e.g. \"region one/20/30/40\"",
|
||||||
|
HandleTeleportUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveRegion(Scene scene)
|
||||||
|
{
|
||||||
|
// m_log.DebugFormat("[USER COMMANDS MODULE]: REGION {0} REMOVED", scene.RegionInfo.RegionName);
|
||||||
|
|
||||||
|
lock (m_scenes)
|
||||||
|
m_scenes.Remove(scene.RegionInfo.RegionID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RegionLoaded(Scene scene)
|
||||||
|
{
|
||||||
|
// m_log.DebugFormat("[USER COMMANDS MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ScenePresence GetUser(string firstName, string lastName)
|
||||||
|
{
|
||||||
|
ScenePresence userFound = null;
|
||||||
|
|
||||||
|
lock (m_scenes)
|
||||||
|
{
|
||||||
|
foreach (Scene scene in m_scenes.Values)
|
||||||
|
{
|
||||||
|
ScenePresence user = scene.GetScenePresence(firstName, lastName);
|
||||||
|
if (user != null && !user.IsChildAgent)
|
||||||
|
{
|
||||||
|
userFound = user;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return userFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleTeleportUser(string module, string[] cmd)
|
||||||
|
{
|
||||||
|
if (cmd.Length < 5)
|
||||||
|
{
|
||||||
|
MainConsole.Instance.OutputFormat("Usage: " + TeleportUserCommandSyntax);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string firstName = cmd[2];
|
||||||
|
string lastName = cmd[3];
|
||||||
|
string rawDestination = cmd[4];
|
||||||
|
|
||||||
|
ScenePresence user = GetUser(firstName, lastName);
|
||||||
|
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
MainConsole.Instance.OutputFormat("No user found with name {0} {1}", firstName, lastName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// MainConsole.Instance.OutputFormat("rawDestination [{0}]", rawDestination);
|
||||||
|
|
||||||
|
Match m = WithinRegionDestinationRegex.Match(rawDestination);
|
||||||
|
|
||||||
|
if (!m.Success)
|
||||||
|
{
|
||||||
|
m = InterRegionDestinationRegex.Match(rawDestination);
|
||||||
|
|
||||||
|
if (!m.Success)
|
||||||
|
{
|
||||||
|
MainConsole.Instance.OutputFormat("Invalid destination {0}", rawDestination);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string regionName
|
||||||
|
= m.Groups["regionName"].Success ? m.Groups["regionName"].Value : user.Scene.RegionInfo.RegionName;
|
||||||
|
|
||||||
|
MainConsole.Instance.OutputFormat(
|
||||||
|
"Teleporting {0} to {1},{2},{3} in {4}",
|
||||||
|
user.Name,
|
||||||
|
m.Groups["x"], m.Groups["y"], m.Groups["z"],
|
||||||
|
regionName);
|
||||||
|
|
||||||
|
user.Scene.RequestTeleportLocation(
|
||||||
|
user.ControllingClient,
|
||||||
|
regionName,
|
||||||
|
new Vector3(
|
||||||
|
float.Parse(m.Groups["x"].Value),
|
||||||
|
float.Parse(m.Groups["y"].Value),
|
||||||
|
float.Parse(m.Groups["z"].Value)),
|
||||||
|
user.Lookat,
|
||||||
|
(uint)TeleportFlags.ViaLocation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -49,7 +49,16 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
|
||||||
public bool Enabled { get; private set; }
|
public bool Enabled { get; private set; }
|
||||||
|
|
||||||
private Scene m_scene;
|
private Scene m_scene;
|
||||||
private readonly List<IMonitor> m_monitors = new List<IMonitor>();
|
|
||||||
|
/// <summary>
|
||||||
|
/// These are monitors where we know the static details in advance.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Dynamic monitors also exist (we don't know any of the details of what stats we get back here)
|
||||||
|
/// but these are currently hardcoded.
|
||||||
|
/// </remarks>
|
||||||
|
private readonly List<IMonitor> m_staticMonitors = new List<IMonitor>();
|
||||||
|
|
||||||
private readonly List<IAlert> m_alerts = new List<IAlert>();
|
private readonly List<IAlert> m_alerts = new List<IAlert>();
|
||||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
|
@ -84,9 +93,18 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
|
||||||
|
|
||||||
public void DebugMonitors(string module, string[] args)
|
public void DebugMonitors(string module, string[] args)
|
||||||
{
|
{
|
||||||
foreach (IMonitor monitor in m_monitors)
|
foreach (IMonitor monitor in m_staticMonitors)
|
||||||
{
|
{
|
||||||
m_log.Info("[MonitorModule]: " + m_scene.RegionInfo.RegionName + " reports " + monitor.GetFriendlyName() + " = " + monitor.GetFriendlyValue());
|
m_log.InfoFormat(
|
||||||
|
"[MONITOR MODULE]: {0} reports {1} = {2}",
|
||||||
|
m_scene.RegionInfo.RegionName, monitor.GetFriendlyName(), monitor.GetFriendlyValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (KeyValuePair<string, float> tuple in m_scene.StatsReporter.GetExtraSimStats())
|
||||||
|
{
|
||||||
|
m_log.InfoFormat(
|
||||||
|
"[MONITOR MODULE]: {0} reports {1} = {2}",
|
||||||
|
m_scene.RegionInfo.RegionName, tuple.Key, tuple.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,11 +124,12 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
|
||||||
{
|
{
|
||||||
string monID = (string) request["monitor"];
|
string monID = (string) request["monitor"];
|
||||||
|
|
||||||
foreach (IMonitor monitor in m_monitors)
|
foreach (IMonitor monitor in m_staticMonitors)
|
||||||
{
|
{
|
||||||
string elemName = monitor.ToString();
|
string elemName = monitor.ToString();
|
||||||
if (elemName.StartsWith(monitor.GetType().Namespace))
|
if (elemName.StartsWith(monitor.GetType().Namespace))
|
||||||
elemName = elemName.Substring(monitor.GetType().Namespace.Length + 1);
|
elemName = elemName.Substring(monitor.GetType().Namespace.Length + 1);
|
||||||
|
|
||||||
if (elemName == monID || monitor.ToString() == monID)
|
if (elemName == monID || monitor.ToString() == monID)
|
||||||
{
|
{
|
||||||
Hashtable ereply3 = new Hashtable();
|
Hashtable ereply3 = new Hashtable();
|
||||||
|
@ -123,6 +142,9 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: Arguably this should also be done with dynamic monitors but I'm not sure what the above code
|
||||||
|
// is even doing. Why are we inspecting the type of the monitor???
|
||||||
|
|
||||||
// No monitor with that name
|
// No monitor with that name
|
||||||
Hashtable ereply2 = new Hashtable();
|
Hashtable ereply2 = new Hashtable();
|
||||||
|
|
||||||
|
@ -134,12 +156,18 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
|
||||||
}
|
}
|
||||||
|
|
||||||
string xml = "<data>";
|
string xml = "<data>";
|
||||||
foreach (IMonitor monitor in m_monitors)
|
foreach (IMonitor monitor in m_staticMonitors)
|
||||||
{
|
{
|
||||||
string elemName = monitor.GetName();
|
string elemName = monitor.GetName();
|
||||||
xml += "<" + elemName + ">" + monitor.GetValue().ToString() + "</" + elemName + ">";
|
xml += "<" + elemName + ">" + monitor.GetValue().ToString() + "</" + elemName + ">";
|
||||||
// m_log.DebugFormat("[MONITOR MODULE]: {0} = {1}", elemName, monitor.GetValue());
|
// m_log.DebugFormat("[MONITOR MODULE]: {0} = {1}", elemName, monitor.GetValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (KeyValuePair<string, float> tuple in m_scene.StatsReporter.GetExtraSimStats())
|
||||||
|
{
|
||||||
|
xml += "<" + tuple.Key + ">" + tuple.Value + "</" + tuple.Key + ">";
|
||||||
|
}
|
||||||
|
|
||||||
xml += "</data>";
|
xml += "</data>";
|
||||||
|
|
||||||
Hashtable ereply = new Hashtable();
|
Hashtable ereply = new Hashtable();
|
||||||
|
@ -156,20 +184,20 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
|
||||||
if (!Enabled)
|
if (!Enabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_monitors.Add(new AgentCountMonitor(m_scene));
|
m_staticMonitors.Add(new AgentCountMonitor(m_scene));
|
||||||
m_monitors.Add(new ChildAgentCountMonitor(m_scene));
|
m_staticMonitors.Add(new ChildAgentCountMonitor(m_scene));
|
||||||
m_monitors.Add(new GCMemoryMonitor());
|
m_staticMonitors.Add(new GCMemoryMonitor());
|
||||||
m_monitors.Add(new ObjectCountMonitor(m_scene));
|
m_staticMonitors.Add(new ObjectCountMonitor(m_scene));
|
||||||
m_monitors.Add(new PhysicsFrameMonitor(m_scene));
|
m_staticMonitors.Add(new PhysicsFrameMonitor(m_scene));
|
||||||
m_monitors.Add(new PhysicsUpdateFrameMonitor(m_scene));
|
m_staticMonitors.Add(new PhysicsUpdateFrameMonitor(m_scene));
|
||||||
m_monitors.Add(new PWSMemoryMonitor());
|
m_staticMonitors.Add(new PWSMemoryMonitor());
|
||||||
m_monitors.Add(new ThreadCountMonitor());
|
m_staticMonitors.Add(new ThreadCountMonitor());
|
||||||
m_monitors.Add(new TotalFrameMonitor(m_scene));
|
m_staticMonitors.Add(new TotalFrameMonitor(m_scene));
|
||||||
m_monitors.Add(new EventFrameMonitor(m_scene));
|
m_staticMonitors.Add(new EventFrameMonitor(m_scene));
|
||||||
m_monitors.Add(new LandFrameMonitor(m_scene));
|
m_staticMonitors.Add(new LandFrameMonitor(m_scene));
|
||||||
m_monitors.Add(new LastFrameTimeMonitor(m_scene));
|
m_staticMonitors.Add(new LastFrameTimeMonitor(m_scene));
|
||||||
|
|
||||||
m_monitors.Add(
|
m_staticMonitors.Add(
|
||||||
new GenericMonitor(
|
new GenericMonitor(
|
||||||
m_scene,
|
m_scene,
|
||||||
"TimeDilationMonitor",
|
"TimeDilationMonitor",
|
||||||
|
@ -177,7 +205,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
|
||||||
m => m.Scene.StatsReporter.LastReportedSimStats[0],
|
m => m.Scene.StatsReporter.LastReportedSimStats[0],
|
||||||
m => m.GetValue().ToString()));
|
m => m.GetValue().ToString()));
|
||||||
|
|
||||||
m_monitors.Add(
|
m_staticMonitors.Add(
|
||||||
new GenericMonitor(
|
new GenericMonitor(
|
||||||
m_scene,
|
m_scene,
|
||||||
"SimFPSMonitor",
|
"SimFPSMonitor",
|
||||||
|
@ -185,7 +213,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
|
||||||
m => m.Scene.StatsReporter.LastReportedSimStats[1],
|
m => m.Scene.StatsReporter.LastReportedSimStats[1],
|
||||||
m => string.Format("{0}", m.GetValue())));
|
m => string.Format("{0}", m.GetValue())));
|
||||||
|
|
||||||
m_monitors.Add(
|
m_staticMonitors.Add(
|
||||||
new GenericMonitor(
|
new GenericMonitor(
|
||||||
m_scene,
|
m_scene,
|
||||||
"PhysicsFPSMonitor",
|
"PhysicsFPSMonitor",
|
||||||
|
@ -193,7 +221,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
|
||||||
m => m.Scene.StatsReporter.LastReportedSimStats[2],
|
m => m.Scene.StatsReporter.LastReportedSimStats[2],
|
||||||
m => string.Format("{0}", m.GetValue())));
|
m => string.Format("{0}", m.GetValue())));
|
||||||
|
|
||||||
m_monitors.Add(
|
m_staticMonitors.Add(
|
||||||
new GenericMonitor(
|
new GenericMonitor(
|
||||||
m_scene,
|
m_scene,
|
||||||
"AgentUpdatesPerSecondMonitor",
|
"AgentUpdatesPerSecondMonitor",
|
||||||
|
@ -201,15 +229,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
|
||||||
m => m.Scene.StatsReporter.LastReportedSimStats[3],
|
m => m.Scene.StatsReporter.LastReportedSimStats[3],
|
||||||
m => string.Format("{0} per second", m.GetValue())));
|
m => string.Format("{0} per second", m.GetValue())));
|
||||||
|
|
||||||
m_monitors.Add(
|
m_staticMonitors.Add(
|
||||||
new GenericMonitor(
|
|
||||||
m_scene,
|
|
||||||
"ObjectUpdatesPerSecondMonitor",
|
|
||||||
"Object Updates",
|
|
||||||
m => m.Scene.StatsReporter.LastReportedObjectUpdates,
|
|
||||||
m => string.Format("{0} per second", m.GetValue())));
|
|
||||||
|
|
||||||
m_monitors.Add(
|
|
||||||
new GenericMonitor(
|
new GenericMonitor(
|
||||||
m_scene,
|
m_scene,
|
||||||
"ActiveObjectCountMonitor",
|
"ActiveObjectCountMonitor",
|
||||||
|
@ -217,7 +237,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
|
||||||
m => m.Scene.StatsReporter.LastReportedSimStats[7],
|
m => m.Scene.StatsReporter.LastReportedSimStats[7],
|
||||||
m => string.Format("{0}", m.GetValue())));
|
m => string.Format("{0}", m.GetValue())));
|
||||||
|
|
||||||
m_monitors.Add(
|
m_staticMonitors.Add(
|
||||||
new GenericMonitor(
|
new GenericMonitor(
|
||||||
m_scene,
|
m_scene,
|
||||||
"ActiveScriptsMonitor",
|
"ActiveScriptsMonitor",
|
||||||
|
@ -225,7 +245,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
|
||||||
m => m.Scene.StatsReporter.LastReportedSimStats[19],
|
m => m.Scene.StatsReporter.LastReportedSimStats[19],
|
||||||
m => string.Format("{0}", m.GetValue())));
|
m => string.Format("{0}", m.GetValue())));
|
||||||
|
|
||||||
m_monitors.Add(
|
m_staticMonitors.Add(
|
||||||
new GenericMonitor(
|
new GenericMonitor(
|
||||||
m_scene,
|
m_scene,
|
||||||
"ScriptEventsPerSecondMonitor",
|
"ScriptEventsPerSecondMonitor",
|
||||||
|
@ -233,7 +253,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
|
||||||
m => m.Scene.StatsReporter.LastReportedSimStats[20],
|
m => m.Scene.StatsReporter.LastReportedSimStats[20],
|
||||||
m => string.Format("{0} per second", m.GetValue())));
|
m => string.Format("{0} per second", m.GetValue())));
|
||||||
|
|
||||||
m_monitors.Add(
|
m_staticMonitors.Add(
|
||||||
new GenericMonitor(
|
new GenericMonitor(
|
||||||
m_scene,
|
m_scene,
|
||||||
"InPacketsPerSecondMonitor",
|
"InPacketsPerSecondMonitor",
|
||||||
|
@ -241,7 +261,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
|
||||||
m => m.Scene.StatsReporter.LastReportedSimStats[13],
|
m => m.Scene.StatsReporter.LastReportedSimStats[13],
|
||||||
m => string.Format("{0} per second", m.GetValue())));
|
m => string.Format("{0} per second", m.GetValue())));
|
||||||
|
|
||||||
m_monitors.Add(
|
m_staticMonitors.Add(
|
||||||
new GenericMonitor(
|
new GenericMonitor(
|
||||||
m_scene,
|
m_scene,
|
||||||
"OutPacketsPerSecondMonitor",
|
"OutPacketsPerSecondMonitor",
|
||||||
|
@ -249,7 +269,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
|
||||||
m => m.Scene.StatsReporter.LastReportedSimStats[14],
|
m => m.Scene.StatsReporter.LastReportedSimStats[14],
|
||||||
m => string.Format("{0} per second", m.GetValue())));
|
m => string.Format("{0} per second", m.GetValue())));
|
||||||
|
|
||||||
m_monitors.Add(
|
m_staticMonitors.Add(
|
||||||
new GenericMonitor(
|
new GenericMonitor(
|
||||||
m_scene,
|
m_scene,
|
||||||
"UnackedBytesMonitor",
|
"UnackedBytesMonitor",
|
||||||
|
@ -257,7 +277,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
|
||||||
m => m.Scene.StatsReporter.LastReportedSimStats[15],
|
m => m.Scene.StatsReporter.LastReportedSimStats[15],
|
||||||
m => string.Format("{0}", m.GetValue())));
|
m => string.Format("{0}", m.GetValue())));
|
||||||
|
|
||||||
m_monitors.Add(
|
m_staticMonitors.Add(
|
||||||
new GenericMonitor(
|
new GenericMonitor(
|
||||||
m_scene,
|
m_scene,
|
||||||
"PendingDownloadsMonitor",
|
"PendingDownloadsMonitor",
|
||||||
|
@ -265,7 +285,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
|
||||||
m => m.Scene.StatsReporter.LastReportedSimStats[17],
|
m => m.Scene.StatsReporter.LastReportedSimStats[17],
|
||||||
m => string.Format("{0}", m.GetValue())));
|
m => string.Format("{0}", m.GetValue())));
|
||||||
|
|
||||||
m_monitors.Add(
|
m_staticMonitors.Add(
|
||||||
new GenericMonitor(
|
new GenericMonitor(
|
||||||
m_scene,
|
m_scene,
|
||||||
"PendingUploadsMonitor",
|
"PendingUploadsMonitor",
|
||||||
|
@ -273,7 +293,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
|
||||||
m => m.Scene.StatsReporter.LastReportedSimStats[18],
|
m => m.Scene.StatsReporter.LastReportedSimStats[18],
|
||||||
m => string.Format("{0}", m.GetValue())));
|
m => string.Format("{0}", m.GetValue())));
|
||||||
|
|
||||||
m_monitors.Add(
|
m_staticMonitors.Add(
|
||||||
new GenericMonitor(
|
new GenericMonitor(
|
||||||
m_scene,
|
m_scene,
|
||||||
"TotalFrameTimeMonitor",
|
"TotalFrameTimeMonitor",
|
||||||
|
@ -281,7 +301,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
|
||||||
m => m.Scene.StatsReporter.LastReportedSimStats[8],
|
m => m.Scene.StatsReporter.LastReportedSimStats[8],
|
||||||
m => string.Format("{0} ms", m.GetValue())));
|
m => string.Format("{0} ms", m.GetValue())));
|
||||||
|
|
||||||
m_monitors.Add(
|
m_staticMonitors.Add(
|
||||||
new GenericMonitor(
|
new GenericMonitor(
|
||||||
m_scene,
|
m_scene,
|
||||||
"NetFrameTimeMonitor",
|
"NetFrameTimeMonitor",
|
||||||
|
@ -289,7 +309,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
|
||||||
m => m.Scene.StatsReporter.LastReportedSimStats[9],
|
m => m.Scene.StatsReporter.LastReportedSimStats[9],
|
||||||
m => string.Format("{0} ms", m.GetValue())));
|
m => string.Format("{0} ms", m.GetValue())));
|
||||||
|
|
||||||
m_monitors.Add(
|
m_staticMonitors.Add(
|
||||||
new GenericMonitor(
|
new GenericMonitor(
|
||||||
m_scene,
|
m_scene,
|
||||||
"PhysicsFrameTimeMonitor",
|
"PhysicsFrameTimeMonitor",
|
||||||
|
@ -297,7 +317,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
|
||||||
m => m.Scene.StatsReporter.LastReportedSimStats[10],
|
m => m.Scene.StatsReporter.LastReportedSimStats[10],
|
||||||
m => string.Format("{0} ms", m.GetValue())));
|
m => string.Format("{0} ms", m.GetValue())));
|
||||||
|
|
||||||
m_monitors.Add(
|
m_staticMonitors.Add(
|
||||||
new GenericMonitor(
|
new GenericMonitor(
|
||||||
m_scene,
|
m_scene,
|
||||||
"SimulationFrameTimeMonitor",
|
"SimulationFrameTimeMonitor",
|
||||||
|
@ -305,7 +325,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
|
||||||
m => m.Scene.StatsReporter.LastReportedSimStats[12],
|
m => m.Scene.StatsReporter.LastReportedSimStats[12],
|
||||||
m => string.Format("{0} ms", m.GetValue())));
|
m => string.Format("{0} ms", m.GetValue())));
|
||||||
|
|
||||||
m_monitors.Add(
|
m_staticMonitors.Add(
|
||||||
new GenericMonitor(
|
new GenericMonitor(
|
||||||
m_scene,
|
m_scene,
|
||||||
"AgentFrameTimeMonitor",
|
"AgentFrameTimeMonitor",
|
||||||
|
@ -313,7 +333,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
|
||||||
m => m.Scene.StatsReporter.LastReportedSimStats[16],
|
m => m.Scene.StatsReporter.LastReportedSimStats[16],
|
||||||
m => string.Format("{0} ms", m.GetValue())));
|
m => string.Format("{0} ms", m.GetValue())));
|
||||||
|
|
||||||
m_monitors.Add(
|
m_staticMonitors.Add(
|
||||||
new GenericMonitor(
|
new GenericMonitor(
|
||||||
m_scene,
|
m_scene,
|
||||||
"ImagesFrameTimeMonitor",
|
"ImagesFrameTimeMonitor",
|
||||||
|
@ -321,7 +341,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
|
||||||
m => m.Scene.StatsReporter.LastReportedSimStats[11],
|
m => m.Scene.StatsReporter.LastReportedSimStats[11],
|
||||||
m => string.Format("{0} ms", m.GetValue())));
|
m => string.Format("{0} ms", m.GetValue())));
|
||||||
|
|
||||||
m_alerts.Add(new DeadlockAlert(m_monitors.Find(x => x is LastFrameTimeMonitor) as LastFrameTimeMonitor));
|
m_alerts.Add(new DeadlockAlert(m_staticMonitors.Find(x => x is LastFrameTimeMonitor) as LastFrameTimeMonitor));
|
||||||
|
|
||||||
foreach (IAlert alert in m_alerts)
|
foreach (IAlert alert in m_alerts)
|
||||||
{
|
{
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
//using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Timers;
|
using System.Timers;
|
||||||
using OpenMetaverse.Packets;
|
using OpenMetaverse.Packets;
|
||||||
using OpenSim.Framework;
|
using OpenSim.Framework;
|
||||||
|
@ -35,10 +35,18 @@ using OpenSim.Region.Framework.Interfaces;
|
||||||
|
|
||||||
namespace OpenSim.Region.Framework.Scenes
|
namespace OpenSim.Region.Framework.Scenes
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Collect statistics from the scene to send to the client and for access by other monitoring tools.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// FIXME: This should be a monitoring region module
|
||||||
|
/// </remarks>
|
||||||
public class SimStatsReporter
|
public class SimStatsReporter
|
||||||
{
|
{
|
||||||
// private static readonly log4net.ILog m_log
|
private static readonly log4net.ILog m_log
|
||||||
// = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
= log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
|
public const string LastReportedObjectUpdateStatName = "LastReportedObjectUpdates";
|
||||||
|
|
||||||
public delegate void SendStatResult(SimStats stats);
|
public delegate void SendStatResult(SimStats stats);
|
||||||
|
|
||||||
|
@ -100,6 +108,14 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
get { return lastReportedSimStats; }
|
get { return lastReportedSimStats; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extra sim statistics that are used by monitors but not sent to the client.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// The keys are the stat names.
|
||||||
|
/// </value>
|
||||||
|
private Dictionary<string, float> m_lastReportedExtraSimStats = new Dictionary<string, float>();
|
||||||
|
|
||||||
// Sending a stats update every 3 seconds-
|
// Sending a stats update every 3 seconds-
|
||||||
private int statsUpdatesEveryMS = 3000;
|
private int statsUpdatesEveryMS = 3000;
|
||||||
private float statsUpdateFactor = 0;
|
private float statsUpdateFactor = 0;
|
||||||
|
@ -334,7 +350,20 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extra statistics that aren't currently sent to clients
|
// Extra statistics that aren't currently sent to clients
|
||||||
LastReportedObjectUpdates = m_objectUpdates / statsUpdateFactor;
|
lock (m_lastReportedExtraSimStats)
|
||||||
|
{
|
||||||
|
m_lastReportedExtraSimStats[LastReportedObjectUpdateStatName] = m_objectUpdates / statsUpdateFactor;
|
||||||
|
|
||||||
|
Dictionary<string, float> physicsStats = m_scene.PhysicsScene.GetStats();
|
||||||
|
|
||||||
|
if (physicsStats != null)
|
||||||
|
{
|
||||||
|
foreach (KeyValuePair<string, float> tuple in physicsStats)
|
||||||
|
{
|
||||||
|
m_lastReportedExtraSimStats[tuple.Key] = tuple.Value / statsUpdateFactor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
resetvalues();
|
resetvalues();
|
||||||
}
|
}
|
||||||
|
@ -487,7 +516,10 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
public void AddPendingDownloads(int count)
|
public void AddPendingDownloads(int count)
|
||||||
{
|
{
|
||||||
m_pendingDownloads += count;
|
m_pendingDownloads += count;
|
||||||
if (m_pendingDownloads < 0) m_pendingDownloads = 0;
|
|
||||||
|
if (m_pendingDownloads < 0)
|
||||||
|
m_pendingDownloads = 0;
|
||||||
|
|
||||||
//m_log.InfoFormat("[stats]: Adding {0} to pending downloads to make {1}", count, m_pendingDownloads);
|
//m_log.InfoFormat("[stats]: Adding {0} to pending downloads to make {1}", count, m_pendingDownloads);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -509,5 +541,11 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
public Dictionary<string, float> GetExtraSimStats()
|
||||||
|
{
|
||||||
|
lock (m_lastReportedExtraSimStats)
|
||||||
|
return new Dictionary<string, float>(m_lastReportedExtraSimStats);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,8 +192,22 @@ namespace OpenSim.Region.Physics.Manager
|
||||||
|
|
||||||
public abstract void AddPhysicsActorTaint(PhysicsActor prim);
|
public abstract void AddPhysicsActorTaint(PhysicsActor prim);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Perform a simulation of the current physics scene over the given timestep.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="timeStep"></param>
|
||||||
|
/// <returns>The number of frames simulated over that period.</returns>
|
||||||
public abstract float Simulate(float timeStep);
|
public abstract float Simulate(float timeStep);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get statistics about this scene.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>This facility is currently experimental and subject to change.</remarks>
|
||||||
|
/// <returns>
|
||||||
|
/// A dictionary where the key is the statistic name. If no statistics are supplied then returns null.
|
||||||
|
/// </returns>
|
||||||
|
public virtual Dictionary<string, float> GetStats() { return null; }
|
||||||
|
|
||||||
public abstract void GetResults();
|
public abstract void GetResults();
|
||||||
|
|
||||||
public abstract void SetTerrain(float[] heightMap);
|
public abstract void SetTerrain(float[] heightMap);
|
||||||
|
|
|
@ -30,20 +30,21 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.IO;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using log4net;
|
using log4net;
|
||||||
using Nini.Config;
|
using Nini.Config;
|
||||||
using Ode.NET;
|
using Ode.NET;
|
||||||
|
using OpenMetaverse;
|
||||||
#if USE_DRAWSTUFF
|
#if USE_DRAWSTUFF
|
||||||
using Drawstuff.NET;
|
using Drawstuff.NET;
|
||||||
#endif
|
#endif
|
||||||
using OpenSim.Framework;
|
using OpenSim.Framework;
|
||||||
using OpenSim.Region.Physics.Manager;
|
using OpenSim.Region.Physics.Manager;
|
||||||
using OpenMetaverse;
|
|
||||||
|
|
||||||
namespace OpenSim.Region.Physics.OdePlugin
|
namespace OpenSim.Region.Physics.OdePlugin
|
||||||
{
|
{
|
||||||
|
@ -54,15 +55,15 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
End = 2
|
End = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct sCollisionData
|
// public struct sCollisionData
|
||||||
{
|
// {
|
||||||
public uint ColliderLocalId;
|
// public uint ColliderLocalId;
|
||||||
public uint CollidedWithLocalId;
|
// public uint CollidedWithLocalId;
|
||||||
public int NumberOfCollisions;
|
// public int NumberOfCollisions;
|
||||||
public int CollisionType;
|
// public int CollisionType;
|
||||||
public int StatusIndicator;
|
// public int StatusIndicator;
|
||||||
public int lastframe;
|
// public int lastframe;
|
||||||
}
|
// }
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
public enum CollisionCategories : int
|
public enum CollisionCategories : int
|
||||||
|
@ -131,6 +132,80 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
internal static Object UniversalColliderSyncObject = new Object();
|
internal static Object UniversalColliderSyncObject = new Object();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Is stats collecting enabled for this ODE scene?
|
||||||
|
/// </summary>
|
||||||
|
public bool CollectStats { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Statistics for this scene.
|
||||||
|
/// </summary>
|
||||||
|
private Dictionary<string, float> m_stats = new Dictionary<string, float>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stat name for the total time spent in ODE frame processing.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// A sanity check for the main scene loop physics time.
|
||||||
|
/// </remarks>
|
||||||
|
public const string ODETotalFrameMsStatName = "ODETotalFrameMS";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The amount of time spent in native code that actually steps through the simulation.
|
||||||
|
/// </summary>
|
||||||
|
public const string ODENativeStepFrameMsStatName = "ODENativeStepFrameMS";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stat name for recording the number of milliseconds that ODE spends in native collision code.
|
||||||
|
/// </summary>
|
||||||
|
public const string ODENativeCollisionFrameMsStatName = "ODENativeCollisionFrameMS";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stat name for recording the number of milliseconds that ODE spends in native space collision code.
|
||||||
|
/// </summary>
|
||||||
|
public const string ODENativeSpaceCollisionFrameMsStatName = "ODENativeSpaceCollisionFrameMS";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stat name for recording the number of milliseconds that ODE spends in native geom collision code.
|
||||||
|
/// </summary>
|
||||||
|
public const string ODENativeGeomCollisionFrameMsStatName = "ODENativeGeomCollisionFrameMS";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stat name for the number of avatar collisions with another entity.
|
||||||
|
/// </summary>
|
||||||
|
public const string ODEAvatarContactsStatsName = "ODEAvatarContacts";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stat name for the number of prim collisions with another entity.
|
||||||
|
/// </summary>
|
||||||
|
public const string ODEPrimContactsStatName = "ODEPrimContacts";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used to hold tick numbers for stat collection purposes.
|
||||||
|
/// </summary>
|
||||||
|
private int m_nativeCollisionStartTick;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A messy way to tell if we need to avoid adding a collision time because this was already done in the callback.
|
||||||
|
/// </summary>
|
||||||
|
private bool m_inCollisionTiming;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A temporary holder for the number of avatar collisions in a frame, so we can work out how many object
|
||||||
|
/// collisions occured using the _perloopcontact if stats collection is enabled.
|
||||||
|
/// </summary>
|
||||||
|
private int m_tempAvatarCollisionsThisFrame;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used in calculating physics frame time dilation
|
||||||
|
/// </summary>
|
||||||
|
private int tickCountFrameRun;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used in calculating physics frame time dilation
|
||||||
|
/// </summary>
|
||||||
|
private int latertickcount;
|
||||||
|
|
||||||
private Random fluidRandomizer = new Random(Environment.TickCount);
|
private Random fluidRandomizer = new Random(Environment.TickCount);
|
||||||
|
|
||||||
private const uint m_regionWidth = Constants.RegionSize;
|
private const uint m_regionWidth = Constants.RegionSize;
|
||||||
|
@ -345,9 +420,6 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
private OdePrim cp1;
|
private OdePrim cp1;
|
||||||
private OdeCharacter cc2;
|
private OdeCharacter cc2;
|
||||||
private OdePrim cp2;
|
private OdePrim cp2;
|
||||||
private int tickCountFrameRun;
|
|
||||||
|
|
||||||
private int latertickcount=0;
|
|
||||||
//private int cStartStop = 0;
|
//private int cStartStop = 0;
|
||||||
//private string cDictKey = "";
|
//private string cDictKey = "";
|
||||||
|
|
||||||
|
@ -440,6 +512,8 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
// Initialize the mesh plugin
|
// Initialize the mesh plugin
|
||||||
public override void Initialise(IMesher meshmerizer, IConfigSource config)
|
public override void Initialise(IMesher meshmerizer, IConfigSource config)
|
||||||
{
|
{
|
||||||
|
InitializeExtraStats();
|
||||||
|
|
||||||
mesher = meshmerizer;
|
mesher = meshmerizer;
|
||||||
m_config = config;
|
m_config = config;
|
||||||
// Defaults
|
// Defaults
|
||||||
|
@ -464,6 +538,8 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
IConfig physicsconfig = m_config.Configs["ODEPhysicsSettings"];
|
IConfig physicsconfig = m_config.Configs["ODEPhysicsSettings"];
|
||||||
if (physicsconfig != null)
|
if (physicsconfig != null)
|
||||||
{
|
{
|
||||||
|
CollectStats = physicsconfig.GetBoolean("collect_stats", false);
|
||||||
|
|
||||||
gravityx = physicsconfig.GetFloat("world_gravityx", 0f);
|
gravityx = physicsconfig.GetFloat("world_gravityx", 0f);
|
||||||
gravityy = physicsconfig.GetFloat("world_gravityy", 0f);
|
gravityy = physicsconfig.GetFloat("world_gravityy", 0f);
|
||||||
gravityz = physicsconfig.GetFloat("world_gravityz", -9.8f);
|
gravityz = physicsconfig.GetFloat("world_gravityz", -9.8f);
|
||||||
|
@ -764,6 +840,62 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
|
|
||||||
#region Collision Detection
|
#region Collision Detection
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Collides two geometries.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <param name='geom1'></param>
|
||||||
|
/// <param name='geom2'>/param>
|
||||||
|
/// <param name='maxContacts'></param>
|
||||||
|
/// <param name='contactsArray'></param>
|
||||||
|
/// <param name='contactGeomSize'></param>
|
||||||
|
private int CollideGeoms(
|
||||||
|
IntPtr geom1, IntPtr geom2, int maxContacts, Ode.NET.d.ContactGeom[] contactsArray, int contactGeomSize)
|
||||||
|
{
|
||||||
|
int count;
|
||||||
|
|
||||||
|
lock (OdeScene.UniversalColliderSyncObject)
|
||||||
|
{
|
||||||
|
// We do this inside the lock so that we don't count any delay in acquiring it
|
||||||
|
if (CollectStats)
|
||||||
|
m_nativeCollisionStartTick = Util.EnvironmentTickCount();
|
||||||
|
|
||||||
|
count = d.Collide(geom1, geom2, maxContacts, contactsArray, contactGeomSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We do this outside the lock so that any waiting threads aren't held up, though the effect is probably
|
||||||
|
// negligable
|
||||||
|
if (CollectStats)
|
||||||
|
m_stats[ODENativeGeomCollisionFrameMsStatName]
|
||||||
|
+= Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Collide two spaces or a space and a geometry.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name='space1'></param>
|
||||||
|
/// <param name='space2'>/param>
|
||||||
|
/// <param name='data'></param>
|
||||||
|
private void CollideSpaces(IntPtr space1, IntPtr space2, IntPtr data)
|
||||||
|
{
|
||||||
|
if (CollectStats)
|
||||||
|
{
|
||||||
|
m_inCollisionTiming = true;
|
||||||
|
m_nativeCollisionStartTick = Util.EnvironmentTickCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SpaceCollide2(space1, space2, data, nearCallback);
|
||||||
|
|
||||||
|
if (CollectStats && m_inCollisionTiming)
|
||||||
|
{
|
||||||
|
m_stats[ODENativeSpaceCollisionFrameMsStatName]
|
||||||
|
+= Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick);
|
||||||
|
m_inCollisionTiming = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This is our near callback. A geometry is near a body
|
/// This is our near callback. A geometry is near a body
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -772,6 +904,13 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
/// <param name="g2">another geometry or space</param>
|
/// <param name="g2">another geometry or space</param>
|
||||||
private void near(IntPtr space, IntPtr g1, IntPtr g2)
|
private void near(IntPtr space, IntPtr g1, IntPtr g2)
|
||||||
{
|
{
|
||||||
|
if (CollectStats && m_inCollisionTiming)
|
||||||
|
{
|
||||||
|
m_stats[ODENativeSpaceCollisionFrameMsStatName]
|
||||||
|
+= Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick);
|
||||||
|
m_inCollisionTiming = false;
|
||||||
|
}
|
||||||
|
|
||||||
// m_log.DebugFormat("[PHYSICS]: Colliding {0} and {1} in {2}", g1, g2, space);
|
// m_log.DebugFormat("[PHYSICS]: Colliding {0} and {1} in {2}", g1, g2, space);
|
||||||
// no lock here! It's invoked from within Simulate(), which is thread-locked
|
// no lock here! It's invoked from within Simulate(), which is thread-locked
|
||||||
|
|
||||||
|
@ -789,7 +928,7 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
// contact points in the space
|
// contact points in the space
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback);
|
CollideSpaces(g1, g2, IntPtr.Zero);
|
||||||
}
|
}
|
||||||
catch (AccessViolationException)
|
catch (AccessViolationException)
|
||||||
{
|
{
|
||||||
|
@ -832,6 +971,7 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
|
|
||||||
// Figure out how many contact points we have
|
// Figure out how many contact points we have
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Colliding Geom To Geom
|
// Colliding Geom To Geom
|
||||||
|
@ -843,8 +983,7 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact))
|
if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
lock (OdeScene.UniversalColliderSyncObject)
|
count = CollideGeoms(g1, g2, contacts.Length, contacts, d.ContactGeom.SizeOf);
|
||||||
count = d.Collide(g1, g2, contacts.Length, contacts, d.ContactGeom.SizeOf);
|
|
||||||
|
|
||||||
if (count > contacts.Length)
|
if (count > contacts.Length)
|
||||||
m_log.Error("[ODE SCENE]: Got " + count + " contacts when we asked for a maximum of " + contacts.Length);
|
m_log.Error("[ODE SCENE]: Got " + count + " contacts when we asked for a maximum of " + contacts.Length);
|
||||||
|
@ -1113,14 +1252,12 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
{
|
{
|
||||||
_perloopContact.Add(curContact);
|
_perloopContact.Add(curContact);
|
||||||
|
|
||||||
// If we're colliding against terrain
|
|
||||||
if (name1 == "Terrain" || name2 == "Terrain")
|
if (name1 == "Terrain" || name2 == "Terrain")
|
||||||
{
|
{
|
||||||
// If we're moving
|
|
||||||
if ((p2.PhysicsActorType == (int) ActorTypes.Agent) &&
|
if ((p2.PhysicsActorType == (int) ActorTypes.Agent) &&
|
||||||
(Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
|
(Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
|
||||||
{
|
{
|
||||||
// Use the movement terrain contact
|
// Avatar is moving on terrain, use the movement terrain contact
|
||||||
AvatarMovementTerrainContact.geom = curContact;
|
AvatarMovementTerrainContact.geom = curContact;
|
||||||
|
|
||||||
if (m_global_contactcount < maxContactsbeforedeath)
|
if (m_global_contactcount < maxContactsbeforedeath)
|
||||||
|
@ -1133,7 +1270,7 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
{
|
{
|
||||||
if (p2.PhysicsActorType == (int)ActorTypes.Agent)
|
if (p2.PhysicsActorType == (int)ActorTypes.Agent)
|
||||||
{
|
{
|
||||||
// Use the non moving terrain contact
|
// Avatar is standing on terrain, use the non moving terrain contact
|
||||||
TerrainContact.geom = curContact;
|
TerrainContact.geom = curContact;
|
||||||
|
|
||||||
if (m_global_contactcount < maxContactsbeforedeath)
|
if (m_global_contactcount < maxContactsbeforedeath)
|
||||||
|
@ -1228,13 +1365,11 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// we're colliding with prim or avatar
|
|
||||||
// check if we're moving
|
|
||||||
if ((p2.PhysicsActorType == (int)ActorTypes.Agent))
|
if ((p2.PhysicsActorType == (int)ActorTypes.Agent))
|
||||||
{
|
{
|
||||||
if ((Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
|
if ((Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
|
||||||
{
|
{
|
||||||
// Use the Movement prim contact
|
// Avatar is moving on a prim, use the Movement prim contact
|
||||||
AvatarMovementprimContact.geom = curContact;
|
AvatarMovementprimContact.geom = curContact;
|
||||||
|
|
||||||
if (m_global_contactcount < maxContactsbeforedeath)
|
if (m_global_contactcount < maxContactsbeforedeath)
|
||||||
|
@ -1245,9 +1380,8 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Use the non movement contact
|
// Avatar is standing still on a prim, use the non movement contact
|
||||||
contact.geom = curContact;
|
contact.geom = curContact;
|
||||||
_perloopContact.Add(curContact);
|
|
||||||
|
|
||||||
if (m_global_contactcount < maxContactsbeforedeath)
|
if (m_global_contactcount < maxContactsbeforedeath)
|
||||||
{
|
{
|
||||||
|
@ -1355,7 +1489,7 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
|
//m_log.DebugFormat("[Collision]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
|
||||||
//m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z));
|
//m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1578,7 +1712,7 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
// and we'll run it again on all of them.
|
// and we'll run it again on all of them.
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
d.SpaceCollide2(space, chr.Shell, IntPtr.Zero, nearCallback);
|
CollideSpaces(space, chr.Shell, IntPtr.Zero);
|
||||||
}
|
}
|
||||||
catch (AccessViolationException)
|
catch (AccessViolationException)
|
||||||
{
|
{
|
||||||
|
@ -1593,6 +1727,12 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (CollectStats)
|
||||||
|
{
|
||||||
|
m_tempAvatarCollisionsThisFrame = _perloopContact.Count;
|
||||||
|
m_stats[ODEAvatarContactsStatsName] += m_tempAvatarCollisionsThisFrame;
|
||||||
|
}
|
||||||
|
|
||||||
List<OdePrim> removeprims = null;
|
List<OdePrim> removeprims = null;
|
||||||
foreach (OdePrim chr in _activeprims)
|
foreach (OdePrim chr in _activeprims)
|
||||||
{
|
{
|
||||||
|
@ -1604,7 +1744,7 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
{
|
{
|
||||||
if (space != IntPtr.Zero && chr.prim_geom != IntPtr.Zero && chr.m_taintremove == false)
|
if (space != IntPtr.Zero && chr.prim_geom != IntPtr.Zero && chr.m_taintremove == false)
|
||||||
{
|
{
|
||||||
d.SpaceCollide2(space, chr.prim_geom, IntPtr.Zero, nearCallback);
|
CollideSpaces(space, chr.prim_geom, IntPtr.Zero);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1625,6 +1765,9 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (CollectStats)
|
||||||
|
m_stats[ODEPrimContactsStatName] += _perloopContact.Count - m_tempAvatarCollisionsThisFrame;
|
||||||
|
|
||||||
if (removeprims != null)
|
if (removeprims != null)
|
||||||
{
|
{
|
||||||
foreach (OdePrim chr in removeprims)
|
foreach (OdePrim chr in removeprims)
|
||||||
|
@ -2683,21 +2826,23 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This is our main simulate loop
|
/// This is our main simulate loop
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
/// It's thread locked by a Mutex in the scene.
|
/// It's thread locked by a Mutex in the scene.
|
||||||
/// It holds Collisions, it instructs ODE to step through the physical reactions
|
/// It holds Collisions, it instructs ODE to step through the physical reactions
|
||||||
/// It moves the objects around in memory
|
/// It moves the objects around in memory
|
||||||
/// It calls the methods that report back to the object owners.. (scenepresence, SceneObjectGroup)
|
/// It calls the methods that report back to the object owners.. (scenepresence, SceneObjectGroup)
|
||||||
/// </summary>
|
/// </remarks>
|
||||||
/// <param name="timeStep"></param>
|
/// <param name="timeStep"></param>
|
||||||
/// <returns></returns>
|
/// <returns>The number of frames simulated over that period.</returns>
|
||||||
public override float Simulate(float timeStep)
|
public override float Simulate(float timeStep)
|
||||||
{
|
{
|
||||||
|
int startFrameTick = CollectStats ? Util.EnvironmentTickCount() : 0;
|
||||||
|
int quickStepTick = 0;
|
||||||
|
|
||||||
if (framecount >= int.MaxValue)
|
if (framecount >= int.MaxValue)
|
||||||
framecount = 0;
|
framecount = 0;
|
||||||
|
|
||||||
//if (m_worldOffset != Vector3.Zero)
|
|
||||||
// return 0;
|
|
||||||
|
|
||||||
framecount++;
|
framecount++;
|
||||||
|
|
||||||
float fps = 0;
|
float fps = 0;
|
||||||
|
@ -2705,7 +2850,7 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
float timeLeft = timeStep;
|
float timeLeft = timeStep;
|
||||||
|
|
||||||
//m_log.Info(timeStep.ToString());
|
//m_log.Info(timeStep.ToString());
|
||||||
// step_time += timeStep;
|
// step_time += timeSte
|
||||||
//
|
//
|
||||||
// // If We're loaded down by something else,
|
// // If We're loaded down by something else,
|
||||||
// // or debugging with the Visual Studio project on pause
|
// // or debugging with the Visual Studio project on pause
|
||||||
|
@ -2867,9 +3012,15 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
// "[PHYSICS]: Collision contacts to process this frame = {0}", m_global_contactcount);
|
// "[PHYSICS]: Collision contacts to process this frame = {0}", m_global_contactcount);
|
||||||
|
|
||||||
m_global_contactcount = 0;
|
m_global_contactcount = 0;
|
||||||
|
|
||||||
|
if (CollectStats)
|
||||||
|
quickStepTick = Util.EnvironmentTickCount();
|
||||||
|
|
||||||
d.WorldQuickStep(world, ODE_STEPSIZE);
|
d.WorldQuickStep(world, ODE_STEPSIZE);
|
||||||
|
|
||||||
|
if (CollectStats)
|
||||||
|
m_stats[ODENativeStepFrameMsStatName] += Util.EnvironmentTickCountSubtract(quickStepTick);
|
||||||
|
|
||||||
d.JointGroupEmpty(contactgroup);
|
d.JointGroupEmpty(contactgroup);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
@ -2937,7 +3088,7 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix);
|
d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
latertickcount = Util.EnvironmentTickCount() - tickCountFrameRun;
|
latertickcount = Util.EnvironmentTickCountSubtract(tickCountFrameRun);
|
||||||
|
|
||||||
// OpenSimulator above does 10 fps. 10 fps = means that the main thread loop and physics
|
// OpenSimulator above does 10 fps. 10 fps = means that the main thread loop and physics
|
||||||
// has a max of 100 ms to run theoretically.
|
// has a max of 100 ms to run theoretically.
|
||||||
|
@ -2957,6 +3108,9 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
tickCountFrameRun = Util.EnvironmentTickCount();
|
tickCountFrameRun = Util.EnvironmentTickCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (CollectStats)
|
||||||
|
m_stats[ODETotalFrameMsStatName] += Util.EnvironmentTickCountSubtract(startFrameTick);
|
||||||
|
|
||||||
return fps;
|
return fps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3190,7 +3344,7 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
public override bool IsThreaded
|
public override bool IsThreaded
|
||||||
{
|
{
|
||||||
// for now we won't be multithreaded
|
// for now we won't be multithreaded
|
||||||
get { return (false); }
|
get { return false; }
|
||||||
}
|
}
|
||||||
|
|
||||||
#region ODE Specific Terrain Fixes
|
#region ODE Specific Terrain Fixes
|
||||||
|
@ -3766,26 +3920,19 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
|
|
||||||
public override Dictionary<uint, float> GetTopColliders()
|
public override Dictionary<uint, float> GetTopColliders()
|
||||||
{
|
{
|
||||||
Dictionary<uint, float> returncolliders = new Dictionary<uint, float>();
|
Dictionary<uint, float> topColliders;
|
||||||
int cnt = 0;
|
|
||||||
lock (_prims)
|
lock (_prims)
|
||||||
{
|
{
|
||||||
foreach (OdePrim prm in _prims)
|
List<OdePrim> orderedPrims = new List<OdePrim>(_prims);
|
||||||
{
|
orderedPrims.OrderByDescending(p => p.CollisionScore).Take(25);
|
||||||
if (prm.CollisionScore > 0)
|
topColliders = orderedPrims.ToDictionary(p => p.LocalID, p => p.CollisionScore);
|
||||||
{
|
|
||||||
returncolliders.Add(prm.LocalID, prm.CollisionScore);
|
foreach (OdePrim p in _prims)
|
||||||
cnt++;
|
p.CollisionScore = 0;
|
||||||
prm.CollisionScore = 0f;
|
|
||||||
if (cnt > 25)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return returncolliders;
|
return topColliders;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool SupportsRayCast()
|
public override bool SupportsRayCast()
|
||||||
|
@ -3955,5 +4102,39 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
ds.SetViewpoint(ref xyz, ref hpr);
|
ds.SetViewpoint(ref xyz, ref hpr);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
public override Dictionary<string, float> GetStats()
|
||||||
|
{
|
||||||
|
if (!CollectStats)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
Dictionary<string, float> returnStats;
|
||||||
|
|
||||||
|
lock (OdeLock)
|
||||||
|
{
|
||||||
|
returnStats = new Dictionary<string, float>(m_stats);
|
||||||
|
|
||||||
|
returnStats[ODENativeCollisionFrameMsStatName]
|
||||||
|
= returnStats[ODENativeSpaceCollisionFrameMsStatName]
|
||||||
|
+ returnStats[ODENativeGeomCollisionFrameMsStatName];
|
||||||
|
|
||||||
|
InitializeExtraStats();
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnStats;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeExtraStats()
|
||||||
|
{
|
||||||
|
// No need to zero since this is calculated by addition
|
||||||
|
// m_stats[ODENativeCollisionFrameMsStatName] = 0;
|
||||||
|
|
||||||
|
m_stats[ODETotalFrameMsStatName] = 0;
|
||||||
|
m_stats[ODENativeStepFrameMsStatName] = 0;
|
||||||
|
m_stats[ODENativeSpaceCollisionFrameMsStatName] = 0;
|
||||||
|
m_stats[ODENativeGeomCollisionFrameMsStatName] = 0;
|
||||||
|
m_stats[ODEAvatarContactsStatsName] = 0;
|
||||||
|
m_stats[ODEPrimContactsStatName] = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -675,6 +675,25 @@
|
||||||
|
|
||||||
|
|
||||||
[ODEPhysicsSettings]
|
[ODEPhysicsSettings]
|
||||||
|
; ##
|
||||||
|
; ## Physics stats settings
|
||||||
|
;
|
||||||
|
|
||||||
|
; If collect_stats is enabled, then extra stat information is collected which is accessible via the MonitorModule
|
||||||
|
; (see http://opensimulator.org/wiki/Monitoring_Module for more details).
|
||||||
|
collect_stats = false
|
||||||
|
|
||||||
|
; ##
|
||||||
|
; ## Physics logging settings - logfiles are saved to *.DIF files
|
||||||
|
; ##
|
||||||
|
|
||||||
|
; default is false
|
||||||
|
;physics_logging = true
|
||||||
|
;; every n simulation iterations, the physics snapshot file is updated
|
||||||
|
;physics_logging_interval = 50
|
||||||
|
;; append to existing physics logfile, or overwrite existing logfiles?
|
||||||
|
;physics_logging_append_existing_logfile = true
|
||||||
|
|
||||||
;##
|
;##
|
||||||
;## World Settings
|
;## World Settings
|
||||||
;##
|
;##
|
||||||
|
@ -823,17 +842,6 @@
|
||||||
; number^2 physical level of detail of the sculpt texture. 16x16 - 256 verticies
|
; number^2 physical level of detail of the sculpt texture. 16x16 - 256 verticies
|
||||||
mesh_physical_lod = 16
|
mesh_physical_lod = 16
|
||||||
|
|
||||||
; ##
|
|
||||||
; ## Physics logging settings - logfiles are saved to *.DIF files
|
|
||||||
; ##
|
|
||||||
|
|
||||||
; default is false
|
|
||||||
;physics_logging = true
|
|
||||||
;; every n simulation iterations, the physics snapshot file is updated
|
|
||||||
;physics_logging_interval = 50
|
|
||||||
;; append to existing physics logfile, or overwrite existing logfiles?
|
|
||||||
;physics_logging_append_existing_logfile = true
|
|
||||||
|
|
||||||
; ##
|
; ##
|
||||||
; ## Joint support
|
; ## Joint support
|
||||||
; ##
|
; ##
|
||||||
|
|
Loading…
Reference in New Issue