Merge branch 'master' of /home/opensim/var/repo/opensim
commit
fc507ff59b
|
@ -330,6 +330,9 @@ namespace OpenSim.Framework
|
||||||
SetVisualParams(visualParams);
|
SetVisualParams(visualParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set avatar height by a calculation based on their visual parameters.
|
||||||
|
/// </summary>
|
||||||
public virtual void SetHeight()
|
public virtual void SetHeight()
|
||||||
{
|
{
|
||||||
// Start with shortest possible female avatar height
|
// Start with shortest possible female avatar height
|
||||||
|
|
|
@ -33,7 +33,8 @@ namespace OpenSim.Framework.Client
|
||||||
{
|
{
|
||||||
event ChatMessage OnChatFromClient;
|
event ChatMessage OnChatFromClient;
|
||||||
|
|
||||||
void SendChatMessage(string message, byte type, Vector3 fromPos, string fromName, UUID fromAgentID, byte source,
|
void SendChatMessage(
|
||||||
byte audible);
|
string message, byte type, Vector3 fromPos, string fromName, UUID fromAgentID, UUID ownerID, byte source,
|
||||||
|
byte audible);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -27,88 +27,202 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using log4net;
|
using log4net;
|
||||||
using OpenMetaverse;
|
using OpenMetaverse;
|
||||||
|
|
||||||
public class ConsoleUtil
|
namespace OpenSim.Framework.Console
|
||||||
{
|
{
|
||||||
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
public class ConsoleUtil
|
||||||
|
|
||||||
public const string MinRawConsoleVectorValue = "-~";
|
|
||||||
public const string MaxRawConsoleVectorValue = "~";
|
|
||||||
|
|
||||||
public const string VectorSeparator = ",";
|
|
||||||
public static char[] VectorSeparatorChars = VectorSeparator.ToCharArray();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Convert a minimum vector input from the console to an OpenMetaverse.Vector3
|
|
||||||
/// </summary>
|
|
||||||
/// <param name='rawConsoleVector'>/param>
|
|
||||||
/// <param name='vector'></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static bool TryParseConsoleMinVector(string rawConsoleVector, out Vector3 vector)
|
|
||||||
{
|
{
|
||||||
return TryParseConsoleVector(rawConsoleVector, c => float.MinValue.ToString(), out vector);
|
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
public const int LocalIdNotFound = 0;
|
||||||
/// Convert a maximum vector input from the console to an OpenMetaverse.Vector3
|
|
||||||
/// </summary>
|
|
||||||
/// <param name='rawConsoleVector'>/param>
|
|
||||||
/// <param name='vector'></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static bool TryParseConsoleMaxVector(string rawConsoleVector, out Vector3 vector)
|
|
||||||
{
|
|
||||||
return TryParseConsoleVector(rawConsoleVector, c => float.MaxValue.ToString(), out vector);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Convert a vector input from the console to an OpenMetaverse.Vector3
|
/// Used by modules to display stock co-ordinate help, though possibly this should be under some general section
|
||||||
/// </summary>
|
/// rather than in each help summary.
|
||||||
/// <param name='rawConsoleVector'>
|
/// </summary>
|
||||||
/// A string in the form <x>,<y>,<z> where there is no space between values.
|
public const string CoordHelp
|
||||||
/// Any component can be missing (e.g. ,,40). blankComponentFunc is invoked to replace the blank with a suitable value
|
= @"Each component of the coord is comma separated. There must be no spaces between the commas.
|
||||||
/// Also, if the blank component is at the end, then the comma can be missed off entirely (e.g. 40,30 or 40)
|
If you don't care about the z component you can simply omit it.
|
||||||
/// The strings "~" and "-~" are valid in components. The first substitutes float.MaxValue whilst the second is float.MinValue
|
If you don't care about the x or y components then you can leave them blank (though a comma is still required)
|
||||||
/// Other than that, component values must be numeric.
|
If you want to specify the maxmimum value of a component then you can use ~ instead of a number
|
||||||
/// </param>
|
If you want to specify the minimum value of a component then you can use -~ instead of a number
|
||||||
/// <param name='blankComponentFunc'></param>
|
e.g.
|
||||||
/// <param name='vector'></param>
|
delete object pos 20,20,20 to 40,40,40
|
||||||
/// <returns></returns>
|
delete object pos 20,20 to 40,40
|
||||||
public static bool TryParseConsoleVector(
|
delete object pos ,20,20 to ,40,40
|
||||||
string rawConsoleVector, Func<string, string> blankComponentFunc, out Vector3 vector)
|
delete object pos ,,30 to ,,~
|
||||||
{
|
delete object pos ,,-~ to ,,30";
|
||||||
List<string> components = rawConsoleVector.Split(VectorSeparatorChars).ToList();
|
|
||||||
|
|
||||||
if (components.Count < 1 || components.Count > 3)
|
public const string MinRawConsoleVectorValue = "-~";
|
||||||
|
public const string MaxRawConsoleVectorValue = "~";
|
||||||
|
|
||||||
|
public const string VectorSeparator = ",";
|
||||||
|
public static char[] VectorSeparatorChars = VectorSeparator.ToCharArray();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if the given file path exists.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>If not, warning is printed to the given console.</remarks>
|
||||||
|
/// <returns>true if the file does not exist, false otherwise.</returns>
|
||||||
|
/// <param name='console'></param>
|
||||||
|
/// <param name='path'></param>
|
||||||
|
public static bool CheckFileDoesNotExist(ICommandConsole console, string path)
|
||||||
{
|
{
|
||||||
vector = Vector3.Zero;
|
if (File.Exists(path))
|
||||||
|
{
|
||||||
|
console.OutputFormat("File {0} already exists. Please move or remove it.", path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Try to parse a console UUID from the console.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Will complain to the console if parsing fails.
|
||||||
|
/// </remarks>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <param name='console'>If null then no complaint is printed.</param>
|
||||||
|
/// <param name='rawUuid'></param>
|
||||||
|
/// <param name='uuid'></param>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (localId == 0)
|
||||||
|
{
|
||||||
|
if (console != null)
|
||||||
|
console.OutputFormat("{0} is not a valid local id - it must be greater than 0", localId);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to parse the input as either a UUID or a local ID.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>true if parsing succeeded, false otherwise.</returns>
|
||||||
|
/// <param name='console'></param>
|
||||||
|
/// <param name='rawId'></param>
|
||||||
|
/// <param name='uuid'></param>
|
||||||
|
/// <param name='localId'>
|
||||||
|
/// Will be set to ConsoleUtil.LocalIdNotFound if parsing result was a UUID or no parse succeeded.
|
||||||
|
/// </param>
|
||||||
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = components.Count; i < 3; i++)
|
/// <summary>
|
||||||
components.Add("");
|
/// Convert a minimum vector input from the console to an OpenMetaverse.Vector3
|
||||||
|
/// </summary>
|
||||||
|
/// <param name='rawConsoleVector'>/param>
|
||||||
|
/// <param name='vector'></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static bool TryParseConsoleMinVector(string rawConsoleVector, out Vector3 vector)
|
||||||
|
{
|
||||||
|
return TryParseConsoleVector(rawConsoleVector, c => float.MinValue.ToString(), out vector);
|
||||||
|
}
|
||||||
|
|
||||||
List<string> semiDigestedComponents
|
/// <summary>
|
||||||
= components.ConvertAll<string>(
|
/// Convert a maximum vector input from the console to an OpenMetaverse.Vector3
|
||||||
c =>
|
/// </summary>
|
||||||
{
|
/// <param name='rawConsoleVector'>/param>
|
||||||
if (c == "")
|
/// <param name='vector'></param>
|
||||||
return blankComponentFunc.Invoke(c);
|
/// <returns></returns>
|
||||||
else if (c == MaxRawConsoleVectorValue)
|
public static bool TryParseConsoleMaxVector(string rawConsoleVector, out Vector3 vector)
|
||||||
return float.MaxValue.ToString();
|
{
|
||||||
else if (c == MinRawConsoleVectorValue)
|
return TryParseConsoleVector(rawConsoleVector, c => float.MaxValue.ToString(), out vector);
|
||||||
return float.MinValue.ToString();
|
}
|
||||||
else
|
|
||||||
return c;
|
|
||||||
});
|
|
||||||
|
|
||||||
string semiDigestedConsoleVector = string.Join(VectorSeparator, semiDigestedComponents.ToArray());
|
/// <summary>
|
||||||
|
/// Convert a vector input from the console to an OpenMetaverse.Vector3
|
||||||
|
/// </summary>
|
||||||
|
/// <param name='rawConsoleVector'>
|
||||||
|
/// A string in the form <x>,<y>,<z> 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.
|
||||||
|
/// </param>
|
||||||
|
/// <param name='blankComponentFunc'></param>
|
||||||
|
/// <param name='vector'></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static bool TryParseConsoleVector(
|
||||||
|
string rawConsoleVector, Func<string, string> blankComponentFunc, out Vector3 vector)
|
||||||
|
{
|
||||||
|
List<string> components = rawConsoleVector.Split(VectorSeparatorChars).ToList();
|
||||||
|
|
||||||
// m_log.DebugFormat("[CONSOLE UTIL]: Parsing {0} into OpenMetaverse.Vector3", semiDigestedConsoleVector);
|
if (components.Count < 1 || components.Count > 3)
|
||||||
|
{
|
||||||
|
vector = Vector3.Zero;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return Vector3.TryParse(semiDigestedConsoleVector, out vector);
|
for (int i = components.Count; i < 3; i++)
|
||||||
|
components.Add("");
|
||||||
|
|
||||||
|
List<string> semiDigestedComponents
|
||||||
|
= components.ConvertAll<string>(
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1099,8 +1099,20 @@ namespace OpenSim.Framework
|
||||||
void SendAnimations(UUID[] animID, int[] seqs, UUID sourceAgentId, UUID[] objectIDs);
|
void SendAnimations(UUID[] animID, int[] seqs, UUID sourceAgentId, UUID[] objectIDs);
|
||||||
void SendRegionHandshake(RegionInfo regionInfo, RegionHandshakeArgs args);
|
void SendRegionHandshake(RegionInfo regionInfo, RegionHandshakeArgs args);
|
||||||
|
|
||||||
void SendChatMessage(string message, byte type, Vector3 fromPos, string fromName, UUID fromAgentID, byte source,
|
/// <summary>
|
||||||
byte audible);
|
/// Send chat to the viewer.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name='message'></param>
|
||||||
|
/// <param name='type'></param>
|
||||||
|
/// <param name='fromPos'></param>
|
||||||
|
/// <param name='fromName'></param>
|
||||||
|
/// <param name='fromAgentID'></param>
|
||||||
|
/// <param name='ownerID'></param>
|
||||||
|
/// <param name='source'></param>
|
||||||
|
/// <param name='audible'></param>
|
||||||
|
void SendChatMessage(
|
||||||
|
string message, byte type, Vector3 fromPos, string fromName, UUID fromAgentID, UUID ownerID, byte source,
|
||||||
|
byte audible);
|
||||||
|
|
||||||
void SendInstantMessage(GridInstantMessage im);
|
void SendInstantMessage(GridInstantMessage im);
|
||||||
|
|
||||||
|
|
|
@ -207,7 +207,7 @@ namespace OpenSim.Framework.Monitoring
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
newContainer = new Dictionary<string, Stat>(container);
|
newContainer = new Dictionary<string, Stat>(container);
|
||||||
newContainer.Remove(stat.UniqueName);
|
newContainer.Remove(stat.ShortName);
|
||||||
|
|
||||||
newCategory = new Dictionary<string, Dictionary<string, Stat>>(category);
|
newCategory = new Dictionary<string, Dictionary<string, Stat>>(category);
|
||||||
newCategory.Remove(stat.Container);
|
newCategory.Remove(stat.Container);
|
||||||
|
@ -248,6 +248,19 @@ namespace OpenSim.Framework.Monitoring
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stat type.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// 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.
|
||||||
|
/// </remarks>
|
||||||
|
public enum StatType
|
||||||
|
{
|
||||||
|
Push,
|
||||||
|
Pull
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Verbosity of stat.
|
/// Verbosity of stat.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -265,11 +278,6 @@ namespace OpenSim.Framework.Monitoring
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Stat
|
public class Stat
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Unique stat name used for indexing. Each ShortName in a Category must be unique.
|
|
||||||
/// </summary>
|
|
||||||
public string UniqueName { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Category of this stat (e.g. cache, scene, etc).
|
/// Category of this stat (e.g. cache, scene, etc).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -285,29 +293,65 @@ namespace OpenSim.Framework.Monitoring
|
||||||
/// </value>
|
/// </value>
|
||||||
public string Container { get; private set; }
|
public string Container { get; private set; }
|
||||||
|
|
||||||
|
public StatType StatType { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Action used to update this stat when the value is requested if it's a pull type.
|
||||||
|
/// </summary>
|
||||||
|
public Action<Stat> PullAction { get; private set; }
|
||||||
|
|
||||||
public StatVerbosity Verbosity { get; private set; }
|
public StatVerbosity Verbosity { get; private set; }
|
||||||
public string ShortName { get; private set; }
|
public string ShortName { get; private set; }
|
||||||
public string Name { get; private set; }
|
public string Name { get; private set; }
|
||||||
public string Description { get; private set; }
|
public string Description { get; private set; }
|
||||||
public virtual string UnitName { 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;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructor
|
/// Constructor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name='shortName'>Short name for the stat. Must not contain spaces. e.g. "LongFrames"</param>
|
/// <param name='shortName'>Short name for the stat. Must not contain spaces. e.g. "LongFrames"</param>
|
||||||
/// <param name='name'>Human readable name for the stat. e.g. "Long frames"</param>
|
/// <param name='name'>Human readable name for the stat. e.g. "Long frames"</param>
|
||||||
|
/// <param name='description'>Description of stat</param>
|
||||||
/// <param name='unitName'>
|
/// <param name='unitName'>
|
||||||
/// Unit name for the stat. Should be preceeded by a space if the unit name isn't normally appeneded immediately to the value.
|
/// 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"
|
/// e.g. " frames"
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <param name='category'>Category under which this stat should appear, e.g. "scene". Do not capitalize.</param>
|
/// <param name='category'>Category under which this stat should appear, e.g. "scene". Do not capitalize.</param>
|
||||||
/// <param name='container'>Entity to which this stat relates. e.g. scene name if this is a per scene stat.</param>
|
/// <param name='container'>Entity to which this stat relates. e.g. scene name if this is a per scene stat.</param>
|
||||||
|
/// <param name='type'>Push or pull</param>
|
||||||
|
/// <param name='pullAction'>Pull stats need an action to update the stat on request. Push stats should set null here.</param>
|
||||||
/// <param name='verbosity'>Verbosity of stat. Controls whether it will appear in short stat display or only full display.</param>
|
/// <param name='verbosity'>Verbosity of stat. Controls whether it will appear in short stat display or only full display.</param>
|
||||||
/// <param name='description'>Description of stat</param>
|
|
||||||
public Stat(
|
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<Stat> pullAction,
|
||||||
|
StatVerbosity verbosity)
|
||||||
{
|
{
|
||||||
if (StatsManager.SubCommands.Contains(category))
|
if (StatsManager.SubCommands.Contains(category))
|
||||||
throw new Exception(
|
throw new Exception(
|
||||||
|
@ -315,18 +359,18 @@ namespace OpenSim.Framework.Monitoring
|
||||||
|
|
||||||
ShortName = shortName;
|
ShortName = shortName;
|
||||||
Name = name;
|
Name = name;
|
||||||
|
Description = description;
|
||||||
UnitName = unitName;
|
UnitName = unitName;
|
||||||
Category = category;
|
Category = category;
|
||||||
Container = container;
|
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;
|
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()
|
public virtual string ToConsoleString()
|
||||||
|
@ -361,8 +405,15 @@ namespace OpenSim.Framework.Monitoring
|
||||||
}
|
}
|
||||||
|
|
||||||
public PercentageStat(
|
public PercentageStat(
|
||||||
string shortName, string name, string category, string container, StatVerbosity verbosity, string description)
|
string shortName,
|
||||||
: base(shortName, name, "%", category, container, verbosity, description) {}
|
string name,
|
||||||
|
string description,
|
||||||
|
string category,
|
||||||
|
string container,
|
||||||
|
StatType type,
|
||||||
|
Action<Stat> pullAction,
|
||||||
|
StatVerbosity verbosity)
|
||||||
|
: base(shortName, name, description, "%", category, container, type, pullAction, verbosity) {}
|
||||||
|
|
||||||
public override string ToConsoleString()
|
public override string ToConsoleString()
|
||||||
{
|
{
|
||||||
|
|
|
@ -38,8 +38,23 @@ namespace OpenSim.Framework
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public class Pool<T>
|
public class Pool<T>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Number of objects in the pool.
|
||||||
|
/// </summary>
|
||||||
|
public int Count
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
lock (m_pool)
|
||||||
|
return m_pool.Count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Stack<T> m_pool;
|
private Stack<T> m_pool;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Maximum pool size. Beyond this, any returned objects are not pooled.
|
||||||
|
/// </summary>
|
||||||
private int m_maxPoolSize;
|
private int m_maxPoolSize;
|
||||||
|
|
||||||
private Func<T> m_createFunction;
|
private Func<T> m_createFunction;
|
||||||
|
|
|
@ -542,11 +542,8 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
{
|
{
|
||||||
case null:
|
case null:
|
||||||
case "text/html":
|
case "text/html":
|
||||||
|
|
||||||
if (DebugLevel >= 3)
|
if (DebugLevel >= 3)
|
||||||
m_log.DebugFormat(
|
LogIncomingToContentTypeHandler(request);
|
||||||
"[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);
|
|
||||||
|
|
||||||
buffer = HandleHTTPRequest(request, response);
|
buffer = HandleHTTPRequest(request, response);
|
||||||
break;
|
break;
|
||||||
|
@ -554,11 +551,8 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
case "application/llsd+xml":
|
case "application/llsd+xml":
|
||||||
case "application/xml+llsd":
|
case "application/xml+llsd":
|
||||||
case "application/llsd+json":
|
case "application/llsd+json":
|
||||||
|
|
||||||
if (DebugLevel >= 3)
|
if (DebugLevel >= 3)
|
||||||
m_log.DebugFormat(
|
LogIncomingToContentTypeHandler(request);
|
||||||
"[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);
|
|
||||||
|
|
||||||
buffer = HandleLLSDRequests(request, response);
|
buffer = HandleLLSDRequests(request, response);
|
||||||
break;
|
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}",
|
"[BASE HTTP SERVER]: HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}",
|
||||||
RequestNumber,
|
RequestNumber,
|
||||||
Port,
|
Port,
|
||||||
request.ContentType,
|
(request.ContentType == null || request.ContentType == "") ? "not set" : request.ContentType,
|
||||||
request.HttpMethod,
|
request.HttpMethod,
|
||||||
request.Url.PathAndQuery,
|
request.Url.PathAndQuery,
|
||||||
request.RemoteIPEndPoint);
|
request.RemoteIPEndPoint);
|
||||||
|
|
|
@ -543,7 +543,7 @@ namespace OpenSim
|
||||||
if (account == null)
|
if (account == null)
|
||||||
{
|
{
|
||||||
m_log.ErrorFormat(
|
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
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -817,8 +817,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
OutPacket(mov, ThrottleOutPacketType.Unknown);
|
OutPacket(mov, ThrottleOutPacketType.Unknown);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendChatMessage(string message, byte type, Vector3 fromPos, string fromName,
|
public void SendChatMessage(
|
||||||
UUID fromAgentID, byte source, byte audible)
|
string message, byte type, Vector3 fromPos, string fromName,
|
||||||
|
UUID fromAgentID, UUID ownerID, byte source, byte audible)
|
||||||
{
|
{
|
||||||
ChatFromSimulatorPacket reply = (ChatFromSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.ChatFromSimulator);
|
ChatFromSimulatorPacket reply = (ChatFromSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.ChatFromSimulator);
|
||||||
reply.ChatData.Audible = audible;
|
reply.ChatData.Audible = audible;
|
||||||
|
@ -827,7 +828,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
reply.ChatData.SourceType = source;
|
reply.ChatData.SourceType = source;
|
||||||
reply.ChatData.Position = fromPos;
|
reply.ChatData.Position = fromPos;
|
||||||
reply.ChatData.FromName = Util.StringToBytes256(fromName);
|
reply.ChatData.FromName = Util.StringToBytes256(fromName);
|
||||||
reply.ChatData.OwnerID = fromAgentID;
|
reply.ChatData.OwnerID = ownerID;
|
||||||
reply.ChatData.SourceID = fromAgentID;
|
reply.ChatData.SourceID = fromAgentID;
|
||||||
|
|
||||||
OutPacket(reply, ThrottleOutPacketType.Task);
|
OutPacket(reply, ThrottleOutPacketType.Task);
|
||||||
|
|
|
@ -170,6 +170,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
|
|
||||||
private Pool<IncomingPacket> m_incomingPacketPool;
|
private Pool<IncomingPacket> m_incomingPacketPool;
|
||||||
|
|
||||||
|
private Stat m_incomingPacketPoolStat;
|
||||||
|
|
||||||
private int m_defaultRTO = 0;
|
private int m_defaultRTO = 0;
|
||||||
private int m_maxRTO = 0;
|
private int m_maxRTO = 0;
|
||||||
private int m_ackTimeout = 0;
|
private int m_ackTimeout = 0;
|
||||||
|
@ -214,6 +216,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
|
|
||||||
m_circuitManager = circuitManager;
|
m_circuitManager = circuitManager;
|
||||||
int sceneThrottleBps = 0;
|
int sceneThrottleBps = 0;
|
||||||
|
bool usePools = false;
|
||||||
|
|
||||||
IConfig config = configSource.Configs["ClientStack.LindenUDP"];
|
IConfig config = configSource.Configs["ClientStack.LindenUDP"];
|
||||||
if (config != null)
|
if (config != null)
|
||||||
|
@ -246,7 +249,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
{
|
{
|
||||||
PacketPool.Instance.RecyclePackets = packetConfig.GetBoolean("RecyclePackets", true);
|
PacketPool.Instance.RecyclePackets = packetConfig.GetBoolean("RecyclePackets", true);
|
||||||
PacketPool.Instance.RecycleDataBlocks = packetConfig.GetBoolean("RecycleDataBlocks", true);
|
PacketPool.Instance.RecycleDataBlocks = packetConfig.GetBoolean("RecycleDataBlocks", true);
|
||||||
UsePools = packetConfig.GetBoolean("RecycleBaseUDPPackets", false);
|
usePools = packetConfig.GetBoolean("RecycleBaseUDPPackets", usePools);
|
||||||
}
|
}
|
||||||
|
|
||||||
#region BinaryStats
|
#region BinaryStats
|
||||||
|
@ -277,8 +280,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
m_throttle = new TokenBucket(null, sceneThrottleBps);
|
m_throttle = new TokenBucket(null, sceneThrottleBps);
|
||||||
ThrottleRates = new ThrottleRates(configSource);
|
ThrottleRates = new ThrottleRates(configSource);
|
||||||
|
|
||||||
if (UsePools)
|
if (usePools)
|
||||||
m_incomingPacketPool = new Pool<IncomingPacket>(() => new IncomingPacket(), 500);
|
EnablePools();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Start()
|
public void Start()
|
||||||
|
@ -331,6 +334,50 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
base.StopInbound();
|
base.StopInbound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override bool EnablePools()
|
||||||
|
{
|
||||||
|
if (!UsePools)
|
||||||
|
{
|
||||||
|
base.EnablePools();
|
||||||
|
|
||||||
|
m_incomingPacketPool = new Pool<IncomingPacket>(() => 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;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// If the outgoing UDP thread times out, then return client that was being processed to help with debugging.
|
/// If the outgoing UDP thread times out, then return client that was being processed to help with debugging.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -394,6 +441,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
+ "all - stop in and outbound processing.\n",
|
+ "all - stop in and outbound processing.\n",
|
||||||
HandleStopCommand);
|
HandleStopCommand);
|
||||||
|
|
||||||
|
MainConsole.Instance.Commands.AddCommand(
|
||||||
|
"Debug",
|
||||||
|
false,
|
||||||
|
"debug lludp pool",
|
||||||
|
"debug lludp pool <on|off>",
|
||||||
|
"Turn object pooling within the lludp component on or off.",
|
||||||
|
HandlePoolCommand);
|
||||||
|
|
||||||
MainConsole.Instance.Commands.AddCommand(
|
MainConsole.Instance.Commands.AddCommand(
|
||||||
"Debug",
|
"Debug",
|
||||||
false,
|
false,
|
||||||
|
@ -437,6 +492,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
StopOutbound();
|
StopOutbound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void HandlePoolCommand(string module, string[] args)
|
||||||
|
{
|
||||||
|
if (args.Length != 4)
|
||||||
|
{
|
||||||
|
MainConsole.Instance.Output("Usage: debug lludp pool <on|off>");
|
||||||
|
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 <on|off>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void HandleStatusCommand(string module, string[] args)
|
private void HandleStatusCommand(string module, string[] args)
|
||||||
{
|
{
|
||||||
MainConsole.Instance.OutputFormat(
|
MainConsole.Instance.OutputFormat(
|
||||||
|
@ -444,6 +525,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
|
|
||||||
MainConsole.Instance.OutputFormat(
|
MainConsole.Instance.OutputFormat(
|
||||||
"OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled");
|
"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)
|
public bool HandlesRegion(Location x)
|
||||||
|
|
|
@ -31,6 +31,7 @@ using System.Net.Sockets;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using log4net;
|
using log4net;
|
||||||
using OpenSim.Framework;
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Framework.Monitoring;
|
||||||
|
|
||||||
namespace OpenMetaverse
|
namespace OpenMetaverse
|
||||||
{
|
{
|
||||||
|
@ -76,6 +77,8 @@ namespace OpenMetaverse
|
||||||
/// <remarks>If IsRunningOut = false, then any request to send a packet is simply dropped.</remarks>
|
/// <remarks>If IsRunningOut = false, then any request to send a packet is simply dropped.</remarks>
|
||||||
public bool IsRunningOutbound { get; private set; }
|
public bool IsRunningOutbound { get; private set; }
|
||||||
|
|
||||||
|
private Stat m_poolCountStat;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default constructor
|
/// Default constructor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -106,11 +109,6 @@ namespace OpenMetaverse
|
||||||
/// necessary</remarks>
|
/// necessary</remarks>
|
||||||
public void StartInbound(int recvBufferSize, bool asyncPacketHandling)
|
public void StartInbound(int recvBufferSize, bool asyncPacketHandling)
|
||||||
{
|
{
|
||||||
if (UsePools)
|
|
||||||
m_pool = new Pool<UDPPacketBuffer>(() => new UDPPacketBuffer(), 500);
|
|
||||||
else
|
|
||||||
m_pool = null;
|
|
||||||
|
|
||||||
m_asyncPacketHandling = asyncPacketHandling;
|
m_asyncPacketHandling = asyncPacketHandling;
|
||||||
|
|
||||||
if (!IsRunningInbound)
|
if (!IsRunningInbound)
|
||||||
|
@ -180,6 +178,49 @@ namespace OpenMetaverse
|
||||||
IsRunningOutbound = false;
|
IsRunningOutbound = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual bool EnablePools()
|
||||||
|
{
|
||||||
|
if (!UsePools)
|
||||||
|
{
|
||||||
|
m_pool = new Pool<UDPPacketBuffer>(() => 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()
|
private void AsyncBeginReceive()
|
||||||
{
|
{
|
||||||
UDPPacketBuffer buf;
|
UDPPacketBuffer buf;
|
||||||
|
|
|
@ -47,18 +47,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
private PercentageStat m_packetsReusedStat = new PercentageStat(
|
private PercentageStat m_packetsReusedStat = new PercentageStat(
|
||||||
"PacketsReused",
|
"PacketsReused",
|
||||||
"Packets reused",
|
"Packets reused",
|
||||||
|
"Number of packets reused out of all requests to the packet pool",
|
||||||
"clientstack",
|
"clientstack",
|
||||||
"packetpool",
|
"packetpool",
|
||||||
StatVerbosity.Debug,
|
StatType.Push,
|
||||||
"Number of packets reused out of all requests to the packet pool");
|
null,
|
||||||
|
StatVerbosity.Debug);
|
||||||
|
|
||||||
private PercentageStat m_blocksReusedStat = new PercentageStat(
|
private PercentageStat m_blocksReusedStat = new PercentageStat(
|
||||||
"BlocksReused",
|
"PacketDataBlocksReused",
|
||||||
"Blocks reused",
|
"Packet data blocks reused",
|
||||||
|
"Number of data blocks reused out of all requests to the packet pool",
|
||||||
"clientstack",
|
"clientstack",
|
||||||
"packetpool",
|
"packetpool",
|
||||||
StatVerbosity.Debug,
|
StatType.Push,
|
||||||
"Number of data blocks reused out of all requests to the packet pool");
|
null,
|
||||||
|
StatVerbosity.Debug);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Pool of packets available for reuse.
|
/// Pool of packets available for reuse.
|
||||||
|
@ -88,6 +92,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
{
|
{
|
||||||
StatsManager.RegisterStat(m_packetsReusedStat);
|
StatsManager.RegisterStat(m_packetsReusedStat);
|
||||||
StatsManager.RegisterStat(m_blocksReusedStat);
|
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -186,6 +186,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
|
||||||
{
|
{
|
||||||
string fromName = c.From;
|
string fromName = c.From;
|
||||||
UUID fromID = UUID.Zero;
|
UUID fromID = UUID.Zero;
|
||||||
|
UUID ownerID = UUID.Zero;
|
||||||
UUID targetID = c.TargetUUID;
|
UUID targetID = c.TargetUUID;
|
||||||
string message = c.Message;
|
string message = c.Message;
|
||||||
IScene scene = c.Scene;
|
IScene scene = c.Scene;
|
||||||
|
@ -208,12 +209,16 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
|
||||||
fromPos = avatar.AbsolutePosition;
|
fromPos = avatar.AbsolutePosition;
|
||||||
fromName = avatar.Name;
|
fromName = avatar.Name;
|
||||||
fromID = c.Sender.AgentId;
|
fromID = c.Sender.AgentId;
|
||||||
|
ownerID = c.Sender.AgentId;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ChatSourceType.Object:
|
case ChatSourceType.Object:
|
||||||
fromID = c.SenderUUID;
|
fromID = c.SenderUUID;
|
||||||
|
|
||||||
|
if (c.SenderObject != null && c.SenderObject is SceneObjectPart)
|
||||||
|
ownerID = ((SceneObjectPart)c.SenderObject).OwnerID;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,7 +241,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
|
||||||
s.ForEachRootScenePresence(
|
s.ForEachRootScenePresence(
|
||||||
delegate(ScenePresence presence)
|
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);
|
receiverIDs.Add(presence.UUID);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -248,8 +254,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
|
||||||
ScenePresence presence = s.GetScenePresence(targetID);
|
ScenePresence presence = s.GetScenePresence(targetID);
|
||||||
if (presence != null && !presence.IsChildAgent)
|
if (presence != null && !presence.IsChildAgent)
|
||||||
{
|
{
|
||||||
if (TrySendChatMessage(presence, fromPos, regionPos, fromID, fromName, ChatTypeEnum.Say, message, sourceType, true))
|
if (TrySendChatMessage(
|
||||||
receiverIDs.Add(presence.UUID);
|
presence, fromPos, regionPos, fromID, ownerID, fromName, ChatTypeEnum.Say, message, sourceType, true))
|
||||||
|
receiverIDs.Add(presence.UUID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -306,8 +313,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
|
||||||
(((SceneObjectPart)c.SenderObject).OwnerID != client.AgentId))
|
(((SceneObjectPart)c.SenderObject).OwnerID != client.AgentId))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
client.SendChatMessage(c.Message, (byte)cType, CenterOfRegion, fromName, fromID,
|
client.SendChatMessage(
|
||||||
(byte)sourceType, (byte)ChatAudibleLevel.Fully);
|
c.Message, (byte)cType, CenterOfRegion, fromName, fromID, fromID,
|
||||||
|
(byte)sourceType, (byte)ChatAudibleLevel.Fully);
|
||||||
|
|
||||||
receiverIDs.Add(client.AgentId);
|
receiverIDs.Add(client.AgentId);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -322,15 +331,20 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
|
||||||
/// <param name="fromPos"></param>
|
/// <param name="fromPos"></param>
|
||||||
/// <param name="regionPos">/param>
|
/// <param name="regionPos">/param>
|
||||||
/// <param name="fromAgentID"></param>
|
/// <param name="fromAgentID"></param>
|
||||||
|
/// <param name='ownerID'>
|
||||||
|
/// 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
|
||||||
|
/// </param>
|
||||||
/// <param name="fromName"></param>
|
/// <param name="fromName"></param>
|
||||||
/// <param name="type"></param>
|
/// <param name="type"></param>
|
||||||
/// <param name="message"></param>
|
/// <param name="message"></param>
|
||||||
/// <param name="src"></param>
|
/// <param name="src"></param>
|
||||||
/// <returns>true if the message was sent to the receiver, false if it was not sent due to failing a
|
/// <returns>true if the message was sent to the receiver, false if it was not sent due to failing a
|
||||||
/// precondition</returns>
|
/// precondition</returns>
|
||||||
protected virtual bool TrySendChatMessage(ScenePresence presence, Vector3 fromPos, Vector3 regionPos,
|
protected virtual bool TrySendChatMessage(
|
||||||
UUID fromAgentID, string fromName, ChatTypeEnum type,
|
ScenePresence presence, Vector3 fromPos, Vector3 regionPos,
|
||||||
string message, ChatSourceType src, bool ignoreDistance)
|
UUID fromAgentID, UUID ownerID, string fromName, ChatTypeEnum type,
|
||||||
|
string message, ChatSourceType src, bool ignoreDistance)
|
||||||
{
|
{
|
||||||
// don't send stuff to child agents
|
// don't send stuff to child agents
|
||||||
if (presence.IsChildAgent) return false;
|
if (presence.IsChildAgent) return false;
|
||||||
|
@ -353,8 +367,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: should change so the message is sent through the avatar rather than direct to the ClientView
|
// 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,
|
presence.ControllingClient.SendChatMessage(
|
||||||
fromAgentID, (byte)src, (byte)ChatAudibleLevel.Fully);
|
message, (byte) type, fromPos, fromName,
|
||||||
|
fromAgentID, ownerID, (byte)src, (byte)ChatAudibleLevel.Fully);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@ using Nini.Config;
|
||||||
using OpenMetaverse;
|
using OpenMetaverse;
|
||||||
using OpenSim.Framework;
|
using OpenSim.Framework;
|
||||||
using OpenSim.Framework.Communications;
|
using OpenSim.Framework.Communications;
|
||||||
|
using OpenSim.Framework.Console;
|
||||||
using OpenSim.Region.Framework.Interfaces;
|
using OpenSim.Region.Framework.Interfaces;
|
||||||
using OpenSim.Region.Framework.Scenes;
|
using OpenSim.Region.Framework.Scenes;
|
||||||
using OpenSim.Services.Interfaces;
|
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,
|
Guid id, string firstName, string lastName, string invPath, string pass, string savePath,
|
||||||
Dictionary<string, object> options)
|
Dictionary<string, object> options)
|
||||||
{
|
{
|
||||||
|
if (!ConsoleUtil.CheckFileDoesNotExist(MainConsole.Instance, savePath))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (m_scenes.Count > 0)
|
if (m_scenes.Count > 0)
|
||||||
{
|
{
|
||||||
UserAccount userInfo = GetUserInfo(firstName, lastName, pass);
|
UserAccount userInfo = GetUserInfo(firstName, lastName, pass);
|
||||||
|
|
|
@ -38,15 +38,15 @@ using OpenSim.Services.Interfaces;
|
||||||
|
|
||||||
namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
|
namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
|
||||||
{
|
{
|
||||||
public class InventoryTransferModule : IInventoryTransferModule, ISharedRegionModule
|
public class InventoryTransferModule : ISharedRegionModule
|
||||||
{
|
{
|
||||||
private static readonly ILog m_log
|
private static readonly ILog m_log
|
||||||
= LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
= LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
private List<Scene> m_Scenelist = new List<Scene>();
|
private List<Scene> m_Scenelist = new List<Scene>();
|
||||||
private Dictionary<UUID, Scene> m_AgentRegions =
|
// private Dictionary<UUID, Scene> m_AgentRegions =
|
||||||
new Dictionary<UUID, Scene>();
|
// new Dictionary<UUID, Scene>();
|
||||||
|
|
||||||
private IMessageTransferModule m_TransferModule = null;
|
private IMessageTransferModule m_TransferModule = null;
|
||||||
private bool m_Enabled = true;
|
private bool m_Enabled = true;
|
||||||
|
@ -76,12 +76,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
|
||||||
|
|
||||||
m_Scenelist.Add(scene);
|
m_Scenelist.Add(scene);
|
||||||
|
|
||||||
scene.RegisterModuleInterface<IInventoryTransferModule>(this);
|
// scene.RegisterModuleInterface<IInventoryTransferModule>(this);
|
||||||
|
|
||||||
scene.EventManager.OnNewClient += OnNewClient;
|
scene.EventManager.OnNewClient += OnNewClient;
|
||||||
scene.EventManager.OnClientClosed += ClientLoggedOut;
|
// scene.EventManager.OnClientClosed += ClientLoggedOut;
|
||||||
scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage;
|
scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage;
|
||||||
scene.EventManager.OnSetRootAgentScene += OnSetRootAgentScene;
|
// scene.EventManager.OnSetRootAgentScene += OnSetRootAgentScene;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RegionLoaded(Scene scene)
|
public void RegionLoaded(Scene scene)
|
||||||
|
@ -96,9 +96,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
|
||||||
|
|
||||||
m_Scenelist.Clear();
|
m_Scenelist.Clear();
|
||||||
scene.EventManager.OnNewClient -= OnNewClient;
|
scene.EventManager.OnNewClient -= OnNewClient;
|
||||||
scene.EventManager.OnClientClosed -= ClientLoggedOut;
|
// scene.EventManager.OnClientClosed -= ClientLoggedOut;
|
||||||
scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage;
|
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)
|
public void RemoveRegion(Scene scene)
|
||||||
{
|
{
|
||||||
scene.EventManager.OnNewClient -= OnNewClient;
|
scene.EventManager.OnNewClient -= OnNewClient;
|
||||||
scene.EventManager.OnClientClosed -= ClientLoggedOut;
|
// scene.EventManager.OnClientClosed -= ClientLoggedOut;
|
||||||
scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage;
|
scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage;
|
||||||
scene.EventManager.OnSetRootAgentScene -= OnSetRootAgentScene;
|
// scene.EventManager.OnSetRootAgentScene -= OnSetRootAgentScene;
|
||||||
m_Scenelist.Remove(scene);
|
m_Scenelist.Remove(scene);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,10 +138,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
|
||||||
client.OnInstantMessage += OnInstantMessage;
|
client.OnInstantMessage += OnInstantMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void OnSetRootAgentScene(UUID id, Scene scene)
|
// protected void OnSetRootAgentScene(UUID id, Scene scene)
|
||||||
{
|
// {
|
||||||
m_AgentRegions[id] = scene;
|
// m_AgentRegions[id] = scene;
|
||||||
}
|
// }
|
||||||
|
|
||||||
private Scene FindClientScene(UUID agentId)
|
private Scene FindClientScene(UUID agentId)
|
||||||
{
|
{
|
||||||
|
@ -448,69 +448,69 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool NeedSceneCacheClear(UUID agentID, Scene scene)
|
// public bool NeedSceneCacheClear(UUID agentID, Scene scene)
|
||||||
{
|
// {
|
||||||
if (!m_AgentRegions.ContainsKey(agentID))
|
// if (!m_AgentRegions.ContainsKey(agentID))
|
||||||
{
|
// {
|
||||||
// Since we can get here two ways, we need to scan
|
// // Since we can get here two ways, we need to scan
|
||||||
// the scenes here. This is somewhat more expensive
|
// // the scenes here. This is somewhat more expensive
|
||||||
// but helps avoid a nasty bug
|
// // but helps avoid a nasty bug
|
||||||
//
|
// //
|
||||||
|
//
|
||||||
foreach (Scene s in m_Scenelist)
|
// foreach (Scene s in m_Scenelist)
|
||||||
{
|
// {
|
||||||
ScenePresence presence;
|
// ScenePresence presence;
|
||||||
|
//
|
||||||
if (s.TryGetScenePresence(agentID, out presence))
|
// if (s.TryGetScenePresence(agentID, out presence))
|
||||||
{
|
// {
|
||||||
// If the agent is in this scene, then we
|
// // If the agent is in this scene, then we
|
||||||
// are being called twice in a single
|
// // are being called twice in a single
|
||||||
// teleport. This is wasteful of cycles
|
// // teleport. This is wasteful of cycles
|
||||||
// but harmless due to this 2nd level check
|
// // but harmless due to this 2nd level check
|
||||||
//
|
// //
|
||||||
// If the agent is found in another scene
|
// // If the agent is found in another scene
|
||||||
// then the list wasn't current
|
// // then the list wasn't current
|
||||||
//
|
// //
|
||||||
// If the agent is totally unknown, then what
|
// // If the agent is totally unknown, then what
|
||||||
// are we even doing here??
|
// // are we even doing here??
|
||||||
//
|
// //
|
||||||
if (s == scene)
|
// if (s == scene)
|
||||||
{
|
// {
|
||||||
//m_log.Debug("[INVTRANSFERMOD]: s == scene. Returning true in " + scene.RegionInfo.RegionName);
|
// //m_log.Debug("[INVTRANSFERMOD]: s == scene. Returning true in " + scene.RegionInfo.RegionName);
|
||||||
return true;
|
// return true;
|
||||||
}
|
// }
|
||||||
else
|
// else
|
||||||
{
|
// {
|
||||||
//m_log.Debug("[INVTRANSFERMOD]: s != scene. Returning false in " + scene.RegionInfo.RegionName);
|
// //m_log.Debug("[INVTRANSFERMOD]: s != scene. Returning false in " + scene.RegionInfo.RegionName);
|
||||||
return false;
|
// return false;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
//m_log.Debug("[INVTRANSFERMOD]: agent not in scene. Returning true in " + scene.RegionInfo.RegionName);
|
// //m_log.Debug("[INVTRANSFERMOD]: agent not in scene. Returning true in " + scene.RegionInfo.RegionName);
|
||||||
return true;
|
// return true;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// The agent is left in current Scene, so we must be
|
// // The agent is left in current Scene, so we must be
|
||||||
// going to another instance
|
// // going to another instance
|
||||||
//
|
// //
|
||||||
if (m_AgentRegions[agentID] == scene)
|
// if (m_AgentRegions[agentID] == scene)
|
||||||
{
|
// {
|
||||||
//m_log.Debug("[INVTRANSFERMOD]: m_AgentRegions[agentID] == scene. Returning true in " + scene.RegionInfo.RegionName);
|
// //m_log.Debug("[INVTRANSFERMOD]: m_AgentRegions[agentID] == scene. Returning true in " + scene.RegionInfo.RegionName);
|
||||||
m_AgentRegions.Remove(agentID);
|
// m_AgentRegions.Remove(agentID);
|
||||||
return true;
|
// return true;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// Another region has claimed the agent
|
// // Another region has claimed the agent
|
||||||
//
|
// //
|
||||||
//m_log.Debug("[INVTRANSFERMOD]: last resort. Returning false in " + scene.RegionInfo.RegionName);
|
// //m_log.Debug("[INVTRANSFERMOD]: last resort. Returning false in " + scene.RegionInfo.RegionName);
|
||||||
return false;
|
// return false;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public void ClientLoggedOut(UUID agentID, Scene scene)
|
// public void ClientLoggedOut(UUID agentID, Scene scene)
|
||||||
{
|
// {
|
||||||
if (m_AgentRegions.ContainsKey(agentID))
|
// if (m_AgentRegions.ContainsKey(agentID))
|
||||||
m_AgentRegions.Remove(agentID);
|
// m_AgentRegions.Remove(agentID);
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
|
|
|
@ -672,13 +672,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
sp.Reset();
|
sp.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
// REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE!
|
// Commented pending deletion since this method no longer appears to do anything at all
|
||||||
if (sp.Scene.NeedSceneCacheClear(sp.UUID))
|
// // 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",
|
// m_log.DebugFormat(
|
||||||
sp.UUID);
|
// "[ENTITY TRANSFER MODULE]: User {0} is going to another region, profile cache removed",
|
||||||
}
|
// sp.UUID);
|
||||||
|
// }
|
||||||
|
|
||||||
m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
|
m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
|
||||||
}
|
}
|
||||||
|
@ -1237,14 +1238,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
|
|
||||||
AgentHasMovedAway(agent, false);
|
AgentHasMovedAway(agent, false);
|
||||||
|
|
||||||
// the user may change their profile information in other region,
|
// // the user may change their profile information in other region,
|
||||||
// so the userinfo in UserProfileCache is not reliable any more, delete it
|
// // so the userinfo in UserProfileCache is not reliable any more, delete it
|
||||||
// REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE!
|
// // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE!
|
||||||
if (agent.Scene.NeedSceneCacheClear(agent.UUID))
|
// if (agent.Scene.NeedSceneCacheClear(agent.UUID))
|
||||||
{
|
// {
|
||||||
m_log.DebugFormat(
|
// m_log.DebugFormat(
|
||||||
"[ENTITY TRANSFER MODULE]: User {0} is going to another region", agent.UUID);
|
// "[ENTITY TRANSFER MODULE]: User {0} is going to another region", agent.UUID);
|
||||||
}
|
// }
|
||||||
|
|
||||||
//m_log.Debug("AFTER CROSS");
|
//m_log.Debug("AFTER CROSS");
|
||||||
//Scene.DumpChildrenSeeds(UUID);
|
//Scene.DumpChildrenSeeds(UUID);
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using Nini.Config;
|
using Nini.Config;
|
||||||
using OpenMetaverse;
|
using OpenMetaverse;
|
||||||
using OpenSim.Framework;
|
using OpenSim.Framework;
|
||||||
|
@ -170,12 +171,42 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
|
||||||
/// <param name="hostID">UUID of the SceneObjectPart</param>
|
/// <param name="hostID">UUID of the SceneObjectPart</param>
|
||||||
/// <param name="channel">channel to listen on</param>
|
/// <param name="channel">channel to listen on</param>
|
||||||
/// <param name="name">name to filter on</param>
|
/// <param name="name">name to filter on</param>
|
||||||
/// <param name="id">key to filter on (user given, could be totally faked)</param>
|
/// <param name="id">
|
||||||
|
/// key to filter on (user given, could be totally faked)
|
||||||
|
/// </param>
|
||||||
/// <param name="msg">msg to filter on</param>
|
/// <param name="msg">msg to filter on</param>
|
||||||
/// <returns>number of the scripts handle</returns>
|
/// <returns>number of the scripts handle</returns>
|
||||||
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="localID">localID of the script engine</param>
|
||||||
|
/// <param name="itemID">UUID of the script engine</param>
|
||||||
|
/// <param name="hostID">UUID of the SceneObjectPart</param>
|
||||||
|
/// <param name="channel">channel to listen on</param>
|
||||||
|
/// <param name="name">name to filter on</param>
|
||||||
|
/// <param name="id">
|
||||||
|
/// key to filter on (user given, could be totally faked)
|
||||||
|
/// </param>
|
||||||
|
/// <param name="msg">msg to filter on</param>
|
||||||
|
/// <param name="regexBitfield">
|
||||||
|
/// Bitfield indicating which strings should be processed as regex.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>number of the scripts handle</returns>
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -465,15 +496,25 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
|
||||||
m_curlisteners = 0;
|
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?
|
// do we already have a match on this particular filter event?
|
||||||
List<ListenerInfo> coll = GetListeners(itemID, channel, name, id, msg);
|
List<ListenerInfo> coll = GetListeners(itemID, channel, name, id,
|
||||||
|
msg);
|
||||||
|
|
||||||
if (coll.Count > 0)
|
if (coll.Count > 0)
|
||||||
{
|
{
|
||||||
// special case, called with same filter settings, return same handle
|
// special case, called with same filter settings, return same
|
||||||
// (2008-05-02, tested on 1.21.1 server, still holds)
|
// handle (2008-05-02, tested on 1.21.1 server, still holds)
|
||||||
return coll[0].GetHandle();
|
return coll[0].GetHandle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -485,7 +526,9 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
|
||||||
|
|
||||||
if (newHandle > 0)
|
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<ListenerInfo> listeners;
|
List<ListenerInfo> listeners;
|
||||||
if (!m_listeners.TryGetValue(channel,out listeners))
|
if (!m_listeners.TryGetValue(channel,out listeners))
|
||||||
|
@ -626,6 +669,22 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// These are duplicated from ScriptBaseClass
|
||||||
|
/// http://opensimulator.org/mantis/view.php?id=6106#c21945
|
||||||
|
#region Constants for the bitfield parameter of osListenRegex
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// process name parameter as regex
|
||||||
|
/// </summary>
|
||||||
|
public const int OS_LISTEN_REGEX_NAME = 0x1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// process message parameter as regex
|
||||||
|
/// </summary>
|
||||||
|
public const int OS_LISTEN_REGEX_MESSAGE = 0x2;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
// Theres probably a more clever and efficient way to
|
// Theres probably a more clever and efficient way to
|
||||||
// do this, maybe with regex.
|
// do this, maybe with regex.
|
||||||
// PM2008: Ha, one could even be smart and define a specialized Enumerator.
|
// PM2008: Ha, one could even be smart and define a specialized Enumerator.
|
||||||
|
@ -651,7 +710,10 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
|
||||||
{
|
{
|
||||||
continue;
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -659,7 +721,10 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
|
||||||
{
|
{
|
||||||
continue;
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -692,10 +757,13 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
|
||||||
{
|
{
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
Object[] item = new Object[6];
|
Object[] item = new Object[6];
|
||||||
|
int dataItemLength = 6;
|
||||||
|
|
||||||
while (idx < data.Length)
|
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 info =
|
||||||
ListenerInfo.FromData(localID, itemID, hostID, item);
|
ListenerInfo.FromData(localID, itemID, hostID, item);
|
||||||
|
@ -707,12 +775,12 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
|
||||||
m_listeners[(int)item[2]].Add(info);
|
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 bool m_active; // Listener is active or not
|
||||||
private int m_handle; // Assigned handle of this listener
|
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)
|
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)
|
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,
|
public ListenerInfo(ListenerInfo li, string name, UUID id, string message, int regexBitfield)
|
||||||
UUID id, string message)
|
{
|
||||||
|
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_active = true;
|
||||||
m_handle = handle;
|
m_handle = handle;
|
||||||
|
@ -746,11 +827,12 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
|
||||||
m_name = name;
|
m_name = name;
|
||||||
m_id = id;
|
m_id = id;
|
||||||
m_message = message;
|
m_message = message;
|
||||||
|
RegexBitfield = regexBitfield;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object[] GetSerializationData()
|
public Object[] GetSerializationData()
|
||||||
{
|
{
|
||||||
Object[] data = new Object[6];
|
Object[] data = new Object[7];
|
||||||
|
|
||||||
data[0] = m_active;
|
data[0] = m_active;
|
||||||
data[1] = m_handle;
|
data[1] = m_handle;
|
||||||
|
@ -758,16 +840,19 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
|
||||||
data[3] = m_name;
|
data[3] = m_name;
|
||||||
data[4] = m_id;
|
data[4] = m_id;
|
||||||
data[5] = m_message;
|
data[5] = m_message;
|
||||||
|
data[6] = RegexBitfield;
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ListenerInfo FromData(uint localID, UUID ItemID, UUID hostID, Object[] data)
|
public static ListenerInfo FromData(uint localID, UUID ItemID, UUID hostID, Object[] data)
|
||||||
{
|
{
|
||||||
ListenerInfo linfo = new ListenerInfo((int)data[1], localID,
|
ListenerInfo linfo = new ListenerInfo((int)data[1], localID, ItemID, hostID, (int)data[2], (string)data[3], (UUID)data[4], (string)data[5]);
|
||||||
ItemID, hostID, (int)data[2], (string)data[3],
|
linfo.m_active = (bool)data[0];
|
||||||
(UUID)data[4], (string)data[5]);
|
if (data.Length >= 7)
|
||||||
linfo.m_active=(bool)data[0];
|
{
|
||||||
|
linfo.RegexBitfield = (int)data[6];
|
||||||
|
}
|
||||||
|
|
||||||
return linfo;
|
return linfo;
|
||||||
}
|
}
|
||||||
|
@ -826,5 +911,7 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
|
||||||
{
|
{
|
||||||
return m_id;
|
return m_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int RegexBitfield { get; private set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,7 +110,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||||
lastX = (lastX == null) ? curLastX : (lastX > curLastX) ? lastX : curLastX;
|
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
|
// Calculate the subdirectory in which each region will be stored in the archive
|
||||||
|
|
|
@ -32,6 +32,8 @@ using System.Reflection;
|
||||||
using log4net;
|
using log4net;
|
||||||
using NDesk.Options;
|
using NDesk.Options;
|
||||||
using Nini.Config;
|
using Nini.Config;
|
||||||
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Framework.Console;
|
||||||
using OpenSim.Region.Framework.Interfaces;
|
using OpenSim.Region.Framework.Interfaces;
|
||||||
using OpenSim.Region.Framework.Scenes;
|
using OpenSim.Region.Framework.Scenes;
|
||||||
|
|
||||||
|
@ -150,14 +152,16 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||||
|
|
||||||
List<string> mainParams = ops.Parse(cmdparams);
|
List<string> mainParams = ops.Parse(cmdparams);
|
||||||
|
|
||||||
|
string path;
|
||||||
if (mainParams.Count > 2)
|
if (mainParams.Count > 2)
|
||||||
{
|
path = mainParams[2];
|
||||||
ArchiveRegion(mainParams[2], options);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
path = DEFAULT_OAR_BACKUP_FILENAME;
|
||||||
ArchiveRegion(DEFAULT_OAR_BACKUP_FILENAME, options);
|
|
||||||
}
|
if (!ConsoleUtil.CheckFileDoesNotExist(MainConsole.Instance, path))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ArchiveRegion(path, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ArchiveRegion(string savePath, Dictionary<string, object> options)
|
public void ArchiveRegion(string savePath, Dictionary<string, object> options)
|
||||||
|
|
|
@ -27,10 +27,12 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Xml;
|
||||||
using log4net;
|
using log4net;
|
||||||
using Mono.Addins;
|
using Mono.Addins;
|
||||||
using NDesk.Options;
|
using NDesk.Options;
|
||||||
|
@ -41,6 +43,7 @@ using OpenSim.Framework.Console;
|
||||||
using OpenSim.Framework.Monitoring;
|
using OpenSim.Framework.Monitoring;
|
||||||
using OpenSim.Region.Framework.Interfaces;
|
using OpenSim.Region.Framework.Interfaces;
|
||||||
using OpenSim.Region.Framework.Scenes;
|
using OpenSim.Region.Framework.Scenes;
|
||||||
|
using OpenSim.Region.Framework.Scenes.Serialization;
|
||||||
|
|
||||||
namespace OpenSim.Region.CoreModules.World.Objects.Commands
|
namespace OpenSim.Region.CoreModules.World.Objects.Commands
|
||||||
{
|
{
|
||||||
|
@ -96,9 +99,9 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
|
||||||
HandleDeleteObject);
|
HandleDeleteObject);
|
||||||
|
|
||||||
m_console.Commands.AddCommand(
|
m_console.Commands.AddCommand(
|
||||||
"Objects", false, "delete object uuid",
|
"Objects", false, "delete object id",
|
||||||
"delete object uuid <UUID>",
|
"delete object id <UUID-or-localID>",
|
||||||
"Delete a scene object by uuid",
|
"Delete a scene object by uuid or localID",
|
||||||
HandleDeleteObject);
|
HandleDeleteObject);
|
||||||
|
|
||||||
m_console.Commands.AddCommand(
|
m_console.Commands.AddCommand(
|
||||||
|
@ -122,28 +125,18 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
|
||||||
"delete object pos",
|
"delete object pos",
|
||||||
"delete object pos <start-coord> to <end-coord>",
|
"delete object pos <start-coord> to <end-coord>",
|
||||||
"Delete scene objects within the given area.",
|
"Delete scene objects within the given area.",
|
||||||
"Each component of the coord is comma separated. There must be no spaces between the commas.\n"
|
ConsoleUtil.CoordHelp,
|
||||||
+ "If you don't care about the z component you can simply omit it.\n"
|
|
||||||
+ "If you don't care about the x or y components then you can leave them blank (though a comma is still required)\n"
|
|
||||||
+ "If you want to specify the maxmimum value of a component then you can use ~ instead of a number\n"
|
|
||||||
+ "If you want to specify the minimum value of a component then you can use -~ instead of a number\n"
|
|
||||||
+ "e.g.\n"
|
|
||||||
+ "delete object pos 20,20,20 to 40,40,40\n"
|
|
||||||
+ "delete object pos 20,20 to 40,40\n"
|
|
||||||
+ "delete object pos ,20,20 to ,40,40\n"
|
|
||||||
+ "delete object pos ,,30 to ,,~\n"
|
|
||||||
+ "delete object pos ,,-~ to ,,30",
|
|
||||||
HandleDeleteObject);
|
HandleDeleteObject);
|
||||||
|
|
||||||
m_console.Commands.AddCommand(
|
m_console.Commands.AddCommand(
|
||||||
"Objects",
|
"Objects",
|
||||||
false,
|
false,
|
||||||
"show object uuid",
|
"show object id",
|
||||||
"show object uuid [--full] <UUID>",
|
"show object id [--full] <UUID-or-localID>",
|
||||||
"Show details of a scene object with the given UUID",
|
"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"
|
"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.",
|
+ "For yet more detailed part information, use the \"show part\" commands.",
|
||||||
HandleShowObjectByUuid);
|
HandleShowObjectById);
|
||||||
|
|
||||||
m_console.Commands.AddCommand(
|
m_console.Commands.AddCommand(
|
||||||
"Objects",
|
"Objects",
|
||||||
|
@ -164,25 +157,15 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
|
||||||
"Show details of scene objects within the given area.",
|
"Show details of scene objects within the given area.",
|
||||||
"The --full option will print out information on all the parts of the object.\n"
|
"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"
|
+ "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"
|
+ ConsoleUtil.CoordHelp,
|
||||||
+ "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",
|
|
||||||
HandleShowObjectByPos);
|
HandleShowObjectByPos);
|
||||||
|
|
||||||
m_console.Commands.AddCommand(
|
m_console.Commands.AddCommand(
|
||||||
"Objects",
|
"Objects",
|
||||||
false,
|
false,
|
||||||
"show part uuid",
|
"show part id",
|
||||||
"show part uuid <UUID>",
|
"show part id <UUID-or-localID>",
|
||||||
"Show details of a scene object parts with the given UUID", HandleShowPartByUuid);
|
"Show details of a scene object part with the given UUID or localID", HandleShowPartById);
|
||||||
|
|
||||||
m_console.Commands.AddCommand(
|
m_console.Commands.AddCommand(
|
||||||
"Objects",
|
"Objects",
|
||||||
|
@ -190,7 +173,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
|
||||||
"show part name",
|
"show part name",
|
||||||
"show part name [--regex] <name>",
|
"show part name [--regex] <name>",
|
||||||
"Show details of scene object parts with the given name.",
|
"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);
|
HandleShowPartByName);
|
||||||
|
|
||||||
m_console.Commands.AddCommand(
|
m_console.Commands.AddCommand(
|
||||||
|
@ -199,18 +182,19 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
|
||||||
"show part pos",
|
"show part pos",
|
||||||
"show part pos <start-coord> to <end-coord>",
|
"show part pos <start-coord> to <end-coord>",
|
||||||
"Show details of scene object parts within the given area.",
|
"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"
|
ConsoleUtil.CoordHelp,
|
||||||
+ "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",
|
|
||||||
HandleShowPartByPos);
|
HandleShowPartByPos);
|
||||||
|
|
||||||
|
m_console.Commands.AddCommand(
|
||||||
|
"Objects",
|
||||||
|
false,
|
||||||
|
"dump object id",
|
||||||
|
"dump object id <UUID-or-localID>",
|
||||||
|
"Dump the formatted serialization of the given object to the file <UUID>.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)
|
public void RemoveRegion(Scene scene)
|
||||||
|
@ -265,7 +249,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
|
||||||
m_console.OutputFormat(sb.ToString());
|
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))
|
if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene))
|
||||||
return;
|
return;
|
||||||
|
@ -281,14 +265,17 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
UUID objectUuid;
|
UUID uuid;
|
||||||
if (!UUID.TryParse(mainParams[3], out objectUuid))
|
uint localId;
|
||||||
{
|
if (!ConsoleUtil.TryParseConsoleId(m_console, mainParams[3], out uuid, out localId))
|
||||||
m_console.OutputFormat("{0} is not a valid uuid", mainParams[3]);
|
|
||||||
return;
|
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)
|
if (so == null)
|
||||||
{
|
{
|
||||||
|
@ -365,7 +352,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
|
||||||
OutputSogsToConsole(searchPredicate, showFull);
|
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))
|
if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene))
|
||||||
return;
|
return;
|
||||||
|
@ -378,18 +365,20 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
|
||||||
|
|
||||||
if (mainParams.Count < 4)
|
if (mainParams.Count < 4)
|
||||||
{
|
{
|
||||||
m_console.OutputFormat("Usage: show part uuid [--full] <uuid>");
|
m_console.OutputFormat("Usage: show part id [--full] <UUID-or-localID>");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
UUID objectUuid;
|
UUID objectUuid;
|
||||||
if (!UUID.TryParse(mainParams[3], out objectUuid))
|
uint localId;
|
||||||
{
|
if (!ConsoleUtil.TryParseConsoleId(m_console, mainParams[3], out objectUuid, out localId))
|
||||||
m_console.OutputFormat("{0} is not a valid uuid", mainParams[3]);
|
|
||||||
return;
|
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)
|
if (sop == null)
|
||||||
{
|
{
|
||||||
|
@ -477,6 +466,51 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
|
||||||
OutputSopsToConsole(searchPredicate, true);
|
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 <UUID-or-localID>");
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Append a scene object report to an input StringBuilder
|
/// Append a scene object report to an input StringBuilder
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -641,18 +675,23 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "uuid":
|
case "id":
|
||||||
if (!UUID.TryParse(o, out match))
|
UUID uuid;
|
||||||
|
uint localId;
|
||||||
|
if (!ConsoleUtil.TryParseConsoleId(m_console, o, out uuid, out localId))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
requireConfirmation = false;
|
requireConfirmation = false;
|
||||||
deletes = new List<SceneObjectGroup>();
|
deletes = new List<SceneObjectGroup>();
|
||||||
|
|
||||||
m_scene.ForEachSOG(delegate (SceneObjectGroup g)
|
SceneObjectGroup so;
|
||||||
{
|
if (localId == ConsoleUtil.LocalIdNotFound)
|
||||||
if (g.UUID == match && !g.IsAttachment)
|
so = m_scene.GetSceneObjectGroup(uuid);
|
||||||
deletes.Add(g);
|
else
|
||||||
});
|
so = m_scene.GetSceneObjectGroup(localId);
|
||||||
|
|
||||||
|
if (!so.IsAttachment)
|
||||||
|
deletes.Add(so);
|
||||||
|
|
||||||
// if (deletes.Count == 0)
|
// if (deletes.Count == 0)
|
||||||
// m_console.OutputFormat("No objects were found with uuid {0}", match);
|
// m_console.OutputFormat("No objects were found with uuid {0}", match);
|
||||||
|
|
|
@ -45,6 +45,13 @@ namespace OpenSim.Region.Framework.Interfaces
|
||||||
void Deactivate();
|
void Deactivate();
|
||||||
void Activate();
|
void Activate();
|
||||||
UUID GetID();
|
UUID GetID();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Bitfield indicating which strings should be processed as regex.
|
||||||
|
/// 1 corresponds to IWorldCommListenerInfo::GetName()
|
||||||
|
/// 2 corresponds to IWorldCommListenerInfo::GetMessage()
|
||||||
|
/// </summary>
|
||||||
|
int RegexBitfield { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IWorldComm
|
public interface IWorldComm
|
||||||
|
@ -60,7 +67,7 @@ namespace OpenSim.Region.Framework.Interfaces
|
||||||
/// the script during 'peek' time. Parameter hostID is needed to
|
/// the script during 'peek' time. Parameter hostID is needed to
|
||||||
/// determine the position of the script.
|
/// determine the position of the script.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="localID">localID of the script engine</param>
|
/// <param name="LocalID">localID of the script engine</param>
|
||||||
/// <param name="itemID">UUID of the script engine</param>
|
/// <param name="itemID">UUID of the script engine</param>
|
||||||
/// <param name="hostID">UUID of the SceneObjectPart</param>
|
/// <param name="hostID">UUID of the SceneObjectPart</param>
|
||||||
/// <param name="channel">channel to listen on</param>
|
/// <param name="channel">channel to listen on</param>
|
||||||
|
@ -70,6 +77,23 @@ namespace OpenSim.Region.Framework.Interfaces
|
||||||
/// <returns>number of the scripts handle</returns>
|
/// <returns>number of the scripts handle</returns>
|
||||||
int Listen(uint LocalID, UUID itemID, UUID hostID, int channel, string name, UUID id, string msg);
|
int Listen(uint LocalID, UUID itemID, UUID hostID, int channel, string name, UUID id, string msg);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="LocalID">localID of the script engine</param>
|
||||||
|
/// <param name="itemID">UUID of the script engine</param>
|
||||||
|
/// <param name="hostID">UUID of the SceneObjectPart</param>
|
||||||
|
/// <param name="channel">channel to listen on</param>
|
||||||
|
/// <param name="name">name to filter on</param>
|
||||||
|
/// <param name="id">key to filter on (user given, could be totally faked)</param>
|
||||||
|
/// <param name="msg">msg to filter on</param>
|
||||||
|
/// <param name="regexBitfield">Bitfield indicating which strings should be processed as regex.</param>
|
||||||
|
/// <returns>number of the scripts handle</returns>
|
||||||
|
int Listen(uint LocalID, UUID itemID, UUID hostID, int channel, string name, UUID id, string msg, int regexBitfield);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This method scans over the objects which registered an interest in listen callbacks.
|
/// 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
|
/// For everyone it finds, it checks if it fits the given filter. If it does, then
|
||||||
|
|
|
@ -41,12 +41,13 @@ namespace OpenSim.Region.Framework.Scenes.Animation
|
||||||
{
|
{
|
||||||
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
// 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 OpenSim.Framework.Animation m_defaultAnimation = new OpenSim.Framework.Animation();
|
||||||
private List<OpenSim.Framework.Animation> m_animations = new List<OpenSim.Framework.Animation>();
|
private List<OpenSim.Framework.Animation> m_animations = new List<OpenSim.Framework.Animation>();
|
||||||
|
|
||||||
public OpenSim.Framework.Animation DefaultAnimation
|
public OpenSim.Framework.Animation ImplicitDefaultAnimation
|
||||||
{
|
{
|
||||||
get { return m_defaultAnimation; }
|
get { return m_implicitDefaultAnimation; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public AnimationSet()
|
public AnimationSet()
|
||||||
|
@ -119,6 +120,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation
|
||||||
if (m_defaultAnimation.AnimID != animID)
|
if (m_defaultAnimation.AnimID != animID)
|
||||||
{
|
{
|
||||||
m_defaultAnimation = new OpenSim.Framework.Animation(animID, sequenceNum, objectID);
|
m_defaultAnimation = new OpenSim.Framework.Animation(animID, sequenceNum, objectID);
|
||||||
|
m_implicitDefaultAnimation = m_defaultAnimation;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -38,7 +38,18 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
{
|
{
|
||||||
public partial class Scene
|
public partial class Scene
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Send chat to listeners.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name='message'></param>
|
||||||
|
/// <param name='type'>/param>
|
||||||
|
/// <param name='channel'></param>
|
||||||
|
/// <param name='fromPos'></param>
|
||||||
|
/// <param name='fromName'></param>
|
||||||
|
/// <param name='fromID'></param>
|
||||||
|
/// <param name='targetID'></param>
|
||||||
|
/// <param name='fromAgent'></param>
|
||||||
|
/// <param name='broadcast'></param>
|
||||||
protected void SimChat(byte[] message, ChatTypeEnum type, int channel, Vector3 fromPos, string fromName,
|
protected void SimChat(byte[] message, ChatTypeEnum type, int channel, Vector3 fromPos, string fromName,
|
||||||
UUID fromID, UUID targetID, bool fromAgent, bool broadcast)
|
UUID fromID, UUID targetID, bool fromAgent, bool broadcast)
|
||||||
{
|
{
|
||||||
|
@ -66,6 +77,10 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
args.From = fromName;
|
args.From = fromName;
|
||||||
args.TargetUUID = targetID;
|
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)
|
if (broadcast)
|
||||||
EventManager.TriggerOnChatBroadcast(this, args);
|
EventManager.TriggerOnChatBroadcast(this, args);
|
||||||
else
|
else
|
||||||
|
|
|
@ -1267,6 +1267,12 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
// This is the method that shuts down the scene.
|
// This is the method that shuts down the scene.
|
||||||
public override void Close()
|
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);
|
m_log.InfoFormat("[SCENE]: Closing down the single simulator: {0}", RegionInfo.RegionName);
|
||||||
|
|
||||||
StatsReporter.Close();
|
StatsReporter.Close();
|
||||||
|
@ -1310,6 +1316,14 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
m_sceneGraph.Close();
|
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)
|
if (PhysicsScene != null)
|
||||||
{
|
{
|
||||||
PhysicsScene phys = PhysicsScene;
|
PhysicsScene phys = PhysicsScene;
|
||||||
|
@ -1318,12 +1332,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
phys.Dispose();
|
phys.Dispose();
|
||||||
phys = null;
|
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -3427,9 +3435,10 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
if (closeChildAgents && CapsModule != null)
|
if (closeChildAgents && CapsModule != null)
|
||||||
CapsModule.RemoveCaps(agentID);
|
CapsModule.RemoveCaps(agentID);
|
||||||
|
|
||||||
// REFACTORING PROBLEM -- well not really a problem, but just to point out that whatever
|
// // REFACTORING PROBLEM -- well not really a problem, but just to point out that whatever
|
||||||
// this method is doing is HORRIBLE!!!
|
// // this method is doing is HORRIBLE!!!
|
||||||
avatar.Scene.NeedSceneCacheClear(avatar.UUID);
|
// Commented pending deletion since this method no longer appears to do anything at all
|
||||||
|
// avatar.Scene.NeedSceneCacheClear(avatar.UUID);
|
||||||
|
|
||||||
if (closeChildAgents && !isChildAgent)
|
if (closeChildAgents && !isChildAgent)
|
||||||
{
|
{
|
||||||
|
@ -4688,12 +4697,23 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
/// Get a group via its UUID
|
/// Get a group via its UUID
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="fullID"></param>
|
/// <param name="fullID"></param>
|
||||||
/// <returns>null if no group with that name exists</returns>
|
/// <returns>null if no group with that id exists</returns>
|
||||||
public SceneObjectGroup GetSceneObjectGroup(UUID fullID)
|
public SceneObjectGroup GetSceneObjectGroup(UUID fullID)
|
||||||
{
|
{
|
||||||
return m_sceneGraph.GetSceneObjectGroup(fullID);
|
return m_sceneGraph.GetSceneObjectGroup(fullID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a group via its local ID
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>This will only return a group if the local ID matches a root part</remarks>
|
||||||
|
/// <param name="localID"></param>
|
||||||
|
/// <returns>null if no group with that id exists</returns>
|
||||||
|
public SceneObjectGroup GetSceneObjectGroup(uint localID)
|
||||||
|
{
|
||||||
|
return m_sceneGraph.GetSceneObjectGroup(localID);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get a group by name from the scene (will return the first
|
/// Get a group by name from the scene (will return the first
|
||||||
/// found, if there are more than one prim with the same name)
|
/// 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);
|
client.SendRegionHandle(regionID, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool NeedSceneCacheClear(UUID agentID)
|
// Commented pending deletion since this method no longer appears to do anything at all
|
||||||
{
|
// public bool NeedSceneCacheClear(UUID agentID)
|
||||||
IInventoryTransferModule inv = RequestModuleInterface<IInventoryTransferModule>();
|
// {
|
||||||
if (inv == null)
|
// IInventoryTransferModule inv = RequestModuleInterface<IInventoryTransferModule>();
|
||||||
return true;
|
// if (inv == null)
|
||||||
|
// return true;
|
||||||
return inv.NeedSceneCacheClear(agentID, this);
|
//
|
||||||
}
|
// return inv.NeedSceneCacheClear(agentID, this);
|
||||||
|
// }
|
||||||
|
|
||||||
public void CleanTempObjects()
|
public void CleanTempObjects()
|
||||||
{
|
{
|
||||||
|
|
|
@ -982,6 +982,30 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a group in the scene
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This will only return a group if the local ID matches the root part, not other parts.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="localID">Local id of the root part of the group</param>
|
||||||
|
/// <returns>null if no such group was found</returns>
|
||||||
|
protected internal SceneObjectGroup GetSceneObjectGroup(uint localID)
|
||||||
|
{
|
||||||
|
lock (SceneObjectGroupsByLocalPartID)
|
||||||
|
{
|
||||||
|
if (SceneObjectGroupsByLocalPartID.ContainsKey(localID))
|
||||||
|
{
|
||||||
|
SceneObjectGroup so = SceneObjectGroupsByLocalPartID[localID];
|
||||||
|
|
||||||
|
if (so.LocalId == localID)
|
||||||
|
return so;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get a group by name from the scene (will return the first
|
/// Get a group by name from the scene (will return the first
|
||||||
/// found, if there are more than one prim with the same name)
|
/// found, if there are more than one prim with the same name)
|
||||||
|
|
|
@ -68,7 +68,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
public ScriptControlled eventControls;
|
public ScriptControlled eventControls;
|
||||||
}
|
}
|
||||||
|
|
||||||
public delegate void SendCourseLocationsMethod(UUID scene, ScenePresence presence, List<Vector3> coarseLocations, List<UUID> avatarUUIDs);
|
public delegate void SendCoarseLocationsMethod(UUID scene, ScenePresence presence, List<Vector3> coarseLocations, List<UUID> avatarUUIDs);
|
||||||
|
|
||||||
public class ScenePresence : EntityBase, IScenePresence
|
public class ScenePresence : EntityBase, IScenePresence
|
||||||
{
|
{
|
||||||
|
@ -186,7 +186,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool SitGround { get; private set; }
|
public bool SitGround { get; private set; }
|
||||||
|
|
||||||
private SendCourseLocationsMethod m_sendCourseLocationsMethod;
|
private SendCoarseLocationsMethod m_sendCoarseLocationsMethod;
|
||||||
|
|
||||||
//private Vector3 m_requestedSitOffset = new Vector3();
|
//private Vector3 m_requestedSitOffset = new Vector3();
|
||||||
|
|
||||||
|
@ -695,7 +695,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
AttachmentsSyncLock = new Object();
|
AttachmentsSyncLock = new Object();
|
||||||
AllowMovement = true;
|
AllowMovement = true;
|
||||||
IsChildAgent = true;
|
IsChildAgent = true;
|
||||||
m_sendCourseLocationsMethod = SendCoarseLocationsDefault;
|
m_sendCoarseLocationsMethod = SendCoarseLocationsDefault;
|
||||||
Animator = new ScenePresenceAnimator(this);
|
Animator = new ScenePresenceAnimator(this);
|
||||||
PresenceType = type;
|
PresenceType = type;
|
||||||
DrawDistance = world.DefaultDrawDistance;
|
DrawDistance = world.DefaultDrawDistance;
|
||||||
|
@ -2432,17 +2432,17 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
public void SendCoarseLocations(List<Vector3> coarseLocations, List<UUID> avatarUUIDs)
|
public void SendCoarseLocations(List<Vector3> coarseLocations, List<UUID> avatarUUIDs)
|
||||||
{
|
{
|
||||||
SendCourseLocationsMethod d = m_sendCourseLocationsMethod;
|
SendCoarseLocationsMethod d = m_sendCoarseLocationsMethod;
|
||||||
if (d != null)
|
if (d != null)
|
||||||
{
|
{
|
||||||
d.Invoke(m_scene.RegionInfo.originRegionID, this, coarseLocations, avatarUUIDs);
|
d.Invoke(m_scene.RegionInfo.originRegionID, this, coarseLocations, avatarUUIDs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetSendCourseLocationMethod(SendCourseLocationsMethod d)
|
public void SetSendCoarseLocationMethod(SendCoarseLocationsMethod d)
|
||||||
{
|
{
|
||||||
if (d != null)
|
if (d != null)
|
||||||
m_sendCourseLocationsMethod = d;
|
m_sendCoarseLocationsMethod = d;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendCoarseLocationsDefault(UUID sceneId, ScenePresence p, List<Vector3> coarseLocations, List<UUID> avatarUUIDs)
|
public void SendCoarseLocationsDefault(UUID sceneId, ScenePresence p, List<Vector3> coarseLocations, List<UUID> avatarUUIDs)
|
||||||
|
@ -2646,7 +2646,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
#region Significant Movement Method
|
#region Significant Movement Method
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This checks for a significant movement and sends a courselocationchange update
|
/// This checks for a significant movement and sends a coarselocationchange update
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected void CheckForSignificantMovement()
|
protected void CheckForSignificantMovement()
|
||||||
{
|
{
|
||||||
|
|
|
@ -245,11 +245,13 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
= new Stat(
|
= new Stat(
|
||||||
"SlowFrames",
|
"SlowFrames",
|
||||||
"Slow Frames",
|
"Slow Frames",
|
||||||
|
"Number of frames where frame time has been significantly longer than the desired frame time.",
|
||||||
" frames",
|
" frames",
|
||||||
"scene",
|
"scene",
|
||||||
m_scene.Name,
|
m_scene.Name,
|
||||||
StatVerbosity.Info,
|
StatType.Push,
|
||||||
"Number of frames where frame time has been significantly longer than the desired frame time.");
|
null,
|
||||||
|
StatVerbosity.Info);
|
||||||
|
|
||||||
StatsManager.RegisterStat(SlowFramesStat);
|
StatsManager.RegisterStat(SlowFramesStat);
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,5 +65,22 @@ namespace OpenSim.Region.Framework.Scenes.Tests
|
||||||
|
|
||||||
Assert.That(scene.Frame, Is.EqualTo(1));
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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)
|
if (audible > 0 && message.Length > 0)
|
||||||
IRC_SendChannelPrivmsg(fromName, message);
|
IRC_SendChannelPrivmsg(fromName, message);
|
||||||
|
|
|
@ -128,6 +128,9 @@ namespace OpenSim.Region.OptionalModules.Asset
|
||||||
|
|
||||||
string fileName = rawAssetId;
|
string fileName = rawAssetId;
|
||||||
|
|
||||||
|
if (!ConsoleUtil.CheckFileDoesNotExist(MainConsole.Instance, fileName))
|
||||||
|
return;
|
||||||
|
|
||||||
using (FileStream fs = new FileStream(fileName, FileMode.CreateNew))
|
using (FileStream fs = new FileStream(fileName, FileMode.CreateNew))
|
||||||
{
|
{
|
||||||
using (BinaryWriter bw = new BinaryWriter(fs))
|
using (BinaryWriter bw = new BinaryWriter(fs))
|
||||||
|
|
|
@ -546,8 +546,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.Concierge
|
||||||
c.SenderUUID = UUID.Zero;
|
c.SenderUUID = UUID.Zero;
|
||||||
c.Scene = agent.Scene;
|
c.Scene = agent.Scene;
|
||||||
|
|
||||||
agent.ControllingClient.SendChatMessage(msg, (byte) ChatTypeEnum.Say, PosOfGod, m_whoami, UUID.Zero,
|
agent.ControllingClient.SendChatMessage(
|
||||||
(byte)ChatSourceType.Object, (byte)ChatAudibleLevel.Fully);
|
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)
|
private static void checkStringParameters(XmlRpcRequest request, string[] param)
|
||||||
|
|
|
@ -603,13 +603,15 @@ namespace OpenSim.Region.OptionalModules.World.NPC
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void SendChatMessage(string message, byte type, Vector3 fromPos, string fromName,
|
public virtual void SendChatMessage(
|
||||||
UUID fromAgentID, byte source, byte audible)
|
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,
|
public virtual void SendChatMessage(
|
||||||
UUID fromAgentID, byte source, byte audible)
|
byte[] message, byte type, Vector3 fromPos, string fromName,
|
||||||
|
UUID fromAgentID, UUID ownerID, byte source, byte audible)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -105,7 +105,7 @@ public class BSCharacter : BSPhysObject
|
||||||
shapeData.Position = _position;
|
shapeData.Position = _position;
|
||||||
shapeData.Rotation = _orientation;
|
shapeData.Rotation = _orientation;
|
||||||
shapeData.Velocity = _velocity;
|
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.Scale = Scale;
|
||||||
shapeData.Mass = _mass;
|
shapeData.Mass = _mass;
|
||||||
shapeData.Buoyancy = _buoyancy;
|
shapeData.Buoyancy = _buoyancy;
|
||||||
|
@ -144,7 +144,9 @@ public class BSCharacter : BSPhysObject
|
||||||
ForcePosition = _position;
|
ForcePosition = _position;
|
||||||
// Set the velocity and compute the proper friction
|
// Set the velocity and compute the proper friction
|
||||||
ForceVelocity = _velocity;
|
ForceVelocity = _velocity;
|
||||||
|
|
||||||
BulletSimAPI.SetRestitution2(BSBody.ptr, PhysicsScene.Params.avatarRestitution);
|
BulletSimAPI.SetRestitution2(BSBody.ptr, PhysicsScene.Params.avatarRestitution);
|
||||||
|
BulletSimAPI.SetMargin2(BSShape.ptr, PhysicsScene.Params.collisionMargin);
|
||||||
BulletSimAPI.SetLocalScaling2(BSShape.ptr, Scale);
|
BulletSimAPI.SetLocalScaling2(BSShape.ptr, Scale);
|
||||||
BulletSimAPI.SetContactProcessingThreshold2(BSBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
|
BulletSimAPI.SetContactProcessingThreshold2(BSBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
|
||||||
if (PhysicsScene.Params.ccdMotionThreshold > 0f)
|
if (PhysicsScene.Params.ccdMotionThreshold > 0f)
|
||||||
|
@ -156,11 +158,15 @@ public class BSCharacter : BSPhysObject
|
||||||
OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(BSShape.ptr, MassRaw);
|
OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(BSShape.ptr, MassRaw);
|
||||||
BulletSimAPI.SetMassProps2(BSBody.ptr, MassRaw, localInertia);
|
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.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT);
|
||||||
|
|
||||||
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, BSBody.ptr);
|
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);
|
BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, BSBody.ptr);
|
||||||
|
|
||||||
// Do this after the object has been added to the world
|
// Do this after the object has been added to the world
|
||||||
|
@ -175,11 +181,13 @@ public class BSCharacter : BSPhysObject
|
||||||
}
|
}
|
||||||
// No one calls this method so I don't know what it could possibly mean
|
// No one calls this method so I don't know what it could possibly mean
|
||||||
public override bool Stopped { get { return false; } }
|
public override bool Stopped { get { return false; } }
|
||||||
|
|
||||||
public override OMV.Vector3 Size {
|
public override OMV.Vector3 Size {
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
// Avatar capsule size is kept in the scale parameter.
|
// 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 {
|
set {
|
||||||
|
@ -199,7 +207,9 @@ public class BSCharacter : BSPhysObject
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override OMV.Vector3 Scale { get; set; }
|
public override OMV.Vector3 Scale { get; set; }
|
||||||
|
|
||||||
public override PrimitiveBaseShape Shape
|
public override PrimitiveBaseShape Shape
|
||||||
{
|
{
|
||||||
set { BaseShape = value; }
|
set { BaseShape = value; }
|
||||||
|
@ -264,7 +274,7 @@ public class BSCharacter : BSPhysObject
|
||||||
|
|
||||||
|
|
||||||
// Check that the current position is sane and, if not, modify the position to make it so.
|
// 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.
|
// Returns 'true' of the position was made sane by some action.
|
||||||
private bool PositionSanityCheck()
|
private bool PositionSanityCheck()
|
||||||
{
|
{
|
||||||
|
@ -335,7 +345,7 @@ public class BSCharacter : BSPhysObject
|
||||||
}
|
}
|
||||||
|
|
||||||
// Avatars don't do vehicles
|
// 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 VehicleFloatParam(int param, float value) { }
|
||||||
public override void VehicleVectorParam(int param, OMV.Vector3 value) {}
|
public override void VehicleVectorParam(int param, OMV.Vector3 value) {}
|
||||||
public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { }
|
public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { }
|
||||||
|
@ -588,9 +598,8 @@ public class BSCharacter : BSPhysObject
|
||||||
newScale.X = PhysicsScene.Params.avatarCapsuleRadius;
|
newScale.X = PhysicsScene.Params.avatarCapsuleRadius;
|
||||||
newScale.Y = PhysicsScene.Params.avatarCapsuleRadius;
|
newScale.Y = PhysicsScene.Params.avatarCapsuleRadius;
|
||||||
|
|
||||||
// From the total height, remote the capsule half spheres that are at each end
|
// From the total height, remove the capsule half spheres that are at each end
|
||||||
newScale.Z = (size.Z * 2f) - Math.Min(newScale.X, newScale.Y);
|
newScale.Z = size.Z- (newScale.X + newScale.Y);
|
||||||
// newScale.Z = (size.Z * 2f);
|
|
||||||
Scale = newScale;
|
Scale = newScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -636,7 +645,7 @@ public class BSCharacter : BSPhysObject
|
||||||
BulletSimAPI.SetLinearVelocity2(BSBody.ptr, avVel);
|
BulletSimAPI.SetLinearVelocity2(BSBody.ptr, avVel);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tell the linkset about this
|
// Tell the linkset about value changes
|
||||||
Linkset.UpdateProperties(this);
|
Linkset.UpdateProperties(this);
|
||||||
|
|
||||||
// Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
|
// Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
|
||||||
|
|
|
@ -34,6 +34,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
|
|
||||||
public abstract class BSConstraint : IDisposable
|
public abstract class BSConstraint : IDisposable
|
||||||
{
|
{
|
||||||
|
private static string LogHeader = "[BULLETSIM CONSTRAINT]";
|
||||||
|
|
||||||
protected BulletSim m_world;
|
protected BulletSim m_world;
|
||||||
protected BulletBody m_body1;
|
protected BulletBody m_body1;
|
||||||
protected BulletBody m_body2;
|
protected BulletBody m_body2;
|
||||||
|
@ -124,7 +126,7 @@ public abstract class BSConstraint : IDisposable
|
||||||
}
|
}
|
||||||
else
|
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;
|
return ret;
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*
|
||||||
|
|
||||||
/* RA: June 14, 2011. Copied from ODEDynamics.cs and converted to
|
/* RA: June 14, 2011. Copied from ODEDynamics.cs and converted to
|
||||||
* call the BulletSim system.
|
* call the BulletSim system.
|
||||||
|
@ -464,8 +464,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
// Set the prim's inertia to zero. The vehicle code handles that and this
|
// Set the prim's inertia to zero. The vehicle code handles that and this
|
||||||
// removes the motion and torque actions introduced by Bullet.
|
// removes the motion and torque actions introduced by Bullet.
|
||||||
Vector3 inertia = Vector3.Zero;
|
Vector3 inertia = Vector3.Zero;
|
||||||
BulletSimAPI.SetMassProps2(Prim.BSBody.ptr, Prim.MassRaw, inertia);
|
// comment out for DEBUG test
|
||||||
BulletSimAPI.UpdateInertiaTensor2(Prim.BSBody.ptr);
|
// BulletSimAPI.SetMassProps2(Prim.BSBody.ptr, Prim.MassRaw, inertia);
|
||||||
|
// BulletSimAPI.UpdateInertiaTensor2(Prim.BSBody.ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// One step of the vehicle properties for the next 'pTimestep' seconds.
|
// One step of the vehicle properties for the next 'pTimestep' seconds.
|
||||||
|
|
|
@ -32,10 +32,27 @@ using OMV = OpenMetaverse;
|
||||||
|
|
||||||
namespace OpenSim.Region.Physics.BulletSPlugin
|
namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
{
|
{
|
||||||
public class BSLinkset
|
public abstract class BSLinkset
|
||||||
{
|
{
|
||||||
// private static string LogHeader = "[BULLETSIM LINKSET]";
|
// 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 BSPhysObject LinksetRoot { get; protected set; }
|
||||||
|
|
||||||
public BSScene PhysicsScene { get; private set; }
|
public BSScene PhysicsScene { get; private set; }
|
||||||
|
@ -52,16 +69,16 @@ public class BSLinkset
|
||||||
// the physical 'taint' children separately.
|
// the physical 'taint' children separately.
|
||||||
// After taint processing and before the simulation step, these
|
// After taint processing and before the simulation step, these
|
||||||
// two lists must be the same.
|
// two lists must be the same.
|
||||||
private HashSet<BSPhysObject> m_children;
|
protected HashSet<BSPhysObject> m_children;
|
||||||
private HashSet<BSPhysObject> m_taintChildren;
|
protected HashSet<BSPhysObject> m_taintChildren;
|
||||||
|
|
||||||
// We lock the diddling of linkset classes to prevent any badness.
|
// We lock the diddling of linkset classes to prevent any badness.
|
||||||
// This locks the modification of the instances of this class. Changes
|
// This locks the modification of the instances of this class. Changes
|
||||||
// to the physical representation is done via the tainting mechenism.
|
// 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
|
// 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
|
public float LinksetMass
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
@ -81,7 +98,7 @@ public class BSLinkset
|
||||||
get { return ComputeLinksetGeometricCenter(); }
|
get { return ComputeLinksetGeometricCenter(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public BSLinkset(BSScene scene, BSPhysObject parent)
|
protected void Initialize(BSScene scene, BSPhysObject parent)
|
||||||
{
|
{
|
||||||
// A simple linkset of one (no children)
|
// A simple linkset of one (no children)
|
||||||
LinksetID = m_nextLinksetID++;
|
LinksetID = m_nextLinksetID++;
|
||||||
|
@ -128,7 +145,7 @@ public class BSLinkset
|
||||||
}
|
}
|
||||||
|
|
||||||
// The child is down to a linkset of just itself
|
// 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
|
// Return 'true' if the passed object is the root object of this linkset
|
||||||
|
@ -148,6 +165,9 @@ public class BSLinkset
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
lock (m_linksetActivityLock)
|
lock (m_linksetActivityLock)
|
||||||
{
|
{
|
||||||
|
if (m_children.Contains(child))
|
||||||
|
ret = true;
|
||||||
|
/*
|
||||||
foreach (BSPhysObject bp in m_children)
|
foreach (BSPhysObject bp in m_children)
|
||||||
{
|
{
|
||||||
if (child.LocalID == bp.LocalID)
|
if (child.LocalID == bp.LocalID)
|
||||||
|
@ -156,6 +176,7 @@ public class BSLinkset
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -163,24 +184,7 @@ public class BSLinkset
|
||||||
// When physical properties are changed the linkset needs to recalculate
|
// When physical properties are changed the linkset needs to recalculate
|
||||||
// its internal properties.
|
// its internal properties.
|
||||||
// May be called at runtime or taint-time (just pass the appropriate flag).
|
// May be called at runtime or taint-time (just pass the appropriate flag).
|
||||||
public void Refresh(BSPhysObject requestor, bool inTaintTime)
|
public abstract void Refresh(BSPhysObject requestor, bool inTaintTime);
|
||||||
{
|
|
||||||
// If there are no children, not physical or not root, I am not the one that recomputes the constraints
|
|
||||||
// (For the moment, static linksets do create constraints so remove the test for physical.)
|
|
||||||
if (!HasAnyChildren || /*!requestor.IsPhysical ||*/ !IsRoot(requestor))
|
|
||||||
return;
|
|
||||||
|
|
||||||
BSScene.TaintCallback refreshOperation = delegate()
|
|
||||||
{
|
|
||||||
RecomputeLinksetConstraintVariables();
|
|
||||||
DetailLog("{0},BSLinkset.Refresh,complete,rBody={1}",
|
|
||||||
LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
|
|
||||||
};
|
|
||||||
if (inTaintTime)
|
|
||||||
refreshOperation();
|
|
||||||
else
|
|
||||||
PhysicsScene.TaintedObject("BSLinkSet.Refresh", refreshOperation);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The object is going dynamic (physical). Do any setup necessary
|
// The object is going dynamic (physical). Do any setup necessary
|
||||||
// for a dynamic linkset.
|
// for a dynamic linkset.
|
||||||
|
@ -188,102 +192,35 @@ public class BSLinkset
|
||||||
// has not yet been fully constructed.
|
// has not yet been fully constructed.
|
||||||
// Return 'true' if any properties updated on the passed object.
|
// Return 'true' if any properties updated on the passed object.
|
||||||
// Called at taint-time!
|
// Called at taint-time!
|
||||||
public bool MakeDynamic(BSPhysObject child)
|
public abstract 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
|
// The object is going static (non-physical). Do any setup necessary
|
||||||
// for a static linkset.
|
// for a static linkset.
|
||||||
// Return 'true' if any properties updated on the passed object.
|
// Return 'true' if any properties updated on the passed object.
|
||||||
// Called at taint-time!
|
// Called at taint-time!
|
||||||
public bool MakeStatic(BSPhysObject child)
|
public abstract bool MakeStatic(BSPhysObject child);
|
||||||
{
|
|
||||||
// What is done for each object in BSPrim is what we want.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the software is handling the movement of all the objects in a linkset
|
// Called when a parameter update comes from the physics engine for any object
|
||||||
// (like if one doesn't use constraints for static linksets), this is called
|
// of the linkset is received.
|
||||||
// when an update for the root of the linkset is received.
|
|
||||||
// Called at taint-time!!
|
// Called at taint-time!!
|
||||||
public void UpdateProperties(BSPhysObject physObject)
|
public abstract 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Routine used when rebuilding the body of the root of the linkset
|
// Routine used when rebuilding the body of the root of the linkset
|
||||||
// Destroy all the constraints have have been made to root.
|
// Destroy all the constraints have have been made to root.
|
||||||
// This is called when the root body is changing.
|
// 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!!
|
// Called at taint-time!!
|
||||||
public bool RemoveBodyDependencies(BSPrim child)
|
public abstract 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',
|
// 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!!
|
// Called at taint-time!!
|
||||||
public void RestoreBodyDependencies(BSPrim child)
|
public abstract 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
|
// Below this point is internal magic
|
||||||
|
|
||||||
private float ComputeLinksetMass()
|
protected virtual float ComputeLinksetMass()
|
||||||
{
|
{
|
||||||
float mass;
|
float mass;
|
||||||
lock (m_linksetActivityLock)
|
lock (m_linksetActivityLock)
|
||||||
|
@ -297,7 +234,7 @@ public class BSLinkset
|
||||||
return mass;
|
return mass;
|
||||||
}
|
}
|
||||||
|
|
||||||
private OMV.Vector3 ComputeLinksetCenterOfMass()
|
protected virtual OMV.Vector3 ComputeLinksetCenterOfMass()
|
||||||
{
|
{
|
||||||
OMV.Vector3 com;
|
OMV.Vector3 com;
|
||||||
lock (m_linksetActivityLock)
|
lock (m_linksetActivityLock)
|
||||||
|
@ -317,7 +254,7 @@ public class BSLinkset
|
||||||
return com;
|
return com;
|
||||||
}
|
}
|
||||||
|
|
||||||
private OMV.Vector3 ComputeLinksetGeometricCenter()
|
protected virtual OMV.Vector3 ComputeLinksetGeometricCenter()
|
||||||
{
|
{
|
||||||
OMV.Vector3 com;
|
OMV.Vector3 com;
|
||||||
lock (m_linksetActivityLock)
|
lock (m_linksetActivityLock)
|
||||||
|
@ -336,236 +273,21 @@ public class BSLinkset
|
||||||
|
|
||||||
// I am the root of a linkset and a new child is being added
|
// I am the root of a linkset and a new child is being added
|
||||||
// Called while LinkActivity is locked.
|
// Called while LinkActivity is locked.
|
||||||
private void AddChildToLinkset(BSPhysObject child)
|
protected abstract 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.
|
// 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
|
// 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.
|
// it's still connected to the linkset.
|
||||||
// Normal OpenSimulator operation will never do this because other SceneObjectPart information
|
// Normal OpenSimulator operation will never do this because other SceneObjectPart information
|
||||||
// also has to be updated (like pointer to prim's parent).
|
// also has to be updated (like pointer to prim's parent).
|
||||||
private void RemoveChildFromOtherLinkset(BSPhysObject pchild)
|
protected abstract void RemoveChildFromOtherLinkset(BSPhysObject pchild);
|
||||||
{
|
|
||||||
pchild.Linkset = new BSLinkset(PhysicsScene, pchild);
|
|
||||||
RemoveChildFromLinkset(pchild);
|
|
||||||
}
|
|
||||||
|
|
||||||
// I am the root of a linkset and one of my children is being removed.
|
// 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.
|
// Safe to call even if the child is not really in my linkset.
|
||||||
private void RemoveChildFromLinkset(BSPhysObject child)
|
protected abstract 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Invoke the detailed logger and output something if it's enabled.
|
// 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)
|
if (PhysicsScene.PhysicsLogging.Enabled)
|
||||||
PhysicsScene.DetailLog(msg, args);
|
PhysicsScene.DetailLog(msg, args);
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -46,7 +46,7 @@ public abstract class BSPhysObject : PhysicsActor
|
||||||
PhysObjectName = name;
|
PhysObjectName = name;
|
||||||
TypeName = typeName;
|
TypeName = typeName;
|
||||||
|
|
||||||
Linkset = new BSLinkset(PhysicsScene, this);
|
Linkset = BSLinkset.Factory(PhysicsScene, this);
|
||||||
LastAssetBuildFailed = false;
|
LastAssetBuildFailed = false;
|
||||||
|
|
||||||
CollisionCollection = new CollisionEventUpdate();
|
CollisionCollection = new CollisionEventUpdate();
|
||||||
|
|
|
@ -173,6 +173,7 @@ public sealed class BSPrim : BSPhysObject
|
||||||
}
|
}
|
||||||
public override bool ForceBodyShapeRebuild(bool inTaintTime)
|
public override bool ForceBodyShapeRebuild(bool inTaintTime)
|
||||||
{
|
{
|
||||||
|
LastAssetBuildFailed = false;
|
||||||
BSScene.TaintCallback rebuildOperation = delegate()
|
BSScene.TaintCallback rebuildOperation = delegate()
|
||||||
{
|
{
|
||||||
_mass = CalculateMass(); // changing the shape changes the mass
|
_mass = CalculateMass(); // changing the shape changes the mass
|
||||||
|
@ -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
|
// 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.
|
// Vehicle code changes the parameters for this vehicle type.
|
||||||
this._vehicle.ProcessTypeChange(type);
|
_vehicle.ProcessTypeChange(type);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1245,12 +1246,13 @@ public sealed class BSPrim : BSPhysObject
|
||||||
FillShapeInfo(out shapeData);
|
FillShapeInfo(out shapeData);
|
||||||
|
|
||||||
// If this prim is part of a linkset, we must remove and restore the physical
|
// 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;
|
bool needToRestoreLinkset = false;
|
||||||
|
|
||||||
// Create the correct physical representation for this type of object.
|
// Create the correct physical representation for this type of object.
|
||||||
// Updates BSBody and BSShape with the new information.
|
// Updates BSBody and BSShape with the new information.
|
||||||
// Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary.
|
// Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary.
|
||||||
|
// Returns 'true' if either the body or the shape was changed.
|
||||||
PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, shapeData, BaseShape,
|
PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, shapeData, BaseShape,
|
||||||
null, delegate(BulletBody dBody)
|
null, delegate(BulletBody dBody)
|
||||||
{
|
{
|
||||||
|
@ -1354,7 +1356,7 @@ public sealed class BSPrim : BSPhysObject
|
||||||
DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
|
DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
|
||||||
LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
|
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();
|
base.RequestPhysicsterseUpdate();
|
||||||
}
|
}
|
||||||
|
@ -1367,8 +1369,8 @@ public sealed class BSPrim : BSPhysObject
|
||||||
entprop.Acceleration, entprop.RotationalVelocity);
|
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);
|
Linkset.UpdateProperties(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -692,7 +692,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
{
|
{
|
||||||
if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process
|
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;
|
int taintCount = m_taintsToProcessPerStep;
|
||||||
TaintCallbackEntry oneCallback = new TaintCallbackEntry();
|
TaintCallbackEntry oneCallback = new TaintCallbackEntry();
|
||||||
while (_taintedObjects.Count > 0 && taintCount-- > 0)
|
while (_taintedObjects.Count > 0 && taintCount-- > 0)
|
||||||
|
@ -711,11 +710,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
{
|
{
|
||||||
try
|
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();
|
oneCallback.callback();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
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);
|
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.
|
// Add the Flush() if debugging crashes to get all the messages written out.
|
||||||
// PhysicsLogging.Flush();
|
// 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";
|
public const string DetailLogZero = "0000000000";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
{
|
{
|
||||||
public class BSShapeCollection : IDisposable
|
public class BSShapeCollection : IDisposable
|
||||||
{
|
{
|
||||||
// private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]";
|
private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]";
|
||||||
|
|
||||||
protected BSScene PhysicsScene { get; set; }
|
protected BSScene PhysicsScene { get; set; }
|
||||||
|
|
||||||
|
@ -338,6 +338,7 @@ public class BSShapeCollection : IDisposable
|
||||||
ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_AVATAR,
|
ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_AVATAR,
|
||||||
ShapeData.FixedShapeKey.KEY_CAPSULE, shapeCallback);
|
ShapeData.FixedShapeKey.KEY_CAPSULE, shapeCallback);
|
||||||
DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.BSShape);
|
DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.BSShape);
|
||||||
|
ret = true;
|
||||||
haveShape = true;
|
haveShape = true;
|
||||||
}
|
}
|
||||||
// If the prim attributes are simple, this could be a simple Bullet native shape
|
// If the prim attributes are simple, this could be a simple Bullet native shape
|
||||||
|
@ -411,15 +412,14 @@ public class BSShapeCollection : IDisposable
|
||||||
ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey,
|
ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey,
|
||||||
ShapeDestructionCallback shapeCallback)
|
ShapeDestructionCallback shapeCallback)
|
||||||
{
|
{
|
||||||
|
// release any previous shape
|
||||||
|
DereferenceShape(prim.BSShape, true, shapeCallback);
|
||||||
|
|
||||||
shapeData.Type = shapeType;
|
shapeData.Type = shapeType;
|
||||||
// Bullet native objects are scaled by the Bullet engine so pass the size in
|
// Bullet native objects are scaled by the Bullet engine so pass the size in
|
||||||
prim.Scale = shapeData.Size;
|
prim.Scale = shapeData.Size;
|
||||||
shapeData.Scale = shapeData.Size;
|
shapeData.Scale = shapeData.Size;
|
||||||
|
|
||||||
// release any previous shape
|
|
||||||
DereferenceShape(prim.BSShape, true, shapeCallback);
|
|
||||||
|
|
||||||
BulletShape newShape = BuildPhysicalNativeShape(shapeType, shapeData, shapeKey);
|
BulletShape newShape = BuildPhysicalNativeShape(shapeType, shapeData, shapeKey);
|
||||||
|
|
||||||
// Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
|
// Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
|
||||||
|
@ -434,16 +434,27 @@ public class BSShapeCollection : IDisposable
|
||||||
ShapeData shapeData, ShapeData.FixedShapeKey shapeKey)
|
ShapeData shapeData, ShapeData.FixedShapeKey shapeKey)
|
||||||
{
|
{
|
||||||
BulletShape newShape;
|
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)
|
if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR)
|
||||||
{
|
{
|
||||||
newShape = new BulletShape(
|
newShape = new BulletShape(
|
||||||
BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1.0f, 1.0f, shapeData.Scale),
|
BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, nativeShapeData.Scale)
|
||||||
shapeType);
|
, shapeType);
|
||||||
|
DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", nativeShapeData.ID, nativeShapeData.Scale);
|
||||||
}
|
}
|
||||||
else
|
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.shapeKey = (System.UInt64)shapeKey;
|
||||||
newShape.isNativeShape = true;
|
newShape.isNativeShape = true;
|
||||||
|
@ -698,19 +709,26 @@ public class BSShapeCollection : IDisposable
|
||||||
return ComputeShapeKey(shapeData, pbs, out lod);
|
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)
|
private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs)
|
||||||
{
|
{
|
||||||
// If the shape was successfully created, nothing more to do
|
// If the shape was successfully created, nothing more to do
|
||||||
if (newShape.ptr != IntPtr.Zero)
|
if (newShape.ptr != IntPtr.Zero)
|
||||||
return newShape;
|
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 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)
|
if (pbs.SculptEntry && !prim.LastAssetBuildFailed && pbs.SculptTexture != OMV.UUID.Zero)
|
||||||
{
|
{
|
||||||
prim.LastAssetBuildFailed = true;
|
prim.LastAssetBuildFailed = true;
|
||||||
BSPhysObject xprim = prim;
|
BSPhysObject xprim = prim;
|
||||||
|
DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lID={1},lastFailed={2}",
|
||||||
|
LogHeader, shapeData.ID.ToString("X"), prim.LastAssetBuildFailed);
|
||||||
Util.FireAndForget(delegate
|
Util.FireAndForget(delegate
|
||||||
{
|
{
|
||||||
RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
|
RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
|
||||||
|
@ -724,20 +742,28 @@ public class BSShapeCollection : IDisposable
|
||||||
if (yprim.BaseShape.SculptTexture.ToString() != asset.ID)
|
if (yprim.BaseShape.SculptTexture.ToString() != asset.ID)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
yprim.BaseShape.SculptData = new byte[asset.Data.Length];
|
yprim.BaseShape.SculptData = asset.Data;
|
||||||
asset.Data.CopyTo(yprim.BaseShape.SculptData, 0);
|
|
||||||
// This will cause the prim to see that the filler shape is not the right
|
// This will cause the prim to see that the filler shape is not the right
|
||||||
// one and try again to build the object.
|
// 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);
|
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.
|
// While we figure out the real problem, stick a simple native shape on the object.
|
||||||
BulletShape fillinShape =
|
BulletShape fillinShape =
|
||||||
BuildPhysicalNativeShape(ShapeData.PhysicsShapeType.SHAPE_SPHERE, shapeData, ShapeData.FixedShapeKey.KEY_SPHERE);
|
BuildPhysicalNativeShape(ShapeData.PhysicsShapeType.SHAPE_BOX, shapeData, ShapeData.FixedShapeKey.KEY_BOX);
|
||||||
|
|
||||||
return fillinShape;
|
return fillinShape;
|
||||||
}
|
}
|
||||||
|
@ -765,7 +791,6 @@ public class BSShapeCollection : IDisposable
|
||||||
// If the collisionObject is not the correct type for solidness, rebuild what's there
|
// If the collisionObject is not the correct type for solidness, rebuild what's there
|
||||||
mustRebuild = true;
|
mustRebuild = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mustRebuild || forceRebuild)
|
if (mustRebuild || forceRebuild)
|
||||||
|
|
|
@ -201,9 +201,7 @@ public class BSTerrainManager
|
||||||
// If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new
|
// 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.
|
// terrain shape is created and added to the body.
|
||||||
// This call is most often used to update the heightMap and parameters of the terrain.
|
// 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
|
// (The above does suggest that some simplification/refactoring is in order.)
|
||||||
// calling this routine from initialization or taint-time routines) or whether to delay
|
|
||||||
// all the unmanaged activities to taint-time.
|
|
||||||
private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
|
private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},inTaintTime={3}",
|
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.
|
// Make sure the new shape is processed.
|
||||||
// BulletSimAPI.Activate2(mapInfo.terrainBody.ptr, true);
|
// BulletSimAPI.Activate2(mapInfo.terrainBody.ptr, true);
|
||||||
BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.ISLAND_SLEEPING);
|
// BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.ISLAND_SLEEPING);
|
||||||
// BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
|
BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
|
||||||
|
|
||||||
m_terrainModified = true;
|
m_terrainModified = true;
|
||||||
};
|
};
|
||||||
|
|
|
@ -719,21 +719,21 @@ namespace OpenSim.Region.RegionCombinerModule
|
||||||
rootConn.ClientEventForwarder = new RegionCombinerClientEventForwarder(rootConn);
|
rootConn.ClientEventForwarder = new RegionCombinerClientEventForwarder(rootConn);
|
||||||
|
|
||||||
// Sets up the CoarseLocationUpdate forwarder for this root region
|
// 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
|
// Adds this root region to a dictionary of regions that are connectable
|
||||||
m_regions.Add(scene.RegionInfo.originRegionID, rootConn);
|
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 delegate was refactored for non-combined regions.
|
||||||
// This combined region version will not use the pre-compiled lists of locations and ids
|
// This combined region version will not use the pre-compiled lists of locations and ids
|
||||||
private void SendCourseLocationUpdates(UUID sceneId, ScenePresence presence, List<Vector3> coarseLocations, List<UUID> avatarUUIDs)
|
private void SendCoarseLocationUpdates(UUID sceneId, ScenePresence presence, List<Vector3> coarseLocations, List<UUID> avatarUUIDs)
|
||||||
{
|
{
|
||||||
RegionConnections connectiondata = null;
|
RegionConnections connectiondata = null;
|
||||||
lock (m_regions)
|
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<Vector3> locations, List<UUID> uuids,
|
private void DistributeCoarseLocationUpdates(List<Vector3> locations, List<UUID> uuids,
|
||||||
RegionConnections connectiondata, ScenePresence rootPresence)
|
RegionConnections connectiondata, ScenePresence rootPresence)
|
||||||
{
|
{
|
||||||
RegionData[] rdata = connectiondata.ConnectedRegions.ToArray();
|
RegionData[] rdata = connectiondata.ConnectedRegions.ToArray();
|
||||||
//List<IClientAPI> clients = new List<IClientAPI>();
|
//List<IClientAPI> clients = new List<IClientAPI>();
|
||||||
Dictionary<Vector2, RegionCourseLocationStruct> updates = new Dictionary<Vector2, RegionCourseLocationStruct>();
|
Dictionary<Vector2, RegionCoarseLocationStruct> updates = new Dictionary<Vector2, RegionCoarseLocationStruct>();
|
||||||
|
|
||||||
// Root Region entry
|
// Root Region entry
|
||||||
RegionCourseLocationStruct rootupdatedata = new RegionCourseLocationStruct();
|
RegionCoarseLocationStruct rootupdatedata = new RegionCoarseLocationStruct();
|
||||||
rootupdatedata.Locations = new List<Vector3>();
|
rootupdatedata.Locations = new List<Vector3>();
|
||||||
rootupdatedata.Uuids = new List<UUID>();
|
rootupdatedata.Uuids = new List<UUID>();
|
||||||
rootupdatedata.Offset = Vector2.Zero;
|
rootupdatedata.Offset = Vector2.Zero;
|
||||||
|
@ -781,7 +781,7 @@ namespace OpenSim.Region.RegionCombinerModule
|
||||||
foreach (RegionData regiondata in rdata)
|
foreach (RegionData regiondata in rdata)
|
||||||
{
|
{
|
||||||
Vector2 offset = new Vector2(regiondata.Offset.X, regiondata.Offset.Y);
|
Vector2 offset = new Vector2(regiondata.Offset.X, regiondata.Offset.Y);
|
||||||
RegionCourseLocationStruct updatedata = new RegionCourseLocationStruct();
|
RegionCoarseLocationStruct updatedata = new RegionCoarseLocationStruct();
|
||||||
updatedata.Locations = new List<Vector3>();
|
updatedata.Locations = new List<Vector3>();
|
||||||
updatedata.Uuids = new List<UUID>();
|
updatedata.Uuids = new List<UUID>();
|
||||||
updatedata.Offset = offset;
|
updatedata.Offset = offset;
|
||||||
|
@ -807,7 +807,7 @@ namespace OpenSim.Region.RegionCombinerModule
|
||||||
if (!updates.ContainsKey(offset))
|
if (!updates.ContainsKey(offset))
|
||||||
{
|
{
|
||||||
// This shouldn't happen
|
// This shouldn't happen
|
||||||
RegionCourseLocationStruct updatedata = new RegionCourseLocationStruct();
|
RegionCoarseLocationStruct updatedata = new RegionCoarseLocationStruct();
|
||||||
updatedata.Locations = new List<Vector3>();
|
updatedata.Locations = new List<Vector3>();
|
||||||
updatedata.Uuids = new List<UUID>();
|
updatedata.Uuids = new List<UUID>();
|
||||||
updatedata.Offset = offset;
|
updatedata.Offset = offset;
|
||||||
|
|
|
@ -33,7 +33,7 @@ using OpenSim.Framework;
|
||||||
namespace OpenSim.Region.RegionCombinerModule
|
namespace OpenSim.Region.RegionCombinerModule
|
||||||
{
|
{
|
||||||
|
|
||||||
struct RegionCourseLocationStruct
|
struct RegionCoarseLocationStruct
|
||||||
{
|
{
|
||||||
public List<Vector3> Locations;
|
public List<Vector3> Locations;
|
||||||
public List<UUID> Uuids;
|
public List<UUID> Uuids;
|
||||||
|
|
|
@ -4388,7 +4388,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
{
|
{
|
||||||
AnimationSet currentAnims = presence.Animator.Animations;
|
AnimationSet currentAnims = presence.Animator.Animations;
|
||||||
string currentAnimationState = String.Empty;
|
string currentAnimationState = String.Empty;
|
||||||
if (animationstateNames.TryGetValue(currentAnims.DefaultAnimation.AnimID, out currentAnimationState))
|
if (animationstateNames.TryGetValue(currentAnims.ImplicitDefaultAnimation.AnimID, out currentAnimationState))
|
||||||
return currentAnimationState;
|
return currentAnimationState;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5705,7 +5705,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
flags |= ScriptBaseClass.AGENT_SITTING;
|
flags |= ScriptBaseClass.AGENT_SITTING;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (agent.Animator.Animations.DefaultAnimation.AnimID
|
if (agent.Animator.Animations.ImplicitDefaultAnimation.AnimID
|
||||||
== DefaultAvatarAnimations.AnimsUUID["SIT_GROUND_CONSTRAINED"])
|
== DefaultAvatarAnimations.AnimsUUID["SIT_GROUND_CONSTRAINED"])
|
||||||
{
|
{
|
||||||
flags |= ScriptBaseClass.AGENT_SITTING;
|
flags |= ScriptBaseClass.AGENT_SITTING;
|
||||||
|
@ -7892,7 +7892,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
{
|
{
|
||||||
LSL_Vector lower;
|
LSL_Vector lower;
|
||||||
LSL_Vector upper;
|
LSL_Vector upper;
|
||||||
if (presence.Animator.Animations.DefaultAnimation.AnimID
|
if (presence.Animator.Animations.ImplicitDefaultAnimation.AnimID
|
||||||
== DefaultAvatarAnimations.AnimsUUID["SIT_GROUND_CONSTRAINED"])
|
== DefaultAvatarAnimations.AnimsUUID["SIT_GROUND_CONSTRAINED"])
|
||||||
{
|
{
|
||||||
// This is for ground sitting avatars
|
// This is for ground sitting avatars
|
||||||
|
@ -10685,12 +10685,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
|
|
||||||
internal void Deprecated(string command)
|
internal void Deprecated(string command)
|
||||||
{
|
{
|
||||||
throw new Exception("Command deprecated: " + command);
|
throw new ScriptException("Command deprecated: " + command);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void LSLError(string msg)
|
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);
|
public delegate void AssetRequestCallback(UUID assetID, AssetBase asset);
|
||||||
|
|
|
@ -95,13 +95,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
|
|
||||||
internal void MODError(string msg)
|
internal void MODError(string msg)
|
||||||
{
|
{
|
||||||
throw new Exception("MOD Runtime Error: " + msg);
|
throw new ScriptException("MOD Runtime Error: " + msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
/// <summary>
|
||||||
//Dumps an error message on the debug console.
|
/// Dumps an error message on the debug console.
|
||||||
//
|
/// </summary>
|
||||||
|
/// <param name='message'></param>
|
||||||
internal void MODShoutError(string message)
|
internal void MODShoutError(string message)
|
||||||
{
|
{
|
||||||
if (message.Length > 1023)
|
if (message.Length > 1023)
|
||||||
|
@ -359,20 +359,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
result[i] = (string)(LSL_String)plist[i];
|
result[i] = (string)(LSL_String)plist[i];
|
||||||
else if (plist[i] is LSL_Integer)
|
else if (plist[i] is LSL_Integer)
|
||||||
result[i] = (int)(LSL_Integer)plist[i];
|
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)
|
else if (plist[i] is LSL_Float)
|
||||||
result[i] = (float)(LSL_Float)plist[i];
|
result[i] = (float)(LSL_Float)plist[i];
|
||||||
else if (plist[i] is LSL_Key)
|
else if (plist[i] is LSL_Key)
|
||||||
result[i] = new UUID((LSL_Key)plist[i]);
|
result[i] = new UUID((LSL_Key)plist[i]);
|
||||||
else if (plist[i] is LSL_Rotation)
|
else if (plist[i] is LSL_Rotation)
|
||||||
{
|
result[i] = (Quaternion)((LSL_Rotation)plist[i]);
|
||||||
result[i] = (OpenMetaverse.Quaternion)(
|
|
||||||
(LSL_Rotation)plist[i]);
|
|
||||||
}
|
|
||||||
else if (plist[i] is LSL_Vector)
|
else if (plist[i] is LSL_Vector)
|
||||||
{
|
result[i] = (Vector3)((LSL_Vector)plist[i]);
|
||||||
result[i] = (OpenMetaverse.Vector3)(
|
|
||||||
(LSL_Vector)plist[i]);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
MODError(String.Format("{0}: unknown LSL list element type", fname));
|
MODError(String.Format("{0}: unknown LSL list element type", fname));
|
||||||
}
|
}
|
||||||
|
|
|
@ -210,7 +210,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
|
|
||||||
internal void OSSLError(string msg)
|
internal void OSSLError(string msg)
|
||||||
{
|
{
|
||||||
throw new Exception("OSSL Runtime Error: " + msg);
|
throw new ScriptException("OSSL Runtime Error: " + msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1780,18 +1780,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
protected string LoadNotecard(string notecardNameOrUuid)
|
protected string LoadNotecard(string notecardNameOrUuid)
|
||||||
{
|
{
|
||||||
UUID assetID = CacheNotecard(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";
|
StringBuilder notecardData = new StringBuilder();
|
||||||
|
|
||||||
// m_log.DebugFormat("[OSSL]: From notecard {0} loading line {1}", notecardNameOrUuid, line);
|
for (int count = 0; count < NotecardCache.GetLines(assetID); count++)
|
||||||
|
{
|
||||||
|
string line = NotecardCache.GetLine(assetID, count) + "\n";
|
||||||
|
|
||||||
notecardData.Append(line);
|
// m_log.DebugFormat("[OSSL]: From notecard {0} loading line {1}", notecardNameOrUuid, line);
|
||||||
|
|
||||||
|
notecardData.Append(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
return notecardData.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
return notecardData.ToString();
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -2340,11 +2346,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
appearance = new AvatarAppearance();
|
appearance = new AvatarAppearance();
|
||||||
appearance.Unpack(appearanceOsd);
|
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;
|
UUID ownerID = UUID.Zero;
|
||||||
if (owned)
|
if (owned)
|
||||||
ownerID = m_host.OwnerID;
|
ownerID = m_host.OwnerID;
|
||||||
|
@ -2407,6 +2414,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
return;
|
return;
|
||||||
|
|
||||||
string appearanceSerialized = LoadNotecard(notecard);
|
string appearanceSerialized = LoadNotecard(notecard);
|
||||||
|
|
||||||
|
if (appearanceSerialized == null)
|
||||||
|
OSSLError(string.Format("osNpcCreate: Notecard reference '{0}' not found.", notecard));
|
||||||
|
|
||||||
OSDMap appearanceOsd = (OSDMap)OSDParser.DeserializeLLSDXml(appearanceSerialized);
|
OSDMap appearanceOsd = (OSDMap)OSDParser.DeserializeLLSDXml(appearanceSerialized);
|
||||||
// OSD a = OSDParser.DeserializeLLSDXml(appearanceSerialized);
|
// OSD a = OSDParser.DeserializeLLSDXml(appearanceSerialized);
|
||||||
// Console.WriteLine("appearanceSerialized {0}", appearanceSerialized);
|
// Console.WriteLine("appearanceSerialized {0}", appearanceSerialized);
|
||||||
|
@ -3636,5 +3647,68 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
|
|
||||||
DropAttachmentAt(false, pos, rot);
|
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<IWorldComm>();
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -418,5 +418,29 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
|
||||||
/// <param name="pos"></param>
|
/// <param name="pos"></param>
|
||||||
/// <param name="rot"></param>
|
/// <param name="rot"></param>
|
||||||
void osForceDropAttachmentAt(vector pos, rotation rot);
|
void osForceDropAttachmentAt(vector pos, rotation rot);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Identical to llListen except for a bitfield which indicates which
|
||||||
|
/// string parameters should be parsed as regex patterns.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="channelID"></param>
|
||||||
|
/// <param name="name"></param>
|
||||||
|
/// <param name="ID"></param>
|
||||||
|
/// <param name="msg"></param>
|
||||||
|
/// <param name="regexBitfield">
|
||||||
|
/// OS_LISTEN_REGEX_NAME
|
||||||
|
/// OS_LISTEN_REGEX_MESSAGE
|
||||||
|
/// </param>
|
||||||
|
/// <returns></returns>
|
||||||
|
LSL_Integer osListenRegex(int channelID, string name, string ID,
|
||||||
|
string msg, int regexBitfield);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Wraps to bool Regex.IsMatch(string input, string pattern)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input">string to test for match</param>
|
||||||
|
/// <param name="regex">string to use as pattern</param>
|
||||||
|
/// <returns>boolean</returns>
|
||||||
|
LSL_Integer osRegexIsMatch(string input, string pattern);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -716,5 +716,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
|
||||||
public static readonly LSLInteger RCERR_UNKNOWN = -1;
|
public static readonly LSLInteger RCERR_UNKNOWN = -1;
|
||||||
public static readonly LSLInteger RCERR_SIM_PERF_LOW = -2;
|
public static readonly LSLInteger RCERR_SIM_PERF_LOW = -2;
|
||||||
public static readonly LSLInteger RCERR_CAST_TIME_EXCEEDED = 3;
|
public static readonly LSLInteger RCERR_CAST_TIME_EXCEEDED = 3;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// process name parameter as regex
|
||||||
|
/// </summary>
|
||||||
|
public const int OS_LISTEN_REGEX_NAME = 0x1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// process message parameter as regex
|
||||||
|
/// </summary>
|
||||||
|
public const int OS_LISTEN_REGEX_MESSAGE = 0x2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -992,5 +992,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
|
||||||
{
|
{
|
||||||
m_OSSL_Functions.osForceDropAttachmentAt(pos, rot);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {}
|
||||||
|
}
|
||||||
|
}
|
|
@ -75,76 +75,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
|
||||||
m_engine.AddRegion(m_scene);
|
m_engine.AddRegion(m_scene);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Test creation of an NPC where the appearance data comes from a notecard
|
|
||||||
/// </summary>
|
|
||||||
[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));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Test creation of an NPC where the appearance data comes from an avatar already in the region.
|
|
||||||
/// </summary>
|
|
||||||
[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]
|
[Test]
|
||||||
public void TestOsOwnerSaveAppearance()
|
public void TestOsOwnerSaveAppearance()
|
||||||
{
|
{
|
||||||
|
|
|
@ -36,6 +36,7 @@ using OpenMetaverse;
|
||||||
using OpenMetaverse.Assets;
|
using OpenMetaverse.Assets;
|
||||||
using OpenMetaverse.StructuredData;
|
using OpenMetaverse.StructuredData;
|
||||||
using OpenSim.Framework;
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Region.CoreModules.Avatar.Attachments;
|
||||||
using OpenSim.Region.CoreModules.Avatar.AvatarFactory;
|
using OpenSim.Region.CoreModules.Avatar.AvatarFactory;
|
||||||
using OpenSim.Region.OptionalModules.World.NPC;
|
using OpenSim.Region.OptionalModules.World.NPC;
|
||||||
using OpenSim.Region.Framework.Scenes;
|
using OpenSim.Region.Framework.Scenes;
|
||||||
|
@ -71,13 +72,193 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
|
||||||
config.Set("Enabled", "true");
|
config.Set("Enabled", "true");
|
||||||
|
|
||||||
m_scene = new SceneHelpers().SetupScene();
|
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 = new XEngine.XEngine();
|
||||||
m_engine.Initialise(initConfigSource);
|
m_engine.Initialise(initConfigSource);
|
||||||
m_engine.AddRegion(m_scene);
|
m_engine.AddRegion(m_scene);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test creation of an NPC where the appearance data comes from a notecard
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test creation of an NPC where the appearance data comes from an avatar already in the region.
|
||||||
|
/// </summary>
|
||||||
|
[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));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test removal of an owned NPC.
|
/// Test removal of an owned NPC.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -85,7 +266,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
|
||||||
public void TestOsNpcRemoveOwned()
|
public void TestOsNpcRemoveOwned()
|
||||||
{
|
{
|
||||||
TestHelpers.InMethod();
|
TestHelpers.InMethod();
|
||||||
// log4net.Config.XmlConfigurator.Configure();
|
|
||||||
|
|
||||||
// Store an avatar with a different height from default in a notecard.
|
// Store an avatar with a different height from default in a notecard.
|
||||||
UUID userId = TestHelpers.ParseTail(0x1);
|
UUID userId = TestHelpers.ParseTail(0x1);
|
||||||
|
|
|
@ -142,6 +142,9 @@ namespace OpenSim.Server.Handlers.Asset
|
||||||
|
|
||||||
string fileName = rawAssetId;
|
string fileName = rawAssetId;
|
||||||
|
|
||||||
|
if (!ConsoleUtil.CheckFileDoesNotExist(MainConsole.Instance, fileName))
|
||||||
|
return;
|
||||||
|
|
||||||
using (FileStream fs = new FileStream(fileName, FileMode.CreateNew))
|
using (FileStream fs = new FileStream(fileName, FileMode.CreateNew))
|
||||||
{
|
{
|
||||||
using (BinaryWriter bw = new BinaryWriter(fs))
|
using (BinaryWriter bw = new BinaryWriter(fs))
|
||||||
|
|
|
@ -528,13 +528,9 @@ namespace OpenSim.Tests.Common.Mock
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void SendChatMessage(string message, byte type, Vector3 fromPos, string fromName,
|
public virtual void SendChatMessage(
|
||||||
UUID fromAgentID, byte source, byte audible)
|
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)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -303,37 +303,37 @@
|
||||||
<Key Name="fileName" Value="snd_TerrainStone.ogg" />
|
<Key Name="fileName" Value="snd_TerrainStone.ogg" />
|
||||||
</Section>
|
</Section>
|
||||||
<Section Name="snd_TerrainMetal">
|
<Section Name="snd_TerrainMetal">
|
||||||
<Key Name="assetID" Value="be7295c0-a158-11e1-b3dd-0807200c9a66" />
|
<Key Name="assetID" Value="be7295c0-a158-11e1-b3dd-0807201c9a66" />
|
||||||
<Key Name="name" Value="snd_TerrainMetal" />
|
<Key Name="name" Value="snd_TerrainMetal" />
|
||||||
<Key Name="assetType" Value="1" />
|
<Key Name="assetType" Value="1" />
|
||||||
<Key Name="fileName" Value="snd_TerrainMetal.ogg" />
|
<Key Name="fileName" Value="snd_TerrainMetal.ogg" />
|
||||||
</Section>
|
</Section>
|
||||||
<Section Name="snd_TerrainGlass">
|
<Section Name="snd_TerrainGlass">
|
||||||
<Key Name="assetID" Value="be7295c0-a158-11e1-b3dd-0807200c9a66" />
|
<Key Name="assetID" Value="be7295c0-a158-11e1-b3dd-0807202c9a66" />
|
||||||
<Key Name="name" Value="snd_TerrainGlass" />
|
<Key Name="name" Value="snd_TerrainGlass" />
|
||||||
<Key Name="assetType" Value="1" />
|
<Key Name="assetType" Value="1" />
|
||||||
<Key Name="fileName" Value="snd_TerrainGlass.ogg" />
|
<Key Name="fileName" Value="snd_TerrainGlass.ogg" />
|
||||||
</Section>
|
</Section>
|
||||||
<Section Name="snd_TerrainWood">
|
<Section Name="snd_TerrainWood">
|
||||||
<Key Name="assetID" Value="be7295c0-a158-11e1-b3dd-0807200c9a66" />
|
<Key Name="assetID" Value="be7295c0-a158-11e1-b3dd-0807203c9a66" />
|
||||||
<Key Name="name" Value="snd_TerrainWood" />
|
<Key Name="name" Value="snd_TerrainWood" />
|
||||||
<Key Name="assetType" Value="1" />
|
<Key Name="assetType" Value="1" />
|
||||||
<Key Name="fileName" Value="snd_TerrainWood.ogg" />
|
<Key Name="fileName" Value="snd_TerrainWood.ogg" />
|
||||||
</Section>
|
</Section>
|
||||||
<Section Name="snd_TerrainFlesh">
|
<Section Name="snd_TerrainFlesh">
|
||||||
<Key Name="assetID" Value="be7295c0-a158-11e1-b3dd-0807200c9a66" />
|
<Key Name="assetID" Value="be7295c0-a158-11e1-b3dd-0807204c9a66" />
|
||||||
<Key Name="name" Value="snd_TerrainFlesh" />
|
<Key Name="name" Value="snd_TerrainFlesh" />
|
||||||
<Key Name="assetType" Value="1" />
|
<Key Name="assetType" Value="1" />
|
||||||
<Key Name="fileName" Value="snd_TerrainFlesh.ogg" />
|
<Key Name="fileName" Value="snd_TerrainFlesh.ogg" />
|
||||||
</Section>
|
</Section>
|
||||||
<Section Name="snd_TerrainPlastic">
|
<Section Name="snd_TerrainPlastic">
|
||||||
<Key Name="assetID" Value="be7295c0-a158-11e1-b3dd-0807200c9a66" />
|
<Key Name="assetID" Value="be7295c0-a158-11e1-b3dd-0807205c9a66" />
|
||||||
<Key Name="name" Value="snd_TerrainPlastic" />
|
<Key Name="name" Value="snd_TerrainPlastic" />
|
||||||
<Key Name="assetType" Value="1" />
|
<Key Name="assetType" Value="1" />
|
||||||
<Key Name="fileName" Value="snd_TerrainPlastic.ogg" />
|
<Key Name="fileName" Value="snd_TerrainPlastic.ogg" />
|
||||||
</Section>
|
</Section>
|
||||||
<Section Name="snd_TerrainRubber">
|
<Section Name="snd_TerrainRubber">
|
||||||
<Key Name="assetID" Value="be7295c0-a158-11e1-b3dd-0807200c9a66" />
|
<Key Name="assetID" Value="be7295c0-a158-11e1-b3dd-0807206c9a66" />
|
||||||
<Key Name="name" Value="snd_TerrainRubber" />
|
<Key Name="name" Value="snd_TerrainRubber" />
|
||||||
<Key Name="assetType" Value="1" />
|
<Key Name="assetType" Value="1" />
|
||||||
<Key Name="fileName" Value="snd_TerrainRubber.ogg" />
|
<Key Name="fileName" Value="snd_TerrainRubber.ogg" />
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue