Merge branch 'master' into careminster

Conflicts:
	OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
	OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
	OpenSim/Region/Framework/Scenes/Scene.cs
avinationmerge
Melanie 2012-10-12 19:05:06 +01:00
commit 6ce93b22d1
50 changed files with 1315 additions and 674 deletions

View File

@ -85,21 +85,6 @@ namespace OpenSim.Data
List<RegionData> GetHyperlinks(UUID scopeID);
}
[Flags]
public enum RegionFlags : int
{
DefaultRegion = 1, // Used for new Rez. Random if multiple defined
FallbackRegion = 2, // Regions we redirect to when the destination is down
RegionOnline = 4, // Set when a region comes online, unset when it unregisters and DeleteOnUnregister is false
NoDirectLogin = 8, // Region unavailable for direct logins (by name)
Persistent = 16, // Don't remove on unregister
LockedOut = 32, // Don't allow registration
NoMove = 64, // Don't allow moving this region
Reservation = 128, // This is an inactive reservation
Authenticate = 256, // Require authentication
Hyperlink = 512 // Record represents a HG link
}
public class RegionDataDistanceCompare : IComparer<RegionData>
{
private Vector2 m_origin;

View File

@ -37,6 +37,7 @@ using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
using RegionFlags = OpenSim.Framework.RegionFlags;
namespace OpenSim.Data.MSSQL
{

View File

@ -30,11 +30,11 @@ using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Reflection;
using MySql.Data.MySqlClient;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Data;
using MySql.Data.MySqlClient;
using RegionFlags = OpenSim.Framework.RegionFlags;
namespace OpenSim.Data.MySQL
{

View File

@ -33,6 +33,7 @@ using OpenSim.Framework;
using OpenSim.Data;
using System.Reflection;
using log4net;
using RegionFlags = OpenSim.Framework.RegionFlags;
namespace OpenSim.Data.Null
{

View File

@ -34,7 +34,7 @@ using OpenMetaverse;
public class ConsoleUtil
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public const string MinRawConsoleVectorValue = "-~";
public const string MaxRawConsoleVectorValue = "~";
@ -107,7 +107,7 @@ public class ConsoleUtil
string semiDigestedConsoleVector = string.Join(VectorSeparator, semiDigestedComponents.ToArray());
m_log.DebugFormat("[CONSOLE UTIL]: Parsing {0} into OpenMetaverse.Vector3", semiDigestedConsoleVector);
// m_log.DebugFormat("[CONSOLE UTIL]: Parsing {0} into OpenMetaverse.Vector3", semiDigestedConsoleVector);
return Vector3.TryParse(semiDigestedConsoleVector, out vector);
}

View File

@ -359,13 +359,19 @@ Asset service request failures: {3}" + Environment.NewLine,
inPacketsPerSecond, outPacketsPerSecond, pendingDownloads, pendingUploads, unackedBytes, totalFrameTime,
netFrameTime, physicsFrameTime, otherFrameTime, agentFrameTime, imageFrameTime));
foreach (KeyValuePair<string, Stat> kvp in StatsManager.RegisteredStats)
{
Stat stat = kvp.Value;
Dictionary<string, Dictionary<string, Stat>> sceneStats;
if (stat.Category == "scene" && stat.Verbosity == StatVerbosity.Info)
if (StatsManager.TryGetStats("scene", out sceneStats))
{
foreach (KeyValuePair<string, Dictionary<string, Stat>> kvp in sceneStats)
{
sb.AppendFormat("Slow frames ({0}): {1}\n", stat.Container, stat.Value);
foreach (Stat stat in kvp.Value.Values)
{
if (stat.Verbosity == StatVerbosity.Info)
{
sb.AppendFormat("{0} ({1}): {2}{3}\n", stat.Name, stat.Container, stat.Value, stat.UnitName);
}
}
}
}

View File

@ -35,13 +35,23 @@ namespace OpenSim.Framework.Monitoring
/// </summary>
public class StatsManager
{
// Subcommand used to list other stats.
public const string AllSubCommand = "all";
// Subcommand used to list other stats.
public const string ListSubCommand = "list";
// All subcommands
public static HashSet<string> SubCommands = new HashSet<string> { AllSubCommand, ListSubCommand };
/// <summary>
/// Registered stats.
/// Registered stats categorized by category/container/shortname
/// </summary>
/// <remarks>
/// Do not add or remove from this dictionary.
/// Do not add or remove directly from this dictionary.
/// </remarks>
public static Dictionary<string, Stat> RegisteredStats = new Dictionary<string, Stat>();
public static Dictionary<string, Dictionary<string, Dictionary<string, Stat>>> RegisteredStats
= new Dictionary<string, Dictionary<string, Dictionary<string, Stat>>>();
private static AssetStatsCollector assetStats;
private static UserStatsCollector userStats;
@ -51,6 +61,75 @@ namespace OpenSim.Framework.Monitoring
public static UserStatsCollector UserStats { get { return userStats; } }
public static SimExtraStatsCollector SimExtraStats { get { return simExtraStats; } }
public static void RegisterConsoleCommands(ICommandConsole console)
{
console.Commands.AddCommand(
"General",
false,
"show stats",
"show stats [list|all|<category>]",
"Show statistical information for this server",
"If no final argument is specified then legacy statistics information is currently shown.\n"
+ "If list is specified then statistic categories are shown.\n"
+ "If all is specified then all registered statistics are shown.\n"
+ "If a category name is specified then only statistics from that category are shown.\n"
+ "THIS STATS FACILITY IS EXPERIMENTAL AND DOES NOT YET CONTAIN ALL STATS",
HandleShowStatsCommand);
}
public static void HandleShowStatsCommand(string module, string[] cmd)
{
ICommandConsole con = MainConsole.Instance;
if (cmd.Length > 2)
{
var categoryName = cmd[2];
if (categoryName == AllSubCommand)
{
foreach (var category in RegisteredStats.Values)
{
OutputCategoryStatsToConsole(con, category);
}
}
else if (categoryName == ListSubCommand)
{
con.Output("Statistic categories available are:");
foreach (string category in RegisteredStats.Keys)
con.OutputFormat(" {0}", category);
}
else
{
Dictionary<string, Dictionary<string, Stat>> category;
if (!RegisteredStats.TryGetValue(categoryName, out category))
{
con.OutputFormat("No such category as {0}", categoryName);
}
else
{
OutputCategoryStatsToConsole(con, category);
}
}
}
else
{
// Legacy
con.Output(SimExtraStats.Report());
}
}
private static void OutputCategoryStatsToConsole(
ICommandConsole con, Dictionary<string, Dictionary<string, Stat>> category)
{
foreach (var container in category.Values)
{
foreach (Stat stat in container.Values)
{
con.Output(stat.ToConsoleString());
}
}
}
/// <summary>
/// Start collecting statistics related to assets.
/// Should only be called once.
@ -73,43 +152,100 @@ namespace OpenSim.Framework.Monitoring
return userStats;
}
/// <summary>
/// Registers a statistic.
/// </summary>
/// <param name='stat'></param>
/// <returns></returns>
public static bool RegisterStat(Stat stat)
{
Dictionary<string, Dictionary<string, Stat>> category = null, newCategory;
Dictionary<string, Stat> container = null, newContainer;
lock (RegisteredStats)
{
if (RegisteredStats.ContainsKey(stat.UniqueName))
{
// XXX: For now just return false. This is to avoid problems in regression tests where all tests
// in a class are run in the same instance of the VM.
// Stat name is not unique across category/container/shortname key.
// XXX: For now just return false. This is to avoid problems in regression tests where all tests
// in a class are run in the same instance of the VM.
if (TryGetStat(stat, out category, out container))
return false;
// throw new Exception(
// "StatsManager already contains stat with ShortName {0} in Category {1}", stat.ShortName, stat.Category);
}
// We take a copy-on-write approach here of replacing dictionaries when keys are added or removed.
// This means that we don't need to lock or copy them on iteration, which will be a much more
// common operation after startup.
if (container != null)
newContainer = new Dictionary<string, Stat>(container);
else
newContainer = new Dictionary<string, Stat>();
// We take a replace-on-write approach here so that we don't need to generate a new Dictionary
Dictionary<string, Stat> newRegisteredStats = new Dictionary<string, Stat>(RegisteredStats);
newRegisteredStats[stat.UniqueName] = stat;
RegisteredStats = newRegisteredStats;
if (category != null)
newCategory = new Dictionary<string, Dictionary<string, Stat>>(category);
else
newCategory = new Dictionary<string, Dictionary<string, Stat>>();
newContainer[stat.ShortName] = stat;
newCategory[stat.Container] = newContainer;
RegisteredStats[stat.Category] = newCategory;
}
return true;
}
/// <summary>
/// Deregister a statistic
/// </summary>>
/// <param name='stat'></param>
/// <returns></returns
public static bool DeregisterStat(Stat stat)
{
Dictionary<string, Dictionary<string, Stat>> category = null, newCategory;
Dictionary<string, Stat> container = null, newContainer;
lock (RegisteredStats)
{
if (!RegisteredStats.ContainsKey(stat.UniqueName))
if (!TryGetStat(stat, out category, out container))
return false;
Dictionary<string, Stat> newRegisteredStats = new Dictionary<string, Stat>(RegisteredStats);
newRegisteredStats.Remove(stat.UniqueName);
RegisteredStats = newRegisteredStats;
newContainer = new Dictionary<string, Stat>(container);
newContainer.Remove(stat.UniqueName);
newCategory = new Dictionary<string, Dictionary<string, Stat>>(category);
newCategory.Remove(stat.Container);
newCategory[stat.Container] = newContainer;
RegisteredStats[stat.Category] = newCategory;
return true;
}
}
public static bool TryGetStats(string category, out Dictionary<string, Dictionary<string, Stat>> stats)
{
return RegisteredStats.TryGetValue(category, out stats);
}
public static bool TryGetStat(
Stat stat,
out Dictionary<string, Dictionary<string, Stat>> category,
out Dictionary<string, Stat> container)
{
category = null;
container = null;
lock (RegisteredStats)
{
if (RegisteredStats.TryGetValue(stat.Category, out category))
{
if (category.TryGetValue(stat.Container, out container))
{
if (container.ContainsKey(stat.ShortName))
return true;
}
}
}
return false;
}
}
/// <summary>
@ -157,9 +293,26 @@ namespace OpenSim.Framework.Monitoring
public virtual double Value { get; set; }
/// <summary>
/// Constructor
/// </summary>
/// <param name='shortName'>Short name for the stat. Must not contain spaces. e.g. "LongFrames"</param>
/// <param name='name'>Human readable name for the stat. e.g. "Long frames"</param>
/// <param name='unitName'>
/// Unit name for the stat. Should be preceeded by a space if the unit name isn't normally appeneded immediately to the value.
/// e.g. " frames"
/// </param>
/// <param name='category'>Category under which this stat should appear, e.g. "scene". Do not capitalize.</param>
/// <param name='container'>Entity to which this stat relates. e.g. scene name if this is a per scene stat.</param>
/// <param name='verbosity'>Verbosity of stat. Controls whether it will appear in short stat display or only full display.</param>
/// <param name='description'>Description of stat</param>
public Stat(
string shortName, string name, string unitName, string category, string container, StatVerbosity verbosity, string description)
{
if (StatsManager.SubCommands.Contains(category))
throw new Exception(
string.Format("Stat cannot be in category '{0}' since this is reserved for a subcommand", category));
ShortName = shortName;
Name = name;
UnitName = unitName;
@ -175,6 +328,12 @@ namespace OpenSim.Framework.Monitoring
{
return string.Format("{0}+{1}+{2}", container, category, shortName);
}
public virtual string ToConsoleString()
{
return string.Format(
"{0}.{1}.{2} : {3}{4}", Category, Container, ShortName, Value, UnitName);
}
}
public class PercentageStat : Stat
@ -192,7 +351,7 @@ namespace OpenSim.Framework.Monitoring
if (c == 0)
return 0;
return (double)Antecedent / c;
return (double)Antecedent / c * 100;
}
set
@ -203,8 +362,13 @@ namespace OpenSim.Framework.Monitoring
public PercentageStat(
string shortName, string name, string category, string container, StatVerbosity verbosity, string description)
: base(shortName, name, " %", category, container, verbosity, description)
: base(shortName, name, "%", category, container, verbosity, description) {}
public override string ToConsoleString()
{
return string.Format(
"{0}.{1}.{2} : {3:0.##}{4} ({5}/{6})",
Category, Container, ShortName, Value, UnitName, Antecedent, Consequent);
}
}
}

View File

@ -231,7 +231,25 @@ namespace OpenSim.Framework.Monitoring
private static bool RemoveThread(int threadID)
{
lock (m_threads)
return m_threads.Remove(threadID);
{
ThreadWatchdogInfo twi;
if (m_threads.TryGetValue(threadID, out twi))
{
m_log.DebugFormat(
"[WATCHDOG]: Removing thread {0}, ID {1}", twi.Thread.Name, twi.Thread.ManagedThreadId);
m_threads.Remove(threadID);
return true;
}
else
{
m_log.WarnFormat(
"[WATCHDOG]: Requested to remove thread with ID {0} but this is not being monitored", threadID);
return false;
}
}
}
public static bool AbortThread(int threadID)

View File

@ -0,0 +1,53 @@
/*
* 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;
namespace OpenSim.Framework
{
/// <summary>
/// Region flags used internally by OpenSimulator to store installation specific information about regions.
/// </summary>
/// <remarks>
/// Don't confuse with OpenMetaverse.RegionFlags which are client facing flags (i.e. they go over the wire).
/// Returned by IGridService.GetRegionFlags()
/// </remarks>
[Flags]
public enum RegionFlags : int
{
DefaultRegion = 1, // Used for new Rez. Random if multiple defined
FallbackRegion = 2, // Regions we redirect to when the destination is down
RegionOnline = 4, // Set when a region comes online, unset when it unregisters and DeleteOnUnregister is false
NoDirectLogin = 8, // Region unavailable for direct logins (by name)
Persistent = 16, // Don't remove on unregister
LockedOut = 32, // Don't allow registration
NoMove = 64, // Don't allow moving this region
Reservation = 128, // This is an inactive reservation
Authenticate = 256, // Require authentication
Hyperlink = 512 // Record represents a HG link
}
}

View File

@ -96,11 +96,6 @@ namespace OpenSim.Framework.Servers
get { return m_httpServer; }
}
/// <summary>
/// Holds the non-viewer statistics collection object for this service/server
/// </summary>
protected IStatsCollector m_stats;
public BaseOpenSimServer()
{
m_startuptime = DateTime.Now;
@ -177,10 +172,6 @@ namespace OpenSim.Framework.Servers
"show info",
"Show general information about the server", HandleShow);
m_console.Commands.AddCommand("General", false, "show stats",
"show stats",
"Show statistics", HandleShow);
m_console.Commands.AddCommand("General", false, "show threads",
"show threads",
"Show thread status", HandleShow);
@ -226,12 +217,7 @@ namespace OpenSim.Framework.Servers
{
StringBuilder sb = new StringBuilder("DIAGNOSTICS\n\n");
sb.Append(GetUptimeReport());
if (m_stats != null)
{
sb.Append(m_stats.Report());
}
sb.Append(StatsManager.SimExtraStats.Report());
sb.Append(Environment.NewLine);
sb.Append(GetThreadsReport());
@ -382,10 +368,6 @@ namespace OpenSim.Framework.Servers
{
Notice("set log level [level] - change the console logging level only. For example, off or debug.");
Notice("show info - show server information (e.g. startup path).");
if (m_stats != null)
Notice("show stats - show statistical information for this server");
Notice("show threads - list tracked threads");
Notice("show uptime - show server startup time and uptime.");
Notice("show version - show server version.");
@ -409,11 +391,6 @@ namespace OpenSim.Framework.Servers
ShowInfo();
break;
case "stats":
if (m_stats != null)
Notice(m_stats.Report());
break;
case "threads":
Notice(GetThreadsReport());
break;
@ -604,8 +581,7 @@ namespace OpenSim.Framework.Servers
public string osSecret {
// Secret uuid for the simulator
get { return m_osSecret; }
get { return m_osSecret; }
}
public string StatReport(IOSHttpRequest httpRequest)
@ -613,11 +589,11 @@ namespace OpenSim.Framework.Servers
// If we catch a request for "callback", wrap the response in the value for jsonp
if (httpRequest.Query.ContainsKey("callback"))
{
return httpRequest.Query["callback"].ToString() + "(" + m_stats.XReport((DateTime.Now - m_startuptime).ToString() , m_version) + ");";
return httpRequest.Query["callback"].ToString() + "(" + StatsManager.SimExtraStats.XReport((DateTime.Now - m_startuptime).ToString() , m_version) + ");";
}
else
{
return m_stats.XReport((DateTime.Now - m_startuptime).ToString() , m_version);
return StatsManager.SimExtraStats.XReport((DateTime.Now - m_startuptime).ToString() , m_version);
}
}

View File

@ -254,8 +254,14 @@ namespace OpenSim
m_console.Commands.AddCommand("Debug", false, "debug teleport", "debug teleport", "Toggle teleport route debugging", Debug);
m_console.Commands.AddCommand("Debug", false, "debug scene",
"debug scene <scripting> <collisions> <physics>",
"Turn on scene debugging", Debug);
"debug scene active|collisions|physics|scripting|teleport true|false",
"Turn on scene debugging.",
"If active is false then main scene update and maintenance loops are suspended.\n"
+ "If collisions is false then collisions with other objects are turned off.\n"
+ "If physics is false then all physics objects are non-physical.\n"
+ "If scripting is false then no scripting operations happen.\n"
+ "If teleport is true then some extra teleport debug information is logged.",
Debug);
m_console.Commands.AddCommand("General", false, "change region",
"change region <region name>",
@ -930,7 +936,8 @@ namespace OpenSim
}
else
{
MainConsole.Instance.Output("Usage: debug scene scripting|collisions|physics|teleport true|false");
MainConsole.Instance.Output(
"Usage: debug scene active|scripting|collisions|physics|teleport true|false");
}
break;

View File

@ -232,8 +232,6 @@ namespace OpenSim
base.StartupSpecific();
m_stats = StatsManager.SimExtraStats;
// Create a ModuleLoader instance
m_moduleLoader = new ModuleLoader(m_config.Source);
@ -249,51 +247,51 @@ namespace OpenSim
plugin.PostInitialise();
}
AddPluginCommands();
}
protected virtual void AddPluginCommands()
{
// If console exists add plugin commands.
if (m_console != null)
{
List<string> topics = GetHelpTopics();
StatsManager.RegisterConsoleCommands(m_console);
AddPluginCommands(m_console);
}
}
foreach (string topic in topics)
protected virtual void AddPluginCommands(CommandConsole console)
{
List<string> topics = GetHelpTopics();
foreach (string topic in topics)
{
string capitalizedTopic = char.ToUpper(topic[0]) + topic.Substring(1);
// This is a hack to allow the user to enter the help command in upper or lowercase. This will go
// away at some point.
console.Commands.AddCommand(capitalizedTopic, false, "help " + topic,
"help " + capitalizedTopic,
"Get help on plugin command '" + topic + "'",
HandleCommanderHelp);
console.Commands.AddCommand(capitalizedTopic, false, "help " + capitalizedTopic,
"help " + capitalizedTopic,
"Get help on plugin command '" + topic + "'",
HandleCommanderHelp);
ICommander commander = null;
Scene s = SceneManager.CurrentOrFirstScene;
if (s != null && s.GetCommanders() != null)
{
string capitalizedTopic = char.ToUpper(topic[0]) + topic.Substring(1);
if (s.GetCommanders().ContainsKey(topic))
commander = s.GetCommanders()[topic];
}
// This is a hack to allow the user to enter the help command in upper or lowercase. This will go
// away at some point.
m_console.Commands.AddCommand(capitalizedTopic, false, "help " + topic,
"help " + capitalizedTopic,
"Get help on plugin command '" + topic + "'",
HandleCommanderHelp);
m_console.Commands.AddCommand(capitalizedTopic, false, "help " + capitalizedTopic,
"help " + capitalizedTopic,
"Get help on plugin command '" + topic + "'",
HandleCommanderHelp);
if (commander == null)
continue;
ICommander commander = null;
Scene s = SceneManager.CurrentOrFirstScene;
if (s != null && s.GetCommanders() != null)
{
if (s.GetCommanders().ContainsKey(topic))
commander = s.GetCommanders()[topic];
}
if (commander == null)
continue;
foreach (string command in commander.Commands.Keys)
{
m_console.Commands.AddCommand(capitalizedTopic, false,
topic + " " + command,
topic + " " + commander.Commands[command].ShortHelp(),
String.Empty, HandleCommanderCommand);
}
foreach (string command in commander.Commands.Keys)
{
console.Commands.AddCommand(capitalizedTopic, false,
topic + " " + command,
topic + " " + commander.Commands[command].ShortHelp(),
String.Empty, HandleCommanderCommand);
}
}
}

View File

@ -94,7 +94,7 @@ namespace OpenSim.Region.ClientStack.Linden
//scene.CommsManager.HttpServer.AddLLSDHandler("/CAPS/EQG/", EventQueueFallBack);
scene.EventManager.OnNewClient += OnNewClient;
// scene.EventManager.OnNewClient += OnNewClient;
// TODO: Leaving these open, or closing them when we
// become a child is incorrect. It messes up TP in a big
@ -102,6 +102,7 @@ namespace OpenSim.Region.ClientStack.Linden
// circuit is there.
scene.EventManager.OnClientClosed += ClientClosed;
scene.EventManager.OnMakeChildAgent += MakeChildAgent;
scene.EventManager.OnRegisterCaps += OnRegisterCaps;
@ -226,16 +227,6 @@ namespace OpenSim.Region.ClientStack.Linden
#endregion
private void OnNewClient(IClientAPI client)
{
//client.OnLogout += ClientClosed;
}
// private void ClientClosed(IClientAPI client)
// {
// ClientClosed(client.AgentId);
// }
private void ClientClosed(UUID agentID, Scene scene)
{
// m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", agentID, m_scene.RegionInfo.RegionName);

View File

@ -47,6 +47,7 @@ using OpenSim.Region.Framework.Scenes;
using OpenSim.Services.Interfaces;
using Timer = System.Timers.Timer;
using AssetLandmark = OpenSim.Framework.AssetLandmark;
using RegionFlags = OpenMetaverse.RegionFlags;
using Nini.Config;
using System.IO;
@ -3983,7 +3984,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{
List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value;
ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
ImprovedTerseObjectUpdatePacket packet
= (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate);
packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
packet.RegionData.TimeDilation = timeDilation;
packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
@ -4028,7 +4030,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{
List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
ImprovedTerseObjectUpdatePacket packet
= (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
PacketType.ImprovedTerseObjectUpdate);
packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
packet.RegionData.TimeDilation = timeDilation;
packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
@ -4036,7 +4040,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
for (int i = 0; i < blocks.Count; i++)
packet.ObjectData[i] = blocks[i];
OutPacket(packet, ThrottleOutPacketType.Task, true);
OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); });
}
#endregion Packet Sending
@ -5037,7 +5041,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Y, -64.0f, 64.0f), data, pos); pos += 2;
Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Z, -64.0f, 64.0f), data, pos); pos += 2;
ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock();
ImprovedTerseObjectUpdatePacket.ObjectDataBlock block
= PacketPool.Instance.GetDataBlock<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>();
block.Data = data;
if (textureEntry != null && textureEntry.Length > 0)
@ -11949,7 +11955,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
logPacket = false;
if (DebugPacketLevel <= 50
& (packet.Type == PacketType.ImprovedTerseObjectUpdate || packet.Type == PacketType.ObjectUpdate))
&& (packet.Type == PacketType.ImprovedTerseObjectUpdate || packet.Type == PacketType.ObjectUpdate))
logPacket = false;
if (DebugPacketLevel <= 25 && packet.Type == PacketType.ObjectPropertiesFamily)
@ -12481,7 +12487,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f);
ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
ImprovedTerseObjectUpdatePacket packet
= (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
PacketType.ImprovedTerseObjectUpdate);
packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
packet.RegionData.TimeDilation = timeDilation;
packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1];

View File

@ -100,9 +100,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// <summary>The measured resolution of Environment.TickCount</summary>
public readonly float TickCountResolution;
/// <summary>Number of prim updates to put on the queue each time the
/// OnQueueEmpty event is triggered for updates</summary>
public readonly int PrimUpdatesPerCallback;
/// <summary>Number of texture packets to put on the queue each time the
/// OnQueueEmpty event is triggered for textures</summary>
public readonly int TextureSendLimit;
@ -124,28 +126,37 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// <summary>Manages authentication for agent circuits</summary>
private AgentCircuitManager m_circuitManager;
/// <summary>Reference to the scene this UDP server is attached to</summary>
protected Scene m_scene;
/// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary>
private Location m_location;
/// <summary>The size of the receive buffer for the UDP socket. This value
/// is passed up to the operating system and used in the system networking
/// stack. Use zero to leave this value as the default</summary>
private int m_recvBufferSize;
/// <summary>Flag to process packets asynchronously or synchronously</summary>
private bool m_asyncPacketHandling;
/// <summary>Tracks whether or not a packet was sent each round so we know
/// whether or not to sleep</summary>
private bool m_packetSent;
/// <summary>Environment.TickCount of the last time that packet stats were reported to the scene</summary>
private int m_elapsedMSSinceLastStatReport = 0;
/// <summary>Environment.TickCount of the last time the outgoing packet handler executed</summary>
private int m_tickLastOutgoingPacketHandler;
/// <summary>Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler looped</summary>
private int m_elapsedMSOutgoingPacketHandler;
/// <summary>Keeps track of the number of 100 millisecond periods elapsed in the outgoing packet handler executed</summary>
private int m_elapsed100MSOutgoingPacketHandler;
/// <summary>Keeps track of the number of 500 millisecond periods elapsed in the outgoing packet handler executed</summary>
private int m_elapsed500MSOutgoingPacketHandler;
@ -425,6 +436,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
byte[] data = packet.ToBytes();
SendPacketData(udpClient, data, packet.Type, category, method);
}
PacketPool.Instance.ReturnPacket(packet);
}
/// <summary>
@ -742,7 +755,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
try
{
packet = Packet.BuildPacket(buffer.Data, ref packetEnd,
// packet = Packet.BuildPacket(buffer.Data, ref packetEnd,
// // Only allocate a buffer for zerodecoding if the packet is zerocoded
// ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
packet = PacketPool.Instance.GetPacket(buffer.Data, ref packetEnd,
// Only allocate a buffer for zerodecoding if the packet is zerocoded
((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
}
@ -757,11 +773,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
return; // Drop short packet
}
catch(Exception e)
catch (Exception e)
{
if (m_malformedCount < 100)
m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
m_malformedCount++;
if ((m_malformedCount % 100000) == 0)
m_log.DebugFormat("[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack.", m_malformedCount);
}
@ -1169,20 +1187,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{
IClientAPI client = null;
// In priciple there shouldn't be more than one thread here, ever.
// But in case that happens, we need to synchronize this piece of code
// because it's too important
lock (this)
// We currently synchronize this code across the whole scene to avoid issues such as
// http://opensimulator.org/mantis/view.php?id=5365 However, once locking per agent circuit can be done
// consistently, this lock could probably be removed.
lock (this)
{
if (!m_scene.TryGetClient(agentID, out client))
{
LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO);
client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
client.OnLogout += LogoutHandler;
((LLClientView)client).DisableFacelights = m_disableFacelights;
client.Start();
}
}

View File

@ -31,6 +31,7 @@ using System.Reflection;
using OpenMetaverse;
using OpenMetaverse.Packets;
using log4net;
using OpenSim.Framework.Monitoring;
namespace OpenSim.Region.ClientStack.LindenUDP
{
@ -43,17 +44,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
private bool packetPoolEnabled = true;
private bool dataBlockPoolEnabled = true;
private PercentageStat m_packetsReusedStat = new PercentageStat(
"PacketsReused",
"Packets reused",
"clientstack",
"packetpool",
StatVerbosity.Debug,
"Number of packets reused out of all requests to the packet pool");
private PercentageStat m_blocksReusedStat = new PercentageStat(
"BlocksReused",
"Blocks reused",
"clientstack",
"packetpool",
StatVerbosity.Debug,
"Number of data blocks reused out of all requests to the packet pool");
/// <summary>
/// Pool of packets available for reuse.
/// </summary>
private readonly Dictionary<PacketType, Stack<Packet>> pool = new Dictionary<PacketType, Stack<Packet>>();
private static Dictionary<Type, Stack<Object>> DataBlocks =
new Dictionary<Type, Stack<Object>>();
static PacketPool()
{
}
private static Dictionary<Type, Stack<Object>> DataBlocks = new Dictionary<Type, Stack<Object>>();
public static PacketPool Instance
{
@ -72,8 +84,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
get { return dataBlockPoolEnabled; }
}
private PacketPool()
{
StatsManager.RegisterStat(m_packetsReusedStat);
StatsManager.RegisterStat(m_blocksReusedStat);
}
/// <summary>
/// Gets a packet of the given type.
/// </summary>
/// <param name='type'></param>
/// <returns>Guaranteed to always return a packet, whether from the pool or newly constructed.</returns>
public Packet GetPacket(PacketType type)
{
m_packetsReusedStat.Consequent++;
Packet packet;
if (!packetPoolEnabled)
@ -89,6 +114,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
else
{
// Recycle old packages
m_packetsReusedStat.Antecedent++;
packet = (pool[type]).Pop();
}
}
@ -138,7 +165,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{
PacketType type = GetType(bytes);
Array.Clear(zeroBuffer, 0, zeroBuffer.Length);
// Array.Clear(zeroBuffer, 0, zeroBuffer.Length);
int i = 0;
Packet packet = GetPacket(type);
@ -185,6 +212,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
switch (packet.Type)
{
// List pooling packets here
case PacketType.AgentUpdate:
case PacketType.PacketAck:
case PacketType.ObjectUpdate:
case PacketType.ImprovedTerseObjectUpdate:
@ -211,16 +239,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
}
}
public static T GetDataBlock<T>() where T: new()
public T GetDataBlock<T>() where T: new()
{
lock (DataBlocks)
{
m_blocksReusedStat.Consequent++;
Stack<Object> s;
if (DataBlocks.TryGetValue(typeof(T), out s))
{
if (s.Count > 0)
{
m_blocksReusedStat.Antecedent++;
return (T)s.Pop();
}
}
else
{
@ -231,7 +264,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
}
}
public static void ReturnDataBlock<T>(T block) where T: new()
public void ReturnDataBlock<T>(T block) where T: new()
{
if (block == null)
return;

View File

@ -43,7 +43,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
/// This will contain basic tests for the LindenUDP client stack
/// </summary>
[TestFixture]
public class BasicCircuitTests
public class BasicCircuitTests : OpenSimTestCase
{
private Scene m_scene;
private TestLLUDPServer m_udpServer;
@ -143,7 +143,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
public void TestAddClient()
{
TestHelpers.InMethod();
// XmlConfigurator.Configure();
// TestHelpers.EnableLogging();
AddUdpServer();

View File

@ -212,7 +212,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, region.RegionID);
m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: region {0} flags: {1}", region.RegionID, flags);
if ((flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0)
if ((flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0)
{
m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Destination region {0} is hyperlink", region.RegionID);
GridRegion real_destination = m_GatekeeperConnector.GetHyperlinkRegion(region, region.RegionID);
@ -232,7 +232,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
return true;
int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID);
if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0)
if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0)
return true;
return false;
@ -256,7 +256,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
reason = string.Empty;
logout = false;
int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID);
if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0)
if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0)
{
// this user is going to another grid
// check if HyperGrid teleport is allowed, based on user level
@ -303,7 +303,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
// The rest is only needed for controlling appearance
int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID);
if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0)
if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0)
{
// this user is going to another grid
if (Scene.UserManagementModule.IsLocalGridUser(sp.UUID))

View File

@ -40,6 +40,7 @@ using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
using RegionFlags = OpenMetaverse.RegionFlags;
namespace OpenSim.Region.CoreModules.World.Estate
{

View File

@ -33,6 +33,7 @@ using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
using RegionFlags = OpenMetaverse.RegionFlags;
namespace OpenSim.Region.CoreModules.World.Land
{

View File

@ -27,6 +27,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
@ -83,29 +84,56 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
m_console.Commands.AddCommand(
"Objects", false, "delete object owner",
"delete object owner <UUID>",
"Delete a scene object by owner", HandleDeleteObject);
"Delete scene objects by owner",
"Command will ask for confirmation before proceeding.",
HandleDeleteObject);
m_console.Commands.AddCommand(
"Objects", false, "delete object creator",
"delete object creator <UUID>",
"Delete a scene object by creator", HandleDeleteObject);
"Delete scene objects by creator",
"Command will ask for confirmation before proceeding.",
HandleDeleteObject);
m_console.Commands.AddCommand(
"Objects", false, "delete object uuid",
"delete object uuid <UUID>",
"Delete a scene object by uuid", HandleDeleteObject);
"Delete a scene object by uuid",
HandleDeleteObject);
m_console.Commands.AddCommand(
"Objects", false, "delete object name",
"delete object name [--regex] <name>",
"Delete a scene object by name.",
"If --regex is specified then the name is treatead as a regular expression",
"Command will ask for confirmation before proceeding.\n"
+ "If --regex is specified then the name is treatead as a regular expression",
HandleDeleteObject);
m_console.Commands.AddCommand(
"Objects", false, "delete object outside",
"delete object outside",
"Delete all scene objects outside region boundaries", HandleDeleteObject);
"Delete all scene objects outside region boundaries",
"Command will ask for confirmation before proceeding.",
HandleDeleteObject);
m_console.Commands.AddCommand(
"Objects",
false,
"delete object pos",
"delete object pos <start-coord> to <end-coord>",
"Delete scene objects within the given area.",
"Each component of the coord is comma separated. There must be no spaces between the commas.\n"
+ "If you don't care about the z component you can simply omit it.\n"
+ "If you don't care about the x or y components then you can leave them blank (though a comma is still required)\n"
+ "If you want to specify the maxmimum value of a component then you can use ~ instead of a number\n"
+ "If you want to specify the minimum value of a component then you can use -~ instead of a number\n"
+ "e.g.\n"
+ "delete object pos 20,20,20 to 40,40,40\n"
+ "delete object pos 20,20 to 40,40\n"
+ "delete object pos ,20,20 to ,40,40\n"
+ "delete object pos ,,30 to ,,~\n"
+ "delete object pos ,,-~ to ,,30",
HandleDeleteObject);
m_console.Commands.AddCommand(
"Objects",
@ -301,23 +329,10 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
return;
}
string rawConsoleStartVector = cmdparams[3];
Vector3 startVector;
Vector3 startVector, endVector;
if (!ConsoleUtil.TryParseConsoleMinVector(rawConsoleStartVector, out startVector))
{
m_console.OutputFormat("Error: Start vector {0} does not have a valid format", rawConsoleStartVector);
if (!TryParseVectorRange(cmdparams.Skip(3).Take(3), out startVector, out endVector))
return;
}
string rawConsoleEndVector = cmdparams[5];
Vector3 endVector;
if (!ConsoleUtil.TryParseConsoleMaxVector(rawConsoleEndVector, out endVector))
{
m_console.OutputFormat("Error: End vector {0} does not have a valid format", rawConsoleEndVector);
return;
}
Predicate<SceneObjectGroup> searchPredicate
= so => Util.IsInsideBox(so.AbsolutePosition, startVector, endVector);
@ -557,6 +572,10 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
break;
case "pos":
deletes = GetDeleteCandidatesByPos(module, cmd);
break;
default:
m_console.OutputFormat("Unrecognized mode {0}", mode);
return;
@ -571,7 +590,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
string.Format(
"Are you sure that you want to delete {0} objects from {1}",
deletes.Count, m_scene.RegionInfo.RegionName),
"n");
"y/N");
if (response.ToLower() != "y")
{
@ -593,9 +612,6 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
private List<SceneObjectGroup> GetDeleteCandidatesByName(string module, string[] cmdparams)
{
if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene))
return null;
bool useRegex = false;
OptionSet options = new OptionSet().Add("regex", v=> useRegex = v != null );
@ -629,5 +645,52 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
return sceneObjects;
}
/// <summary>
/// Get scene object delete candidates by position
/// </summary>
/// <param name='module'></param>
/// <param name='cmdparams'></param>
/// <returns>null if parsing failed on one of the arguments, otherwise a list of objects to delete. If there
/// are no objects to delete then the list will be empty./returns>
private List<SceneObjectGroup> GetDeleteCandidatesByPos(string module, string[] cmdparams)
{
if (cmdparams.Length < 5)
{
m_console.OutputFormat("Usage: delete object pos <start-coord> to <end-coord>");
return null;
}
Vector3 startVector, endVector;
if (!TryParseVectorRange(cmdparams.Skip(3).Take(3), out startVector, out endVector))
return null;
return m_scene.GetSceneObjectGroups().FindAll(
so => !so.IsAttachment && Util.IsInsideBox(so.AbsolutePosition, startVector, endVector));
}
private bool TryParseVectorRange(IEnumerable<string> rawComponents, out Vector3 startVector, out Vector3 endVector)
{
string rawConsoleStartVector = rawComponents.Take(1).Single();
if (!ConsoleUtil.TryParseConsoleMinVector(rawConsoleStartVector, out startVector))
{
m_console.OutputFormat("Error: Start vector {0} does not have a valid format", rawConsoleStartVector);
endVector = Vector3.Zero;
return false;
}
string rawConsoleEndVector = rawComponents.Skip(1).Take(1).Single();
if (!ConsoleUtil.TryParseConsoleMaxVector(rawConsoleEndVector, out endVector))
{
m_console.OutputFormat("Error: End vector {0} does not have a valid format", rawConsoleEndVector);
return false;
}
return true;
}
}
}

View File

@ -125,13 +125,21 @@ namespace OpenSim.Region.Framework.Scenes
/// </summary>
/// <remarks>
/// This is triggered for both child and root agent client connections.
///
/// Triggered before OnClientLogin.
///
/// This is triggered under per-agent lock. So if you want to perform any long-running operations, please
/// do this on a separate thread.
/// </remarks>
public event OnNewClientDelegate OnNewClient;
/// <summary>
/// Fired if the client entering this sim is doing so as a new login
/// </summary>
/// <remarks>
/// This is triggered under per-agent lock. So if you want to perform any long-running operations, please
/// do this on a separate thread.
/// </remarks>
public event Action<IClientAPI> OnClientLogin;
public delegate void OnNewPresenceDelegate(ScenePresence presence);
@ -153,6 +161,9 @@ namespace OpenSim.Region.Framework.Scenes
/// <remarks>
/// Triggered in <see cref="OpenSim.Region.Framework.Scenes.Scene.AddNewClient"/> which is used by both
/// <see cref="OpenSim.Framework.PresenceType.User">users</see> and <see cref="OpenSim.Framework.PresenceType.Npc">NPCs</see>
///
/// Triggered under per-agent lock. So if you want to perform any long-running operations, please
/// do this on a separate thread.
/// </remarks>
public event OnRemovePresenceDelegate OnRemovePresence;
@ -429,6 +440,9 @@ namespace OpenSim.Region.Framework.Scenes
/// </summary>
/// <remarks>
/// At the point of firing, the scene still contains the client's scene presence.
///
/// This is triggered under per-agent lock. So if you want to perform any long-running operations, please
/// do this on a separate thread.
/// </remarks>
public event ClientClosed OnClientClosed;
@ -917,7 +931,7 @@ namespace OpenSim.Region.Framework.Scenes
public event SceneObjectPartCopyDelegate OnSceneObjectPartCopy;
public delegate void SceneObjectPartCopyDelegate(SceneObjectPart copy, SceneObjectPart original, bool userExposed);
public delegate void SceneObjectPartUpdated(SceneObjectPart sop);
public delegate void SceneObjectPartUpdated(SceneObjectPart sop, bool full);
public event SceneObjectPartUpdated OnSceneObjectPartUpdated;
public delegate void ScenePresenceUpdated(ScenePresence sp);
@ -2862,7 +2876,7 @@ namespace OpenSim.Region.Framework.Scenes
}
}
public void TriggerSceneObjectPartUpdated(SceneObjectPart sop)
public void TriggerSceneObjectPartUpdated(SceneObjectPart sop, bool full)
{
SceneObjectPartUpdated handler = OnSceneObjectPartUpdated;
if (handler != null)
@ -2871,7 +2885,7 @@ namespace OpenSim.Region.Framework.Scenes
{
try
{
d(sop);
d(sop, full);
}
catch (Exception e)
{

View File

@ -79,6 +79,11 @@ namespace OpenSim.Region.Framework.Scenes
public SynchronizeSceneHandler SynchronizeScene;
/// <summary>
/// Used to prevent simultaneous calls to RemoveClient() for the same agent from interfering with each other.
/// </summary>
private object m_removeClientLock = new object();
/// <summary>
/// Statistical information for this scene.
/// </summary>
@ -308,6 +313,31 @@ namespace OpenSim.Region.Framework.Scenes
}
private volatile bool m_shuttingDown;
/// <summary>
/// Is the scene active?
/// </summary>
/// <remarks>
/// If false, maintenance and update loops are not being run. Updates can still be triggered manually if
/// the scene is not active.
/// </remarks>
public bool Active
{
get { return m_active; }
set
{
if (value)
{
if (!m_active)
Start();
}
else
{
m_active = false;
}
}
}
private volatile bool m_active;
// private int m_lastUpdate;
private bool m_firstHeartbeat = true;
@ -1187,6 +1217,14 @@ namespace OpenSim.Region.Framework.Scenes
public void SetSceneCoreDebug(Dictionary<string, string> options)
{
if (options.ContainsKey("active"))
{
bool active;
if (bool.TryParse(options["active"], out active))
Active = active;
}
if (options.ContainsKey("scripting"))
{
bool enableScripts = true;
@ -1326,6 +1364,8 @@ namespace OpenSim.Region.Framework.Scenes
/// </summary>
public void Start()
{
m_active = true;
// m_log.DebugFormat("[SCENE]: Starting Heartbeat timer for {0}", RegionInfo.RegionName);
//m_heartbeatTimer.Enabled = true;
@ -1382,7 +1422,7 @@ namespace OpenSim.Region.Framework.Scenes
#region Update Methods
/// <summary>
/// Performs per-frame updates regularly
/// Activate the various loops necessary to continually update the scene.
/// </summary>
private void Heartbeat()
{
@ -1439,7 +1479,7 @@ namespace OpenSim.Region.Framework.Scenes
List<Vector3> coarseLocations;
List<UUID> avatarUUIDs;
while (!m_shuttingDown && (endRun == null || MaintenanceRun < endRun))
while (!m_shuttingDown && ((endRun == null && Active) || MaintenanceRun < endRun))
{
runtc = Util.EnvironmentTickCount();
++MaintenanceRun;
@ -1501,7 +1541,7 @@ namespace OpenSim.Region.Framework.Scenes
int sleepMS;
int framestart;
while (!m_shuttingDown && (endFrame == null || Frame < endFrame))
while (!m_shuttingDown && ((endFrame == null && Active) || Frame < endFrame))
{
framestart = Util.EnvironmentTickCount();
++Frame;
@ -2218,10 +2258,14 @@ namespace OpenSim.Region.Framework.Scenes
public bool AddRestoredSceneObject(
SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates)
{
bool result = m_sceneGraph.AddRestoredSceneObject(sceneObject, attachToBackup, alreadyPersisted, sendClientUpdates);
if (result)
if (m_sceneGraph.AddRestoredSceneObject(sceneObject, attachToBackup, alreadyPersisted, sendClientUpdates))
{
sceneObject.IsDeleted = false;
return result;
EventManager.TriggerObjectAddedToScene(sceneObject);
return true;
}
return false;
}
/// <summary>
@ -2862,77 +2906,89 @@ namespace OpenSim.Region.Framework.Scenes
public override ISceneAgent AddNewClient(IClientAPI client, PresenceType type)
{
ScenePresence sp;
bool vialogin;
// Validation occurs in LLUDPServer
//
// XXX: A race condition exists here where two simultaneous calls to AddNewClient can interfere with
// each other. In practice, this does not currently occur in the code.
AgentCircuitData aCircuit = m_authenticateHandler.GetAgentCircuitData(client.CircuitCode);
bool vialogin
= (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0
|| (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaLogin) != 0;
CheckHeartbeat();
ScenePresence sp = GetScenePresence(client.AgentId);
// XXX: Not sure how good it is to add a new client if a scene presence already exists. Possibly this
// could occur if a viewer crashes and relogs before the old client is kicked out. But this could cause
// other problems, and possible the code calling AddNewClient() should ensure that no client is already
// connected.
if (sp == null)
// We lock here on AgentCircuitData to prevent a race condition between the thread adding a new connection
// and a simultaneous one that removes it (as can happen if the client is closed at a particular point
// whilst connecting).
//
// It would be easier to lock across all NewUserConnection(), AddNewClient() and
// RemoveClient() calls for all agents, but this would allow a slow call (e.g. because of slow service
// response in some module listening to AddNewClient()) from holding up unrelated agent calls.
//
// In practice, the lock (this) in LLUDPServer.AddNewClient() currently lock across all
// AddNewClient() operations (though not other ops).
// In the future this can be relieved once locking per agent (not necessarily on AgentCircuitData) is improved.
lock (aCircuit)
{
m_log.DebugFormat(
"[SCENE]: Adding new child scene presence {0} {1} to scene {2} at pos {3}",
client.Name, client.AgentId, RegionInfo.RegionName, client.StartPos);
vialogin
= (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0
|| (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaLogin) != 0;
CheckHeartbeat();
sp = GetScenePresence(client.AgentId);
m_clientManager.Add(client);
SubscribeToClientEvents(client);
sp = m_sceneGraph.CreateAndAddChildScenePresence(client, aCircuit.Appearance, type);
m_eventManager.TriggerOnNewPresence(sp);
sp.TeleportFlags = (TPFlags)aCircuit.teleportFlags;
// The first agent upon login is a root agent by design.
// For this agent we will have to rez the attachments.
// All other AddNewClient calls find aCircuit.child to be true.
if (aCircuit.child == false)
// XXX: Not sure how good it is to add a new client if a scene presence already exists. Possibly this
// could occur if a viewer crashes and relogs before the old client is kicked out. But this could cause
// other problems, and possible the code calling AddNewClient() should ensure that no client is already
// connected.
if (sp == null)
{
// We have to set SP to be a root agent here so that SP.MakeRootAgent() will later not try to
// start the scripts again (since this is done in RezAttachments()).
// XXX: This is convoluted.
sp.IsChildAgent = false;
if (AttachmentsModule != null)
Util.FireAndForget(delegate(object o) { AttachmentsModule.RezAttachments(sp); });
m_log.DebugFormat(
"[SCENE]: Adding new child scene presence {0} {1} to scene {2} at pos {3}",
client.Name, client.AgentId, RegionInfo.RegionName, client.StartPos);
m_clientManager.Add(client);
SubscribeToClientEvents(client);
sp = m_sceneGraph.CreateAndAddChildScenePresence(client, aCircuit.Appearance, type);
m_eventManager.TriggerOnNewPresence(sp);
sp.TeleportFlags = (TPFlags)aCircuit.teleportFlags;
// The first agent upon login is a root agent by design.
// For this agent we will have to rez the attachments.
// All other AddNewClient calls find aCircuit.child to be true.
if (aCircuit.child == false)
{
// We have to set SP to be a root agent here so that SP.MakeRootAgent() will later not try to
// start the scripts again (since this is done in RezAttachments()).
// XXX: This is convoluted.
sp.IsChildAgent = false;
if (AttachmentsModule != null)
Util.FireAndForget(delegate(object o) { AttachmentsModule.RezAttachments(sp); });
}
}
}
else
{
m_log.WarnFormat(
"[SCENE]: Already found {0} scene presence for {1} in {2} when asked to add new scene presence",
sp.IsChildAgent ? "child" : "root", sp.Name, RegionInfo.RegionName);
}
else
{
m_log.WarnFormat(
"[SCENE]: Already found {0} scene presence for {1} in {2} when asked to add new scene presence",
sp.IsChildAgent ? "child" : "root", sp.Name, RegionInfo.RegionName);
}
// We must set this here so that TriggerOnNewClient and TriggerOnClientLogin can determine whether the
// client is for a root or child agent.
client.SceneAgent = sp;
// We must set this here so that TriggerOnNewClient and TriggerOnClientLogin can determine whether the
// client is for a root or child agent.
client.SceneAgent = sp;
// Cache the user's name
CacheUserName(sp, aCircuit);
EventManager.TriggerOnNewClient(client);
if (vialogin)
EventManager.TriggerOnClientLogin(client);
}
m_LastLogin = Util.EnvironmentTickCount();
// Cache the user's name
CacheUserName(sp, aCircuit);
EventManager.TriggerOnNewClient(client);
if (vialogin)
{
EventManager.TriggerOnClientLogin(client);
// Send initial parcel data
/* this is done on TriggerOnNewClient by landmanegement respective event handler
Vector3 pos = sp.AbsolutePosition;
ILandObject land = LandChannel.GetLandObject(pos.X, pos.Y);
land.SendLandUpdateToClient(client);
*/
}
return sp;
}
@ -3472,110 +3528,130 @@ namespace OpenSim.Region.Framework.Scenes
{
// CheckHeartbeat();
bool isChildAgent = false;
ScenePresence avatar = GetScenePresence(agentID);
AgentCircuitData acd;
if (avatar == null)
lock (m_removeClientLock)
{
m_log.WarnFormat(
"[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in the scene.", agentID);
acd = m_authenticateHandler.GetAgentCircuitData(agentID);
return;
if (acd == null)
{
m_log.ErrorFormat("[SCENE]: No agent circuit found for {0}, aborting Scene.RemoveClient", agentID);
return;
}
else
{
// We remove the acd up here to avoid later raec conditions if two RemoveClient() calls occurred
// simultaneously.
m_authenticateHandler.RemoveCircuit(acd.circuitcode);
}
}
try
lock (acd)
{
isChildAgent = avatar.IsChildAgent;
m_log.DebugFormat(
"[SCENE]: Removing {0} agent {1} {2} from {3}",
(isChildAgent ? "child" : "root"), avatar.Name, agentID, RegionInfo.RegionName);
// Don't do this to root agents, it's not nice for the viewer
if (closeChildAgents && isChildAgent)
ScenePresence avatar = GetScenePresence(agentID);
if (avatar == null)
{
// Tell a single agent to disconnect from the region.
IEventQueue eq = RequestModuleInterface<IEventQueue>();
if (eq != null)
{
eq.DisableSimulator(RegionInfo.RegionHandle, avatar.UUID);
}
else
{
avatar.ControllingClient.SendShutdownConnectionNotice();
}
m_log.WarnFormat(
"[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in the scene.", agentID);
return;
}
// Only applies to root agents.
if (avatar.ParentID != 0)
{
avatar.StandUp();
}
m_sceneGraph.removeUserCount(!isChildAgent);
// TODO: We shouldn't use closeChildAgents here - it's being used by the NPC module to stop
// unnecessary operations. This should go away once NPCs have no accompanying IClientAPI
if (closeChildAgents && CapsModule != null)
CapsModule.RemoveCaps(agentID);
// REFACTORING PROBLEM -- well not really a problem, but just to point out that whatever
// this method is doing is HORRIBLE!!!
avatar.Scene.NeedSceneCacheClear(avatar.UUID);
if (closeChildAgents && !isChildAgent)
{
List<ulong> regions = avatar.KnownRegionHandles;
regions.Remove(RegionInfo.RegionHandle);
m_sceneGridService.SendCloseChildAgentConnections(agentID, regions);
}
m_eventManager.TriggerClientClosed(agentID, this);
m_eventManager.TriggerOnRemovePresence(agentID);
if (!isChildAgent)
{
if (AttachmentsModule != null)
{
AttachmentsModule.DeRezAttachments(avatar);
}
ForEachClient(
delegate(IClientAPI client)
{
//We can safely ignore null reference exceptions. It means the avatar is dead and cleaned up anyway
try { client.SendKillObject(avatar.RegionHandle, new List<uint> { avatar.LocalId }); }
catch (NullReferenceException) { }
});
}
// It's possible for child agents to have transactions if changes are being made cross-border.
if (AgentTransactionsModule != null)
AgentTransactionsModule.RemoveAgentAssetTransactions(agentID);
m_authenticateHandler.RemoveCircuit(avatar.ControllingClient.CircuitCode);
m_log.Debug("[Scene] The avatar has left the building");
}
catch (Exception e)
{
m_log.Error(
string.Format("[SCENE]: Exception removing {0} from {1}. Cleaning up. Exception ", avatar.Name, Name), e);
}
finally
{
try
{
// Always clean these structures up so that any failure above doesn't cause them to remain in the
// scene with possibly bad effects (e.g. continually timing out on unacked packets and triggering
// the same cleanup exception continually.
m_sceneGraph.RemoveScenePresence(agentID);
m_clientManager.Remove(agentID);
isChildAgent = avatar.IsChildAgent;
m_log.DebugFormat(
"[SCENE]: Removing {0} agent {1} {2} from {3}",
(isChildAgent ? "child" : "root"), avatar.Name, agentID, RegionInfo.RegionName);
avatar.Close();
// Don't do this to root agents, it's not nice for the viewer
if (closeChildAgents && isChildAgent)
{
// Tell a single agent to disconnect from the region.
IEventQueue eq = RequestModuleInterface<IEventQueue>();
if (eq != null)
{
eq.DisableSimulator(RegionInfo.RegionHandle, avatar.UUID);
}
else
{
avatar.ControllingClient.SendShutdownConnectionNotice();
}
}
// Only applies to root agents.
if (avatar.ParentID != 0)
{
avatar.StandUp();
}
m_sceneGraph.removeUserCount(!isChildAgent);
// TODO: We shouldn't use closeChildAgents here - it's being used by the NPC module to stop
// unnecessary operations. This should go away once NPCs have no accompanying IClientAPI
if (closeChildAgents && CapsModule != null)
CapsModule.RemoveCaps(agentID);
// REFACTORING PROBLEM -- well not really a problem, but just to point out that whatever
// this method is doing is HORRIBLE!!!
avatar.Scene.NeedSceneCacheClear(avatar.UUID);
if (closeChildAgents && !isChildAgent)
{
List<ulong> regions = avatar.KnownRegionHandles;
regions.Remove(RegionInfo.RegionHandle);
m_sceneGridService.SendCloseChildAgentConnections(agentID, regions);
}
m_eventManager.TriggerClientClosed(agentID, this);
m_eventManager.TriggerOnRemovePresence(agentID);
if (!isChildAgent)
{
if (AttachmentsModule != null)
{
AttachmentsModule.DeRezAttachments(avatar);
}
ForEachClient(
delegate(IClientAPI client)
{
//We can safely ignore null reference exceptions. It means the avatar is dead and cleaned up anyway
try { client.SendKillObject(avatar.RegionHandle, new List<uint> { avatar.LocalId }); }
catch (NullReferenceException) { }
});
}
// It's possible for child agents to have transactions if changes are being made cross-border.
if (AgentTransactionsModule != null)
AgentTransactionsModule.RemoveAgentAssetTransactions(agentID);
m_log.Debug("[Scene] The avatar has left the building");
}
catch (Exception e)
{
m_log.Error(
string.Format("[SCENE]: Exception in final clean up of {0} in {1}. Exception ", avatar.Name, Name), e);
string.Format("[SCENE]: Exception removing {0} from {1}. Cleaning up. Exception ", avatar.Name, Name), e);
}
finally
{
try
{
// Always clean these structures up so that any failure above doesn't cause them to remain in the
// scene with possibly bad effects (e.g. continually timing out on unacked packets and triggering
// the same cleanup exception continually.
m_sceneGraph.RemoveScenePresence(agentID);
m_clientManager.Remove(agentID);
avatar.Close();
}
catch (Exception e)
{
m_log.Error(
string.Format("[SCENE]: Exception in final clean up of {0} in {1}. Exception ", avatar.Name, Name), e);
}
}
}
@ -3634,11 +3710,9 @@ namespace OpenSim.Region.Framework.Scenes
/// <summary>
/// Do the work necessary to initiate a new user connection for a particular scene.
/// At the moment, this consists of setting up the caps infrastructure
/// The return bool should allow for connections to be refused, but as not all calling paths
/// take proper notice of it let, we allowed banned users in still.
/// </summary>
/// <param name="agent">CircuitData of the agent who is connecting</param>
/// <param name="teleportFlags"></param>
/// <param name="reason">Outputs the reason for the false response on this string</param>
/// <returns>True if the region accepts this agent. False if it does not. False will
/// also return a reason.</returns>
@ -3649,10 +3723,20 @@ namespace OpenSim.Region.Framework.Scenes
/// <summary>
/// Do the work necessary to initiate a new user connection for a particular scene.
/// At the moment, this consists of setting up the caps infrastructure
/// </summary>
/// <remarks>
/// The return bool should allow for connections to be refused, but as not all calling paths
/// take proper notice of it yet, we still allowed banned users in.
///
/// At the moment this method consists of setting up the caps infrastructure
/// The return bool should allow for connections to be refused, but as not all calling paths
/// take proper notice of it let, we allowed banned users in still.
/// </summary>
///
/// This method is called by the login service (in the case of login) or another simulator (in the case of region
/// cross or teleport) to initiate the connection. It is not triggered by the viewer itself - the connection
/// is activated later when the viewer sends the initial UseCircuitCodePacket UDP packet (in the case of
/// the LLUDP stack).
/// </remarks>
/// <param name="agent">CircuitData of the agent who is connecting</param>
/// <param name="reason">Outputs the reason for the false response on this string</param>
/// <param name="requirePresenceLookup">True for normal presence. False for NPC
@ -3755,79 +3839,82 @@ namespace OpenSim.Region.Framework.Scenes
sp = null;
}
//On login test land permisions
if (vialogin)
lock (agent)
{
IUserAccountCacheModule cache = RequestModuleInterface<IUserAccountCacheModule>();
if (cache != null)
cache.Remove(agent.firstname + " " + agent.lastname);
if (!TestLandRestrictions(agent.AgentID, out reason, ref agent.startpos.X, ref agent.startpos.Y))
//On login test land permisions
if (vialogin)
{
m_log.DebugFormat("[CONNECTION BEGIN]: Denying access to {0} due to no land access", agent.AgentID.ToString());
return false;
}
}
if (sp == null) // We don't have an [child] agent here already
{
if (requirePresenceLookup)
{
try
IUserAccountCacheModule cache = RequestModuleInterface<IUserAccountCacheModule>();
if (cache != null)
cache.Remove(agent.firstname + " " + agent.lastname);
if (!TestLandRestrictions(agent.AgentID, out reason, ref agent.startpos.X, ref agent.startpos.Y))
{
if (!VerifyUserPresence(agent, out reason))
return false;
} catch (Exception e)
{
m_log.ErrorFormat(
"[SCENE]: Exception verifying presence {0}{1}", e.Message, e.StackTrace);
m_log.DebugFormat("[CONNECTION BEGIN]: Denying access to {0} due to no land access", agent.AgentID.ToString());
return false;
}
}
try
if (sp == null) // We don't have an [child] agent here already
{
// Always check estate if this is a login. Always
// check if banned regions are to be blacked out.
if (vialogin || (!m_seeIntoBannedRegion))
if (requirePresenceLookup)
{
if (!AuthorizeUser(agent, out reason))
try
{
if (!VerifyUserPresence(agent, out reason))
return false;
} catch (Exception e)
{
m_log.ErrorFormat(
"[SCENE]: Exception verifying presence {0}{1}", e.Message, e.StackTrace);
return false;
}
}
try
{
// Always check estate if this is a login. Always
// check if banned regions are to be blacked out.
if (vialogin || (!m_seeIntoBannedRegion))
{
if (!AuthorizeUser(agent, out reason))
return false;
}
}
catch (Exception e)
{
m_log.ErrorFormat(
"[SCENE]: Exception authorizing user {0}{1}", e.Message, e.StackTrace);
return false;
}
m_log.InfoFormat(
"[SCENE]: Region {0} authenticated and authorized incoming {1} agent {2} {3} {4} (circuit code {5})",
RegionInfo.RegionName, (agent.child ? "child" : "root"), agent.firstname, agent.lastname,
agent.AgentID, agent.circuitcode);
if (CapsModule != null)
{
CapsModule.SetAgentCapsSeeds(agent);
CapsModule.CreateCaps(agent.AgentID);
}
}
catch (Exception e)
else
{
m_log.ErrorFormat(
"[SCENE]: Exception authorizing user {0}{1}", e.Message, e.StackTrace);
return false;
}
// Let the SP know how we got here. This has a lot of interesting
// uses down the line.
sp.TeleportFlags = (TPFlags)teleportFlags;
m_log.InfoFormat(
"[SCENE]: Region {0} authenticated and authorized incoming {1} agent {2} {3} {4} (circuit code {5})",
RegionInfo.RegionName, (agent.child ? "child" : "root"), agent.firstname, agent.lastname,
agent.AgentID, agent.circuitcode);
if (sp.IsChildAgent)
{
m_log.DebugFormat(
"[SCENE]: Adjusting known seeds for existing agent {0} in {1}",
agent.AgentID, RegionInfo.RegionName);
if (CapsModule != null)
{
CapsModule.SetAgentCapsSeeds(agent);
CapsModule.CreateCaps(agent.AgentID);
}
} else
{
// Let the SP know how we got here. This has a lot of interesting
// uses down the line.
sp.TeleportFlags = (TPFlags)teleportFlags;
sp.AdjustKnownSeeds();
if (sp.IsChildAgent)
{
m_log.DebugFormat(
"[SCENE]: Adjusting known seeds for existing agent {0} in {1}",
agent.AgentID, RegionInfo.RegionName);
sp.AdjustKnownSeeds();
if (CapsModule != null)
CapsModule.SetAgentCapsSeeds(agent);
if (CapsModule != null)
CapsModule.SetAgentCapsSeeds(agent);
}
}
}

View File

@ -3082,7 +3082,7 @@ namespace OpenSim.Region.Framework.Scenes
// UUID, Name, TimeStampFull);
if (ParentGroup.Scene != null)
ParentGroup.Scene.EventManager.TriggerSceneObjectPartUpdated(this);
ParentGroup.Scene.EventManager.TriggerSceneObjectPartUpdated(this, true);
}
/// <summary>
@ -3116,7 +3116,7 @@ namespace OpenSim.Region.Framework.Scenes
}
if (ParentGroup.Scene != null)
ParentGroup.Scene.EventManager.TriggerSceneObjectPartUpdated(this);
ParentGroup.Scene.EventManager.TriggerSceneObjectPartUpdated(this, false);
}
public void ScriptSetPhysicsStatus(bool UsePhysics)

View File

@ -263,7 +263,7 @@ public class BSCharacter : BSPhysObject
// A version of the sanity check that also makes sure a new position value is
// pushed back to the physics engine. This routine would be used by anyone
// who is not already pushing the value.
private bool PositionSanityCheck2(bool atTaintTime)
private bool PositionSanityCheck2(bool inTaintTime)
{
bool ret = false;
if (PositionSanityCheck())
@ -275,7 +275,7 @@ public class BSCharacter : BSPhysObject
DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation);
};
if (atTaintTime)
if (inTaintTime)
sanityOperation();
else
PhysicsScene.TaintedObject("BSCharacter.PositionSanityCheck", sanityOperation);
@ -332,6 +332,13 @@ public class BSCharacter : BSPhysObject
});
}
}
public override OMV.Vector3 ForceVelocity {
get { return _velocity; }
set {
_velocity = value;
BulletSimAPI.SetObjectVelocity(PhysicsScene.WorldID, LocalID, _velocity);
}
}
public override OMV.Vector3 Torque {
get { return _torque; }
set { _torque = value;
@ -432,6 +439,10 @@ public class BSCharacter : BSPhysObject
get { return _rotationalVelocity; }
set { _rotationalVelocity = value; }
}
public override OMV.Vector3 ForceRotationalVelocity {
get { return _rotationalVelocity; }
set { _rotationalVelocity = value; }
}
public override bool Kinematic {
get { return _kinematic; }
set { _kinematic = value; }

View File

@ -49,9 +49,16 @@ public abstract class BSConstraint : IDisposable
if (m_enabled)
{
m_enabled = false;
bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr);
m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,body1={1},body2={2},success={3}", BSScene.DetailLogZero, m_body1.ID, m_body2.ID, success);
m_constraint.ptr = System.IntPtr.Zero;
if (m_constraint.ptr != IntPtr.Zero)
{
bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr);
m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}",
BSScene.DetailLogZero,
m_body1.ID, m_body1.ptr.ToString("X"),
m_body2.ID, m_body2.ptr.ToString("X"),
success);
m_constraint.ptr = System.IntPtr.Zero;
}
}
}

View File

@ -462,7 +462,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
return;
// Set the prim's inertia to zero. The vehicle code handles that and this
// removes the torque action introduced by Bullet.
// removes the motion and torque actions introduced by Bullet.
Vector3 inertia = Vector3.Zero;
BulletSimAPI.SetMassProps2(Prim.BSBody.ptr, Prim.MassRaw, inertia);
BulletSimAPI.UpdateInertiaTensor2(Prim.BSBody.ptr);
@ -481,7 +481,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_lastPositionVector = Prim.ForcePosition;
VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}",
Prim.LocalID, Prim.Position, Prim.Force, Prim.Velocity, Prim.RotationalVelocity);
Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity);
}// end Step
// Apply the effect of the linear motor.
@ -540,7 +540,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// add Gravity and Buoyancy
// There is some gravity, make a gravity force vector that is applied after object velocity.
// m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
Vector3 grav = Prim.PhysicsScene.DefaultGravity * (Prim.Mass * (1f - m_VehicleBuoyancy));
Vector3 grav = Prim.PhysicsScene.DefaultGravity * (Prim.Linkset.LinksetMass * (1f - m_VehicleBuoyancy));
/*
* RA: Not sure why one would do this
@ -678,10 +678,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_newVelocity.Z = 0;
// Apply velocity
Prim.Velocity = m_newVelocity;
Prim.ForceVelocity = m_newVelocity;
// apply gravity force
// Why is this set here? The physics engine already does gravity.
// m_prim.AddForce(grav, false);
Prim.AddForce(grav, false, true);
// Apply friction
Vector3 keepFraction = Vector3.One - (Vector3.One / (m_linearFrictionTimescale / pTimestep));
@ -704,7 +704,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// m_lastAngularVelocity // what was last applied to body
// Get what the body is doing, this includes 'external' influences
Vector3 angularVelocity = Prim.RotationalVelocity;
Vector3 angularVelocity = Prim.ForceRotationalVelocity;
if (m_angularMotorApply > 0)
{
@ -810,7 +810,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_lastAngularVelocity -= m_lastAngularVelocity * decayamount;
// Apply to the body
Prim.RotationalVelocity = m_lastAngularVelocity;
Prim.ForceRotationalVelocity = m_lastAngularVelocity;
VDetailLog("{0},MoveAngular,done,decay={1},lastAngular={2}", Prim.LocalID, decayamount, m_lastAngularVelocity);
} //end MoveAngular
@ -862,7 +862,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
private void VDetailLog(string msg, params Object[] args)
{
if (Prim.PhysicsScene.VehicleLoggingEnabled)
Prim.PhysicsScene.PhysicsLogging.Write(msg, args);
Prim.PhysicsScene.DetailLog(msg, args);
}
}
}

View File

@ -52,8 +52,8 @@ public class BSLinkset
// the physical 'taint' children separately.
// After taint processing and before the simulation step, these
// two lists must be the same.
private List<BSPhysObject> m_children;
private List<BSPhysObject> m_taintChildren;
private HashSet<BSPhysObject> m_children;
private HashSet<BSPhysObject> m_taintChildren;
// We lock the diddling of linkset classes to prevent any badness.
// This locks the modification of the instances of this class. Changes
@ -90,8 +90,8 @@ public class BSLinkset
m_nextLinksetID = 1;
PhysicsScene = scene;
LinksetRoot = parent;
m_children = new List<BSPhysObject>();
m_taintChildren = new List<BSPhysObject>();
m_children = new HashSet<BSPhysObject>();
m_taintChildren = new HashSet<BSPhysObject>();
m_mass = parent.MassRaw;
}
@ -160,6 +160,28 @@ public class BSLinkset
return ret;
}
// When physical properties are changed the linkset needs to recalculate
// its internal properties.
// May be called at runtime or taint-time (just pass the appropriate flag).
public void Refresh(BSPhysObject requestor, bool inTaintTime)
{
// If there are no children, not physical or not root, I am not the one that recomputes the constraints
// (For the moment, static linksets do create constraints so remove the test for physical.)
if (!HasAnyChildren || /*!requestor.IsPhysical ||*/ !IsRoot(requestor))
return;
BSScene.TaintCallback refreshOperation = delegate()
{
RecomputeLinksetConstraintVariables();
DetailLog("{0},BSLinkset.Refresh,complete,rBody={1}",
LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
};
if (inTaintTime)
refreshOperation();
else
PhysicsScene.TaintedObject("BSLinkSet.Refresh", refreshOperation);
}
// The object is going dynamic (physical). Do any setup necessary
// for a dynamic linkset.
// Only the state of the passed object can be modified. The rest of the linkset
@ -182,22 +204,19 @@ public class BSLinkset
return false;
}
// When physical properties are changed the linkset needs to recalculate
// its internal properties.
// Called at runtime.
public void Refresh(BSPhysObject requestor)
// If the software is handling the movement of all the objects in a linkset
// (like if one doesn't use constraints for static linksets), this is called
// when an update for the root of the linkset is received.
// Called at taint-time!!
public void UpdateProperties(BSPhysObject physObject)
{
// If there are no children, there can't be any constraints to recompute
if (!HasAnyChildren)
return;
// Only the root does the recomputation
if (IsRoot(requestor))
// The root local properties have been updated. Apply to the children if appropriate.
if (IsRoot(physObject) && HasAnyChildren)
{
PhysicsScene.TaintedObject("BSLinkSet.Refresh", delegate()
if (!physObject.IsPhysical)
{
RecomputeLinksetConstraintVariables();
});
// TODO: implement software linkset update for static object linksets
}
}
}
@ -215,13 +234,10 @@ public class BSLinkset
if (IsRoot(child))
{
// If the one with the dependency is root, must undo all children
DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeChildrenForRoot,rID={1},numChild={2}",
child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count);
foreach (BSPhysObject bpo in m_taintChildren)
{
PhysicallyUnlinkAChildFromRoot(LinksetRoot, LinksetRoot.BSBody, bpo, bpo.BSBody);
ret = true;
}
DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}",
child.LocalID, LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
}
else
{
@ -229,20 +245,16 @@ public class BSLinkset
child.LocalID,
LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
child.LocalID, child.BSBody.ptr.ToString("X"));
// Remove the dependency on the body of this one
if (m_taintChildren.Contains(child))
{
PhysicallyUnlinkAChildFromRoot(LinksetRoot, LinksetRoot.BSBody, child, child.BSBody);
ret = true;
}
// ret = PhysicallyUnlinkAChildFromRoot(LinksetRoot, child);
// Despite the function name, this removes any link to the specified object.
ret = PhysicallyUnlinkAllChildrenFromRoot(child);
}
}
return ret;
}
// Routine used when rebuilding the body of the root of the linkset
// This is called after RemoveAllLinksToRoot() to restore all the constraints.
// This is called when the root body has been changed.
// Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
// this routine will restore the removed constraints.
// Called at taint-time!!
public void RestoreBodyDependencies(BSPrim child)
{
@ -254,7 +266,7 @@ public class BSLinkset
child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count);
foreach (BSPhysObject bpo in m_taintChildren)
{
PhysicallyLinkAChildToRoot(LinksetRoot, LinksetRoot.BSBody, bpo, bpo.BSBody);
PhysicallyLinkAChildToRoot(LinksetRoot, bpo);
}
}
else
@ -263,7 +275,7 @@ public class BSLinkset
LinksetRoot.LocalID,
LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
child.LocalID, child.BSBody.ptr.ToString("X"));
PhysicallyLinkAChildToRoot(LinksetRoot, LinksetRoot.BSBody, child, child.BSBody);
PhysicallyLinkAChildToRoot(LinksetRoot, child);
}
}
}
@ -330,22 +342,22 @@ public class BSLinkset
{
m_children.Add(child);
BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
BSPhysObject rootx = LinksetRoot; // capture the root as of now
BSPhysObject childx = child;
DetailLog("{0},AddChildToLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
rootx.LocalID,
rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
childx.LocalID, childx.BSBody.ptr.ToString("X"));
DetailLog("{0},AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
PhysicsScene.TaintedObject("AddChildToLinkset", delegate()
{
DetailLog("{0},AddChildToLinkset,taint,child={1}", LinksetRoot.LocalID, child.LocalID);
// build the physical binding between me and the child
m_taintChildren.Add(childx);
DetailLog("{0},AddChildToLinkset,taint,rID={1},rBody={2},cID={3},cBody={4}",
rootx.LocalID,
rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
childx.LocalID, childx.BSBody.ptr.ToString("X"));
// Since this is taint-time, the body and shape could have changed for the child
PhysicallyLinkAChildToRoot(rootx, rootx.BSBody, childx, childx.BSBody);
rootx.ForcePosition = rootx.Position; // DEBUG
childx.ForcePosition = childx.Position; // DEBUG
PhysicallyLinkAChildToRoot(rootx, childx);
m_taintChildren.Add(child);
});
}
return;
@ -378,10 +390,8 @@ public class BSLinkset
PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate()
{
if (m_taintChildren.Contains(childx))
m_taintChildren.Remove(childx);
PhysicallyUnlinkAChildFromRoot(rootx, rootx.BSBody, childx, childx.BSBody);
m_taintChildren.Remove(child);
PhysicallyUnlinkAChildFromRoot(rootx, childx);
RecomputeLinksetConstraintVariables();
});
@ -396,8 +406,7 @@ public class BSLinkset
// Create a constraint between me (root of linkset) and the passed prim (the child).
// Called at taint time!
private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BulletBody rootBody,
BSPhysObject childPrim, BulletBody childBody)
private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
{
// Zero motion for children so they don't interpolate
childPrim.ZeroMotion();
@ -409,33 +418,17 @@ public class BSLinkset
// real world coordinate of midpoint between the two objects
OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
rootPrim.LocalID,
rootPrim.LocalID, rootBody.ptr.ToString("X"),
childPrim.LocalID, childBody.ptr.ToString("X"),
rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"),
childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"),
rootPrim.Position, childPrim.Position, midPoint);
// create a constraint that allows no freedom of movement between the two objects
// http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
// There is great subtlty in these paramters. Notice the check for a ptr of zero.
// We pass the BulletBody structure into the taint in order to capture the pointer
// of the body at the time of constraint creation. This doesn't work for the very first
// construction because there is no body yet. The body
// is constructed later at taint time. Thus we use the body address at time of the
// taint creation but, if it is zero, use what's in the prim at the moment.
// There is a possible race condition since shape can change without a taint call
// (like changing to a mesh that is already constructed). The fix for that would be
// to only change BSShape at taint time thus syncronizing these operations at
// the cost of efficiency and lag.
BS6DofConstraint constrain = new BS6DofConstraint(
PhysicsScene.World,
rootBody.ptr == IntPtr.Zero ? rootPrim.BSBody : rootBody,
childBody.ptr == IntPtr.Zero ? childPrim.BSBody : childBody,
midPoint,
true,
true
);
PhysicsScene.World, rootPrim.BSBody, childPrim.BSBody, midPoint, true, true );
/* NOTE: below is an attempt to build constraint with full frame computation, etc.
* Using the midpoint is easier since it lets the Bullet code manipulate the transforms
@ -452,7 +445,7 @@ public class BSLinkset
// create a constraint that allows no freedom of movement between the two objects
// http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
BS6DofConstraint constrain = new BS6DofConstraint(
PhysicsScene.World, rootPrim.Body, childPrim.Body,
OMV.Vector3.Zero,
@ -486,39 +479,44 @@ public class BSLinkset
{
constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations);
}
RecomputeLinksetConstraintVariables();
}
// Remove linkage between myself and a particular child
// The root and child bodies are passed in because we need to remove the constraint between
// the bodies that were at unlink time.
// Called at taint time!
private void PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BulletBody rootBody,
BSPhysObject childPrim, BulletBody childBody)
private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
{
DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
bool ret = false;
DetailLog("{0},BSLinkset.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
rootPrim.LocalID,
rootPrim.LocalID, rootBody.ptr.ToString("X"),
childPrim.LocalID, childBody.ptr.ToString("X"));
rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"),
childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"));
// Find the constraint for this link and get rid of it from the overall collection and from my list
PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootBody, childBody);
if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody, childPrim.BSBody))
{
// Make the child refresh its location
BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr);
ret = true;
}
// Make the child refresh its location
BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr);
return ret;
}
/*
// Remove linkage between myself and any possible children I might have.
// Called at taint time!
private void PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
{
DetailLog("{0},PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
DetailLog("{0},BSLinkset.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
bool ret = false;
PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody);
if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody))
{
ret = true;
}
return ret;
}
*/
// Call each of the constraints that make up this linkset and recompute the
// various transforms and variables. Used when objects are added or removed
@ -550,11 +548,17 @@ public class BSLinkset
{
// If this is a multiple object linkset, set everybody's center of mass to the set's center of mass
OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass();
BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.ptr, centerOfMass, OMV.Quaternion.Identity);
BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.ptr,
centerOfMass, OMV.Quaternion.Identity);
DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,setCenterOfMass,COM={1},rBody={2}",
LinksetRoot.LocalID, centerOfMass, LinksetRoot.BSBody.ptr.ToString("X"));
foreach (BSPhysObject child in m_taintChildren)
{
BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.ptr, centerOfMass, OMV.Quaternion.Identity);
BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.ptr,
centerOfMass, OMV.Quaternion.Identity);
}
// BulletSimAPI.DumpAllInfo2(PhysicsScene.World.ptr); // DEBUG DEBUG DEBUG
}
return;
}
@ -563,7 +567,8 @@ public class BSLinkset
// Invoke the detailed logger and output something if it's enabled.
private void DetailLog(string msg, params Object[] args)
{
PhysicsScene.PhysicsLogging.Write(msg, args);
if (PhysicsScene.PhysicsLogging.Enabled)
PhysicsScene.DetailLog(msg, args);
}
}

View File

@ -85,6 +85,10 @@ public abstract class BSPhysObject : PhysicsActor
public abstract OMV.Quaternion ForceOrientation { get; set; }
public abstract OMV.Vector3 ForceVelocity { get; set; }
public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
#region Collisions
// Requested number of milliseconds between collision events. Zero means disabled.
@ -207,7 +211,8 @@ public abstract class BSPhysObject : PhysicsActor
// High performance detailed logging routine used by the physical objects.
protected void DetailLog(string msg, params Object[] args)
{
PhysicsScene.PhysicsLogging.Write(msg, args);
if (PhysicsScene.PhysicsLogging.Enabled)
PhysicsScene.DetailLog(msg, args);
}
}
}

View File

@ -196,7 +196,7 @@ public sealed class BSPrim : BSPhysObject
_isSelected = value;
PhysicsScene.TaintedObject("BSPrim.setSelected", delegate()
{
// DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
SetObjectDynamic(false);
});
}
@ -265,6 +265,11 @@ public sealed class BSPrim : BSPhysObject
return _position;
}
set {
// If you must push the position into the physics engine, use ForcePosition.
if (_position == value)
{
return;
}
_position = value;
// TODO: what does it mean to set the position of a child prim?? Rebuild the constraint?
PositionSanityCheck();
@ -322,7 +327,7 @@ public sealed class BSPrim : BSPhysObject
// A version of the sanity check that also makes sure a new position value is
// pushed back to the physics engine. This routine would be used by anyone
// who is not already pushing the value.
private bool PositionSanityCheck2(bool atTaintTime)
private bool PositionSanityCheck2(bool inTaintTime)
{
bool ret = false;
if (PositionSanityCheck())
@ -334,7 +339,7 @@ public sealed class BSPrim : BSPhysObject
DetailLog("{0},BSPrim.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation);
};
if (atTaintTime)
if (inTaintTime)
sanityOperation();
else
PhysicsScene.TaintedObject("BSPrim.PositionSanityCheck", sanityOperation);
@ -453,7 +458,6 @@ public sealed class BSPrim : BSPhysObject
}
return;
}
public override OMV.Vector3 Velocity {
get { return _velocity; }
set {
@ -465,6 +469,13 @@ public sealed class BSPrim : BSPhysObject
});
}
}
public override OMV.Vector3 ForceVelocity {
get { return _velocity; }
set {
_velocity = value;
BulletSimAPI.SetLinearVelocity2(BSBody.ptr, _velocity);
}
}
public override OMV.Vector3 Torque {
get { return _torque; }
set { _torque = value;
@ -490,6 +501,8 @@ public sealed class BSPrim : BSPhysObject
return _orientation;
}
set {
if (_orientation == value)
return;
_orientation = value;
// TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint?
PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate()
@ -570,7 +583,7 @@ public sealed class BSPrim : BSPhysObject
// Set up the object physicalness (does gravity and collisions move this object)
MakeDynamic(IsStatic);
// Update vehicle specific parameters
// Update vehicle specific parameters (after MakeDynamic() so can change physical parameters)
_vehicle.Refresh();
// Arrange for collision events if the simulator wants them
@ -593,7 +606,7 @@ public sealed class BSPrim : BSPhysObject
// Recompute any linkset parameters.
// When going from non-physical to physical, this re-enables the constraints that
// had been automatically disabled when the mass was set to zero.
Linkset.Refresh(this);
Linkset.Refresh(this, true);
DetailLog("{0},BSPrim.UpdatePhysicalParameters,exit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}",
LocalID, IsStatic, IsSolid, _mass, SubscribedEvents(), CurrentCollisionFlags, BSBody, BSShape);
@ -620,8 +633,10 @@ public sealed class BSPrim : BSPhysObject
BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr);
// There can be special things needed for implementing linksets
Linkset.MakeStatic(this);
// The activation state is 'disabled' so Bullet will not try to act on it
// The activation state is 'disabled' so Bullet will not try to act on it.
BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.DISABLE_SIMULATION);
// Start it out sleeping and physical actions could wake it up.
// BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING);
BSBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter;
BSBody.collisionMask = CollisionFilterGroups.StaticObjectMask;
@ -638,6 +653,9 @@ public sealed class BSPrim : BSPhysObject
// per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
BulletSimAPI.ClearAllForces2(BSBody.ptr);
// For good measure, make sure the transform is set through to the motion state
BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
// A dynamic object has mass
IntPtr collisionShapePtr = BulletSimAPI.GetCollisionShape2(BSBody.ptr);
OMV.Vector3 inertia = BulletSimAPI.CalculateLocalInertia2(collisionShapePtr, Mass);
@ -655,8 +673,8 @@ public sealed class BSPrim : BSPhysObject
// Force activation of the object so Bullet will act on it.
// Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING);
BulletSimAPI.Activate2(BSBody.ptr, true);
BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG);
// BulletSimAPI.Activate2(BSBody.ptr, true);
BSBody.collisionFilter = CollisionFilterGroups.ObjectFilter;
BSBody.collisionMask = CollisionFilterGroups.ObjectMask;
@ -774,6 +792,15 @@ public sealed class BSPrim : BSPhysObject
});
}
}
public override OMV.Vector3 ForceRotationalVelocity {
get {
return _rotationalVelocity;
}
set {
_rotationalVelocity = value;
BulletSimAPI.SetAngularVelocity2(BSBody.ptr, _rotationalVelocity);
}
}
public override bool Kinematic {
get { return _kinematic; }
set { _kinematic = value;
@ -828,6 +855,9 @@ public sealed class BSPrim : BSPhysObject
private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>();
public override void AddForce(OMV.Vector3 force, bool pushforce) {
AddForce(force, pushforce, false);
}
public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
// for an object, doesn't matter if force is a pushforce or not
if (force.IsFinite())
{
@ -840,11 +870,12 @@ public sealed class BSPrim : BSPhysObject
m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
return;
}
PhysicsScene.TaintedObject("BSPrim.AddForce", delegate()
BSScene.TaintCallback addForceOperation = delegate()
{
OMV.Vector3 fSum = OMV.Vector3.Zero;
lock (m_accumulatedForces)
{
// Sum the accumulated additional forces for one big force to apply once.
foreach (OMV.Vector3 v in m_accumulatedForces)
{
fSum += v;
@ -854,7 +885,11 @@ public sealed class BSPrim : BSPhysObject
// DetailLog("{0},BSPrim.AddObjectForce,taint,force={1}", LocalID, fSum);
// For unknown reasons, "ApplyCentralForce" adds this force to the total force on the object.
BulletSimAPI.ApplyCentralForce2(BSBody.ptr, fSum);
});
};
if (inTaintTime)
addForceOperation();
else
PhysicsScene.TaintedObject("BSPrim.AddForce", addForceOperation);
}
public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
@ -1204,6 +1239,7 @@ public sealed class BSPrim : BSPhysObject
{
// Called if the current prim body is about to be destroyed.
// Remove all the physical dependencies on the old body.
// (Maybe someday make the changing of BSShape an event handled by BSLinkset.)
needToRestoreLinkset = Linkset.RemoveBodyDependencies(this);
});
@ -1294,6 +1330,8 @@ public sealed class BSPrim : BSPhysObject
PositionSanityCheck2(true);
Linkset.UpdateProperties(this);
DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
@ -1304,7 +1342,7 @@ public sealed class BSPrim : BSPhysObject
/*
else
{
// For debugging, we can also report the movement of children
// For debugging, report the movement of children
DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
entprop.Acceleration, entprop.RotationalVelocity);

View File

@ -39,7 +39,6 @@ using log4net;
using OpenMetaverse;
// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim)
// Move all logic out of the C++ code and into the C# code for easier future modifications.
// Test sculpties (verified that they don't work)
// Compute physics FPS reasonably
// Based on material, set density and friction
@ -90,10 +89,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// let my minuions use my logger
public ILog Logger { get { return m_log; } }
// If non-zero, the number of simulation steps between calls to the physics
// engine to output detailed physics stats. Debug logging level must be on also.
private int m_detailedStatsStep = 0;
public IMesher mesher;
// Level of Detail values kept as float because that's what the Meshmerizer wants
public float MeshLOD { get; private set; }
@ -112,6 +107,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
private float m_fixedTimeStep;
private long m_simulationStep = 0;
public long SimulationStep { get { return m_simulationStep; } }
private int m_taintsToProcessPerStep;
// A value of the time now so all the collision and update routines do not have to get their own
// Set to 'now' just before all the prims and actors are called for collisions and updates
@ -131,6 +127,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
public bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed
public bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes
public bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects
public float PID_D { get; private set; } // derivative
public float PID_P { get; private set; } // proportional
@ -254,7 +251,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// The bounding box for the simulated world. The origin is 0,0,0 unless we're
// a child in a mega-region.
// Turns out that Bullet really doesn't care about the extents of the simulated
// Bullet actually doesn't care about the extents of the simulated
// area. It tracks active objects no matter where they are.
Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
@ -331,7 +328,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// Called directly from unmanaged code so don't do much
private void BulletLoggerPhysLog(string msg)
{
PhysicsLogging.Write("[BULLETS UNMANAGED]:" + msg);
DetailLog("[BULLETS UNMANAGED]:" + msg);
}
public override void Dispose()
@ -494,8 +491,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
m_simulationStep++;
int numSubSteps = 0;
// Sometimes needed for debugging to find out what happened before the step
// PhysicsLogging.Flush();
// DEBUG
// DetailLog("{0},BSScene.Simulate,beforeStep,ntaimts={1},step={2}", DetailLogZero, numTaints, m_simulationStep);
try
{
@ -505,8 +502,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr);
if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime);
DetailLog("{0},Simulate,call, nTaints={1}, simTime={2}, substeps={3}, updates={4}, colliders={5}",
DetailLogZero, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount);
DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}",
DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount);
}
catch (Exception e)
{
@ -582,19 +579,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
}
}
// If enabled, call into the physics engine to dump statistics
if (m_detailedStatsStep > 0)
{
if ((m_simulationStep % m_detailedStatsStep) == 0)
{
BulletSimAPI.DumpBulletStatistics();
}
}
// The physics engine returns the number of milliseconds it simulated this call.
// These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
// Since Bullet normally does 5 or 6 substeps, this will normally sum to about 60 FPS.
return numSubSteps * m_fixedTimeStep * 1000;
// We multiply by 45 to give a recognizable running rate (45 or less).
return numSubSteps * m_fixedTimeStep * 1000 * 45;
// return timeStep * 1000 * 45;
}
// Something has collided
@ -617,7 +606,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
BSPhysObject collidee = null;
PhysObjects.TryGetValue(collidingWith, out collidee);
DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith);
// DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith);
if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration))
{
@ -703,6 +692,35 @@ public class BSScene : PhysicsScene, IPhysicsParameters
{
if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process
{
// swizzle a new list into the list location so we can process what's there
int taintCount = m_taintsToProcessPerStep;
TaintCallbackEntry oneCallback = new TaintCallbackEntry();
while (_taintedObjects.Count > 0 && taintCount-- > 0)
{
bool gotOne = false;
lock (_taintLock)
{
if (_taintedObjects.Count > 0)
{
oneCallback = _taintedObjects[0];
_taintedObjects.RemoveAt(0);
gotOne = true;
}
}
if (gotOne)
{
try
{
DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, oneCallback.ident); // DEBUG DEBUG DEBUG
oneCallback.callback();
}
catch (Exception e)
{
m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, oneCallback.ident, e);
}
}
}
/*
// swizzle a new list into the list location so we can process what's there
List<TaintCallbackEntry> oldList;
lock (_taintLock)
@ -715,6 +733,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
{
try
{
DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG
tcbe.callback();
}
catch (Exception e)
@ -723,6 +742,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
}
}
oldList.Clear();
*/
}
}
@ -834,6 +854,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
(s,cf,p,v) => { s.ShouldForceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); },
(s) => { return s.NumericBool(s.ShouldForceSimplePrimMeshing); },
(s,p,l,v) => { s.ShouldForceSimplePrimMeshing = s.BoolNumeric(v); } ),
new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects",
ConfigurationParameters.numericTrue,
(s,cf,p,v) => { s.ShouldUseHullsForPhysicalObjects = cf.GetBoolean(p, s.BoolNumeric(v)); },
(s) => { return s.NumericBool(s.ShouldUseHullsForPhysicalObjects); },
(s,p,l,v) => { s.ShouldUseHullsForPhysicalObjects = s.BoolNumeric(v); } ),
new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
8f,
@ -876,6 +901,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
(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("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step",
100f,
(s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); },
(s) => { return (float)s.m_taintsToProcessPerStep; },
(s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ),
new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
10000.01f,
(s,cf,p,v) => { s.MaximumObjectMass = cf.GetFloat(p, v); },
@ -1070,12 +1100,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
(s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; },
(s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ),
new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1",
0.1f,
0.001f,
(s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].linkConstraintCFM; },
(s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ),
new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2",
0.2f,
0.8f,
(s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].linkConstraintERP; },
(s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ),
@ -1085,11 +1115,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
(s) => { return s.m_params[0].linkConstraintSolverIterations; },
(s,p,l,v) => { s.m_params[0].linkConstraintSolverIterations = v; } ),
new ParameterDefn("DetailedStats", "Frames between outputting detailed phys stats. (0 is off)",
new ParameterDefn("LogPhysicsStatisticsFrames", "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; } ),
(s,cf,p,v) => { s.m_params[0].physicsLoggingFrames = cf.GetInt(p, (int)v); },
(s) => { return (float)s.m_params[0].physicsLoggingFrames; },
(s,p,l,v) => { s.m_params[0].physicsLoggingFrames = (int)v; } ),
};
// Convert a boolean to our numeric true and false values
@ -1270,6 +1300,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
public void DetailLog(string msg, params Object[] args)
{
PhysicsLogging.Write(msg, args);
// Add the Flush() if debugging crashes to get all the messages written out.
// PhysicsLogging.Flush();
}
// used to fill in the LocalID when there isn't one
public const string DetailLogZero = "0000000000";

View File

@ -67,8 +67,8 @@ public class BSShapeCollection : IDisposable
public DateTime lastReferenced;
}
private Dictionary<ulong, MeshDesc> Meshes = new Dictionary<ulong, MeshDesc>();
private Dictionary<ulong, HullDesc> Hulls = new Dictionary<ulong, HullDesc>();
private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>();
private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>();
private Dictionary<uint, BodyDesc> Bodies = new Dictionary<uint, BodyDesc>();
public BSShapeCollection(BSScene physScene)
@ -121,7 +121,7 @@ public class BSShapeCollection : IDisposable
// Track another user of a body
// We presume the caller has allocated the body.
// Bodies only have one user so the reference count is either 1 or 0.
public void ReferenceBody(BulletBody body, bool atTaintTime)
public void ReferenceBody(BulletBody body, bool inTaintTime)
{
lock (m_collectionActivityLock)
{
@ -136,7 +136,21 @@ public class BSShapeCollection : IDisposable
// New entry
bodyDesc.ptr = body.ptr;
bodyDesc.referenceCount = 1;
DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,ref={1}", body.ID, body, bodyDesc.referenceCount);
DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,ref={2}",
body.ID, body, bodyDesc.referenceCount);
BSScene.TaintCallback createOperation = delegate()
{
if (!BulletSimAPI.IsInWorld2(body.ptr))
{
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr);
DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}",
body.ID, body);
}
};
if (inTaintTime)
createOperation();
else
PhysicsScene.TaintedObject("BSShapeCollection.ReferenceBody", createOperation);
}
bodyDesc.lastReferenced = System.DateTime.Now;
Bodies[body.ID] = bodyDesc;
@ -160,21 +174,22 @@ public class BSShapeCollection : IDisposable
Bodies[body.ID] = bodyDesc;
DetailLog("{0},BSShapeCollection.DereferenceBody,ref={1}", body.ID, bodyDesc.referenceCount);
// If body is no longer being used, free it -- bodies are never shared.
// If body is no longer being used, free it -- bodies can never be shared.
if (bodyDesc.referenceCount == 0)
{
Bodies.Remove(body.ID);
BSScene.TaintCallback removeOperation = delegate()
{
DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}",
body.ID, body.ptr.ToString("X"));
DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}, inTaintTime={2}",
body.ID, body.ptr.ToString("X"), inTaintTime);
// If the caller needs to know the old body is going away, pass the event up.
if (bodyCallback != null) bodyCallback(body);
// Zero any reference to the shape so it is not freed when the body is deleted.
BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero);
// It may have already been removed from the world in which case the next is a NOOP.
BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr);
// Zero any reference to the shape so it is not freed when the body is deleted.
BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero);
BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr);
};
// If already in taint-time, do the operations now. Otherwise queue for later.
@ -208,7 +223,7 @@ public class BSShapeCollection : IDisposable
{
// There is an existing instance of this mesh.
meshDesc.referenceCount++;
DetailLog("{0},BSShapeColliction.ReferenceShape,existingMesh,key={1},cnt={2}",
DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}",
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
}
else
@ -217,7 +232,7 @@ public class BSShapeCollection : IDisposable
meshDesc.ptr = shape.ptr;
// We keep a reference to the underlying IMesh data so a hull can be built
meshDesc.referenceCount = 1;
DetailLog("{0},BSShapeColliction.ReferenceShape,newMesh,key={1},cnt={2}",
DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}",
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
ret = true;
}
@ -230,7 +245,7 @@ public class BSShapeCollection : IDisposable
{
// There is an existing instance of this hull.
hullDesc.referenceCount++;
DetailLog("{0},BSShapeColliction.ReferenceShape,existingHull,key={1},cnt={2}",
DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}",
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
}
else
@ -238,7 +253,7 @@ public class BSShapeCollection : IDisposable
// This is a new reference to a hull
hullDesc.ptr = shape.ptr;
hullDesc.referenceCount = 1;
DetailLog("{0},BSShapeColliction.ReferenceShape,newHull,key={1},cnt={2}",
DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}",
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
ret = true;
@ -257,7 +272,7 @@ public class BSShapeCollection : IDisposable
// Release the usage of a shape.
// The collisionObject is released since it is a copy of the real collision shape.
public void DereferenceShape(BulletShape shape, bool atTaintTime, ShapeDestructionCallback shapeCallback)
public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback)
{
if (shape.ptr == IntPtr.Zero)
return;
@ -279,14 +294,14 @@ public class BSShapeCollection : IDisposable
if (shape.ptr != IntPtr.Zero & shape.isNativeShape)
{
DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}",
BSScene.DetailLogZero, shape.ptr.ToString("X"), atTaintTime);
BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime);
if (shapeCallback != null) shapeCallback(shape);
BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr);
}
break;
}
};
if (atTaintTime)
if (inTaintTime)
{
lock (m_collectionActivityLock)
{
@ -358,7 +373,8 @@ public class BSShapeCollection : IDisposable
&& pbs.PathScaleX == 100 && pbs.PathScaleY == 100
&& pbs.PathShearX == 0 && pbs.PathShearY == 0) ) )
{
if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
&& pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)
{
haveShape = true;
if (forceRebuild
@ -372,7 +388,7 @@ public class BSShapeCollection : IDisposable
prim.LocalID, forceRebuild, prim.BSShape);
}
}
else
if (pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
{
haveShape = true;
if (forceRebuild
@ -392,7 +408,7 @@ public class BSShapeCollection : IDisposable
// made. Native shapes are best used in either case.
if (!haveShape)
{
if (prim.IsPhysical)
if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects)
{
// Update prim.BSShape to reference a hull of this shape.
ret = GetReferenceToHull(prim, shapeData, pbs, shapeCallback);
@ -426,7 +442,7 @@ public class BSShapeCollection : IDisposable
// Native shapes are always built independently.
newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType);
newShape.shapeKey = (ulong)shapeKey;
newShape.shapeKey = (System.UInt64)shapeKey;
newShape.isNativeShape = true;
// Don't need to do a 'ReferenceShape()' here because native shapes are not tracked.
@ -446,7 +462,7 @@ public class BSShapeCollection : IDisposable
BulletShape newShape = new BulletShape(IntPtr.Zero);
float lod;
ulong newMeshKey = ComputeShapeKey(shapeData, pbs, out lod);
System.UInt64 newMeshKey = ComputeShapeKey(shapeData, pbs, out lod);
// if this new shape is the same as last time, don't recreate the mesh
if (newMeshKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_MESH)
@ -469,7 +485,7 @@ public class BSShapeCollection : IDisposable
return true; // 'true' means a new shape has been added to this prim
}
private BulletShape CreatePhysicalMesh(string objName, ulong newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
{
IMesh meshData = null;
IntPtr meshPtr;
@ -516,7 +532,7 @@ public class BSShapeCollection : IDisposable
BulletShape newShape;
float lod;
ulong newHullKey = ComputeShapeKey(shapeData, pbs, out lod);
System.UInt64 newHullKey = ComputeShapeKey(shapeData, pbs, out lod);
// if the hull hasn't changed, don't rebuild it
if (newHullKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_HULL)
@ -525,7 +541,7 @@ public class BSShapeCollection : IDisposable
DetailLog("{0},BSShapeCollection.CreateGeomHull,create,oldKey={1},newKey={2}",
prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
// Remove usage of the previous shape. Also removes reference to underlying mesh if it is a hull.
// Remove usage of the previous shape.
DereferenceShape(prim.BSShape, true, shapeCallback);
newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod);
@ -539,7 +555,7 @@ public class BSShapeCollection : IDisposable
}
List<ConvexResult> m_hulls;
private BulletShape CreatePhysicalHull(string objName, ulong newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
{
IntPtr hullPtr;
@ -652,22 +668,23 @@ public class BSShapeCollection : IDisposable
// Create a hash of all the shape parameters to be used as a key
// for this particular shape.
private ulong ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs, out float retLod)
private System.UInt64 ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs, out float retLod)
{
// level of detail based on size and type of the object
float lod = PhysicsScene.MeshLOD;
if (pbs.SculptEntry)
lod = PhysicsScene.SculptLOD;
// Mega prims usually get more detail because one can interact with shape approximations at this size.
float maxAxis = Math.Max(shapeData.Size.X, Math.Max(shapeData.Size.Y, shapeData.Size.Z));
if (maxAxis > PhysicsScene.MeshMegaPrimThreshold)
lod = PhysicsScene.MeshMegaPrimLOD;
retLod = lod;
return (ulong)pbs.GetMeshKey(shapeData.Size, lod);
return pbs.GetMeshKey(shapeData.Size, lod);
}
// For those who don't want the LOD
private ulong ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs)
private System.UInt64 ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs)
{
float lod;
return ComputeShapeKey(shapeData, pbs, out lod);
@ -701,6 +718,7 @@ public class BSShapeCollection : IDisposable
if (mustRebuild || forceRebuild)
{
// Free any old body
DereferenceBody(prim.BSBody, true, bodyCallback);
BulletBody aBody;
@ -709,13 +727,13 @@ public class BSShapeCollection : IDisposable
{
bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr,
shapeData.ID, shapeData.Position, shapeData.Rotation);
// DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
}
else
{
bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr,
shapeData.ID, shapeData.Position, shapeData.Rotation);
// DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
}
aBody = new BulletBody(shapeData.ID, bodyPtr);
@ -731,7 +749,8 @@ public class BSShapeCollection : IDisposable
private void DetailLog(string msg, params Object[] args)
{
PhysicsScene.PhysicsLogging.Write(msg, args);
if (PhysicsScene.PhysicsLogging.Enabled)
PhysicsScene.DetailLog(msg, args);
}
}
}

View File

@ -114,6 +114,8 @@ public class BSTerrainManager
BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID,
Vector3.Zero, Quaternion.Identity));
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr);
// Ground plane does not move
BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION);
// Everything collides with the ground plane.
BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr,
(uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask);
@ -201,10 +203,10 @@ public class BSTerrainManager
// The 'doNow' boolean says whether to do all the unmanaged activities right now (like when
// calling this routine from initialization or taint-time routines) or whether to delay
// all the unmanaged activities to taint-time.
private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool atTaintTime)
private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
{
DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},atTaintTime={3}",
BSScene.DetailLogZero, minCoords, maxCoords, atTaintTime);
DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},inTaintTime={3}",
BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime);
float minZ = float.MaxValue;
float maxZ = float.MinValue;
@ -296,16 +298,16 @@ public class BSTerrainManager
mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, mapInfo.ID,
mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN);
// Create the terrain shape from the mapInfo
mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr),
ShapeData.PhysicsShapeType.SHAPE_TERRAIN);
// The terrain object initial position is at the center of the object
Vector3 centerPos;
centerPos.X = minCoords.X + (mapInfo.sizeX / 2f);
centerPos.Y = minCoords.Y + (mapInfo.sizeY / 2f);
centerPos.Z = minZ + ((maxZ - minZ) / 2f);
// Create the terrain shape from the mapInfo
mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr),
ShapeData.PhysicsShapeType.SHAPE_TERRAIN);
mapInfo.terrainBody = new BulletBody(mapInfo.ID,
BulletSimAPI.CreateBodyWithDefaultMotionState2(mapInfo.terrainShape.ptr,
id, centerPos, Quaternion.Identity));
@ -320,9 +322,6 @@ public class BSTerrainManager
BulletSimAPI.SetRestitution2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution);
BulletSimAPI.SetCollisionFlags2(mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
BulletSimAPI.SetMassProps2(mapInfo.terrainBody.ptr, 0f, Vector3.Zero);
BulletSimAPI.UpdateInertiaTensor2(mapInfo.terrainBody.ptr);
// Return the new terrain to the world of physical objects
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
@ -342,7 +341,7 @@ public class BSTerrainManager
// There is the option to do the changes now (we're already in 'taint time'), or
// to do the Bullet operations later.
if (atTaintTime)
if (inTaintTime)
rebuildOperation();
else
PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:UpdateExisting", rebuildOperation);
@ -381,7 +380,7 @@ public class BSTerrainManager
};
// If already in taint-time, just call Bullet. Otherwise queue the operations for the safe time.
if (atTaintTime)
if (inTaintTime)
createOperation();
else
PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:NewTerrain", createOperation);

View File

@ -101,9 +101,8 @@ public struct BulletShape
}
public IntPtr ptr;
public ShapeData.PhysicsShapeType type;
public ulong shapeKey;
public System.UInt64 shapeKey;
public bool isNativeShape;
// Hulls have an underlying mesh. A pointer to it is hidden here.
public override string ToString()
{
StringBuilder buff = new StringBuilder();
@ -192,8 +191,9 @@ public struct ShapeData
SHAPE_SPHERE = 5,
SHAPE_MESH = 6,
SHAPE_HULL = 7,
SHAPE_GROUNDPLANE = 8,
SHAPE_TERRAIN = 9,
// following defined by BulletSim
SHAPE_GROUNDPLANE = 20,
SHAPE_TERRAIN = 21,
};
public uint ID;
public PhysicsShapeType Type;
@ -305,6 +305,8 @@ public struct ConfigurationParameters
public float linkConstraintCFM;
public float linkConstraintSolverIterations;
public float physicsLoggingFrames;
public const float numericTrue = 1f;
public const float numericFalse = 0f;
}
@ -1036,18 +1038,6 @@ public static extern IntPtr GetConstraintRef2(IntPtr obj, int index);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern int GetNumConstraintRefs2(IntPtr obj);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern Vector3 GetDeltaLinearVelocity2(IntPtr obj);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern Vector3 GetDeltaAngularVelocity2(IntPtr obj);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern Vector3 GetPushVelocity2(IntPtr obj);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern Vector3 GetTurnVelocity2(IntPtr obj);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void SetCollisionFilterMask2(IntPtr body, uint filter, uint mask);
@ -1107,6 +1097,15 @@ public static extern float GetMargin2(IntPtr shape);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void DumpAllInfo2(IntPtr sim);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo);

View File

@ -100,7 +100,7 @@ namespace OpenSim.Region.Physics.OdePlugin
private bool m_hackSentFly = false;
private int m_requestedUpdateFrequency = 0;
private Vector3 m_taintPosition;
internal bool m_avatarplanted = false;
/// <summary>
/// Hold set forces so we can process them outside physics calculations. This prevents race conditions if we set force
/// while calculatios are going on
@ -413,7 +413,7 @@ namespace OpenSim.Region.Physics.OdePlugin
set
{
m_iscollidingObj = value;
if (value)
if (value && !m_avatarplanted)
m_pidControllerActive = false;
else
m_pidControllerActive = true;

View File

@ -501,6 +501,8 @@ namespace OpenSim.Region.Physics.OdePlugin
public int physics_logging_interval = 0;
public bool physics_logging_append_existing_logfile = false;
private bool avplanted = false;
private bool av_av_collisions_off = false;
public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f);
public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f);
@ -644,6 +646,9 @@ namespace OpenSim.Region.Physics.OdePlugin
avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", 1.3f);
avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", 0.8f);
avCapRadius = physicsconfig.GetFloat("av_capsule_radius", 0.37f);
avplanted = physicsconfig.GetBoolean("av_planted", false);
av_av_collisions_off = physicsconfig.GetBoolean("av_av_collisions_off", false);
IsAvCapsuleTilted = physicsconfig.GetBoolean("av_capsule_tilted", false);
contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80);
@ -663,6 +668,8 @@ namespace OpenSim.Region.Physics.OdePlugin
meshSculptLOD = physicsconfig.GetFloat("mesh_lod", 32f);
MeshSculptphysicalLOD = physicsconfig.GetFloat("mesh_physical_lod", 16f);
m_filterCollisions = physicsconfig.GetBoolean("filter_collisions", false);
if (Environment.OSVersion.Platform == PlatformID.Unix)
{
@ -1309,6 +1316,10 @@ namespace OpenSim.Region.Physics.OdePlugin
if ((p1 is OdePrim) && (((OdePrim)p1).m_isVolumeDetect))
skipThisContact = true; // No collision on volume detect prims
if (av_av_collisions_off)
if ((p1 is OdeCharacter) && (p2 is OdeCharacter))
skipThisContact = true;
if (!skipThisContact && (p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect))
skipThisContact = true; // No collision on volume detect prims
@ -1972,7 +1983,8 @@ namespace OpenSim.Region.Physics.OdePlugin
newAv.Flying = isFlying;
newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset;
newAv.m_avatarplanted = avplanted;
return newAv;
}
@ -1987,6 +1999,7 @@ namespace OpenSim.Region.Physics.OdePlugin
internal void AddCharacter(OdeCharacter chr)
{
chr.m_avatarplanted = avplanted;
if (!_characters.Contains(chr))
{
_characters.Add(chr);

View File

@ -3600,7 +3600,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
/// <returns></returns>
public void osSetContentType(LSL_Key id, string type)
{
CheckThreatLevel(ThreatLevel.High,"osSetResponseType");
CheckThreatLevel(ThreatLevel.High, "osSetContentType");
if (m_UrlModule != null)
m_UrlModule.HttpContentType(new UUID(id),type);
}
@ -3611,7 +3612,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
/// <returns>boolean indicating whether an error was shouted.</returns>
protected bool ShoutErrorOnLackingOwnerPerms(int perms, string errorPrefix)
{
CheckThreatLevel(ThreatLevel.Moderate, "osDropAttachment");
m_host.AddScriptLPS(1);
bool fail = false;
if (m_item.PermsGranter != m_host.OwnerID)

View File

@ -60,7 +60,25 @@ namespace OpenSim.Server
}
string connList = serverConfig.GetString("ServiceConnectors", String.Empty);
string[] conns = connList.Split(new char[] {',', ' '});
IConfig servicesConfig = m_Server.Config.Configs["ServiceList"];
if (servicesConfig != null)
{
List<string> servicesList = new List<string>();
if (connList != String.Empty)
servicesList.Add(connList);
foreach (string k in servicesConfig.GetKeys())
{
string v = servicesConfig.GetString(k);
if (v != String.Empty)
servicesList.Add(v);
}
connList = String.Join(",", servicesList.ToArray());
}
string[] conns = connList.Split(new char[] {',', ' ', '\n', '\r', '\t'});
// int i = 0;
foreach (string c in conns)
@ -130,4 +148,4 @@ namespace OpenSim.Server
return 0;
}
}
}
}

View File

@ -395,8 +395,8 @@ namespace OpenSim.Services.Connectors.SimianGrid
if (response["Success"].AsBoolean())
{
OSDMap extraData = response["ExtraData"] as OSDMap;
int enabled = response["Enabled"].AsBoolean() ? (int) OpenSim.Data.RegionFlags.RegionOnline : 0;
int hypergrid = extraData["HyperGrid"].AsBoolean() ? (int) OpenSim.Data.RegionFlags.Hyperlink : 0;
int enabled = response["Enabled"].AsBoolean() ? (int)OpenSim.Framework.RegionFlags.RegionOnline : 0;
int hypergrid = extraData["HyperGrid"].AsBoolean() ? (int)OpenSim.Framework.RegionFlags.Hyperlink : 0;
int flags = enabled | hypergrid;
m_log.DebugFormat("[SGGC] enabled - {0} hg - {1} flags - {2}", enabled, hypergrid, flags);
return flags;

View File

@ -151,11 +151,11 @@ namespace OpenSim.Services.GridService
//
// Get it's flags
//
OpenSim.Data.RegionFlags rflags = (OpenSim.Data.RegionFlags)Convert.ToInt32(region.Data["flags"]);
OpenSim.Framework.RegionFlags rflags = (OpenSim.Framework.RegionFlags)Convert.ToInt32(region.Data["flags"]);
// Is this a reservation?
//
if ((rflags & OpenSim.Data.RegionFlags.Reservation) != 0)
if ((rflags & OpenSim.Framework.RegionFlags.Reservation) != 0)
{
// Regions reserved for the null key cannot be taken.
if ((string)region.Data["PrincipalID"] == UUID.Zero.ToString())
@ -166,10 +166,10 @@ namespace OpenSim.Services.GridService
// NOTE: Fudging the flags value here, so these flags
// should not be used elsewhere. Don't optimize
// this with the later retrieval of the same flags!
rflags |= OpenSim.Data.RegionFlags.Authenticate;
rflags |= OpenSim.Framework.RegionFlags.Authenticate;
}
if ((rflags & OpenSim.Data.RegionFlags.Authenticate) != 0)
if ((rflags & OpenSim.Framework.RegionFlags.Authenticate) != 0)
{
// Can we authenticate at all?
//
@ -205,10 +205,10 @@ namespace OpenSim.Services.GridService
if ((region != null) && (region.RegionID == regionInfos.RegionID) &&
((region.posX != regionInfos.RegionLocX) || (region.posY != regionInfos.RegionLocY)))
{
if ((Convert.ToInt32(region.Data["flags"]) & (int)OpenSim.Data.RegionFlags.NoMove) != 0)
if ((Convert.ToInt32(region.Data["flags"]) & (int)OpenSim.Framework.RegionFlags.NoMove) != 0)
return "Can't move this region";
if ((Convert.ToInt32(region.Data["flags"]) & (int)OpenSim.Data.RegionFlags.LockedOut) != 0)
if ((Convert.ToInt32(region.Data["flags"]) & (int)OpenSim.Framework.RegionFlags.LockedOut) != 0)
return "Region locked out";
// Region reregistering in other coordinates. Delete the old entry
@ -233,7 +233,7 @@ namespace OpenSim.Services.GridService
{
int oldFlags = Convert.ToInt32(region.Data["flags"]);
oldFlags &= ~(int)OpenSim.Data.RegionFlags.Reservation;
oldFlags &= ~(int)OpenSim.Framework.RegionFlags.Reservation;
rdata.Data["flags"] = oldFlags.ToString(); // Preserve flags
}
@ -252,7 +252,7 @@ namespace OpenSim.Services.GridService
}
int flags = Convert.ToInt32(rdata.Data["flags"]);
flags |= (int)OpenSim.Data.RegionFlags.RegionOnline;
flags |= (int)OpenSim.Framework.RegionFlags.RegionOnline;
rdata.Data["flags"] = flags.ToString();
try
@ -283,9 +283,9 @@ namespace OpenSim.Services.GridService
int flags = Convert.ToInt32(region.Data["flags"]);
if (!m_DeleteOnUnregister || (flags & (int)OpenSim.Data.RegionFlags.Persistent) != 0)
if (!m_DeleteOnUnregister || (flags & (int)OpenSim.Framework.RegionFlags.Persistent) != 0)
{
flags &= ~(int)OpenSim.Data.RegionFlags.RegionOnline;
flags &= ~(int)OpenSim.Framework.RegionFlags.RegionOnline;
region.Data["flags"] = flags.ToString();
region.Data["last_seen"] = Util.UnixTimeSinceEpoch();
try
@ -320,7 +320,7 @@ namespace OpenSim.Services.GridService
if (rdata.RegionID != regionID)
{
int flags = Convert.ToInt32(rdata.Data["flags"]);
if ((flags & (int)Data.RegionFlags.Hyperlink) == 0) // no hyperlinks as neighbours
if ((flags & (int)Framework.RegionFlags.Hyperlink) == 0) // no hyperlinks as neighbours
rinfos.Add(RegionData2RegionInfo(rdata));
}
}
@ -470,7 +470,7 @@ namespace OpenSim.Services.GridService
foreach (RegionData r in regions)
{
if ((Convert.ToInt32(r.Data["flags"]) & (int)OpenSim.Data.RegionFlags.RegionOnline) != 0)
if ((Convert.ToInt32(r.Data["flags"]) & (int)OpenSim.Framework.RegionFlags.RegionOnline) != 0)
ret.Add(RegionData2RegionInfo(r));
}
@ -486,7 +486,7 @@ namespace OpenSim.Services.GridService
foreach (RegionData r in regions)
{
if ((Convert.ToInt32(r.Data["flags"]) & (int)OpenSim.Data.RegionFlags.RegionOnline) != 0)
if ((Convert.ToInt32(r.Data["flags"]) & (int)OpenSim.Framework.RegionFlags.RegionOnline) != 0)
ret.Add(RegionData2RegionInfo(r));
}
@ -502,7 +502,7 @@ namespace OpenSim.Services.GridService
foreach (RegionData r in regions)
{
if ((Convert.ToInt32(r.Data["flags"]) & (int)OpenSim.Data.RegionFlags.RegionOnline) != 0)
if ((Convert.ToInt32(r.Data["flags"]) & (int)OpenSim.Framework.RegionFlags.RegionOnline) != 0)
ret.Add(RegionData2RegionInfo(r));
}
@ -629,7 +629,7 @@ namespace OpenSim.Services.GridService
private void OutputRegionToConsole(RegionData r)
{
OpenSim.Data.RegionFlags flags = (OpenSim.Data.RegionFlags)Convert.ToInt32(r.Data["flags"]);
OpenSim.Framework.RegionFlags flags = (OpenSim.Framework.RegionFlags)Convert.ToInt32(r.Data["flags"]);
ConsoleDisplayList dispList = new ConsoleDisplayList();
dispList.AddRow("Region Name", r.RegionName);
@ -659,7 +659,7 @@ namespace OpenSim.Services.GridService
foreach (RegionData r in regions)
{
OpenSim.Data.RegionFlags flags = (OpenSim.Data.RegionFlags)Convert.ToInt32(r.Data["flags"]);
OpenSim.Framework.RegionFlags flags = (OpenSim.Framework.RegionFlags)Convert.ToInt32(r.Data["flags"]);
dispTable.AddRow(
r.RegionName,
r.RegionID.ToString(),
@ -673,7 +673,7 @@ namespace OpenSim.Services.GridService
private int ParseFlags(int prev, string flags)
{
OpenSim.Data.RegionFlags f = (OpenSim.Data.RegionFlags)prev;
OpenSim.Framework.RegionFlags f = (OpenSim.Framework.RegionFlags)prev;
string[] parts = flags.Split(new char[] {',', ' '}, StringSplitOptions.RemoveEmptyEntries);
@ -685,18 +685,18 @@ namespace OpenSim.Services.GridService
{
if (p.StartsWith("+"))
{
val = (int)Enum.Parse(typeof(OpenSim.Data.RegionFlags), p.Substring(1));
f |= (OpenSim.Data.RegionFlags)val;
val = (int)Enum.Parse(typeof(OpenSim.Framework.RegionFlags), p.Substring(1));
f |= (OpenSim.Framework.RegionFlags)val;
}
else if (p.StartsWith("-"))
{
val = (int)Enum.Parse(typeof(OpenSim.Data.RegionFlags), p.Substring(1));
f &= ~(OpenSim.Data.RegionFlags)val;
val = (int)Enum.Parse(typeof(OpenSim.Framework.RegionFlags), p.Substring(1));
f &= ~(OpenSim.Framework.RegionFlags)val;
}
else
{
val = (int)Enum.Parse(typeof(OpenSim.Data.RegionFlags), p);
f |= (OpenSim.Data.RegionFlags)val;
val = (int)Enum.Parse(typeof(OpenSim.Framework.RegionFlags), p);
f |= (OpenSim.Framework.RegionFlags)val;
}
}
catch (Exception)
@ -728,7 +728,7 @@ namespace OpenSim.Services.GridService
int flags = Convert.ToInt32(r.Data["flags"]);
flags = ParseFlags(flags, cmd[4]);
r.Data["flags"] = flags.ToString();
OpenSim.Data.RegionFlags f = (OpenSim.Data.RegionFlags)flags;
OpenSim.Framework.RegionFlags f = (OpenSim.Framework.RegionFlags)flags;
MainConsole.Instance.Output(String.Format("Set region {0} to {1}", r.RegionName, f));
m_Database.Store(r);

View File

@ -390,8 +390,8 @@ namespace OpenSim.Services.GridService
List<RegionData> regions = m_Database.Get(mapName, m_ScopeID);
if (regions != null && regions.Count > 0)
{
OpenSim.Data.RegionFlags rflags = (OpenSim.Data.RegionFlags)Convert.ToInt32(regions[0].Data["flags"]);
if ((rflags & OpenSim.Data.RegionFlags.Hyperlink) != 0)
OpenSim.Framework.RegionFlags rflags = (OpenSim.Framework.RegionFlags)Convert.ToInt32(regions[0].Data["flags"]);
if ((rflags & OpenSim.Framework.RegionFlags.Hyperlink) != 0)
{
regInfo = new GridRegion();
regInfo.RegionID = regions[0].RegionID;
@ -460,7 +460,7 @@ namespace OpenSim.Services.GridService
private void AddHyperlinkRegion(GridRegion regionInfo, ulong regionHandle)
{
RegionData rdata = m_GridService.RegionInfo2RegionData(regionInfo);
int flags = (int)OpenSim.Data.RegionFlags.Hyperlink + (int)OpenSim.Data.RegionFlags.NoDirectLogin + (int)OpenSim.Data.RegionFlags.RegionOnline;
int flags = (int)OpenSim.Framework.RegionFlags.Hyperlink + (int)OpenSim.Framework.RegionFlags.NoDirectLogin + (int)OpenSim.Framework.RegionFlags.RegionOnline;
rdata.Data["flags"] = flags.ToString();
m_Database.Store(rdata);

View File

@ -100,6 +100,19 @@ namespace OpenSim.Services.Interfaces
List<GridRegion> GetFallbackRegions(UUID scopeID, int x, int y);
List<GridRegion> GetHyperlinks(UUID scopeID);
/// <summary>
/// Get internal OpenSimulator region flags.
/// </summary>
/// <remarks>
/// See OpenSimulator.Framework.RegionFlags. These are not returned in the GridRegion structure -
/// they currently need to be requested separately. Possibly this should change to avoid multiple service calls
/// in some situations.
/// </remarks>
/// <returns>
/// The region flags.
/// </returns>
/// <param name='scopeID'></param>
/// <param name='regionID'></param>
int GetRegionFlags(UUID scopeID, UUID regionID);
}

View File

@ -840,6 +840,15 @@
; When the avatar flies, it will be moved up by this amount off the ground (in meters)
minimum_ground_flight_offset = 3.0
; Plant avatar. This reduces the effect of physical contacts with the avatar.
; If you have a group of unruly and rude visitors that bump each other, turn this on to make that less attractive.
; The avatar still allows a small movement based on the PID settings above. Stronger PID settings AND this active
; will lock the avatar in place
av_planted = false
; No Avatar Avatar Collissions. This causes avatar to be able to walk through each other as if they're ghosts but still interact with the environment
av_av_collisions_off = false
; ##
; ## Object options
; ##

View File

@ -21,7 +21,38 @@
; * [[<ConfigName>@]<port>/]<dll name>[:<class name>]
; *
[Startup]
ServiceConnectors = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector,8003/OpenSim.Server.Handlers.dll:XInventoryInConnector,8004/OpenSim.Server.Handlers.dll:FreeswitchServerConnector,8003/OpenSim.Server.Handlers.dll:GridServiceConnector,8002/OpenSim.Server.Handlers.dll:GridInfoServerInConnector,8003/OpenSim.Server.Handlers.dll:AuthenticationServiceConnector,8002/OpenSim.Server.Handlers.dll:OpenIdServerConnector,8003/OpenSim.Server.Handlers.dll:AvatarServiceConnector,8002/OpenSim.Server.Handlers.dll:LLLoginServiceInConnector,8003/OpenSim.Server.Handlers.dll:PresenceServiceConnector,8003/OpenSim.Server.Handlers.dll:UserAccountServiceConnector,8003/OpenSim.Server.Handlers.dll:GridUserServiceConnector,8003/OpenSim.Server.Handlers.dll:FriendsServiceConnector,8002/OpenSim.Server.Handlers.dll:GatekeeperServiceInConnector,8002/OpenSim.Server.Handlers.dll:UserAgentServerConnector,HGInventoryService@8002/OpenSim.Server.Handlers.dll:XInventoryInConnector,HGAssetService@8002/OpenSim.Server.Handlers.dll:AssetServiceConnector,8002/OpenSim.Server.Handlers.dll:HeloServiceInConnector,8002/OpenSim.Server.Handlers.dll:HGFriendsServerConnector,8002/OpenSim.Server.Handlers.dll:InstantMessageServerConnector,8003/OpenSim.Server.Handlers.dll:MapAddServiceConnector,8002/OpenSim.Server.Handlers.dll:MapGetServiceConnector"
[ServiceList]
AssetServiceConnector = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector"
InventoryInConnector = "8003/OpenSim.Server.Handlers.dll:XInventoryInConnector"
VoiceConnector = "8004/OpenSim.Server.Handlers.dll:FreeswitchServerConnector"
GridServiceConnector = "8003/OpenSim.Server.Handlers.dll:GridServiceConnector"
GridInfoServerInConnector = "8002/OpenSim.Server.Handlers.dll:GridInfoServerInConnector"
AuthenticationServiceConnector = "8003/OpenSim.Server.Handlers.dll:AuthenticationServiceConnector"
OpenIdServerConnector = "8002/OpenSim.Server.Handlers.dll:OpenIdServerConnector"
AvatarServiceConnector = "8003/OpenSim.Server.Handlers.dll:AvatarServiceConnector"
LLLoginServiceInConnector = "8002/OpenSim.Server.Handlers.dll:LLLoginServiceInConnector"
PresenceServiceConnector = "8003/OpenSim.Server.Handlers.dll:PresenceServiceConnector"
UserAccountServiceConnector = "8003/OpenSim.Server.Handlers.dll:UserAccountServiceConnector"
GridUserServiceConnector = "8003/OpenSim.Server.Handlers.dll:GridUserServiceConnector"
FriendsServiceConnector = "8003/OpenSim.Server.Handlers.dll:FriendsServiceConnector"
MapAddServiceConnector = "8003/OpenSim.Server.Handlers.dll:MapAddServiceConnector"
MapGetServiceConnector = "8002/OpenSim.Server.Handlers.dll:MapGetServiceConnector"
;; Additions for Hypergrid
GatekeeperServiceInConnector = "8002/OpenSim.Server.Handlers.dll:GatekeeperServiceInConnector"
UserAgentServerConnector = "8002/OpenSim.Server.Handlers.dll:UserAgentServerConnector"
HeloServiceInConnector = "8002/OpenSim.Server.Handlers.dll:HeloServiceInConnector"
HGFriendsServerConnector = "8002/OpenSim.Server.Handlers.dll:HGFriendsServerConnector"
InstantMessageServerConnector = "8002/OpenSim.Server.Handlers.dll:InstantMessageServerConnector"
HGInventoryServiceConnector = "HGInventoryService@8002/OpenSim.Server.Handlers.dll:XInventoryInConnector"
HGAssetServiceConnector = "HGAssetService@8002/OpenSim.Server.Handlers.dll:AssetServiceConnector"
;; Additions for other add-on modules. For example:
;; WifiServerConnector = "8002/Diva.Wifi.dll:WifiServerConnector"
; * This is common for all services, it's the network setup for the entire
; * server instance, if none is specified above

View File

@ -13,7 +13,23 @@
; * [[<ConfigName>@]<port>/]<dll name>[:<class name>]
; *
[Startup]
ServiceConnectors = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector,8003/OpenSim.Server.Handlers.dll:XInventoryInConnector,8004/OpenSim.Server.Handlers.dll:FreeswitchServerConnector,8003/OpenSim.Server.Handlers.dll:GridServiceConnector,8002/OpenSim.Server.Handlers.dll:GridInfoServerInConnector,8003/OpenSim.Server.Handlers.dll:AuthenticationServiceConnector,8002/OpenSim.Server.Handlers.dll:OpenIdServerConnector,8003/OpenSim.Server.Handlers.dll:AvatarServiceConnector,8002/OpenSim.Server.Handlers.dll:LLLoginServiceInConnector,8003/OpenSim.Server.Handlers.dll:PresenceServiceConnector,8003/OpenSim.Server.Handlers.dll:UserAccountServiceConnector,8003/OpenSim.Server.Handlers.dll:GridUserServiceConnector,8003/OpenSim.Server.Handlers.dll:FriendsServiceConnector,8003/OpenSim.Server.Handlers.dll:MapAddServiceConnector,8002/OpenSim.Server.Handlers.dll:MapGetServiceConnector"
[ServiceList]
AssetServiceConnector = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector"
InventoryInConnector = "8003/OpenSim.Server.Handlers.dll:XInventoryInConnector"
VoiceConnector = "8004/OpenSim.Server.Handlers.dll:FreeswitchServerConnector"
GridServiceConnector = "8003/OpenSim.Server.Handlers.dll:GridServiceConnector"
GridInfoServerInConnector = "8002/OpenSim.Server.Handlers.dll:GridInfoServerInConnector"
AuthenticationServiceConnector = "8003/OpenSim.Server.Handlers.dll:AuthenticationServiceConnector"
OpenIdServerConnector = "8002/OpenSim.Server.Handlers.dll:OpenIdServerConnector"
AvatarServiceConnector = "8003/OpenSim.Server.Handlers.dll:AvatarServiceConnector"
LLLoginServiceInConnector = "8002/OpenSim.Server.Handlers.dll:LLLoginServiceInConnector"
PresenceServiceConnector = "8003/OpenSim.Server.Handlers.dll:PresenceServiceConnector"
UserAccountServiceConnector = "8003/OpenSim.Server.Handlers.dll:UserAccountServiceConnector"
GridUserServiceConnector = "8003/OpenSim.Server.Handlers.dll:GridUserServiceConnector"
FriendsServiceConnector = "8003/OpenSim.Server.Handlers.dll:FriendsServiceConnector"
MapAddServiceConnector = "8003/OpenSim.Server.Handlers.dll:MapAddServiceConnector"
MapGetServiceConnector = "8002/OpenSim.Server.Handlers.dll:MapGetServiceConnector"
; * This is common for all services, it's the network setup for the entire
; * server instance, if none is specified above

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -112,6 +112,34 @@
</Files>
</Project>
<Project frameworkVersion="v3_5" name="OpenSim.Services.Interfaces" path="OpenSim/Services/Interfaces" type="Library">
<Configuration name="Debug">
<Options>
<OutputPath>../../../bin/</OutputPath>
</Options>
</Configuration>
<Configuration name="Release">
<Options>
<OutputPath>../../../bin/</OutputPath>
</Options>
</Configuration>
<ReferencePath>../../../bin/</ReferencePath>
<Reference name="System"/>
<Reference name="OpenMetaverseTypes" path="../../../bin/"/>
<Reference name="OpenMetaverse" path="../../../bin/"/>
<Reference name="OpenMetaverse.StructuredData" path="../../../bin/"/>
<Reference name="OpenSim.Framework"/>
<Reference name="OpenSim.Framework.Console"/>
<Reference name="OpenSim.Framework.Servers.HttpServer"/>
<Reference name="Nini" path="../../../bin/"/>
<Reference name="log4net" path="../../../bin/"/>
<Files>
<Match pattern="*.cs" recurse="true"/>
</Files>
</Project>
<Project frameworkVersion="v3_5" name="OpenSim.Framework.Monitoring" path="OpenSim/Framework/Monitoring" type="Library">
<Configuration name="Debug">
<Options>
@ -206,34 +234,6 @@
</Files>
</Project>
<Project frameworkVersion="v3_5" name="OpenSim.Services.Interfaces" path="OpenSim/Services/Interfaces" type="Library">
<Configuration name="Debug">
<Options>
<OutputPath>../../../bin/</OutputPath>
</Options>
</Configuration>
<Configuration name="Release">
<Options>
<OutputPath>../../../bin/</OutputPath>
</Options>
</Configuration>
<ReferencePath>../../../bin/</ReferencePath>
<Reference name="System"/>
<Reference name="OpenMetaverseTypes" path="../../../bin/"/>
<Reference name="OpenMetaverse" path="../../../bin/"/>
<Reference name="OpenMetaverse.StructuredData" path="../../../bin/"/>
<Reference name="OpenSim.Framework"/>
<Reference name="OpenSim.Framework.Console"/>
<Reference name="OpenSim.Framework.Servers.HttpServer"/>
<Reference name="Nini" path="../../../bin/"/>
<Reference name="log4net" path="../../../bin/"/>
<Files>
<Match pattern="*.cs" recurse="true"/>
</Files>
</Project>
<Project frameworkVersion="v3_5" name="OpenSim.Framework.Serialization" path="OpenSim/Framework/Serialization" type="Library">
<Configuration name="Debug">
<Options>