Merge branch 'master' of /home/opensim/var/repo/opensim

integration
BlueWall 2012-11-09 08:49:38 -05:00
commit c24fe86f0e
54 changed files with 2748 additions and 1105 deletions

View File

@ -182,12 +182,14 @@ what it is today.
This software uses components from the following developers:
* Sleepycat Software (Berkeley DB)
* Aurora-Sim (http://aurora-sim.org)
* SQLite (Public Domain)
* XmlRpcCS (http://xmlrpccs.sf.net/)
* MySQL, Inc. (MySQL Connector/NET)
* NUnit (http://www.nunit.org)
* AGEIA Inc. (PhysX)
* Russel L. Smith (ODE)
* Erwin Coumans (Bullet)
* Prebuild (http://sourceforge.net/projects/dnpb/)
* LibOpenMetaverse (http://lib.openmetaverse.org/)
* DotNetOpenMail v0.5.8b (http://dotnetopenmail.sourceforge.net)

View File

@ -116,7 +116,22 @@ namespace OpenSim.Data
/// <returns>true if the delete was successful, false if it was not</returns>
bool DeleteItems(string[] fields, string[] vals);
bool MoveItem(string id, string newParent);
/// <summary>
/// Move an item to another folder.
/// </summary>
/// <returns>/returns>
/// <param name='id'>UUID of the item</param>
/// <param name='newParent'>UUID of the new parent folder.</param>
bool MoveItem(string id, string newParentFolderID);
/// <summary>
/// Move a folder to another folder.
/// </summary>
/// <returns>/returns>
/// <param name='id'>UUID of the item</param>
/// <param name='newParent'>UUID of the new parent folder.</param>
bool MoveFolder(string id, string newParentFolderID);
XInventoryItem[] GetActiveGestures(UUID principalID);
int GetAssetPermissions(UUID principalID, UUID assetID);
}

View File

@ -43,12 +43,12 @@ namespace OpenSim.Data.MSSQL
// private static readonly ILog m_log = LogManager.GetLogger(
// MethodBase.GetCurrentMethod().DeclaringType);
private MSSQLGenericTableHandler<XInventoryFolder> m_Folders;
private MSSQLFolderHandler m_Folders;
private MSSQLItemHandler m_Items;
public MSSQLXInventoryData(string conn, string realm)
{
m_Folders = new MSSQLGenericTableHandler<XInventoryFolder>(
m_Folders = new MSSQLFolderHandler(
conn, "inventoryfolders", "InventoryStore");
m_Items = new MSSQLItemHandler(
conn, "inventoryitems", String.Empty);
@ -85,6 +85,7 @@ namespace OpenSim.Data.MSSQL
{
return m_Folders.Delete(field, val);
}
public bool DeleteFolders(string[] fields, string[] vals)
{
return m_Folders.Delete(fields, vals);
@ -94,15 +95,22 @@ namespace OpenSim.Data.MSSQL
{
return m_Items.Delete(field, val);
}
public bool DeleteItems(string[] fields, string[] vals)
{
return m_Items.Delete(fields, vals);
}
public bool MoveItem(string id, string newParent)
{
return m_Items.MoveItem(id, newParent);
}
public bool MoveFolder(string id, string newParent)
{
return m_Folders.MoveFolder(id, newParent);
}
public XInventoryItem[] GetActiveGestures(UUID principalID)
{
return m_Items.GetActiveGestures(principalID);
@ -124,6 +132,7 @@ namespace OpenSim.Data.MSSQL
public bool MoveItem(string id, string newParent)
{
using (SqlConnection conn = new SqlConnection(m_ConnectionString))
{
using (SqlCommand cmd = new SqlCommand())
{
@ -135,10 +144,12 @@ namespace OpenSim.Data.MSSQL
return cmd.ExecuteNonQuery() == 0 ? false : true;
}
}
}
public XInventoryItem[] GetActiveGestures(UUID principalID)
{
using (SqlConnection conn = new SqlConnection(m_ConnectionString))
{
using (SqlCommand cmd = new SqlCommand())
{
cmd.CommandText = String.Format("select * from inventoryitems where avatarId = @uuid and assetType = @type and flags = 1", m_Realm);
@ -150,10 +161,12 @@ namespace OpenSim.Data.MSSQL
return DoQuery(cmd);
}
}
}
public int GetAssetPermissions(UUID principalID, UUID assetID)
{
using (SqlConnection conn = new SqlConnection(m_ConnectionString))
{
using (SqlCommand cmd = new SqlCommand())
{
cmd.CommandText = String.Format("select bit_or(inventoryCurrentPermissions) as inventoryCurrentPermissions from inventoryitems where avatarID = @PrincipalID and assetID = @AssetID group by assetID", m_Realm);
@ -176,12 +189,16 @@ namespace OpenSim.Data.MSSQL
}
}
}
public override bool Store(XInventoryItem item)
{
if (!base.Store(item))
return false;
string sql = "update inventoryfolders set version=version+1 where folderID = @folderID";
using (SqlConnection conn = new SqlConnection(m_ConnectionString))
{
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
conn.Open();
@ -196,7 +213,34 @@ namespace OpenSim.Data.MSSQL
return false;
}
}
return true;
}
}
}
public class MSSQLFolderHandler : MSSQLGenericTableHandler<XInventoryFolder>
{
public MSSQLFolderHandler(string c, string t, string m) :
base(c, t, m)
{
}
public bool MoveFolder(string id, string newParentFolderID)
{
using (SqlConnection conn = new SqlConnection(m_ConnectionString))
{
using (SqlCommand cmd = new SqlCommand())
{
cmd.CommandText = String.Format("update {0} set parentFolderID = @ParentFolderID where folderID = @folderID", m_Realm);
cmd.Parameters.Add(m_database.CreateParameter("@ParentFolderID", newParentFolderID));
cmd.Parameters.Add(m_database.CreateParameter("@folderID", id));
cmd.Connection = conn;
conn.Open();
return cmd.ExecuteNonQuery() == 0 ? false : true;
}
}
}
}
}

View File

@ -219,6 +219,8 @@ namespace OpenSim.Data.MySQL
public virtual bool Store(T row)
{
// m_log.DebugFormat("[MYSQL GENERIC TABLE HANDLER]: Store(T row) invoked");
using (MySqlCommand cmd = new MySqlCommand())
{
string query = "";
@ -273,6 +275,10 @@ namespace OpenSim.Data.MySQL
public virtual bool Delete(string[] fields, string[] keys)
{
// m_log.DebugFormat(
// "[MYSQL GENERIC TABLE HANDLER]: Delete(string[] fields, string[] keys) invoked with {0}:{1}",
// string.Join(",", fields), string.Join(",", keys));
if (fields.Length != keys.Length)
return false;

View File

@ -26,9 +26,10 @@
*/
using System;
using System.Data;
using System.Reflection;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using log4net;
using MySql.Data.MySqlClient;
using OpenMetaverse;
@ -41,12 +42,12 @@ namespace OpenSim.Data.MySQL
/// </summary>
public class MySQLXInventoryData : IXInventoryData
{
private MySQLGenericTableHandler<XInventoryFolder> m_Folders;
private MySqlFolderHandler m_Folders;
private MySqlItemHandler m_Items;
public MySQLXInventoryData(string conn, string realm)
{
m_Folders = new MySQLGenericTableHandler<XInventoryFolder>(
m_Folders = new MySqlFolderHandler(
conn, "inventoryfolders", "InventoryStore");
m_Items = new MySqlItemHandler(
conn, "inventoryitems", String.Empty);
@ -105,6 +106,11 @@ namespace OpenSim.Data.MySQL
return m_Items.MoveItem(id, newParent);
}
public bool MoveFolder(string id, string newParent)
{
return m_Folders.MoveFolder(id, newParent);
}
public XInventoryItem[] GetActiveGestures(UUID principalID)
{
return m_Items.GetActiveGestures(principalID);
@ -118,22 +124,69 @@ namespace OpenSim.Data.MySQL
public class MySqlItemHandler : MySQLGenericTableHandler<XInventoryItem>
{
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public MySqlItemHandler(string c, string t, string m) :
base(c, t, m)
{
}
public override bool Delete(string field, string val)
{
XInventoryItem[] retrievedItems = Get(new string[] { field }, new string[] { val });
if (retrievedItems.Length == 0)
return false;
if (!base.Delete(field, val))
return false;
// Don't increment folder version here since Delete(string, string) calls Delete(string[], string[])
// IncrementFolderVersion(retrievedItems[0].parentFolderID);
return true;
}
public override bool Delete(string[] fields, string[] vals)
{
XInventoryItem[] retrievedItems = Get(fields, vals);
if (retrievedItems.Length == 0)
return false;
if (!base.Delete(fields, vals))
return false;
HashSet<UUID> deletedItemFolderUUIDs = new HashSet<UUID>();
Array.ForEach<XInventoryItem>(retrievedItems, i => deletedItemFolderUUIDs.Add(i.parentFolderID));
foreach (UUID deletedItemFolderUUID in deletedItemFolderUUIDs)
IncrementFolderVersion(deletedItemFolderUUID);
return true;
}
public bool MoveItem(string id, string newParent)
{
XInventoryItem[] retrievedItems = Get(new string[] { "inventoryID" }, new string[] { id });
if (retrievedItems.Length == 0)
return false;
UUID oldParent = retrievedItems[0].parentFolderID;
using (MySqlCommand cmd = new MySqlCommand())
{
cmd.CommandText = String.Format("update {0} set parentFolderID = ?ParentFolderID where inventoryID = ?InventoryID", m_Realm);
cmd.Parameters.AddWithValue("?ParentFolderID", newParent);
cmd.Parameters.AddWithValue("?InventoryID", id);
return ExecuteNonQuery(cmd) == 0 ? false : true;
if (ExecuteNonQuery(cmd) == 0)
return false;
}
IncrementFolderVersion(oldParent);
IncrementFolderVersion(newParent);
return true;
}
public XInventoryItem[] GetActiveGestures(UUID principalID)
@ -184,6 +237,21 @@ namespace OpenSim.Data.MySQL
if (!base.Store(item))
return false;
IncrementFolderVersion(item.parentFolderID);
return true;
}
private bool IncrementFolderVersion(UUID folderID)
{
return IncrementFolderVersion(folderID.ToString());
}
private bool IncrementFolderVersion(string folderID)
{
// m_log.DebugFormat("[MYSQL ITEM HANDLER]: Incrementing version on folder {0}", folderID);
// Util.PrintCallStack();
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{
dbcon.Open();
@ -193,7 +261,7 @@ namespace OpenSim.Data.MySQL
cmd.Connection = dbcon;
cmd.CommandText = String.Format("update inventoryfolders set version=version+1 where folderID = ?folderID");
cmd.Parameters.AddWithValue("?folderID", item.parentFolderID.ToString());
cmd.Parameters.AddWithValue("?folderID", folderID);
try
{
@ -205,8 +273,95 @@ namespace OpenSim.Data.MySQL
}
cmd.Dispose();
}
dbcon.Close();
}
return true;
}
}
public class MySqlFolderHandler : MySQLGenericTableHandler<XInventoryFolder>
{
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public MySqlFolderHandler(string c, string t, string m) :
base(c, t, m)
{
}
public bool MoveFolder(string id, string newParentFolderID)
{
XInventoryFolder[] folders = Get(new string[] { "folderID" }, new string[] { id });
if (folders.Length == 0)
return false;
UUID oldParentFolderUUID = folders[0].parentFolderID;
using (MySqlCommand cmd = new MySqlCommand())
{
cmd.CommandText
= String.Format(
"update {0} set parentFolderID = ?ParentFolderID where folderID = ?folderID", m_Realm);
cmd.Parameters.AddWithValue("?ParentFolderID", newParentFolderID);
cmd.Parameters.AddWithValue("?folderID", id);
if (ExecuteNonQuery(cmd) == 0)
return false;
}
IncrementFolderVersion(oldParentFolderUUID);
IncrementFolderVersion(newParentFolderID);
return true;
}
public override bool Store(XInventoryFolder folder)
{
if (!base.Store(folder))
return false;
IncrementFolderVersion(folder.parentFolderID);
return true;
}
private bool IncrementFolderVersion(UUID folderID)
{
return IncrementFolderVersion(folderID.ToString());
}
private bool IncrementFolderVersion(string folderID)
{
// m_log.DebugFormat("[MYSQL FOLDER HANDLER]: Incrementing version on folder {0}", folderID);
// Util.PrintCallStack();
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{
dbcon.Open();
using (MySqlCommand cmd = new MySqlCommand())
{
cmd.Connection = dbcon;
cmd.CommandText = String.Format("update inventoryfolders set version=version+1 where folderID = ?folderID");
cmd.Parameters.AddWithValue("?folderID", folderID);
try
{
cmd.ExecuteNonQuery();
}
catch (Exception)
{
return false;
}
cmd.Dispose();
}
dbcon.Close();
}
return true;
}
}

View File

@ -47,7 +47,7 @@ namespace OpenSim.Data.SQLite
{
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private SQLiteGenericTableHandler<XInventoryFolder> m_Folders;
private SqliteFolderHandler m_Folders;
private SqliteItemHandler m_Items;
public SQLiteXInventoryData(string conn, string realm)
@ -55,7 +55,7 @@ namespace OpenSim.Data.SQLite
if (Util.IsWindows())
Util.LoadArchSpecificWindowsDll("sqlite3.dll");
m_Folders = new SQLiteGenericTableHandler<XInventoryFolder>(
m_Folders = new SqliteFolderHandler(
conn, "inventoryfolders", "XInventoryStore");
m_Items = new SqliteItemHandler(
conn, "inventoryitems", String.Empty);
@ -114,6 +114,11 @@ namespace OpenSim.Data.SQLite
return m_Items.MoveItem(id, newParent);
}
public bool MoveFolder(string id, string newParent)
{
return m_Folders.MoveFolder(id, newParent);
}
public XInventoryItem[] GetActiveGestures(UUID principalID)
{
return m_Items.GetActiveGestures(principalID);
@ -177,4 +182,23 @@ namespace OpenSim.Data.SQLite
return perms;
}
}
public class SqliteFolderHandler : SQLiteGenericTableHandler<XInventoryFolder>
{
public SqliteFolderHandler(string c, string t, string m) :
base(c, t, m)
{
}
public bool MoveFolder(string id, string newParentFolderID)
{
SqliteCommand cmd = new SqliteCommand();
cmd.CommandText = String.Format("update {0} set parentFolderID = :ParentFolderID where folderID = :FolderID", m_Realm);
cmd.Parameters.Add(new SqliteParameter(":ParentFolderID", newParentFolderID));
cmd.Parameters.Add(new SqliteParameter(":FolderID", id));
return ExecuteNonQuery(cmd, m_Connection) == 0 ? false : true;
}
}
}

View File

@ -121,6 +121,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods
if (sp != null || agentID == kickUserID)
{
m_dialogModule = m_scene.RequestModuleInterface<IDialogModule>();
if (m_scene.Permissions.IsGod(godID))
{
if (kickflags == 0)
@ -162,19 +163,26 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods
if (kickflags == 1)
{
sp.AllowMovement = false;
if (m_dialogModule != null)
{
m_dialogModule.SendAlertToUser(agentID, Utils.BytesToString(reason));
m_dialogModule.SendAlertToUser(godID, "User Frozen");
}
}
if (kickflags == 2)
{
sp.AllowMovement = true;
if (m_dialogModule != null)
{
m_dialogModule.SendAlertToUser(agentID, Utils.BytesToString(reason));
m_dialogModule.SendAlertToUser(godID, "User Unfrozen");
}
}
}
else
{
if (m_dialogModule != null)
m_dialogModule.SendAlertToUser(godID, "Kick request denied");
}
}

View File

@ -210,8 +210,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
Guid id, string firstName, string lastName, string invPath, string pass, string savePath,
Dictionary<string, object> options)
{
if (!ConsoleUtil.CheckFileDoesNotExist(MainConsole.Instance, savePath))
return false;
// if (!ConsoleUtil.CheckFileDoesNotExist(MainConsole.Instance, savePath))
// return false;
if (m_scenes.Count > 0)
{

View File

@ -434,6 +434,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
scene.SendInventoryUpdate(client, trashFolder, true, true);
}
if (im.dialog == (byte)InstantMessageDialog.InventoryDeclined)
{
ScenePresence user = scene.GetScenePresence(new UUID(im.toAgentID));
if (user != null) // Local
@ -443,7 +445,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
else
{
if (m_TransferModule != null)
m_TransferModule.SendInstantMessage(im, delegate(bool success) {});
m_TransferModule.SendInstantMessage(im, delegate(bool success) { });
}
}
}
}

View File

@ -259,8 +259,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0)
{
// this user is going to another grid
// check if HyperGrid teleport is allowed, based on user level
if (sp.UserLevel < m_levelHGTeleport)
// for local users, check if HyperGrid teleport is allowed, based on user level
if (Scene.UserManagementModule.IsLocalGridUser(sp.UUID) && sp.UserLevel < m_levelHGTeleport)
{
m_log.WarnFormat("[HG ENTITY TRANSFER MODULE]: Unable to HG teleport agent due to insufficient UserLevel.");
reason = "Hypergrid teleport not allowed";

View File

@ -92,7 +92,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
m_HomeURI = thisModuleConfig.GetString("HomeURI", m_HomeURI);
m_OutboundPermission = thisModuleConfig.GetBoolean("OutboundPermission", true);
m_ThisGatekeeper = thisModuleConfig.GetString("Gatekeeper", string.Empty);
m_RestrictInventoryAccessAbroad = thisModuleConfig.GetBoolean("RestrictInventoryAccessAbroad", false);
m_RestrictInventoryAccessAbroad = thisModuleConfig.GetBoolean("RestrictInventoryAccessAbroad", true);
}
else
m_log.Warn("[HG INVENTORY ACCESS MODULE]: HGInventoryAccessModule configs not found. ProfileServerURI not set!");
@ -351,6 +351,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
private void ProcessInventoryForArriving(IClientAPI client)
{
// No-op for now, but we may need to do something for freign users inventory
}
//
@ -397,6 +398,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
private void ProcessInventoryForLeaving(IClientAPI client)
{
// No-op for now
}
#endregion

View File

@ -361,6 +361,22 @@ namespace OpenSim.Region.OptionalModules.Scripting.ScriptModuleComms
return null;
}
/// <summary>
/// Get all registered constants
/// </summary>
public Dictionary<string, object> GetConstants()
{
Dictionary<string, object> ret = new Dictionary<string, object>();
lock (m_constants)
{
foreach (KeyValuePair<string, object> kvp in m_constants)
ret[kvp.Key] = kvp.Value;
}
return ret;
}
#endregion
}

View File

@ -158,8 +158,10 @@ namespace OpenSim.Region.CoreModules.World.Archiver
else
path = DEFAULT_OAR_BACKUP_FILENAME;
if (!ConsoleUtil.CheckFileDoesNotExist(MainConsole.Instance, path))
return;
// Not doing this right now as this causes some problems with auto-backup systems. Maybe a force flag is
// needed
// if (!ConsoleUtil.CheckFileDoesNotExist(MainConsole.Instance, path))
// return;
ArchiveRegion(path, options);
}

View File

@ -27,6 +27,7 @@
using System;
using System.Reflection;
using System.Collections.Generic;
using OpenMetaverse;
namespace OpenSim.Region.Framework.Interfaces
@ -131,6 +132,7 @@ namespace OpenSim.Region.Framework.Interfaces
/// <param name="cname">Name of constant</param>
/// <returns>Value of constant or null if none found.</returns>
object LookupModConstant(string cname);
Dictionary<string, object> GetConstants();
// For use ONLY by the script API
void RaiseEvent(UUID script, string id, string module, string command, string key);

View File

@ -1,4 +1,4 @@
/*
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
@ -538,7 +538,7 @@ namespace OpenSim.Region.Framework.Scenes
{
try
{
PhysicsActor.Velocity = value;
PhysicsActor.TargetVelocity = value;
}
catch (Exception e)
{

View File

@ -34,7 +34,7 @@ using OpenSim.Region.Physics.Manager;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public class BSCharacter : BSPhysObject
public sealed class BSCharacter : BSPhysObject
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static readonly string LogHeader = "[BULLETS CHAR]";
@ -97,28 +97,14 @@ public class BSCharacter : BSPhysObject
// set _avatarVolume and _mass based on capsule size, _density and Scale
ComputeAvatarVolumeAndMass();
DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
LocalID, _size, Scale, _avatarDensity, _avatarVolume, MassRaw);
ShapeData shapeData = new ShapeData();
shapeData.ID = LocalID;
shapeData.Type = ShapeData.PhysicsShapeType.SHAPE_AVATAR;
shapeData.Position = _position;
shapeData.Rotation = _orientation;
shapeData.Velocity = _velocity;
shapeData.Size = Scale; // capsule is a native shape but scale is not just <1,1,1>
shapeData.Scale = Scale;
shapeData.Mass = _mass;
shapeData.Buoyancy = _buoyancy;
shapeData.Static = ShapeData.numericFalse;
shapeData.Friction = PhysicsScene.Params.avatarStandingFriction;
shapeData.Restitution = PhysicsScene.Params.avatarRestitution;
LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
// do actual create at taint time
PhysicsScene.TaintedObject("BSCharacter.create", delegate()
{
DetailLog("{0},BSCharacter.create,taint", LocalID);
// New body and shape into BSBody and BSShape
PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this, shapeData, null, null, null);
// New body and shape into PhysBody and PhysShape
PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this, null, null);
SetPhysicalProperties();
});
@ -131,46 +117,45 @@ public class BSCharacter : BSPhysObject
DetailLog("{0},BSCharacter.Destroy", LocalID);
PhysicsScene.TaintedObject("BSCharacter.destroy", delegate()
{
PhysicsScene.Shapes.DereferenceBody(BSBody, true, null);
PhysicsScene.Shapes.DereferenceShape(BSShape, true, null);
PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null);
PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null);
});
}
private void SetPhysicalProperties()
{
BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, BSBody.ptr);
BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr);
ZeroMotion();
ZeroMotion(true);
ForcePosition = _position;
// Set the velocity and compute the proper friction
ForceVelocity = _velocity;
BulletSimAPI.SetRestitution2(BSBody.ptr, PhysicsScene.Params.avatarRestitution);
BulletSimAPI.SetMargin2(BSShape.ptr, PhysicsScene.Params.collisionMargin);
BulletSimAPI.SetLocalScaling2(BSShape.ptr, Scale);
BulletSimAPI.SetContactProcessingThreshold2(BSBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.avatarRestitution);
BulletSimAPI.SetMargin2(PhysShape.ptr, PhysicsScene.Params.collisionMargin);
BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale);
BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
if (PhysicsScene.Params.ccdMotionThreshold > 0f)
{
BulletSimAPI.SetCcdMotionThreshold2(BSBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
BulletSimAPI.SetCcdSweepSphereRadius2(BSBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
}
OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(BSShape.ptr, MassRaw);
BulletSimAPI.SetMassProps2(BSBody.ptr, MassRaw, localInertia);
UpdatePhysicalMassProperties(RawMass);
// Make so capsule does not fall over
BulletSimAPI.SetAngularFactorV2(BSBody.ptr, OMV.Vector3.Zero);
BulletSimAPI.SetAngularFactorV2(PhysBody.ptr, OMV.Vector3.Zero);
BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT);
BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT);
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, BSBody.ptr);
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr);
// BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG);
BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.DISABLE_DEACTIVATION);
BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, BSBody.ptr);
BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_DEACTIVATION);
BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr);
// Do this after the object has been added to the world
BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr,
BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr,
(uint)CollisionFilterGroups.AvatarFilter,
(uint)CollisionFilterGroups.AvatarMask);
}
@ -196,13 +181,12 @@ public class BSCharacter : BSPhysObject
ComputeAvatarScale(_size);
ComputeAvatarVolumeAndMass();
DetailLog("{0},BSCharacter.setSize,call,scale={1},density={2},volume={3},mass={4}",
LocalID, Scale, _avatarDensity, _avatarVolume, MassRaw);
LocalID, Scale, _avatarDensity, _avatarVolume, RawMass);
PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
{
BulletSimAPI.SetLocalScaling2(BSShape.ptr, Scale);
OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(BSShape.ptr, MassRaw);
BulletSimAPI.SetMassProps2(BSBody.ptr, MassRaw, localInertia);
BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale);
UpdatePhysicalMassProperties(RawMass);
});
}
@ -214,6 +198,11 @@ public class BSCharacter : BSPhysObject
{
set { BaseShape = value; }
}
// I want the physics engine to make an avatar capsule
public override ShapeData.PhysicsShapeType PreferredPhysicalShape
{
get {return ShapeData.PhysicsShapeType.SHAPE_AVATAR; }
}
public override bool Grabbed {
set { _grabbed = value; }
@ -229,23 +218,42 @@ public class BSCharacter : BSPhysObject
// Do it to the properties so the values get set in the physics engine.
// Push the setting of the values to the viewer.
// Called at taint time!
public override void ZeroMotion()
public override void ZeroMotion(bool inTaintTime)
{
_velocity = OMV.Vector3.Zero;
_acceleration = OMV.Vector3.Zero;
_rotationalVelocity = OMV.Vector3.Zero;
// Zero some other properties directly into the physics engine
BulletSimAPI.SetLinearVelocity2(BSBody.ptr, OMV.Vector3.Zero);
BulletSimAPI.SetAngularVelocity2(BSBody.ptr, OMV.Vector3.Zero);
BulletSimAPI.SetInterpolationVelocity2(BSBody.ptr, OMV.Vector3.Zero, OMV.Vector3.Zero);
BulletSimAPI.ClearForces2(BSBody.ptr);
PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
{
BulletSimAPI.ClearAllForces2(PhysBody.ptr);
});
}
public override void ZeroAngularMotion(bool inTaintTime)
{
_rotationalVelocity = OMV.Vector3.Zero;
PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
{
BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero);
BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero);
// The next also get rid of applied linear force but the linear velocity is untouched.
BulletSimAPI.ClearForces2(PhysBody.ptr);
});
}
public override void LockAngularMotion(OMV.Vector3 axis) { return; }
public override OMV.Vector3 RawPosition
{
get { return _position; }
set { _position = value; }
}
public override OMV.Vector3 Position {
get {
// Don't refetch the position because this function is called a zillion times
// _position = BulletSimAPI.GetObjectPosition2(Scene.World.ptr, LocalID);
return _position;
}
@ -256,19 +264,19 @@ public class BSCharacter : BSPhysObject
PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate()
{
DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
});
}
}
public override OMV.Vector3 ForcePosition {
get {
_position = BulletSimAPI.GetPosition2(BSBody.ptr);
_position = BulletSimAPI.GetPosition2(PhysBody.ptr);
return _position;
}
set {
_position = value;
PositionSanityCheck();
BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
}
}
@ -312,15 +320,11 @@ public class BSCharacter : BSPhysObject
{
// 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()
PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate()
{
DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
};
if (inTaintTime)
sanityOperation();
else
PhysicsScene.TaintedObject("BSCharacter.PositionSanityCheck", sanityOperation);
BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
});
ret = true;
}
return ret;
@ -329,7 +333,14 @@ public class BSCharacter : BSPhysObject
public override float Mass { get { return _mass; } }
// used when we only want this prim's mass and not the linkset thing
public override float MassRaw { get {return _mass; } }
public override float RawMass {
get {return _mass; }
}
public override void UpdatePhysicalMassProperties(float physMass)
{
OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass);
BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, localInertia);
}
public override OMV.Vector3 Force {
get { return _force; }
@ -339,7 +350,7 @@ public class BSCharacter : BSPhysObject
PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate()
{
DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
BulletSimAPI.SetObjectForce2(BSBody.ptr, _force);
BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force);
});
}
}
@ -378,7 +389,7 @@ public class BSCharacter : BSPhysObject
if (_currentFriction != PhysicsScene.Params.avatarStandingFriction)
{
_currentFriction = PhysicsScene.Params.avatarStandingFriction;
BulletSimAPI.SetFriction2(BSBody.ptr, _currentFriction);
BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction);
}
}
else
@ -386,15 +397,15 @@ public class BSCharacter : BSPhysObject
if (_currentFriction != PhysicsScene.Params.avatarFriction)
{
_currentFriction = PhysicsScene.Params.avatarFriction;
BulletSimAPI.SetFriction2(BSBody.ptr, _currentFriction);
BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction);
}
}
_velocity = value;
// Remember the set velocity so we can suppress the reduction by friction, ...
_appliedVelocity = value;
BulletSimAPI.SetLinearVelocity2(BSBody.ptr, _velocity);
BulletSimAPI.Activate2(BSBody.ptr, true);
BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
BulletSimAPI.Activate2(PhysBody.ptr, true);
}
}
public override OMV.Vector3 Torque {
@ -411,6 +422,11 @@ public class BSCharacter : BSPhysObject
get { return _acceleration; }
set { _acceleration = value; }
}
public override OMV.Quaternion RawOrientation
{
get { return _orientation; }
set { _orientation = value; }
}
public override OMV.Quaternion Orientation {
get { return _orientation; }
set {
@ -419,7 +435,7 @@ public class BSCharacter : BSPhysObject
PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate()
{
// _position = BulletSimAPI.GetPosition2(BSBody.ptr);
BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
});
}
}
@ -428,13 +444,13 @@ public class BSCharacter : BSPhysObject
{
get
{
_orientation = BulletSimAPI.GetOrientation2(BSBody.ptr);
_orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr);
return _orientation;
}
set
{
_orientation = value;
BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
}
}
public override int PhysicsActorType {
@ -493,9 +509,9 @@ public class BSCharacter : BSPhysObject
PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate()
{
if (_floatOnWater)
CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
else
CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
});
}
}
@ -528,7 +544,7 @@ public class BSCharacter : BSPhysObject
DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
// Buoyancy is faked by changing the gravity applied to the object
float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
BulletSimAPI.SetGravity2(BSBody.ptr, new OMV.Vector3(0f, 0f, grav));
BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav));
}
}
@ -574,7 +590,7 @@ public class BSCharacter : BSPhysObject
PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate()
{
DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force);
BulletSimAPI.SetObjectForce2(BSBody.ptr, _force);
BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force);
});
}
else
@ -642,7 +658,7 @@ public class BSCharacter : BSPhysObject
// That's just the way they are defined.
OMV.Vector3 avVel = new OMV.Vector3(_appliedVelocity.X, _appliedVelocity.Y, entprop.Velocity.Z);
_velocity = avVel;
BulletSimAPI.SetLinearVelocity2(BSBody.ptr, avVel);
BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, avVel);
}
// Tell the linkset about value changes

View File

@ -42,6 +42,12 @@ public abstract class BSConstraint : IDisposable
protected BulletConstraint m_constraint;
protected bool m_enabled = false;
public BulletBody Body1 { get { return m_body1; } }
public BulletBody Body2 { get { return m_body2; } }
public BulletConstraint Constraint { get { return m_constraint; } }
public abstract ConstraintType Type { get; }
public bool IsEnabled { get { return m_enabled; } }
public BSConstraint()
{
}
@ -64,12 +70,6 @@ public abstract class BSConstraint : IDisposable
}
}
public BulletBody Body1 { get { return m_body1; } }
public BulletBody Body2 { get { return m_body2; } }
public BulletConstraint Constraint { get { return m_constraint; } }
public abstract ConstraintType Type { get; }
public virtual bool SetLinearLimits(Vector3 low, Vector3 high)
{
bool ret = false;

View File

@ -32,14 +32,14 @@ using OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public class BS6DofConstraint : BSConstraint
public sealed class BSConstraint6Dof : BSConstraint
{
private static string LogHeader = "[BULLETSIM 6DOF CONSTRAINT]";
public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } }
// Create a btGeneric6DofConstraint
public BS6DofConstraint(BulletSim world, BulletBody obj1, BulletBody obj2,
public BSConstraint6Dof(BulletSim world, BulletBody obj1, BulletBody obj2,
Vector3 frame1, Quaternion frame1rot,
Vector3 frame2, Quaternion frame2rot,
bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
@ -58,7 +58,7 @@ public class BS6DofConstraint : BSConstraint
obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
}
public BS6DofConstraint(BulletSim world, BulletBody obj1, BulletBody obj2,
public BSConstraint6Dof(BulletSim world, BulletBody obj1, BulletBody obj2,
Vector3 joinPoint,
bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
{
@ -71,8 +71,7 @@ public class BS6DofConstraint : BSConstraint
BSScene.DetailLogZero, world.worldID,
obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
world.physicsScene.Logger.ErrorFormat("{0} Attempt to build 6DOF constraint with missing bodies: wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
"[BULLETSIM 6DOF CONSTRAINT]", world.worldID,
obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
LogHeader, world.worldID, obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
m_enabled = false;
}
else
@ -135,7 +134,11 @@ public class BS6DofConstraint : BSConstraint
bool ret = false;
float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
if (m_enabled)
{
ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.ptr, onOff, targetVelocity, maxMotorForce);
m_world.physicsScene.DetailLog("{0},BS6DOFConstraint,TransLimitMotor,enable={1},vel={2},maxForce={3}",
BSScene.DetailLogZero, enable, targetVelocity, maxMotorForce);
}
return ret;
}

View File

@ -33,7 +33,7 @@ using OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public class BSConstraintCollection : IDisposable
public sealed class BSConstraintCollection : IDisposable
{
// private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
// private static readonly string LogHeader = "[CONSTRAINT COLLECTION]";
@ -143,8 +143,6 @@ public class BSConstraintCollection : IDisposable
// Return 'true' if any constraints were destroyed.
public bool RemoveAndDestroyConstraint(BulletBody body1)
{
// return BulletSimAPI.RemoveConstraintByID(m_world.ID, obj.ID);
List<BSConstraint> toRemove = new List<BSConstraint>();
uint lookingID = body1.ID;
lock (m_constraints)

View File

@ -32,11 +32,11 @@ using OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin
{
class BSHingeConstraint : BSConstraint
public sealed class BSConstraintHinge : BSConstraint
{
public override ConstraintType Type { get { return ConstraintType.HINGE_CONSTRAINT_TYPE; } }
public BSHingeConstraint(BulletSim world, BulletBody obj1, BulletBody obj2,
public BSConstraintHinge(BulletSim world, BulletBody obj1, BulletBody obj2,
Vector3 pivotInA, Vector3 pivotInB,
Vector3 axisInA, Vector3 axisInB,
bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)

File diff suppressed because it is too large Load Diff

View File

@ -36,20 +36,32 @@ public abstract class BSLinkset
{
// private static string LogHeader = "[BULLETSIM LINKSET]";
public enum LinksetImplementation
{
Constraint = 0, // linkset tied together with constraints
Compound = 1, // linkset tied together as a compound object
Manual = 2 // linkset tied together manually (code moves all the pieces)
}
// Create the correct type of linkset for this child
public static BSLinkset Factory(BSScene physScene, BSPhysObject parent)
{
BSLinkset ret = null;
/*
if (parent.IsPhysical)
ret = new BSLinksetConstraints(physScene, parent);
else
ret = new BSLinksetManual(physScene, parent);
*/
// at the moment, there is only one
switch ((int)physScene.Params.linksetImplementation)
{
case (int)LinksetImplementation.Constraint:
ret = new BSLinksetConstraints(physScene, parent);
break;
case (int)LinksetImplementation.Compound:
ret = new BSLinksetCompound(physScene, parent);
break;
case (int)LinksetImplementation.Manual:
// ret = new BSLinksetManual(physScene, parent);
break;
default:
ret = new BSLinksetCompound(physScene, parent);
break;
}
return ret;
}
@ -61,33 +73,39 @@ public abstract class BSLinkset
public int LinksetID { get; private set; }
// The children under the root in this linkset.
// There are two lists of children: the current children at runtime
// and the children at taint-time. For instance, if you delink a
// child from the linkset, the child is removed from m_children
// but the constraint won't be removed until taint time.
// Two lists lets this track the 'current' children and
// the physical 'taint' children separately.
// After taint processing and before the simulation step, these
// two lists must be the same.
protected HashSet<BSPhysObject> m_children;
protected HashSet<BSPhysObject> m_taintChildren;
// We lock the diddling of linkset classes to prevent any badness.
// This locks the modification of the instances of this class. Changes
// to the physical representation is done via the tainting mechenism.
protected object m_linksetActivityLock = new Object();
// Some linksets have a preferred physical shape.
// Returns SHAPE_UNKNOWN if there is no preference. Causes the correct shape to be selected.
public virtual ShapeData.PhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor)
{
return ShapeData.PhysicsShapeType.SHAPE_UNKNOWN;
}
// Linksets move around the children so the linkset might need to compute the child position
public virtual OMV.Vector3 Position(BSPhysObject member)
{ return member.RawPosition; }
public virtual OMV.Quaternion Orientation(BSPhysObject member)
{ return member.RawOrientation; }
// TODO: does this need to be done for Velocity and RotationalVelocityy?
// We keep the prim's mass in the linkset structure since it could be dependent on other prims
protected float m_mass;
public float LinksetMass
{
get
{
m_mass = ComputeLinksetMass();
return m_mass;
}
}
public virtual bool LinksetIsColliding { get { return false; } }
public OMV.Vector3 CenterOfMass
{
get { return ComputeLinksetCenterOfMass(); }
@ -108,8 +126,7 @@ public abstract class BSLinkset
PhysicsScene = scene;
LinksetRoot = parent;
m_children = new HashSet<BSPhysObject>();
m_taintChildren = new HashSet<BSPhysObject>();
m_mass = parent.MassRaw;
m_mass = parent.RawMass;
}
// Link to a linkset where the child knows the parent.
@ -123,6 +140,7 @@ public abstract class BSLinkset
// Don't add the root to its own linkset
if (!IsRoot(child))
AddChildToLinkset(child);
m_mass = ComputeLinksetMass();
}
return this;
}
@ -140,8 +158,8 @@ public abstract class BSLinkset
// Cannot remove the root from a linkset.
return this;
}
RemoveChildFromLinkset(child);
m_mass = ComputeLinksetMass();
}
// The child is down to a linkset of just itself
@ -165,9 +183,8 @@ public abstract class BSLinkset
bool ret = false;
lock (m_linksetActivityLock)
{
if (m_children.Contains(child))
ret = true;
/*
ret = m_children.Contains(child);
/* Safer version but the above should work
foreach (BSPhysObject bp in m_children)
{
if (child.LocalID == bp.LocalID)
@ -181,10 +198,36 @@ public abstract class BSLinkset
return ret;
}
// Perform an action on each member of the linkset including root prim.
// Depends on the action on whether this should be done at taint time.
public delegate bool ForEachMemberAction(BSPhysObject obj);
public virtual bool ForEachMember(ForEachMemberAction action)
{
bool ret = false;
lock (m_linksetActivityLock)
{
action(LinksetRoot);
foreach (BSPhysObject po in m_children)
{
if (action(po))
break;
}
}
return ret;
}
// I am the root of a linkset and a new child is being added
// Called while LinkActivity is locked.
protected abstract void AddChildToLinkset(BSPhysObject child);
// I am the root of a linkset and one of my children is being removed.
// Safe to call even if the child is not really in my linkset.
protected abstract void RemoveChildFromLinkset(BSPhysObject child);
// When physical properties are changed the linkset needs to recalculate
// its internal properties.
// May be called at runtime or taint-time (just pass the appropriate flag).
public abstract void Refresh(BSPhysObject requestor, bool inTaintTime);
// May be called at runtime or taint-time.
public abstract void Refresh(BSPhysObject requestor);
// The object is going dynamic (physical). Do any setup necessary
// for a dynamic linkset.
@ -218,17 +261,17 @@ public abstract class BSLinkset
public abstract void RestoreBodyDependencies(BSPrim child);
// ================================================================
// Below this point is internal magic
protected virtual float ComputeLinksetMass()
{
float mass;
float mass = LinksetRoot.RawMass;
if (HasAnyChildren)
{
lock (m_linksetActivityLock)
{
mass = LinksetRoot.MassRaw;
foreach (BSPhysObject bp in m_taintChildren)
foreach (BSPhysObject bp in m_children)
{
mass += bp.MassRaw;
mass += bp.RawMass;
}
}
}
return mass;
@ -239,13 +282,13 @@ public abstract class BSLinkset
OMV.Vector3 com;
lock (m_linksetActivityLock)
{
com = LinksetRoot.Position * LinksetRoot.MassRaw;
float totalMass = LinksetRoot.MassRaw;
com = LinksetRoot.Position * LinksetRoot.RawMass;
float totalMass = LinksetRoot.RawMass;
foreach (BSPhysObject bp in m_taintChildren)
foreach (BSPhysObject bp in m_children)
{
com += bp.Position * bp.MassRaw;
totalMass += bp.MassRaw;
com += bp.Position * bp.RawMass;
totalMass += bp.RawMass;
}
if (totalMass != 0f)
com /= totalMass;
@ -261,31 +304,16 @@ public abstract class BSLinkset
{
com = LinksetRoot.Position;
foreach (BSPhysObject bp in m_taintChildren)
foreach (BSPhysObject bp in m_children)
{
com += bp.Position * bp.MassRaw;
com += bp.Position * bp.RawMass;
}
com /= (m_taintChildren.Count + 1);
com /= (m_children.Count + 1);
}
return com;
}
// I am the root of a linkset and a new child is being added
// Called while LinkActivity is locked.
protected abstract void AddChildToLinkset(BSPhysObject child);
// Forcefully removing a child from a linkset.
// This is not being called by the child so we have to make sure the child doesn't think
// it's still connected to the linkset.
// Normal OpenSimulator operation will never do this because other SceneObjectPart information
// also has to be updated (like pointer to prim's parent).
protected abstract void RemoveChildFromOtherLinkset(BSPhysObject pchild);
// I am the root of a linkset and one of my children is being removed.
// Safe to call even if the child is not really in my linkset.
protected abstract void RemoveChildFromLinkset(BSPhysObject child);
// Invoke the detailed logger and output something if it's enabled.
protected void DetailLog(string msg, params Object[] args)
{

View File

@ -0,0 +1,275 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyrightD
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Text;
using OMV = OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public sealed class BSLinksetCompound : BSLinkset
{
private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]";
public BSLinksetCompound(BSScene scene, BSPhysObject parent)
{
base.Initialize(scene, parent);
}
// For compound implimented linksets, if there are children, use compound shape for the root.
public override ShapeData.PhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor)
{
ShapeData.PhysicsShapeType ret = ShapeData.PhysicsShapeType.SHAPE_UNKNOWN;
if (IsRoot(requestor) && HasAnyChildren)
{
ret = ShapeData.PhysicsShapeType.SHAPE_COMPOUND;
}
// DetailLog("{0},BSLinksetCompound.PreferredPhysicalShape,call,shape={1}", LinksetRoot.LocalID, ret);
return ret;
}
// When physical properties are changed the linkset needs to recalculate
// its internal properties.
// This is queued in the 'post taint' queue so the
// refresh will happen once after all the other taints are applied.
public override void Refresh(BSPhysObject requestor)
{
// External request for Refresh (from BSPrim) is not necessary
// InternalRefresh(requestor);
}
private void InternalRefresh(BSPhysObject requestor)
{
DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,requestor={1}", LinksetRoot.LocalID, requestor.LocalID);
// Queue to happen after all the other taint processing
PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", requestor.LocalID, delegate()
{
if (IsRoot(requestor) && HasAnyChildren)
RecomputeLinksetCompound();
});
}
// The object is going dynamic (physical). Do any setup necessary
// for a dynamic linkset.
// Only the state of the passed object can be modified. The rest of the linkset
// has not yet been fully constructed.
// Return 'true' if any properties updated on the passed object.
// Called at taint-time!
public override bool MakeDynamic(BSPhysObject child)
{
bool ret = false;
DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
if (!IsRoot(child))
{
// Physical children are removed from the world as the shape ofthe root compound
// shape takes over.
BulletSimAPI.AddToCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
BulletSimAPI.ForceActivationState2(child.PhysBody.ptr, ActivationState.DISABLE_SIMULATION);
ret = true;
}
return ret;
}
// The object is going static (non-physical). Do any setup necessary for a static linkset.
// Return 'true' if any properties updated on the passed object.
// This doesn't normally happen -- OpenSim removes the objects from the physical
// world if it is a static linkset.
// Called at taint-time!
public override bool MakeStatic(BSPhysObject child)
{
bool ret = false;
DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
if (!IsRoot(child))
{
// The non-physical children can come back to life.
BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
// Don't force activation so setting of DISABLE_SIMULATION can stay.
BulletSimAPI.Activate2(child.PhysBody.ptr, false);
ret = true;
}
return ret;
}
// Called at taint-time!!
public override void UpdateProperties(BSPhysObject updated)
{
// Nothing to do for constraints on property updates
}
// The children move around in relationship to the root.
// Just grab the current values of wherever it is right now.
public override OMV.Vector3 Position(BSPhysObject member)
{
return BulletSimAPI.GetPosition2(member.PhysBody.ptr);
}
public override OMV.Quaternion Orientation(BSPhysObject member)
{
return BulletSimAPI.GetOrientation2(member.PhysBody.ptr);
}
// Routine called when rebuilding the body of some member of the linkset.
// Since we don't keep in world relationships, do nothing unless it's a child changing.
// Returns 'true' of something was actually removed and would need restoring
// Called at taint-time!!
public override bool RemoveBodyDependencies(BSPrim child)
{
bool ret = false;
DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}",
child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), IsRoot(child));
if (!IsRoot(child))
{
// Cause the current shape to be freed and the new one to be built.
InternalRefresh(LinksetRoot);
ret = true;
}
return ret;
}
// Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
// this routine will restore the removed constraints.
// Called at taint-time!!
public override void RestoreBodyDependencies(BSPrim child)
{
// The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints.
}
// ================================================================
// Add a new child to the linkset.
// Called while LinkActivity is locked.
protected override void AddChildToLinkset(BSPhysObject child)
{
if (!HasChild(child))
{
m_children.Add(child);
DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
// Cause constraints and assorted properties to be recomputed before the next simulation step.
InternalRefresh(LinksetRoot);
}
return;
}
// Remove the specified child from the linkset.
// Safe to call even if the child is not really in my linkset.
protected override void RemoveChildFromLinkset(BSPhysObject child)
{
if (m_children.Remove(child))
{
DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
child.LocalID,
LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"),
child.LocalID, child.PhysBody.ptr.ToString("X"));
// Cause the child's body to be rebuilt and thus restored to normal operation
child.ForceBodyShapeRebuild(false);
if (!HasAnyChildren)
{
// The linkset is now empty. The root needs rebuilding.
LinksetRoot.ForceBodyShapeRebuild(false);
}
else
{
// Schedule a rebuild of the linkset before the next simulation tick.
InternalRefresh(LinksetRoot);
}
}
return;
}
// Called before the simulation step to make sure the compound based linkset
// is all initialized.
// Constraint linksets are rebuilt every time.
// Note that this works for rebuilding just the root after a linkset is taken apart.
// Called at taint time!!
private void RecomputeLinksetCompound()
{
// Cause the root shape to be rebuilt as a compound object with just the root in it
LinksetRoot.ForceBodyShapeRebuild(true);
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}",
LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren);
// Add a shape for each of the other children in the linkset
ForEachMember(delegate(BSPhysObject cPrim)
{
if (!IsRoot(cPrim))
{
// Each child position and rotation is given relative to the root.
OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation);
OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation;
OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation;
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}",
LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, displacementPos, displacementRot);
if (cPrim.PhysShape.isNativeShape)
{
// Native shapes are not shared so we need to create a new one.
// A mesh or hull is created because scale is not available on a native shape.
// (TODO: Bullet does have a btScaledCollisionShape. Can that be used?)
BulletShape saveShape = cPrim.PhysShape;
cPrim.PhysShape.ptr = IntPtr.Zero; // Don't let the create free the child's shape
PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
BulletShape newShape = cPrim.PhysShape;
cPrim.PhysShape = saveShape;
BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot);
}
else
{
// For the shared shapes (meshes and hulls), just use the shape in the child.
if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape))
{
PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}",
LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape);
}
BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, displacementPos, displacementRot);
}
}
return false; // 'false' says to move onto the next child in the list
});
// With all of the linkset packed into the root prim, it has the mass of everyone.
float linksetMass = LinksetMass;
LinksetRoot.UpdatePhysicalMassProperties(linksetMass);
BulletSimAPI.RecalculateCompoundShapeLocalAabb2(LinksetRoot.PhysShape.ptr);
// DEBUG: see of inter-linkset collisions are causing problems for constraint linksets.
// BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr,
// (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask);
}
}
}

View File

@ -32,7 +32,7 @@ using OMV = OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public class BSLinksetConstraints : BSLinkset
public sealed class BSLinksetConstraints : BSLinkset
{
// private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]";
@ -43,23 +43,16 @@ public class BSLinksetConstraints : BSLinkset
// When physical properties are changed the linkset needs to recalculate
// its internal properties.
// May be called at runtime or taint-time (just pass the appropriate flag).
public override void Refresh(BSPhysObject requestor, bool inTaintTime)
// This is queued in the 'post taint' queue so the
// refresh will happen once after all the other taints are applied.
public override void Refresh(BSPhysObject requestor)
{
// If there are no children or not root, I am not the one that recomputes the constraints
if (!HasAnyChildren || !IsRoot(requestor))
return;
BSScene.TaintCallback refreshOperation = delegate()
// Queue to happen after all the other taint processing
PhysicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate()
{
RecomputeLinksetConstraintVariables();
DetailLog("{0},BSLinkset.Refresh,complete,rBody={1}",
LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
};
if (inTaintTime)
refreshOperation();
else
PhysicsScene.TaintedObject("BSLinkSet.Refresh", refreshOperation);
if (HasAnyChildren && IsRoot(requestor))
RecomputeLinksetConstraints();
});
}
// The object is going dynamic (physical). Do any setup necessary
@ -74,9 +67,10 @@ public class BSLinksetConstraints : BSLinkset
return false;
}
// The object is going static (non-physical). Do any setup necessary
// for a static linkset.
// The object is going static (non-physical). Do any setup necessary for a static linkset.
// Return 'true' if any properties updated on the passed object.
// This doesn't normally happen -- OpenSim removes the objects from the physical
// world if it is a static linkset.
// Called at taint-time!
public override bool MakeStatic(BSPhysObject child)
{
@ -90,35 +84,36 @@ public class BSLinksetConstraints : BSLinkset
// Nothing to do for constraints on property updates
}
// Routine used when rebuilding the body of the root of the linkset
// Destroy all the constraints have have been made to root.
// This is called when the root body is changing.
// Returns 'true' of something eas actually removed and would need restoring
// The children of the linkset are moved around by the constraints.
// Just grab the current values of wherever it is right now.
public override OMV.Vector3 Position(BSPhysObject member)
{
return BulletSimAPI.GetPosition2(member.PhysBody.ptr);
}
public override OMV.Quaternion Orientation(BSPhysObject member)
{
return BulletSimAPI.GetOrientation2(member.PhysBody.ptr);
}
// Routine called when rebuilding the body of some member of the linkset.
// Destroy all the constraints have have been made to root and set
// up to rebuild the constraints before the next simulation step.
// Returns 'true' of something was actually removed and would need restoring
// Called at taint-time!!
public override bool RemoveBodyDependencies(BSPrim child)
{
bool ret = false;
DetailLog("{0},BSLinksetConstraint.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}",
child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"));
lock (m_linksetActivityLock)
{
if (IsRoot(child))
{
// If the one with the dependency is root, must undo all children
DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}",
child.LocalID, LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
// Just undo all the constraints for this linkset. Rebuild at the end of the step.
ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
}
else
{
DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
child.LocalID,
LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
child.LocalID, child.BSBody.ptr.ToString("X"));
// ret = PhysicallyUnlinkAChildFromRoot(LinksetRoot, child);
// Despite the function name, this removes any link to the specified object.
ret = PhysicallyUnlinkAllChildrenFromRoot(child);
}
// Cause the constraints, et al to be rebuilt before the next simulation step.
Refresh(LinksetRoot);
}
return ret;
}
@ -128,32 +123,12 @@ public class BSLinksetConstraints : BSLinkset
// Called at taint-time!!
public override void RestoreBodyDependencies(BSPrim child)
{
lock (m_linksetActivityLock)
{
if (IsRoot(child))
{
DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreChildrenForRoot,rID={1},numChild={2}",
child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count);
foreach (BSPhysObject bpo in m_taintChildren)
{
PhysicallyLinkAChildToRoot(LinksetRoot, bpo);
}
}
else
{
DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
LinksetRoot.LocalID,
LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
child.LocalID, child.BSBody.ptr.ToString("X"));
PhysicallyLinkAChildToRoot(LinksetRoot, child);
}
}
// The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints.
}
// ================================================================
// Below this point is internal magic
// I am the root of a linkset and a new child is being added
// Add a new child to the linkset.
// Called while LinkActivity is locked.
protected override void AddChildToLinkset(BSPhysObject child)
{
@ -161,39 +136,15 @@ public class BSLinksetConstraints : BSLinkset
{
m_children.Add(child);
BSPhysObject rootx = LinksetRoot; // capture the root as of now
BSPhysObject childx = child;
DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
DetailLog("{0},AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
PhysicsScene.TaintedObject("AddChildToLinkset", delegate()
{
DetailLog("{0},AddChildToLinkset,taint,rID={1},rBody={2},cID={3},cBody={4}",
rootx.LocalID,
rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
childx.LocalID, childx.BSBody.ptr.ToString("X"));
// Since this is taint-time, the body and shape could have changed for the child
rootx.ForcePosition = rootx.Position; // DEBUG
childx.ForcePosition = childx.Position; // DEBUG
PhysicallyLinkAChildToRoot(rootx, childx);
m_taintChildren.Add(child);
});
// Cause constraints and assorted properties to be recomputed before the next simulation step.
Refresh(LinksetRoot);
}
return;
}
// Forcefully removing a child from a linkset.
// This is not being called by the child so we have to make sure the child doesn't think
// it's still connected to the linkset.
// Normal OpenSimulator operation will never do this because other SceneObjectPart information
// also has to be updated (like pointer to prim's parent).
protected override void RemoveChildFromOtherLinkset(BSPhysObject pchild)
{
pchild.Linkset = BSLinkset.Factory(PhysicsScene, pchild);
RemoveChildFromLinkset(pchild);
}
// I am the root of a linkset and one of my children is being removed.
// Remove the specified child from the linkset.
// Safe to call even if the child is not really in my linkset.
protected override void RemoveChildFromLinkset(BSPhysObject child)
{
@ -202,22 +153,21 @@ public class BSLinksetConstraints : BSLinkset
BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
BSPhysObject childx = child;
DetailLog("{0},RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
childx.LocalID,
rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
childx.LocalID, childx.BSBody.ptr.ToString("X"));
rootx.LocalID, rootx.PhysBody.ptr.ToString("X"),
childx.LocalID, childx.PhysBody.ptr.ToString("X"));
PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate()
PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate()
{
m_taintChildren.Remove(child);
PhysicallyUnlinkAChildFromRoot(rootx, childx);
RecomputeLinksetConstraintVariables();
});
// See that the linkset parameters are recomputed at the end of the taint time.
Refresh(LinksetRoot);
}
else
{
// This will happen if we remove the root of the linkset first. Non-fatal occurance.
// Non-fatal occurance.
// PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader);
}
return;
@ -226,9 +176,15 @@ public class BSLinksetConstraints : BSLinkset
// Create a constraint between me (root of linkset) and the passed prim (the child).
// Called at taint time!
private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
{
// Don't build the constraint when asked. Put it off until just before the simulation step.
Refresh(rootPrim);
}
private BSConstraint BuildConstraint(BSPhysObject rootPrim, BSPhysObject childPrim)
{
// Zero motion for children so they don't interpolate
childPrim.ZeroMotion();
childPrim.ZeroMotion(true);
// Relative position normalized to the root prim
// Essentually a vector pointing from center of rootPrim to center of childPrim
@ -237,22 +193,23 @@ public class BSLinksetConstraints : BSLinkset
// real world coordinate of midpoint between the two objects
OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
DetailLog("{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
rootPrim.LocalID,
rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"),
childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"),
rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString("X"),
childPrim.LocalID, childPrim.PhysBody.ptr.ToString("X"),
rootPrim.Position, childPrim.Position, midPoint);
// create a constraint that allows no freedom of movement between the two objects
// http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
BS6DofConstraint constrain = new BS6DofConstraint(
PhysicsScene.World, rootPrim.BSBody, childPrim.BSBody, midPoint, true, true );
BSConstraint6Dof constrain = new BSConstraint6Dof(
PhysicsScene.World, rootPrim.PhysBody, childPrim.PhysBody, midPoint, true, true );
// PhysicsScene.World, childPrim.BSBody, rootPrim.BSBody, midPoint, true, true );
/* NOTE: below is an attempt to build constraint with full frame computation, etc.
* Using the midpoint is easier since it lets the Bullet code manipulate the transforms
* of the objects.
* Code left as a warning to future programmers.
* Code left for future programmers.
// ==================================================================================
// relative position normalized to the root prim
OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
@ -262,20 +219,13 @@ public class BSLinksetConstraints : BSLinkset
OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);
// create a constraint that allows no freedom of movement between the two objects
// http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
DetailLog("{0},BSLinksetConstraint.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
BS6DofConstraint constrain = new BS6DofConstraint(
PhysicsScene.World, rootPrim.Body, childPrim.Body,
OMV.Vector3.Zero,
OMV.Quaternion.Inverse(rootPrim.Orientation),
OMV.Vector3.Zero,
OMV.Quaternion.Inverse(childPrim.Orientation),
// A point half way between the parent and child
// childRelativePosition/2,
// childRelativeRotation,
// childRelativePosition/2,
// inverseChildRelativeRotation,
true,
true
);
@ -298,25 +248,26 @@ public class BSLinksetConstraints : BSLinkset
{
constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations);
}
return constrain;
}
// Remove linkage between myself and a particular child
// Remove linkage between the linkset root and a particular child
// The root and child bodies are passed in because we need to remove the constraint between
// the bodies that were at unlink time.
// the bodies that were present at unlink time.
// Called at taint time!
private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
{
bool ret = false;
DetailLog("{0},BSLinkset.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
rootPrim.LocalID,
rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"),
childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"));
rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString("X"),
childPrim.LocalID, childPrim.PhysBody.ptr.ToString("X"));
// Find the constraint for this link and get rid of it from the overall collection and from my list
if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody, childPrim.BSBody))
if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody))
{
// Make the child refresh its location
BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr);
BulletSimAPI.PushUpdate2(childPrim.PhysBody.ptr);
ret = true;
}
@ -324,62 +275,53 @@ public class BSLinksetConstraints : BSLinkset
}
// Remove linkage between myself and any possible children I might have.
// Returns 'true' of any constraints were destroyed.
// Called at taint time!
private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
{
DetailLog("{0},BSLinkset.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
bool ret = false;
DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody))
{
ret = true;
}
return ret;
return PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody);
}
// Call each of the constraints that make up this linkset and recompute the
// various transforms and variables. Used when objects are added or removed
// from a linkset to make sure the constraints know about the new mass and
// geometry.
// Must only be called at taint time!!
private void RecomputeLinksetConstraintVariables()
// various transforms and variables. Create constraints of not created yet.
// Called before the simulation step to make sure the constraint based linkset
// is all initialized.
// Called at taint time!!
private void RecomputeLinksetConstraints()
{
float linksetMass = LinksetMass;
foreach (BSPhysObject child in m_taintChildren)
LinksetRoot.UpdatePhysicalMassProperties(linksetMass);
// DEBUG: see of inter-linkset collisions are causing problems
// BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr,
// (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask);
DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}",
LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), linksetMass);
foreach (BSPhysObject child in m_children)
{
// A child in the linkset physically shows the mass of the whole linkset.
// This allows Bullet to apply enough force on the child to move the whole linkset.
// (Also do the mass stuff before recomputing the constraint so mass is not zero.)
child.UpdatePhysicalMassProperties(linksetMass);
BSConstraint constrain;
if (PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.BSBody, child.BSBody, out constrain))
if (!PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain))
{
// DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,taint,child={1},mass={2},A={3},B={4}",
// LinksetRoot.LocalID, child.LocalID, linksetMass, constrain.Body1.ID, constrain.Body2.ID);
// If constraint doesn't exist yet, create it.
constrain = BuildConstraint(LinksetRoot, child);
}
constrain.RecomputeConstraintVariables(linksetMass);
}
else
{
// Non-fatal error that happens when children are being added to the linkset but
// their constraints have not been created yet.
break;
}
// DEBUG: see of inter-linkset collisions are causing problems
// BulletSimAPI.SetCollisionFilterMask2(child.BSBody.ptr,
// (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask);
// BulletSimAPI.DumpConstraint2(PhysicsScene.World.ptr, constrain.Constraint.ptr); // DEBUG DEBUG
}
// If the whole linkset is not here, doesn't make sense to recompute linkset wide values
if (m_children.Count == m_taintChildren.Count)
{
// If this is a multiple object linkset, set everybody's center of mass to the set's center of mass
OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass();
BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.ptr,
centerOfMass, OMV.Quaternion.Identity);
DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,setCenterOfMass,COM={1},rBody={2}",
LinksetRoot.LocalID, centerOfMass, LinksetRoot.BSBody.ptr.ToString("X"));
foreach (BSPhysObject child in m_taintChildren)
{
BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.ptr,
centerOfMass, OMV.Quaternion.Identity);
}
// BulletSimAPI.DumpAllInfo2(PhysicsScene.World.ptr); // DEBUG DEBUG DEBUG
}
return;
}
}
}

View File

@ -0,0 +1,104 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public abstract class BSMotor
{
public virtual void Reset() { }
public virtual void Zero() { }
}
// Can all the incremental stepping be replaced with motor classes?
public class BSVMotor : BSMotor
{
public Vector3 FrameOfReference { get; set; }
public Vector3 Offset { get; set; }
public float TimeScale { get; set; }
public float TargetValueDecayTimeScale { get; set; }
public Vector3 CurrentValueReductionTimescale { get; set; }
public float Efficiency { get; set; }
public Vector3 TargetValue { get; private set; }
public Vector3 CurrentValue { get; private set; }
BSVMotor(float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency)
{
TimeScale = timeScale;
TargetValueDecayTimeScale = decayTimeScale;
CurrentValueReductionTimescale = frictionTimeScale;
Efficiency = efficiency;
}
public void SetCurrent(Vector3 current)
{
CurrentValue = current;
}
public void SetTarget(Vector3 target)
{
TargetValue = target;
}
public Vector3 Step(float timeStep)
{
if (CurrentValue.LengthSquared() > 0.001f)
{
// Vector3 origDir = Target; // DEBUG
// Vector3 origVel = CurrentValue; // DEBUG
// Add (desiredVelocity - currentAppliedVelocity) / howLongItShouldTakeToComplete
Vector3 addAmount = (TargetValue - CurrentValue)/(TargetValue) * timeStep;
CurrentValue += addAmount;
float decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep;
TargetValue *= (1f - decayFactor);
Vector3 frictionFactor = (Vector3.One / CurrentValueReductionTimescale) * timeStep;
CurrentValue *= (Vector3.One - frictionFactor);
}
else
{
// if what remains of direction is very small, zero it.
TargetValue = Vector3.Zero;
CurrentValue = Vector3.Zero;
// VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID);
}
return CurrentValue;
}
}
public class BSFMotor : BSMotor
{
public float TimeScale { get; set; }
public float DecayTimeScale { get; set; }
public float Friction { get; set; }
public float Efficiency { get; set; }
public float Target { get; private set; }
public float CurrentValue { get; private set; }
BSFMotor(float timeScale, float decayTimescale, float friction, float efficiency)
{
}
public void SetCurrent(float target)
{
}
public void SetTarget(float target)
{
}
public float Step(float timeStep)
{
return 0f;
}
}
public class BSPIDMotor : BSMotor
{
// TODO: write and use this one
BSPIDMotor()
{
}
}
}

View File

@ -34,9 +34,17 @@ using OpenSim.Region.Physics.Manager;
namespace OpenSim.Region.Physics.BulletSPlugin
{
// Class to wrap all objects.
// The rest of BulletSim doesn't need to keep checking for avatars or prims
// unless the difference is significant.
/*
* Class to wrap all objects.
* The rest of BulletSim doesn't need to keep checking for avatars or prims
* unless the difference is significant.
*
* Variables in the physicsl objects are in three forms:
* VariableName: used by the simulator and performs taint operations, etc
* RawVariableName: direct reference to the BulletSim storage for the variable value
* ForceVariableName: direct reference (store and fetch) to the value in the physics engine.
* The last two (and certainly the last one) should be referenced only in taint-time.
*/
public abstract class BSPhysObject : PhysicsActor
{
protected void BaseInitialize(BSScene parentScene, uint localID, string name, string typeName)
@ -63,12 +71,17 @@ public abstract class BSPhysObject : PhysicsActor
public BSLinkset Linkset { get; set; }
// Return the object mass without calculating it or having side effects
public abstract float MassRaw { get; }
public abstract float RawMass { get; }
// Set the raw mass but also update physical mass properties (inertia, ...)
public abstract void UpdatePhysicalMassProperties(float mass);
// The last value calculated for the prim's inertia
public OMV.Vector3 Inertia { get; set; }
// Reference to the physical body (btCollisionObject) of this object
public BulletBody BSBody;
public BulletBody PhysBody;
// Reference to the physical shape (btCollisionShape) of this object
public BulletShape BSShape;
public BulletShape PhysShape;
// 'true' if the mesh's underlying asset failed to build.
// This will keep us from looping after the first time the build failed.
@ -76,6 +89,12 @@ public abstract class BSPhysObject : PhysicsActor
// The objects base shape information. Null if not a prim type shape.
public PrimitiveBaseShape BaseShape { get; protected set; }
// Some types of objects have preferred physical representations.
// Returns SHAPE_UNKNOWN if there is no preference.
public virtual ShapeData.PhysicsShapeType PreferredPhysicalShape
{
get { return ShapeData.PhysicsShapeType.SHAPE_UNKNOWN; }
}
// When the physical properties are updated, an EntityProperty holds the update values.
// Keep the current and last EntityProperties to enable computation of differences
@ -88,7 +107,8 @@ public abstract class BSPhysObject : PhysicsActor
public abstract bool IsStatic { get; }
// Stop all physical motion.
public abstract void ZeroMotion();
public abstract void ZeroMotion(bool inTaintTime);
public abstract void ZeroAngularMotion(bool inTaintTime);
// Step the vehicle simulation for this object. A NOOP if the vehicle was not configured.
public virtual void StepVehicle(float timeStep) { }
@ -99,8 +119,10 @@ public abstract class BSPhysObject : PhysicsActor
// Tell the object to clean up.
public abstract void Destroy();
public abstract OMV.Vector3 RawPosition { get; set; }
public abstract OMV.Vector3 ForcePosition { get; set; }
public abstract OMV.Quaternion RawOrientation { get; set; }
public abstract OMV.Quaternion ForceOrientation { get; set; }
public abstract OMV.Vector3 ForceVelocity { get; set; }
@ -204,7 +226,7 @@ public abstract class BSPhysObject : PhysicsActor
PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate()
{
CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
});
}
else
@ -218,7 +240,7 @@ public abstract class BSPhysObject : PhysicsActor
SubscribedEventsMs = 0;
PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate()
{
CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
});
}
// Return 'true' if the simulator wants collision events

View File

@ -25,8 +25,6 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Uncomment this it enable code to do all shape an body memory management
// in the C# code.
using System;
using System.Reflection;
using System.Collections.Generic;
@ -111,8 +109,8 @@ public sealed class BSPrim : BSPhysObject
_mass = CalculateMass();
// No body or shape yet
BSBody = new BulletBody(LocalID, IntPtr.Zero);
BSShape = new BulletShape(IntPtr.Zero);
PhysBody = new BulletBody(LocalID, IntPtr.Zero);
PhysShape = new BulletShape(IntPtr.Zero);
DetailLog("{0},BSPrim.constructor,call", LocalID);
// do the actual object creation at taint time
@ -120,7 +118,7 @@ public sealed class BSPrim : BSPhysObject
{
CreateGeomAndObject(true);
CurrentCollisionFlags = BulletSimAPI.GetCollisionFlags2(BSBody.ptr);
CurrentCollisionFlags = BulletSimAPI.GetCollisionFlags2(PhysBody.ptr);
});
}
@ -145,8 +143,8 @@ public sealed class BSPrim : BSPhysObject
{
DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
// If there are physical body and shape, release my use of same.
PhysicsScene.Shapes.DereferenceBody(BSBody, true, null);
PhysicsScene.Shapes.DereferenceShape(BSShape, true, null);
PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null);
PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null);
});
}
@ -171,18 +169,18 @@ public sealed class BSPrim : BSPhysObject
ForceBodyShapeRebuild(false);
}
}
// Whatever the linkset wants is what I want.
public override ShapeData.PhysicsShapeType PreferredPhysicalShape
{ get { return Linkset.PreferredPhysicalShape(this); } }
public override bool ForceBodyShapeRebuild(bool inTaintTime)
{
LastAssetBuildFailed = false;
BSScene.TaintCallback rebuildOperation = delegate()
PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate()
{
_mass = CalculateMass(); // changing the shape changes the mass
CreateGeomAndObject(true);
};
if (inTaintTime)
rebuildOperation();
else
PhysicsScene.TaintedObject("BSPrim.ForceBodyShapeRebuild", rebuildOperation);
});
return true;
}
public override bool Grabbed {
@ -236,14 +234,27 @@ public sealed class BSPrim : BSPhysObject
// Do it to the properties so the values get set in the physics engine.
// Push the setting of the values to the viewer.
// Called at taint time!
public override void ZeroMotion()
public override void ZeroMotion(bool inTaintTime)
{
_velocity = OMV.Vector3.Zero;
_acceleration = OMV.Vector3.Zero;
_rotationalVelocity = OMV.Vector3.Zero;
// Zero some other properties directly into the physics engine
BulletSimAPI.ClearForces2(BSBody.ptr);
// Zero some other properties in the physics engine
PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
{
BulletSimAPI.ClearAllForces2(PhysBody.ptr);
});
}
public override void ZeroAngularMotion(bool inTaintTime)
{
_rotationalVelocity = OMV.Vector3.Zero;
// Zero some other properties in the physics engine
PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
{
BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero);
BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero);
});
}
public override void LockAngularMotion(OMV.Vector3 axis)
@ -252,11 +263,16 @@ public sealed class BSPrim : BSPhysObject
return;
}
public override OMV.Vector3 RawPosition
{
get { return _position; }
set { _position = value; }
}
public override OMV.Vector3 Position {
get {
if (!Linkset.IsRoot(this))
// child prims move around based on their parent. Need to get the latest location
_position = BulletSimAPI.GetPosition2(BSBody.ptr);
if (!Linkset.IsRoot(this))
_position = Linkset.Position(this);
// don't do the GetObjectPosition for root elements because this function is called a zillion times
// _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr);
@ -274,19 +290,21 @@ public sealed class BSPrim : BSPhysObject
PhysicsScene.TaintedObject("BSPrim.setPosition", delegate()
{
// DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
ActivateIfPhysical(false);
});
}
}
public override OMV.Vector3 ForcePosition {
get {
_position = BulletSimAPI.GetPosition2(BSBody.ptr);
_position = BulletSimAPI.GetPosition2(PhysBody.ptr);
return _position;
}
set {
_position = value;
PositionSanityCheck();
BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
ActivateIfPhysical(false);
}
}
@ -311,6 +329,7 @@ public sealed class BSPrim : BSPhysObject
if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
{
float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position);
// TODO: a floating motor so object will bob in the water
if (Position.Z < waterHeight)
{
_position.Z = waterHeight;
@ -332,16 +351,11 @@ public sealed class BSPrim : BSPhysObject
{
// 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()
PhysicsScene.TaintedObject(inTaintTime, "BSPrim.PositionSanityCheck", delegate()
{
DetailLog("{0},BSPrim.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
ForcePosition = _position;
};
if (inTaintTime)
sanityOperation();
else
PhysicsScene.TaintedObject("BSPrim.PositionSanityCheck", sanityOperation);
});
ret = true;
}
return ret;
@ -353,13 +367,35 @@ public sealed class BSPrim : BSPhysObject
{
get
{
// return Linkset.LinksetMass;
return _mass;
return Linkset.LinksetMass;
// return _mass;
}
}
// used when we only want this prim's mass and not the linkset thing
public override float MassRaw { get { return _mass; } }
public override float RawMass {
get { return _mass; }
}
// Set the physical mass to the passed mass.
// Note that this does not change _mass!
public override void UpdatePhysicalMassProperties(float physMass)
{
if (IsStatic)
{
Inertia = OMV.Vector3.Zero;
BulletSimAPI.SetMassProps2(PhysBody.ptr, 0f, Inertia);
BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr);
}
else
{
Inertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass);
BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, Inertia);
BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr);
// center of mass is at the zero of the object
// DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(PhysBody.ptr, ForcePosition, ForceOrientation);
DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2}", LocalID, physMass, Inertia);
}
}
// Is this used?
public override OMV.Vector3 CenterOfMass
@ -380,7 +416,7 @@ public sealed class BSPrim : BSPhysObject
PhysicsScene.TaintedObject("BSPrim.setForce", delegate()
{
// DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force);
BulletSimAPI.SetObjectForce2(BSBody.ptr, _force);
BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force);
});
}
}
@ -400,6 +436,7 @@ public sealed class BSPrim : BSPhysObject
// Done at taint time so we're sure the physics engine is not using the variables
// Vehicle code changes the parameters for this vehicle type.
_vehicle.ProcessTypeChange(type);
ActivateIfPhysical(false);
});
}
}
@ -408,6 +445,7 @@ public sealed class BSPrim : BSPhysObject
PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate()
{
_vehicle.ProcessFloatVehicleParam((Vehicle)param, value);
ActivateIfPhysical(false);
});
}
public override void VehicleVectorParam(int param, OMV.Vector3 value)
@ -415,6 +453,7 @@ public sealed class BSPrim : BSPhysObject
PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate()
{
_vehicle.ProcessVectorVehicleParam((Vehicle)param, value);
ActivateIfPhysical(false);
});
}
public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
@ -422,6 +461,7 @@ public sealed class BSPrim : BSPhysObject
PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate()
{
_vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation);
ActivateIfPhysical(false);
});
}
public override void VehicleFlags(int param, bool remove)
@ -436,9 +476,16 @@ public sealed class BSPrim : BSPhysObject
// Called from Scene when doing simulation step so we're in taint processing time.
public override void StepVehicle(float timeStep)
{
if (IsPhysical)
if (IsPhysical && _vehicle.IsActive)
{
_vehicle.Step(timeStep);
/* // TEST TEST DEBUG DEBUG -- trying to reduce the extra action of Bullet simulation step
PhysicsScene.PostTaintObject("BSPrim.StepVehicles", LocalID, delegate()
{
// This resets the interpolation values and recomputes the tensor variables
BulletSimAPI.SetCenterOfMassByPosRot2(BSBody.ptr, ForcePosition, ForceOrientation);
});
*/
}
}
@ -463,7 +510,7 @@ public sealed class BSPrim : BSPhysObject
PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate()
{
// DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity);
BulletSimAPI.SetLinearVelocity2(BSBody.ptr, _velocity);
BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
});
}
}
@ -471,12 +518,14 @@ public sealed class BSPrim : BSPhysObject
get { return _velocity; }
set {
_velocity = value;
BulletSimAPI.SetLinearVelocity2(BSBody.ptr, _velocity);
BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
}
}
public override OMV.Vector3 Torque {
get { return _torque; }
set { _torque = value;
set {
_torque = value;
AddAngularForce(_torque, false, false);
// DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque);
}
}
@ -489,12 +538,17 @@ public sealed class BSPrim : BSPhysObject
get { return _acceleration; }
set { _acceleration = value; }
}
public override OMV.Quaternion RawOrientation
{
get { return _orientation; }
set { _orientation = value; }
}
public override OMV.Quaternion Orientation {
get {
// Children move around because tied to parent. Get a fresh value.
if (!Linkset.IsRoot(this))
{
// Children move around because tied to parent. Get a fresh value.
_orientation = BulletSimAPI.GetOrientation2(BSBody.ptr);
_orientation = Linkset.Orientation(this);
}
return _orientation;
}
@ -507,7 +561,7 @@ public sealed class BSPrim : BSPhysObject
{
// _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr);
// DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation);
BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
});
}
}
@ -516,13 +570,13 @@ public sealed class BSPrim : BSPhysObject
{
get
{
_orientation = BulletSimAPI.GetOrientation2(BSBody.ptr);
_orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr);
return _orientation;
}
set
{
_orientation = value;
BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
}
}
public override int PhysicsActorType {
@ -539,6 +593,8 @@ public sealed class BSPrim : BSPhysObject
{
// DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
SetObjectDynamic(true);
// whether phys-to-static or static-to-phys, the object is not moving.
ZeroMotion(true);
});
}
}
@ -576,7 +632,7 @@ public sealed class BSPrim : BSPhysObject
// Mangling all the physical properties requires the object not be in the physical world.
// 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);
BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr);
// Set up the object physicalness (does gravity and collisions move this object)
MakeDynamic(IsStatic);
@ -590,24 +646,25 @@ public sealed class BSPrim : BSPhysObject
// Make solid or not (do things bounce off or pass through this object).
MakeSolid(IsSolid);
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, BSBody.ptr);
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr);
// Rebuild its shape
BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, BSBody.ptr);
BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr);
// Collision filter can be set only when the object is in the world
if (BSBody.collisionFilter != 0 || BSBody.collisionMask != 0)
if (PhysBody.collisionFilter != 0 || PhysBody.collisionMask != 0)
{
BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr, (uint)BSBody.collisionFilter, (uint)BSBody.collisionMask);
BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr, (uint)PhysBody.collisionFilter, (uint)PhysBody.collisionMask);
}
// Recompute any linkset parameters.
// When going from non-physical to physical, this re-enables the constraints that
// had been automatically disabled when the mass was set to zero.
Linkset.Refresh(this, true);
// For compound based linksets, this enables and disables interactions of the children.
Linkset.Refresh(this);
DetailLog("{0},BSPrim.UpdatePhysicalParameters,exit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}",
LocalID, IsStatic, IsSolid, _mass, SubscribedEvents(), CurrentCollisionFlags, BSBody, BSShape);
DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}",
LocalID, IsStatic, IsSolid, _mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody, PhysShape);
}
// "Making dynamic" means changing to and from static.
@ -620,75 +677,74 @@ public sealed class BSPrim : BSPhysObject
if (makeStatic)
{
// Become a Bullet 'static' object type
CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
// Stop all movement
BulletSimAPI.ClearAllForces2(BSBody.ptr);
ZeroMotion(true);
// Center of mass is at the center of the object
BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.BSBody.ptr, _position, _orientation);
// DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation);
// Mass is zero which disables a bunch of physics stuff in Bullet
BulletSimAPI.SetMassProps2(BSBody.ptr, 0f, OMV.Vector3.Zero);
// There is no inertia in a static object
BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr);
UpdatePhysicalMassProperties(0f);
// Set collision detection parameters
if (PhysicsScene.Params.ccdMotionThreshold > 0f)
{
BulletSimAPI.SetCcdMotionThreshold2(BSBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
BulletSimAPI.SetCcdSweepSphereRadius2(BSBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
}
// There can be special things needed for implementing linksets
Linkset.MakeStatic(this);
// The activation state is 'disabled' so Bullet will not try to act on it.
BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.DISABLE_SIMULATION);
BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_SIMULATION);
// Start it out sleeping and physical actions could wake it up.
// BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING);
BSBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter;
BSBody.collisionMask = CollisionFilterGroups.StaticObjectMask;
PhysBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter;
PhysBody.collisionMask = CollisionFilterGroups.StaticObjectMask;
}
else
{
// Not a Bullet static object
CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
// Set various physical properties so internal dynamic properties will get computed correctly as they are set
BulletSimAPI.SetFriction2(BSBody.ptr, PhysicsScene.Params.defaultFriction);
BulletSimAPI.SetRestitution2(BSBody.ptr, PhysicsScene.Params.defaultRestitution);
BulletSimAPI.SetFriction2(PhysBody.ptr, PhysicsScene.Params.defaultFriction);
BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.defaultRestitution);
// per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
BulletSimAPI.ClearAllForces2(BSBody.ptr);
// Since this can be called multiple times, only zero forces when becoming physical
// BulletSimAPI.ClearAllForces2(BSBody.ptr);
// For good measure, make sure the transform is set through to the motion state
BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
// Center of mass is at the center of the object
// DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation);
// A dynamic object has mass
IntPtr collisionShapePtr = BulletSimAPI.GetCollisionShape2(BSBody.ptr);
OMV.Vector3 inertia = BulletSimAPI.CalculateLocalInertia2(collisionShapePtr, Mass);
BulletSimAPI.SetMassProps2(BSBody.ptr, _mass, inertia);
BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr);
UpdatePhysicalMassProperties(RawMass);
// Set collision detection parameters
if (PhysicsScene.Params.ccdMotionThreshold > 0f)
{
BulletSimAPI.SetCcdMotionThreshold2(BSBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
BulletSimAPI.SetCcdSweepSphereRadius2(BSBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
}
// Various values for simulation limits
BulletSimAPI.SetDamping2(BSBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping);
BulletSimAPI.SetDeactivationTime2(BSBody.ptr, PhysicsScene.Params.deactivationTime);
BulletSimAPI.SetSleepingThresholds2(BSBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold);
BulletSimAPI.SetContactProcessingThreshold2(BSBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
BulletSimAPI.SetDamping2(PhysBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping);
BulletSimAPI.SetDeactivationTime2(PhysBody.ptr, PhysicsScene.Params.deactivationTime);
BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold);
BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
// There might be special things needed for implementing linksets.
Linkset.MakeDynamic(this);
// Force activation of the object so Bullet will act on it.
// Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG);
BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG);
// BulletSimAPI.Activate2(BSBody.ptr, true);
BSBody.collisionFilter = CollisionFilterGroups.ObjectFilter;
BSBody.collisionMask = CollisionFilterGroups.ObjectMask;
PhysBody.collisionFilter = CollisionFilterGroups.ObjectFilter;
PhysBody.collisionMask = CollisionFilterGroups.ObjectMask;
}
}
@ -698,7 +754,7 @@ public sealed class BSPrim : BSPhysObject
// the functions after this one set up the state of a possibly newly created collision body.
private void MakeSolid(bool makeSolid)
{
CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(BSBody.ptr);
CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(PhysBody.ptr);
if (makeSolid)
{
// Verify the previous code created the correct shape for this type of thing.
@ -706,7 +762,7 @@ public sealed class BSPrim : BSPhysObject
{
m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType);
}
CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
}
else
{
@ -714,22 +770,31 @@ public sealed class BSPrim : BSPhysObject
{
m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
}
CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
BSBody.collisionFilter = CollisionFilterGroups.VolumeDetectFilter;
BSBody.collisionMask = CollisionFilterGroups.VolumeDetectMask;
CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
PhysBody.collisionFilter = CollisionFilterGroups.VolumeDetectFilter;
PhysBody.collisionMask = CollisionFilterGroups.VolumeDetectMask;
}
}
// Enable physical actions. Bullet will keep sleeping non-moving physical objects so
// they need waking up when parameters are changed.
// Called in taint-time!!
private void ActivateIfPhysical(bool forceIt)
{
if (IsPhysical)
BulletSimAPI.Activate2(PhysBody.ptr, forceIt);
}
// Turn on or off the flag controlling whether collision events are returned to the simulator.
private void EnableCollisions(bool wantsCollisionEvents)
{
if (wantsCollisionEvents)
{
CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
}
else
{
CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
}
}
@ -774,9 +839,9 @@ public sealed class BSPrim : BSPhysObject
PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate()
{
if (_floatOnWater)
CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
else
CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
});
}
}
@ -798,8 +863,8 @@ public sealed class BSPrim : BSPhysObject
// m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate()
{
// DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
BulletSimAPI.SetAngularVelocity2(BSBody.ptr, _rotationalVelocity);
DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
});
}
}
@ -809,7 +874,7 @@ public sealed class BSPrim : BSPhysObject
}
set {
_rotationalVelocity = value;
BulletSimAPI.SetAngularVelocity2(BSBody.ptr, _rotationalVelocity);
BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
}
}
public override bool Kinematic {
@ -835,7 +900,7 @@ public sealed class BSPrim : BSPhysObject
// DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
// Buoyancy is faked by changing the gravity applied to the object
float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
BulletSimAPI.SetGravity2(BSBody.ptr, new OMV.Vector3(0f, 0f, grav));
BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav));
}
}
@ -888,7 +953,7 @@ public sealed class BSPrim : BSPhysObject
m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
return;
}
BSScene.TaintCallback addForceOperation = delegate()
PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate()
{
OMV.Vector3 fSum = OMV.Vector3.Zero;
lock (m_accumulatedForces)
@ -900,20 +965,69 @@ public sealed class BSPrim : BSPhysObject
}
m_accumulatedForces.Clear();
}
// DetailLog("{0},BSPrim.AddObjectForce,taint,force={1}", LocalID, fSum);
// For unknown reasons, "ApplyCentralForce" adds this force to the total force on the object.
BulletSimAPI.ApplyCentralForce2(BSBody.ptr, fSum);
};
if (inTaintTime)
addForceOperation();
else
PhysicsScene.TaintedObject("BSPrim.AddForce", addForceOperation);
DetailLog("{0},BSPrim.AddForce,taint,force={1}", LocalID, fSum);
if (fSum != OMV.Vector3.Zero)
BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, fSum);
});
}
public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
// DetailLog("{0},BSPrim.AddAngularForce,call,angForce={1},push={2}", LocalID, force, pushforce);
// m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce);
public void ApplyForceImpulse(OMV.Vector3 impulse, bool inTaintTime)
{
OMV.Vector3 applyImpulse = impulse;
PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyForceImpulse", delegate()
{
DetailLog("{0},BSPrim.ApplyForceImpulse,taint,tImpulse={1}", LocalID, applyImpulse);
BulletSimAPI.ApplyCentralImpulse2(PhysBody.ptr, applyImpulse);
});
}
private List<OMV.Vector3> m_accumulatedAngularForces = new List<OMV.Vector3>();
public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
AddAngularForce(force, pushforce, false);
}
public void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime)
{
if (force.IsFinite())
{
// _force += force;
lock (m_accumulatedAngularForces)
m_accumulatedAngularForces.Add(new OMV.Vector3(force));
}
else
{
m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
return;
}
PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate()
{
OMV.Vector3 fSum = OMV.Vector3.Zero;
lock (m_accumulatedAngularForces)
{
// Sum the accumulated additional forces for one big force to apply once.
foreach (OMV.Vector3 v in m_accumulatedAngularForces)
{
fSum += v;
}
m_accumulatedAngularForces.Clear();
}
DetailLog("{0},BSPrim.AddAngularForce,taint,aForce={1}", LocalID, fSum);
if (fSum != OMV.Vector3.Zero)
{
BulletSimAPI.ApplyTorque2(PhysBody.ptr, fSum);
_torque = fSum;
}
});
}
// A torque impulse.
public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime)
{
OMV.Vector3 applyImpulse = impulse;
PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate()
{
BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse);
});
}
public override void SetMomentum(OMV.Vector3 momentum) {
// DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum);
}
@ -1195,9 +1309,7 @@ public sealed class BSPrim : BSPhysObject
returnMass = _density * volume;
/*
* This change means each object keeps its own mass and the Mass property
* will return the sum if we're part of a linkset.
/* Comment out code that computes the mass of the linkset. That is done in the Linkset class.
if (IsRootOfLinkset)
{
foreach (BSPrim prim in _childrenPrims)
@ -1217,49 +1329,27 @@ public sealed class BSPrim : BSPhysObject
}// end CalculateMass
#endregion Mass Calculation
// Copy prim's info into the BulletSim shape description structure
public void FillShapeInfo(out ShapeData shape)
{
shape.ID = LocalID;
shape.Type = ShapeData.PhysicsShapeType.SHAPE_UNKNOWN;
shape.Position = _position;
shape.Rotation = _orientation;
shape.Velocity = _velocity;
shape.Size = _size;
shape.Scale = Scale;
shape.Mass = _isPhysical ? _mass : 0f;
shape.Buoyancy = _buoyancy;
shape.HullKey = 0;
shape.MeshKey = 0;
shape.Friction = _friction;
shape.Restitution = _restitution;
shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse;
shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue;
shape.Solid = IsSolid ? ShapeData.numericFalse : ShapeData.numericTrue;
}
// Rebuild the geometry and object.
// This is called when the shape changes so we need to recreate the mesh/hull.
// Called at taint-time!!!
private void CreateGeomAndObject(bool forceRebuild)
{
ShapeData shapeData;
FillShapeInfo(out shapeData);
// If this prim is part of a linkset, we must remove and restore the physical
// links if the body is rebuilt.
bool needToRestoreLinkset = false;
bool needToRestoreVehicle = false;
// Create the correct physical representation for this type of object.
// Updates BSBody and BSShape with the new information.
// Updates PhysBody and PhysShape with the new information.
// Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary.
// Returns 'true' if either the body or the shape was changed.
PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, shapeData, BaseShape,
null, delegate(BulletBody dBody)
PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody)
{
// Called if the current prim body is about to be destroyed.
// Remove all the physical dependencies on the old body.
// (Maybe someday make the changing of BSShape an event handled by BSLinkset.)
needToRestoreLinkset = Linkset.RemoveBodyDependencies(this);
needToRestoreVehicle = _vehicle.RemoveBodyDependencies(this);
});
if (needToRestoreLinkset)
@ -1267,6 +1357,11 @@ public sealed class BSPrim : BSPhysObject
// If physical body dependencies were removed, restore them
Linkset.RestoreBodyDependencies(this);
}
if (needToRestoreVehicle)
{
// If physical body dependencies were removed, restore them
_vehicle.RestoreBodyDependencies(this);
}
// Make sure the properties are set on the new object
UpdatePhysicalParameters();
@ -1353,8 +1448,9 @@ public sealed class BSPrim : BSPhysObject
PositionSanityCheck(true);
DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation;
DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}",
LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity);
// BulletSimAPI.DumpRigidBody2(PhysicsScene.World.ptr, BSBody.ptr); // DEBUG DEBUG DEBUG

View File

@ -62,7 +62,7 @@ using OpenMetaverse;
//
namespace OpenSim.Region.Physics.BulletSPlugin
{
public class BSScene : PhysicsScene, IPhysicsParameters
public sealed class BSScene : PhysicsScene, IPhysicsParameters
{
private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private static readonly string LogHeader = "[BULLETS SCENE]";
@ -116,6 +116,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// True if initialized and ready to do simulation steps
private bool m_initialized = false;
// Flag which is true when processing taints.
// Not guaranteed to be correct all the time (don't depend on this) but good for debugging.
public bool InTaintTime { get; private set; }
// Pinned memory used to pass step information between managed and unmanaged
private int m_maxCollisionsPerFrame;
private CollisionDesc[] m_collisionArray;
@ -171,7 +175,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
}
}
private Object _taintLock = new Object(); // lock for using the next object
private List<TaintCallbackEntry> _taintedObjects;
private List<TaintCallbackEntry> _taintOperations;
private Dictionary<string, TaintCallbackEntry> _postTaintOperations;
private List<TaintCallbackEntry> _postStepOperations;
// A pointer to an instance if this structure is passed to the C++ code
// Used to pass basic configuration values to the unmanaged code.
@ -203,7 +209,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
public override void Initialise(IMesher meshmerizer, IConfigSource config)
{
mesher = meshmerizer;
_taintedObjects = new List<TaintCallbackEntry>();
_taintOperations = new List<TaintCallbackEntry>();
_postTaintOperations = new Dictionary<string, TaintCallbackEntry>();
_postStepOperations = new List<TaintCallbackEntry>();
PhysObjects = new Dictionary<uint, BSPhysObject>();
Shapes = new BSShapeCollection(this);
@ -266,6 +274,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
TerrainManager = new BSTerrainManager(this);
TerrainManager.CreateInitialGroundPlaneAndTerrain();
m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)Params.linksetImplementation);
InTaintTime = false;
m_initialized = true;
}
@ -475,23 +486,20 @@ public class BSScene : PhysicsScene, IPhysicsParameters
if (!m_initialized) return 5.0f;
// update the prim states while we know the physics engine is not busy
int numTaints = _taintedObjects.Count;
int numTaints = _taintOperations.Count;
ProcessTaints();
// Some of the prims operate with special vehicle properties
ProcessVehicles(timeStep);
numTaints += _taintedObjects.Count;
ProcessTaints(); // the vehicles might have added taints
// step the physical world one interval
m_simulationStep++;
int numSubSteps = 0;
// DEBUG
// DetailLog("{0},BSScene.Simulate,beforeStep,ntaimts={1},step={2}", DetailLogZero, numTaints, m_simulationStep);
try
{
if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG
if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount();
numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep,
@ -500,6 +508,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime);
DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}",
DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount);
if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG
}
catch (Exception e)
{
@ -511,7 +520,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters
collidersCount = 0;
}
// Don't have to use the pointers passed back since we know it is the same pinned memory we passed in
// Get a value for 'now' so all the collision and update routines don't have to get their own
@ -575,6 +583,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
}
}
ProcessPostStepTaints();
// This causes the unmanaged code to output ALL the values found in ALL the objects in the world.
// Only enable this in a limited test world with few objects.
// BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG
@ -670,6 +680,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
public override bool IsThreaded { get { return false; } }
#region Taints
// Calls to the PhysicsActors can't directly call into the physics engine
// because it might be busy. We delay changes to a known time.
// We rely on C#'s closure to save and restore the context for the delegate.
@ -679,30 +691,51 @@ public class BSScene : PhysicsScene, IPhysicsParameters
lock (_taintLock)
{
_taintedObjects.Add(new TaintCallbackEntry(ident, callback));
_taintOperations.Add(new TaintCallbackEntry(ident, callback));
}
return;
}
// Sometimes a potentially tainted operation can be used in and out of taint time.
// This routine executes the command immediately if in taint-time otherwise it is queued.
public void TaintedObject(bool inTaintTime, string ident, TaintCallback callback)
{
if (inTaintTime)
callback();
else
TaintedObject(ident, callback);
}
// When someone tries to change a property on a BSPrim or BSCharacter, the object queues
// a callback into itself to do the actual property change. That callback is called
// here just before the physics engine is called to step the simulation.
public void ProcessTaints()
{
if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process
InTaintTime = true;
ProcessRegularTaints();
ProcessPostTaintTaints();
InTaintTime = false;
}
private void ProcessRegularTaints()
{
if (_taintOperations.Count > 0) // save allocating new list if there is nothing to process
{
/*
// Code to limit the number of taints processed per step. Meant to limit step time.
// Unsure if a good idea as code assumes that taints are done before the step.
int taintCount = m_taintsToProcessPerStep;
TaintCallbackEntry oneCallback = new TaintCallbackEntry();
while (_taintedObjects.Count > 0 && taintCount-- > 0)
while (_taintOperations.Count > 0 && taintCount-- > 0)
{
bool gotOne = false;
lock (_taintLock)
{
if (_taintedObjects.Count > 0)
if (_taintOperations.Count > 0)
{
oneCallback = _taintedObjects[0];
_taintedObjects.RemoveAt(0);
oneCallback = _taintOperations[0];
_taintOperations.RemoveAt(0);
gotOne = true;
}
}
@ -720,13 +753,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
}
}
}
/*
if (_taintOperations.Count > 0)
{
DetailLog("{0},BSScene.ProcessTaints,leftTaintsOnList,numNotProcessed={1}", DetailLogZero, _taintOperations.Count);
}
*/
// swizzle a new list into the list location so we can process what's there
List<TaintCallbackEntry> oldList;
lock (_taintLock)
{
oldList = _taintedObjects;
_taintedObjects = new List<TaintCallbackEntry>();
oldList = _taintOperations;
_taintOperations = new List<TaintCallbackEntry>();
}
foreach (TaintCallbackEntry tcbe in oldList)
@ -742,10 +779,104 @@ public class BSScene : PhysicsScene, IPhysicsParameters
}
}
oldList.Clear();
*/
}
}
// Schedule an update to happen after all the regular taints are processed.
// Note that new requests for the same operation ("ident") for the same object ("ID")
// will replace any previous operation by the same object.
public void PostTaintObject(String ident, uint ID, TaintCallback callback)
{
if (!m_initialized) return;
string uniqueIdent = ident + "-" + ID.ToString();
lock (_taintLock)
{
_postTaintOperations[uniqueIdent] = new TaintCallbackEntry(uniqueIdent, callback);
}
return;
}
private void ProcessPostTaintTaints()
{
if (_postTaintOperations.Count > 0)
{
Dictionary<string, TaintCallbackEntry> oldList;
lock (_taintLock)
{
oldList = _postTaintOperations;
_postTaintOperations = new Dictionary<string, TaintCallbackEntry>();
}
foreach (KeyValuePair<string,TaintCallbackEntry> kvp in oldList)
{
try
{
DetailLog("{0},BSScene.ProcessPostTaintTaints,doTaint,id={1}", DetailLogZero, kvp.Key); // DEBUG DEBUG DEBUG
kvp.Value.callback();
}
catch (Exception e)
{
m_log.ErrorFormat("{0}: ProcessPostTaintTaints: {1}: Exception: {2}", LogHeader, kvp.Key, e);
}
}
oldList.Clear();
}
}
public void PostStepTaintObject(String ident, TaintCallback callback)
{
if (!m_initialized) return;
lock (_taintLock)
{
_postStepOperations.Add(new TaintCallbackEntry(ident, callback));
}
return;
}
private void ProcessPostStepTaints()
{
if (_postStepOperations.Count > 0)
{
List<TaintCallbackEntry> oldList;
lock (_taintLock)
{
oldList = _postStepOperations;
_postStepOperations = new List<TaintCallbackEntry>();
}
foreach (TaintCallbackEntry tcbe in oldList)
{
try
{
DetailLog("{0},BSScene.ProcessPostStepTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG
tcbe.callback();
}
catch (Exception e)
{
m_log.ErrorFormat("{0}: ProcessPostStepTaints: {1}: Exception: {2}", LogHeader, tcbe.ident, e);
}
}
oldList.Clear();
}
}
public bool AssertInTaintTime(string whereFrom)
{
if (!InTaintTime)
{
DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom);
m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom);
Util.PrintCallStack();
}
return InTaintTime;
}
#endregion // Taints
#region Vehicles
public void VehicleInSceneTypeChanged(BSPrim vehic, Vehicle newType)
@ -916,7 +1047,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
(s) => { return (float)s.m_maxUpdatesPerFrame; },
(s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step",
100f,
500f,
(s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); },
(s) => { return (float)s.m_taintsToProcessPerStep; },
(s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ),
@ -970,49 +1101,49 @@ public class BSScene : PhysicsScene, IPhysicsParameters
(s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].linearDamping; },
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearDamping, p, l, v); },
(s,o,v) => { BulletSimAPI.SetDamping2(o.BSBody.ptr, v, v); } ),
(s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, v, s.m_params[0].angularDamping); } ),
new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
0f,
(s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].angularDamping; },
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularDamping, p, l, v); },
(s,o,v) => { BulletSimAPI.SetDamping2(o.BSBody.ptr, v, v); } ),
(s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, s.m_params[0].linearDamping, v); } ),
new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
0.2f,
(s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].deactivationTime; },
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].deactivationTime, p, l, v); },
(s,o,v) => { BulletSimAPI.SetDeactivationTime2(o.BSBody.ptr, v); } ),
(s,o,v) => { BulletSimAPI.SetDeactivationTime2(o.PhysBody.ptr, v); } ),
new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
0.8f,
(s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].linearSleepingThreshold; },
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearSleepingThreshold, p, l, v); },
(s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.BSBody.ptr, v, v); } ),
(s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ),
new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
1.0f,
(s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].angularSleepingThreshold; },
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularSleepingThreshold, p, l, v); },
(s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.BSBody.ptr, v, v); } ),
(s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ),
new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
0f, // set to zero to disable
(s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].ccdMotionThreshold; },
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdMotionThreshold, p, l, v); },
(s,o,v) => { BulletSimAPI.SetCcdMotionThreshold2(o.BSBody.ptr, v); } ),
(s,o,v) => { BulletSimAPI.SetCcdMotionThreshold2(o.PhysBody.ptr, v); } ),
new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
0f,
(s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].ccdSweptSphereRadius; },
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); },
(s,o,v) => { BulletSimAPI.SetCcdSweepSphereRadius2(o.BSBody.ptr, v); } ),
(s,o,v) => { BulletSimAPI.SetCcdSweptSphereRadius2(o.PhysBody.ptr, v); } ),
new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" ,
0.1f,
(s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].contactProcessingThreshold; },
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); },
(s,o,v) => { BulletSimAPI.SetContactProcessingThreshold2(o.BSBody.ptr, v); } ),
(s,o,v) => { BulletSimAPI.SetContactProcessingThreshold2(o.PhysBody.ptr, v); } ),
new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
0.5f,
@ -1107,6 +1238,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
(s) => { return s.m_params[0].numberOfSolverIterations; },
(s,p,l,v) => { s.m_params[0].numberOfSolverIterations = v; } ),
new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)",
(float)BSLinkset.LinksetImplementation.Compound,
(s,cf,p,v) => { s.m_params[0].linksetImplementation = cf.GetFloat(p,v); },
(s) => { return s.m_params[0].linksetImplementation; },
(s,p,l,v) => { s.m_params[0].linksetImplementation = v; } ),
new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
ConfigurationParameters.numericFalse,
(s,cf,p,v) => { s.m_params[0].linkConstraintUseFrameOffset = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
@ -1128,12 +1264,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
(s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; },
(s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ),
new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1",
0.001f,
0.1f,
(s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].linkConstraintCFM; },
(s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ),
new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2",
0.8f,
0.1f,
(s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].linkConstraintERP; },
(s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ),
@ -1259,7 +1395,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// If the local ID is APPLY_TO_NONE, just change the default value
// If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs
// If the localID is a specific object, apply the parameter change to only that object
protected void UpdateParameterObject(ref float defaultLoc, string parm, uint localID, float val)
private void UpdateParameterObject(ref float defaultLoc, string parm, uint localID, float val)
{
List<uint> objectIDs = new List<uint>();
switch (localID)
@ -1284,7 +1420,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
}
// schedule the actual updating of the paramter to when the phys engine is not busy
protected void TaintedUpdateParameter(string parm, List<uint> lIDs, float val)
private void TaintedUpdateParameter(string parm, List<uint> lIDs, float val)
{
float xval = val;
List<uint> xlIDs = lIDs;
@ -1326,11 +1462,21 @@ public class BSScene : PhysicsScene, IPhysicsParameters
#endregion Runtime settable parameters
// Debugging routine for dumping detailed physical information for vehicle prims
private void DumpVehicles()
{
foreach (BSPrim prim in m_vehicles)
{
BulletSimAPI.DumpRigidBody2(World.ptr, prim.PhysBody.ptr);
BulletSimAPI.DumpCollisionShape2(World.ptr, prim.PhysShape.ptr);
}
}
// Invoke the detailed logger and output something if it's enabled.
public void DetailLog(string msg, params Object[] args)
{
PhysicsLogging.Write(msg, args);
// Add the Flush() if debugging crashes to get all the messages written out.
// Add the Flush() if debugging crashes. Gets all the messages written out.
// PhysicsLogging.Flush();
}
// Used to fill in the LocalID when there isn't one. It's the correct number of characters.

View File

@ -34,11 +34,11 @@ using OpenSim.Region.Physics.ConvexDecompositionDotNet;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public class BSShapeCollection : IDisposable
public sealed class BSShapeCollection : IDisposable
{
private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]";
protected BSScene PhysicsScene { get; set; }
private BSScene PhysicsScene { get; set; }
private Object m_collectionActivityLock = new Object();
@ -48,6 +48,7 @@ public class BSShapeCollection : IDisposable
public IntPtr ptr;
public int referenceCount;
public DateTime lastReferenced;
public UInt64 shapeKey;
}
// Description of a hull.
@ -57,6 +58,7 @@ public class BSShapeCollection : IDisposable
public IntPtr ptr;
public int referenceCount;
public DateTime lastReferenced;
public UInt64 shapeKey;
}
// The sharable set of meshes and hulls. Indexed by their shape hash.
@ -90,9 +92,10 @@ public class BSShapeCollection : IDisposable
// remove the physical constraints before the body is destroyed.
// Called at taint-time!!
public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim,
ShapeData shapeData, PrimitiveBaseShape pbs,
ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
{
PhysicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape");
bool ret = false;
// This lock could probably be pushed down lower but building shouldn't take long
@ -100,41 +103,38 @@ public class BSShapeCollection : IDisposable
{
// Do we have the correct geometry for this type of object?
// Updates prim.BSShape with information/pointers to shape.
// CreateGeom returns 'true' of BSShape as changed to a new shape.
bool newGeom = CreateGeom(forceRebuild, prim, shapeData, pbs, shapeCallback);
// Returns 'true' of BSShape is changed to a new shape.
bool newGeom = CreateGeom(forceRebuild, prim, shapeCallback);
// 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
// Returns 'true' if BSBody was changed.
bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World,
prim.BSShape, shapeData, bodyCallback);
prim.PhysShape, bodyCallback);
ret = newGeom || newBody;
}
DetailLog("{0},BSShapeCollection.GetBodyAndShape,force={1},ret={2},body={3},shape={4}",
prim.LocalID, forceRebuild, ret, prim.BSBody, prim.BSShape);
DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}",
prim.LocalID, forceRebuild, ret, prim.PhysBody, prim.PhysShape);
return ret;
}
// Track another user of a body
// Track another user of a body.
// We presume the caller has allocated the body.
// Bodies only have one user so the body is just put into the world if not already there.
public void ReferenceBody(BulletBody body, bool inTaintTime)
{
lock (m_collectionActivityLock)
{
DetailLog("{0},BSShapeCollection.ReferenceBody,newBody", body.ID, body);
BSScene.TaintCallback createOperation = delegate()
DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body);
PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate()
{
if (!BulletSimAPI.IsInWorld2(body.ptr))
{
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr);
DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
}
};
if (inTaintTime)
createOperation();
else
PhysicsScene.TaintedObject("BSShapeCollection.ReferenceBody", createOperation);
});
}
}
@ -147,25 +147,23 @@ public class BSShapeCollection : IDisposable
lock (m_collectionActivityLock)
{
BSScene.TaintCallback removeOperation = delegate()
PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate()
{
DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}, inTaintTime={2}",
body.ID, body.ptr.ToString("X"), inTaintTime);
DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}",
body.ID, body, inTaintTime);
// If the caller needs to know the old body is going away, pass the event up.
if (bodyCallback != null) bodyCallback(body);
// It may have already been removed from the world in which case the next is a NOOP.
if (BulletSimAPI.IsInWorld2(body.ptr))
{
BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr);
DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body);
}
// Zero any reference to the shape so it is not freed when the body is deleted.
BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero);
BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr);
};
// If already in taint-time, do the operations now. Otherwise queue for later.
if (inTaintTime)
removeOperation();
else
PhysicsScene.TaintedObject("BSShapeCollection.DereferenceBody", removeOperation);
});
}
}
@ -175,7 +173,7 @@ public class BSShapeCollection : IDisposable
// Meshes and hulls for the same shape have the same hash key.
// NOTE that native shapes are not added to the mesh list or removed.
// Returns 'true' if this is the initial reference to the shape. Otherwise reused.
private bool ReferenceShape(BulletShape shape)
public bool ReferenceShape(BulletShape shape)
{
bool ret = false;
switch (shape.type)
@ -193,6 +191,7 @@ public class BSShapeCollection : IDisposable
{
// This is a new reference to a mesh
meshDesc.ptr = shape.ptr;
meshDesc.shapeKey = shape.shapeKey;
// We keep a reference to the underlying IMesh data so a hull can be built
meshDesc.referenceCount = 1;
DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}",
@ -215,6 +214,7 @@ public class BSShapeCollection : IDisposable
{
// This is a new reference to a hull
hullDesc.ptr = shape.ptr;
hullDesc.shapeKey = shape.shapeKey;
hullDesc.referenceCount = 1;
DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}",
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
@ -239,7 +239,7 @@ public class BSShapeCollection : IDisposable
if (shape.ptr == IntPtr.Zero)
return;
BSScene.TaintCallback dereferenceOperation = delegate()
PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate()
{
if (shape.ptr != IntPtr.Zero)
{
@ -261,6 +261,9 @@ public class BSShapeCollection : IDisposable
case ShapeData.PhysicsShapeType.SHAPE_MESH:
DereferenceMesh(shape, shapeCallback);
break;
case ShapeData.PhysicsShapeType.SHAPE_COMPOUND:
DereferenceCompound(shape, shapeCallback);
break;
case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN:
break;
default:
@ -268,18 +271,7 @@ public class BSShapeCollection : IDisposable
}
}
}
};
if (inTaintTime)
{
lock (m_collectionActivityLock)
{
dereferenceOperation();
}
}
else
{
PhysicsScene.TaintedObject("BSShapeCollection.DereferenceShape", dereferenceOperation);
}
});
}
// Count down the reference count for a mesh shape
@ -294,8 +286,8 @@ public class BSShapeCollection : IDisposable
if (shapeCallback != null) shapeCallback(shape);
meshDesc.lastReferenced = System.DateTime.Now;
Meshes[shape.shapeKey] = meshDesc;
DetailLog("{0},BSShapeCollection.DereferenceMesh,key={1},refCnt={2}",
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}",
BSScene.DetailLogZero, shape, meshDesc.referenceCount);
}
}
@ -309,11 +301,94 @@ public class BSShapeCollection : IDisposable
{
hullDesc.referenceCount--;
// TODO: release the Bullet storage (aging old entries?)
// Tell upper layers that, if they have dependencies on this shape, this link is going away
if (shapeCallback != null) shapeCallback(shape);
hullDesc.lastReferenced = System.DateTime.Now;
Hulls[shape.shapeKey] = hullDesc;
DetailLog("{0},BSShapeCollection.DereferenceHull,key={1},refCnt={2}",
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}",
BSScene.DetailLogZero, shape, hullDesc.referenceCount);
}
}
// Remove a reference to a compound shape.
// Taking a compound shape apart is a little tricky because if you just delete the
// physical shape, it will free all the underlying children. We can't do that because
// they could be shared. So, this removes each of the children from the compound and
// dereferences them separately before destroying the compound collision object itself.
// Called at taint-time.
private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback)
{
if (!BulletSimAPI.IsCompound2(shape.ptr))
{
// Failed the sanity check!!
PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}",
LogHeader, shape.type, shape.ptr.ToString("X"));
DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
BSScene.DetailLogZero, shape.type, shape.ptr.ToString("X"));
return;
}
int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr);
DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren);
for (int ii = numChildren - 1; ii >= 0; ii--)
{
IntPtr childShape = BulletSimAPI.RemoveChildShapeFromCompoundShapeIndex2(shape.ptr, ii);
DereferenceAnonCollisionShape(childShape);
}
BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr);
}
// Sometimes we have a pointer to a collision shape but don't know what type it is.
// Figure out type and call the correct dereference routine.
// Called at taint-time.
private void DereferenceAnonCollisionShape(IntPtr cShape)
{
MeshDesc meshDesc;
HullDesc hullDesc;
BulletShape shapeInfo = new BulletShape(cShape);
if (TryGetMeshByPtr(cShape, out meshDesc))
{
shapeInfo.type = ShapeData.PhysicsShapeType.SHAPE_MESH;
shapeInfo.shapeKey = meshDesc.shapeKey;
}
else
{
if (TryGetHullByPtr(cShape, out hullDesc))
{
shapeInfo.type = ShapeData.PhysicsShapeType.SHAPE_HULL;
shapeInfo.shapeKey = hullDesc.shapeKey;
}
else
{
if (BulletSimAPI.IsCompound2(cShape))
{
shapeInfo.type = ShapeData.PhysicsShapeType.SHAPE_COMPOUND;
}
else
{
if (BulletSimAPI.IsNativeShape2(cShape))
{
shapeInfo.isNativeShape = true;
shapeInfo.type = ShapeData.PhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter)
}
}
}
}
DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo);
if (shapeInfo.type != ShapeData.PhysicsShapeType.SHAPE_UNKNOWN)
{
DereferenceShape(shapeInfo, true, null);
}
else
{
PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}",
LogHeader, PhysicsScene.RegionName, cShape.ToString("X"));
}
}
@ -325,22 +400,46 @@ public class BSShapeCollection : IDisposable
// Info in prim.BSShape is updated to the new shape.
// Returns 'true' if the geometry was rebuilt.
// Called at taint-time!
private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeData shapeData,
PrimitiveBaseShape pbs, ShapeDestructionCallback shapeCallback)
private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback)
{
bool ret = false;
bool haveShape = false;
if (!haveShape && prim.PreferredPhysicalShape == ShapeData.PhysicsShapeType.SHAPE_AVATAR)
{
// an avatar capsule is close to a native shape (it is not shared)
ret = GetReferenceToNativeShape(prim, ShapeData.PhysicsShapeType.SHAPE_AVATAR,
ShapeData.FixedShapeKey.KEY_CAPSULE, shapeCallback);
DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape);
ret = true;
haveShape = true;
}
// Compound shapes are handled special as they are rebuilt from scratch.
// This isn't too great a hardship since most of the child shapes will already been created.
if (!haveShape && prim.PreferredPhysicalShape == ShapeData.PhysicsShapeType.SHAPE_COMPOUND)
{
ret = GetReferenceToCompoundShape(prim, shapeCallback);
DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape);
haveShape = true;
}
if (!haveShape)
{
ret = CreateGeomNonSpecial(forceRebuild, prim, shapeCallback);
}
return ret;
}
// Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'.
private bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback)
{
bool ret = false;
bool haveShape = false;
bool nativeShapePossible = true;
PrimitiveBaseShape pbs = prim.BaseShape;
if (shapeData.Type == ShapeData.PhysicsShapeType.SHAPE_AVATAR)
{
// an avatar capsule is close to a native shape (it is not shared)
ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_AVATAR,
ShapeData.FixedShapeKey.KEY_CAPSULE, shapeCallback);
DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.BSShape);
ret = true;
haveShape = true;
}
// If the prim attributes are simple, this could be a simple Bullet native shape
if (!haveShape
&& pbs != null
@ -354,98 +453,110 @@ public class BSShapeCollection : IDisposable
&& pbs.PathScaleX == 100 && pbs.PathScaleY == 100
&& pbs.PathShearX == 0 && pbs.PathShearY == 0) ) )
{
// It doesn't look like Bullet scales spheres so make sure the scales are all equal
if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
&& pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)
{
haveShape = true;
if (forceRebuild
|| prim.Scale != shapeData.Size
|| prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_SPHERE
|| prim.Scale != prim.Size
|| prim.PhysShape.type != ShapeData.PhysicsShapeType.SHAPE_SPHERE
)
{
ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_SPHERE,
ret = GetReferenceToNativeShape(prim, ShapeData.PhysicsShapeType.SHAPE_SPHERE,
ShapeData.FixedShapeKey.KEY_SPHERE, shapeCallback);
DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
prim.LocalID, forceRebuild, prim.BSShape);
prim.LocalID, forceRebuild, prim.PhysShape);
}
}
if (pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
{
haveShape = true;
if (forceRebuild
|| prim.Scale != shapeData.Size
|| prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_BOX
|| prim.Scale != prim.Size
|| prim.PhysShape.type != ShapeData.PhysicsShapeType.SHAPE_BOX
)
{
ret = GetReferenceToNativeShape( prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_BOX,
ret = GetReferenceToNativeShape( prim, ShapeData.PhysicsShapeType.SHAPE_BOX,
ShapeData.FixedShapeKey.KEY_BOX, shapeCallback);
DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
prim.LocalID, forceRebuild, prim.BSShape);
prim.LocalID, forceRebuild, prim.PhysShape);
}
}
}
// If a simple shape is not happening, create a mesh and possibly a hull.
// Note that if it's a native shape, the check for physical/non-physical is not
// made. Native shapes are best used in either case.
if (!haveShape && pbs != null)
{
ret = CreateGeomMeshOrHull(prim, shapeCallback);
}
return ret;
}
public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
{
bool ret = false;
// Note that if it's a native shape, the check for physical/non-physical is not
// made. Native shapes work in either case.
if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects)
{
// Update prim.BSShape to reference a hull of this shape.
ret = GetReferenceToHull(prim, shapeData, pbs, shapeCallback);
ret = GetReferenceToHull(prim,shapeCallback);
DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
shapeData.ID, prim.BSShape, prim.BSShape.shapeKey.ToString("X"));
prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
}
else
{
ret = GetReferenceToMesh(prim, shapeData, pbs, shapeCallback);
ret = GetReferenceToMesh(prim, shapeCallback);
DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
shapeData.ID, prim.BSShape, prim.BSShape.shapeKey.ToString("X"));
}
prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
}
return ret;
}
// Creates a native shape and assignes it to prim.BSShape.
// "Native" shapes are never shared. they are created here and destroyed in DereferenceShape().
private bool GetReferenceToNativeShape(BSPhysObject prim, ShapeData shapeData,
private bool GetReferenceToNativeShape(BSPhysObject prim,
ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey,
ShapeDestructionCallback shapeCallback)
{
// release any previous shape
DereferenceShape(prim.BSShape, true, shapeCallback);
DereferenceShape(prim.PhysShape, true, shapeCallback);
shapeData.Type = shapeType;
// Bullet native objects are scaled by the Bullet engine so pass the size in
prim.Scale = shapeData.Size;
shapeData.Scale = shapeData.Size;
prim.Scale = prim.Size;
BulletShape newShape = BuildPhysicalNativeShape(shapeType, shapeData, shapeKey);
BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey);
// Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
shapeData.ID, newShape, shapeData.Scale);
prim.LocalID, newShape, prim.Scale);
prim.BSShape = newShape;
prim.PhysShape = newShape;
return true;
}
private BulletShape BuildPhysicalNativeShape(ShapeData.PhysicsShapeType shapeType,
ShapeData shapeData, ShapeData.FixedShapeKey shapeKey)
private BulletShape BuildPhysicalNativeShape(BSPhysObject prim, ShapeData.PhysicsShapeType shapeType,
ShapeData.FixedShapeKey shapeKey)
{
BulletShape newShape;
// Need to make sure the passed shape information is for the native type.
ShapeData nativeShapeData = shapeData;
ShapeData nativeShapeData = new ShapeData();
nativeShapeData.Type = shapeType;
nativeShapeData.ID = prim.LocalID;
nativeShapeData.Scale = prim.Scale;
nativeShapeData.Size = prim.Scale;
nativeShapeData.MeshKey = (ulong)shapeKey;
nativeShapeData.HullKey = (ulong)shapeKey;
if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR)
{
newShape = new BulletShape(
BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, nativeShapeData.Scale)
BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale)
, shapeType);
DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", nativeShapeData.ID, nativeShapeData.Scale);
DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
}
else
{
@ -454,7 +565,7 @@ public class BSShapeCollection : IDisposable
if (newShape.ptr == IntPtr.Zero)
{
PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
LogHeader, nativeShapeData.ID, nativeShapeData.Type);
LogHeader, prim.LocalID, shapeType);
}
newShape.shapeKey = (System.UInt64)shapeKey;
newShape.isNativeShape = true;
@ -466,33 +577,32 @@ public class BSShapeCollection : IDisposable
// Dereferences previous shape in BSShape and adds a reference for this new shape.
// Returns 'true' of a mesh was actually built. Otherwise .
// Called at taint-time!
private bool GetReferenceToMesh(BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs,
ShapeDestructionCallback shapeCallback)
private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
{
BulletShape newShape = new BulletShape(IntPtr.Zero);
float lod;
System.UInt64 newMeshKey = ComputeShapeKey(shapeData, pbs, out lod);
System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
// if this new shape is the same as last time, don't recreate the mesh
if (newMeshKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_MESH)
if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.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"));
DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}",
prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"));
// Since we're recreating new, get rid of the reference to the previous shape
DereferenceShape(prim.BSShape, true, shapeCallback);
DereferenceShape(prim.PhysShape, true, shapeCallback);
newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, pbs, shapeData.Size, lod);
newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, prim.BaseShape, prim.Size, lod);
// Take evasive action if the mesh was not constructed.
newShape = VerifyMeshCreated(newShape, prim, shapeData, pbs);
newShape = VerifyMeshCreated(newShape, prim);
ReferenceShape(newShape);
// meshes are already scaled by the meshmerizer
prim.Scale = new OMV.Vector3(1f, 1f, 1f);
prim.BSShape = newShape;
prim.PhysShape = newShape;
return true; // 'true' means a new shape has been added to this prim
}
@ -526,7 +636,7 @@ public class BSShapeCollection : IDisposable
verticesAsFloats[vi++] = vv.Z;
}
// m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
// m_log.DebugFormat("{0}: BSShapeCollection.CreatePhysicalMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
// LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count);
meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
@ -541,32 +651,31 @@ public class BSShapeCollection : IDisposable
// See that hull shape exists in the physical world and update prim.BSShape.
// We could be creating the hull because scale changed or whatever.
private bool GetReferenceToHull(BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs,
ShapeDestructionCallback shapeCallback)
private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
{
BulletShape newShape;
float lod;
System.UInt64 newHullKey = ComputeShapeKey(shapeData, pbs, out lod);
System.UInt64 newHullKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
// if the hull hasn't changed, don't rebuild it
if (newHullKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_HULL)
if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == ShapeData.PhysicsShapeType.SHAPE_HULL)
return false;
DetailLog("{0},BSShapeCollection.CreateGeomHull,create,oldKey={1},newKey={2}",
prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}",
prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
// Remove usage of the previous shape.
DereferenceShape(prim.BSShape, true, shapeCallback);
DereferenceShape(prim.PhysShape, true, shapeCallback);
newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod);
newShape = VerifyMeshCreated(newShape, prim, shapeData, pbs);
newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod);
newShape = VerifyMeshCreated(newShape, prim);
ReferenceShape(newShape);
// hulls are already scaled by the meshmerizer
prim.Scale = new OMV.Vector3(1f, 1f, 1f);
prim.BSShape = newShape;
prim.PhysShape = newShape;
return true; // 'true' means a new shape has been added to this prim
}
@ -685,9 +794,31 @@ public class BSShapeCollection : IDisposable
return;
}
// Compound shapes are always built from scratch.
// This shouldn't be to bad since most of the parts will be meshes that had been built previously.
private bool GetReferenceToCompoundShape(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
{
// Remove reference to the old shape
// Don't need to do this as the shape is freed when the new root shape is created below.
// DereferenceShape(prim.PhysShape, true, shapeCallback);
BulletShape cShape = new BulletShape(
BulletSimAPI.CreateCompoundShape2(PhysicsScene.World.ptr, false), ShapeData.PhysicsShapeType.SHAPE_COMPOUND);
// Create the shape for the root prim and add it to the compound shape. Cannot be a native shape.
CreateGeomMeshOrHull(prim, shapeCallback);
BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity);
DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}",
prim.LocalID, cShape, prim.PhysShape);
prim.PhysShape = cShape;
return true;
}
// Create a hash of all the shape parameters to be used as a key
// for this particular shape.
private System.UInt64 ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs, out float retLod)
private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
{
// level of detail based on size and type of the object
float lod = PhysicsScene.MeshLOD;
@ -695,40 +826,40 @@ public class BSShapeCollection : IDisposable
lod = PhysicsScene.SculptLOD;
// Mega prims usually get more detail because one can interact with shape approximations at this size.
float maxAxis = Math.Max(shapeData.Size.X, Math.Max(shapeData.Size.Y, shapeData.Size.Z));
float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
if (maxAxis > PhysicsScene.MeshMegaPrimThreshold)
lod = PhysicsScene.MeshMegaPrimLOD;
retLod = lod;
return pbs.GetMeshKey(shapeData.Size, lod);
return pbs.GetMeshKey(size, lod);
}
// For those who don't want the LOD
private System.UInt64 ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs)
private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs)
{
float lod;
return ComputeShapeKey(shapeData, pbs, out lod);
return ComputeShapeKey(size, pbs, out lod);
}
// The creation of a mesh or hull can fail if an underlying asset is not available.
// There are two cases: 1) the asset is not in the cache and it needs to be fetched;
// and 2) the asset cannot be converted (like decompressing JPEG2000s).
// The first case causes the asset to be fetched. The second case just requires
// and 2) the asset cannot be converted (like failed decompression of JPEG2000s).
// The first case causes the asset to be fetched. The second case requires
// us to not loop forever.
// Called after creating a physical mesh or hull. If the physical shape was created,
// just return.
private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs)
private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim)
{
// If the shape was successfully created, nothing more to do
if (newShape.ptr != IntPtr.Zero)
return newShape;
// If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
if (pbs.SculptEntry && !prim.LastAssetBuildFailed && pbs.SculptTexture != OMV.UUID.Zero)
if (prim.BaseShape.SculptEntry && !prim.LastAssetBuildFailed && prim.BaseShape.SculptTexture != OMV.UUID.Zero)
{
prim.LastAssetBuildFailed = true;
BSPhysObject xprim = prim;
DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lID={1},lastFailed={2}",
LogHeader, shapeData.ID.ToString("X"), prim.LastAssetBuildFailed);
LogHeader, prim.LocalID, prim.LastAssetBuildFailed);
Util.FireAndForget(delegate
{
RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
@ -745,7 +876,7 @@ public class BSShapeCollection : IDisposable
yprim.BaseShape.SculptData = asset.Data;
// This will cause the prim to see that the filler shape is not the right
// one and try again to build the object.
// No race condition with the native sphere setting since the rebuild is at taint time.
// No race condition with the normal shape setting since the rebuild is at taint time.
yprim.ForceBodyShapeRebuild(false);
});
@ -757,13 +888,13 @@ public class BSShapeCollection : IDisposable
if (prim.LastAssetBuildFailed)
{
PhysicsScene.Logger.ErrorFormat("{0} Mesh failed to fetch asset. lID={1}, texture={2}",
LogHeader, shapeData.ID, pbs.SculptTexture);
LogHeader, prim.LocalID, prim.BaseShape.SculptTexture);
}
}
// While we figure out the real problem, stick a simple native shape on the object.
BulletShape fillinShape =
BuildPhysicalNativeShape(ShapeData.PhysicsShapeType.SHAPE_BOX, shapeData, ShapeData.FixedShapeKey.KEY_BOX);
BuildPhysicalNativeShape(prim, ShapeData.PhysicsShapeType.SHAPE_BOX, ShapeData.FixedShapeKey.KEY_BOX);
return fillinShape;
}
@ -773,18 +904,18 @@ public class BSShapeCollection : IDisposable
// Returns 'true' if an object was actually created.
// Called at taint-time.
private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape,
ShapeData shapeData, BodyDestructionCallback bodyCallback)
BodyDestructionCallback bodyCallback)
{
bool ret = false;
// the mesh, hull or native shape must have already been created in Bullet
bool mustRebuild = (prim.BSBody.ptr == IntPtr.Zero);
bool mustRebuild = (prim.PhysBody.ptr == IntPtr.Zero);
// If there is an existing body, verify it's of an acceptable type.
// If not a solid object, body is a GhostObject. Otherwise a RigidBody.
if (!mustRebuild)
{
CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(prim.BSBody.ptr);
CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(prim.PhysBody.ptr);
if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY
|| !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT)
{
@ -796,27 +927,27 @@ public class BSShapeCollection : IDisposable
if (mustRebuild || forceRebuild)
{
// Free any old body
DereferenceBody(prim.BSBody, true, bodyCallback);
DereferenceBody(prim.PhysBody, true, bodyCallback);
BulletBody aBody;
IntPtr bodyPtr = IntPtr.Zero;
if (prim.IsSolid)
{
bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr,
shapeData.ID, shapeData.Position, shapeData.Rotation);
prim.LocalID, prim.RawPosition, prim.RawOrientation);
DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
}
else
{
bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr,
shapeData.ID, shapeData.Position, shapeData.Rotation);
prim.LocalID, prim.ForcePosition, prim.ForceOrientation);
DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
}
aBody = new BulletBody(shapeData.ID, bodyPtr);
aBody = new BulletBody(prim.LocalID, bodyPtr);
ReferenceBody(aBody, true);
prim.BSBody = aBody;
prim.PhysBody = aBody;
ret = true;
}
@ -824,6 +955,42 @@ public class BSShapeCollection : IDisposable
return ret;
}
private bool TryGetMeshByPtr(IntPtr addr, out MeshDesc outDesc)
{
bool ret = false;
MeshDesc foundDesc = new MeshDesc();
foreach (MeshDesc md in Meshes.Values)
{
if (md.ptr == addr)
{
foundDesc = md;
ret = true;
break;
}
}
outDesc = foundDesc;
return ret;
}
private bool TryGetHullByPtr(IntPtr addr, out HullDesc outDesc)
{
bool ret = false;
HullDesc foundDesc = new HullDesc();
foreach (HullDesc hd in Hulls.Values)
{
if (hd.ptr == addr)
{
foundDesc = hd;
ret = true;
break;
}
}
outDesc = foundDesc;
return ret;
}
private void DetailLog(string msg, params Object[] args)
{
if (PhysicsScene.PhysicsLogging.Enabled)

View File

@ -0,0 +1,213 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyrightD
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public abstract class BSShape
{
public IntPtr ptr { get; set; }
public ShapeData.PhysicsShapeType type { get; set; }
public System.UInt64 key { get; set; }
public int referenceCount { get; set; }
public DateTime lastReferenced { get; set; }
protected void Initialize()
{
ptr = IntPtr.Zero;
type = ShapeData.PhysicsShapeType.SHAPE_UNKNOWN;
key = 0;
referenceCount = 0;
lastReferenced = DateTime.Now;
}
// Get a reference to a physical shape. Create if it doesn't exist
public static BSShape GetShapeReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
{
BSShape ret = null;
if (prim.PreferredPhysicalShape == ShapeData.PhysicsShapeType.SHAPE_AVATAR)
{
// an avatar capsule is close to a native shape (it is not shared)
ret = BSShapeNative.GetReference(physicsScene, prim, ShapeData.PhysicsShapeType.SHAPE_AVATAR,
ShapeData.FixedShapeKey.KEY_CAPSULE);
physicsScene.DetailLog("{0},BSShape.GetShapeReference,avatarCapsule,shape={1}", prim.LocalID, ret);
}
// Compound shapes are handled special as they are rebuilt from scratch.
// This isn't too great a hardship since most of the child shapes will already been created.
if (ret == null && prim.PreferredPhysicalShape == ShapeData.PhysicsShapeType.SHAPE_COMPOUND)
{
// Getting a reference to a compound shape gets you the compound shape with the root prim shape added
ret = BSShapeCompound.GetReference(prim);
physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, ret);
}
if (ret == null)
ret = GetShapeReferenceNonSpecial(physicsScene, forceRebuild, prim);
return ret;
}
public static BSShape GetShapeReferenceNonSpecial(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
{
return null;
}
public static BSShape GetShapeReferenceNonNative(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
{
return null;
}
// Release the use of a physical shape.
public abstract void Dereference(BSScene physicsScene);
// All shapes have a static call to get a reference to the physical shape
// protected abstract static BSShape GetReference();
public override string ToString()
{
StringBuilder buff = new StringBuilder();
buff.Append("<p=");
buff.Append(ptr.ToString("X"));
buff.Append(",s=");
buff.Append(type.ToString());
buff.Append(",k=");
buff.Append(key.ToString("X"));
buff.Append(",c=");
buff.Append(referenceCount.ToString());
buff.Append(">");
return buff.ToString();
}
}
public class BSShapeNull : BSShape
{
public BSShapeNull()
{
base.Initialize();
}
public static BSShape GetReference() { return new BSShapeNull(); }
public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ }
}
public class BSShapeNative : BSShape
{
private static string LogHeader = "[BULLETSIM SHAPE NATIVE]";
public BSShapeNative()
{
base.Initialize();
}
public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim,
ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey)
{
// Native shapes are not shared and are always built anew.
return new BSShapeNative(physicsScene, prim, shapeType, shapeKey);
}
private BSShapeNative(BSScene physicsScene, BSPhysObject prim,
ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey)
{
ShapeData nativeShapeData = new ShapeData();
nativeShapeData.Type = shapeType;
nativeShapeData.ID = prim.LocalID;
nativeShapeData.Scale = prim.Scale;
nativeShapeData.Size = prim.Scale;
nativeShapeData.MeshKey = (ulong)shapeKey;
nativeShapeData.HullKey = (ulong)shapeKey;
if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR)
{
ptr = BulletSimAPI.BuildCapsuleShape2(physicsScene.World.ptr, 1f, 1f, prim.Scale);
physicsScene.DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
}
else
{
ptr = BulletSimAPI.BuildNativeShape2(physicsScene.World.ptr, nativeShapeData);
}
if (ptr == IntPtr.Zero)
{
physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
LogHeader, prim.LocalID, shapeType);
}
type = shapeType;
key = (UInt64)shapeKey;
}
// Make this reference to the physical shape go away since native shapes are not shared.
public override void Dereference(BSScene physicsScene)
{
// Native shapes are not tracked and are released immediately
physicsScene.DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this);
BulletSimAPI.DeleteCollisionShape2(physicsScene.World.ptr, ptr);
ptr = IntPtr.Zero;
// Garbage collection will free up this instance.
}
}
public class BSShapeMesh : BSShape
{
private static string LogHeader = "[BULLETSIM SHAPE MESH]";
private static Dictionary<System.UInt64, BSShapeMesh> Meshes = new Dictionary<System.UInt64, BSShapeMesh>();
public BSShapeMesh()
{
base.Initialize();
}
public static BSShape GetReference() { return new BSShapeNull(); }
public override void Dereference(BSScene physicsScene) { }
}
public class BSShapeHull : BSShape
{
private static string LogHeader = "[BULLETSIM SHAPE HULL]";
private static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>();
public BSShapeHull()
{
base.Initialize();
}
public static BSShape GetReference() { return new BSShapeNull(); }
public override void Dereference(BSScene physicsScene) { }
}
public class BSShapeCompound : BSShape
{
private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]";
public BSShapeCompound()
{
base.Initialize();
}
public static BSShape GetReference(BSPhysObject prim)
{
return new BSShapeNull();
}
public override void Dereference(BSScene physicsScene) { }
}
}

View File

@ -40,7 +40,7 @@ using OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public class BSTerrainManager
public sealed class BSTerrainManager
{
static string LogHeader = "[BULLETSIM TERRAIN MANAGER]";
@ -238,7 +238,7 @@ public class BSTerrainManager
DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,call,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}",
BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY);
BSScene.TaintCallback rebuildOperation = delegate()
PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateOrCreateTerrain:UpdateExisting", delegate()
{
if (MegaRegionParentPhysicsScene != null)
{
@ -337,14 +337,7 @@ public class BSTerrainManager
BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
m_terrainModified = true;
};
// There is the option to do the changes now (we're already in 'taint time'), or
// to do the Bullet operations later.
if (inTaintTime)
rebuildOperation();
else
PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:UpdateExisting", rebuildOperation);
});
}
else
{
@ -364,7 +357,7 @@ public class BSTerrainManager
BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
// Code that must happen at taint-time
BSScene.TaintCallback createOperation = delegate()
PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateOrCreateTerrain:NewTerrain", delegate()
{
DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,taint,baseX={1},baseY={2}", BSScene.DetailLogZero, minCoords.X, minCoords.Y);
// Create a new mapInfo that will be filled with the new info
@ -377,13 +370,7 @@ public class BSTerrainManager
UpdateOrCreateTerrain(newTerrainID, heightMap, minCoords, maxCoords, true);
m_terrainModified = true;
};
// If already in taint-time, just call Bullet. Otherwise queue the operations for the safe time.
if (inTaintTime)
createOperation();
else
PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:NewTerrain", createOperation);
});
}
}

View File

@ -194,6 +194,7 @@ public struct ShapeData
// following defined by BulletSim
SHAPE_GROUNDPLANE = 20,
SHAPE_TERRAIN = 21,
SHAPE_COMPOUND = 22,
};
public uint ID;
public PhysicsShapeType Type;
@ -299,6 +300,7 @@ public struct ConfigurationParameters
public float shouldEnableFrictionCaching;
public float numberOfSolverIterations;
public float linksetImplementation;
public float linkConstraintUseFrameOffset;
public float linkConstraintEnableTransMotor;
public float linkConstraintTransMotorMaxVel;
@ -378,6 +380,7 @@ public enum CollisionFilterGroups : uint
BTerrainFilter = 1 << 11,
BRaycastFilter = 1 << 12,
BSolidFilter = 1 << 13,
BLinksetFilter = 1 << 14,
// The collsion filters and masked are defined in one place -- don't want them scattered
AvatarFilter = BCharacterFilter,
@ -386,6 +389,8 @@ public enum CollisionFilterGroups : uint
ObjectMask = BAllFilter,
StaticObjectFilter = BStaticFilter,
StaticObjectMask = BAllFilter,
LinksetFilter = BLinksetFilter,
LinksetMask = BAllFilter & ~BLinksetFilter,
VolumeDetectFilter = BSensorTrigger,
VolumeDetectMask = ~BSensorTrigger,
TerrainFilter = BTerrainFilter,
@ -395,8 +400,6 @@ public enum CollisionFilterGroups : uint
};
// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0
// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2.
public enum ConstraintParams : int
@ -611,13 +614,25 @@ public static extern bool IsNativeShape2(IntPtr shape);
public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr CreateCompoundShape2(IntPtr sim);
public static extern IntPtr CreateCompoundShape2(IntPtr sim, bool enableDynamicAabbTree);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void AddChildToCompoundShape2(IntPtr cShape, IntPtr addShape, Vector3 pos, Quaternion rot);
public static extern int GetNumberOfCompoundChildren2(IntPtr cShape);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void RemoveChildFromCompoundShape2(IntPtr cShape, IntPtr removeShape);
public static extern void AddChildShapeToCompoundShape2(IntPtr cShape, IntPtr addShape, Vector3 pos, Quaternion rot);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr GetChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr RemoveChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void RecalculateCompoundShapeLocalAabb2(IntPtr cShape);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id);
@ -881,10 +896,10 @@ public static extern float GetCcdMotionThreshold2(IntPtr obj);
public static extern void SetCcdMotionThreshold2(IntPtr obj, float val);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern float GetCcdSweepSphereRadius2(IntPtr obj);
public static extern float GetCcdSweptSphereRadius2(IntPtr obj);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void SetCcdSweepSphereRadius2(IntPtr obj, float val);
public static extern void SetCcdSweptSphereRadius2(IntPtr obj, float val);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr GetUserPointer2(IntPtr obj);
@ -906,6 +921,12 @@ public static extern Vector3 GetGravity2(IntPtr obj);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void SetDamping2(IntPtr obj, float lin_damping, float ang_damping);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void SetLinearDamping2(IntPtr obj, float lin_damping);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void SetAngularDamping2(IntPtr obj, float ang_damping);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern float GetLinearDamping2(IntPtr obj);

View File

@ -257,6 +257,12 @@ namespace OpenSim.Region.Physics.Manager
/// Getting this returns the velocity calculated by physics scene updates, using factors such as target velocity,
/// time to accelerate and collisions.
/// </remarks>
public virtual Vector3 TargetVelocity
{
get { return Velocity; }
set { Velocity = value; }
}
public abstract Vector3 Velocity { get; set; }
public abstract Vector3 Torque { get; set; }

View File

@ -661,6 +661,20 @@ namespace OpenSim.Region.Physics.OdePlugin
set { return; }
}
public override Vector3 TargetVelocity
{
get
{
return m_taintTargetVelocity;
}
set
{
Velocity = value;
}
}
public override Vector3 Velocity
{
get

View File

@ -3963,17 +3963,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
if (m_TransferModule != null)
{
byte[] bucket = new byte[] { (byte)item.Type };
byte[] bucket = new byte[1];
bucket[0] = (byte)item.Type;
GridInstantMessage msg = new GridInstantMessage(World,
m_host.UUID, m_host.Name + ", an object owned by " +
resolveName(m_host.OwnerID) + ",", destId,
m_host.OwnerID, m_host.Name, destId,
(byte)InstantMessageDialog.TaskInventoryOffered,
false, item.Name + "\n" + m_host.Name + " is located at " +
false, item.Name+". "+m_host.Name+" is located at "+
World.RegionInfo.RegionName+" "+
m_host.AbsolutePosition.ToString(),
agentItem.ID, true, m_host.AbsolutePosition,
bucket, true); // TODO: May actually send no timestamp
bucket, true);
m_TransferModule.SendInstantMessage(msg, delegate(bool success) {});
}

View File

@ -67,10 +67,25 @@ namespace OpenSim.Server.Handlers.Asset
throw new Exception(String.Format("Failed to load AssetService from {0}; config is {1}", assetService, m_ConfigName));
bool allowDelete = serverConfig.GetBoolean("AllowRemoteDelete", false);
bool allowDeleteAllTypes = serverConfig.GetBoolean("AllowRemoteDeleteAllTypes", false);
AllowedRemoteDeleteTypes allowedRemoteDeleteTypes;
if (!allowDelete)
{
allowedRemoteDeleteTypes = AllowedRemoteDeleteTypes.None;
}
else
{
if (allowDeleteAllTypes)
allowedRemoteDeleteTypes = AllowedRemoteDeleteTypes.All;
else
allowedRemoteDeleteTypes = AllowedRemoteDeleteTypes.MapTile;
}
server.AddStreamHandler(new AssetServerGetHandler(m_AssetService));
server.AddStreamHandler(new AssetServerPostHandler(m_AssetService));
server.AddStreamHandler(new AssetServerDeleteHandler(m_AssetService, allowDelete));
server.AddStreamHandler(new AssetServerDeleteHandler(m_AssetService, allowedRemoteDeleteTypes));
MainConsole.Instance.Commands.AddCommand("Assets", false,
"show asset",

View File

@ -42,18 +42,32 @@ using OpenSim.Framework.Servers.HttpServer;
namespace OpenSim.Server.Handlers.Asset
{
/// <summary>
/// Remote deletes allowed.
/// </summary>
public enum AllowedRemoteDeleteTypes
{
None,
MapTile,
All
}
public class AssetServerDeleteHandler : BaseStreamHandler
{
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private IAssetService m_AssetService;
protected bool m_allowDelete;
public AssetServerDeleteHandler(IAssetService service, bool allowDelete) :
/// <summary>
/// Asset types that can be deleted remotely.
/// </summary>
private AllowedRemoteDeleteTypes m_allowedTypes;
public AssetServerDeleteHandler(IAssetService service, AllowedRemoteDeleteTypes allowedTypes) :
base("DELETE", "/assets")
{
m_AssetService = service;
m_allowDelete = allowDelete;
m_allowedTypes = allowedTypes;
}
public override byte[] Handle(string path, Stream request,
@ -63,9 +77,28 @@ namespace OpenSim.Server.Handlers.Asset
string[] p = SplitParams(path);
if (p.Length > 0 && m_allowDelete)
if (p.Length > 0)
{
result = m_AssetService.Delete(p[0]);
if (m_allowedTypes != AllowedRemoteDeleteTypes.None)
{
string assetID = p[0];
AssetBase asset = m_AssetService.Get(assetID);
if (asset != null)
{
if (m_allowedTypes == AllowedRemoteDeleteTypes.All
|| (int)(asset.Flags & AssetFlags.Maptile) != 0)
{
result = m_AssetService.Delete(assetID);
}
else
{
m_log.DebugFormat(
"[ASSET SERVER DELETE HANDLER]: Request to delete asset {0}, but type is {1} and allowed remote delete types are {2}",
assetID, (AssetFlags)asset.Flags, m_allowedTypes);
}
}
}
}
XmlSerializer xs = new XmlSerializer(typeof(bool));

View File

@ -70,7 +70,7 @@ namespace OpenSim.Services.AssetService
if (assetLoaderEnabled)
{
m_log.DebugFormat("[ASSET]: Loading default asset set from {0}", loaderArgs);
m_log.DebugFormat("[ASSET SERVICE]: Loading default asset set from {0}", loaderArgs);
m_AssetLoader.ForEachDefaultXmlAsset(
loaderArgs,
@ -197,20 +197,7 @@ namespace OpenSim.Services.AssetService
if (!UUID.TryParse(id, out assetID))
return false;
AssetBase asset = m_Database.GetAsset(assetID);
if (asset == null)
return false;
if ((int)(asset.Flags & AssetFlags.Maptile) != 0)
{
return m_Database.Delete(id);
}
else
{
m_log.DebugFormat("[ASSET SERVICE]: Request to delete asset {0}, but flags are not Maptile", id);
}
return false;
}
}
}

View File

@ -194,21 +194,7 @@ namespace OpenSim.Services.AssetService
if (!UUID.TryParse(id, out assetID))
return false;
AssetBase asset = m_Database.GetAsset(assetID);
if (asset == null)
return false;
if ((int)(asset.Flags & AssetFlags.Maptile) != 0)
{
return m_Database.Delete(id);
}
else
{
m_log.DebugFormat("[XASSET SERVICE]: Request to delete asset {0}, but flags are not Maptile", id);
}
return false;
}
}
}

View File

@ -321,7 +321,7 @@ namespace OpenSim.Services.Connectors.Hypergrid
args["destination_uuid"] = OSD.FromString(destination.RegionID.ToString());
args["teleport_flags"] = OSD.FromString(flags.ToString());
OSDMap result = WebUtil.PostToService(uri, args, 20000);
OSDMap result = WebUtil.PostToService(uri, args, 80000);
if (result["Success"].AsBoolean())
{
OSDMap unpacked = (OSDMap)result["_Result"];

View File

@ -68,6 +68,7 @@ namespace OpenSim.Services.HypergridService
private static UUID m_ScopeID;
private static bool m_AllowTeleportsToAnyRegion;
private static string m_ExternalName;
private static Uri m_Uri;
private static GridRegion m_DefaultGatewayRegion;
public GatekeeperService(IConfigSource config, ISimulationService simService)
@ -99,6 +100,15 @@ namespace OpenSim.Services.HypergridService
if (m_ExternalName != string.Empty && !m_ExternalName.EndsWith("/"))
m_ExternalName = m_ExternalName + "/";
try
{
m_Uri = new Uri(m_ExternalName);
}
catch
{
m_log.WarnFormat("[GATEKEEPER SERVICE]: Malformed gatekeeper address {0}", m_ExternalName);
}
Object[] args = new Object[] { config };
m_GridService = ServerUtils.LoadPlugin<IGridService>(gridService, args);
m_PresenceService = ServerUtils.LoadPlugin<IPresenceService>(presenceService, args);
@ -433,7 +443,18 @@ namespace OpenSim.Services.HypergridService
string externalname = m_ExternalName.TrimEnd(trailing_slash);
m_log.DebugFormat("[GATEKEEPER SERVICE]: Verifying {0} against {1}", addressee, externalname);
return string.Equals(addressee, externalname, StringComparison.OrdinalIgnoreCase);
Uri uri;
try
{
uri = new Uri(addressee);
}
catch
{
m_log.DebugFormat("[GATEKEEPER SERVICE]: Visitor provided malformed service address {0}", addressee);
return false;
}
return string.Equals(uri.GetLeftPart(UriPartial.Authority), m_Uri.GetLeftPart(UriPartial.Authority), StringComparison.OrdinalIgnoreCase) ;
}
#endregion

View File

@ -71,7 +71,7 @@ namespace OpenSim.Services.HypergridService
m_ConfigName = configName;
if (m_Database == null)
m_log.WarnFormat("[XXX]: m_Database is null!");
m_log.ErrorFormat("[HG SUITCASE INVENTORY SERVICE]: m_Database is null!");
//
// Try reading the [InventoryService] section, if it exists
@ -301,7 +301,7 @@ namespace OpenSim.Services.HypergridService
public override bool AddFolder(InventoryFolderBase folder)
{
m_log.WarnFormat("[HG SUITCASE INVENTORY SERVICE]: AddFolder {0} {1}", folder.Name, folder.ParentID);
//m_log.WarnFormat("[HG SUITCASE INVENTORY SERVICE]: AddFolder {0} {1}", folder.Name, folder.ParentID);
// Let's do a bit of sanity checking, more than the base service does
// make sure the given folder's parent folder exists under the suitcase tree of this user
@ -323,7 +323,7 @@ namespace OpenSim.Services.HypergridService
public override bool UpdateFolder(InventoryFolderBase folder)
{
m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: Update folder {0}, version {1}", folder.ID, folder.Version);
//m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: Update folder {0}, version {1}", folder.ID, folder.Version);
if (!IsWithinSuitcaseTree(folder.Owner, folder.ID))
{
m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: folder {0} not within Suitcase tree", folder.Name);
@ -460,6 +460,15 @@ namespace OpenSim.Services.HypergridService
if (folders != null && folders.Length > 0)
return folders[0];
// OK, so the RootFolder type didn't work. Let's look for any type with parent UUID.Zero.
folders = m_Database.GetFolders(
new string[] { "agentID", "folderName", "parentFolderID" },
new string[] { principalID.ToString(), "My Inventory", UUID.Zero.ToString() });
if (folders != null && folders.Length > 0)
return folders[0];
return null;
}
@ -584,7 +593,7 @@ namespace OpenSim.Services.HypergridService
{
if (a.Wearables[i][j].ItemID == itemID)
{
m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: item {0} is a wearable", itemID);
//m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: item {0} is a wearable", itemID);
return true;
}
}
@ -593,7 +602,7 @@ namespace OpenSim.Services.HypergridService
// Check attachments
if (a.GetAttachmentForItem(itemID) != null)
{
m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: item {0} is an attachment", itemID);
//m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: item {0} is an attachment", itemID);
return true;
}

View File

@ -400,16 +400,7 @@ namespace OpenSim.Services.InventoryService
public virtual bool MoveFolder(InventoryFolderBase folder)
{
XInventoryFolder[] x = m_Database.GetFolders(
new string[] { "folderID" },
new string[] { folder.ID.ToString() });
if (x.Length == 0)
return false;
x[0].parentFolderID = folder.ParentID;
return m_Database.StoreFolder(x[0]);
return m_Database.MoveFolder(folder.ID.ToString(), folder.ParentID.ToString());
}
// We don't check the principal's ID here

View File

@ -125,6 +125,7 @@ namespace OpenSim.Tests.Common.Mock
}
public bool MoveItem(string id, string newParent) { throw new NotImplementedException(); }
public bool MoveFolder(string id, string newParent) { throw new NotImplementedException(); }
public XInventoryItem[] GetActiveGestures(UUID principalID) { throw new NotImplementedException(); }
public int GetAssetPermissions(UUID principalID, UUID assetID) { throw new NotImplementedException(); }
}

View File

@ -0,0 +1,26 @@
/*
* Copyright (c) Contributors, http://aurora-sim.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 Aurora-Sim 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.
*/

View File

@ -484,8 +484,15 @@ IntegrationService = "8002/OpenSim.Server.Handlers.dll:IntegrationServiceConnect
; *
[HGInventoryService]
; For the InventoryServiceInConnector
LocalServiceModule = "OpenSim.Services.HypergridService.dll:HGInventoryService"
LocalServiceModule = "OpenSim.Services.HypergridService.dll:HGSuitcaseInventoryService"
;; alternatives:
;; HG1.5, more permissive, not recommended, but still supported
;LocalServiceModule = "OpenSim.Services.HypergridService.dll:HGInventoryService"
;; HG1.0, totally permissive, not recommended, but OK for grids with 100% trust
;LocalServiceModule = "OpenSim.Services.InventoryService.dll:XInventoryService"
UserAccountsService = "OpenSim.Services.UserAccountService.dll:UserAccountService"
AvatarService = "OpenSim.Services.AvatarService.dll:AvatarService"
HomeURI = "http://127.0.0.1:8002"
; * The interface that local users get when they are in other grids.

View File

@ -77,7 +77,19 @@ IntegrationService = "8002/OpenSim.Server.Handlers.dll:IntegrationServiceConnect
LocalServiceModule = "OpenSim.Services.AssetService.dll:AssetService"
DefaultAssetLoader = "OpenSim.Framework.AssetLoader.Filesystem.dll"
AssetLoaderArgs = "./assets/AssetSets.xml"
AllowRemoteDelete = "false"
; Allow maptile assets to remotely deleted by remote calls to the asset service.
; There is no harm in having this as false - it just means that historical maptile assets are not deleted.
; This only applies to maptiles served via the version 1 viewer mechanisms
; Default is false
AllowRemoteDelete = false
; Allow all assets to be remotely deleted.
; Only set this to true if you are operating a grid where you control all calls to the asset service
; (where a necessary condition is that you control all simulators) and you need this for admin purposes.
; If set to true, AllowRemoteDelete = true is required as well.
; Default is false.
AllowRemoteDeleteAllTypes = false
; * This configuration loads the inventory server modules. It duplicates
; * the function of the legacy inventory server

View File

@ -47,36 +47,6 @@
DefaultAssetLoader = "OpenSim.Framework.AssetLoader.Filesystem.dll"
AssetLoaderArgs = "assets/AssetSets.xml"
[HGInventoryService]
HomeURI = "http://127.0.0.1:9000"
[HGAssetService]
HomeURI = "http://127.0.0.1:9000"
;; The asset types that this grid can export to / import from other grids.
;; Comma separated.
;; Valid values are all the asset types in OpenMetaverse.AssetType, namely:
;; Unknown, Texture, Sound, CallingCard, Landmark, Clothing, Object, Notecard, LSLText,
;; LSLBytecode, TextureTGA, Bodypart, SoundWAV, ImageTGA, ImageJPEG, Animation, Gesture, Mesh
;;
;; Leave blank or commented if you don't want to apply any restrictions.
;; A more strict, but still reasonable, policy may be to disallow the exchange
;; of scripts, like so:
; DisallowExport ="LSLText"
; DisallowImport ="LSLBytecode"
[HGInventoryAccessModule]
HomeURI = "http://127.0.0.1:9000"
Gatekeeper = "http://127.0.0.1:9000"
;; If you want to protect your assets from being copied by foreign visitors
;; uncomment the next line. You may want to do this on sims that have licensed content.
; OutboundPermission = False
[HGFriendsModule]
; User level required to be able to send friendship invitations to foreign users
;LevelHGFriends = 0;
[GridService]
;; For in-memory region storage (default)
@ -97,11 +67,6 @@
;; change this to the address of your simulator
Gatekeeper="http://127.0.0.1:9000"
[Messaging]
; === HG ONLY ===
;; change this to the address of your simulator
Gatekeeper = "http://127.0.0.1:9000"
[LibraryModule]
; Set this if you want to change the name of the OpenSim Library
;LibraryName = "My World's Library"
@ -140,41 +105,6 @@
;AllowedClients = ""
;DeniedClients = ""
[GatekeeperService]
ExternalName = "http://127.0.0.1:9000"
; Does this grid allow incoming links to any region in it?
; If false, HG TPs happen only to the Default regions specified in [GridService] section
AllowTeleportsToAnyRegion = true
;; Regular expressions for controlling which client versions are accepted/denied.
;; An empty string means nothing is checked.
;;
;; Example 1: allow only these 3 types of clients (any version of them)
;; AllowedClients = "Imprudence|Hippo|Second Life"
;;
;; Example 2: allow all clients except these
;; DeniedClients = "Twisted|Crawler|Cryolife|FuckLife|StreetLife|GreenLife|AntiLife|KORE-Phaze|Synlyfe|Purple Second Life|SecondLi |Emerald"
;;
;; Note that these are regular expressions, so every character counts.
;; Also note that this is very weak security and should not be trusted as a reliable means
;; for keeping bad clients out; modified clients can fake their identifiers.
;;
;;
;AllowedClients = ""
;DeniedClients = ""
;; Are foreign visitors allowed?
;ForeignAgentsAllowed = true
;;
;; If ForeignAgentsAllowed is true, make exceptions using AllowExcept.
;; Leave blank or commented for no exceptions.
; AllowExcept = "http://griefer.com:8002, http://enemy.com:8002"
;;
;; If ForeignAgentsAllowed is false, make exceptions using DisallowExcept
;; Leave blank or commented for no exceptions.
; DisallowExcept = "http://myfriendgrid.com:8002, http://myboss.com:8002"
[FreeswitchService]
;; If FreeSWITCH is not being used then you don't need to set any of these parameters
@ -279,6 +209,44 @@
; Example:
; Region_Test_1 = "DisallowForeigners"
;;
;; HG configurations
;;
[GatekeeperService]
ExternalName = "http://127.0.0.1:9000"
; Does this grid allow incoming links to any region in it?
; If false, HG TPs happen only to the Default regions specified in [GridService] section
AllowTeleportsToAnyRegion = true
;; Regular expressions for controlling which client versions are accepted/denied.
;; An empty string means nothing is checked.
;;
;; Example 1: allow only these 3 types of clients (any version of them)
;; AllowedClients = "Imprudence|Hippo|Second Life"
;;
;; Example 2: allow all clients except these
;; DeniedClients = "Twisted|Crawler|Cryolife|FuckLife|StreetLife|GreenLife|AntiLife|KORE-Phaze|Synlyfe|Purple Second Life|SecondLi |Emerald"
;;
;; Note that these are regular expressions, so every character counts.
;; Also note that this is very weak security and should not be trusted as a reliable means
;; for keeping bad clients out; modified clients can fake their identifiers.
;;
;;
;AllowedClients = ""
;DeniedClients = ""
;; Are foreign visitors allowed?
;ForeignAgentsAllowed = true
;;
;; If ForeignAgentsAllowed is true, make exceptions using AllowExcept.
;; Leave blank or commented for no exceptions.
; AllowExcept = "http://griefer.com:8002, http://enemy.com:8002"
;;
;; If ForeignAgentsAllowed is false, make exceptions using DisallowExcept
;; Leave blank or commented for no exceptions.
; DisallowExcept = "http://myfriendgrid.com:8002, http://myboss.com:8002"
[UserAgentService]
;; User level required to be contacted from other grids
;LevelOutsideContacts = 0
@ -299,3 +267,57 @@
;; If ForeignTripsAllowed is true, make exceptions using AllowExcept.
;; Leave blank or commented for no exceptions.
; AllowExcept_Level_200 = "http://griefer.com:8002, http://enemy.com:8002"
[HGInventoryService]
HomeURI = "http://127.0.0.1:9000"
[HGAssetService]
HomeURI = "http://127.0.0.1:9000"
;; The asset types that this grid can export to / import from other grids.
;; Comma separated.
;; Valid values are all the asset types in OpenMetaverse.AssetType, namely:
;; Unknown, Texture, Sound, CallingCard, Landmark, Clothing, Object, Notecard, LSLText,
;; LSLBytecode, TextureTGA, Bodypart, SoundWAV, ImageTGA, ImageJPEG, Animation, Gesture, Mesh
;;
;; Leave blank or commented if you don't want to apply any restrictions.
;; A more strict, but still reasonable, policy may be to disallow the exchange
;; of scripts, like so:
; DisallowExport ="LSLText"
; DisallowImport ="LSLBytecode"
[HGInventoryAccessModule]
HomeURI = "http://127.0.0.1:9000"
Gatekeeper = "http://127.0.0.1:9000"
;; If you want to protect your assets from being copied by foreign visitors
;; uncomment the next line. You may want to do this on sims that have licensed content.
;; true = allow exports, false = disallow exports. True by default.
; OutboundPermission = True
;; Send visual reminder to local users that their inventories are unavailable while they are traveling
;; and available when they return. True by default.
;RestrictInventoryAccessAbroad = True
[HGFriendsModule]
; User level required to be able to send friendship invitations to foreign users
;LevelHGFriends = 0;
[Messaging]
; === HG ONLY ===
;; change this to the address of your simulator
Gatekeeper = "http://127.0.0.1:9000"
[EntityTransfer]
;; User level from which local users are allowed to HG teleport. Default 0 (all users)
;LevelHGTeleport = 0
;; Are local users restricted from taking their appearance abroad?
;; Default is no restrictions
;RestrictAppearanceAbroad = false
;; If appearance is restricted, which accounts' appearances are allowed to be exported?
;; Comma-separated list of account names
AccountForAppearance = "Test User, Astronaut Smith"

View File

@ -152,7 +152,13 @@
;; This greatly restricts the inventory operations while in other grids
[HGInventoryService]
; For the InventoryServiceInConnector
LocalServiceModule = "OpenSim.Services.HypergridService.dll:HGInventoryService"
LocalServiceModule = "OpenSim.Services.HypergridService.dll:HGSuitcaseInventoryService"
;; alternatives:
;; HG1.5, more permissive, not recommended, but still supported
;LocalServiceModule = "OpenSim.Services.HypergridService.dll:HGInventoryService"
;; HG1.0, totally permissive, not recommended, but OK for grids with 100% trust
;LocalServiceModule = "OpenSim.Services.InventoryService.dll:XInventoryService"
UserAccountsService = "OpenSim.Services.UserAccountService.dll:UserAccountService"
AvatarService = "OpenSim.Services.AvatarService.dll:AvatarService"

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.