diff --git a/OpenSim/Framework/AvatarAppearance.cs b/OpenSim/Framework/AvatarAppearance.cs
index 4f598b04ae..95e9667f6b 100644
--- a/OpenSim/Framework/AvatarAppearance.cs
+++ b/OpenSim/Framework/AvatarAppearance.cs
@@ -330,6 +330,9 @@ namespace OpenSim.Framework
SetVisualParams(visualParams);
}
+ ///
+ /// Set avatar height by a calculation based on their visual parameters.
+ ///
public virtual void SetHeight()
{
// Start with shortest possible female avatar height
diff --git a/OpenSim/Framework/Client/IClientChat.cs b/OpenSim/Framework/Client/IClientChat.cs
index 078ea9b668..86b1faa8f6 100644
--- a/OpenSim/Framework/Client/IClientChat.cs
+++ b/OpenSim/Framework/Client/IClientChat.cs
@@ -33,7 +33,8 @@ namespace OpenSim.Framework.Client
{
event ChatMessage OnChatFromClient;
- void SendChatMessage(string message, byte type, Vector3 fromPos, string fromName, UUID fromAgentID, byte source,
- byte audible);
+ void SendChatMessage(
+ string message, byte type, Vector3 fromPos, string fromName, UUID fromAgentID, UUID ownerID, byte source,
+ byte audible);
}
-}
+}
\ No newline at end of file
diff --git a/OpenSim/Framework/Console/ConsoleUtil.cs b/OpenSim/Framework/Console/ConsoleUtil.cs
index a7cf0c03b2..16a63e0ca5 100644
--- a/OpenSim/Framework/Console/ConsoleUtil.cs
+++ b/OpenSim/Framework/Console/ConsoleUtil.cs
@@ -27,88 +27,202 @@
using System;
using System.Collections.Generic;
+using System.IO;
using System.Linq;
using System.Reflection;
using log4net;
using OpenMetaverse;
-public class ConsoleUtil
+namespace OpenSim.Framework.Console
{
-// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
-
- public const string MinRawConsoleVectorValue = "-~";
- public const string MaxRawConsoleVectorValue = "~";
-
- public const string VectorSeparator = ",";
- public static char[] VectorSeparatorChars = VectorSeparator.ToCharArray();
-
- ///
- /// Convert a minimum vector input from the console to an OpenMetaverse.Vector3
- ///
- /// /param>
- ///
- ///
- public static bool TryParseConsoleMinVector(string rawConsoleVector, out Vector3 vector)
+ public class ConsoleUtil
{
- return TryParseConsoleVector(rawConsoleVector, c => float.MinValue.ToString(), out vector);
- }
+ // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
- ///
- /// Convert a maximum vector input from the console to an OpenMetaverse.Vector3
- ///
- /// /param>
- ///
- ///
- public static bool TryParseConsoleMaxVector(string rawConsoleVector, out Vector3 vector)
- {
- return TryParseConsoleVector(rawConsoleVector, c => float.MaxValue.ToString(), out vector);
- }
+ public const int LocalIdNotFound = 0;
+
+ ///
+ /// Used by modules to display stock co-ordinate help, though possibly this should be under some general section
+ /// rather than in each help summary.
+ ///
+ public const string CoordHelp
+ = @"Each component of the coord is comma separated. There must be no spaces between the commas.
+ If you don't care about the z component you can simply omit it.
+ If you don't care about the x or y components then you can leave them blank (though a comma is still required)
+ If you want to specify the maxmimum value of a component then you can use ~ instead of a number
+ If you want to specify the minimum value of a component then you can use -~ instead of a number
+ e.g.
+ delete object pos 20,20,20 to 40,40,40
+ delete object pos 20,20 to 40,40
+ delete object pos ,20,20 to ,40,40
+ delete object pos ,,30 to ,,~
+ delete object pos ,,-~ to ,,30";
+
+ public const string MinRawConsoleVectorValue = "-~";
+ public const string MaxRawConsoleVectorValue = "~";
+
+ public const string VectorSeparator = ",";
+ public static char[] VectorSeparatorChars = VectorSeparator.ToCharArray();
- ///
- /// Convert a vector input from the console to an OpenMetaverse.Vector3
- ///
- ///
- /// A string in the form ,, where there is no space between values.
- /// Any component can be missing (e.g. ,,40). blankComponentFunc is invoked to replace the blank with a suitable value
- /// Also, if the blank component is at the end, then the comma can be missed off entirely (e.g. 40,30 or 40)
- /// The strings "~" and "-~" are valid in components. The first substitutes float.MaxValue whilst the second is float.MinValue
- /// Other than that, component values must be numeric.
- ///
- ///
- ///
- ///
- public static bool TryParseConsoleVector(
- string rawConsoleVector, Func blankComponentFunc, out Vector3 vector)
- {
- List components = rawConsoleVector.Split(VectorSeparatorChars).ToList();
-
- if (components.Count < 1 || components.Count > 3)
+ ///
+ /// Check if the given file path exists.
+ ///
+ /// If not, warning is printed to the given console.
+ /// true if the file does not exist, false otherwise.
+ ///
+ ///
+ public static bool CheckFileDoesNotExist(ICommandConsole console, string path)
{
- vector = Vector3.Zero;
- return false;
+ if (File.Exists(path))
+ {
+ console.OutputFormat("File {0} already exists. Please move or remove it.", path);
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Try to parse a console UUID from the console.
+ ///
+ ///
+ /// Will complain to the console if parsing fails.
+ ///
+ ///
+ /// If null then no complaint is printed.
+ ///
+ ///
+ public static bool TryParseConsoleUuid(ICommandConsole console, string rawUuid, out UUID uuid)
+ {
+ if (!UUID.TryParse(rawUuid, out uuid))
+ {
+ if (console != null)
+ console.OutputFormat("{0} is not a valid uuid", rawUuid);
+
+ return false;
+ }
+
+ return true;
}
- for (int i = components.Count; i < 3; i++)
- components.Add("");
+ public static bool TryParseConsoleLocalId(ICommandConsole console, string rawLocalId, out uint localId)
+ {
+ if (!uint.TryParse(rawLocalId, out localId))
+ {
+ if (console != null)
+ console.OutputFormat("{0} is not a valid local id", localId);
- List semiDigestedComponents
- = components.ConvertAll(
- c =>
- {
- if (c == "")
- return blankComponentFunc.Invoke(c);
- else if (c == MaxRawConsoleVectorValue)
- return float.MaxValue.ToString();
- else if (c == MinRawConsoleVectorValue)
- return float.MinValue.ToString();
- else
- return c;
- });
+ return false;
+ }
- string semiDigestedConsoleVector = string.Join(VectorSeparator, semiDigestedComponents.ToArray());
+ if (localId == 0)
+ {
+ if (console != null)
+ console.OutputFormat("{0} is not a valid local id - it must be greater than 0", localId);
-// m_log.DebugFormat("[CONSOLE UTIL]: Parsing {0} into OpenMetaverse.Vector3", semiDigestedConsoleVector);
+ return false;
+ }
- return Vector3.TryParse(semiDigestedConsoleVector, out vector);
+ return true;
+ }
+
+ ///
+ /// Tries to parse the input as either a UUID or a local ID.
+ ///
+ /// true if parsing succeeded, false otherwise.
+ ///
+ ///
+ ///
+ ///
+ /// Will be set to ConsoleUtil.LocalIdNotFound if parsing result was a UUID or no parse succeeded.
+ ///
+ public static bool TryParseConsoleId(ICommandConsole console, string rawId, out UUID uuid, out uint localId)
+ {
+ if (TryParseConsoleUuid(null, rawId, out uuid))
+ {
+ localId = LocalIdNotFound;
+ return true;
+ }
+
+ if (TryParseConsoleLocalId(null, rawId, out localId))
+ {
+ return true;
+ }
+
+ if (console != null)
+ console.OutputFormat("{0} is not a valid UUID or local id", rawId);
+
+ return false;
+ }
+
+ ///
+ /// Convert a minimum vector input from the console to an OpenMetaverse.Vector3
+ ///
+ /// /param>
+ ///
+ ///
+ public static bool TryParseConsoleMinVector(string rawConsoleVector, out Vector3 vector)
+ {
+ return TryParseConsoleVector(rawConsoleVector, c => float.MinValue.ToString(), out vector);
+ }
+
+ ///
+ /// Convert a maximum vector input from the console to an OpenMetaverse.Vector3
+ ///
+ /// /param>
+ ///
+ ///
+ public static bool TryParseConsoleMaxVector(string rawConsoleVector, out Vector3 vector)
+ {
+ return TryParseConsoleVector(rawConsoleVector, c => float.MaxValue.ToString(), out vector);
+ }
+
+ ///
+ /// Convert a vector input from the console to an OpenMetaverse.Vector3
+ ///
+ ///
+ /// A string in the form ,, where there is no space between values.
+ /// Any component can be missing (e.g. ,,40). blankComponentFunc is invoked to replace the blank with a suitable value
+ /// Also, if the blank component is at the end, then the comma can be missed off entirely (e.g. 40,30 or 40)
+ /// The strings "~" and "-~" are valid in components. The first substitutes float.MaxValue whilst the second is float.MinValue
+ /// Other than that, component values must be numeric.
+ ///
+ ///
+ ///
+ ///
+ public static bool TryParseConsoleVector(
+ string rawConsoleVector, Func blankComponentFunc, out Vector3 vector)
+ {
+ List components = rawConsoleVector.Split(VectorSeparatorChars).ToList();
+
+ if (components.Count < 1 || components.Count > 3)
+ {
+ vector = Vector3.Zero;
+ return false;
+ }
+
+ for (int i = components.Count; i < 3; i++)
+ components.Add("");
+
+ List semiDigestedComponents
+ = components.ConvertAll(
+ c =>
+ {
+ if (c == "")
+ return blankComponentFunc.Invoke(c);
+ else if (c == MaxRawConsoleVectorValue)
+ return float.MaxValue.ToString();
+ else if (c == MinRawConsoleVectorValue)
+ return float.MinValue.ToString();
+ else
+ return c;
+ });
+
+ string semiDigestedConsoleVector = string.Join(VectorSeparator, semiDigestedComponents.ToArray());
+
+ // m_log.DebugFormat("[CONSOLE UTIL]: Parsing {0} into OpenMetaverse.Vector3", semiDigestedConsoleVector);
+
+ return Vector3.TryParse(semiDigestedConsoleVector, out vector);
+ }
}
}
\ No newline at end of file
diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs
index 9856978cfd..87433cc3cb 100644
--- a/OpenSim/Framework/IClientAPI.cs
+++ b/OpenSim/Framework/IClientAPI.cs
@@ -1099,8 +1099,20 @@ namespace OpenSim.Framework
void SendAnimations(UUID[] animID, int[] seqs, UUID sourceAgentId, UUID[] objectIDs);
void SendRegionHandshake(RegionInfo regionInfo, RegionHandshakeArgs args);
- void SendChatMessage(string message, byte type, Vector3 fromPos, string fromName, UUID fromAgentID, byte source,
- byte audible);
+ ///
+ /// Send chat to the viewer.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ void SendChatMessage(
+ string message, byte type, Vector3 fromPos, string fromName, UUID fromAgentID, UUID ownerID, byte source,
+ byte audible);
void SendInstantMessage(GridInstantMessage im);
diff --git a/OpenSim/Framework/Monitoring/StatsManager.cs b/OpenSim/Framework/Monitoring/StatsManager.cs
index 31989e50ad..4844336e31 100644
--- a/OpenSim/Framework/Monitoring/StatsManager.cs
+++ b/OpenSim/Framework/Monitoring/StatsManager.cs
@@ -207,7 +207,7 @@ namespace OpenSim.Framework.Monitoring
return false;
newContainer = new Dictionary(container);
- newContainer.Remove(stat.UniqueName);
+ newContainer.Remove(stat.ShortName);
newCategory = new Dictionary>(category);
newCategory.Remove(stat.Container);
@@ -248,6 +248,19 @@ namespace OpenSim.Framework.Monitoring
}
}
+ ///
+ /// Stat type.
+ ///
+ ///
+ /// A push stat is one which is continually updated and so it's value can simply by read.
+ /// A pull stat is one where reading the value triggers a collection method - the stat is not continually updated.
+ ///
+ public enum StatType
+ {
+ Push,
+ Pull
+ }
+
///
/// Verbosity of stat.
///
@@ -265,11 +278,6 @@ namespace OpenSim.Framework.Monitoring
///
public class Stat
{
- ///
- /// Unique stat name used for indexing. Each ShortName in a Category must be unique.
- ///
- public string UniqueName { get; private set; }
-
///
/// Category of this stat (e.g. cache, scene, etc).
///
@@ -285,29 +293,65 @@ namespace OpenSim.Framework.Monitoring
///
public string Container { get; private set; }
+ public StatType StatType { get; private set; }
+
+ ///
+ /// Action used to update this stat when the value is requested if it's a pull type.
+ ///
+ public Action PullAction { get; private set; }
+
public StatVerbosity Verbosity { get; private set; }
public string ShortName { get; private set; }
public string Name { get; private set; }
public string Description { get; private set; }
public virtual string UnitName { get; private set; }
- public virtual double Value { get; set; }
+ public virtual double Value
+ {
+ get
+ {
+ // Asking for an update here means that the updater cannot access this value without infinite recursion.
+ // XXX: A slightly messy but simple solution may be to flick a flag so we can tell if this is being
+ // called by the pull action and just return the value.
+ if (StatType == StatType.Pull)
+ PullAction(this);
+
+ return m_value;
+ }
+
+ set
+ {
+ m_value = value;
+ }
+ }
+
+ private double m_value;
///
/// Constructor
///
/// Short name for the stat. Must not contain spaces. e.g. "LongFrames"
/// Human readable name for the stat. e.g. "Long frames"
+ /// Description of stat
///
/// 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"
///
/// Category under which this stat should appear, e.g. "scene". Do not capitalize.
/// Entity to which this stat relates. e.g. scene name if this is a per scene stat.
+ /// Push or pull
+ /// Pull stats need an action to update the stat on request. Push stats should set null here.
/// Verbosity of stat. Controls whether it will appear in short stat display or only full display.
- /// Description of stat
public Stat(
- string shortName, string name, string unitName, string category, string container, StatVerbosity verbosity, string description)
+ string shortName,
+ string name,
+ string description,
+ string unitName,
+ string category,
+ string container,
+ StatType type,
+ Action pullAction,
+ StatVerbosity verbosity)
{
if (StatsManager.SubCommands.Contains(category))
throw new Exception(
@@ -315,18 +359,18 @@ namespace OpenSim.Framework.Monitoring
ShortName = shortName;
Name = name;
+ Description = description;
UnitName = unitName;
Category = category;
Container = container;
+ StatType = type;
+
+ if (StatType == StatType.Push && pullAction != null)
+ throw new Exception("A push stat cannot have a pull action");
+ else
+ PullAction = pullAction;
+
Verbosity = verbosity;
- Description = description;
-
- UniqueName = GenUniqueName(Container, Category, ShortName);
- }
-
- public static string GenUniqueName(string container, string category, string shortName)
- {
- return string.Format("{0}+{1}+{2}", container, category, shortName);
}
public virtual string ToConsoleString()
@@ -361,8 +405,15 @@ 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) {}
+ string shortName,
+ string name,
+ string description,
+ string category,
+ string container,
+ StatType type,
+ Action pullAction,
+ StatVerbosity verbosity)
+ : base(shortName, name, description, "%", category, container, type, pullAction, verbosity) {}
public override string ToConsoleString()
{
diff --git a/OpenSim/Framework/Pool.cs b/OpenSim/Framework/Pool.cs
index 1ca06c3065..5484f5c2d5 100644
--- a/OpenSim/Framework/Pool.cs
+++ b/OpenSim/Framework/Pool.cs
@@ -38,8 +38,23 @@ namespace OpenSim.Framework
///
public class Pool
{
+ ///
+ /// Number of objects in the pool.
+ ///
+ public int Count
+ {
+ get
+ {
+ lock (m_pool)
+ return m_pool.Count;
+ }
+ }
+
private Stack m_pool;
+ ///
+ /// Maximum pool size. Beyond this, any returned objects are not pooled.
+ ///
private int m_maxPoolSize;
private Func m_createFunction;
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
index b018e57c45..410a76a798 100644
--- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
+++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
@@ -542,11 +542,8 @@ namespace OpenSim.Framework.Servers.HttpServer
{
case null:
case "text/html":
-
if (DebugLevel >= 3)
- m_log.DebugFormat(
- "[BASE HTTP SERVER]: HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}",
- RequestNumber, Port, request.ContentType, request.HttpMethod, request.Url.PathAndQuery, request.RemoteIPEndPoint);
+ LogIncomingToContentTypeHandler(request);
buffer = HandleHTTPRequest(request, response);
break;
@@ -554,11 +551,8 @@ namespace OpenSim.Framework.Servers.HttpServer
case "application/llsd+xml":
case "application/xml+llsd":
case "application/llsd+json":
-
if (DebugLevel >= 3)
- m_log.DebugFormat(
- "[BASE HTTP SERVER]: HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}",
- RequestNumber, Port, request.ContentType, request.HttpMethod, request.Url.PathAndQuery, request.RemoteIPEndPoint);
+ LogIncomingToContentTypeHandler(request);
buffer = HandleLLSDRequests(request, response);
break;
@@ -693,7 +687,7 @@ namespace OpenSim.Framework.Servers.HttpServer
"[BASE HTTP SERVER]: HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}",
RequestNumber,
Port,
- request.ContentType,
+ (request.ContentType == null || request.ContentType == "") ? "not set" : request.ContentType,
request.HttpMethod,
request.Url.PathAndQuery,
request.RemoteIPEndPoint);
diff --git a/OpenSim/Region/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs
index 4f1b4392ad..7b591a88be 100644
--- a/OpenSim/Region/Application/OpenSimBase.cs
+++ b/OpenSim/Region/Application/OpenSimBase.cs
@@ -543,7 +543,7 @@ namespace OpenSim
if (account == null)
{
m_log.ErrorFormat(
- "[OPENSIM]: Unable to store account. If this simulator is connected to a grid, you must create the estate owner account first.");
+ "[OPENSIM]: Unable to store account. If this simulator is connected to a grid, you must create the estate owner account first at the grid level.");
}
else
{
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index 7427c5947a..8e5a6d2b42 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -817,8 +817,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
OutPacket(mov, ThrottleOutPacketType.Unknown);
}
- public void SendChatMessage(string message, byte type, Vector3 fromPos, string fromName,
- UUID fromAgentID, byte source, byte audible)
+ public void SendChatMessage(
+ string message, byte type, Vector3 fromPos, string fromName,
+ UUID fromAgentID, UUID ownerID, byte source, byte audible)
{
ChatFromSimulatorPacket reply = (ChatFromSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.ChatFromSimulator);
reply.ChatData.Audible = audible;
@@ -827,7 +828,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
reply.ChatData.SourceType = source;
reply.ChatData.Position = fromPos;
reply.ChatData.FromName = Util.StringToBytes256(fromName);
- reply.ChatData.OwnerID = fromAgentID;
+ reply.ChatData.OwnerID = ownerID;
reply.ChatData.SourceID = fromAgentID;
OutPacket(reply, ThrottleOutPacketType.Task);
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index 419de66e7b..14cc863f6b 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -170,6 +170,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
private Pool m_incomingPacketPool;
+ private Stat m_incomingPacketPoolStat;
+
private int m_defaultRTO = 0;
private int m_maxRTO = 0;
private int m_ackTimeout = 0;
@@ -214,6 +216,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_circuitManager = circuitManager;
int sceneThrottleBps = 0;
+ bool usePools = false;
IConfig config = configSource.Configs["ClientStack.LindenUDP"];
if (config != null)
@@ -246,7 +249,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{
PacketPool.Instance.RecyclePackets = packetConfig.GetBoolean("RecyclePackets", true);
PacketPool.Instance.RecycleDataBlocks = packetConfig.GetBoolean("RecycleDataBlocks", true);
- UsePools = packetConfig.GetBoolean("RecycleBaseUDPPackets", false);
+ usePools = packetConfig.GetBoolean("RecycleBaseUDPPackets", usePools);
}
#region BinaryStats
@@ -277,8 +280,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_throttle = new TokenBucket(null, sceneThrottleBps);
ThrottleRates = new ThrottleRates(configSource);
- if (UsePools)
- m_incomingPacketPool = new Pool(() => new IncomingPacket(), 500);
+ if (usePools)
+ EnablePools();
}
public void Start()
@@ -331,6 +334,50 @@ namespace OpenSim.Region.ClientStack.LindenUDP
base.StopInbound();
}
+ protected override bool EnablePools()
+ {
+ if (!UsePools)
+ {
+ base.EnablePools();
+
+ m_incomingPacketPool = new Pool(() => new IncomingPacket(), 500);
+
+ m_incomingPacketPoolStat
+ = new Stat(
+ "IncomingPacketPoolCount",
+ "Objects within incoming packet pool",
+ "The number of objects currently stored within the incoming packet pool",
+ "",
+ "clientstack",
+ "packetpool",
+ StatType.Pull,
+ stat => stat.Value = m_incomingPacketPool.Count,
+ StatVerbosity.Debug);
+
+ StatsManager.RegisterStat(m_incomingPacketPoolStat);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ protected override bool DisablePools()
+ {
+ if (UsePools)
+ {
+ base.DisablePools();
+
+ StatsManager.DeregisterStat(m_incomingPacketPoolStat);
+
+ // We won't null out the pool to avoid a race condition with code that may be in the middle of using it.
+
+ return true;
+ }
+
+ return false;
+ }
+
///
/// If the outgoing UDP thread times out, then return client that was being processed to help with debugging.
///
@@ -394,6 +441,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
+ "all - stop in and outbound processing.\n",
HandleStopCommand);
+ MainConsole.Instance.Commands.AddCommand(
+ "Debug",
+ false,
+ "debug lludp pool",
+ "debug lludp pool ",
+ "Turn object pooling within the lludp component on or off.",
+ HandlePoolCommand);
+
MainConsole.Instance.Commands.AddCommand(
"Debug",
false,
@@ -437,6 +492,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
StopOutbound();
}
+ private void HandlePoolCommand(string module, string[] args)
+ {
+ if (args.Length != 4)
+ {
+ MainConsole.Instance.Output("Usage: debug lludp pool ");
+ return;
+ }
+
+ string enabled = args[3];
+
+ if (enabled == "on")
+ {
+ if (EnablePools())
+ MainConsole.Instance.OutputFormat("Packet pools enabled on {0}", m_scene.Name);
+ }
+ else if (enabled == "off")
+ {
+ if (DisablePools())
+ MainConsole.Instance.OutputFormat("Packet pools disabled on {0}", m_scene.Name);
+ }
+ else
+ {
+ MainConsole.Instance.Output("Usage: debug lludp pool ");
+ }
+ }
+
private void HandleStatusCommand(string module, string[] args)
{
MainConsole.Instance.OutputFormat(
@@ -444,6 +525,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
MainConsole.Instance.OutputFormat(
"OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled");
+
+ MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_scene.Name, UsePools ? "on" : "off");
}
public bool HandlesRegion(Location x)
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
index 6e6b3ef1b5..85cbb0659b 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
@@ -31,6 +31,7 @@ using System.Net.Sockets;
using System.Threading;
using log4net;
using OpenSim.Framework;
+using OpenSim.Framework.Monitoring;
namespace OpenMetaverse
{
@@ -76,6 +77,8 @@ namespace OpenMetaverse
/// If IsRunningOut = false, then any request to send a packet is simply dropped.
public bool IsRunningOutbound { get; private set; }
+ private Stat m_poolCountStat;
+
///
/// Default constructor
///
@@ -106,11 +109,6 @@ namespace OpenMetaverse
/// necessary
public void StartInbound(int recvBufferSize, bool asyncPacketHandling)
{
- if (UsePools)
- m_pool = new Pool(() => new UDPPacketBuffer(), 500);
- else
- m_pool = null;
-
m_asyncPacketHandling = asyncPacketHandling;
if (!IsRunningInbound)
@@ -180,6 +178,49 @@ namespace OpenMetaverse
IsRunningOutbound = false;
}
+ protected virtual bool EnablePools()
+ {
+ if (!UsePools)
+ {
+ m_pool = new Pool(() => new UDPPacketBuffer(), 500);
+
+ m_poolCountStat
+ = new Stat(
+ "UDPPacketBufferPoolCount",
+ "Objects within the UDPPacketBuffer pool",
+ "The number of objects currently stored within the UDPPacketBuffer pool",
+ "",
+ "clientstack",
+ "packetpool",
+ StatType.Pull,
+ stat => stat.Value = m_pool.Count,
+ StatVerbosity.Debug);
+
+ StatsManager.RegisterStat(m_poolCountStat);
+
+ UsePools = true;
+
+ return true;
+ }
+
+ return false;
+ }
+
+ protected virtual bool DisablePools()
+ {
+ if (UsePools)
+ {
+ UsePools = false;
+ StatsManager.DeregisterStat(m_poolCountStat);
+
+ // We won't null out the pool to avoid a race condition with code that may be in the middle of using it.
+
+ return true;
+ }
+
+ return false;
+ }
+
private void AsyncBeginReceive()
{
UDPPacketBuffer buf;
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
index 2a3d14f69f..9f22fb48ec 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
@@ -47,18 +47,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
private PercentageStat m_packetsReusedStat = new PercentageStat(
"PacketsReused",
"Packets reused",
+ "Number of packets reused out of all requests to the packet pool",
"clientstack",
"packetpool",
- StatVerbosity.Debug,
- "Number of packets reused out of all requests to the packet pool");
+ StatType.Push,
+ null,
+ StatVerbosity.Debug);
private PercentageStat m_blocksReusedStat = new PercentageStat(
- "BlocksReused",
- "Blocks reused",
+ "PacketDataBlocksReused",
+ "Packet data blocks reused",
+ "Number of data blocks reused out of all requests to the packet pool",
"clientstack",
"packetpool",
- StatVerbosity.Debug,
- "Number of data blocks reused out of all requests to the packet pool");
+ StatType.Push,
+ null,
+ StatVerbosity.Debug);
///
/// Pool of packets available for reuse.
@@ -88,6 +92,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{
StatsManager.RegisterStat(m_packetsReusedStat);
StatsManager.RegisterStat(m_blocksReusedStat);
+
+ StatsManager.RegisterStat(
+ new Stat(
+ "PacketsPoolCount",
+ "Objects within the packet pool",
+ "The number of objects currently stored within the packet pool",
+ "",
+ "clientstack",
+ "packetpool",
+ StatType.Pull,
+ stat => { lock (pool) { stat.Value = pool.Count; } },
+ StatVerbosity.Debug));
+
+ StatsManager.RegisterStat(
+ new Stat(
+ "PacketDataBlocksPoolCount",
+ "Objects within the packet data block pool",
+ "The number of objects currently stored within the packet data block pool",
+ "",
+ "clientstack",
+ "packetpool",
+ StatType.Pull,
+ stat => { lock (DataBlocks) { stat.Value = DataBlocks.Count; } },
+ StatVerbosity.Debug));
}
///
diff --git a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs
index e4452fbb87..ddf92c3e44 100644
--- a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs
@@ -186,6 +186,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
{
string fromName = c.From;
UUID fromID = UUID.Zero;
+ UUID ownerID = UUID.Zero;
UUID targetID = c.TargetUUID;
string message = c.Message;
IScene scene = c.Scene;
@@ -208,12 +209,16 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
fromPos = avatar.AbsolutePosition;
fromName = avatar.Name;
fromID = c.Sender.AgentId;
+ ownerID = c.Sender.AgentId;
break;
case ChatSourceType.Object:
fromID = c.SenderUUID;
+ if (c.SenderObject != null && c.SenderObject is SceneObjectPart)
+ ownerID = ((SceneObjectPart)c.SenderObject).OwnerID;
+
break;
}
@@ -236,7 +241,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
s.ForEachRootScenePresence(
delegate(ScenePresence presence)
{
- if (TrySendChatMessage(presence, fromPos, regionPos, fromID, fromName, c.Type, message, sourceType, false))
+ if (TrySendChatMessage(
+ presence, fromPos, regionPos, fromID, ownerID, fromName, c.Type, message, sourceType, false))
receiverIDs.Add(presence.UUID);
}
);
@@ -248,8 +254,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
ScenePresence presence = s.GetScenePresence(targetID);
if (presence != null && !presence.IsChildAgent)
{
- if (TrySendChatMessage(presence, fromPos, regionPos, fromID, fromName, ChatTypeEnum.Say, message, sourceType, true))
- receiverIDs.Add(presence.UUID);
+ if (TrySendChatMessage(
+ presence, fromPos, regionPos, fromID, ownerID, fromName, ChatTypeEnum.Say, message, sourceType, true))
+ receiverIDs.Add(presence.UUID);
}
}
}
@@ -305,9 +312,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
(null != c.SenderObject) &&
(((SceneObjectPart)c.SenderObject).OwnerID != client.AgentId))
return;
-
- client.SendChatMessage(c.Message, (byte)cType, CenterOfRegion, fromName, fromID,
- (byte)sourceType, (byte)ChatAudibleLevel.Fully);
+
+ client.SendChatMessage(
+ c.Message, (byte)cType, CenterOfRegion, fromName, fromID, fromID,
+ (byte)sourceType, (byte)ChatAudibleLevel.Fully);
+
receiverIDs.Add(client.AgentId);
});
@@ -322,15 +331,20 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
///
/// /param>
///
+ ///
+ /// Owner of the message. For at least some messages from objects, this has to be correctly filled with the owner's UUID.
+ /// This is the case for script error messages in viewer 3 since LLViewer change EXT-7762
+ ///
///
///
///
///
/// true if the message was sent to the receiver, false if it was not sent due to failing a
/// precondition
- protected virtual bool TrySendChatMessage(ScenePresence presence, Vector3 fromPos, Vector3 regionPos,
- UUID fromAgentID, string fromName, ChatTypeEnum type,
- string message, ChatSourceType src, bool ignoreDistance)
+ protected virtual bool TrySendChatMessage(
+ ScenePresence presence, Vector3 fromPos, Vector3 regionPos,
+ UUID fromAgentID, UUID ownerID, string fromName, ChatTypeEnum type,
+ string message, ChatSourceType src, bool ignoreDistance)
{
// don't send stuff to child agents
if (presence.IsChildAgent) return false;
@@ -353,10 +367,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
}
// TODO: should change so the message is sent through the avatar rather than direct to the ClientView
- presence.ControllingClient.SendChatMessage(message, (byte) type, fromPos, fromName,
- fromAgentID, (byte)src, (byte)ChatAudibleLevel.Fully);
+ presence.ControllingClient.SendChatMessage(
+ message, (byte) type, fromPos, fromName,
+ fromAgentID, ownerID, (byte)src, (byte)ChatAudibleLevel.Fully);
return true;
}
}
-}
+}
\ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs
index cf870100a4..afe12003b1 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs
@@ -35,6 +35,7 @@ using Nini.Config;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Framework.Communications;
+using OpenSim.Framework.Console;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Services.Interfaces;
@@ -209,6 +210,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
Guid id, string firstName, string lastName, string invPath, string pass, string savePath,
Dictionary options)
{
+ if (!ConsoleUtil.CheckFileDoesNotExist(MainConsole.Instance, savePath))
+ return false;
+
if (m_scenes.Count > 0)
{
UserAccount userInfo = GetUserInfo(firstName, lastName, pass);
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
index 33b48393fb..8ff20ddb08 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
@@ -38,15 +38,15 @@ using OpenSim.Services.Interfaces;
namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
{
- public class InventoryTransferModule : IInventoryTransferModule, ISharedRegionModule
+ public class InventoryTransferModule : ISharedRegionModule
{
private static readonly ILog m_log
= LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
///
private List m_Scenelist = new List();
- private Dictionary m_AgentRegions =
- new Dictionary();
+// private Dictionary m_AgentRegions =
+// new Dictionary();
private IMessageTransferModule m_TransferModule = null;
private bool m_Enabled = true;
@@ -76,12 +76,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
m_Scenelist.Add(scene);
- scene.RegisterModuleInterface(this);
+// scene.RegisterModuleInterface(this);
scene.EventManager.OnNewClient += OnNewClient;
- scene.EventManager.OnClientClosed += ClientLoggedOut;
+// scene.EventManager.OnClientClosed += ClientLoggedOut;
scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage;
- scene.EventManager.OnSetRootAgentScene += OnSetRootAgentScene;
+// scene.EventManager.OnSetRootAgentScene += OnSetRootAgentScene;
}
public void RegionLoaded(Scene scene)
@@ -96,9 +96,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
m_Scenelist.Clear();
scene.EventManager.OnNewClient -= OnNewClient;
- scene.EventManager.OnClientClosed -= ClientLoggedOut;
+// scene.EventManager.OnClientClosed -= ClientLoggedOut;
scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage;
- scene.EventManager.OnSetRootAgentScene -= OnSetRootAgentScene;
+// scene.EventManager.OnSetRootAgentScene -= OnSetRootAgentScene;
}
}
}
@@ -106,9 +106,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
public void RemoveRegion(Scene scene)
{
scene.EventManager.OnNewClient -= OnNewClient;
- scene.EventManager.OnClientClosed -= ClientLoggedOut;
+// scene.EventManager.OnClientClosed -= ClientLoggedOut;
scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage;
- scene.EventManager.OnSetRootAgentScene -= OnSetRootAgentScene;
+// scene.EventManager.OnSetRootAgentScene -= OnSetRootAgentScene;
m_Scenelist.Remove(scene);
}
@@ -138,10 +138,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
client.OnInstantMessage += OnInstantMessage;
}
- protected void OnSetRootAgentScene(UUID id, Scene scene)
- {
- m_AgentRegions[id] = scene;
- }
+// protected void OnSetRootAgentScene(UUID id, Scene scene)
+// {
+// m_AgentRegions[id] = scene;
+// }
private Scene FindClientScene(UUID agentId)
{
@@ -448,69 +448,69 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
}
}
- public bool NeedSceneCacheClear(UUID agentID, Scene scene)
- {
- if (!m_AgentRegions.ContainsKey(agentID))
- {
- // Since we can get here two ways, we need to scan
- // the scenes here. This is somewhat more expensive
- // but helps avoid a nasty bug
- //
-
- foreach (Scene s in m_Scenelist)
- {
- ScenePresence presence;
-
- if (s.TryGetScenePresence(agentID, out presence))
- {
- // If the agent is in this scene, then we
- // are being called twice in a single
- // teleport. This is wasteful of cycles
- // but harmless due to this 2nd level check
- //
- // If the agent is found in another scene
- // then the list wasn't current
- //
- // If the agent is totally unknown, then what
- // are we even doing here??
- //
- if (s == scene)
- {
- //m_log.Debug("[INVTRANSFERMOD]: s == scene. Returning true in " + scene.RegionInfo.RegionName);
- return true;
- }
- else
- {
- //m_log.Debug("[INVTRANSFERMOD]: s != scene. Returning false in " + scene.RegionInfo.RegionName);
- return false;
- }
- }
- }
- //m_log.Debug("[INVTRANSFERMOD]: agent not in scene. Returning true in " + scene.RegionInfo.RegionName);
- return true;
- }
-
- // The agent is left in current Scene, so we must be
- // going to another instance
- //
- if (m_AgentRegions[agentID] == scene)
- {
- //m_log.Debug("[INVTRANSFERMOD]: m_AgentRegions[agentID] == scene. Returning true in " + scene.RegionInfo.RegionName);
- m_AgentRegions.Remove(agentID);
- return true;
- }
-
- // Another region has claimed the agent
- //
- //m_log.Debug("[INVTRANSFERMOD]: last resort. Returning false in " + scene.RegionInfo.RegionName);
- return false;
- }
-
- public void ClientLoggedOut(UUID agentID, Scene scene)
- {
- if (m_AgentRegions.ContainsKey(agentID))
- m_AgentRegions.Remove(agentID);
- }
+// public bool NeedSceneCacheClear(UUID agentID, Scene scene)
+// {
+// if (!m_AgentRegions.ContainsKey(agentID))
+// {
+// // Since we can get here two ways, we need to scan
+// // the scenes here. This is somewhat more expensive
+// // but helps avoid a nasty bug
+// //
+//
+// foreach (Scene s in m_Scenelist)
+// {
+// ScenePresence presence;
+//
+// if (s.TryGetScenePresence(agentID, out presence))
+// {
+// // If the agent is in this scene, then we
+// // are being called twice in a single
+// // teleport. This is wasteful of cycles
+// // but harmless due to this 2nd level check
+// //
+// // If the agent is found in another scene
+// // then the list wasn't current
+// //
+// // If the agent is totally unknown, then what
+// // are we even doing here??
+// //
+// if (s == scene)
+// {
+// //m_log.Debug("[INVTRANSFERMOD]: s == scene. Returning true in " + scene.RegionInfo.RegionName);
+// return true;
+// }
+// else
+// {
+// //m_log.Debug("[INVTRANSFERMOD]: s != scene. Returning false in " + scene.RegionInfo.RegionName);
+// return false;
+// }
+// }
+// }
+// //m_log.Debug("[INVTRANSFERMOD]: agent not in scene. Returning true in " + scene.RegionInfo.RegionName);
+// return true;
+// }
+//
+// // The agent is left in current Scene, so we must be
+// // going to another instance
+// //
+// if (m_AgentRegions[agentID] == scene)
+// {
+// //m_log.Debug("[INVTRANSFERMOD]: m_AgentRegions[agentID] == scene. Returning true in " + scene.RegionInfo.RegionName);
+// m_AgentRegions.Remove(agentID);
+// return true;
+// }
+//
+// // Another region has claimed the agent
+// //
+// //m_log.Debug("[INVTRANSFERMOD]: last resort. Returning false in " + scene.RegionInfo.RegionName);
+// return false;
+// }
+//
+// public void ClientLoggedOut(UUID agentID, Scene scene)
+// {
+// if (m_AgentRegions.ContainsKey(agentID))
+// m_AgentRegions.Remove(agentID);
+// }
///
///
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
index 90fe43034b..7498cfe73e 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
@@ -672,13 +672,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
sp.Reset();
}
- // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE!
- if (sp.Scene.NeedSceneCacheClear(sp.UUID))
- {
- m_log.DebugFormat(
- "[ENTITY TRANSFER MODULE]: User {0} is going to another region, profile cache removed",
- sp.UUID);
- }
+ // Commented pending deletion since this method no longer appears to do anything at all
+// // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE!
+// if (sp.Scene.NeedSceneCacheClear(sp.UUID))
+// {
+// m_log.DebugFormat(
+// "[ENTITY TRANSFER MODULE]: User {0} is going to another region, profile cache removed",
+// sp.UUID);
+// }
m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
}
@@ -1237,14 +1238,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
AgentHasMovedAway(agent, false);
- // the user may change their profile information in other region,
- // so the userinfo in UserProfileCache is not reliable any more, delete it
- // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE!
- if (agent.Scene.NeedSceneCacheClear(agent.UUID))
- {
- m_log.DebugFormat(
- "[ENTITY TRANSFER MODULE]: User {0} is going to another region", agent.UUID);
- }
+// // the user may change their profile information in other region,
+// // so the userinfo in UserProfileCache is not reliable any more, delete it
+// // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE!
+// if (agent.Scene.NeedSceneCacheClear(agent.UUID))
+// {
+// m_log.DebugFormat(
+// "[ENTITY TRANSFER MODULE]: User {0} is going to another region", agent.UUID);
+// }
//m_log.Debug("AFTER CROSS");
//Scene.DumpChildrenSeeds(UUID);
diff --git a/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs b/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs
index 8358bc0c64..401ff6cdef 100644
--- a/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs
@@ -28,6 +28,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
+using System.Text.RegularExpressions;
using Nini.Config;
using OpenMetaverse;
using OpenSim.Framework;
@@ -170,12 +171,42 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
/// UUID of the SceneObjectPart
/// channel to listen on
/// name to filter on
- /// key to filter on (user given, could be totally faked)
+ ///
+ /// key to filter on (user given, could be totally faked)
+ ///
/// msg to filter on
/// number of the scripts handle
- public int Listen(uint localID, UUID itemID, UUID hostID, int channel, string name, UUID id, string msg)
+ public int Listen(uint localID, UUID itemID, UUID hostID, int channel,
+ string name, UUID id, string msg)
{
- return m_listenerManager.AddListener(localID, itemID, hostID, channel, name, id, msg);
+ return m_listenerManager.AddListener(localID, itemID, hostID,
+ channel, name, id, msg);
+ }
+
+ ///
+ /// Create a listen event callback with the specified filters.
+ /// The parameters localID,itemID are needed to uniquely identify
+ /// the script during 'peek' time. Parameter hostID is needed to
+ /// determine the position of the script.
+ ///
+ /// localID of the script engine
+ /// UUID of the script engine
+ /// UUID of the SceneObjectPart
+ /// channel to listen on
+ /// name to filter on
+ ///
+ /// key to filter on (user given, could be totally faked)
+ ///
+ /// msg to filter on
+ ///
+ /// Bitfield indicating which strings should be processed as regex.
+ ///
+ /// number of the scripts handle
+ public int Listen(uint localID, UUID itemID, UUID hostID, int channel,
+ string name, UUID id, string msg, int regexBitfield)
+ {
+ return m_listenerManager.AddListener(localID, itemID, hostID,
+ channel, name, id, msg, regexBitfield);
}
///
@@ -465,15 +496,25 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
m_curlisteners = 0;
}
- public int AddListener(uint localID, UUID itemID, UUID hostID, int channel, string name, UUID id, string msg)
+ public int AddListener(uint localID, UUID itemID, UUID hostID,
+ int channel, string name, UUID id, string msg)
+ {
+ return AddListener(localID, itemID, hostID, channel, name, id,
+ msg, 0);
+ }
+
+ public int AddListener(uint localID, UUID itemID, UUID hostID,
+ int channel, string name, UUID id, string msg,
+ int regexBitfield)
{
// do we already have a match on this particular filter event?
- List coll = GetListeners(itemID, channel, name, id, msg);
+ List coll = GetListeners(itemID, channel, name, id,
+ msg);
if (coll.Count > 0)
{
- // special case, called with same filter settings, return same handle
- // (2008-05-02, tested on 1.21.1 server, still holds)
+ // special case, called with same filter settings, return same
+ // handle (2008-05-02, tested on 1.21.1 server, still holds)
return coll[0].GetHandle();
}
@@ -485,7 +526,9 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
if (newHandle > 0)
{
- ListenerInfo li = new ListenerInfo(newHandle, localID, itemID, hostID, channel, name, id, msg);
+ ListenerInfo li = new ListenerInfo(newHandle, localID,
+ itemID, hostID, channel, name, id, msg,
+ regexBitfield);
List listeners;
if (!m_listeners.TryGetValue(channel,out listeners))
@@ -626,6 +669,22 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
return -1;
}
+ /// These are duplicated from ScriptBaseClass
+ /// http://opensimulator.org/mantis/view.php?id=6106#c21945
+ #region Constants for the bitfield parameter of osListenRegex
+
+ ///
+ /// process name parameter as regex
+ ///
+ public const int OS_LISTEN_REGEX_NAME = 0x1;
+
+ ///
+ /// process message parameter as regex
+ ///
+ public const int OS_LISTEN_REGEX_MESSAGE = 0x2;
+
+ #endregion
+
// Theres probably a more clever and efficient way to
// do this, maybe with regex.
// PM2008: Ha, one could even be smart and define a specialized Enumerator.
@@ -651,7 +710,10 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
{
continue;
}
- if (li.GetName().Length > 0 && !li.GetName().Equals(name))
+ if (li.GetName().Length > 0 && (
+ ((li.RegexBitfield & OS_LISTEN_REGEX_NAME) != OS_LISTEN_REGEX_NAME && !li.GetName().Equals(name)) ||
+ ((li.RegexBitfield & OS_LISTEN_REGEX_NAME) == OS_LISTEN_REGEX_NAME && !Regex.IsMatch(name, li.GetName()))
+ ))
{
continue;
}
@@ -659,7 +721,10 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
{
continue;
}
- if (li.GetMessage().Length > 0 && !li.GetMessage().Equals(msg))
+ if (li.GetMessage().Length > 0 && (
+ ((li.RegexBitfield & OS_LISTEN_REGEX_MESSAGE) != OS_LISTEN_REGEX_MESSAGE && !li.GetMessage().Equals(msg)) ||
+ ((li.RegexBitfield & OS_LISTEN_REGEX_MESSAGE) == OS_LISTEN_REGEX_MESSAGE && !Regex.IsMatch(msg, li.GetMessage()))
+ ))
{
continue;
}
@@ -692,10 +757,13 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
{
int idx = 0;
Object[] item = new Object[6];
+ int dataItemLength = 6;
while (idx < data.Length)
{
- Array.Copy(data, idx, item, 0, 6);
+ dataItemLength = (idx + 7 == data.Length || (idx + 7 < data.Length && data[idx + 7] is bool)) ? 7 : 6;
+ item = new Object[dataItemLength];
+ Array.Copy(data, idx, item, 0, dataItemLength);
ListenerInfo info =
ListenerInfo.FromData(localID, itemID, hostID, item);
@@ -707,12 +775,12 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
m_listeners[(int)item[2]].Add(info);
}
- idx+=6;
+ idx+=dataItemLength;
}
}
}
- public class ListenerInfo: IWorldCommListenerInfo
+ public class ListenerInfo : IWorldCommListenerInfo
{
private bool m_active; // Listener is active or not
private int m_handle; // Assigned handle of this listener
@@ -726,16 +794,29 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
public ListenerInfo(int handle, uint localID, UUID ItemID, UUID hostID, int channel, string name, UUID id, string message)
{
- Initialise(handle, localID, ItemID, hostID, channel, name, id, message);
+ Initialise(handle, localID, ItemID, hostID, channel, name, id,
+ message, 0);
+ }
+
+ public ListenerInfo(int handle, uint localID, UUID ItemID,
+ UUID hostID, int channel, string name, UUID id,
+ string message, int regexBitfield)
+ {
+ Initialise(handle, localID, ItemID, hostID, channel, name, id,
+ message, regexBitfield);
}
public ListenerInfo(ListenerInfo li, string name, UUID id, string message)
{
- Initialise(li.m_handle, li.m_localID, li.m_itemID, li.m_hostID, li.m_channel, name, id, message);
+ Initialise(li.m_handle, li.m_localID, li.m_itemID, li.m_hostID, li.m_channel, name, id, message, 0);
}
- private void Initialise(int handle, uint localID, UUID ItemID, UUID hostID, int channel, string name,
- UUID id, string message)
+ public ListenerInfo(ListenerInfo li, string name, UUID id, string message, int regexBitfield)
+ {
+ Initialise(li.m_handle, li.m_localID, li.m_itemID, li.m_hostID, li.m_channel, name, id, message, regexBitfield);
+ }
+
+ private void Initialise(int handle, uint localID, UUID ItemID, UUID hostID, int channel, string name, UUID id, string message, int regexBitfield)
{
m_active = true;
m_handle = handle;
@@ -746,11 +827,12 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
m_name = name;
m_id = id;
m_message = message;
+ RegexBitfield = regexBitfield;
}
public Object[] GetSerializationData()
{
- Object[] data = new Object[6];
+ Object[] data = new Object[7];
data[0] = m_active;
data[1] = m_handle;
@@ -758,16 +840,19 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
data[3] = m_name;
data[4] = m_id;
data[5] = m_message;
+ data[6] = RegexBitfield;
return data;
}
public static ListenerInfo FromData(uint localID, UUID ItemID, UUID hostID, Object[] data)
{
- ListenerInfo linfo = new ListenerInfo((int)data[1], localID,
- ItemID, hostID, (int)data[2], (string)data[3],
- (UUID)data[4], (string)data[5]);
- linfo.m_active=(bool)data[0];
+ ListenerInfo linfo = new ListenerInfo((int)data[1], localID, ItemID, hostID, (int)data[2], (string)data[3], (UUID)data[4], (string)data[5]);
+ linfo.m_active = (bool)data[0];
+ if (data.Length >= 7)
+ {
+ linfo.RegexBitfield = (int)data[6];
+ }
return linfo;
}
@@ -826,5 +911,7 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
{
return m_id;
}
+
+ public int RegexBitfield { get; private set; }
}
}
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveScenesGroup.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveScenesGroup.cs
index a66ed88ad1..d8dace20c8 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveScenesGroup.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveScenesGroup.cs
@@ -110,7 +110,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
lastX = (lastX == null) ? curLastX : (lastX > curLastX) ? lastX : curLastX;
}
- Rect = new Rectangle((int)firstX, (int)firstY, (int)(lastY - firstY + 1), (int)(lastX - firstX + 1));
+ Rect = new Rectangle((int)firstX, (int)firstY, (int)(lastX - firstX + 1), (int)(lastY - firstY + 1));
// Calculate the subdirectory in which each region will be stored in the archive
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs
index 2a87dc2a5f..970487a3d4 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs
@@ -32,6 +32,8 @@ using System.Reflection;
using log4net;
using NDesk.Options;
using Nini.Config;
+using OpenSim.Framework;
+using OpenSim.Framework.Console;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
@@ -117,7 +119,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
//
// foreach (string param in mainParams)
// m_log.DebugFormat("GOT PARAM [{0}]", param);
-
+
if (mainParams.Count > 2)
{
DearchiveRegion(mainParams[2], mergeOar, skipAssets, Guid.Empty);
@@ -150,14 +152,16 @@ namespace OpenSim.Region.CoreModules.World.Archiver
List mainParams = ops.Parse(cmdparams);
+ string path;
if (mainParams.Count > 2)
- {
- ArchiveRegion(mainParams[2], options);
- }
+ path = mainParams[2];
else
- {
- ArchiveRegion(DEFAULT_OAR_BACKUP_FILENAME, options);
- }
+ path = DEFAULT_OAR_BACKUP_FILENAME;
+
+ if (!ConsoleUtil.CheckFileDoesNotExist(MainConsole.Instance, path))
+ return;
+
+ ArchiveRegion(path, options);
}
public void ArchiveRegion(string savePath, Dictionary options)
diff --git a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs
index 87241e1559..b2c9bce7e5 100644
--- a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs
+++ b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs
@@ -27,10 +27,12 @@
using System;
using System.Collections.Generic;
+using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
+using System.Xml;
using log4net;
using Mono.Addins;
using NDesk.Options;
@@ -41,6 +43,7 @@ using OpenSim.Framework.Console;
using OpenSim.Framework.Monitoring;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
+using OpenSim.Region.Framework.Scenes.Serialization;
namespace OpenSim.Region.CoreModules.World.Objects.Commands
{
@@ -96,9 +99,9 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
HandleDeleteObject);
m_console.Commands.AddCommand(
- "Objects", false, "delete object uuid",
- "delete object uuid ",
- "Delete a scene object by uuid",
+ "Objects", false, "delete object id",
+ "delete object id ",
+ "Delete a scene object by uuid or localID",
HandleDeleteObject);
m_console.Commands.AddCommand(
@@ -122,28 +125,18 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
"delete object pos",
"delete object pos to ",
"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",
+ ConsoleUtil.CoordHelp,
HandleDeleteObject);
m_console.Commands.AddCommand(
"Objects",
false,
- "show object uuid",
- "show object uuid [--full] ",
- "Show details of a scene object with the given UUID",
+ "show object id",
+ "show object id [--full] ",
+ "Show details of a scene object with the given UUID or localID",
"The --full option will print out information on all the parts of the object.\n"
+ "For yet more detailed part information, use the \"show part\" commands.",
- HandleShowObjectByUuid);
+ HandleShowObjectById);
m_console.Commands.AddCommand(
"Objects",
@@ -164,25 +157,15 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
"Show details of scene objects within the given area.",
"The --full option will print out information on all the parts of the object.\n"
+ "For yet more detailed part information, use the \"show part\" commands.\n"
- + "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"
- + "show object pos 20,20,20 to 40,40,40\n"
- + "show object pos 20,20 to 40,40\n"
- + "show object pos ,20,20 to ,40,40\n"
- + "show object pos ,,30 to ,,~\n"
- + "show object pos ,,-~ to ,,30",
+ + ConsoleUtil.CoordHelp,
HandleShowObjectByPos);
m_console.Commands.AddCommand(
"Objects",
false,
- "show part uuid",
- "show part uuid ",
- "Show details of a scene object parts with the given UUID", HandleShowPartByUuid);
+ "show part id",
+ "show part id ",
+ "Show details of a scene object part with the given UUID or localID", HandleShowPartById);
m_console.Commands.AddCommand(
"Objects",
@@ -190,7 +173,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
"show part name",
"show part name [--regex] ",
"Show details of scene object parts with the given name.",
- "If --regex is specified then the name is treatead as a regular expression",
+ "If --regex is specified then the name is treated as a regular expression",
HandleShowPartByName);
m_console.Commands.AddCommand(
@@ -199,18 +182,19 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
"show part pos",
"show part pos to ",
"Show details of scene object parts 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"
- + "show object pos 20,20,20 to 40,40,40\n"
- + "show object pos 20,20 to 40,40\n"
- + "show object pos ,20,20 to ,40,40\n"
- + "show object pos ,,30 to ,,~\n"
- + "show object pos ,,-~ to ,,30",
+ ConsoleUtil.CoordHelp,
HandleShowPartByPos);
+
+ m_console.Commands.AddCommand(
+ "Objects",
+ false,
+ "dump object id",
+ "dump object id ",
+ "Dump the formatted serialization of the given object to the file .xml",
+ "e.g. dump object uuid c1ed6809-cc24-4061-a4c2-93082a2d1f1d will dump serialization to c1ed6809-cc24-4061-a4c2-93082a2d1f1d.xml\n"
+ + "To locate the UUID or localID in the first place, you need to use the other show object commands.\n"
+ + "If a local ID is given then the filename used is still that for the UUID",
+ HandleDumpObjectById);
}
public void RemoveRegion(Scene scene)
@@ -265,7 +249,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
m_console.OutputFormat(sb.ToString());
}
- private void HandleShowObjectByUuid(string module, string[] cmdparams)
+ private void HandleShowObjectById(string module, string[] cmdparams)
{
if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene))
return;
@@ -281,14 +265,17 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
return;
}
- UUID objectUuid;
- if (!UUID.TryParse(mainParams[3], out objectUuid))
- {
- m_console.OutputFormat("{0} is not a valid uuid", mainParams[3]);
+ UUID uuid;
+ uint localId;
+ if (!ConsoleUtil.TryParseConsoleId(m_console, mainParams[3], out uuid, out localId))
return;
- }
- SceneObjectGroup so = m_scene.GetSceneObjectGroup(objectUuid);
+ SceneObjectGroup so;
+
+ if (localId != ConsoleUtil.LocalIdNotFound)
+ so = m_scene.GetSceneObjectGroup(localId);
+ else
+ so = m_scene.GetSceneObjectGroup(uuid);
if (so == null)
{
@@ -365,7 +352,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
OutputSogsToConsole(searchPredicate, showFull);
}
- private void HandleShowPartByUuid(string module, string[] cmdparams)
+ private void HandleShowPartById(string module, string[] cmdparams)
{
if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene))
return;
@@ -378,18 +365,20 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
if (mainParams.Count < 4)
{
- m_console.OutputFormat("Usage: show part uuid [--full] ");
+ m_console.OutputFormat("Usage: show part id [--full] ");
return;
}
UUID objectUuid;
- if (!UUID.TryParse(mainParams[3], out objectUuid))
- {
- m_console.OutputFormat("{0} is not a valid uuid", mainParams[3]);
+ uint localId;
+ if (!ConsoleUtil.TryParseConsoleId(m_console, mainParams[3], out objectUuid, out localId))
return;
- }
- SceneObjectPart sop = m_scene.GetSceneObjectPart(objectUuid);
+ SceneObjectPart sop;
+ if (localId == ConsoleUtil.LocalIdNotFound)
+ sop = m_scene.GetSceneObjectPart(objectUuid);
+ else
+ sop = m_scene.GetSceneObjectPart(localId);
if (sop == null)
{
@@ -477,6 +466,51 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
OutputSopsToConsole(searchPredicate, true);
}
+ private void HandleDumpObjectById(string module, string[] cmdparams)
+ {
+ if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene))
+ return;
+
+ if (cmdparams.Length < 4)
+ {
+ m_console.OutputFormat("Usage: dump object id ");
+ return;
+ }
+
+ UUID objectUuid;
+ uint localId;
+ if (!ConsoleUtil.TryParseConsoleId(m_console, cmdparams[3], out objectUuid, out localId))
+ return;
+
+ SceneObjectGroup so;
+ if (localId == ConsoleUtil.LocalIdNotFound)
+ so = m_scene.GetSceneObjectGroup(objectUuid);
+ else
+ so = m_scene.GetSceneObjectGroup(localId);
+
+ if (so == null)
+ {
+// m_console.OutputFormat("No part found with uuid {0}", objectUuid);
+ return;
+ }
+
+ // In case we found it via local ID.
+ objectUuid = so.UUID;
+
+ string fileName = string.Format("{0}.xml", objectUuid);
+
+ if (!ConsoleUtil.CheckFileDoesNotExist(m_console, fileName))
+ return;
+
+ using (XmlTextWriter xtw = new XmlTextWriter(fileName, Encoding.UTF8))
+ {
+ xtw.Formatting = Formatting.Indented;
+ SceneObjectSerializer.ToOriginalXmlFormat(so, xtw, true);
+ }
+
+ m_console.OutputFormat("Object dumped to file {0}", fileName);
+ }
+
///
/// Append a scene object report to an input StringBuilder
///
@@ -641,19 +675,24 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
break;
- case "uuid":
- if (!UUID.TryParse(o, out match))
+ case "id":
+ UUID uuid;
+ uint localId;
+ if (!ConsoleUtil.TryParseConsoleId(m_console, o, out uuid, out localId))
return;
requireConfirmation = false;
deletes = new List();
-
- m_scene.ForEachSOG(delegate (SceneObjectGroup g)
- {
- if (g.UUID == match && !g.IsAttachment)
- deletes.Add(g);
- });
-
+
+ SceneObjectGroup so;
+ if (localId == ConsoleUtil.LocalIdNotFound)
+ so = m_scene.GetSceneObjectGroup(uuid);
+ else
+ so = m_scene.GetSceneObjectGroup(localId);
+
+ if (!so.IsAttachment)
+ deletes.Add(so);
+
// if (deletes.Count == 0)
// m_console.OutputFormat("No objects were found with uuid {0}", match);
diff --git a/OpenSim/Region/Framework/Interfaces/IWorldComm.cs b/OpenSim/Region/Framework/Interfaces/IWorldComm.cs
index 4e74781b9b..d76a0d755d 100644
--- a/OpenSim/Region/Framework/Interfaces/IWorldComm.cs
+++ b/OpenSim/Region/Framework/Interfaces/IWorldComm.cs
@@ -45,6 +45,13 @@ namespace OpenSim.Region.Framework.Interfaces
void Deactivate();
void Activate();
UUID GetID();
+
+ ///
+ /// Bitfield indicating which strings should be processed as regex.
+ /// 1 corresponds to IWorldCommListenerInfo::GetName()
+ /// 2 corresponds to IWorldCommListenerInfo::GetMessage()
+ ///
+ int RegexBitfield { get; }
}
public interface IWorldComm
@@ -60,7 +67,7 @@ namespace OpenSim.Region.Framework.Interfaces
/// the script during 'peek' time. Parameter hostID is needed to
/// determine the position of the script.
///
- /// localID of the script engine
+ /// localID of the script engine
/// UUID of the script engine
/// UUID of the SceneObjectPart
/// channel to listen on
@@ -70,6 +77,23 @@ namespace OpenSim.Region.Framework.Interfaces
/// number of the scripts handle
int Listen(uint LocalID, UUID itemID, UUID hostID, int channel, string name, UUID id, string msg);
+ ///
+ /// Create a listen event callback with the specified filters.
+ /// The parameters localID,itemID are needed to uniquely identify
+ /// the script during 'peek' time. Parameter hostID is needed to
+ /// determine the position of the script.
+ ///
+ /// localID of the script engine
+ /// UUID of the script engine
+ /// UUID of the SceneObjectPart
+ /// channel to listen on
+ /// name to filter on
+ /// key to filter on (user given, could be totally faked)
+ /// msg to filter on
+ /// Bitfield indicating which strings should be processed as regex.
+ /// number of the scripts handle
+ int Listen(uint LocalID, UUID itemID, UUID hostID, int channel, string name, UUID id, string msg, int regexBitfield);
+
///
/// This method scans over the objects which registered an interest in listen callbacks.
/// For everyone it finds, it checks if it fits the given filter. If it does, then
diff --git a/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs b/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs
index ad421eeedb..3d8e8be795 100644
--- a/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs
+++ b/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs
@@ -41,12 +41,13 @@ namespace OpenSim.Region.Framework.Scenes.Animation
{
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+ private OpenSim.Framework.Animation m_implicitDefaultAnimation = new OpenSim.Framework.Animation();
private OpenSim.Framework.Animation m_defaultAnimation = new OpenSim.Framework.Animation();
private List m_animations = new List();
- public OpenSim.Framework.Animation DefaultAnimation
+ public OpenSim.Framework.Animation ImplicitDefaultAnimation
{
- get { return m_defaultAnimation; }
+ get { return m_implicitDefaultAnimation; }
}
public AnimationSet()
@@ -119,6 +120,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation
if (m_defaultAnimation.AnimID != animID)
{
m_defaultAnimation = new OpenSim.Framework.Animation(animID, sequenceNum, objectID);
+ m_implicitDefaultAnimation = m_defaultAnimation;
return true;
}
return false;
diff --git a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs
index 6e53951003..df432718d4 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs
@@ -38,7 +38,18 @@ namespace OpenSim.Region.Framework.Scenes
{
public partial class Scene
{
-
+ ///
+ /// Send chat to listeners.
+ ///
+ ///
+ /// /param>
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
protected void SimChat(byte[] message, ChatTypeEnum type, int channel, Vector3 fromPos, string fromName,
UUID fromID, UUID targetID, bool fromAgent, bool broadcast)
{
@@ -66,6 +77,10 @@ namespace OpenSim.Region.Framework.Scenes
args.From = fromName;
args.TargetUUID = targetID;
+// m_log.DebugFormat(
+// "[SCENE]: Sending message {0} on channel {1}, type {2} from {3}, broadcast {4}",
+// args.Message.Replace("\n", "\\n"), args.Channel, args.Type, fromName, broadcast);
+
if (broadcast)
EventManager.TriggerOnChatBroadcast(this, args);
else
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index 5f45529ca8..9c61fe7da8 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -1267,6 +1267,12 @@ namespace OpenSim.Region.Framework.Scenes
// This is the method that shuts down the scene.
public override void Close()
{
+ if (m_shuttingDown)
+ {
+ m_log.WarnFormat("[SCENE]: Ignoring close request because already closing {0}", Name);
+ return;
+ }
+
m_log.InfoFormat("[SCENE]: Closing down the single simulator: {0}", RegionInfo.RegionName);
StatsReporter.Close();
@@ -1310,6 +1316,14 @@ namespace OpenSim.Region.Framework.Scenes
m_sceneGraph.Close();
+ if (!GridService.DeregisterRegion(RegionInfo.RegionID))
+ m_log.WarnFormat("[SCENE]: Deregister from grid failed for region {0}", Name);
+
+ base.Close();
+
+ // XEngine currently listens to the EventManager.OnShutdown event to trigger script stop and persistence.
+ // Therefore. we must dispose of the PhysicsScene after this to prevent a window where script code can
+ // attempt to reference a null or disposed physics scene.
if (PhysicsScene != null)
{
PhysicsScene phys = PhysicsScene;
@@ -1318,12 +1332,6 @@ namespace OpenSim.Region.Framework.Scenes
phys.Dispose();
phys = null;
}
-
- if (!GridService.DeregisterRegion(RegionInfo.RegionID))
- m_log.WarnFormat("[SCENE]: Deregister from grid failed for region {0}", Name);
-
- // call the base class Close method.
- base.Close();
}
///
@@ -3427,9 +3435,10 @@ namespace OpenSim.Region.Framework.Scenes
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);
+// // REFACTORING PROBLEM -- well not really a problem, but just to point out that whatever
+// // this method is doing is HORRIBLE!!!
+ // Commented pending deletion since this method no longer appears to do anything at all
+// avatar.Scene.NeedSceneCacheClear(avatar.UUID);
if (closeChildAgents && !isChildAgent)
{
@@ -4688,12 +4697,23 @@ namespace OpenSim.Region.Framework.Scenes
/// Get a group via its UUID
///
///
- /// null if no group with that name exists
+ /// null if no group with that id exists
public SceneObjectGroup GetSceneObjectGroup(UUID fullID)
{
return m_sceneGraph.GetSceneObjectGroup(fullID);
}
+ ///
+ /// Get a group via its local ID
+ ///
+ /// This will only return a group if the local ID matches a root part
+ ///
+ /// null if no group with that id exists
+ public SceneObjectGroup GetSceneObjectGroup(uint localID)
+ {
+ return m_sceneGraph.GetSceneObjectGroup(localID);
+ }
+
///
/// Get a group by name from the scene (will return the first
/// found, if there are more than one prim with the same name)
@@ -4854,14 +4874,15 @@ namespace OpenSim.Region.Framework.Scenes
client.SendRegionHandle(regionID, handle);
}
- public bool NeedSceneCacheClear(UUID agentID)
- {
- IInventoryTransferModule inv = RequestModuleInterface();
- if (inv == null)
- return true;
-
- return inv.NeedSceneCacheClear(agentID, this);
- }
+// Commented pending deletion since this method no longer appears to do anything at all
+// public bool NeedSceneCacheClear(UUID agentID)
+// {
+// IInventoryTransferModule inv = RequestModuleInterface();
+// if (inv == null)
+// return true;
+//
+// return inv.NeedSceneCacheClear(agentID, this);
+// }
public void CleanTempObjects()
{
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
index 209a770396..a4383fd23b 100644
--- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
@@ -982,6 +982,30 @@ namespace OpenSim.Region.Framework.Scenes
return null;
}
+ ///
+ /// Get a group in the scene
+ ///
+ ///
+ /// This will only return a group if the local ID matches the root part, not other parts.
+ ///
+ /// Local id of the root part of the group
+ /// null if no such group was found
+ protected internal SceneObjectGroup GetSceneObjectGroup(uint localID)
+ {
+ lock (SceneObjectGroupsByLocalPartID)
+ {
+ if (SceneObjectGroupsByLocalPartID.ContainsKey(localID))
+ {
+ SceneObjectGroup so = SceneObjectGroupsByLocalPartID[localID];
+
+ if (so.LocalId == localID)
+ return so;
+ }
+ }
+
+ return null;
+ }
+
///
/// Get a group by name from the scene (will return the first
/// found, if there are more than one prim with the same name)
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index 1222ac6bcf..b6d0a3b661 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -68,7 +68,7 @@ namespace OpenSim.Region.Framework.Scenes
public ScriptControlled eventControls;
}
- public delegate void SendCourseLocationsMethod(UUID scene, ScenePresence presence, List coarseLocations, List avatarUUIDs);
+ public delegate void SendCoarseLocationsMethod(UUID scene, ScenePresence presence, List coarseLocations, List avatarUUIDs);
public class ScenePresence : EntityBase, IScenePresence
{
@@ -186,7 +186,7 @@ namespace OpenSim.Region.Framework.Scenes
///
public bool SitGround { get; private set; }
- private SendCourseLocationsMethod m_sendCourseLocationsMethod;
+ private SendCoarseLocationsMethod m_sendCoarseLocationsMethod;
//private Vector3 m_requestedSitOffset = new Vector3();
@@ -695,7 +695,7 @@ namespace OpenSim.Region.Framework.Scenes
AttachmentsSyncLock = new Object();
AllowMovement = true;
IsChildAgent = true;
- m_sendCourseLocationsMethod = SendCoarseLocationsDefault;
+ m_sendCoarseLocationsMethod = SendCoarseLocationsDefault;
Animator = new ScenePresenceAnimator(this);
PresenceType = type;
DrawDistance = world.DefaultDrawDistance;
@@ -2432,17 +2432,17 @@ namespace OpenSim.Region.Framework.Scenes
public void SendCoarseLocations(List coarseLocations, List avatarUUIDs)
{
- SendCourseLocationsMethod d = m_sendCourseLocationsMethod;
+ SendCoarseLocationsMethod d = m_sendCoarseLocationsMethod;
if (d != null)
{
d.Invoke(m_scene.RegionInfo.originRegionID, this, coarseLocations, avatarUUIDs);
}
}
- public void SetSendCourseLocationMethod(SendCourseLocationsMethod d)
+ public void SetSendCoarseLocationMethod(SendCoarseLocationsMethod d)
{
if (d != null)
- m_sendCourseLocationsMethod = d;
+ m_sendCoarseLocationsMethod = d;
}
public void SendCoarseLocationsDefault(UUID sceneId, ScenePresence p, List coarseLocations, List avatarUUIDs)
@@ -2646,7 +2646,7 @@ namespace OpenSim.Region.Framework.Scenes
#region Significant Movement Method
///
- /// This checks for a significant movement and sends a courselocationchange update
+ /// This checks for a significant movement and sends a coarselocationchange update
///
protected void CheckForSignificantMovement()
{
diff --git a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
index 2addb5bab8..b9d615e804 100644
--- a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
+++ b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
@@ -245,11 +245,13 @@ namespace OpenSim.Region.Framework.Scenes
= new Stat(
"SlowFrames",
"Slow Frames",
+ "Number of frames where frame time has been significantly longer than the desired frame time.",
" frames",
"scene",
m_scene.Name,
- StatVerbosity.Info,
- "Number of frames where frame time has been significantly longer than the desired frame time.");
+ StatType.Push,
+ null,
+ StatVerbosity.Info);
StatsManager.RegisterStat(SlowFramesStat);
}
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs
index d722a0990a..ac3da1e2cc 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs
@@ -65,5 +65,22 @@ namespace OpenSim.Region.Framework.Scenes.Tests
Assert.That(scene.Frame, Is.EqualTo(1));
}
+
+ [Test]
+ public void TestShutdownScene()
+ {
+ TestHelpers.InMethod();
+
+ Scene scene = new SceneHelpers().SetupScene();
+ scene.Close();
+
+ Assert.That(scene.ShuttingDown, Is.True);
+ Assert.That(scene.Active, Is.False);
+
+ // Trying to update a shutdown scene should result in no update
+ scene.Update(1);
+
+ Assert.That(scene.Frame, Is.EqualTo(0));
+ }
}
}
\ No newline at end of file
diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
index e93bd7cb1d..781539acc1 100644
--- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
+++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
@@ -954,7 +954,8 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
}
- public void SendChatMessage(string message, byte type, Vector3 fromPos, string fromName, UUID fromAgentID, byte source, byte audible)
+ public void SendChatMessage(
+ string message, byte type, Vector3 fromPos, string fromName, UUID fromAgentID, UUID ownerID, byte source, byte audible)
{
if (audible > 0 && message.Length > 0)
IRC_SendChannelPrivmsg(fromName, message);
diff --git a/OpenSim/Region/OptionalModules/Asset/AssetInfoModule.cs b/OpenSim/Region/OptionalModules/Asset/AssetInfoModule.cs
index 41ec14f224..7639c6ce45 100644
--- a/OpenSim/Region/OptionalModules/Asset/AssetInfoModule.cs
+++ b/OpenSim/Region/OptionalModules/Asset/AssetInfoModule.cs
@@ -127,6 +127,9 @@ namespace OpenSim.Region.OptionalModules.Asset
}
string fileName = rawAssetId;
+
+ if (!ConsoleUtil.CheckFileDoesNotExist(MainConsole.Instance, fileName))
+ return;
using (FileStream fs = new FileStream(fileName, FileMode.CreateNew))
{
diff --git a/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs b/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs
index e22618dff3..5c3be29e9a 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs
@@ -546,8 +546,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.Concierge
c.SenderUUID = UUID.Zero;
c.Scene = agent.Scene;
- agent.ControllingClient.SendChatMessage(msg, (byte) ChatTypeEnum.Say, PosOfGod, m_whoami, UUID.Zero,
- (byte)ChatSourceType.Object, (byte)ChatAudibleLevel.Fully);
+ agent.ControllingClient.SendChatMessage(
+ msg, (byte) ChatTypeEnum.Say, PosOfGod, m_whoami, UUID.Zero, UUID.Zero,
+ (byte)ChatSourceType.Object, (byte)ChatAudibleLevel.Fully);
}
private static void checkStringParameters(XmlRpcRequest request, string[] param)
diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
index ffd4222935..5ea2bcd908 100644
--- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
+++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
@@ -603,13 +603,15 @@ namespace OpenSim.Region.OptionalModules.World.NPC
{
}
- public virtual void SendChatMessage(string message, byte type, Vector3 fromPos, string fromName,
- UUID fromAgentID, byte source, byte audible)
+ public virtual void SendChatMessage(
+ string message, byte type, Vector3 fromPos, string fromName,
+ UUID fromAgentID, UUID ownerID, byte source, byte audible)
{
}
- public virtual void SendChatMessage(byte[] message, byte type, Vector3 fromPos, string fromName,
- UUID fromAgentID, byte source, byte audible)
+ public virtual void SendChatMessage(
+ byte[] message, byte type, Vector3 fromPos, string fromName,
+ UUID fromAgentID, UUID ownerID, byte source, byte audible)
{
}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index 623ac8ff16..a041ba8e0a 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -105,7 +105,7 @@ public class BSCharacter : BSPhysObject
shapeData.Position = _position;
shapeData.Rotation = _orientation;
shapeData.Velocity = _velocity;
- shapeData.Size = Scale;
+ shapeData.Size = Scale; // capsule is a native shape but scale is not just <1,1,1>
shapeData.Scale = Scale;
shapeData.Mass = _mass;
shapeData.Buoyancy = _buoyancy;
@@ -144,7 +144,9 @@ public class BSCharacter : BSPhysObject
ForcePosition = _position;
// Set the velocity and compute the proper friction
ForceVelocity = _velocity;
+
BulletSimAPI.SetRestitution2(BSBody.ptr, PhysicsScene.Params.avatarRestitution);
+ BulletSimAPI.SetMargin2(BSShape.ptr, PhysicsScene.Params.collisionMargin);
BulletSimAPI.SetLocalScaling2(BSShape.ptr, Scale);
BulletSimAPI.SetContactProcessingThreshold2(BSBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
if (PhysicsScene.Params.ccdMotionThreshold > 0f)
@@ -156,16 +158,20 @@ public class BSCharacter : BSPhysObject
OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(BSShape.ptr, MassRaw);
BulletSimAPI.SetMassProps2(BSBody.ptr, MassRaw, localInertia);
+ // Make so capsule does not fall over
+ BulletSimAPI.SetAngularFactorV2(BSBody.ptr, OMV.Vector3.Zero);
+
BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT);
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, BSBody.ptr);
- BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG);
+ // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG);
+ BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.DISABLE_DEACTIVATION);
BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, BSBody.ptr);
// Do this after the object has been added to the world
BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr,
- (uint)CollisionFilterGroups.AvatarFilter,
+ (uint)CollisionFilterGroups.AvatarFilter,
(uint)CollisionFilterGroups.AvatarMask);
}
@@ -175,11 +181,13 @@ public class BSCharacter : BSPhysObject
}
// No one calls this method so I don't know what it could possibly mean
public override bool Stopped { get { return false; } }
+
public override OMV.Vector3 Size {
get
{
// Avatar capsule size is kept in the scale parameter.
- return _size;
+ // return _size;
+ return new OMV.Vector3(Scale.X * 2f, Scale.Y * 2f, Scale.Z);
}
set {
@@ -199,7 +207,9 @@ public class BSCharacter : BSPhysObject
}
}
+
public override OMV.Vector3 Scale { get; set; }
+
public override PrimitiveBaseShape Shape
{
set { BaseShape = value; }
@@ -264,12 +274,12 @@ public class BSCharacter : BSPhysObject
// Check that the current position is sane and, if not, modify the position to make it so.
- // Check for being below terrain and being out of bounds.
+ // Check for being below terrain or on water.
// Returns 'true' of the position was made sane by some action.
private bool PositionSanityCheck()
{
bool ret = false;
-
+
// If below the ground, move the avatar up
float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
if (Position.Z < terrainHeight)
@@ -335,7 +345,7 @@ public class BSCharacter : BSPhysObject
}
// Avatars don't do vehicles
- public override int VehicleType { get { return 0; } set { return; } }
+ public override int VehicleType { get { return (int)Vehicle.TYPE_NONE; } set { return; } }
public override void VehicleFloatParam(int param, float value) { }
public override void VehicleVectorParam(int param, OMV.Vector3 value) {}
public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { }
@@ -413,7 +423,7 @@ public class BSCharacter : BSPhysObject
});
}
}
- // Go directly to Bullet to get/set the value.
+ // Go directly to Bullet to get/set the value.
public override OMV.Quaternion ForceOrientation
{
get
@@ -478,7 +488,7 @@ public class BSCharacter : BSPhysObject
set { _collidingObj = value; }
}
public override bool FloatOnWater {
- set {
+ set {
_floatOnWater = value;
PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate()
{
@@ -588,9 +598,8 @@ public class BSCharacter : BSPhysObject
newScale.X = PhysicsScene.Params.avatarCapsuleRadius;
newScale.Y = PhysicsScene.Params.avatarCapsuleRadius;
- // From the total height, remote the capsule half spheres that are at each end
- newScale.Z = (size.Z * 2f) - Math.Min(newScale.X, newScale.Y);
- // newScale.Z = (size.Z * 2f);
+ // From the total height, remove the capsule half spheres that are at each end
+ newScale.Z = size.Z- (newScale.X + newScale.Y);
Scale = newScale;
}
@@ -636,7 +645,7 @@ public class BSCharacter : BSPhysObject
BulletSimAPI.SetLinearVelocity2(BSBody.ptr, avVel);
}
- // Tell the linkset about this
+ // Tell the linkset about value changes
Linkset.UpdateProperties(this);
// Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
index a20be3a285..f017cdd669 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
@@ -34,6 +34,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
public abstract class BSConstraint : IDisposable
{
+ private static string LogHeader = "[BULLETSIM CONSTRAINT]";
+
protected BulletSim m_world;
protected BulletBody m_body1;
protected BulletBody m_body2;
@@ -53,7 +55,7 @@ public abstract class BSConstraint : IDisposable
{
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,
+ BSScene.DetailLogZero,
m_body1.ID, m_body1.ptr.ToString("X"),
m_body2.ID, m_body2.ptr.ToString("X"),
success);
@@ -124,7 +126,7 @@ public abstract class BSConstraint : IDisposable
}
else
{
- m_world.physicsScene.Logger.ErrorFormat("[BULLETSIM CONSTRAINT] CalculateTransforms failed. A={0}, B={1}", Body1.ID, Body2.ID);
+ m_world.physicsScene.Logger.ErrorFormat("{0} CalculateTransforms failed. A={1}, B={2}", LogHeader, Body1.ID, Body2.ID);
}
}
return ret;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index 56342b88f8..117c8787d1 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -23,7 +23,7 @@
* 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.
- */
+ *
/* RA: June 14, 2011. Copied from ODEDynamics.cs and converted to
* call the BulletSim system.
@@ -352,7 +352,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// m_bankingMix = 1;
// m_bankingTimescale = 1;
// m_referenceFrame = Quaternion.Identity;
- m_flags |= (VehicleFlag.NO_DEFLECTION_UP
+ m_flags |= (VehicleFlag.NO_DEFLECTION_UP
| VehicleFlag.LIMIT_ROLL_ONLY
| VehicleFlag.LIMIT_MOTOR_UP);
m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT);
@@ -382,7 +382,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// m_bankingTimescale = 1;
// m_referenceFrame = Quaternion.Identity;
m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY
- | VehicleFlag.HOVER_GLOBAL_HEIGHT
+ | VehicleFlag.HOVER_GLOBAL_HEIGHT
| VehicleFlag.LIMIT_ROLL_ONLY
| VehicleFlag.HOVER_UP_ONLY);
m_flags |= (VehicleFlag.NO_DEFLECTION_UP
@@ -458,14 +458,15 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// Do any updating needed for a vehicle
public void Refresh()
{
- if (!IsActive)
+ if (!IsActive)
return;
// Set the prim's inertia to zero. The vehicle code handles that and this
// 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);
+ // comment out for DEBUG test
+ // BulletSimAPI.SetMassProps2(Prim.BSBody.ptr, Prim.MassRaw, inertia);
+ // BulletSimAPI.UpdateInertiaTensor2(Prim.BSBody.ptr);
}
// One step of the vehicle properties for the next 'pTimestep' seconds.
@@ -791,7 +792,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// Sum velocities
m_lastAngularVelocity = m_angularMotorVelocity + vertattr; // + bank + deflection
-
+
if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
{
m_lastAngularVelocity.X = 0;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
index 43b12623cc..c984824278 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
@@ -32,10 +32,27 @@ using OMV = OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin
{
-public class BSLinkset
+public abstract class BSLinkset
{
// private static string LogHeader = "[BULLETSIM LINKSET]";
+ // Create the correct type of linkset for this child
+ public static BSLinkset Factory(BSScene physScene, BSPhysObject parent)
+ {
+ BSLinkset ret = null;
+ /*
+ if (parent.IsPhysical)
+ ret = new BSLinksetConstraints(physScene, parent);
+ else
+ ret = new BSLinksetManual(physScene, parent);
+ */
+
+ // at the moment, there is only one
+ ret = new BSLinksetConstraints(physScene, parent);
+
+ return ret;
+ }
+
public BSPhysObject LinksetRoot { get; protected set; }
public BSScene PhysicsScene { get; private set; }
@@ -52,16 +69,16 @@ public class BSLinkset
// the physical 'taint' children separately.
// After taint processing and before the simulation step, these
// two lists must be the same.
- private HashSet m_children;
- private HashSet m_taintChildren;
+ protected HashSet m_children;
+ protected HashSet m_taintChildren;
// We lock the diddling of linkset classes to prevent any badness.
// This locks the modification of the instances of this class. Changes
// to the physical representation is done via the tainting mechenism.
- private object m_linksetActivityLock = new Object();
+ protected object m_linksetActivityLock = new Object();
// We keep the prim's mass in the linkset structure since it could be dependent on other prims
- private float m_mass;
+ protected float m_mass;
public float LinksetMass
{
get
@@ -81,7 +98,7 @@ public class BSLinkset
get { return ComputeLinksetGeometricCenter(); }
}
- public BSLinkset(BSScene scene, BSPhysObject parent)
+ protected void Initialize(BSScene scene, BSPhysObject parent)
{
// A simple linkset of one (no children)
LinksetID = m_nextLinksetID++;
@@ -128,7 +145,7 @@ public class BSLinkset
}
// The child is down to a linkset of just itself
- return new BSLinkset(PhysicsScene, child);
+ return BSLinkset.Factory(PhysicsScene, child);
}
// Return 'true' if the passed object is the root object of this linkset
@@ -148,6 +165,9 @@ public class BSLinkset
bool ret = false;
lock (m_linksetActivityLock)
{
+ if (m_children.Contains(child))
+ ret = true;
+ /*
foreach (BSPhysObject bp in m_children)
{
if (child.LocalID == bp.LocalID)
@@ -156,6 +176,7 @@ public class BSLinkset
break;
}
}
+ */
}
return ret;
}
@@ -163,24 +184,7 @@ public class BSLinkset
// 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);
- }
+ public abstract void Refresh(BSPhysObject requestor, bool inTaintTime);
// The object is going dynamic (physical). Do any setup necessary
// for a dynamic linkset.
@@ -188,102 +192,35 @@ public class BSLinkset
// has not yet been fully constructed.
// Return 'true' if any properties updated on the passed object.
// Called at taint-time!
- public bool MakeDynamic(BSPhysObject child)
- {
- // What is done for each object in BSPrim is what we want.
- return false;
- }
+ public abstract bool MakeDynamic(BSPhysObject child);
// The object is going static (non-physical). Do any setup necessary
// for a static linkset.
// Return 'true' if any properties updated on the passed object.
// Called at taint-time!
- public bool MakeStatic(BSPhysObject child)
- {
- // What is done for each object in BSPrim is what we want.
- return false;
- }
+ public abstract bool MakeStatic(BSPhysObject child);
- // 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 when a parameter update comes from the physics engine for any object
+ // of the linkset is received.
// Called at taint-time!!
- public void UpdateProperties(BSPhysObject physObject)
- {
- // The root local properties have been updated. Apply to the children if appropriate.
- if (IsRoot(physObject) && HasAnyChildren)
- {
- if (!physObject.IsPhysical)
- {
- // TODO: implement software linkset update for static object linksets
- }
- }
- }
+ public abstract void UpdateProperties(BSPhysObject physObject);
// Routine used when rebuilding the body of the root of the linkset
// Destroy all the constraints have have been made to root.
// This is called when the root body is changing.
- // Returns 'true' of something eas actually removed and would need restoring
+ // Returns 'true' of something was actually removed and would need restoring
// Called at taint-time!!
- public bool RemoveBodyDependencies(BSPrim child)
- {
- bool ret = false;
-
- lock (m_linksetActivityLock)
- {
- if (IsRoot(child))
- {
- // If the one with the dependency is root, must undo all children
- DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}",
- child.LocalID, LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
-
- ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
- }
- else
- {
- DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
- child.LocalID,
- LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
- child.LocalID, child.BSBody.ptr.ToString("X"));
- // ret = PhysicallyUnlinkAChildFromRoot(LinksetRoot, child);
- // Despite the function name, this removes any link to the specified object.
- ret = PhysicallyUnlinkAllChildrenFromRoot(child);
- }
- }
- return ret;
- }
+ public abstract bool RemoveBodyDependencies(BSPrim child);
// Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
- // this routine will restore the removed constraints.
+ // this routine will restore the removed constraints.
// Called at taint-time!!
- public void RestoreBodyDependencies(BSPrim child)
- {
- lock (m_linksetActivityLock)
- {
- if (IsRoot(child))
- {
- DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreChildrenForRoot,rID={1},numChild={2}",
- child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count);
- foreach (BSPhysObject bpo in m_taintChildren)
- {
- PhysicallyLinkAChildToRoot(LinksetRoot, bpo);
- }
- }
- else
- {
- DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
- LinksetRoot.LocalID,
- LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
- child.LocalID, child.BSBody.ptr.ToString("X"));
- PhysicallyLinkAChildToRoot(LinksetRoot, child);
- }
- }
- }
+ public abstract void RestoreBodyDependencies(BSPrim child);
// ================================================================
// Below this point is internal magic
- private float ComputeLinksetMass()
+ protected virtual float ComputeLinksetMass()
{
float mass;
lock (m_linksetActivityLock)
@@ -297,7 +234,7 @@ public class BSLinkset
return mass;
}
- private OMV.Vector3 ComputeLinksetCenterOfMass()
+ protected virtual OMV.Vector3 ComputeLinksetCenterOfMass()
{
OMV.Vector3 com;
lock (m_linksetActivityLock)
@@ -317,7 +254,7 @@ public class BSLinkset
return com;
}
- private OMV.Vector3 ComputeLinksetGeometricCenter()
+ protected virtual OMV.Vector3 ComputeLinksetGeometricCenter()
{
OMV.Vector3 com;
lock (m_linksetActivityLock)
@@ -336,236 +273,21 @@ public class BSLinkset
// I am the root of a linkset and a new child is being added
// Called while LinkActivity is locked.
- private void AddChildToLinkset(BSPhysObject child)
- {
- if (!HasChild(child))
- {
- m_children.Add(child);
-
- BSPhysObject rootx = LinksetRoot; // capture the root as of now
- BSPhysObject childx = child;
-
- DetailLog("{0},AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
-
- PhysicsScene.TaintedObject("AddChildToLinkset", delegate()
- {
- 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
- rootx.ForcePosition = rootx.Position; // DEBUG
- childx.ForcePosition = childx.Position; // DEBUG
- PhysicallyLinkAChildToRoot(rootx, childx);
- m_taintChildren.Add(child);
- });
- }
- return;
- }
+ protected abstract void AddChildToLinkset(BSPhysObject child);
// Forcefully removing a child from a linkset.
// This is not being called by the child so we have to make sure the child doesn't think
// it's still connected to the linkset.
// Normal OpenSimulator operation will never do this because other SceneObjectPart information
// also has to be updated (like pointer to prim's parent).
- private void RemoveChildFromOtherLinkset(BSPhysObject pchild)
- {
- pchild.Linkset = new BSLinkset(PhysicsScene, pchild);
- RemoveChildFromLinkset(pchild);
- }
+ protected abstract void RemoveChildFromOtherLinkset(BSPhysObject pchild);
// I am the root of a linkset and one of my children is being removed.
// Safe to call even if the child is not really in my linkset.
- private void RemoveChildFromLinkset(BSPhysObject child)
- {
- if (m_children.Remove(child))
- {
- BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
- BSPhysObject childx = child;
-
- DetailLog("{0},RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
- childx.LocalID,
- rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
- childx.LocalID, childx.BSBody.ptr.ToString("X"));
-
- PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate()
- {
- m_taintChildren.Remove(child);
- PhysicallyUnlinkAChildFromRoot(rootx, childx);
- RecomputeLinksetConstraintVariables();
- });
-
- }
- else
- {
- // This will happen if we remove the root of the linkset first. Non-fatal occurance.
- // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader);
- }
- return;
- }
-
- // Create a constraint between me (root of linkset) and the passed prim (the child).
- // Called at taint time!
- private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
- {
- // Zero motion for children so they don't interpolate
- childPrim.ZeroMotion();
-
- // Relative position normalized to the root prim
- // Essentually a vector pointing from center of rootPrim to center of childPrim
- OMV.Vector3 childRelativePosition = childPrim.Position - rootPrim.Position;
-
- // real world coordinate of midpoint between the two objects
- OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
-
- DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
- rootPrim.LocalID,
- 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
-
- BS6DofConstraint constrain = new BS6DofConstraint(
- 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
- * of the objects.
- * Code left as a warning to future programmers.
- // ==================================================================================
- // relative position normalized to the root prim
- OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
- OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation;
-
- // relative rotation of the child to the parent
- OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
- OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);
-
- // create a constraint that allows no freedom of movement between the two objects
- // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
- 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,
- OMV.Quaternion.Inverse(rootPrim.Orientation),
- OMV.Vector3.Zero,
- OMV.Quaternion.Inverse(childPrim.Orientation),
- // A point half way between the parent and child
- // childRelativePosition/2,
- // childRelativeRotation,
- // childRelativePosition/2,
- // inverseChildRelativeRotation,
- true,
- true
- );
- // ==================================================================================
- */
-
- PhysicsScene.Constraints.AddConstraint(constrain);
-
- // zero linear and angular limits makes the objects unable to move in relation to each other
- constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
- constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
-
- // tweek the constraint to increase stability
- constrain.UseFrameOffset(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintUseFrameOffset));
- constrain.TranslationalLimitMotor(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintEnableTransMotor),
- PhysicsScene.Params.linkConstraintTransMotorMaxVel,
- PhysicsScene.Params.linkConstraintTransMotorMaxForce);
- constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP);
- if (PhysicsScene.Params.linkConstraintSolverIterations != 0f)
- {
- constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations);
- }
- }
-
- // 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 bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
- {
- bool ret = false;
- DetailLog("{0},BSLinkset.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
- rootPrim.LocalID,
- 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
- if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody, childPrim.BSBody))
- {
- // Make the child refresh its location
- BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr);
- ret = true;
- }
-
- return ret;
- }
-
- // Remove linkage between myself and any possible children I might have.
- // Called at taint time!
- private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
- {
- DetailLog("{0},BSLinkset.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
- bool ret = false;
-
- 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
- // from a linkset to make sure the constraints know about the new mass and
- // geometry.
- // Must only be called at taint time!!
- private void RecomputeLinksetConstraintVariables()
- {
- float linksetMass = LinksetMass;
- foreach (BSPhysObject child in m_taintChildren)
- {
- BSConstraint constrain;
- if (PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.BSBody, child.BSBody, out constrain))
- {
- // DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,taint,child={1},mass={2},A={3},B={4}",
- // LinksetRoot.LocalID, child.LocalID, linksetMass, constrain.Body1.ID, constrain.Body2.ID);
- constrain.RecomputeConstraintVariables(linksetMass);
- }
- else
- {
- // Non-fatal error that happens when children are being added to the linkset but
- // their constraints have not been created yet.
- break;
- }
- }
-
- // If the whole linkset is not here, doesn't make sense to recompute linkset wide values
- if (m_children.Count == m_taintChildren.Count)
- {
- // 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);
- 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.DumpAllInfo2(PhysicsScene.World.ptr); // DEBUG DEBUG DEBUG
- }
- return;
- }
-
+ protected abstract void RemoveChildFromLinkset(BSPhysObject child);
// Invoke the detailed logger and output something if it's enabled.
- private void DetailLog(string msg, params Object[] args)
+ protected void DetailLog(string msg, params Object[] args)
{
if (PhysicsScene.PhysicsLogging.Enabled)
PhysicsScene.DetailLog(msg, args);
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
new file mode 100755
index 0000000000..8a750b52b7
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
@@ -0,0 +1,385 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyrightD
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+using OMV = OpenMetaverse;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+public class BSLinksetConstraints : BSLinkset
+{
+ // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]";
+
+ public BSLinksetConstraints(BSScene scene, BSPhysObject parent)
+ {
+ base.Initialize(scene, parent);
+ }
+
+ // 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 override void Refresh(BSPhysObject requestor, bool inTaintTime)
+ {
+ // If there are no children or not root, I am not the one that recomputes the constraints
+ if (!HasAnyChildren || !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
+ // has not yet been fully constructed.
+ // Return 'true' if any properties updated on the passed object.
+ // Called at taint-time!
+ public override bool MakeDynamic(BSPhysObject child)
+ {
+ // What is done for each object in BSPrim is what we want.
+ return false;
+ }
+
+ // The object is going static (non-physical). Do any setup necessary
+ // for a static linkset.
+ // Return 'true' if any properties updated on the passed object.
+ // Called at taint-time!
+ public override bool MakeStatic(BSPhysObject child)
+ {
+ // What is done for each object in BSPrim is what we want.
+ return false;
+ }
+
+ // Called at taint-time!!
+ public override void UpdateProperties(BSPhysObject updated)
+ {
+ // Nothing to do for constraints on property updates
+ }
+
+ // Routine used when rebuilding the body of the root of the linkset
+ // Destroy all the constraints have have been made to root.
+ // This is called when the root body is changing.
+ // Returns 'true' of something eas actually removed and would need restoring
+ // Called at taint-time!!
+ public override bool RemoveBodyDependencies(BSPrim child)
+ {
+ bool ret = false;
+
+ lock (m_linksetActivityLock)
+ {
+ if (IsRoot(child))
+ {
+ // If the one with the dependency is root, must undo all children
+ DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}",
+ child.LocalID, LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
+
+ ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
+ }
+ else
+ {
+ DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
+ child.LocalID,
+ LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
+ child.LocalID, child.BSBody.ptr.ToString("X"));
+ // ret = PhysicallyUnlinkAChildFromRoot(LinksetRoot, child);
+ // Despite the function name, this removes any link to the specified object.
+ ret = PhysicallyUnlinkAllChildrenFromRoot(child);
+ }
+ }
+ return ret;
+ }
+
+ // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
+ // this routine will restore the removed constraints.
+ // Called at taint-time!!
+ public override void RestoreBodyDependencies(BSPrim child)
+ {
+ lock (m_linksetActivityLock)
+ {
+ if (IsRoot(child))
+ {
+ DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreChildrenForRoot,rID={1},numChild={2}",
+ child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count);
+ foreach (BSPhysObject bpo in m_taintChildren)
+ {
+ PhysicallyLinkAChildToRoot(LinksetRoot, bpo);
+ }
+ }
+ else
+ {
+ DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
+ LinksetRoot.LocalID,
+ LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
+ child.LocalID, child.BSBody.ptr.ToString("X"));
+ PhysicallyLinkAChildToRoot(LinksetRoot, child);
+ }
+ }
+ }
+
+ // ================================================================
+ // Below this point is internal magic
+
+ // I am the root of a linkset and a new child is being added
+ // Called while LinkActivity is locked.
+ protected override void AddChildToLinkset(BSPhysObject child)
+ {
+ if (!HasChild(child))
+ {
+ m_children.Add(child);
+
+ BSPhysObject rootx = LinksetRoot; // capture the root as of now
+ BSPhysObject childx = child;
+
+ DetailLog("{0},AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
+
+ PhysicsScene.TaintedObject("AddChildToLinkset", delegate()
+ {
+ 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
+ rootx.ForcePosition = rootx.Position; // DEBUG
+ childx.ForcePosition = childx.Position; // DEBUG
+ PhysicallyLinkAChildToRoot(rootx, childx);
+ m_taintChildren.Add(child);
+ });
+ }
+ return;
+ }
+
+ // Forcefully removing a child from a linkset.
+ // This is not being called by the child so we have to make sure the child doesn't think
+ // it's still connected to the linkset.
+ // Normal OpenSimulator operation will never do this because other SceneObjectPart information
+ // also has to be updated (like pointer to prim's parent).
+ protected override void RemoveChildFromOtherLinkset(BSPhysObject pchild)
+ {
+ pchild.Linkset = BSLinkset.Factory(PhysicsScene, pchild);
+ RemoveChildFromLinkset(pchild);
+ }
+
+ // I am the root of a linkset and one of my children is being removed.
+ // Safe to call even if the child is not really in my linkset.
+ protected override void RemoveChildFromLinkset(BSPhysObject child)
+ {
+ if (m_children.Remove(child))
+ {
+ BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
+ BSPhysObject childx = child;
+
+ DetailLog("{0},RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
+ childx.LocalID,
+ rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
+ childx.LocalID, childx.BSBody.ptr.ToString("X"));
+
+ PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate()
+ {
+ m_taintChildren.Remove(child);
+ PhysicallyUnlinkAChildFromRoot(rootx, childx);
+ RecomputeLinksetConstraintVariables();
+ });
+
+ }
+ else
+ {
+ // This will happen if we remove the root of the linkset first. Non-fatal occurance.
+ // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader);
+ }
+ return;
+ }
+
+ // Create a constraint between me (root of linkset) and the passed prim (the child).
+ // Called at taint time!
+ private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
+ {
+ // Zero motion for children so they don't interpolate
+ childPrim.ZeroMotion();
+
+ // Relative position normalized to the root prim
+ // Essentually a vector pointing from center of rootPrim to center of childPrim
+ OMV.Vector3 childRelativePosition = childPrim.Position - rootPrim.Position;
+
+ // real world coordinate of midpoint between the two objects
+ OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
+
+ DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
+ rootPrim.LocalID,
+ 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
+
+ BS6DofConstraint constrain = new BS6DofConstraint(
+ 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
+ * of the objects.
+ * Code left as a warning to future programmers.
+ // ==================================================================================
+ // relative position normalized to the root prim
+ OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
+ OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation;
+
+ // relative rotation of the child to the parent
+ OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
+ OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);
+
+ // create a constraint that allows no freedom of movement between the two objects
+ // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
+ 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,
+ OMV.Quaternion.Inverse(rootPrim.Orientation),
+ OMV.Vector3.Zero,
+ OMV.Quaternion.Inverse(childPrim.Orientation),
+ // A point half way between the parent and child
+ // childRelativePosition/2,
+ // childRelativeRotation,
+ // childRelativePosition/2,
+ // inverseChildRelativeRotation,
+ true,
+ true
+ );
+ // ==================================================================================
+ */
+
+ PhysicsScene.Constraints.AddConstraint(constrain);
+
+ // zero linear and angular limits makes the objects unable to move in relation to each other
+ constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
+ constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
+
+ // tweek the constraint to increase stability
+ constrain.UseFrameOffset(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintUseFrameOffset));
+ constrain.TranslationalLimitMotor(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintEnableTransMotor),
+ PhysicsScene.Params.linkConstraintTransMotorMaxVel,
+ PhysicsScene.Params.linkConstraintTransMotorMaxForce);
+ constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP);
+ if (PhysicsScene.Params.linkConstraintSolverIterations != 0f)
+ {
+ constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations);
+ }
+ }
+
+ // 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 bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
+ {
+ bool ret = false;
+ DetailLog("{0},BSLinkset.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
+ rootPrim.LocalID,
+ 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
+ if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody, childPrim.BSBody))
+ {
+ // Make the child refresh its location
+ BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr);
+ ret = true;
+ }
+
+ return ret;
+ }
+
+ // Remove linkage between myself and any possible children I might have.
+ // Called at taint time!
+ private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
+ {
+ DetailLog("{0},BSLinkset.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
+ bool ret = false;
+
+ 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
+ // from a linkset to make sure the constraints know about the new mass and
+ // geometry.
+ // Must only be called at taint time!!
+ private void RecomputeLinksetConstraintVariables()
+ {
+ float linksetMass = LinksetMass;
+ foreach (BSPhysObject child in m_taintChildren)
+ {
+ BSConstraint constrain;
+ if (PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.BSBody, child.BSBody, out constrain))
+ {
+ // DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,taint,child={1},mass={2},A={3},B={4}",
+ // LinksetRoot.LocalID, child.LocalID, linksetMass, constrain.Body1.ID, constrain.Body2.ID);
+ constrain.RecomputeConstraintVariables(linksetMass);
+ }
+ else
+ {
+ // Non-fatal error that happens when children are being added to the linkset but
+ // their constraints have not been created yet.
+ break;
+ }
+ }
+
+ // If the whole linkset is not here, doesn't make sense to recompute linkset wide values
+ if (m_children.Count == m_taintChildren.Count)
+ {
+ // 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);
+ 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.DumpAllInfo2(PhysicsScene.World.ptr); // DEBUG DEBUG DEBUG
+ }
+ return;
+ }
+}
+}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
index ead6a08f43..538f9056a5 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
@@ -46,7 +46,7 @@ public abstract class BSPhysObject : PhysicsActor
PhysObjectName = name;
TypeName = typeName;
- Linkset = new BSLinkset(PhysicsScene, this);
+ Linkset = BSLinkset.Factory(PhysicsScene, this);
LastAssetBuildFailed = false;
CollisionCollection = new CollisionEventUpdate();
@@ -78,7 +78,7 @@ public abstract class BSPhysObject : PhysicsActor
public PrimitiveBaseShape BaseShape { get; protected set; }
// When the physical properties are updated, an EntityProperty holds the update values.
- // Keep the current and last EntityProperties to enable computation of differences
+ // Keep the current and last EntityProperties to enable computation of differences
// between the current update and the previous values.
public EntityProperties CurrentEntityProperties { get; set; }
public EntityProperties LastEntityProperties { get; set; }
@@ -213,7 +213,7 @@ public abstract class BSPhysObject : PhysicsActor
UnSubscribeEvents();
}
}
- public override void UnSubscribeEvents() {
+ public override void UnSubscribeEvents() {
// DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName);
SubscribedEventsMs = 0;
PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate()
@@ -222,7 +222,7 @@ public abstract class BSPhysObject : PhysicsActor
});
}
// Return 'true' if the simulator wants collision events
- public override bool SubscribedEvents() {
+ public override bool SubscribedEvents() {
return (SubscribedEventsMs > 0);
}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index aeeb4dd27b..38ab3de65d 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -173,6 +173,7 @@ public sealed class BSPrim : BSPhysObject
}
public override bool ForceBodyShapeRebuild(bool inTaintTime)
{
+ LastAssetBuildFailed = false;
BSScene.TaintCallback rebuildOperation = delegate()
{
_mass = CalculateMass(); // changing the shape changes the mass
@@ -295,7 +296,7 @@ public sealed class BSPrim : BSPhysObject
private bool PositionSanityCheck()
{
bool ret = false;
-
+
// If totally below the ground, move the prim up
// TODO: figure out the right solution for this... only for dynamic objects?
/*
@@ -398,7 +399,7 @@ public sealed class BSPrim : BSPhysObject
{
// Done at taint time so we're sure the physics engine is not using the variables
// Vehicle code changes the parameters for this vehicle type.
- this._vehicle.ProcessTypeChange(type);
+ _vehicle.ProcessTypeChange(type);
});
}
}
@@ -510,7 +511,7 @@ public sealed class BSPrim : BSPhysObject
});
}
}
- // Go directly to Bullet to get/set the value.
+ // Go directly to Bullet to get/set the value.
public override OMV.Quaternion ForceOrientation
{
get
@@ -768,7 +769,7 @@ public sealed class BSPrim : BSPhysObject
}
}
public override bool FloatOnWater {
- set {
+ set {
_floatOnWater = value;
PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate()
{
@@ -971,7 +972,7 @@ public sealed class BSPrim : BSPhysObject
if (hollowAmount > 0.0)
{
hollowVolume *= hollowAmount;
-
+
switch (BaseShape.HollowShape)
{
case HollowShape.Square:
@@ -1245,13 +1246,14 @@ public sealed class BSPrim : BSPhysObject
FillShapeInfo(out shapeData);
// If this prim is part of a linkset, we must remove and restore the physical
- // links of the body is rebuilt.
+ // links if the body is rebuilt.
bool needToRestoreLinkset = false;
// Create the correct physical representation for this type of object.
// Updates BSBody and BSShape with the new information.
// Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary.
- PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, shapeData, BaseShape,
+ // Returns 'true' if either the body or the shape was changed.
+ PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, shapeData, BaseShape,
null, delegate(BulletBody dBody)
{
// Called if the current prim body is about to be destroyed.
@@ -1354,7 +1356,7 @@ public sealed class BSPrim : BSPhysObject
DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
- // BulletSimAPI.DumpRigidBody2(Scene.World.Ptr, BSBody.Ptr);
+ // BulletSimAPI.DumpRigidBody2(PhysicsScene.World.ptr, BSBody.ptr); // DEBUG DEBUG DEBUG
base.RequestPhysicsterseUpdate();
}
@@ -1367,8 +1369,8 @@ public sealed class BSPrim : BSPhysObject
entprop.Acceleration, entprop.RotationalVelocity);
}
*/
- // The linkset implimentation might want to know about this.
+ // The linkset implimentation might want to know about this.
Linkset.UpdateProperties(this);
}
}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index 6621d39f2c..db0c99e8d1 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -320,7 +320,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
{
m_log.Debug("[BULLETS UNMANAGED]:" + msg);
}
-
+
// Called directly from unmanaged code so don't do much
private void BulletLoggerPhysLog(string msg)
{
@@ -545,7 +545,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
}
// This is a kludge to get avatar movement updates.
- // The simulator expects collisions for avatars even if there are have been no collisions.
+ // The simulator expects collisions for avatars even if there are have been no collisions.
// The event updates avatar animations and stuff.
// If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
foreach (BSPhysObject bsp in m_avatars)
@@ -692,7 +692,6 @@ 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)
@@ -711,11 +710,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
{
try
{
- DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, oneCallback.ident); // DEBUG DEBUG DEBUG
+ DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, oneCallback.ident);
oneCallback.callback();
}
catch (Exception e)
{
+ DetailLog("{0},BSScene.ProcessTaints,doTaintException,id={1}", DetailLogZero, oneCallback.ident); // DEBUG DEBUG DEBUG
m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, oneCallback.ident, e);
}
}
@@ -1333,7 +1333,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// 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
+ // Used to fill in the LocalID when there isn't one. It's the correct number of characters.
public const string DetailLogZero = "0000000000";
}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
index d3ba2732a8..30fa50a6fd 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
@@ -36,7 +36,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
{
public class BSShapeCollection : IDisposable
{
- // private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]";
+ private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]";
protected BSScene PhysicsScene { get; set; }
@@ -89,7 +89,7 @@ public class BSShapeCollection : IDisposable
// higher level dependencies on the shape or body. Mostly used for LinkSets to
// remove the physical constraints before the body is destroyed.
// Called at taint-time!!
- public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim,
+ public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim,
ShapeData shapeData, PrimitiveBaseShape pbs,
ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
{
@@ -105,7 +105,7 @@ public class BSShapeCollection : IDisposable
// If we had to select a new shape geometry for the object,
// rebuild the body around it.
// Updates prim.BSBody with information/pointers to requested body
- bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World,
+ bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World,
prim.BSShape, shapeData, bodyCallback);
ret = newGeom || newBody;
}
@@ -325,7 +325,7 @@ public class BSShapeCollection : IDisposable
// Info in prim.BSShape is updated to the new shape.
// Returns 'true' if the geometry was rebuilt.
// Called at taint-time!
- private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeData shapeData,
+ private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeData shapeData,
PrimitiveBaseShape pbs, ShapeDestructionCallback shapeCallback)
{
bool ret = false;
@@ -335,9 +335,10 @@ public class BSShapeCollection : IDisposable
if (shapeData.Type == ShapeData.PhysicsShapeType.SHAPE_AVATAR)
{
// an avatar capsule is close to a native shape (it is not shared)
- ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_AVATAR,
+ ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_AVATAR,
ShapeData.FixedShapeKey.KEY_CAPSULE, shapeCallback);
DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.BSShape);
+ ret = true;
haveShape = true;
}
// If the prim attributes are simple, this could be a simple Bullet native shape
@@ -362,7 +363,7 @@ public class BSShapeCollection : IDisposable
|| prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_SPHERE
)
{
- ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_SPHERE,
+ ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_SPHERE,
ShapeData.FixedShapeKey.KEY_SPHERE, shapeCallback);
DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
prim.LocalID, forceRebuild, prim.BSShape);
@@ -376,7 +377,7 @@ public class BSShapeCollection : IDisposable
|| prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_BOX
)
{
- ret = GetReferenceToNativeShape( prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_BOX,
+ ret = GetReferenceToNativeShape( prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_BOX,
ShapeData.FixedShapeKey.KEY_BOX, shapeCallback);
DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
prim.LocalID, forceRebuild, prim.BSShape);
@@ -411,39 +412,49 @@ public class BSShapeCollection : IDisposable
ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey,
ShapeDestructionCallback shapeCallback)
{
+ // release any previous shape
+ DereferenceShape(prim.BSShape, true, shapeCallback);
shapeData.Type = shapeType;
// Bullet native objects are scaled by the Bullet engine so pass the size in
prim.Scale = shapeData.Size;
shapeData.Scale = shapeData.Size;
- // release any previous shape
- DereferenceShape(prim.BSShape, true, shapeCallback);
-
BulletShape newShape = BuildPhysicalNativeShape(shapeType, shapeData, shapeKey);
// Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
- DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
+ DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
shapeData.ID, newShape, shapeData.Scale);
prim.BSShape = newShape;
return true;
}
- private BulletShape BuildPhysicalNativeShape(ShapeData.PhysicsShapeType shapeType,
+ private BulletShape BuildPhysicalNativeShape(ShapeData.PhysicsShapeType shapeType,
ShapeData shapeData, ShapeData.FixedShapeKey shapeKey)
{
BulletShape newShape;
+ // Need to make sure the passed shape information is for the native type.
+ ShapeData nativeShapeData = shapeData;
+ nativeShapeData.Type = shapeType;
+ nativeShapeData.MeshKey = (ulong)shapeKey;
+ nativeShapeData.HullKey = (ulong)shapeKey;
if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR)
{
newShape = new BulletShape(
- BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1.0f, 1.0f, shapeData.Scale),
- shapeType);
+ BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, nativeShapeData.Scale)
+ , shapeType);
+ DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", nativeShapeData.ID, nativeShapeData.Scale);
}
else
{
- newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType);
+ newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType);
+ }
+ if (newShape.ptr == IntPtr.Zero)
+ {
+ PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
+ LogHeader, nativeShapeData.ID, nativeShapeData.Type);
}
newShape.shapeKey = (System.UInt64)shapeKey;
newShape.isNativeShape = true;
@@ -698,19 +709,26 @@ public class BSShapeCollection : IDisposable
return ComputeShapeKey(shapeData, pbs, out lod);
}
+ // The creation of a mesh or hull can fail if an underlying asset is not available.
+ // There are two cases: 1) the asset is not in the cache and it needs to be fetched;
+ // and 2) the asset cannot be converted (like decompressing JPEG2000s).
+ // The first case causes the asset to be fetched. The second case just requires
+ // us to not loop forever.
+ // Called after creating a physical mesh or hull. If the physical shape was created,
+ // just return.
private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs)
{
// If the shape was successfully created, nothing more to do
if (newShape.ptr != IntPtr.Zero)
return newShape;
- // The most common reason for failure is that an underlying asset is not available
-
// If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
if (pbs.SculptEntry && !prim.LastAssetBuildFailed && pbs.SculptTexture != OMV.UUID.Zero)
{
prim.LastAssetBuildFailed = true;
BSPhysObject xprim = prim;
+ DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lID={1},lastFailed={2}",
+ LogHeader, shapeData.ID.ToString("X"), prim.LastAssetBuildFailed);
Util.FireAndForget(delegate
{
RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
@@ -724,20 +742,28 @@ public class BSShapeCollection : IDisposable
if (yprim.BaseShape.SculptTexture.ToString() != asset.ID)
return;
- yprim.BaseShape.SculptData = new byte[asset.Data.Length];
- asset.Data.CopyTo(yprim.BaseShape.SculptData, 0);
+ yprim.BaseShape.SculptData = asset.Data;
// This will cause the prim to see that the filler shape is not the right
// one and try again to build the object.
+ // No race condition with the native sphere setting since the rebuild is at taint time.
yprim.ForceBodyShapeRebuild(false);
});
}
});
}
+ else
+ {
+ if (prim.LastAssetBuildFailed)
+ {
+ PhysicsScene.Logger.ErrorFormat("{0} Mesh failed to fetch asset. lID={1}, texture={2}",
+ LogHeader, shapeData.ID, pbs.SculptTexture);
+ }
+ }
// While we figure out the real problem, stick a simple native shape on the object.
BulletShape fillinShape =
- BuildPhysicalNativeShape(ShapeData.PhysicsShapeType.SHAPE_SPHERE, shapeData, ShapeData.FixedShapeKey.KEY_SPHERE);
+ BuildPhysicalNativeShape(ShapeData.PhysicsShapeType.SHAPE_BOX, shapeData, ShapeData.FixedShapeKey.KEY_BOX);
return fillinShape;
}
@@ -746,7 +772,7 @@ public class BSShapeCollection : IDisposable
// Updates prim.BSBody with the information about the new body if one is created.
// Returns 'true' if an object was actually created.
// Called at taint-time.
- private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape,
+ private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape,
ShapeData shapeData, BodyDestructionCallback bodyCallback)
{
bool ret = false;
@@ -765,7 +791,6 @@ public class BSShapeCollection : IDisposable
// If the collisionObject is not the correct type for solidness, rebuild what's there
mustRebuild = true;
}
-
}
if (mustRebuild || forceRebuild)
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
index 41065344e2..880859a12d 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
@@ -201,9 +201,7 @@ public class BSTerrainManager
// If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new
// terrain shape is created and added to the body.
// This call is most often used to update the heightMap and parameters of the terrain.
- // 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.
+ // (The above does suggest that some simplification/refactoring is in order.)
private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
{
DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},inTaintTime={3}",
@@ -335,8 +333,8 @@ public class BSTerrainManager
// Make sure the new shape is processed.
// BulletSimAPI.Activate2(mapInfo.terrainBody.ptr, true);
- BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.ISLAND_SLEEPING);
- // BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
+ // BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.ISLAND_SLEEPING);
+ BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
m_terrainModified = true;
};
diff --git a/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs b/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs
index 190fca0253..905540d36e 100644
--- a/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs
+++ b/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs
@@ -719,21 +719,21 @@ namespace OpenSim.Region.RegionCombinerModule
rootConn.ClientEventForwarder = new RegionCombinerClientEventForwarder(rootConn);
// Sets up the CoarseLocationUpdate forwarder for this root region
- scene.EventManager.OnNewPresence += SetCourseLocationDelegate;
+ scene.EventManager.OnNewPresence += SetCoarseLocationDelegate;
// Adds this root region to a dictionary of regions that are connectable
m_regions.Add(scene.RegionInfo.originRegionID, rootConn);
}
}
- private void SetCourseLocationDelegate(ScenePresence presence)
+ private void SetCoarseLocationDelegate(ScenePresence presence)
{
- presence.SetSendCourseLocationMethod(SendCourseLocationUpdates);
+ presence.SetSendCoarseLocationMethod(SendCoarseLocationUpdates);
}
// This delegate was refactored for non-combined regions.
// This combined region version will not use the pre-compiled lists of locations and ids
- private void SendCourseLocationUpdates(UUID sceneId, ScenePresence presence, List coarseLocations, List avatarUUIDs)
+ private void SendCoarseLocationUpdates(UUID sceneId, ScenePresence presence, List coarseLocations, List avatarUUIDs)
{
RegionConnections connectiondata = null;
lock (m_regions)
@@ -756,18 +756,18 @@ namespace OpenSim.Region.RegionCombinerModule
}
});
- DistributeCourseLocationUpdates(CoarseLocations, AvatarUUIDs, connectiondata, presence);
+ DistributeCoarseLocationUpdates(CoarseLocations, AvatarUUIDs, connectiondata, presence);
}
- private void DistributeCourseLocationUpdates(List locations, List uuids,
+ private void DistributeCoarseLocationUpdates(List locations, List uuids,
RegionConnections connectiondata, ScenePresence rootPresence)
{
RegionData[] rdata = connectiondata.ConnectedRegions.ToArray();
//List clients = new List();
- Dictionary updates = new Dictionary();
+ Dictionary updates = new Dictionary();
// Root Region entry
- RegionCourseLocationStruct rootupdatedata = new RegionCourseLocationStruct();
+ RegionCoarseLocationStruct rootupdatedata = new RegionCoarseLocationStruct();
rootupdatedata.Locations = new List();
rootupdatedata.Uuids = new List();
rootupdatedata.Offset = Vector2.Zero;
@@ -781,7 +781,7 @@ namespace OpenSim.Region.RegionCombinerModule
foreach (RegionData regiondata in rdata)
{
Vector2 offset = new Vector2(regiondata.Offset.X, regiondata.Offset.Y);
- RegionCourseLocationStruct updatedata = new RegionCourseLocationStruct();
+ RegionCoarseLocationStruct updatedata = new RegionCoarseLocationStruct();
updatedata.Locations = new List();
updatedata.Uuids = new List();
updatedata.Offset = offset;
@@ -807,7 +807,7 @@ namespace OpenSim.Region.RegionCombinerModule
if (!updates.ContainsKey(offset))
{
// This shouldn't happen
- RegionCourseLocationStruct updatedata = new RegionCourseLocationStruct();
+ RegionCoarseLocationStruct updatedata = new RegionCoarseLocationStruct();
updatedata.Locations = new List();
updatedata.Uuids = new List();
updatedata.Offset = offset;
diff --git a/OpenSim/Region/RegionCombinerModule/RegionCourseLocation.cs b/OpenSim/Region/RegionCombinerModule/RegionCourseLocation.cs
index 53a678f82f..224ac9947c 100644
--- a/OpenSim/Region/RegionCombinerModule/RegionCourseLocation.cs
+++ b/OpenSim/Region/RegionCombinerModule/RegionCourseLocation.cs
@@ -33,7 +33,7 @@ using OpenSim.Framework;
namespace OpenSim.Region.RegionCombinerModule
{
- struct RegionCourseLocationStruct
+ struct RegionCoarseLocationStruct
{
public List Locations;
public List Uuids;
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
index cf801baecf..fa57845c7d 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
@@ -4388,7 +4388,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
{
AnimationSet currentAnims = presence.Animator.Animations;
string currentAnimationState = String.Empty;
- if (animationstateNames.TryGetValue(currentAnims.DefaultAnimation.AnimID, out currentAnimationState))
+ if (animationstateNames.TryGetValue(currentAnims.ImplicitDefaultAnimation.AnimID, out currentAnimationState))
return currentAnimationState;
}
}
@@ -5705,7 +5705,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
flags |= ScriptBaseClass.AGENT_SITTING;
}
- if (agent.Animator.Animations.DefaultAnimation.AnimID
+ if (agent.Animator.Animations.ImplicitDefaultAnimation.AnimID
== DefaultAvatarAnimations.AnimsUUID["SIT_GROUND_CONSTRAINED"])
{
flags |= ScriptBaseClass.AGENT_SITTING;
@@ -7892,7 +7892,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
{
LSL_Vector lower;
LSL_Vector upper;
- if (presence.Animator.Animations.DefaultAnimation.AnimID
+ if (presence.Animator.Animations.ImplicitDefaultAnimation.AnimID
== DefaultAvatarAnimations.AnimsUUID["SIT_GROUND_CONSTRAINED"])
{
// This is for ground sitting avatars
@@ -10685,12 +10685,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
internal void Deprecated(string command)
{
- throw new Exception("Command deprecated: " + command);
+ throw new ScriptException("Command deprecated: " + command);
}
internal void LSLError(string msg)
{
- throw new Exception("LSL Runtime Error: " + msg);
+ throw new ScriptException("LSL Runtime Error: " + msg);
}
public delegate void AssetRequestCallback(UUID assetID, AssetBase asset);
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs
index 6809c09d05..8f348332b6 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs
@@ -95,13 +95,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
internal void MODError(string msg)
{
- throw new Exception("MOD Runtime Error: " + msg);
+ throw new ScriptException("MOD Runtime Error: " + msg);
}
- //
- //Dumps an error message on the debug console.
- //
-
+ ///
+ /// Dumps an error message on the debug console.
+ ///
+ ///
internal void MODShoutError(string message)
{
if (message.Length > 1023)
@@ -359,20 +359,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
result[i] = (string)(LSL_String)plist[i];
else if (plist[i] is LSL_Integer)
result[i] = (int)(LSL_Integer)plist[i];
+ // The int check exists because of the many plain old int script constants in ScriptBase which
+ // are not LSL_Integers.
+ else if (plist[i] is int)
+ result[i] = plist[i];
else if (plist[i] is LSL_Float)
result[i] = (float)(LSL_Float)plist[i];
else if (plist[i] is LSL_Key)
result[i] = new UUID((LSL_Key)plist[i]);
else if (plist[i] is LSL_Rotation)
- {
- result[i] = (OpenMetaverse.Quaternion)(
- (LSL_Rotation)plist[i]);
- }
+ result[i] = (Quaternion)((LSL_Rotation)plist[i]);
else if (plist[i] is LSL_Vector)
- {
- result[i] = (OpenMetaverse.Vector3)(
- (LSL_Vector)plist[i]);
- }
+ result[i] = (Vector3)((LSL_Vector)plist[i]);
else
MODError(String.Format("{0}: unknown LSL list element type", fname));
}
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
index 29bc163a19..828288d02e 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
@@ -210,7 +210,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
internal void OSSLError(string msg)
{
- throw new Exception("OSSL Runtime Error: " + msg);
+ throw new ScriptException("OSSL Runtime Error: " + msg);
}
///
@@ -1780,18 +1780,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
protected string LoadNotecard(string notecardNameOrUuid)
{
UUID assetID = CacheNotecard(notecardNameOrUuid);
- StringBuilder notecardData = new StringBuilder();
- for (int count = 0; count < NotecardCache.GetLines(assetID); count++)
+ if (assetID != UUID.Zero)
{
- string line = NotecardCache.GetLine(assetID, count) + "\n";
-
-// m_log.DebugFormat("[OSSL]: From notecard {0} loading line {1}", notecardNameOrUuid, line);
-
- notecardData.Append(line);
+ StringBuilder notecardData = new StringBuilder();
+
+ for (int count = 0; count < NotecardCache.GetLines(assetID); count++)
+ {
+ string line = NotecardCache.GetLine(assetID, count) + "\n";
+
+ // m_log.DebugFormat("[OSSL]: From notecard {0} loading line {1}", notecardNameOrUuid, line);
+
+ notecardData.Append(line);
+ }
+
+ return notecardData.ToString();
}
- return notecardData.ToString();
+ return null;
}
///
@@ -2340,11 +2346,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
appearance = new AvatarAppearance();
appearance.Unpack(appearanceOsd);
}
+ else
+ {
+ OSSLError(string.Format("osNpcCreate: Notecard reference '{0}' not found.", notecard));
+ }
}
- if (appearance == null)
- return new LSL_Key(UUID.Zero.ToString());
-
UUID ownerID = UUID.Zero;
if (owned)
ownerID = m_host.OwnerID;
@@ -2407,6 +2414,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
return;
string appearanceSerialized = LoadNotecard(notecard);
+
+ if (appearanceSerialized == null)
+ OSSLError(string.Format("osNpcCreate: Notecard reference '{0}' not found.", notecard));
+
OSDMap appearanceOsd = (OSDMap)OSDParser.DeserializeLLSDXml(appearanceSerialized);
// OSD a = OSDParser.DeserializeLLSDXml(appearanceSerialized);
// Console.WriteLine("appearanceSerialized {0}", appearanceSerialized);
@@ -3636,5 +3647,68 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
DropAttachmentAt(false, pos, rot);
}
+
+ public LSL_Integer osListenRegex(int channelID, string name, string ID, string msg, int regexBitfield)
+ {
+ CheckThreatLevel(ThreatLevel.Low, "osListenRegex");
+ m_host.AddScriptLPS(1);
+ UUID keyID;
+ UUID.TryParse(ID, out keyID);
+
+ // if we want the name to be used as a regular expression, ensure it is valid first.
+ if ((regexBitfield & ScriptBaseClass.OS_LISTEN_REGEX_NAME) == ScriptBaseClass.OS_LISTEN_REGEX_NAME)
+ {
+ try
+ {
+ Regex.IsMatch("", name);
+ }
+ catch (Exception)
+ {
+ OSSLShoutError("Name regex is invalid.");
+ return -1;
+ }
+ }
+
+ // if we want the msg to be used as a regular expression, ensure it is valid first.
+ if ((regexBitfield & ScriptBaseClass.OS_LISTEN_REGEX_MESSAGE) == ScriptBaseClass.OS_LISTEN_REGEX_MESSAGE)
+ {
+ try
+ {
+ Regex.IsMatch("", msg);
+ }
+ catch (Exception)
+ {
+ OSSLShoutError("Message regex is invalid.");
+ return -1;
+ }
+ }
+
+ IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface();
+ return (wComm == null) ? -1 : wComm.Listen(
+ m_host.LocalId,
+ m_item.ItemID,
+ m_host.UUID,
+ channelID,
+ name,
+ keyID,
+ msg,
+ regexBitfield
+ );
+ }
+
+ public LSL_Integer osRegexIsMatch(string input, string pattern)
+ {
+ CheckThreatLevel(ThreatLevel.Low, "osRegexIsMatch");
+ m_host.AddScriptLPS(1);
+ try
+ {
+ return Regex.IsMatch(input, pattern) ? 1 : 0;
+ }
+ catch (Exception)
+ {
+ OSSLShoutError("Possible invalid regular expression detected.");
+ return 0;
+ }
+ }
}
-}
\ No newline at end of file
+}
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
index 93188c9ec8..cdd9ea85a8 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
@@ -418,5 +418,29 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
///
///
void osForceDropAttachmentAt(vector pos, rotation rot);
+
+ ///
+ /// Identical to llListen except for a bitfield which indicates which
+ /// string parameters should be parsed as regex patterns.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// OS_LISTEN_REGEX_NAME
+ /// OS_LISTEN_REGEX_MESSAGE
+ ///
+ ///
+ LSL_Integer osListenRegex(int channelID, string name, string ID,
+ string msg, int regexBitfield);
+
+ ///
+ /// Wraps to bool Regex.IsMatch(string input, string pattern)
+ ///
+ /// string to test for match
+ /// string to use as pattern
+ /// boolean
+ LSL_Integer osRegexIsMatch(string input, string pattern);
}
}
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs
index 62bd6b81b9..880841b5d9 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs
@@ -716,5 +716,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
public static readonly LSLInteger RCERR_UNKNOWN = -1;
public static readonly LSLInteger RCERR_SIM_PERF_LOW = -2;
public static readonly LSLInteger RCERR_CAST_TIME_EXCEEDED = 3;
+
+ ///
+ /// process name parameter as regex
+ ///
+ public const int OS_LISTEN_REGEX_NAME = 0x1;
+
+ ///
+ /// process message parameter as regex
+ ///
+ public const int OS_LISTEN_REGEX_MESSAGE = 0x2;
}
}
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
index dee1b28cca..afa9ae0431 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
@@ -992,5 +992,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
{
m_OSSL_Functions.osForceDropAttachmentAt(pos, rot);
}
+
+ public LSL_Integer osListenRegex(int channelID, string name, string ID, string msg, int regexBitfield)
+ {
+ return m_OSSL_Functions.osListenRegex(channelID, name, ID, msg, regexBitfield);
+ }
+
+ public LSL_Integer osRegexIsMatch(string input, string pattern)
+ {
+ return m_OSSL_Functions.osRegexIsMatch(input, pattern);
+ }
}
}
diff --git a/OpenSim/Region/ScriptEngine/Shared/ScriptException.cs b/OpenSim/Region/ScriptEngine/Shared/ScriptException.cs
new file mode 100644
index 0000000000..ae67fc5585
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/Shared/ScriptException.cs
@@ -0,0 +1,40 @@
+/*
+ * 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.Region.ScriptEngine.Shared
+{
+ public class ScriptException : Exception
+ {
+ public ScriptException() : base() {}
+
+ public ScriptException(string message) : base(message) {}
+
+ public ScriptException(string message, Exception innerException) : base(message, innerException) {}
+ }
+}
\ No newline at end of file
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs
index c8718d9603..c40179456d 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs
@@ -75,76 +75,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
m_engine.AddRegion(m_scene);
}
- ///
- /// Test creation of an NPC where the appearance data comes from a notecard
- ///
- [Test]
- public void TestOsNpcCreateUsingAppearanceFromNotecard()
- {
- TestHelpers.InMethod();
-// log4net.Config.XmlConfigurator.Configure();
-
- // Store an avatar with a different height from default in a notecard.
- UUID userId = TestHelpers.ParseTail(0x1);
- float newHeight = 1.9f;
-
- ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId);
- sp.Appearance.AvatarHeight = newHeight;
- SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, 0x10);
- SceneObjectPart part = so.RootPart;
- m_scene.AddSceneObject(so);
-
- OSSL_Api osslApi = new OSSL_Api();
- osslApi.Initialize(m_engine, part, null);
-
- string notecardName = "appearanceNc";
- osslApi.osOwnerSaveAppearance(notecardName);
-
- // Try creating a bot using the appearance in the notecard.
- string npcRaw = osslApi.osNpcCreate("Jane", "Doe", new LSL_Types.Vector3(128, 128, 128), notecardName);
- Assert.That(npcRaw, Is.Not.Null);
-
- UUID npcId = new UUID(npcRaw);
- ScenePresence npc = m_scene.GetScenePresence(npcId);
- Assert.That(npc, Is.Not.Null);
- Assert.That(npc.Appearance.AvatarHeight, Is.EqualTo(newHeight));
- }
-
- ///
- /// Test creation of an NPC where the appearance data comes from an avatar already in the region.
- ///
- [Test]
- public void TestOsNpcCreateUsingAppearanceFromAvatar()
- {
- TestHelpers.InMethod();
-// TestHelpers.EnableLogging();
-
- // Store an avatar with a different height from default in a notecard.
- UUID userId = TestHelpers.ParseTail(0x1);
- float newHeight = 1.9f;
-
- ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId);
- sp.Appearance.AvatarHeight = newHeight;
- SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, 0x10);
- SceneObjectPart part = so.RootPart;
- m_scene.AddSceneObject(so);
-
- OSSL_Api osslApi = new OSSL_Api();
- osslApi.Initialize(m_engine, part, null);
-
- string notecardName = "appearanceNc";
- osslApi.osOwnerSaveAppearance(notecardName);
-
- // Try creating a bot using the existing avatar's appearance
- string npcRaw = osslApi.osNpcCreate("Jane", "Doe", new LSL_Types.Vector3(128, 128, 128), sp.UUID.ToString());
- Assert.That(npcRaw, Is.Not.Null);
-
- UUID npcId = new UUID(npcRaw);
- ScenePresence npc = m_scene.GetScenePresence(npcId);
- Assert.That(npc, Is.Not.Null);
- Assert.That(npc.Appearance.AvatarHeight, Is.EqualTo(newHeight));
- }
-
[Test]
public void TestOsOwnerSaveAppearance()
{
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs
index 25679a65c0..b49bcc2000 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs
@@ -36,6 +36,7 @@ using OpenMetaverse;
using OpenMetaverse.Assets;
using OpenMetaverse.StructuredData;
using OpenSim.Framework;
+using OpenSim.Region.CoreModules.Avatar.Attachments;
using OpenSim.Region.CoreModules.Avatar.AvatarFactory;
using OpenSim.Region.OptionalModules.World.NPC;
using OpenSim.Region.Framework.Scenes;
@@ -71,13 +72,193 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
config.Set("Enabled", "true");
m_scene = new SceneHelpers().SetupScene();
- SceneHelpers.SetupSceneModules(m_scene, initConfigSource, new AvatarFactoryModule(), new NPCModule());
+ SceneHelpers.SetupSceneModules(
+ m_scene, initConfigSource, new AvatarFactoryModule(), new AttachmentsModule(), new NPCModule());
m_engine = new XEngine.XEngine();
m_engine.Initialise(initConfigSource);
m_engine.AddRegion(m_scene);
}
+ ///
+ /// Test creation of an NPC where the appearance data comes from a notecard
+ ///
+ [Test]
+ public void TestOsNpcCreateUsingAppearanceFromNotecard()
+ {
+ TestHelpers.InMethod();
+
+ // Store an avatar with a different height from default in a notecard.
+ UUID userId = TestHelpers.ParseTail(0x1);
+ float newHeight = 1.9f;
+
+ ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId);
+ sp.Appearance.AvatarHeight = newHeight;
+ SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, 0x10);
+ SceneObjectPart part = so.RootPart;
+ m_scene.AddSceneObject(so);
+
+ OSSL_Api osslApi = new OSSL_Api();
+ osslApi.Initialize(m_engine, part, null);
+
+ string notecardName = "appearanceNc";
+ osslApi.osOwnerSaveAppearance(notecardName);
+
+ // Try creating a bot using the appearance in the notecard.
+ string npcRaw = osslApi.osNpcCreate("Jane", "Doe", new LSL_Types.Vector3(128, 128, 128), notecardName);
+ Assert.That(npcRaw, Is.Not.Null);
+
+ UUID npcId = new UUID(npcRaw);
+ ScenePresence npc = m_scene.GetScenePresence(npcId);
+ Assert.That(npc, Is.Not.Null);
+ Assert.That(npc.Appearance.AvatarHeight, Is.EqualTo(newHeight));
+ }
+
+ [Test]
+ public void TestOsNpcCreateNotExistingNotecard()
+ {
+ TestHelpers.InMethod();
+
+ UUID userId = TestHelpers.ParseTail(0x1);
+
+ SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, 0x10);
+ m_scene.AddSceneObject(so);
+
+ OSSL_Api osslApi = new OSSL_Api();
+ osslApi.Initialize(m_engine, so.RootPart, null);
+
+ string npcRaw;
+ bool gotExpectedException = false;
+ try
+ {
+ npcRaw
+ = osslApi.osNpcCreate("Jane", "Doe", new LSL_Types.Vector3(128, 128, 128), "not existing notecard name");
+ }
+ catch (ScriptException)
+ {
+ gotExpectedException = true;
+ }
+
+ Assert.That(gotExpectedException, Is.True);
+ }
+
+ ///
+ /// Test creation of an NPC where the appearance data comes from an avatar already in the region.
+ ///
+ [Test]
+ public void TestOsNpcCreateUsingAppearanceFromAvatar()
+ {
+ TestHelpers.InMethod();
+// TestHelpers.EnableLogging();
+
+ // Store an avatar with a different height from default in a notecard.
+ UUID userId = TestHelpers.ParseTail(0x1);
+ float newHeight = 1.9f;
+
+ ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId);
+ sp.Appearance.AvatarHeight = newHeight;
+ SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, 0x10);
+ SceneObjectPart part = so.RootPart;
+ m_scene.AddSceneObject(so);
+
+ OSSL_Api osslApi = new OSSL_Api();
+ osslApi.Initialize(m_engine, part, null);
+
+ string notecardName = "appearanceNc";
+ osslApi.osOwnerSaveAppearance(notecardName);
+
+ // Try creating a bot using the existing avatar's appearance
+ string npcRaw = osslApi.osNpcCreate("Jane", "Doe", new LSL_Types.Vector3(128, 128, 128), sp.UUID.ToString());
+ Assert.That(npcRaw, Is.Not.Null);
+
+ UUID npcId = new UUID(npcRaw);
+ ScenePresence npc = m_scene.GetScenePresence(npcId);
+ Assert.That(npc, Is.Not.Null);
+ Assert.That(npc.Appearance.AvatarHeight, Is.EqualTo(newHeight));
+ }
+
+ [Test]
+ public void TestOsNpcLoadAppearance()
+ {
+ TestHelpers.InMethod();
+
+ // Store an avatar with a different height from default in a notecard.
+ UUID userId = TestHelpers.ParseTail(0x1);
+ float firstHeight = 1.9f;
+ float secondHeight = 2.1f;
+ string firstAppearanceNcName = "appearanceNc1";
+ string secondAppearanceNcName = "appearanceNc2";
+
+ ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId);
+ sp.Appearance.AvatarHeight = firstHeight;
+ SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, 0x10);
+ SceneObjectPart part = so.RootPart;
+ m_scene.AddSceneObject(so);
+
+ OSSL_Api osslApi = new OSSL_Api();
+ osslApi.Initialize(m_engine, part, null);
+
+ osslApi.osOwnerSaveAppearance(firstAppearanceNcName);
+
+ string npcRaw
+ = osslApi.osNpcCreate("Jane", "Doe", new LSL_Types.Vector3(128, 128, 128), firstAppearanceNcName);
+
+ // Create a second appearance notecard with a different height
+ sp.Appearance.AvatarHeight = secondHeight;
+ osslApi.osOwnerSaveAppearance(secondAppearanceNcName);
+
+ osslApi.osNpcLoadAppearance(npcRaw, secondAppearanceNcName);
+
+ UUID npcId = new UUID(npcRaw);
+ ScenePresence npc = m_scene.GetScenePresence(npcId);
+ Assert.That(npc, Is.Not.Null);
+ Assert.That(npc.Appearance.AvatarHeight, Is.EqualTo(secondHeight));
+ }
+
+ [Test]
+ public void TestOsNpcLoadAppearanceNotExistingNotecard()
+ {
+ TestHelpers.InMethod();
+
+ // Store an avatar with a different height from default in a notecard.
+ UUID userId = TestHelpers.ParseTail(0x1);
+ float firstHeight = 1.9f;
+ float secondHeight = 2.1f;
+ string firstAppearanceNcName = "appearanceNc1";
+ string secondAppearanceNcName = "appearanceNc2";
+
+ ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId);
+ sp.Appearance.AvatarHeight = firstHeight;
+ SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, 0x10);
+ SceneObjectPart part = so.RootPart;
+ m_scene.AddSceneObject(so);
+
+ OSSL_Api osslApi = new OSSL_Api();
+ osslApi.Initialize(m_engine, part, null);
+
+ osslApi.osOwnerSaveAppearance(firstAppearanceNcName);
+
+ string npcRaw
+ = osslApi.osNpcCreate("Jane", "Doe", new LSL_Types.Vector3(128, 128, 128), firstAppearanceNcName);
+
+ bool gotExpectedException = false;
+ try
+ {
+ osslApi.osNpcLoadAppearance(npcRaw, secondAppearanceNcName);
+ }
+ catch (ScriptException)
+ {
+ gotExpectedException = true;
+ }
+
+ Assert.That(gotExpectedException, Is.True);
+
+ UUID npcId = new UUID(npcRaw);
+ ScenePresence npc = m_scene.GetScenePresence(npcId);
+ Assert.That(npc, Is.Not.Null);
+ Assert.That(npc.Appearance.AvatarHeight, Is.EqualTo(firstHeight));
+ }
+
///
/// Test removal of an owned NPC.
///
@@ -85,7 +266,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
public void TestOsNpcRemoveOwned()
{
TestHelpers.InMethod();
-// log4net.Config.XmlConfigurator.Configure();
// Store an avatar with a different height from default in a notecard.
UUID userId = TestHelpers.ParseTail(0x1);
diff --git a/OpenSim/Server/Handlers/Asset/AssetServerConnector.cs b/OpenSim/Server/Handlers/Asset/AssetServerConnector.cs
index 46b0c672e2..4123f491bb 100644
--- a/OpenSim/Server/Handlers/Asset/AssetServerConnector.cs
+++ b/OpenSim/Server/Handlers/Asset/AssetServerConnector.cs
@@ -141,6 +141,9 @@ namespace OpenSim.Server.Handlers.Asset
}
string fileName = rawAssetId;
+
+ if (!ConsoleUtil.CheckFileDoesNotExist(MainConsole.Instance, fileName))
+ return;
using (FileStream fs = new FileStream(fileName, FileMode.CreateNew))
{
diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs
index bb8b9358c0..dde37ab7a3 100644
--- a/OpenSim/Tests/Common/Mock/TestClient.cs
+++ b/OpenSim/Tests/Common/Mock/TestClient.cs
@@ -528,13 +528,9 @@ namespace OpenSim.Tests.Common.Mock
{
}
- public virtual void SendChatMessage(string message, byte type, Vector3 fromPos, string fromName,
- UUID fromAgentID, byte source, byte audible)
- {
- }
-
- public virtual void SendChatMessage(byte[] message, byte type, Vector3 fromPos, string fromName,
- UUID fromAgentID, byte source, byte audible)
+ public virtual void SendChatMessage(
+ string message, byte type, Vector3 fromPos, string fromName,
+ UUID fromAgentID, UUID ownerID, byte source, byte audible)
{
}
diff --git a/bin/assets/CollisionSoundsAssetSet/CollisionSoundsAssetSet.xml b/bin/assets/CollisionSoundsAssetSet/CollisionSoundsAssetSet.xml
index 7498ae0af8..b570c554be 100644
--- a/bin/assets/CollisionSoundsAssetSet/CollisionSoundsAssetSet.xml
+++ b/bin/assets/CollisionSoundsAssetSet/CollisionSoundsAssetSet.xml
@@ -303,37 +303,37 @@
-
+
diff --git a/bin/lib32/BulletSim.dll b/bin/lib32/BulletSim.dll
index f976efe72b..fbc83e64c7 100755
Binary files a/bin/lib32/BulletSim.dll and b/bin/lib32/BulletSim.dll differ
diff --git a/bin/lib32/libBulletSim.so b/bin/lib32/libBulletSim.so
index a00bc3ab01..65d3805bb3 100755
Binary files a/bin/lib32/libBulletSim.so and b/bin/lib32/libBulletSim.so differ
diff --git a/bin/lib64/BulletSim.dll b/bin/lib64/BulletSim.dll
index acaa9c875f..936368a4d9 100755
Binary files a/bin/lib64/BulletSim.dll and b/bin/lib64/BulletSim.dll differ
diff --git a/bin/lib64/libBulletSim.so b/bin/lib64/libBulletSim.so
index 996ea21576..82fbad6966 100755
Binary files a/bin/lib64/libBulletSim.so and b/bin/lib64/libBulletSim.so differ