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/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index 8e886d443e..e711afbbbb 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -474,6 +474,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; @@ -516,7 +521,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/Inventory/Transfer/InventoryTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs index 81de29c108..c14cb1791b 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs @@ -313,6 +313,45 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer m_TransferModule.SendInstantMessage(im, delegate(bool success) {}); } } + 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/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 90a13a73b5..d781eae887 100644 --- a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs @@ -113,6 +113,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/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 29c8eb16cd..6e3e4364c7 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -5958,6 +5958,9 @@ Environment.Exit(1); public void StoreExtraSetting(string name, string val) { + if (m_extraSettings == null) + return; + string oldVal; if (m_extraSettings.TryGetValue(name, out oldVal)) @@ -5975,6 +5978,9 @@ Environment.Exit(1); public void RemoveExtraSetting(string name) { + if (m_extraSettings == null) + return; + if (!m_extraSettings.ContainsKey(name)) return; 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/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index 8ad1451c02..2c682d4f82 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -3593,7 +3593,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 /// @@ -3604,5 +3604,92 @@ 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); + } } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs index 0ea363a448..b1fbed5951 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/LLLoginService/LLLoginService.cs b/OpenSim/Services/LLLoginService/LLLoginService.cs index 988a9b9305..cbb6e6c4a9 100644 --- a/OpenSim/Services/LLLoginService/LLLoginService.cs +++ b/OpenSim/Services/LLLoginService/LLLoginService.cs @@ -300,7 +300,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; }