diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index a16d17421d..fd00fe8288 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -16,7 +16,7 @@ people that make the day to day of OpenSim happen. * BlueWall (James Hughes) * Nebadon Izumi (Michael Cerquoni, OSgrid) * Snoopy Pfeffer -* Richard Adams (Intel) +* Robert Adams (Intel) = Core Developers Following the White Rabbit = Core developers who have temporarily (we hope) gone chasing the white rabbit. diff --git a/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs b/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs index cdd7cc711e..8ac9090b06 100644 --- a/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs +++ b/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs @@ -355,10 +355,19 @@ Asset service request failures: {3}" + Environment.NewLine, sb.Append(Environment.NewLine); sb.Append( string.Format( - "{0,6:0} {1,6:0} {2,6:0} {3,6:0} {4,6:0} {5,6:0.0} {6,6:0.0} {7,6:0.0} {8,6:0.0} {9,6:0.0} {10,6:0.0}", + "{0,6:0} {1,6:0} {2,6:0} {3,6:0} {4,6:0} {5,6:0.0} {6,6:0.0} {7,6:0.0} {8,6:0.0} {9,6:0.0} {10,6:0.0}\n\n", inPacketsPerSecond, outPacketsPerSecond, pendingDownloads, pendingUploads, unackedBytes, totalFrameTime, netFrameTime, physicsFrameTime, otherFrameTime, agentFrameTime, imageFrameTime)); - sb.Append(Environment.NewLine); + + foreach (KeyValuePair kvp in StatsManager.RegisteredStats) + { + Stat stat = kvp.Value; + + if (stat.Category == "scene" && stat.Verbosity == StatVerbosity.Info) + { + sb.AppendFormat("Slow frames ({0}): {1}\n", stat.Container, stat.Value); + } + } /* sb.Append(Environment.NewLine); diff --git a/OpenSim/Framework/Monitoring/StatsManager.cs b/OpenSim/Framework/Monitoring/StatsManager.cs index d78fa6a1f0..b5dc24f4ae 100644 --- a/OpenSim/Framework/Monitoring/StatsManager.cs +++ b/OpenSim/Framework/Monitoring/StatsManager.cs @@ -25,6 +25,9 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +using System; +using System.Collections.Generic; + namespace OpenSim.Framework.Monitoring { /// @@ -32,6 +35,14 @@ namespace OpenSim.Framework.Monitoring /// public class StatsManager { + /// + /// Registered stats. + /// + /// + /// Do not add or remove from this dictionary. + /// + public static Dictionary RegisteredStats = new Dictionary(); + private static AssetStatsCollector assetStats; private static UserStatsCollector userStats; private static SimExtraStatsCollector simExtraStats = new SimExtraStatsCollector(); @@ -61,5 +72,139 @@ namespace OpenSim.Framework.Monitoring return userStats; } + + public static bool RegisterStat(Stat stat) + { + lock (RegisteredStats) + { + if (RegisteredStats.ContainsKey(stat.UniqueName)) + { + // XXX: For now just return false. This is to avoid problems in regression tests where all tests + // in a class are run in the same instance of the VM. + return false; + +// throw new Exception( +// "StatsManager already contains stat with ShortName {0} in Category {1}", stat.ShortName, stat.Category); + } + + // We take a replace-on-write approach here so that we don't need to generate a new Dictionary + Dictionary newRegisteredStats = new Dictionary(RegisteredStats); + newRegisteredStats[stat.UniqueName] = stat; + RegisteredStats = newRegisteredStats; + } + + return true; + } + + public static bool DeregisterStat(Stat stat) + { + lock (RegisteredStats) + { + if (!RegisteredStats.ContainsKey(stat.UniqueName)) + return false; + + Dictionary newRegisteredStats = new Dictionary(RegisteredStats); + newRegisteredStats.Remove(stat.UniqueName); + RegisteredStats = newRegisteredStats; + + return true; + } + } + } + + /// + /// Verbosity of stat. + /// + /// + /// Info will always be displayed. + /// + public enum StatVerbosity + { + Debug, + Info + } + + /// + /// Holds individual static details + /// + public class Stat + { + /// + /// Unique stat name used for indexing. Each ShortName in a Category must be unique. + /// + public string UniqueName { get; private set; } + + /// + /// Category of this stat (e.g. cache, scene, etc). + /// + public string Category { get; private set; } + + /// + /// Containing name for this stat. + /// FIXME: In the case of a scene, this is currently the scene name (though this leaves + /// us with a to-be-resolved problem of non-unique region names). + /// + /// + /// The container. + /// + public string Container { get; private set; } + + public StatVerbosity Verbosity { get; private set; } + public string ShortName { get; private set; } + public string Name { get; private set; } + public string Description { get; private set; } + public virtual string UnitName { get; private set; } + + public virtual double Value { get; set; } + + public Stat( + string shortName, string name, string unitName, string category, string container, StatVerbosity verbosity, string description) + { + ShortName = shortName; + Name = name; + UnitName = unitName; + Category = category; + Container = container; + 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 class PercentageStat : Stat + { + public int Antecedent { get; set; } + public int Consequent { get; set; } + + public override double Value + { + get + { + int c = Consequent; + + // Avoid any chance of a multi-threaded divide-by-zero + if (c == 0) + return 0; + + return (double)Antecedent / c; + } + + set + { + throw new Exception("Cannot set value on a PercentageStat"); + } + } + + public PercentageStat( + string shortName, string name, string category, string container, StatVerbosity verbosity, string description) + : base(shortName, name, " %", category, container, verbosity, description) + { + } } } \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index 130c869bc7..2a513e91d8 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -406,6 +406,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments } public void DetachSingleAttachmentToGround(IScenePresence sp, uint soLocalId) + { + DetachSingleAttachmentToGround(sp, soLocalId, sp.AbsolutePosition, Quaternion.Identity); + } + + public void DetachSingleAttachmentToGround(IScenePresence sp, uint soLocalId, Vector3 absolutePos, Quaternion absoluteRot) { if (!Enabled) return; @@ -448,7 +453,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments so.FromItemID = UUID.Zero; SceneObjectPart rootPart = so.RootPart; - so.AbsolutePosition = sp.AbsolutePosition; + so.AbsolutePosition = absolutePos; + if (absoluteRot != Quaternion.Identity) + { + so.UpdateGroupRotationR(absoluteRot); + } so.AttachedAvatar = UUID.Zero; rootPart.SetParentLocalId(0); so.ClearPartAttachmentData(); diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs index 1d6e522add..b5b00825f4 100644 --- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs @@ -525,7 +525,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory { for (int i = 0; i < AvatarWearable.MAX_WEARABLES; i++) { - for (int j = 0; j < appearance.Wearables[j].Count; j++) + for (int j = 0; j < appearance.Wearables[i].Count; j++) { if (appearance.Wearables[i][j].ItemID == UUID.Zero) continue; @@ -533,6 +533,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory // Ignore ruth's assets if (appearance.Wearables[i][j].ItemID == AvatarWearable.DefaultWearables[i][0].ItemID) continue; + InventoryItemBase baseItem = new InventoryItemBase(appearance.Wearables[i][j].ItemID, userID); baseItem = invService.GetItem(baseItem); diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs index f3af59ab2a..91eda19f41 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs @@ -297,6 +297,45 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer }); } } + else if (im.dialog == (byte) InstantMessageDialog.TaskInventoryAccepted) + { + UUID destinationFolderID = UUID.Zero; + + if (im.binaryBucket != null && im.binaryBucket.Length >= 16) + { + destinationFolderID = new UUID(im.binaryBucket, 0); + } + + if (destinationFolderID != UUID.Zero) + { + IInventoryService invService = scene.InventoryService; + + UUID inventoryID = new UUID(im.imSessionID); // The inventory item/folder, back from it's trip + + InventoryItemBase item = new InventoryItemBase(inventoryID, client.AgentId); + item = invService.GetItem(item); + InventoryFolderBase folder = null; + + if (item != null) // It's an item + { + item.Folder = destinationFolderID; + + invService.DeleteItems(item.Owner, new List() { item.ID }); + scene.AddInventoryItem(client, item); + } + else + { + folder = new InventoryFolderBase(inventoryID, client.AgentId); + folder = invService.GetFolder(folder); + + if (folder != null) // It's a folder + { + folder.ParentID = destinationFolderID; + invService.MoveFolder(folder); + } + } + } + } else if ( im.dialog == (byte)InstantMessageDialog.InventoryDeclined || im.dialog == (byte)InstantMessageDialog.TaskInventoryDeclined) diff --git a/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs b/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs index e135c21b79..e4115851af 100644 --- a/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs +++ b/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs @@ -95,14 +95,14 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring { foreach (IMonitor monitor in m_staticMonitors) { - m_log.InfoFormat( + MainConsole.Instance.OutputFormat( "[MONITOR MODULE]: {0} reports {1} = {2}", m_scene.RegionInfo.RegionName, monitor.GetFriendlyName(), monitor.GetFriendlyValue()); } foreach (KeyValuePair tuple in m_scene.StatsReporter.GetExtraSimStats()) { - m_log.InfoFormat( + MainConsole.Instance.OutputFormat( "[MONITOR MODULE]: {0} reports {1} = {2}", m_scene.RegionInfo.RegionName, tuple.Key, tuple.Value); } diff --git a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs index 65e4c90ba5..fd8d5e32bd 100755 --- a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs +++ b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs @@ -1,161 +1,170 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.IO; -using System.Text; -using log4net; - -namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging -{ - /// - /// Class for writing a high performance, high volume log file. - /// Sometimes, to debug, one has a high volume logging to do and the regular - /// log file output is not appropriate. - /// Create a new instance with the parameters needed and - /// call Write() to output a line. Call Close() when finished. - /// If created with no parameters, it will not log anything. - /// - public class LogWriter : IDisposable - { - public bool Enabled { get; private set; } - - private string m_logDirectory = "."; - private int m_logMaxFileTimeMin = 5; // 5 minutes - public String LogFileHeader { get; set; } - - private StreamWriter m_logFile = null; - private TimeSpan m_logFileLife; - private DateTime m_logFileEndTime; - private Object m_logFileWriteLock = new Object(); - - // set externally when debugging. If let 'null', this does not write any error messages. - public ILog ErrorLogger = null; - private string LogHeader = "[LOG WRITER]"; - - /// - /// Create a log writer that will not write anything. Good for when not enabled - /// but the write statements are still in the code. - /// - public LogWriter() - { - Enabled = false; - m_logFile = null; - } - - /// - /// Create a log writer instance. - /// - /// The directory to create the log file in. May be 'null' for default. - /// The characters that begin the log file name. May be 'null' for default. - /// Maximum age of a log file in minutes. If zero, will set default. - public LogWriter(string dir, string headr, int maxFileTime) - { - m_logDirectory = dir == null ? "." : dir; - - LogFileHeader = headr == null ? "log-" : headr; - - m_logMaxFileTimeMin = maxFileTime; - if (m_logMaxFileTimeMin < 1) - m_logMaxFileTimeMin = 5; - - m_logFileLife = new TimeSpan(0, m_logMaxFileTimeMin, 0); - m_logFileEndTime = DateTime.Now + m_logFileLife; - - Enabled = true; - } - - public void Dispose() - { - this.Close(); - } - - public void Close() - { - Enabled = false; - if (m_logFile != null) - { - m_logFile.Close(); - m_logFile.Dispose(); - m_logFile = null; - } - } - - public void Write(string line, params object[] args) - { - if (!Enabled) return; - Write(String.Format(line, args)); - } - - public void Write(string line) - { - if (!Enabled) return; - try - { - lock (m_logFileWriteLock) - { - DateTime now = DateTime.Now; - if (m_logFile == null || now > m_logFileEndTime) - { - if (m_logFile != null) - { - m_logFile.Close(); - m_logFile.Dispose(); - m_logFile = null; - } - - // First log file or time has expired, start writing to a new log file - m_logFileEndTime = now + m_logFileLife; - string path = (m_logDirectory.Length > 0 ? m_logDirectory - + System.IO.Path.DirectorySeparatorChar.ToString() : "") - + String.Format("{0}{1}.log", LogFileHeader, now.ToString("yyyyMMddHHmmss")); - m_logFile = new StreamWriter(File.Open(path, FileMode.Append, FileAccess.Write)); - } - if (m_logFile != null) - { - StringBuilder buff = new StringBuilder(line.Length + 25); - buff.Append(now.ToString("yyyyMMddHHmmssfff")); - // buff.Append(now.ToString("yyyyMMddHHmmss")); - buff.Append(","); - buff.Append(line); - buff.Append("\r\n"); - m_logFile.Write(buff.ToString()); - } - } - } - catch (Exception e) - { - if (ErrorLogger != null) - { - ErrorLogger.ErrorFormat("{0}: FAILURE WRITING TO LOGFILE: {1}", LogHeader, e); - } - Enabled = false; - } - return; - } - } -} \ No newline at end of file +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.IO; +using System.Text; +using log4net; + +namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging +{ + /// + /// Class for writing a high performance, high volume log file. + /// Sometimes, to debug, one has a high volume logging to do and the regular + /// log file output is not appropriate. + /// Create a new instance with the parameters needed and + /// call Write() to output a line. Call Close() when finished. + /// If created with no parameters, it will not log anything. + /// + public class LogWriter : IDisposable + { + public bool Enabled { get; private set; } + + private string m_logDirectory = "."; + private int m_logMaxFileTimeMin = 5; // 5 minutes + public String LogFileHeader { get; set; } + + private StreamWriter m_logFile = null; + private TimeSpan m_logFileLife; + private DateTime m_logFileEndTime; + private Object m_logFileWriteLock = new Object(); + + // set externally when debugging. If let 'null', this does not write any error messages. + public ILog ErrorLogger = null; + private string LogHeader = "[LOG WRITER]"; + + /// + /// Create a log writer that will not write anything. Good for when not enabled + /// but the write statements are still in the code. + /// + public LogWriter() + { + Enabled = false; + m_logFile = null; + } + + /// + /// Create a log writer instance. + /// + /// The directory to create the log file in. May be 'null' for default. + /// The characters that begin the log file name. May be 'null' for default. + /// Maximum age of a log file in minutes. If zero, will set default. + public LogWriter(string dir, string headr, int maxFileTime) + { + m_logDirectory = dir == null ? "." : dir; + + LogFileHeader = headr == null ? "log-" : headr; + + m_logMaxFileTimeMin = maxFileTime; + if (m_logMaxFileTimeMin < 1) + m_logMaxFileTimeMin = 5; + + m_logFileLife = new TimeSpan(0, m_logMaxFileTimeMin, 0); + m_logFileEndTime = DateTime.Now + m_logFileLife; + + Enabled = true; + } + + public void Dispose() + { + this.Close(); + } + + public void Close() + { + Enabled = false; + if (m_logFile != null) + { + m_logFile.Close(); + m_logFile.Dispose(); + m_logFile = null; + } + } + + public void Write(string line, params object[] args) + { + if (!Enabled) return; + Write(String.Format(line, args)); + } + + public void Flush() + { + if (!Enabled) return; + if (m_logFile != null) + { + m_logFile.Flush(); + } + } + + public void Write(string line) + { + if (!Enabled) return; + try + { + lock (m_logFileWriteLock) + { + DateTime now = DateTime.Now; + if (m_logFile == null || now > m_logFileEndTime) + { + if (m_logFile != null) + { + m_logFile.Close(); + m_logFile.Dispose(); + m_logFile = null; + } + + // First log file or time has expired, start writing to a new log file + m_logFileEndTime = now + m_logFileLife; + string path = (m_logDirectory.Length > 0 ? m_logDirectory + + System.IO.Path.DirectorySeparatorChar.ToString() : "") + + String.Format("{0}{1}.log", LogFileHeader, now.ToString("yyyyMMddHHmmss")); + m_logFile = new StreamWriter(File.Open(path, FileMode.Append, FileAccess.Write)); + } + if (m_logFile != null) + { + StringBuilder buff = new StringBuilder(line.Length + 25); + buff.Append(now.ToString("yyyyMMddHHmmssfff")); + // buff.Append(now.ToString("yyyyMMddHHmmss")); + buff.Append(","); + buff.Append(line); + buff.Append("\r\n"); + m_logFile.Write(buff.ToString()); + } + } + } + catch (Exception e) + { + if (ErrorLogger != null) + { + ErrorLogger.ErrorFormat("{0}: FAILURE WRITING TO LOGFILE: {1}", LogHeader, e); + } + Enabled = false; + } + return; + } + } +} diff --git a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs index 8155eabbbe..620ec22cc8 100644 --- a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs @@ -108,6 +108,15 @@ namespace OpenSim.Region.Framework.Interfaces /// void DetachSingleAttachmentToGround(IScenePresence sp, uint objectLocalID); + /// + /// Detach the given item to the ground at the specified coordinates & rotation + /// + /// + /// + /// + /// + void DetachSingleAttachmentToGround(IScenePresence sp, uint objectLocalID, Vector3 absolutePos, Quaternion absoluteRot); + /// /// Detach the given attachment so that it remains in the user's inventory. /// diff --git a/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs b/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs index 33041e9ac7..ad421eeedb 100644 --- a/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs +++ b/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs @@ -87,7 +87,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation { if (m_defaultAnimation.AnimID == animID) { - ResetDefaultAnimation(); + m_defaultAnimation = new OpenSim.Framework.Animation(UUID.Zero, 1, UUID.Zero); } else if (HasAnimation(animID)) { @@ -149,19 +149,26 @@ namespace OpenSim.Region.Framework.Scenes.Animation { lock (m_animations) { - animIDs = new UUID[m_animations.Count + 1]; - sequenceNums = new int[m_animations.Count + 1]; - objectIDs = new UUID[m_animations.Count + 1]; + int defaultSize = 0; + if (m_defaultAnimation.AnimID != UUID.Zero) + defaultSize++; - animIDs[0] = m_defaultAnimation.AnimID; - sequenceNums[0] = m_defaultAnimation.SequenceNum; - objectIDs[0] = m_defaultAnimation.ObjectID; + animIDs = new UUID[m_animations.Count + defaultSize]; + sequenceNums = new int[m_animations.Count + defaultSize]; + objectIDs = new UUID[m_animations.Count + defaultSize]; + + if (m_defaultAnimation.AnimID != UUID.Zero) + { + animIDs[0] = m_defaultAnimation.AnimID; + sequenceNums[0] = m_defaultAnimation.SequenceNum; + objectIDs[0] = m_defaultAnimation.ObjectID; + } for (int i = 0; i < m_animations.Count; ++i) { - animIDs[i + 1] = m_animations[i].AnimID; - sequenceNums[i + 1] = m_animations[i].SequenceNum; - objectIDs[i + 1] = m_animations[i].ObjectID; + animIDs[i + defaultSize] = m_animations[i].AnimID; + sequenceNums[i + defaultSize] = m_animations[i].SequenceNum; + objectIDs[i + defaultSize] = m_animations[i].ObjectID; } } } diff --git a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs index ff53f45f71..bb33f07b77 100644 --- a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs +++ b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs @@ -408,13 +408,19 @@ namespace OpenSim.Region.Framework.Scenes.Animation { lock (m_animations) { - CurrentMovementAnimation = DetermineMovementAnimation(); + string newMovementAnimation = DetermineMovementAnimation(); + if (CurrentMovementAnimation != newMovementAnimation) + { + CurrentMovementAnimation = DetermineMovementAnimation(); -// m_log.DebugFormat( -// "[SCENE PRESENCE ANIMATOR]: Determined animation {0} for {1} in UpdateMovementAnimations()", -// CurrentMovementAnimation, m_scenePresence.Name); +// m_log.DebugFormat( +// "[SCENE PRESENCE ANIMATOR]: Determined animation {0} for {1} in UpdateMovementAnimations()", +// CurrentMovementAnimation, m_scenePresence.Name); - TrySetMovementAnimation(CurrentMovementAnimation); + // Only set it if it's actually changed, give a script + // a chance to stop a default animation + TrySetMovementAnimation(CurrentMovementAnimation); + } } } @@ -536,4 +542,4 @@ namespace OpenSim.Region.Framework.Scenes.Animation SendAnimPack(animIDs, sequenceNums, objectIDs); } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 2e03874c20..0a4aa4aa38 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -5545,6 +5545,9 @@ namespace OpenSim.Region.Framework.Scenes public void StoreExtraSetting(string name, string val) { + if (m_extraSettings == null) + return; + string oldVal; if (m_extraSettings.TryGetValue(name, out oldVal)) @@ -5562,6 +5565,9 @@ namespace OpenSim.Region.Framework.Scenes public void RemoveExtraSetting(string name) { + if (m_extraSettings == null) + return; + if (!m_extraSettings.ContainsKey(name)) return; diff --git a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs index 96317c3de3..2addb5bab8 100644 --- a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs +++ b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs @@ -47,6 +47,7 @@ namespace OpenSim.Region.Framework.Scenes = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); public const string LastReportedObjectUpdateStatName = "LastReportedObjectUpdates"; + public const string SlowFramesStatName = "SlowFrames"; public delegate void SendStatResult(SimStats stats); @@ -128,6 +129,16 @@ namespace OpenSim.Region.Framework.Scenes get { return lastReportedSimStats; } } + /// + /// Number of frames that have taken longer to process than Scene.MIN_FRAME_TIME + /// + public Stat SlowFramesStat { get; private set; } + + /// + /// The threshold at which we log a slow frame. + /// + public int SlowFramesStatReportThreshold { get; private set; } + /// /// Extra sim statistics that are used by monitors but not sent to the client. /// @@ -225,6 +236,22 @@ namespace OpenSim.Region.Framework.Scenes if (StatsManager.SimExtraStats != null) OnSendStatsResult += StatsManager.SimExtraStats.ReceiveClassicSimStatsPacket; + + /// At the moment, we'll only report if a frame is over 120% of target, since commonly frames are a bit + /// longer than ideal (which in itself is a concern). + SlowFramesStatReportThreshold = (int)Math.Ceiling(m_scene.MinFrameTime * 1000 * 1.2); + + SlowFramesStat + = new Stat( + "SlowFrames", + "Slow Frames", + " frames", + "scene", + m_scene.Name, + StatVerbosity.Info, + "Number of frames where frame time has been significantly longer than the desired frame time."); + + StatsManager.RegisterStat(SlowFramesStat); } public void Close() @@ -418,6 +445,7 @@ namespace OpenSim.Region.Framework.Scenes lock (m_lastReportedExtraSimStats) { m_lastReportedExtraSimStats[LastReportedObjectUpdateStatName] = m_objectUpdates / m_statsUpdateFactor; + m_lastReportedExtraSimStats[SlowFramesStat.ShortName] = (float)SlowFramesStat.Value; Dictionary physicsStats = m_scene.PhysicsScene.GetStats(); @@ -535,6 +563,11 @@ namespace OpenSim.Region.Framework.Scenes public void addFrameMS(int ms) { m_frameMS += ms; + + // At the moment, we'll only report if a frame is over 120% of target, since commonly frames are a bit + // longer than ideal due to the inaccuracy of the Sleep in Scene.Update() (which in itself is a concern). + if (ms > SlowFramesStatReportThreshold) + SlowFramesStat.Value++; } public void AddSpareMS(int ms) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index b88ec3cf9d..2a52e0145b 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs @@ -218,6 +218,18 @@ public class BSCharacter : BSPhysObject }); } } + public override OMV.Vector3 ForcePosition { + get { + _position = BulletSimAPI.GetPosition2(BSBody.ptr); + return _position; + } + set { + _position = value; + PositionSanityCheck(); + BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); + } + } + // 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. @@ -234,6 +246,15 @@ public class BSCharacter : BSPhysObject _position.Z = terrainHeight + 2.0f; ret = true; } + if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) + { + float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); + if (Position.Z < waterHeight) + { + _position.Z = waterHeight; + ret = true; + } + } // TODO: check for out of bounds return ret; @@ -242,18 +263,22 @@ public class BSCharacter : BSPhysObject // A version of the sanity check that also makes sure a new position value is // pushed back to the physics engine. This routine would be used by anyone // who is not already pushing the value. - private bool PositionSanityCheck2() + private bool PositionSanityCheck2(bool atTaintTime) { bool ret = false; if (PositionSanityCheck()) { // The new position value must be pushed into the physics engine but we can't // just assign to "Position" because of potential call loops. - PhysicsScene.TaintedObject("BSCharacter.PositionSanityCheck", delegate() + BSScene.TaintCallback sanityOperation = delegate() { DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation); - }); + }; + if (atTaintTime) + sanityOperation(); + else + PhysicsScene.TaintedObject("BSCharacter.PositionSanityCheck", sanityOperation); ret = true; } return ret; @@ -333,6 +358,20 @@ public class BSCharacter : BSPhysObject }); } } + // Go directly to Bullet to get/set the value. + public override OMV.Quaternion ForceOrientation + { + get + { + _orientation = BulletSimAPI.GetOrientation2(BSBody.ptr); + return _orientation; + } + set + { + _orientation = value; + BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); + } + } public override int PhysicsActorType { get { return _physicsActorType; } set { _physicsActorType = value; @@ -378,7 +417,16 @@ public class BSCharacter : BSPhysObject set { _collidingObj = value; } } public override bool FloatOnWater { - set { _floatOnWater = value; } + set { + _floatOnWater = value; + PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() + { + if (_floatOnWater) + CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); + else + CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); + }); + } } public override OMV.Vector3 RotationalVelocity { get { return _rotationalVelocity; } @@ -493,15 +541,14 @@ public class BSCharacter : BSPhysObject _velocity = entprop.Velocity; _acceleration = entprop.Acceleration; _rotationalVelocity = entprop.RotationalVelocity; + // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. + PositionSanityCheck2(true); + // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. // base.RequestPhysicsterseUpdate(); - // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. - PositionSanityCheck2(); - - float heightHere = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); // only for debug - DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5},terrain={6}", - LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity, heightHere); + DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", + LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); } } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index 65b38d696a..4ba2f62639 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -92,7 +92,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body - // private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body + private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body //Deflection properties // private float m_angularDeflectionEfficiency = 0; @@ -138,74 +138,55 @@ namespace OpenSim.Region.Physics.BulletSPlugin switch (pParam) { case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: - if (pValue < 0.01f) pValue = 0.01f; - // m_angularDeflectionEfficiency = pValue; + // m_angularDeflectionEfficiency = Math.Max(pValue, 0.01f); break; case Vehicle.ANGULAR_DEFLECTION_TIMESCALE: - if (pValue < 0.01f) pValue = 0.01f; - // m_angularDeflectionTimescale = pValue; + // m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); break; case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: - if (pValue < 0.01f) pValue = 0.01f; - m_angularMotorDecayTimescale = pValue; + m_angularMotorDecayTimescale = Math.Max(pValue, 0.01f); break; case Vehicle.ANGULAR_MOTOR_TIMESCALE: - if (pValue < 0.01f) pValue = 0.01f; - m_angularMotorTimescale = pValue; + m_angularMotorTimescale = Math.Max(pValue, 0.01f); break; case Vehicle.BANKING_EFFICIENCY: - if (pValue < 0.01f) pValue = 0.01f; - // m_bankingEfficiency = pValue; + // m_bankingEfficiency = Math.Max(pValue, 0.01f); break; case Vehicle.BANKING_MIX: - if (pValue < 0.01f) pValue = 0.01f; - // m_bankingMix = pValue; + // m_bankingMix = Math.Max(pValue, 0.01f); break; case Vehicle.BANKING_TIMESCALE: - if (pValue < 0.01f) pValue = 0.01f; - // m_bankingTimescale = pValue; + // m_bankingTimescale = Math.Max(pValue, 0.01f); break; case Vehicle.BUOYANCY: - if (pValue < -1f) pValue = -1f; - if (pValue > 1f) pValue = 1f; - m_VehicleBuoyancy = pValue; + m_VehicleBuoyancy = Math.Max(-1f, Math.Min(pValue, 1f)); break; // case Vehicle.HOVER_EFFICIENCY: -// if (pValue < 0f) pValue = 0f; -// if (pValue > 1f) pValue = 1f; -// m_VhoverEfficiency = pValue; +// m_VhoverEfficiency = Math.Max(0f, Math.Min(pValue, 1f)); // break; case Vehicle.HOVER_HEIGHT: m_VhoverHeight = pValue; break; case Vehicle.HOVER_TIMESCALE: - if (pValue < 0.01f) pValue = 0.01f; - m_VhoverTimescale = pValue; + m_VhoverTimescale = Math.Max(pValue, 0.01f); break; case Vehicle.LINEAR_DEFLECTION_EFFICIENCY: - if (pValue < 0.01f) pValue = 0.01f; - // m_linearDeflectionEfficiency = pValue; + // m_linearDeflectionEfficiency = Math.Max(pValue, 0.01f); break; case Vehicle.LINEAR_DEFLECTION_TIMESCALE: - if (pValue < 0.01f) pValue = 0.01f; - // m_linearDeflectionTimescale = pValue; + // m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); break; case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: - if (pValue < 0.01f) pValue = 0.01f; - m_linearMotorDecayTimescale = pValue; + m_linearMotorDecayTimescale = Math.Max(pValue, 0.01f); break; case Vehicle.LINEAR_MOTOR_TIMESCALE: - if (pValue < 0.01f) pValue = 0.01f; - m_linearMotorTimescale = pValue; + m_linearMotorTimescale = Math.Max(pValue, 0.01f); break; case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: - if (pValue < 0.1f) pValue = 0.1f; // Less goes unstable - if (pValue > 1.0f) pValue = 1.0f; - m_verticalAttractionEfficiency = pValue; + m_verticalAttractionEfficiency = Math.Max(0.1f, Math.Min(pValue, 1f)); break; case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: - if (pValue < 0.01f) pValue = 0.01f; - m_verticalAttractionTimescale = pValue; + m_verticalAttractionTimescale = Math.Max(pValue, 0.01f); break; // These are vector properties but the engine lets you use a single float value to @@ -371,8 +352,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin // m_bankingMix = 1; // m_bankingTimescale = 1; // m_referenceFrame = Quaternion.Identity; - m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | - VehicleFlag.LIMIT_MOTOR_UP); + m_flags |= (VehicleFlag.NO_DEFLECTION_UP + | VehicleFlag.LIMIT_ROLL_ONLY + | VehicleFlag.LIMIT_MOTOR_UP); m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT); m_flags |= (VehicleFlag.HOVER_UP_ONLY); break; @@ -399,12 +381,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin // m_bankingMix = 0.8f; // m_bankingTimescale = 1; // m_referenceFrame = Quaternion.Identity; - m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY | - VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); - m_flags &= ~(VehicleFlag.LIMIT_ROLL_ONLY); - m_flags |= (VehicleFlag.NO_DEFLECTION_UP | - VehicleFlag.LIMIT_MOTOR_UP); - m_flags |= (VehicleFlag.HOVER_WATER_ONLY); + m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY + | VehicleFlag.HOVER_GLOBAL_HEIGHT + | VehicleFlag.LIMIT_ROLL_ONLY + | VehicleFlag.HOVER_UP_ONLY); + m_flags |= (VehicleFlag.NO_DEFLECTION_UP + | VehicleFlag.LIMIT_MOTOR_UP + | VehicleFlag.HOVER_WATER_ONLY); break; case Vehicle.TYPE_AIRPLANE: m_linearFrictionTimescale = new Vector3(200, 10, 5); @@ -429,9 +412,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin // m_bankingMix = 0.7f; // m_bankingTimescale = 2; // m_referenceFrame = Quaternion.Identity; - m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | - VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); - m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_MOTOR_UP); + m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY + | VehicleFlag.HOVER_TERRAIN_ONLY + | VehicleFlag.HOVER_GLOBAL_HEIGHT + | VehicleFlag.HOVER_UP_ONLY + | VehicleFlag.NO_DEFLECTION_UP + | VehicleFlag.LIMIT_MOTOR_UP); m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); break; case Vehicle.TYPE_BALLOON: @@ -457,11 +443,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin // m_bankingMix = 0.7f; // m_bankingTimescale = 5; // m_referenceFrame = Quaternion.Identity; - m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | - VehicleFlag.HOVER_UP_ONLY); - m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_MOTOR_UP); - m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); - m_flags |= (VehicleFlag.HOVER_GLOBAL_HEIGHT); + m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY + | VehicleFlag.HOVER_TERRAIN_ONLY + | VehicleFlag.HOVER_UP_ONLY + | VehicleFlag.NO_DEFLECTION_UP + | VehicleFlag.LIMIT_MOTOR_UP); + m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY + | VehicleFlag.HOVER_GLOBAL_HEIGHT); break; } }//end SetDefaultsForType @@ -470,7 +458,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin // Do any updating needed for a vehicle public void Refresh() { - if (Type == Vehicle.TYPE_NONE) return; + if (!IsActive) + return; // Set the prim's inertia to zero. The vehicle code handles that and this // removes the torque action introduced by Bullet. @@ -489,7 +478,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin LimitRotation(pTimestep); // remember the position so next step we can limit absolute movement effects - m_lastPositionVector = Prim.Position; + m_lastPositionVector = Prim.ForcePosition; VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", Prim.LocalID, Prim.Position, Prim.Force, Prim.Velocity, Prim.RotationalVelocity); @@ -543,7 +532,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin } // convert requested object velocity to object relative vector - Quaternion rotq = Prim.Orientation; + Quaternion rotq = Prim.ForceOrientation; m_newVelocity = m_lastLinearVelocityVector * rotq; // Add the various forces into m_dir which will be our new direction vector (velocity) @@ -560,19 +549,19 @@ namespace OpenSim.Region.Physics.BulletSPlugin m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity */ - Vector3 pos = Prim.Position; + Vector3 pos = Prim.ForcePosition; // Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f); // If below the terrain, move us above the ground a little. float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); // Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset. // Need to add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass. - // Vector3 rotatedSize = m_prim.Size * m_prim.Orientation; + // Vector3 rotatedSize = m_prim.Size * m_prim.ForceOrientation; // if (rotatedSize.Z < terrainHeight) if (pos.Z < terrainHeight) { pos.Z = terrainHeight + 2; - Prim.Position = pos; + Prim.ForcePosition = pos; VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos); } @@ -602,7 +591,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin { if ((pos.Z - m_VhoverTargetHeight) > .2 || (pos.Z - m_VhoverTargetHeight) < -.2) { - Prim.Position = pos; + Prim.ForcePosition = pos; } } else @@ -654,12 +643,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin } if (changed) { - Prim.Position = pos; + Prim.ForcePosition = pos; VDetailLog("{0},MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", Prim.LocalID, m_BlockingEndPoint, posChange, pos); } } + // Limit absolute vertical change float Zchange = Math.Abs(posChange.Z); if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) { @@ -678,6 +668,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin grav.Z = (float)(grav.Z * 1.037125); VDetailLog("{0},MoveLinear,limitMotorUp,grav={1}", Prim.LocalID, grav); } + + // If not changing some axis, reduce out velocity if ((m_flags & (VehicleFlag.NO_X)) != 0) m_newVelocity.X = 0; if ((m_flags & (VehicleFlag.NO_Y)) != 0) @@ -720,19 +712,19 @@ namespace OpenSim.Region.Physics.BulletSPlugin // a newly set velocity, this routine steps the value from the previous // value (m_angularMotorVelocity) to the requested value (m_angularMotorDirection). // There are m_angularMotorApply steps. - Vector3 origAngularVelocity = m_angularMotorVelocity; + Vector3 origVel = m_angularMotorVelocity; + Vector3 origDir = m_angularMotorDirection; + // ramp up to new value - // current velocity += error / ( time to get there / step interval) + // new velocity += error / ( time to get there / step interval) // requested speed - last motor speed m_angularMotorVelocity.X += (m_angularMotorDirection.X - m_angularMotorVelocity.X) / (m_angularMotorTimescale / pTimestep); m_angularMotorVelocity.Y += (m_angularMotorDirection.Y - m_angularMotorVelocity.Y) / (m_angularMotorTimescale / pTimestep); m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep); - VDetailLog("{0},MoveAngular,angularMotorApply,apply={1},angTScale={2},timeStep={3},origvel={4},dir={5},vel={6}", - Prim.LocalID, m_angularMotorApply, m_angularMotorTimescale, pTimestep, origAngularVelocity, m_angularMotorDirection, m_angularMotorVelocity); + VDetailLog("{0},MoveAngular,angularMotorApply,apply={1},angTScale={2},timeStep={3},origvel={4},origDir={5},vel={6}", + Prim.LocalID, m_angularMotorApply, m_angularMotorTimescale, pTimestep, origVel, origDir, m_angularMotorVelocity); - // This is done so that if script request rate is less than phys frame rate the expected - // velocity may still be acheived. m_angularMotorApply--; } else @@ -746,25 +738,32 @@ namespace OpenSim.Region.Physics.BulletSPlugin // Vertical attractor section Vector3 vertattr = Vector3.Zero; - if (m_verticalAttractionTimescale < 300) + Vector3 deflection = Vector3.Zero; + Vector3 banking = Vector3.Zero; + + if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero) { float VAservo = 0.2f / (m_verticalAttractionTimescale / pTimestep); + VAservo *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); + // get present body rotation - Quaternion rotq = Prim.Orientation; - // make a vector pointing up + Quaternion rotq = Prim.ForceOrientation; + // vector pointing up Vector3 verterr = Vector3.Zero; verterr.Z = 1.0f; + // rotate it to Body Angle verterr = verterr * rotq; - // verterr.X and .Y are the World error ammounts. They are 0 when there is no error (Vehicle Body is 'vertical'), and .Z will be 1. + // verterr.X and .Y are the World error amounts. They are 0 when there is no error (Vehicle Body is 'vertical'), and .Z will be 1. // As the body leans to its side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall and .Z will go // negative. Similar for tilt and |.Y|. .X and .Y must be modulated to prevent a stable inverted body. + + // Error is 0 (no error) to +/- 2 (max error) if (verterr.Z < 0.0f) { verterr.X = 2.0f - verterr.X; verterr.Y = 2.0f - verterr.Y; } - // Error is 0 (no error) to +/- 2 (max error) // scale it by VAservo verterr = verterr * VAservo; @@ -784,7 +783,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin } // else vertical attractor is off - // m_lastVertAttractor = vertattr; + m_lastVertAttractor = vertattr; // Bank section tba @@ -818,7 +817,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin internal void LimitRotation(float timestep) { - Quaternion rotq = Prim.Orientation; + Quaternion rotq = Prim.ForceOrientation; Quaternion m_rot = rotq; bool changed = false; if (m_RollreferenceFrame != Quaternion.Identity) @@ -853,7 +852,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin } if (changed) { - Prim.Orientation = m_rot; + Prim.ForceOrientation = m_rot; VDetailLog("{0},LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot); } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs index 4f225ae0f0..3e82642e52 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs @@ -34,7 +34,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin { public class BSLinkset { - private static string LogHeader = "[BULLETSIM LINKSET]"; + // private static string LogHeader = "[BULLETSIM LINKSET]"; public BSPhysObject LinksetRoot { get; protected set; } @@ -331,21 +331,21 @@ public class BSLinkset m_children.Add(child); BSPhysObject rootx = LinksetRoot; // capture the root and body as of now - BulletBody rootBodyx = LinksetRoot.BSBody; BSPhysObject childx = child; - BulletBody childBodyx = child.BSBody; DetailLog("{0},AddChildToLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", rootx.LocalID, - rootx.LocalID, rootBodyx.ptr.ToString("X"), - childx.LocalID, childBodyx.ptr.ToString("X")); + rootx.LocalID, rootx.BSBody.ptr.ToString("X"), + childx.LocalID, childx.BSBody.ptr.ToString("X")); PhysicsScene.TaintedObject("AddChildToLinkset", delegate() { DetailLog("{0},AddChildToLinkset,taint,child={1}", LinksetRoot.LocalID, child.LocalID); // build the physical binding between me and the child m_taintChildren.Add(childx); - PhysicallyLinkAChildToRoot(rootx, rootBodyx, childx, childBodyx); + + // Since this is taint-time, the body and shape could have changed for the child + PhysicallyLinkAChildToRoot(rootx, rootx.BSBody, childx, childx.BSBody); }); } return; @@ -369,21 +369,19 @@ public class BSLinkset if (m_children.Remove(child)) { BSPhysObject rootx = LinksetRoot; // capture the root and body as of now - BulletBody rootBodyx = LinksetRoot.BSBody; BSPhysObject childx = child; - BulletBody childBodyx = child.BSBody; DetailLog("{0},RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", childx.LocalID, - rootx.LocalID, rootBodyx.ptr.ToString("X"), - childx.LocalID, childBodyx.ptr.ToString("X")); + rootx.LocalID, rootx.BSBody.ptr.ToString("X"), + childx.LocalID, childx.BSBody.ptr.ToString("X")); PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate() { if (m_taintChildren.Contains(childx)) m_taintChildren.Remove(childx); - PhysicallyUnlinkAChildFromRoot(rootx, rootBodyx, childx, childBodyx); + PhysicallyUnlinkAChildFromRoot(rootx, rootx.BSBody, childx, childx.BSBody); RecomputeLinksetConstraintVariables(); }); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index d9b738b865..1ac8c59e07 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs @@ -81,6 +81,10 @@ public abstract class BSPhysObject : PhysicsActor // Tell the object to clean up. public abstract void Destroy(); + public abstract OMV.Vector3 ForcePosition { get; set; } + + public abstract OMV.Quaternion ForceOrientation { get; set; } + #region Collisions // Requested number of milliseconds between collision events. Zero means disabled. diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index a0e627ec66..f7b68bacc3 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -46,19 +46,13 @@ public sealed class BSPrim : BSPhysObject private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly string LogHeader = "[BULLETS PRIM]"; - private IMesh _mesh; private PrimitiveBaseShape _pbs; - private ShapeData.PhysicsShapeType _shapeType; - private ulong _meshKey; - private ulong _hullKey; - private List _hulls; // _size is what the user passed. _scale is what we pass to the physics engine with the mesh. // Often _scale is unity because the meshmerizer will apply _size when creating the mesh. private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user private OMV.Vector3 _scale; // the multiplier for each mesh dimension for the mesh as created by the meshmerizer - private bool _stopped; private bool _grabbed; private bool _isSelected; private bool _isVolumeDetect; @@ -109,8 +103,6 @@ public sealed class BSPrim : BSPhysObject _buoyancy = 1f; _velocity = OMV.Vector3.Zero; _rotationalVelocity = OMV.Vector3.Zero; - _hullKey = 0; - _meshKey = 0; _pbs = pbs; _isPhysical = pisPhysical; _isVolumeDetect = false; @@ -160,8 +152,9 @@ public sealed class BSPrim : BSPhysObject }); } + // No one uses this property. public override bool Stopped { - get { return _stopped; } + get { return false; } } public override OMV.Vector3 Size { get { return _size; } @@ -274,6 +267,7 @@ public sealed class BSPrim : BSPhysObject set { _position = value; // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint? + PositionSanityCheck(); PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() { // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); @@ -281,6 +275,74 @@ public sealed class BSPrim : BSPhysObject }); } } + public override OMV.Vector3 ForcePosition { + get { + _position = BulletSimAPI.GetPosition2(BSBody.ptr); + return _position; + } + set { + _position = value; + PositionSanityCheck(); + BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); + } + } + + // 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. + // Returns 'true' of the position was made sane by some action. + private bool PositionSanityCheck() + { + bool ret = false; + + // If totally below the ground, move the prim up + // TODO: figure out the right solution for this... only for dynamic objects? + /* + float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); + if (Position.Z < terrainHeight) + { + DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); + _position.Z = terrainHeight + 2.0f; + ret = true; + } + */ + if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) + { + float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); + if (Position.Z < waterHeight) + { + _position.Z = waterHeight; + ret = true; + } + } + + // TODO: check for out of bounds + return ret; + } + + // A version of the sanity check that also makes sure a new position value is + // pushed back to the physics engine. This routine would be used by anyone + // who is not already pushing the value. + private bool PositionSanityCheck2(bool atTaintTime) + { + bool ret = false; + if (PositionSanityCheck()) + { + // The new position value must be pushed into the physics engine but we can't + // just assign to "Position" because of potential call loops. + BSScene.TaintCallback sanityOperation = delegate() + { + DetailLog("{0},BSPrim.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); + BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation); + }; + if (atTaintTime) + sanityOperation(); + else + PhysicsScene.TaintedObject("BSPrim.PositionSanityCheck", sanityOperation); + + ret = true; + } + return ret; + } // Return the effective mass of the object. // If there are multiple items in the linkset, add them together for the root @@ -326,14 +388,15 @@ public sealed class BSPrim : BSPhysObject } set { Vehicle type = (Vehicle)value; - BSPrim vehiclePrim = this; + + // Tell the scene about the vehicle so it will get processing each frame. + PhysicsScene.VehicleInSceneTypeChanged(this, type); + PhysicsScene.TaintedObject("setVehicleType", delegate() { // 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.ProcessTypeChange(type); - // Tell the scene about the vehicle so it will get processing each frame. - PhysicsScene.VehicleInSceneTypeChanged(this, type); + this._vehicle.ProcessTypeChange(type); }); } } @@ -371,7 +434,9 @@ public sealed class BSPrim : BSPhysObject public override void StepVehicle(float timeStep) { if (IsPhysical) + { _vehicle.Step(timeStep); + } } // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more @@ -435,6 +500,20 @@ public sealed class BSPrim : BSPhysObject }); } } + // Go directly to Bullet to get/set the value. + public override OMV.Quaternion ForceOrientation + { + get + { + _orientation = BulletSimAPI.GetOrientation2(BSBody.ptr); + return _orientation; + } + set + { + _orientation = value; + BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); + } + } public override int PhysicsActorType { get { return _physicsActorType; } set { _physicsActorType = value; } @@ -488,11 +567,10 @@ public sealed class BSPrim : BSPhysObject // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found). BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, BSBody.ptr); - // Set up the object physicalness (does gravity and collisions move this object) MakeDynamic(IsStatic); - // Do any vehicle stuff + // Update vehicle specific parameters _vehicle.Refresh(); // Arrange for collision events if the simulator wants them @@ -563,7 +641,6 @@ public sealed class BSPrim : BSPhysObject // A dynamic object has mass IntPtr collisionShapePtr = BulletSimAPI.GetCollisionShape2(BSBody.ptr); OMV.Vector3 inertia = BulletSimAPI.CalculateLocalInertia2(collisionShapePtr, Mass); - // OMV.Vector3 inertia = OMV.Vector3.Zero; BulletSimAPI.SetMassProps2(BSBody.ptr, _mass, inertia); BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr); @@ -573,7 +650,7 @@ public sealed class BSPrim : BSPhysObject BulletSimAPI.SetSleepingThresholds2(BSBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); BulletSimAPI.SetContactProcessingThreshold2(BSBody.ptr, PhysicsScene.Params.contactProcessingThreshold); - // There can be special things needed for implementing linksets. + // There might be special things needed for implementing linksets. Linkset.MakeDynamic(this); // Force activation of the object so Bullet will act on it. @@ -663,7 +740,16 @@ public sealed class BSPrim : BSPhysObject } } public override bool FloatOnWater { - set { _floatOnWater = value; } + set { + _floatOnWater = value; + PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate() + { + if (_floatOnWater) + CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); + else + CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); + }); + } } public override OMV.Vector3 RotationalVelocity { get { @@ -1082,15 +1168,15 @@ public sealed class BSPrim : BSPhysObject public void FillShapeInfo(out ShapeData shape) { shape.ID = LocalID; - shape.Type = _shapeType; + shape.Type = ShapeData.PhysicsShapeType.SHAPE_UNKNOWN; shape.Position = _position; shape.Rotation = _orientation; shape.Velocity = _velocity; shape.Scale = _scale; shape.Mass = _isPhysical ? _mass : 0f; shape.Buoyancy = _buoyancy; - shape.HullKey = _hullKey; - shape.MeshKey = _meshKey; + shape.HullKey = 0; + shape.MeshKey = 0; shape.Friction = _friction; shape.Restitution = _restitution; shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse; @@ -1112,7 +1198,8 @@ public sealed class BSPrim : BSPhysObject // Create the correct physical representation for this type of object. // Updates BSBody and BSShape with the new information. - PhysicsScene.Shapes.GetBodyAndShape(forceRebuild, PhysicsScene.World, this, shapeData, _pbs, + // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. + PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, shapeData, _pbs, null, delegate(BulletBody dBody) { // Called if the current prim body is about to be destroyed. @@ -1205,6 +1292,8 @@ public sealed class BSPrim : BSPhysObject _acceleration = entprop.Acceleration; _rotationalVelocity = entprop.RotationalVelocity; + PositionSanityCheck2(true); + DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 0cf8c91a2d..aaed7de73d 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -493,6 +493,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters // step the physical world one interval m_simulationStep++; int numSubSteps = 0; + + // Sometimes needed for debugging to find out what happened before the step + // PhysicsLogging.Flush(); + try { if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); @@ -536,7 +540,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters } // This is a kludge to get avatar movement updates. - // ODE sends collisions for avatars even if there are have been no collisions. This updates + // the simulator expects collisions for avatars even if there are have been no collisions. This updates // avatar animations and stuff. // If you fix avatar animation updates, remove this overhead and let normal collision processing happen. foreach (BSPhysObject bsp in m_avatars) @@ -556,7 +560,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters } // Objects that are done colliding are removed from the ObjectsWithCollisions list. - // This can't be done by SendCollisions because it is inside an iteration of ObjectWithCollisions. + // Not done above because it is inside an iteration of ObjectWithCollisions. if (ObjectsWithNoMoreCollisions.Count > 0) { foreach (BSPhysObject po in ObjectsWithNoMoreCollisions) @@ -726,13 +730,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters public void VehicleInSceneTypeChanged(BSPrim vehic, Vehicle newType) { - if (newType == Vehicle.TYPE_NONE) + RemoveVehiclePrim(vehic); + if (newType != Vehicle.TYPE_NONE) { - RemoveVehiclePrim(vehic); - } - else - { - // make it so the scene will call us each tick to do vehicle things + // make it so the scene will call us each tick to do vehicle things AddVehiclePrim(vehic); } } @@ -764,7 +765,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters } // Some prims have extra vehicle actions - // no locking because only called when physics engine is not busy + // Called at taint time! private void ProcessVehicles(float timeStep) { foreach (BSPhysObject pobj in m_vehicles) @@ -1008,12 +1009,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", - 0f, // zero to disable + 0f, (s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); }, (s) => { return s.m_params[0].maxPersistantManifoldPoolSize; }, (s,p,l,v) => { s.m_params[0].maxPersistantManifoldPoolSize = v; } ), new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)", - 0f, // zero to disable + 0f, (s,cf,p,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); }, (s) => { return s.m_params[0].maxCollisionAlgorithmPoolSize; }, (s,p,l,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = v; } ), @@ -1028,7 +1029,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters (s) => { return s.m_params[0].shouldForceUpdateAllAabbs; }, (s,p,l,v) => { s.m_params[0].shouldForceUpdateAllAabbs = v; } ), new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction", - ConfigurationParameters.numericFalse, + ConfigurationParameters.numericTrue, (s,cf,p,v) => { s.m_params[0].shouldRandomizeSolverOrder = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, (s) => { return s.m_params[0].shouldRandomizeSolverOrder; }, (s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ), @@ -1152,7 +1153,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters { if (SettableParameters.Length < ParameterDefinitions.Length) { - List entries = new List(); for (int ii = 0; ii < ParameterDefinitions.Length; ii++) { diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs index dee6243b7a..399a133493 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs @@ -36,7 +36,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin { public class BSShapeCollection : IDisposable { - private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]"; + // private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]"; protected BSScene PhysicsScene { get; set; } @@ -108,7 +108,8 @@ public class BSShapeCollection : IDisposable // If we had to select a new shape geometry for the object, // rebuild the body around it. // Updates prim.BSBody with information/pointers to requested body - bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, prim.BSShape, shapeData, bodyCallback); + bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, + prim.BSShape, shapeData, bodyCallback); ret = newGeom || newBody; } DetailLog("{0},BSShapeCollection.GetBodyAndShape,force={1},ret={2},body={3},shape={4}", @@ -140,7 +141,7 @@ public class BSShapeCollection : IDisposable bodyDesc.lastReferenced = System.DateTime.Now; Bodies[body.ID] = bodyDesc; } -} + } // Release the usage of a body. // Called when releasing use of a BSBody. BSShape is handled separately. @@ -167,7 +168,7 @@ public class BSShapeCollection : IDisposable { DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}", body.ID, body.ptr.ToString("X")); - // If the caller needs to know, pass the event up. + // If the caller needs to know the old body is going away, pass the event up. if (bodyCallback != null) bodyCallback(body); // Zero any reference to the shape so it is not freed when the body is deleted. @@ -448,7 +449,8 @@ public class BSShapeCollection : IDisposable ulong newMeshKey = ComputeShapeKey(shapeData, pbs, out lod); // if this new shape is the same as last time, don't recreate the mesh - if (prim.BSShape.shapeKey == newMeshKey) return false; + if (newMeshKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_MESH) + return false; DetailLog("{0},BSShapeCollection.CreateGeomMesh,create,oldKey={1},newKey={2}", prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newMeshKey.ToString("X")); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs index 1125d7eb6a..a43880d337 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs @@ -71,7 +71,7 @@ public struct BulletBody buff.Append(ID.ToString()); buff.Append(",p="); buff.Append(ptr.ToString("X")); - if (collisionFilter != 0 && collisionMask != 0) + if (collisionFilter != 0 || collisionMask != 0) { buff.Append(",f="); buff.Append(collisionFilter.ToString("X")); @@ -344,10 +344,7 @@ public enum CollisionFlags : uint CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, // Following used by BulletSim to control collisions BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, - // BS_VOLUME_DETECT_OBJECT = 1 << 11, - // BS_PHANTOM_OBJECT = 1 << 12, - // BS_PHYSICAL_OBJECT = 1 << 13, - // BS_TERRAIN_OBJECT = 1 << 14, + BS_FLOATS_ON_WATER = 1 << 11, BS_NONE = 0, BS_ALL = 0xFFFFFFFF, @@ -356,9 +353,6 @@ public enum CollisionFlags : uint BS_ACTIVE = CF_STATIC_OBJECT | CF_KINEMATIC_OBJECT | CF_NO_CONTACT_RESPONSE - // | BS_VOLUME_DETECT_OBJECT - // | BS_PHANTOM_OBJECT - // | BS_PHYSICAL_OBJECT, }; // Values for collisions groups and masks diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs index 071621495a..e7b3b2b278 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs @@ -63,6 +63,9 @@ namespace OpenSim.Region.Physics.OdePlugin private bool m_isphysical; + public int ExpectedCollisionContacts { get { return m_expectedCollisionContacts; } } + private int m_expectedCollisionContacts = 0; + /// /// Is this prim subject to physics? Even if not, it's still solid for collision purposes. /// @@ -150,7 +153,7 @@ namespace OpenSim.Region.Physics.OdePlugin private PrimitiveBaseShape _pbs; private OdeScene _parent_scene; - + /// /// The physics space which contains prim geometries /// @@ -840,7 +843,7 @@ namespace OpenSim.Region.Physics.OdePlugin int vertexStride, triStride; mesh.getVertexListAsPtrToFloatArray(out vertices, out vertexStride, out vertexCount); // Note, that vertices are fixed in unmanaged heap mesh.getIndexListAsPtrToIntArray(out indices, out triStride, out indexCount); // Also fixed, needs release after usage - + m_expectedCollisionContacts = indexCount; mesh.releaseSourceMeshData(); // free up the original mesh data to save memory // We must lock here since m_MeshToTriMeshMap is static and multiple scene threads may call this method at @@ -1377,6 +1380,7 @@ Console.WriteLine("CreateGeom:"); { //Console.WriteLine(" CreateGeom 1"); SetGeom(d.CreateSphere(m_targetSpace, _size.X / 2)); + m_expectedCollisionContacts = 3; } catch (AccessViolationException) { @@ -1391,6 +1395,7 @@ Console.WriteLine("CreateGeom:"); { //Console.WriteLine(" CreateGeom 2"); SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z)); + m_expectedCollisionContacts = 4; } catch (AccessViolationException) { @@ -1406,6 +1411,7 @@ Console.WriteLine("CreateGeom:"); { //Console.WriteLine(" CreateGeom 3"); SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z)); + m_expectedCollisionContacts = 4; } catch (AccessViolationException) { @@ -1421,6 +1427,7 @@ Console.WriteLine("CreateGeom:"); { //Console.WriteLine(" CreateGeom 4"); SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z)); + m_expectedCollisionContacts = 4; } catch (AccessViolationException) { @@ -1446,11 +1453,13 @@ Console.WriteLine("CreateGeom:"); _parent_scene.geom_name_map.Remove(prim_geom); _parent_scene.actor_name_map.Remove(prim_geom); d.GeomDestroy(prim_geom); + m_expectedCollisionContacts = 0; prim_geom = IntPtr.Zero; } catch (System.AccessViolationException) { prim_geom = IntPtr.Zero; + m_expectedCollisionContacts = 0; m_log.ErrorFormat("[PHYSICS]: PrimGeom dead for {0}", Name); return false; @@ -2395,15 +2404,15 @@ Console.WriteLine(" JointCreateFixed"); { get { - // Averate previous velocity with the new one so + // Average previous velocity with the new one so // client object interpolation works a 'little' better if (_zeroFlag) return Vector3.Zero; Vector3 returnVelocity = Vector3.Zero; - returnVelocity.X = (m_lastVelocity.X + _velocity.X)/2; - returnVelocity.Y = (m_lastVelocity.Y + _velocity.Y)/2; - returnVelocity.Z = (m_lastVelocity.Z + _velocity.Z)/2; + returnVelocity.X = (m_lastVelocity.X + _velocity.X) * 0.5f; // 0.5f is mathematically equiv to '/ 2' + returnVelocity.Y = (m_lastVelocity.Y + _velocity.Y) * 0.5f; + returnVelocity.Z = (m_lastVelocity.Z + _velocity.Z) * 0.5f; return returnVelocity; } set @@ -2600,6 +2609,7 @@ Console.WriteLine(" JointCreateFixed"); { Vector3 pv = Vector3.Zero; bool lastZeroFlag = _zeroFlag; + float m_minvelocity = 0; if (Body != (IntPtr)0) // FIXME -> or if it is a joint { d.Vector3 vec = d.BodyGetPosition(Body); @@ -2752,8 +2762,21 @@ Console.WriteLine(" JointCreateFixed"); _acceleration = ((_velocity - m_lastVelocity) / 0.1f); _acceleration = new Vector3(_velocity.X - m_lastVelocity.X / 0.1f, _velocity.Y - m_lastVelocity.Y / 0.1f, _velocity.Z - m_lastVelocity.Z / 0.1f); //m_log.Info("[PHYSICS]: V1: " + _velocity + " V2: " + m_lastVelocity + " Acceleration: " + _acceleration.ToString()); + + // Note here that linearvelocity is affecting angular velocity... so I'm guessing this is a vehicle specific thing... + // it does make sense to do this for tiny little instabilities with physical prim, however 0.5m/frame is fairly large. + // reducing this to 0.02m/frame seems to help the angular rubberbanding quite a bit, however, to make sure it doesn't affect elevators and vehicles + // adding these logical exclusion situations to maintain this where I think it was intended to be. + if (m_throttleUpdates || m_usePID || (m_vehicle != null && m_vehicle.Type != Vehicle.TYPE_NONE) || (Amotor != IntPtr.Zero)) + { + m_minvelocity = 0.5f; + } + else + { + m_minvelocity = 0.02f; + } - if (_velocity.ApproxEquals(pv, 0.5f)) + if (_velocity.ApproxEquals(pv, m_minvelocity)) { m_rotationalVelocity = pv; } diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs index 929b019ecf..7a50c4c66a 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs @@ -336,6 +336,7 @@ namespace OpenSim.Region.Physics.OdePlugin public int geomContactPointsStartthrottle = 3; public int geomUpdatesPerThrottledUpdate = 15; + private const int avatarExpectedContacts = 3; public float bodyPIDD = 35f; public float bodyPIDG = 25; @@ -474,6 +475,8 @@ namespace OpenSim.Region.Physics.OdePlugin private OdePrim cp1; private OdeCharacter cc2; private OdePrim cp2; + private int p1ExpectedPoints = 0; + private int p2ExpectedPoints = 0; //private int cStartStop = 0; //private string cDictKey = ""; @@ -498,6 +501,7 @@ namespace OpenSim.Region.Physics.OdePlugin public int physics_logging_interval = 0; public bool physics_logging_append_existing_logfile = false; + public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f); public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f); @@ -644,7 +648,7 @@ namespace OpenSim.Region.Physics.OdePlugin contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80); - geomContactPointsStartthrottle = physicsconfig.GetInt("geom_contactpoints_start_throttling", 3); + geomContactPointsStartthrottle = physicsconfig.GetInt("geom_contactpoints_start_throttling", 5); geomUpdatesPerThrottledUpdate = physicsconfig.GetInt("geom_updates_before_throttled_update", 15); geomCrossingFailuresBeforeOutofbounds = physicsconfig.GetInt("geom_crossing_failures_before_outofbounds", 5); @@ -1064,7 +1068,10 @@ namespace OpenSim.Region.Physics.OdePlugin PhysicsActor p1; PhysicsActor p2; - + + p1ExpectedPoints = 0; + p2ExpectedPoints = 0; + if (!actor_name_map.TryGetValue(g1, out p1)) { p1 = PANull; @@ -1121,9 +1128,13 @@ namespace OpenSim.Region.Physics.OdePlugin switch (p1.PhysicsActorType) { case (int)ActorTypes.Agent: + p1ExpectedPoints = avatarExpectedContacts; p2.CollidingObj = true; break; case (int)ActorTypes.Prim: + if (p1 != null && p1 is OdePrim) + p1ExpectedPoints = ((OdePrim) p1).ExpectedCollisionContacts; + if (p2.Velocity.LengthSquared() > 0.0f) p2.CollidingObj = true; break; @@ -1319,6 +1330,7 @@ namespace OpenSim.Region.Physics.OdePlugin if ((p2.PhysicsActorType == (int) ActorTypes.Agent) && (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)) { + p2ExpectedPoints = avatarExpectedContacts; // Avatar is moving on terrain, use the movement terrain contact AvatarMovementTerrainContact.geom = curContact; @@ -1332,6 +1344,7 @@ namespace OpenSim.Region.Physics.OdePlugin { if (p2.PhysicsActorType == (int)ActorTypes.Agent) { + p2ExpectedPoints = avatarExpectedContacts; // Avatar is standing on terrain, use the non moving terrain contact TerrainContact.geom = curContact; @@ -1356,9 +1369,18 @@ namespace OpenSim.Region.Physics.OdePlugin } if (p2 is OdePrim) - material = ((OdePrim)p2).m_material; - + { + material = ((OdePrim) p2).m_material; + p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts; + } + + // Unnessesary because p1 is defined above + //if (p1 is OdePrim) + // { + // p1ExpectedPoints = ((OdePrim)p1).ExpectedCollisionContacts; + // } //m_log.DebugFormat("Material: {0}", material); + m_materialContacts[material, movintYN].geom = curContact; if (m_global_contactcount < maxContactsbeforedeath) @@ -1379,7 +1401,10 @@ namespace OpenSim.Region.Physics.OdePlugin int material = (int)Material.Wood; if (p2 is OdePrim) + { material = ((OdePrim)p2).m_material; + p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts; + } //m_log.DebugFormat("Material: {0}", material); m_materialContacts[material, movintYN].geom = curContact; @@ -1429,6 +1454,7 @@ namespace OpenSim.Region.Physics.OdePlugin { if ((p2.PhysicsActorType == (int)ActorTypes.Agent)) { + p2ExpectedPoints = avatarExpectedContacts; if ((Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)) { // Avatar is moving on a prim, use the Movement prim contact @@ -1458,7 +1484,10 @@ namespace OpenSim.Region.Physics.OdePlugin int material = (int)Material.Wood; if (p2 is OdePrim) + { material = ((OdePrim)p2).m_material; + p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts; + } //m_log.DebugFormat("Material: {0}", material); m_materialContacts[material, 0].geom = curContact; @@ -1479,8 +1508,8 @@ namespace OpenSim.Region.Physics.OdePlugin } collision_accounting_events(p1, p2, maxDepthContact); - - if (count > geomContactPointsStartthrottle) + + if (count > ((p1ExpectedPoints + p2ExpectedPoints) * 0.25) + (geomContactPointsStartthrottle)) { // If there are more then 3 contact points, it's likely // that we've got a pile of objects, so ... diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 52d96bc5c6..7fa6f05e08 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -4006,7 +4006,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); Vector3 av3 = Util.Clip(color, 0.0f, 1.0f); - m_host.SetText(text.Length > 254 ? text.Remove(254) : text, av3, Util.Clip((float)alpha, 0.0f, 1.0f)); + if (text.Length > 254) + text = text.Remove(254); + + byte[] data; + do + { + data = Util.UTF8.GetBytes(text); + if (data.Length > 254) + text = text.Substring(0, text.Length - 1); + } while (data.Length > 254); + + m_host.SetText(text, av3, Util.Clip((float)alpha, 0.0f, 1.0f)); //m_host.ParentGroup.HasGroupChanged = true; //m_host.ParentGroup.ScheduleGroupForFullUpdate(); } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index 8b73cd9ae0..31be45021c 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -3538,7 +3538,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return new LSL_Key(m_host.ParentGroup.FromPartID.ToString()); } - + /// /// Sets the response type for an HTTP request/response /// @@ -3549,6 +3549,91 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (m_UrlModule != null) m_UrlModule.HttpContentType(new UUID(id),type); } - - } + /// Shout an error if the object owner did not grant the script the specified permissions. + /// + /// + /// boolean indicating whether an error was shouted. + protected bool ShoutErrorOnLackingOwnerPerms(int perms, string errorPrefix) + { + CheckThreatLevel(ThreatLevel.Moderate, "osDropAttachment"); + m_host.AddScriptLPS(1); + bool fail = false; + if (m_item.PermsGranter != m_host.OwnerID) + { + fail = true; + OSSLShoutError(string.Format("{0}. Permissions not granted to owner.", errorPrefix)); + } + else if ((m_item.PermsMask & perms) == 0) + { + fail = true; + OSSLShoutError(string.Format("{0}. Permissions not granted.", errorPrefix)); + } + + return fail; + } + + protected void DropAttachment(bool checkPerms) + { + if (checkPerms && ShoutErrorOnLackingOwnerPerms(ScriptBaseClass.PERMISSION_ATTACH, "Cannot drop attachment")) + { + return; + } + + IAttachmentsModule attachmentsModule = m_ScriptEngine.World.AttachmentsModule; + ScenePresence sp = attachmentsModule == null ? null : m_host.ParentGroup.Scene.GetScenePresence(m_host.ParentGroup.OwnerID); + + if (attachmentsModule != null && sp != null) + { + attachmentsModule.DetachSingleAttachmentToGround(sp, m_host.ParentGroup.LocalId); + } + } + + protected void DropAttachmentAt(bool checkPerms, LSL_Vector pos, LSL_Rotation rot) + { + if (checkPerms && ShoutErrorOnLackingOwnerPerms(ScriptBaseClass.PERMISSION_ATTACH, "Cannot drop attachment")) + { + return; + } + + IAttachmentsModule attachmentsModule = m_ScriptEngine.World.AttachmentsModule; + ScenePresence sp = attachmentsModule == null ? null : m_host.ParentGroup.Scene.GetScenePresence(m_host.ParentGroup.OwnerID); + + if (attachmentsModule != null && sp != null) + { + attachmentsModule.DetachSingleAttachmentToGround(sp, m_host.ParentGroup.LocalId, pos, rot); + } + } + + public void osDropAttachment() + { + CheckThreatLevel(ThreatLevel.Moderate, "osDropAttachment"); + m_host.AddScriptLPS(1); + + DropAttachment(true); + } + + public void osForceDropAttachment() + { + CheckThreatLevel(ThreatLevel.High, "osForceDropAttachment"); + m_host.AddScriptLPS(1); + + DropAttachment(false); + } + + public void osDropAttachmentAt(LSL_Vector pos, LSL_Rotation rot) + { + CheckThreatLevel(ThreatLevel.Moderate, "osDropAttachmentAt"); + m_host.AddScriptLPS(1); + + DropAttachmentAt(true, pos, rot); + } + + public void osForceDropAttachmentAt(LSL_Vector pos, LSL_Rotation rot) + { + CheckThreatLevel(ThreatLevel.High, "osForceDropAttachmentAt"); + m_host.AddScriptLPS(1); + + DropAttachmentAt(false, pos, rot); + } + } } \ No newline at end of file diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs index 3985e6629c..93188c9ec8 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs @@ -394,5 +394,29 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces /// /// void osSetContentType(LSL_Key id, string type); + + /// + /// Attempts to drop an attachment to the ground + /// + void osDropAttachment(); + + /// + /// Attempts to drop an attachment to the ground while bypassing the script permissions + /// + void osForceDropAttachment(); + + /// + /// Attempts to drop an attachment at the specified coordinates. + /// + /// + /// + void osDropAttachmentAt(vector pos, rotation rot); + + /// + /// Attempts to drop an attachment at the specified coordinates while bypassing the script permissions + /// + /// + /// + void osForceDropAttachmentAt(vector pos, rotation rot); } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs index 52ca3da154..dee1b28cca 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs @@ -972,5 +972,25 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase { m_OSSL_Functions.osSetContentType(id,type); } + + public void osDropAttachment() + { + m_OSSL_Functions.osDropAttachment(); + } + + public void osForceDropAttachment() + { + m_OSSL_Functions.osForceDropAttachment(); + } + + public void osDropAttachmentAt(vector pos, rotation rot) + { + m_OSSL_Functions.osDropAttachmentAt(pos, rot); + } + + public void osForceDropAttachmentAt(vector pos, rotation rot) + { + m_OSSL_Functions.osForceDropAttachmentAt(pos, rot); + } } } diff --git a/OpenSim/Region/ScriptEngine/XEngine/EventManager.cs b/OpenSim/Region/ScriptEngine/XEngine/EventManager.cs index cee10df54a..9405075e51 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/EventManager.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/EventManager.cs @@ -96,9 +96,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine if (part == null) return; + if ((part.ScriptEvents & scriptEvents.money) == 0) + part = part.ParentGroup.RootPart; + m_log.Debug("Paid: " + objectID + " from " + agentID + ", amount " + amount); - part = part.ParentGroup.RootPart; +// part = part.ParentGroup.RootPart; money(part.LocalId, agentID, amount); } diff --git a/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs b/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs index 086b5adc90..2b2f11f94b 100644 --- a/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs +++ b/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs @@ -47,7 +47,8 @@ namespace OpenSim.Services.Connectors private string m_ServerURI = String.Empty; private IImprovedAssetCache m_Cache = null; - + private int m_maxAssetRequestConcurrency = 30; + private delegate void AssetRetrievedEx(AssetBase asset); // Keeps track of concurrent requests for the same asset, so that it's only loaded once. @@ -71,6 +72,10 @@ namespace OpenSim.Services.Connectors public virtual void Initialise(IConfigSource source) { + IConfig netconfig = source.Configs["Network"]; + if (netconfig != null) + m_maxAssetRequestConcurrency = netconfig.GetInt("MaxRequestConcurrency",m_maxAssetRequestConcurrency); + IConfig assetConfig = source.Configs["AssetService"]; if (assetConfig == null) { @@ -108,7 +113,7 @@ namespace OpenSim.Services.Connectors if (asset == null) { asset = SynchronousRestObjectRequester. - MakeRequest("GET", uri, 0, 30); + MakeRequest("GET", uri, 0, m_maxAssetRequestConcurrency); if (m_Cache != null) m_Cache.Cache(asset); @@ -221,7 +226,7 @@ namespace OpenSim.Services.Connectors m_AssetHandlers.Remove(id); } handlers.Invoke(a); - }, 30); + }, m_maxAssetRequestConcurrency); success = true; } diff --git a/OpenSim/Services/LLLoginService/LLLoginService.cs b/OpenSim/Services/LLLoginService/LLLoginService.cs index 495dc5297c..59fb55981b 100644 --- a/OpenSim/Services/LLLoginService/LLLoginService.cs +++ b/OpenSim/Services/LLLoginService/LLLoginService.cs @@ -293,7 +293,7 @@ namespace OpenSim.Services.LLLoginService { m_log.InfoFormat( "[LLOGIN SERVICE]: Login failed for {0} {1}, reason: user level is {2} but minimum login level is {3}", - firstName, lastName, m_MinLoginLevel, account.UserLevel); + firstName, lastName, account.UserLevel, m_MinLoginLevel); return LLFailedLoginResponse.LoginBlockedProblem; } diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 6e6a089d7f..677ac746ce 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -427,6 +427,10 @@ ; " (Mozilla Compatible)" to the text where there are problems with a web server ;user_agent = "OpenSim LSL (Mozilla Compatible)" + ; OpenSim can send multiple simultaneous requests for services such as asset + ; retrieval. However, some versions of mono appear to hang when there are too + ; many simultaneous requests, default is 30 and is currently applied only to assets + ;MaxRequestConcurrency = 30 [XMLRPC] ; ## diff --git a/bin/lib32/BulletSim.dll b/bin/lib32/BulletSim.dll index da6e31cdd2..1fd0a60cc2 100755 Binary files a/bin/lib32/BulletSim.dll and b/bin/lib32/BulletSim.dll differ diff --git a/bin/lib32/libBulletSim.so b/bin/lib32/libBulletSim.so index 9503cdb188..3b42048552 100755 Binary files a/bin/lib32/libBulletSim.so and b/bin/lib32/libBulletSim.so differ diff --git a/bin/lib64/BulletSim.dll b/bin/lib64/BulletSim.dll index 1782c8e741..bfaabde02c 100755 Binary files a/bin/lib64/BulletSim.dll and b/bin/lib64/BulletSim.dll differ diff --git a/bin/lib64/libBulletSim.so b/bin/lib64/libBulletSim.so index 06e6ce27fb..54ddad95ff 100755 Binary files a/bin/lib64/libBulletSim.so and b/bin/lib64/libBulletSim.so differ