Merge branch 'master' of /home/opensim/var/repo/opensim
commit
c24fe86f0e
|
@ -182,12 +182,14 @@ what it is today.
|
||||||
|
|
||||||
This software uses components from the following developers:
|
This software uses components from the following developers:
|
||||||
* Sleepycat Software (Berkeley DB)
|
* Sleepycat Software (Berkeley DB)
|
||||||
|
* Aurora-Sim (http://aurora-sim.org)
|
||||||
* SQLite (Public Domain)
|
* SQLite (Public Domain)
|
||||||
* XmlRpcCS (http://xmlrpccs.sf.net/)
|
* XmlRpcCS (http://xmlrpccs.sf.net/)
|
||||||
* MySQL, Inc. (MySQL Connector/NET)
|
* MySQL, Inc. (MySQL Connector/NET)
|
||||||
* NUnit (http://www.nunit.org)
|
* NUnit (http://www.nunit.org)
|
||||||
* AGEIA Inc. (PhysX)
|
* AGEIA Inc. (PhysX)
|
||||||
* Russel L. Smith (ODE)
|
* Russel L. Smith (ODE)
|
||||||
|
* Erwin Coumans (Bullet)
|
||||||
* Prebuild (http://sourceforge.net/projects/dnpb/)
|
* Prebuild (http://sourceforge.net/projects/dnpb/)
|
||||||
* LibOpenMetaverse (http://lib.openmetaverse.org/)
|
* LibOpenMetaverse (http://lib.openmetaverse.org/)
|
||||||
* DotNetOpenMail v0.5.8b (http://dotnetopenmail.sourceforge.net)
|
* DotNetOpenMail v0.5.8b (http://dotnetopenmail.sourceforge.net)
|
||||||
|
|
|
@ -116,7 +116,22 @@ namespace OpenSim.Data
|
||||||
/// <returns>true if the delete was successful, false if it was not</returns>
|
/// <returns>true if the delete was successful, false if it was not</returns>
|
||||||
bool DeleteItems(string[] fields, string[] vals);
|
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);
|
XInventoryItem[] GetActiveGestures(UUID principalID);
|
||||||
int GetAssetPermissions(UUID principalID, UUID assetID);
|
int GetAssetPermissions(UUID principalID, UUID assetID);
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,12 +43,12 @@ namespace OpenSim.Data.MSSQL
|
||||||
// private static readonly ILog m_log = LogManager.GetLogger(
|
// private static readonly ILog m_log = LogManager.GetLogger(
|
||||||
// MethodBase.GetCurrentMethod().DeclaringType);
|
// MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
private MSSQLGenericTableHandler<XInventoryFolder> m_Folders;
|
private MSSQLFolderHandler m_Folders;
|
||||||
private MSSQLItemHandler m_Items;
|
private MSSQLItemHandler m_Items;
|
||||||
|
|
||||||
public MSSQLXInventoryData(string conn, string realm)
|
public MSSQLXInventoryData(string conn, string realm)
|
||||||
{
|
{
|
||||||
m_Folders = new MSSQLGenericTableHandler<XInventoryFolder>(
|
m_Folders = new MSSQLFolderHandler(
|
||||||
conn, "inventoryfolders", "InventoryStore");
|
conn, "inventoryfolders", "InventoryStore");
|
||||||
m_Items = new MSSQLItemHandler(
|
m_Items = new MSSQLItemHandler(
|
||||||
conn, "inventoryitems", String.Empty);
|
conn, "inventoryitems", String.Empty);
|
||||||
|
@ -85,6 +85,7 @@ namespace OpenSim.Data.MSSQL
|
||||||
{
|
{
|
||||||
return m_Folders.Delete(field, val);
|
return m_Folders.Delete(field, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool DeleteFolders(string[] fields, string[] vals)
|
public bool DeleteFolders(string[] fields, string[] vals)
|
||||||
{
|
{
|
||||||
return m_Folders.Delete(fields, vals);
|
return m_Folders.Delete(fields, vals);
|
||||||
|
@ -94,15 +95,22 @@ namespace OpenSim.Data.MSSQL
|
||||||
{
|
{
|
||||||
return m_Items.Delete(field, val);
|
return m_Items.Delete(field, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool DeleteItems(string[] fields, string[] vals)
|
public bool DeleteItems(string[] fields, string[] vals)
|
||||||
{
|
{
|
||||||
return m_Items.Delete(fields, vals);
|
return m_Items.Delete(fields, vals);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool MoveItem(string id, string newParent)
|
public bool MoveItem(string id, string newParent)
|
||||||
{
|
{
|
||||||
return m_Items.MoveItem(id, 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)
|
public XInventoryItem[] GetActiveGestures(UUID principalID)
|
||||||
{
|
{
|
||||||
return m_Items.GetActiveGestures(principalID);
|
return m_Items.GetActiveGestures(principalID);
|
||||||
|
@ -124,79 +132,115 @@ namespace OpenSim.Data.MSSQL
|
||||||
public bool MoveItem(string id, string newParent)
|
public bool MoveItem(string id, string newParent)
|
||||||
{
|
{
|
||||||
using (SqlConnection conn = new SqlConnection(m_ConnectionString))
|
using (SqlConnection conn = new SqlConnection(m_ConnectionString))
|
||||||
using (SqlCommand cmd = new SqlCommand())
|
|
||||||
{
|
{
|
||||||
|
using (SqlCommand cmd = new SqlCommand())
|
||||||
|
{
|
||||||
|
|
||||||
cmd.CommandText = String.Format("update {0} set parentFolderID = @ParentFolderID where inventoryID = @InventoryID", m_Realm);
|
cmd.CommandText = String.Format("update {0} set parentFolderID = @ParentFolderID where inventoryID = @InventoryID", m_Realm);
|
||||||
cmd.Parameters.Add(m_database.CreateParameter("@ParentFolderID", newParent));
|
cmd.Parameters.Add(m_database.CreateParameter("@ParentFolderID", newParent));
|
||||||
cmd.Parameters.Add(m_database.CreateParameter("@InventoryID", id));
|
cmd.Parameters.Add(m_database.CreateParameter("@InventoryID", id));
|
||||||
cmd.Connection = conn;
|
cmd.Connection = conn;
|
||||||
conn.Open();
|
conn.Open();
|
||||||
return cmd.ExecuteNonQuery() == 0 ? false : true;
|
return cmd.ExecuteNonQuery() == 0 ? false : true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public XInventoryItem[] GetActiveGestures(UUID principalID)
|
public XInventoryItem[] GetActiveGestures(UUID principalID)
|
||||||
{
|
{
|
||||||
using (SqlConnection conn = new SqlConnection(m_ConnectionString))
|
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);
|
using (SqlCommand cmd = new SqlCommand())
|
||||||
|
{
|
||||||
|
cmd.CommandText = String.Format("select * from inventoryitems where avatarId = @uuid and assetType = @type and flags = 1", m_Realm);
|
||||||
|
|
||||||
cmd.Parameters.Add(m_database.CreateParameter("@uuid", principalID.ToString()));
|
cmd.Parameters.Add(m_database.CreateParameter("@uuid", principalID.ToString()));
|
||||||
cmd.Parameters.Add(m_database.CreateParameter("@type", (int)AssetType.Gesture));
|
cmd.Parameters.Add(m_database.CreateParameter("@type", (int)AssetType.Gesture));
|
||||||
cmd.Connection = conn;
|
cmd.Connection = conn;
|
||||||
conn.Open();
|
conn.Open();
|
||||||
return DoQuery(cmd);
|
return DoQuery(cmd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetAssetPermissions(UUID principalID, UUID assetID)
|
public int GetAssetPermissions(UUID principalID, UUID assetID)
|
||||||
{
|
{
|
||||||
using (SqlConnection conn = new SqlConnection(m_ConnectionString))
|
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);
|
using (SqlCommand cmd = new SqlCommand())
|
||||||
cmd.Parameters.Add(m_database.CreateParameter("@PrincipalID", principalID.ToString()));
|
|
||||||
cmd.Parameters.Add(m_database.CreateParameter("@AssetID", assetID.ToString()));
|
|
||||||
cmd.Connection = conn;
|
|
||||||
conn.Open();
|
|
||||||
using (SqlDataReader reader = cmd.ExecuteReader())
|
|
||||||
{
|
{
|
||||||
|
cmd.CommandText = String.Format("select bit_or(inventoryCurrentPermissions) as inventoryCurrentPermissions from inventoryitems where avatarID = @PrincipalID and assetID = @AssetID group by assetID", m_Realm);
|
||||||
int perms = 0;
|
cmd.Parameters.Add(m_database.CreateParameter("@PrincipalID", principalID.ToString()));
|
||||||
|
cmd.Parameters.Add(m_database.CreateParameter("@AssetID", assetID.ToString()));
|
||||||
if (reader.Read())
|
cmd.Connection = conn;
|
||||||
|
conn.Open();
|
||||||
|
using (SqlDataReader reader = cmd.ExecuteReader())
|
||||||
{
|
{
|
||||||
perms = Convert.ToInt32(reader["inventoryCurrentPermissions"]);
|
|
||||||
|
int perms = 0;
|
||||||
|
|
||||||
|
if (reader.Read())
|
||||||
|
{
|
||||||
|
perms = Convert.ToInt32(reader["inventoryCurrentPermissions"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return perms;
|
||||||
}
|
}
|
||||||
|
|
||||||
return perms;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Store(XInventoryItem item)
|
public override bool Store(XInventoryItem item)
|
||||||
{
|
{
|
||||||
if (!base.Store(item))
|
if (!base.Store(item))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
string sql = "update inventoryfolders set version=version+1 where folderID = @folderID";
|
string sql = "update inventoryfolders set version=version+1 where folderID = @folderID";
|
||||||
using (SqlConnection conn = new SqlConnection(m_ConnectionString))
|
using (SqlConnection conn = new SqlConnection(m_ConnectionString))
|
||||||
using (SqlCommand cmd = new SqlCommand(sql, conn))
|
|
||||||
{
|
{
|
||||||
conn.Open();
|
using (SqlCommand cmd = new SqlCommand(sql, conn))
|
||||||
|
{
|
||||||
|
conn.Open();
|
||||||
|
|
||||||
cmd.Parameters.AddWithValue("@folderID", item.parentFolderID.ToString());
|
cmd.Parameters.AddWithValue("@folderID", item.parentFolderID.ToString());
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
cmd.ExecuteNonQuery();
|
cmd.ExecuteNonQuery();
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -219,6 +219,8 @@ namespace OpenSim.Data.MySQL
|
||||||
|
|
||||||
public virtual bool Store(T row)
|
public virtual bool Store(T row)
|
||||||
{
|
{
|
||||||
|
// m_log.DebugFormat("[MYSQL GENERIC TABLE HANDLER]: Store(T row) invoked");
|
||||||
|
|
||||||
using (MySqlCommand cmd = new MySqlCommand())
|
using (MySqlCommand cmd = new MySqlCommand())
|
||||||
{
|
{
|
||||||
string query = "";
|
string query = "";
|
||||||
|
@ -273,6 +275,10 @@ namespace OpenSim.Data.MySQL
|
||||||
|
|
||||||
public virtual bool Delete(string[] fields, string[] keys)
|
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)
|
if (fields.Length != keys.Length)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
@ -26,9 +26,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Data;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using log4net;
|
using log4net;
|
||||||
using MySql.Data.MySqlClient;
|
using MySql.Data.MySqlClient;
|
||||||
using OpenMetaverse;
|
using OpenMetaverse;
|
||||||
|
@ -41,12 +42,12 @@ namespace OpenSim.Data.MySQL
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MySQLXInventoryData : IXInventoryData
|
public class MySQLXInventoryData : IXInventoryData
|
||||||
{
|
{
|
||||||
private MySQLGenericTableHandler<XInventoryFolder> m_Folders;
|
private MySqlFolderHandler m_Folders;
|
||||||
private MySqlItemHandler m_Items;
|
private MySqlItemHandler m_Items;
|
||||||
|
|
||||||
public MySQLXInventoryData(string conn, string realm)
|
public MySQLXInventoryData(string conn, string realm)
|
||||||
{
|
{
|
||||||
m_Folders = new MySQLGenericTableHandler<XInventoryFolder>(
|
m_Folders = new MySqlFolderHandler(
|
||||||
conn, "inventoryfolders", "InventoryStore");
|
conn, "inventoryfolders", "InventoryStore");
|
||||||
m_Items = new MySqlItemHandler(
|
m_Items = new MySqlItemHandler(
|
||||||
conn, "inventoryitems", String.Empty);
|
conn, "inventoryitems", String.Empty);
|
||||||
|
@ -105,6 +106,11 @@ namespace OpenSim.Data.MySQL
|
||||||
return m_Items.MoveItem(id, 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)
|
public XInventoryItem[] GetActiveGestures(UUID principalID)
|
||||||
{
|
{
|
||||||
return m_Items.GetActiveGestures(principalID);
|
return m_Items.GetActiveGestures(principalID);
|
||||||
|
@ -118,22 +124,69 @@ namespace OpenSim.Data.MySQL
|
||||||
|
|
||||||
public class MySqlItemHandler : MySQLGenericTableHandler<XInventoryItem>
|
public class MySqlItemHandler : MySQLGenericTableHandler<XInventoryItem>
|
||||||
{
|
{
|
||||||
|
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
public MySqlItemHandler(string c, string t, string m) :
|
public MySqlItemHandler(string c, string t, string m) :
|
||||||
base(c, t, 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)
|
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())
|
using (MySqlCommand cmd = new MySqlCommand())
|
||||||
{
|
{
|
||||||
|
|
||||||
cmd.CommandText = String.Format("update {0} set parentFolderID = ?ParentFolderID where inventoryID = ?InventoryID", m_Realm);
|
cmd.CommandText = String.Format("update {0} set parentFolderID = ?ParentFolderID where inventoryID = ?InventoryID", m_Realm);
|
||||||
cmd.Parameters.AddWithValue("?ParentFolderID", newParent);
|
cmd.Parameters.AddWithValue("?ParentFolderID", newParent);
|
||||||
cmd.Parameters.AddWithValue("?InventoryID", id);
|
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)
|
public XInventoryItem[] GetActiveGestures(UUID principalID)
|
||||||
|
@ -184,6 +237,21 @@ namespace OpenSim.Data.MySQL
|
||||||
if (!base.Store(item))
|
if (!base.Store(item))
|
||||||
return false;
|
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))
|
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
|
||||||
{
|
{
|
||||||
dbcon.Open();
|
dbcon.Open();
|
||||||
|
@ -193,7 +261,7 @@ namespace OpenSim.Data.MySQL
|
||||||
cmd.Connection = dbcon;
|
cmd.Connection = dbcon;
|
||||||
|
|
||||||
cmd.CommandText = String.Format("update inventoryfolders set version=version+1 where folderID = ?folderID");
|
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
|
try
|
||||||
{
|
{
|
||||||
|
@ -205,9 +273,96 @@ namespace OpenSim.Data.MySQL
|
||||||
}
|
}
|
||||||
cmd.Dispose();
|
cmd.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
dbcon.Close();
|
dbcon.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -47,7 +47,7 @@ namespace OpenSim.Data.SQLite
|
||||||
{
|
{
|
||||||
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
private SQLiteGenericTableHandler<XInventoryFolder> m_Folders;
|
private SqliteFolderHandler m_Folders;
|
||||||
private SqliteItemHandler m_Items;
|
private SqliteItemHandler m_Items;
|
||||||
|
|
||||||
public SQLiteXInventoryData(string conn, string realm)
|
public SQLiteXInventoryData(string conn, string realm)
|
||||||
|
@ -55,7 +55,7 @@ namespace OpenSim.Data.SQLite
|
||||||
if (Util.IsWindows())
|
if (Util.IsWindows())
|
||||||
Util.LoadArchSpecificWindowsDll("sqlite3.dll");
|
Util.LoadArchSpecificWindowsDll("sqlite3.dll");
|
||||||
|
|
||||||
m_Folders = new SQLiteGenericTableHandler<XInventoryFolder>(
|
m_Folders = new SqliteFolderHandler(
|
||||||
conn, "inventoryfolders", "XInventoryStore");
|
conn, "inventoryfolders", "XInventoryStore");
|
||||||
m_Items = new SqliteItemHandler(
|
m_Items = new SqliteItemHandler(
|
||||||
conn, "inventoryitems", String.Empty);
|
conn, "inventoryitems", String.Empty);
|
||||||
|
@ -114,6 +114,11 @@ namespace OpenSim.Data.SQLite
|
||||||
return m_Items.MoveItem(id, 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)
|
public XInventoryItem[] GetActiveGestures(UUID principalID)
|
||||||
{
|
{
|
||||||
return m_Items.GetActiveGestures(principalID);
|
return m_Items.GetActiveGestures(principalID);
|
||||||
|
@ -177,4 +182,23 @@ namespace OpenSim.Data.SQLite
|
||||||
return perms;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -121,6 +121,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods
|
||||||
|
|
||||||
if (sp != null || agentID == kickUserID)
|
if (sp != null || agentID == kickUserID)
|
||||||
{
|
{
|
||||||
|
m_dialogModule = m_scene.RequestModuleInterface<IDialogModule>();
|
||||||
if (m_scene.Permissions.IsGod(godID))
|
if (m_scene.Permissions.IsGod(godID))
|
||||||
{
|
{
|
||||||
if (kickflags == 0)
|
if (kickflags == 0)
|
||||||
|
@ -162,20 +163,27 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods
|
||||||
if (kickflags == 1)
|
if (kickflags == 1)
|
||||||
{
|
{
|
||||||
sp.AllowMovement = false;
|
sp.AllowMovement = false;
|
||||||
m_dialogModule.SendAlertToUser(agentID, Utils.BytesToString(reason));
|
if (m_dialogModule != null)
|
||||||
m_dialogModule.SendAlertToUser(godID, "User Frozen");
|
{
|
||||||
|
m_dialogModule.SendAlertToUser(agentID, Utils.BytesToString(reason));
|
||||||
|
m_dialogModule.SendAlertToUser(godID, "User Frozen");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kickflags == 2)
|
if (kickflags == 2)
|
||||||
{
|
{
|
||||||
sp.AllowMovement = true;
|
sp.AllowMovement = true;
|
||||||
m_dialogModule.SendAlertToUser(agentID, Utils.BytesToString(reason));
|
if (m_dialogModule != null)
|
||||||
m_dialogModule.SendAlertToUser(godID, "User Unfrozen");
|
{
|
||||||
|
m_dialogModule.SendAlertToUser(agentID, Utils.BytesToString(reason));
|
||||||
|
m_dialogModule.SendAlertToUser(godID, "User Unfrozen");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_dialogModule.SendAlertToUser(godID, "Kick request denied");
|
if (m_dialogModule != null)
|
||||||
|
m_dialogModule.SendAlertToUser(godID, "Kick request denied");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -210,8 +210,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
|
||||||
Guid id, string firstName, string lastName, string invPath, string pass, string savePath,
|
Guid id, string firstName, string lastName, string invPath, string pass, string savePath,
|
||||||
Dictionary<string, object> options)
|
Dictionary<string, object> options)
|
||||||
{
|
{
|
||||||
if (!ConsoleUtil.CheckFileDoesNotExist(MainConsole.Instance, savePath))
|
// if (!ConsoleUtil.CheckFileDoesNotExist(MainConsole.Instance, savePath))
|
||||||
return false;
|
// return false;
|
||||||
|
|
||||||
if (m_scenes.Count > 0)
|
if (m_scenes.Count > 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -434,16 +434,19 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
|
||||||
scene.SendInventoryUpdate(client, trashFolder, true, true);
|
scene.SendInventoryUpdate(client, trashFolder, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
ScenePresence user = scene.GetScenePresence(new UUID(im.toAgentID));
|
if (im.dialog == (byte)InstantMessageDialog.InventoryDeclined)
|
||||||
|
{
|
||||||
|
ScenePresence user = scene.GetScenePresence(new UUID(im.toAgentID));
|
||||||
|
|
||||||
if (user != null) // Local
|
if (user != null) // Local
|
||||||
{
|
{
|
||||||
user.ControllingClient.SendInstantMessage(im);
|
user.ControllingClient.SendInstantMessage(im);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (m_TransferModule != null)
|
if (m_TransferModule != null)
|
||||||
m_TransferModule.SendInstantMessage(im, delegate(bool success) {});
|
m_TransferModule.SendInstantMessage(im, delegate(bool success) { });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -259,8 +259,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0)
|
if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0)
|
||||||
{
|
{
|
||||||
// this user is going to another grid
|
// this user is going to another grid
|
||||||
// check if HyperGrid teleport is allowed, based on user level
|
// for local users, check if HyperGrid teleport is allowed, based on user level
|
||||||
if (sp.UserLevel < m_levelHGTeleport)
|
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.");
|
m_log.WarnFormat("[HG ENTITY TRANSFER MODULE]: Unable to HG teleport agent due to insufficient UserLevel.");
|
||||||
reason = "Hypergrid teleport not allowed";
|
reason = "Hypergrid teleport not allowed";
|
||||||
|
|
|
@ -92,7 +92,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
|
||||||
m_HomeURI = thisModuleConfig.GetString("HomeURI", m_HomeURI);
|
m_HomeURI = thisModuleConfig.GetString("HomeURI", m_HomeURI);
|
||||||
m_OutboundPermission = thisModuleConfig.GetBoolean("OutboundPermission", true);
|
m_OutboundPermission = thisModuleConfig.GetBoolean("OutboundPermission", true);
|
||||||
m_ThisGatekeeper = thisModuleConfig.GetString("Gatekeeper", string.Empty);
|
m_ThisGatekeeper = thisModuleConfig.GetString("Gatekeeper", string.Empty);
|
||||||
m_RestrictInventoryAccessAbroad = thisModuleConfig.GetBoolean("RestrictInventoryAccessAbroad", false);
|
m_RestrictInventoryAccessAbroad = thisModuleConfig.GetBoolean("RestrictInventoryAccessAbroad", true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
m_log.Warn("[HG INVENTORY ACCESS MODULE]: HGInventoryAccessModule configs not found. ProfileServerURI not set!");
|
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)
|
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)
|
private void ProcessInventoryForLeaving(IClientAPI client)
|
||||||
{
|
{
|
||||||
|
// No-op for now
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
|
@ -361,6 +361,22 @@ namespace OpenSim.Region.OptionalModules.Scripting.ScriptModuleComms
|
||||||
return null;
|
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
|
#endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -158,8 +158,10 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||||
else
|
else
|
||||||
path = DEFAULT_OAR_BACKUP_FILENAME;
|
path = DEFAULT_OAR_BACKUP_FILENAME;
|
||||||
|
|
||||||
if (!ConsoleUtil.CheckFileDoesNotExist(MainConsole.Instance, path))
|
// Not doing this right now as this causes some problems with auto-backup systems. Maybe a force flag is
|
||||||
return;
|
// needed
|
||||||
|
// if (!ConsoleUtil.CheckFileDoesNotExist(MainConsole.Instance, path))
|
||||||
|
// return;
|
||||||
|
|
||||||
ArchiveRegion(path, options);
|
ArchiveRegion(path, options);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Collections.Generic;
|
||||||
using OpenMetaverse;
|
using OpenMetaverse;
|
||||||
|
|
||||||
namespace OpenSim.Region.Framework.Interfaces
|
namespace OpenSim.Region.Framework.Interfaces
|
||||||
|
@ -131,6 +132,7 @@ namespace OpenSim.Region.Framework.Interfaces
|
||||||
/// <param name="cname">Name of constant</param>
|
/// <param name="cname">Name of constant</param>
|
||||||
/// <returns>Value of constant or null if none found.</returns>
|
/// <returns>Value of constant or null if none found.</returns>
|
||||||
object LookupModConstant(string cname);
|
object LookupModConstant(string cname);
|
||||||
|
Dictionary<string, object> GetConstants();
|
||||||
|
|
||||||
// For use ONLY by the script API
|
// For use ONLY by the script API
|
||||||
void RaiseEvent(UUID script, string id, string module, string command, string key);
|
void RaiseEvent(UUID script, string id, string module, string command, string key);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Contributors, http://opensimulator.org/
|
* Copyright (c) Contributors, http://opensimulator.org/
|
||||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||||
*
|
*
|
||||||
|
@ -538,7 +538,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
PhysicsActor.Velocity = value;
|
PhysicsActor.TargetVelocity = value;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|
|
@ -34,7 +34,7 @@ using OpenSim.Region.Physics.Manager;
|
||||||
|
|
||||||
namespace OpenSim.Region.Physics.BulletSPlugin
|
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 ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
private static readonly string LogHeader = "[BULLETS CHAR]";
|
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
|
// set _avatarVolume and _mass based on capsule size, _density and Scale
|
||||||
ComputeAvatarVolumeAndMass();
|
ComputeAvatarVolumeAndMass();
|
||||||
DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
|
DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
|
||||||
LocalID, _size, Scale, _avatarDensity, _avatarVolume, MassRaw);
|
LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
// do actual create at taint time
|
// do actual create at taint time
|
||||||
PhysicsScene.TaintedObject("BSCharacter.create", delegate()
|
PhysicsScene.TaintedObject("BSCharacter.create", delegate()
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSCharacter.create,taint", LocalID);
|
DetailLog("{0},BSCharacter.create,taint", LocalID);
|
||||||
// New body and shape into BSBody and BSShape
|
// New body and shape into PhysBody and PhysShape
|
||||||
PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this, shapeData, null, null, null);
|
PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this, null, null);
|
||||||
|
|
||||||
SetPhysicalProperties();
|
SetPhysicalProperties();
|
||||||
});
|
});
|
||||||
|
@ -131,46 +117,45 @@ public class BSCharacter : BSPhysObject
|
||||||
DetailLog("{0},BSCharacter.Destroy", LocalID);
|
DetailLog("{0},BSCharacter.Destroy", LocalID);
|
||||||
PhysicsScene.TaintedObject("BSCharacter.destroy", delegate()
|
PhysicsScene.TaintedObject("BSCharacter.destroy", delegate()
|
||||||
{
|
{
|
||||||
PhysicsScene.Shapes.DereferenceBody(BSBody, true, null);
|
PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null);
|
||||||
PhysicsScene.Shapes.DereferenceShape(BSShape, true, null);
|
PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetPhysicalProperties()
|
private void SetPhysicalProperties()
|
||||||
{
|
{
|
||||||
BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, BSBody.ptr);
|
BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr);
|
||||||
|
|
||||||
ZeroMotion();
|
ZeroMotion(true);
|
||||||
ForcePosition = _position;
|
ForcePosition = _position;
|
||||||
// Set the velocity and compute the proper friction
|
// Set the velocity and compute the proper friction
|
||||||
ForceVelocity = _velocity;
|
ForceVelocity = _velocity;
|
||||||
|
|
||||||
BulletSimAPI.SetRestitution2(BSBody.ptr, PhysicsScene.Params.avatarRestitution);
|
BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.avatarRestitution);
|
||||||
BulletSimAPI.SetMargin2(BSShape.ptr, PhysicsScene.Params.collisionMargin);
|
BulletSimAPI.SetMargin2(PhysShape.ptr, PhysicsScene.Params.collisionMargin);
|
||||||
BulletSimAPI.SetLocalScaling2(BSShape.ptr, Scale);
|
BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale);
|
||||||
BulletSimAPI.SetContactProcessingThreshold2(BSBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
|
BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
|
||||||
if (PhysicsScene.Params.ccdMotionThreshold > 0f)
|
if (PhysicsScene.Params.ccdMotionThreshold > 0f)
|
||||||
{
|
{
|
||||||
BulletSimAPI.SetCcdMotionThreshold2(BSBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
|
BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
|
||||||
BulletSimAPI.SetCcdSweepSphereRadius2(BSBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
|
BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
|
||||||
}
|
}
|
||||||
|
|
||||||
OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(BSShape.ptr, MassRaw);
|
UpdatePhysicalMassProperties(RawMass);
|
||||||
BulletSimAPI.SetMassProps2(BSBody.ptr, MassRaw, localInertia);
|
|
||||||
|
|
||||||
// Make so capsule does not fall over
|
// 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.ACTIVE_TAG);
|
||||||
BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.DISABLE_DEACTIVATION);
|
BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_DEACTIVATION);
|
||||||
BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, BSBody.ptr);
|
BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr);
|
||||||
|
|
||||||
// Do this after the object has been added to the world
|
// Do this after the object has been added to the world
|
||||||
BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr,
|
BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr,
|
||||||
(uint)CollisionFilterGroups.AvatarFilter,
|
(uint)CollisionFilterGroups.AvatarFilter,
|
||||||
(uint)CollisionFilterGroups.AvatarMask);
|
(uint)CollisionFilterGroups.AvatarMask);
|
||||||
}
|
}
|
||||||
|
@ -196,13 +181,12 @@ public class BSCharacter : BSPhysObject
|
||||||
ComputeAvatarScale(_size);
|
ComputeAvatarScale(_size);
|
||||||
ComputeAvatarVolumeAndMass();
|
ComputeAvatarVolumeAndMass();
|
||||||
DetailLog("{0},BSCharacter.setSize,call,scale={1},density={2},volume={3},mass={4}",
|
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()
|
PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
|
||||||
{
|
{
|
||||||
BulletSimAPI.SetLocalScaling2(BSShape.ptr, Scale);
|
BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale);
|
||||||
OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(BSShape.ptr, MassRaw);
|
UpdatePhysicalMassProperties(RawMass);
|
||||||
BulletSimAPI.SetMassProps2(BSBody.ptr, MassRaw, localInertia);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -214,6 +198,11 @@ public class BSCharacter : BSPhysObject
|
||||||
{
|
{
|
||||||
set { BaseShape = value; }
|
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 {
|
public override bool Grabbed {
|
||||||
set { _grabbed = value; }
|
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.
|
// Do it to the properties so the values get set in the physics engine.
|
||||||
// Push the setting of the values to the viewer.
|
// Push the setting of the values to the viewer.
|
||||||
// Called at taint time!
|
// Called at taint time!
|
||||||
public override void ZeroMotion()
|
public override void ZeroMotion(bool inTaintTime)
|
||||||
{
|
{
|
||||||
_velocity = OMV.Vector3.Zero;
|
_velocity = OMV.Vector3.Zero;
|
||||||
_acceleration = OMV.Vector3.Zero;
|
_acceleration = OMV.Vector3.Zero;
|
||||||
_rotationalVelocity = OMV.Vector3.Zero;
|
_rotationalVelocity = OMV.Vector3.Zero;
|
||||||
|
|
||||||
// Zero some other properties directly into the physics engine
|
// Zero some other properties directly into the physics engine
|
||||||
BulletSimAPI.SetLinearVelocity2(BSBody.ptr, OMV.Vector3.Zero);
|
PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
|
||||||
BulletSimAPI.SetAngularVelocity2(BSBody.ptr, OMV.Vector3.Zero);
|
{
|
||||||
BulletSimAPI.SetInterpolationVelocity2(BSBody.ptr, OMV.Vector3.Zero, OMV.Vector3.Zero);
|
BulletSimAPI.ClearAllForces2(PhysBody.ptr);
|
||||||
BulletSimAPI.ClearForces2(BSBody.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 void LockAngularMotion(OMV.Vector3 axis) { return; }
|
||||||
|
|
||||||
|
public override OMV.Vector3 RawPosition
|
||||||
|
{
|
||||||
|
get { return _position; }
|
||||||
|
set { _position = value; }
|
||||||
|
}
|
||||||
public override OMV.Vector3 Position {
|
public override OMV.Vector3 Position {
|
||||||
get {
|
get {
|
||||||
|
// Don't refetch the position because this function is called a zillion times
|
||||||
// _position = BulletSimAPI.GetObjectPosition2(Scene.World.ptr, LocalID);
|
// _position = BulletSimAPI.GetObjectPosition2(Scene.World.ptr, LocalID);
|
||||||
return _position;
|
return _position;
|
||||||
}
|
}
|
||||||
|
@ -256,19 +264,19 @@ public class BSCharacter : BSPhysObject
|
||||||
PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate()
|
PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate()
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
|
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 {
|
public override OMV.Vector3 ForcePosition {
|
||||||
get {
|
get {
|
||||||
_position = BulletSimAPI.GetPosition2(BSBody.ptr);
|
_position = BulletSimAPI.GetPosition2(PhysBody.ptr);
|
||||||
return _position;
|
return _position;
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
_position = value;
|
_position = value;
|
||||||
PositionSanityCheck();
|
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
|
// The new position value must be pushed into the physics engine but we can't
|
||||||
// just assign to "Position" because of potential call loops.
|
// 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);
|
DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
|
||||||
BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
|
BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
|
||||||
};
|
});
|
||||||
if (inTaintTime)
|
|
||||||
sanityOperation();
|
|
||||||
else
|
|
||||||
PhysicsScene.TaintedObject("BSCharacter.PositionSanityCheck", sanityOperation);
|
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -329,7 +333,14 @@ public class BSCharacter : BSPhysObject
|
||||||
public override float Mass { get { return _mass; } }
|
public override float Mass { get { return _mass; } }
|
||||||
|
|
||||||
// used when we only want this prim's mass and not the linkset thing
|
// 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 {
|
public override OMV.Vector3 Force {
|
||||||
get { return _force; }
|
get { return _force; }
|
||||||
|
@ -339,7 +350,7 @@ public class BSCharacter : BSPhysObject
|
||||||
PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate()
|
PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate()
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
|
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)
|
if (_currentFriction != PhysicsScene.Params.avatarStandingFriction)
|
||||||
{
|
{
|
||||||
_currentFriction = PhysicsScene.Params.avatarStandingFriction;
|
_currentFriction = PhysicsScene.Params.avatarStandingFriction;
|
||||||
BulletSimAPI.SetFriction2(BSBody.ptr, _currentFriction);
|
BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -386,15 +397,15 @@ public class BSCharacter : BSPhysObject
|
||||||
if (_currentFriction != PhysicsScene.Params.avatarFriction)
|
if (_currentFriction != PhysicsScene.Params.avatarFriction)
|
||||||
{
|
{
|
||||||
_currentFriction = PhysicsScene.Params.avatarFriction;
|
_currentFriction = PhysicsScene.Params.avatarFriction;
|
||||||
BulletSimAPI.SetFriction2(BSBody.ptr, _currentFriction);
|
BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_velocity = value;
|
_velocity = value;
|
||||||
// Remember the set velocity so we can suppress the reduction by friction, ...
|
// Remember the set velocity so we can suppress the reduction by friction, ...
|
||||||
_appliedVelocity = value;
|
_appliedVelocity = value;
|
||||||
|
|
||||||
BulletSimAPI.SetLinearVelocity2(BSBody.ptr, _velocity);
|
BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
|
||||||
BulletSimAPI.Activate2(BSBody.ptr, true);
|
BulletSimAPI.Activate2(PhysBody.ptr, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public override OMV.Vector3 Torque {
|
public override OMV.Vector3 Torque {
|
||||||
|
@ -411,6 +422,11 @@ public class BSCharacter : BSPhysObject
|
||||||
get { return _acceleration; }
|
get { return _acceleration; }
|
||||||
set { _acceleration = value; }
|
set { _acceleration = value; }
|
||||||
}
|
}
|
||||||
|
public override OMV.Quaternion RawOrientation
|
||||||
|
{
|
||||||
|
get { return _orientation; }
|
||||||
|
set { _orientation = value; }
|
||||||
|
}
|
||||||
public override OMV.Quaternion Orientation {
|
public override OMV.Quaternion Orientation {
|
||||||
get { return _orientation; }
|
get { return _orientation; }
|
||||||
set {
|
set {
|
||||||
|
@ -419,7 +435,7 @@ public class BSCharacter : BSPhysObject
|
||||||
PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate()
|
PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate()
|
||||||
{
|
{
|
||||||
// _position = BulletSimAPI.GetPosition2(BSBody.ptr);
|
// _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
|
get
|
||||||
{
|
{
|
||||||
_orientation = BulletSimAPI.GetOrientation2(BSBody.ptr);
|
_orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr);
|
||||||
return _orientation;
|
return _orientation;
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_orientation = value;
|
_orientation = value;
|
||||||
BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
|
BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public override int PhysicsActorType {
|
public override int PhysicsActorType {
|
||||||
|
@ -493,9 +509,9 @@ public class BSCharacter : BSPhysObject
|
||||||
PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate()
|
PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate()
|
||||||
{
|
{
|
||||||
if (_floatOnWater)
|
if (_floatOnWater)
|
||||||
CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
|
CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
|
||||||
else
|
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);
|
DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
|
||||||
// Buoyancy is faked by changing the gravity applied to the object
|
// Buoyancy is faked by changing the gravity applied to the object
|
||||||
float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
|
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()
|
PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate()
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force);
|
DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force);
|
||||||
BulletSimAPI.SetObjectForce2(BSBody.ptr, _force);
|
BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -642,7 +658,7 @@ public class BSCharacter : BSPhysObject
|
||||||
// That's just the way they are defined.
|
// That's just the way they are defined.
|
||||||
OMV.Vector3 avVel = new OMV.Vector3(_appliedVelocity.X, _appliedVelocity.Y, entprop.Velocity.Z);
|
OMV.Vector3 avVel = new OMV.Vector3(_appliedVelocity.X, _appliedVelocity.Y, entprop.Velocity.Z);
|
||||||
_velocity = avVel;
|
_velocity = avVel;
|
||||||
BulletSimAPI.SetLinearVelocity2(BSBody.ptr, avVel);
|
BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, avVel);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tell the linkset about value changes
|
// Tell the linkset about value changes
|
||||||
|
|
|
@ -42,6 +42,12 @@ public abstract class BSConstraint : IDisposable
|
||||||
protected BulletConstraint m_constraint;
|
protected BulletConstraint m_constraint;
|
||||||
protected bool m_enabled = false;
|
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()
|
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)
|
public virtual bool SetLinearLimits(Vector3 low, Vector3 high)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
|
@ -32,14 +32,14 @@ using OpenMetaverse;
|
||||||
namespace OpenSim.Region.Physics.BulletSPlugin
|
namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
{
|
{
|
||||||
|
|
||||||
public class BS6DofConstraint : BSConstraint
|
public sealed class BSConstraint6Dof : BSConstraint
|
||||||
{
|
{
|
||||||
private static string LogHeader = "[BULLETSIM 6DOF CONSTRAINT]";
|
private static string LogHeader = "[BULLETSIM 6DOF CONSTRAINT]";
|
||||||
|
|
||||||
public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } }
|
public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } }
|
||||||
|
|
||||||
// Create a btGeneric6DofConstraint
|
// Create a btGeneric6DofConstraint
|
||||||
public BS6DofConstraint(BulletSim world, BulletBody obj1, BulletBody obj2,
|
public BSConstraint6Dof(BulletSim world, BulletBody obj1, BulletBody obj2,
|
||||||
Vector3 frame1, Quaternion frame1rot,
|
Vector3 frame1, Quaternion frame1rot,
|
||||||
Vector3 frame2, Quaternion frame2rot,
|
Vector3 frame2, Quaternion frame2rot,
|
||||||
bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
|
bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
|
||||||
|
@ -58,7 +58,7 @@ public class BS6DofConstraint : BSConstraint
|
||||||
obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
|
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,
|
Vector3 joinPoint,
|
||||||
bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
|
bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
|
||||||
{
|
{
|
||||||
|
@ -71,8 +71,7 @@ public class BS6DofConstraint : BSConstraint
|
||||||
BSScene.DetailLogZero, world.worldID,
|
BSScene.DetailLogZero, world.worldID,
|
||||||
obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
|
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}",
|
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,
|
LogHeader, world.worldID, obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
|
||||||
obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
|
|
||||||
m_enabled = false;
|
m_enabled = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -135,7 +134,11 @@ public class BS6DofConstraint : BSConstraint
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
|
float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
|
||||||
if (m_enabled)
|
if (m_enabled)
|
||||||
|
{
|
||||||
ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.ptr, onOff, targetVelocity, maxMotorForce);
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ using OpenMetaverse;
|
||||||
namespace OpenSim.Region.Physics.BulletSPlugin
|
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 ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
// private static readonly string LogHeader = "[CONSTRAINT COLLECTION]";
|
// private static readonly string LogHeader = "[CONSTRAINT COLLECTION]";
|
||||||
|
@ -143,8 +143,6 @@ public class BSConstraintCollection : IDisposable
|
||||||
// Return 'true' if any constraints were destroyed.
|
// Return 'true' if any constraints were destroyed.
|
||||||
public bool RemoveAndDestroyConstraint(BulletBody body1)
|
public bool RemoveAndDestroyConstraint(BulletBody body1)
|
||||||
{
|
{
|
||||||
// return BulletSimAPI.RemoveConstraintByID(m_world.ID, obj.ID);
|
|
||||||
|
|
||||||
List<BSConstraint> toRemove = new List<BSConstraint>();
|
List<BSConstraint> toRemove = new List<BSConstraint>();
|
||||||
uint lookingID = body1.ID;
|
uint lookingID = body1.ID;
|
||||||
lock (m_constraints)
|
lock (m_constraints)
|
||||||
|
|
|
@ -32,11 +32,11 @@ using OpenMetaverse;
|
||||||
namespace OpenSim.Region.Physics.BulletSPlugin
|
namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
{
|
{
|
||||||
|
|
||||||
class BSHingeConstraint : BSConstraint
|
public sealed class BSConstraintHinge : BSConstraint
|
||||||
{
|
{
|
||||||
public override ConstraintType Type { get { return ConstraintType.HINGE_CONSTRAINT_TYPE; } }
|
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 pivotInA, Vector3 pivotInB,
|
||||||
Vector3 axisInA, Vector3 axisInB,
|
Vector3 axisInA, Vector3 axisInB,
|
||||||
bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
|
bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
|
File diff suppressed because it is too large
Load Diff
|
@ -36,20 +36,32 @@ public abstract class BSLinkset
|
||||||
{
|
{
|
||||||
// private static string LogHeader = "[BULLETSIM LINKSET]";
|
// 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
|
// Create the correct type of linkset for this child
|
||||||
public static BSLinkset Factory(BSScene physScene, BSPhysObject parent)
|
public static BSLinkset Factory(BSScene physScene, BSPhysObject parent)
|
||||||
{
|
{
|
||||||
BSLinkset ret = null;
|
BSLinkset ret = null;
|
||||||
/*
|
|
||||||
if (parent.IsPhysical)
|
|
||||||
ret = new BSLinksetConstraints(physScene, parent);
|
|
||||||
else
|
|
||||||
ret = new BSLinksetManual(physScene, parent);
|
|
||||||
*/
|
|
||||||
|
|
||||||
// at the moment, there is only one
|
|
||||||
ret = new BSLinksetConstraints(physScene, parent);
|
|
||||||
|
|
||||||
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,33 +73,39 @@ public abstract class BSLinkset
|
||||||
public int LinksetID { get; private set; }
|
public int LinksetID { get; private set; }
|
||||||
|
|
||||||
// The children under the root in this linkset.
|
// 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_children;
|
||||||
protected HashSet<BSPhysObject> m_taintChildren;
|
|
||||||
|
|
||||||
// We lock the diddling of linkset classes to prevent any badness.
|
// We lock the diddling of linkset classes to prevent any badness.
|
||||||
// This locks the modification of the instances of this class. Changes
|
// This locks the modification of the instances of this class. Changes
|
||||||
// to the physical representation is done via the tainting mechenism.
|
// to the physical representation is done via the tainting mechenism.
|
||||||
protected object m_linksetActivityLock = new Object();
|
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
|
// We keep the prim's mass in the linkset structure since it could be dependent on other prims
|
||||||
protected float m_mass;
|
protected float m_mass;
|
||||||
public float LinksetMass
|
public float LinksetMass
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
m_mass = ComputeLinksetMass();
|
|
||||||
return m_mass;
|
return m_mass;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual bool LinksetIsColliding { get { return false; } }
|
||||||
|
|
||||||
public OMV.Vector3 CenterOfMass
|
public OMV.Vector3 CenterOfMass
|
||||||
{
|
{
|
||||||
get { return ComputeLinksetCenterOfMass(); }
|
get { return ComputeLinksetCenterOfMass(); }
|
||||||
|
@ -108,8 +126,7 @@ public abstract class BSLinkset
|
||||||
PhysicsScene = scene;
|
PhysicsScene = scene;
|
||||||
LinksetRoot = parent;
|
LinksetRoot = parent;
|
||||||
m_children = new HashSet<BSPhysObject>();
|
m_children = new HashSet<BSPhysObject>();
|
||||||
m_taintChildren = new HashSet<BSPhysObject>();
|
m_mass = parent.RawMass;
|
||||||
m_mass = parent.MassRaw;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Link to a linkset where the child knows the parent.
|
// 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
|
// Don't add the root to its own linkset
|
||||||
if (!IsRoot(child))
|
if (!IsRoot(child))
|
||||||
AddChildToLinkset(child);
|
AddChildToLinkset(child);
|
||||||
|
m_mass = ComputeLinksetMass();
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -140,8 +158,8 @@ public abstract class BSLinkset
|
||||||
// Cannot remove the root from a linkset.
|
// Cannot remove the root from a linkset.
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
RemoveChildFromLinkset(child);
|
RemoveChildFromLinkset(child);
|
||||||
|
m_mass = ComputeLinksetMass();
|
||||||
}
|
}
|
||||||
|
|
||||||
// The child is down to a linkset of just itself
|
// The child is down to a linkset of just itself
|
||||||
|
@ -165,9 +183,8 @@ public abstract class BSLinkset
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
lock (m_linksetActivityLock)
|
lock (m_linksetActivityLock)
|
||||||
{
|
{
|
||||||
if (m_children.Contains(child))
|
ret = m_children.Contains(child);
|
||||||
ret = true;
|
/* Safer version but the above should work
|
||||||
/*
|
|
||||||
foreach (BSPhysObject bp in m_children)
|
foreach (BSPhysObject bp in m_children)
|
||||||
{
|
{
|
||||||
if (child.LocalID == bp.LocalID)
|
if (child.LocalID == bp.LocalID)
|
||||||
|
@ -181,10 +198,36 @@ public abstract class BSLinkset
|
||||||
return ret;
|
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
|
// When physical properties are changed the linkset needs to recalculate
|
||||||
// its internal properties.
|
// its internal properties.
|
||||||
// May be called at runtime or taint-time (just pass the appropriate flag).
|
// May be called at runtime or taint-time.
|
||||||
public abstract void Refresh(BSPhysObject requestor, bool inTaintTime);
|
public abstract void Refresh(BSPhysObject requestor);
|
||||||
|
|
||||||
// The object is going dynamic (physical). Do any setup necessary
|
// The object is going dynamic (physical). Do any setup necessary
|
||||||
// for a dynamic linkset.
|
// for a dynamic linkset.
|
||||||
|
@ -218,17 +261,17 @@ public abstract class BSLinkset
|
||||||
public abstract void RestoreBodyDependencies(BSPrim child);
|
public abstract void RestoreBodyDependencies(BSPrim child);
|
||||||
|
|
||||||
// ================================================================
|
// ================================================================
|
||||||
// Below this point is internal magic
|
|
||||||
|
|
||||||
protected virtual float ComputeLinksetMass()
|
protected virtual float ComputeLinksetMass()
|
||||||
{
|
{
|
||||||
float mass;
|
float mass = LinksetRoot.RawMass;
|
||||||
lock (m_linksetActivityLock)
|
if (HasAnyChildren)
|
||||||
{
|
{
|
||||||
mass = LinksetRoot.MassRaw;
|
lock (m_linksetActivityLock)
|
||||||
foreach (BSPhysObject bp in m_taintChildren)
|
|
||||||
{
|
{
|
||||||
mass += bp.MassRaw;
|
foreach (BSPhysObject bp in m_children)
|
||||||
|
{
|
||||||
|
mass += bp.RawMass;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return mass;
|
return mass;
|
||||||
|
@ -239,13 +282,13 @@ public abstract class BSLinkset
|
||||||
OMV.Vector3 com;
|
OMV.Vector3 com;
|
||||||
lock (m_linksetActivityLock)
|
lock (m_linksetActivityLock)
|
||||||
{
|
{
|
||||||
com = LinksetRoot.Position * LinksetRoot.MassRaw;
|
com = LinksetRoot.Position * LinksetRoot.RawMass;
|
||||||
float totalMass = LinksetRoot.MassRaw;
|
float totalMass = LinksetRoot.RawMass;
|
||||||
|
|
||||||
foreach (BSPhysObject bp in m_taintChildren)
|
foreach (BSPhysObject bp in m_children)
|
||||||
{
|
{
|
||||||
com += bp.Position * bp.MassRaw;
|
com += bp.Position * bp.RawMass;
|
||||||
totalMass += bp.MassRaw;
|
totalMass += bp.RawMass;
|
||||||
}
|
}
|
||||||
if (totalMass != 0f)
|
if (totalMass != 0f)
|
||||||
com /= totalMass;
|
com /= totalMass;
|
||||||
|
@ -261,31 +304,16 @@ public abstract class BSLinkset
|
||||||
{
|
{
|
||||||
com = LinksetRoot.Position;
|
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;
|
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.
|
// Invoke the detailed logger and output something if it's enabled.
|
||||||
protected void DetailLog(string msg, params Object[] args)
|
protected void DetailLog(string msg, params Object[] args)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -32,7 +32,7 @@ using OMV = OpenMetaverse;
|
||||||
|
|
||||||
namespace OpenSim.Region.Physics.BulletSPlugin
|
namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
{
|
{
|
||||||
public class BSLinksetConstraints : BSLinkset
|
public sealed class BSLinksetConstraints : BSLinkset
|
||||||
{
|
{
|
||||||
// private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]";
|
// 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
|
// When physical properties are changed the linkset needs to recalculate
|
||||||
// its internal properties.
|
// its internal properties.
|
||||||
// May be called at runtime or taint-time (just pass the appropriate flag).
|
// This is queued in the 'post taint' queue so the
|
||||||
public override void Refresh(BSPhysObject requestor, bool inTaintTime)
|
// 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
|
// Queue to happen after all the other taint processing
|
||||||
if (!HasAnyChildren || !IsRoot(requestor))
|
PhysicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate()
|
||||||
return;
|
|
||||||
|
|
||||||
BSScene.TaintCallback refreshOperation = delegate()
|
|
||||||
{
|
{
|
||||||
RecomputeLinksetConstraintVariables();
|
if (HasAnyChildren && IsRoot(requestor))
|
||||||
DetailLog("{0},BSLinkset.Refresh,complete,rBody={1}",
|
RecomputeLinksetConstraints();
|
||||||
LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
|
});
|
||||||
};
|
|
||||||
if (inTaintTime)
|
|
||||||
refreshOperation();
|
|
||||||
else
|
|
||||||
PhysicsScene.TaintedObject("BSLinkSet.Refresh", refreshOperation);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The object is going dynamic (physical). Do any setup necessary
|
// The object is going dynamic (physical). Do any setup necessary
|
||||||
|
@ -74,9 +67,10 @@ public class BSLinksetConstraints : BSLinkset
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The object is going static (non-physical). Do any setup necessary
|
// The object is going static (non-physical). Do any setup necessary for a static linkset.
|
||||||
// for a static linkset.
|
|
||||||
// Return 'true' if any properties updated on the passed object.
|
// Return 'true' if any properties updated on the passed object.
|
||||||
|
// This doesn't normally happen -- OpenSim removes the objects from the physical
|
||||||
|
// world if it is a static linkset.
|
||||||
// Called at taint-time!
|
// Called at taint-time!
|
||||||
public override bool MakeStatic(BSPhysObject child)
|
public override bool MakeStatic(BSPhysObject child)
|
||||||
{
|
{
|
||||||
|
@ -90,35 +84,36 @@ public class BSLinksetConstraints : BSLinkset
|
||||||
// Nothing to do for constraints on property updates
|
// Nothing to do for constraints on property updates
|
||||||
}
|
}
|
||||||
|
|
||||||
// Routine used when rebuilding the body of the root of the linkset
|
// The children of the linkset are moved around by the constraints.
|
||||||
// Destroy all the constraints have have been made to root.
|
// Just grab the current values of wherever it is right now.
|
||||||
// This is called when the root body is changing.
|
public override OMV.Vector3 Position(BSPhysObject member)
|
||||||
// Returns 'true' of something eas actually removed and would need restoring
|
{
|
||||||
|
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!!
|
// Called at taint-time!!
|
||||||
public override bool RemoveBodyDependencies(BSPrim child)
|
public override bool RemoveBodyDependencies(BSPrim child)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
|
DetailLog("{0},BSLinksetConstraint.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}",
|
||||||
|
child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"));
|
||||||
|
|
||||||
lock (m_linksetActivityLock)
|
lock (m_linksetActivityLock)
|
||||||
{
|
{
|
||||||
if (IsRoot(child))
|
// Just undo all the constraints for this linkset. Rebuild at the end of the step.
|
||||||
{
|
ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
|
||||||
// If the one with the dependency is root, must undo all children
|
// Cause the constraints, et al to be rebuilt before the next simulation step.
|
||||||
DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}",
|
Refresh(LinksetRoot);
|
||||||
child.LocalID, LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
|
|
||||||
|
|
||||||
ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
|
|
||||||
child.LocalID,
|
|
||||||
LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
|
|
||||||
child.LocalID, child.BSBody.ptr.ToString("X"));
|
|
||||||
// ret = PhysicallyUnlinkAChildFromRoot(LinksetRoot, child);
|
|
||||||
// Despite the function name, this removes any link to the specified object.
|
|
||||||
ret = PhysicallyUnlinkAllChildrenFromRoot(child);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -128,32 +123,12 @@ public class BSLinksetConstraints : BSLinkset
|
||||||
// Called at taint-time!!
|
// Called at taint-time!!
|
||||||
public override void RestoreBodyDependencies(BSPrim child)
|
public override void RestoreBodyDependencies(BSPrim child)
|
||||||
{
|
{
|
||||||
lock (m_linksetActivityLock)
|
// The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints.
|
||||||
{
|
|
||||||
if (IsRoot(child))
|
|
||||||
{
|
|
||||||
DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreChildrenForRoot,rID={1},numChild={2}",
|
|
||||||
child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count);
|
|
||||||
foreach (BSPhysObject bpo in m_taintChildren)
|
|
||||||
{
|
|
||||||
PhysicallyLinkAChildToRoot(LinksetRoot, bpo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
|
|
||||||
LinksetRoot.LocalID,
|
|
||||||
LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
|
|
||||||
child.LocalID, child.BSBody.ptr.ToString("X"));
|
|
||||||
PhysicallyLinkAChildToRoot(LinksetRoot, child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================================================================
|
// ================================================================
|
||||||
// Below this point is internal magic
|
|
||||||
|
|
||||||
// I am the root of a linkset and a new child is being added
|
// Add a new child to the linkset.
|
||||||
// Called while LinkActivity is locked.
|
// Called while LinkActivity is locked.
|
||||||
protected override void AddChildToLinkset(BSPhysObject child)
|
protected override void AddChildToLinkset(BSPhysObject child)
|
||||||
{
|
{
|
||||||
|
@ -161,39 +136,15 @@ public class BSLinksetConstraints : BSLinkset
|
||||||
{
|
{
|
||||||
m_children.Add(child);
|
m_children.Add(child);
|
||||||
|
|
||||||
BSPhysObject rootx = LinksetRoot; // capture the root as of now
|
DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
|
||||||
BSPhysObject childx = child;
|
|
||||||
|
|
||||||
DetailLog("{0},AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
|
// Cause constraints and assorted properties to be recomputed before the next simulation step.
|
||||||
|
Refresh(LinksetRoot);
|
||||||
PhysicsScene.TaintedObject("AddChildToLinkset", delegate()
|
|
||||||
{
|
|
||||||
DetailLog("{0},AddChildToLinkset,taint,rID={1},rBody={2},cID={3},cBody={4}",
|
|
||||||
rootx.LocalID,
|
|
||||||
rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
|
|
||||||
childx.LocalID, childx.BSBody.ptr.ToString("X"));
|
|
||||||
// Since this is taint-time, the body and shape could have changed for the child
|
|
||||||
rootx.ForcePosition = rootx.Position; // DEBUG
|
|
||||||
childx.ForcePosition = childx.Position; // DEBUG
|
|
||||||
PhysicallyLinkAChildToRoot(rootx, childx);
|
|
||||||
m_taintChildren.Add(child);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Forcefully removing a child from a linkset.
|
// Remove the specified child from the linkset.
|
||||||
// This is not being called by the child so we have to make sure the child doesn't think
|
|
||||||
// it's still connected to the linkset.
|
|
||||||
// Normal OpenSimulator operation will never do this because other SceneObjectPart information
|
|
||||||
// also has to be updated (like pointer to prim's parent).
|
|
||||||
protected override void RemoveChildFromOtherLinkset(BSPhysObject pchild)
|
|
||||||
{
|
|
||||||
pchild.Linkset = BSLinkset.Factory(PhysicsScene, pchild);
|
|
||||||
RemoveChildFromLinkset(pchild);
|
|
||||||
}
|
|
||||||
|
|
||||||
// I am the root of a linkset and one of my children is being removed.
|
|
||||||
// Safe to call even if the child is not really in my linkset.
|
// Safe to call even if the child is not really in my linkset.
|
||||||
protected override void RemoveChildFromLinkset(BSPhysObject child)
|
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 rootx = LinksetRoot; // capture the root and body as of now
|
||||||
BSPhysObject childx = child;
|
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,
|
childx.LocalID,
|
||||||
rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
|
rootx.LocalID, rootx.PhysBody.ptr.ToString("X"),
|
||||||
childx.LocalID, childx.BSBody.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);
|
PhysicallyUnlinkAChildFromRoot(rootx, childx);
|
||||||
RecomputeLinksetConstraintVariables();
|
|
||||||
});
|
});
|
||||||
|
// See that the linkset parameters are recomputed at the end of the taint time.
|
||||||
|
Refresh(LinksetRoot);
|
||||||
}
|
}
|
||||||
else
|
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);
|
// PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -226,9 +176,15 @@ public class BSLinksetConstraints : BSLinkset
|
||||||
// Create a constraint between me (root of linkset) and the passed prim (the child).
|
// Create a constraint between me (root of linkset) and the passed prim (the child).
|
||||||
// Called at taint time!
|
// Called at taint time!
|
||||||
private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
|
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
|
// Zero motion for children so they don't interpolate
|
||||||
childPrim.ZeroMotion();
|
childPrim.ZeroMotion(true);
|
||||||
|
|
||||||
// Relative position normalized to the root prim
|
// Relative position normalized to the root prim
|
||||||
// Essentually a vector pointing from center of rootPrim to center of childPrim
|
// 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
|
// real world coordinate of midpoint between the two objects
|
||||||
OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
|
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.LocalID, rootPrim.BSBody.ptr.ToString("X"),
|
rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString("X"),
|
||||||
childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"),
|
childPrim.LocalID, childPrim.PhysBody.ptr.ToString("X"),
|
||||||
rootPrim.Position, childPrim.Position, midPoint);
|
rootPrim.Position, childPrim.Position, midPoint);
|
||||||
|
|
||||||
// create a constraint that allows no freedom of movement between the two objects
|
// create a constraint that allows no freedom of movement between the two objects
|
||||||
// http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
|
// http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
|
||||||
|
|
||||||
BS6DofConstraint constrain = new BS6DofConstraint(
|
BSConstraint6Dof constrain = new BSConstraint6Dof(
|
||||||
PhysicsScene.World, rootPrim.BSBody, childPrim.BSBody, midPoint, true, true );
|
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.
|
/* 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
|
* Using the midpoint is easier since it lets the Bullet code manipulate the transforms
|
||||||
* of the objects.
|
* of the objects.
|
||||||
* Code left as a warning to future programmers.
|
* Code left for future programmers.
|
||||||
// ==================================================================================
|
// ==================================================================================
|
||||||
// relative position normalized to the root prim
|
// relative position normalized to the root prim
|
||||||
OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
|
OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
|
||||||
|
@ -262,20 +219,13 @@ public class BSLinksetConstraints : BSLinkset
|
||||||
OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
|
OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
|
||||||
OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);
|
OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);
|
||||||
|
|
||||||
// create a constraint that allows no freedom of movement between the two objects
|
DetailLog("{0},BSLinksetConstraint.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
|
||||||
// http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
|
|
||||||
DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
|
|
||||||
BS6DofConstraint constrain = new BS6DofConstraint(
|
BS6DofConstraint constrain = new BS6DofConstraint(
|
||||||
PhysicsScene.World, rootPrim.Body, childPrim.Body,
|
PhysicsScene.World, rootPrim.Body, childPrim.Body,
|
||||||
OMV.Vector3.Zero,
|
OMV.Vector3.Zero,
|
||||||
OMV.Quaternion.Inverse(rootPrim.Orientation),
|
OMV.Quaternion.Inverse(rootPrim.Orientation),
|
||||||
OMV.Vector3.Zero,
|
OMV.Vector3.Zero,
|
||||||
OMV.Quaternion.Inverse(childPrim.Orientation),
|
OMV.Quaternion.Inverse(childPrim.Orientation),
|
||||||
// A point half way between the parent and child
|
|
||||||
// childRelativePosition/2,
|
|
||||||
// childRelativeRotation,
|
|
||||||
// childRelativePosition/2,
|
|
||||||
// inverseChildRelativeRotation,
|
|
||||||
true,
|
true,
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
@ -298,25 +248,26 @@ public class BSLinksetConstraints : BSLinkset
|
||||||
{
|
{
|
||||||
constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations);
|
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 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!
|
// Called at taint time!
|
||||||
private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
|
private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
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.LocalID, rootPrim.BSBody.ptr.ToString("X"),
|
rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString("X"),
|
||||||
childPrim.LocalID, childPrim.BSBody.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
|
// 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
|
// Make the child refresh its location
|
||||||
BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr);
|
BulletSimAPI.PushUpdate2(childPrim.PhysBody.ptr);
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,62 +275,53 @@ public class BSLinksetConstraints : BSLinkset
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove linkage between myself and any possible children I might have.
|
// Remove linkage between myself and any possible children I might have.
|
||||||
|
// Returns 'true' of any constraints were destroyed.
|
||||||
// Called at taint time!
|
// Called at taint time!
|
||||||
private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
|
private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSLinkset.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
|
DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
|
||||||
bool ret = false;
|
|
||||||
|
|
||||||
if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody))
|
return PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody);
|
||||||
{
|
|
||||||
ret = true;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call each of the constraints that make up this linkset and recompute the
|
// Call each of the constraints that make up this linkset and recompute the
|
||||||
// various transforms and variables. Used when objects are added or removed
|
// various transforms and variables. Create constraints of not created yet.
|
||||||
// from a linkset to make sure the constraints know about the new mass and
|
// Called before the simulation step to make sure the constraint based linkset
|
||||||
// geometry.
|
// is all initialized.
|
||||||
// Must only be called at taint time!!
|
// Called at taint time!!
|
||||||
private void RecomputeLinksetConstraintVariables()
|
private void RecomputeLinksetConstraints()
|
||||||
{
|
{
|
||||||
float linksetMass = LinksetMass;
|
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;
|
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}",
|
// If constraint doesn't exist yet, create it.
|
||||||
// LinksetRoot.LocalID, child.LocalID, linksetMass, constrain.Body1.ID, constrain.Body2.ID);
|
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;
|
|
||||||
}
|
}
|
||||||
|
constrain.RecomputeConstraintVariables(linksetMass);
|
||||||
|
|
||||||
|
// 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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -34,9 +34,17 @@ using OpenSim.Region.Physics.Manager;
|
||||||
|
|
||||||
namespace OpenSim.Region.Physics.BulletSPlugin
|
namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
{
|
{
|
||||||
// Class to wrap all objects.
|
/*
|
||||||
// The rest of BulletSim doesn't need to keep checking for avatars or prims
|
* Class to wrap all objects.
|
||||||
// unless the difference is significant.
|
* 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
|
public abstract class BSPhysObject : PhysicsActor
|
||||||
{
|
{
|
||||||
protected void BaseInitialize(BSScene parentScene, uint localID, string name, string typeName)
|
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; }
|
public BSLinkset Linkset { get; set; }
|
||||||
|
|
||||||
// Return the object mass without calculating it or having side effects
|
// 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
|
// Reference to the physical body (btCollisionObject) of this object
|
||||||
public BulletBody BSBody;
|
public BulletBody PhysBody;
|
||||||
// Reference to the physical shape (btCollisionShape) of this object
|
// 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.
|
// 'true' if the mesh's underlying asset failed to build.
|
||||||
// This will keep us from looping after the first time the build failed.
|
// 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.
|
// The objects base shape information. Null if not a prim type shape.
|
||||||
public PrimitiveBaseShape BaseShape { get; protected set; }
|
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.
|
// When the physical properties are updated, an EntityProperty holds the update values.
|
||||||
// Keep the current and last EntityProperties to enable computation of differences
|
// Keep the current and last EntityProperties to enable computation of differences
|
||||||
|
@ -88,7 +107,8 @@ public abstract class BSPhysObject : PhysicsActor
|
||||||
public abstract bool IsStatic { get; }
|
public abstract bool IsStatic { get; }
|
||||||
|
|
||||||
// Stop all physical motion.
|
// 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.
|
// Step the vehicle simulation for this object. A NOOP if the vehicle was not configured.
|
||||||
public virtual void StepVehicle(float timeStep) { }
|
public virtual void StepVehicle(float timeStep) { }
|
||||||
|
@ -99,8 +119,10 @@ public abstract class BSPhysObject : PhysicsActor
|
||||||
// Tell the object to clean up.
|
// Tell the object to clean up.
|
||||||
public abstract void Destroy();
|
public abstract void Destroy();
|
||||||
|
|
||||||
|
public abstract OMV.Vector3 RawPosition { get; set; }
|
||||||
public abstract OMV.Vector3 ForcePosition { 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.Quaternion ForceOrientation { get; set; }
|
||||||
|
|
||||||
public abstract OMV.Vector3 ForceVelocity { get; set; }
|
public abstract OMV.Vector3 ForceVelocity { get; set; }
|
||||||
|
@ -204,7 +226,7 @@ public abstract class BSPhysObject : PhysicsActor
|
||||||
|
|
||||||
PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate()
|
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
|
else
|
||||||
|
@ -218,7 +240,7 @@ public abstract class BSPhysObject : PhysicsActor
|
||||||
SubscribedEventsMs = 0;
|
SubscribedEventsMs = 0;
|
||||||
PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate()
|
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
|
// Return 'true' if the simulator wants collision events
|
||||||
|
|
|
@ -25,8 +25,6 @@
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* 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;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
@ -111,8 +109,8 @@ public sealed class BSPrim : BSPhysObject
|
||||||
_mass = CalculateMass();
|
_mass = CalculateMass();
|
||||||
|
|
||||||
// No body or shape yet
|
// No body or shape yet
|
||||||
BSBody = new BulletBody(LocalID, IntPtr.Zero);
|
PhysBody = new BulletBody(LocalID, IntPtr.Zero);
|
||||||
BSShape = new BulletShape(IntPtr.Zero);
|
PhysShape = new BulletShape(IntPtr.Zero);
|
||||||
|
|
||||||
DetailLog("{0},BSPrim.constructor,call", LocalID);
|
DetailLog("{0},BSPrim.constructor,call", LocalID);
|
||||||
// do the actual object creation at taint time
|
// do the actual object creation at taint time
|
||||||
|
@ -120,7 +118,7 @@ public sealed class BSPrim : BSPhysObject
|
||||||
{
|
{
|
||||||
CreateGeomAndObject(true);
|
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);
|
DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
|
||||||
// If there are physical body and shape, release my use of same.
|
// If there are physical body and shape, release my use of same.
|
||||||
PhysicsScene.Shapes.DereferenceBody(BSBody, true, null);
|
PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null);
|
||||||
PhysicsScene.Shapes.DereferenceShape(BSShape, true, null);
|
PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,18 +169,18 @@ public sealed class BSPrim : BSPhysObject
|
||||||
ForceBodyShapeRebuild(false);
|
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)
|
public override bool ForceBodyShapeRebuild(bool inTaintTime)
|
||||||
{
|
{
|
||||||
LastAssetBuildFailed = false;
|
LastAssetBuildFailed = false;
|
||||||
BSScene.TaintCallback rebuildOperation = delegate()
|
PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate()
|
||||||
{
|
{
|
||||||
_mass = CalculateMass(); // changing the shape changes the mass
|
_mass = CalculateMass(); // changing the shape changes the mass
|
||||||
CreateGeomAndObject(true);
|
CreateGeomAndObject(true);
|
||||||
};
|
});
|
||||||
if (inTaintTime)
|
|
||||||
rebuildOperation();
|
|
||||||
else
|
|
||||||
PhysicsScene.TaintedObject("BSPrim.ForceBodyShapeRebuild", rebuildOperation);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
public override bool Grabbed {
|
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.
|
// Do it to the properties so the values get set in the physics engine.
|
||||||
// Push the setting of the values to the viewer.
|
// Push the setting of the values to the viewer.
|
||||||
// Called at taint time!
|
// Called at taint time!
|
||||||
public override void ZeroMotion()
|
public override void ZeroMotion(bool inTaintTime)
|
||||||
{
|
{
|
||||||
_velocity = OMV.Vector3.Zero;
|
_velocity = OMV.Vector3.Zero;
|
||||||
_acceleration = OMV.Vector3.Zero;
|
_acceleration = OMV.Vector3.Zero;
|
||||||
_rotationalVelocity = OMV.Vector3.Zero;
|
_rotationalVelocity = OMV.Vector3.Zero;
|
||||||
|
|
||||||
// Zero some other properties directly into the physics engine
|
// Zero some other properties in the physics engine
|
||||||
BulletSimAPI.ClearForces2(BSBody.ptr);
|
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)
|
public override void LockAngularMotion(OMV.Vector3 axis)
|
||||||
|
@ -252,11 +263,16 @@ public sealed class BSPrim : BSPhysObject
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override OMV.Vector3 RawPosition
|
||||||
|
{
|
||||||
|
get { return _position; }
|
||||||
|
set { _position = value; }
|
||||||
|
}
|
||||||
public override OMV.Vector3 Position {
|
public override OMV.Vector3 Position {
|
||||||
get {
|
get {
|
||||||
|
// child prims move around based on their parent. Need to get the latest location
|
||||||
if (!Linkset.IsRoot(this))
|
if (!Linkset.IsRoot(this))
|
||||||
// child prims move around based on their parent. Need to get the latest location
|
_position = Linkset.Position(this);
|
||||||
_position = BulletSimAPI.GetPosition2(BSBody.ptr);
|
|
||||||
|
|
||||||
// don't do the GetObjectPosition for root elements because this function is called a zillion times
|
// don't do the GetObjectPosition for root elements because this function is called a zillion times
|
||||||
// _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr);
|
// _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr);
|
||||||
|
@ -274,19 +290,21 @@ public sealed class BSPrim : BSPhysObject
|
||||||
PhysicsScene.TaintedObject("BSPrim.setPosition", delegate()
|
PhysicsScene.TaintedObject("BSPrim.setPosition", delegate()
|
||||||
{
|
{
|
||||||
// DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
|
// 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 {
|
public override OMV.Vector3 ForcePosition {
|
||||||
get {
|
get {
|
||||||
_position = BulletSimAPI.GetPosition2(BSBody.ptr);
|
_position = BulletSimAPI.GetPosition2(PhysBody.ptr);
|
||||||
return _position;
|
return _position;
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
_position = value;
|
_position = value;
|
||||||
PositionSanityCheck();
|
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)
|
if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
|
||||||
{
|
{
|
||||||
float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position);
|
float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position);
|
||||||
|
// TODO: a floating motor so object will bob in the water
|
||||||
if (Position.Z < waterHeight)
|
if (Position.Z < waterHeight)
|
||||||
{
|
{
|
||||||
_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
|
// The new position value must be pushed into the physics engine but we can't
|
||||||
// just assign to "Position" because of potential call loops.
|
// 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);
|
DetailLog("{0},BSPrim.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
|
||||||
ForcePosition = _position;
|
ForcePosition = _position;
|
||||||
};
|
});
|
||||||
if (inTaintTime)
|
|
||||||
sanityOperation();
|
|
||||||
else
|
|
||||||
PhysicsScene.TaintedObject("BSPrim.PositionSanityCheck", sanityOperation);
|
|
||||||
|
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -353,13 +367,35 @@ public sealed class BSPrim : BSPhysObject
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
// return Linkset.LinksetMass;
|
return Linkset.LinksetMass;
|
||||||
return _mass;
|
// return _mass;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// used when we only want this prim's mass and not the linkset thing
|
// 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?
|
// Is this used?
|
||||||
public override OMV.Vector3 CenterOfMass
|
public override OMV.Vector3 CenterOfMass
|
||||||
|
@ -380,7 +416,7 @@ public sealed class BSPrim : BSPhysObject
|
||||||
PhysicsScene.TaintedObject("BSPrim.setForce", delegate()
|
PhysicsScene.TaintedObject("BSPrim.setForce", delegate()
|
||||||
{
|
{
|
||||||
// DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force);
|
// 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
|
// Done at taint time so we're sure the physics engine is not using the variables
|
||||||
// Vehicle code changes the parameters for this vehicle type.
|
// Vehicle code changes the parameters for this vehicle type.
|
||||||
_vehicle.ProcessTypeChange(type);
|
_vehicle.ProcessTypeChange(type);
|
||||||
|
ActivateIfPhysical(false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -408,6 +445,7 @@ public sealed class BSPrim : BSPhysObject
|
||||||
PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate()
|
PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate()
|
||||||
{
|
{
|
||||||
_vehicle.ProcessFloatVehicleParam((Vehicle)param, value);
|
_vehicle.ProcessFloatVehicleParam((Vehicle)param, value);
|
||||||
|
ActivateIfPhysical(false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public override void VehicleVectorParam(int param, OMV.Vector3 value)
|
public override void VehicleVectorParam(int param, OMV.Vector3 value)
|
||||||
|
@ -415,6 +453,7 @@ public sealed class BSPrim : BSPhysObject
|
||||||
PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate()
|
PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate()
|
||||||
{
|
{
|
||||||
_vehicle.ProcessVectorVehicleParam((Vehicle)param, value);
|
_vehicle.ProcessVectorVehicleParam((Vehicle)param, value);
|
||||||
|
ActivateIfPhysical(false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
|
public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
|
||||||
|
@ -422,6 +461,7 @@ public sealed class BSPrim : BSPhysObject
|
||||||
PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate()
|
PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate()
|
||||||
{
|
{
|
||||||
_vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation);
|
_vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation);
|
||||||
|
ActivateIfPhysical(false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public override void VehicleFlags(int param, bool remove)
|
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.
|
// Called from Scene when doing simulation step so we're in taint processing time.
|
||||||
public override void StepVehicle(float timeStep)
|
public override void StepVehicle(float timeStep)
|
||||||
{
|
{
|
||||||
if (IsPhysical)
|
if (IsPhysical && _vehicle.IsActive)
|
||||||
{
|
{
|
||||||
_vehicle.Step(timeStep);
|
_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()
|
PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate()
|
||||||
{
|
{
|
||||||
// DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity);
|
// 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; }
|
get { return _velocity; }
|
||||||
set {
|
set {
|
||||||
_velocity = value;
|
_velocity = value;
|
||||||
BulletSimAPI.SetLinearVelocity2(BSBody.ptr, _velocity);
|
BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public override OMV.Vector3 Torque {
|
public override OMV.Vector3 Torque {
|
||||||
get { return _torque; }
|
get { return _torque; }
|
||||||
set { _torque = value;
|
set {
|
||||||
|
_torque = value;
|
||||||
|
AddAngularForce(_torque, false, false);
|
||||||
// DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque);
|
// DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -489,12 +538,17 @@ public sealed class BSPrim : BSPhysObject
|
||||||
get { return _acceleration; }
|
get { return _acceleration; }
|
||||||
set { _acceleration = value; }
|
set { _acceleration = value; }
|
||||||
}
|
}
|
||||||
|
public override OMV.Quaternion RawOrientation
|
||||||
|
{
|
||||||
|
get { return _orientation; }
|
||||||
|
set { _orientation = value; }
|
||||||
|
}
|
||||||
public override OMV.Quaternion Orientation {
|
public override OMV.Quaternion Orientation {
|
||||||
get {
|
get {
|
||||||
|
// Children move around because tied to parent. Get a fresh value.
|
||||||
if (!Linkset.IsRoot(this))
|
if (!Linkset.IsRoot(this))
|
||||||
{
|
{
|
||||||
// Children move around because tied to parent. Get a fresh value.
|
_orientation = Linkset.Orientation(this);
|
||||||
_orientation = BulletSimAPI.GetOrientation2(BSBody.ptr);
|
|
||||||
}
|
}
|
||||||
return _orientation;
|
return _orientation;
|
||||||
}
|
}
|
||||||
|
@ -507,7 +561,7 @@ public sealed class BSPrim : BSPhysObject
|
||||||
{
|
{
|
||||||
// _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr);
|
// _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr);
|
||||||
// DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation);
|
// 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
|
get
|
||||||
{
|
{
|
||||||
_orientation = BulletSimAPI.GetOrientation2(BSBody.ptr);
|
_orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr);
|
||||||
return _orientation;
|
return _orientation;
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_orientation = value;
|
_orientation = value;
|
||||||
BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
|
BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public override int PhysicsActorType {
|
public override int PhysicsActorType {
|
||||||
|
@ -539,6 +593,8 @@ public sealed class BSPrim : BSPhysObject
|
||||||
{
|
{
|
||||||
// DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
|
// DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
|
||||||
SetObjectDynamic(true);
|
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.
|
// 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).
|
// 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)
|
// Set up the object physicalness (does gravity and collisions move this object)
|
||||||
MakeDynamic(IsStatic);
|
MakeDynamic(IsStatic);
|
||||||
|
@ -590,24 +646,25 @@ public sealed class BSPrim : BSPhysObject
|
||||||
// Make solid or not (do things bounce off or pass through this object).
|
// Make solid or not (do things bounce off or pass through this object).
|
||||||
MakeSolid(IsSolid);
|
MakeSolid(IsSolid);
|
||||||
|
|
||||||
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, BSBody.ptr);
|
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr);
|
||||||
|
|
||||||
// Rebuild its shape
|
// 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
|
// 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.
|
// Recompute any linkset parameters.
|
||||||
// When going from non-physical to physical, this re-enables the constraints that
|
// When going from non-physical to physical, this re-enables the constraints that
|
||||||
// had been automatically disabled when the mass was set to zero.
|
// 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}",
|
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, BSBody, BSShape);
|
LocalID, IsStatic, IsSolid, _mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody, PhysShape);
|
||||||
}
|
}
|
||||||
|
|
||||||
// "Making dynamic" means changing to and from static.
|
// "Making dynamic" means changing to and from static.
|
||||||
|
@ -620,75 +677,74 @@ public sealed class BSPrim : BSPhysObject
|
||||||
if (makeStatic)
|
if (makeStatic)
|
||||||
{
|
{
|
||||||
// Become a Bullet 'static' object type
|
// 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
|
// Stop all movement
|
||||||
BulletSimAPI.ClearAllForces2(BSBody.ptr);
|
ZeroMotion(true);
|
||||||
// Center of mass is at the center of the object
|
// 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
|
// Mass is zero which disables a bunch of physics stuff in Bullet
|
||||||
BulletSimAPI.SetMassProps2(BSBody.ptr, 0f, OMV.Vector3.Zero);
|
UpdatePhysicalMassProperties(0f);
|
||||||
// There is no inertia in a static object
|
|
||||||
BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr);
|
|
||||||
// Set collision detection parameters
|
// Set collision detection parameters
|
||||||
if (PhysicsScene.Params.ccdMotionThreshold > 0f)
|
if (PhysicsScene.Params.ccdMotionThreshold > 0f)
|
||||||
{
|
{
|
||||||
BulletSimAPI.SetCcdMotionThreshold2(BSBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
|
BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
|
||||||
BulletSimAPI.SetCcdSweepSphereRadius2(BSBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
|
BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
|
||||||
}
|
}
|
||||||
// There can be special things needed for implementing linksets
|
// There can be special things needed for implementing linksets
|
||||||
Linkset.MakeStatic(this);
|
Linkset.MakeStatic(this);
|
||||||
// The activation state is 'disabled' so Bullet will not try to act on it.
|
// 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.
|
// Start it out sleeping and physical actions could wake it up.
|
||||||
// BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING);
|
// BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING);
|
||||||
|
|
||||||
BSBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter;
|
PhysBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter;
|
||||||
BSBody.collisionMask = CollisionFilterGroups.StaticObjectMask;
|
PhysBody.collisionMask = CollisionFilterGroups.StaticObjectMask;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Not a Bullet static object
|
// 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
|
// Set various physical properties so internal dynamic properties will get computed correctly as they are set
|
||||||
BulletSimAPI.SetFriction2(BSBody.ptr, PhysicsScene.Params.defaultFriction);
|
BulletSimAPI.SetFriction2(PhysBody.ptr, PhysicsScene.Params.defaultFriction);
|
||||||
BulletSimAPI.SetRestitution2(BSBody.ptr, PhysicsScene.Params.defaultRestitution);
|
BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.defaultRestitution);
|
||||||
|
|
||||||
// per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
|
// 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
|
// 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
|
// A dynamic object has mass
|
||||||
IntPtr collisionShapePtr = BulletSimAPI.GetCollisionShape2(BSBody.ptr);
|
UpdatePhysicalMassProperties(RawMass);
|
||||||
OMV.Vector3 inertia = BulletSimAPI.CalculateLocalInertia2(collisionShapePtr, Mass);
|
|
||||||
BulletSimAPI.SetMassProps2(BSBody.ptr, _mass, inertia);
|
|
||||||
BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr);
|
|
||||||
|
|
||||||
// Set collision detection parameters
|
// Set collision detection parameters
|
||||||
if (PhysicsScene.Params.ccdMotionThreshold > 0f)
|
if (PhysicsScene.Params.ccdMotionThreshold > 0f)
|
||||||
{
|
{
|
||||||
BulletSimAPI.SetCcdMotionThreshold2(BSBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
|
BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
|
||||||
BulletSimAPI.SetCcdSweepSphereRadius2(BSBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
|
BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Various values for simulation limits
|
// Various values for simulation limits
|
||||||
BulletSimAPI.SetDamping2(BSBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping);
|
BulletSimAPI.SetDamping2(PhysBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping);
|
||||||
BulletSimAPI.SetDeactivationTime2(BSBody.ptr, PhysicsScene.Params.deactivationTime);
|
BulletSimAPI.SetDeactivationTime2(PhysBody.ptr, PhysicsScene.Params.deactivationTime);
|
||||||
BulletSimAPI.SetSleepingThresholds2(BSBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold);
|
BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold);
|
||||||
BulletSimAPI.SetContactProcessingThreshold2(BSBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
|
BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
|
||||||
|
|
||||||
// There might be special things needed for implementing linksets.
|
// There might be special things needed for implementing linksets.
|
||||||
Linkset.MakeDynamic(this);
|
Linkset.MakeDynamic(this);
|
||||||
|
|
||||||
// Force activation of the object so Bullet will act on it.
|
// Force activation of the object so Bullet will act on it.
|
||||||
// Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
|
// 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);
|
// BulletSimAPI.Activate2(BSBody.ptr, true);
|
||||||
|
|
||||||
BSBody.collisionFilter = CollisionFilterGroups.ObjectFilter;
|
PhysBody.collisionFilter = CollisionFilterGroups.ObjectFilter;
|
||||||
BSBody.collisionMask = CollisionFilterGroups.ObjectMask;
|
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.
|
// the functions after this one set up the state of a possibly newly created collision body.
|
||||||
private void MakeSolid(bool makeSolid)
|
private void MakeSolid(bool makeSolid)
|
||||||
{
|
{
|
||||||
CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(BSBody.ptr);
|
CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(PhysBody.ptr);
|
||||||
if (makeSolid)
|
if (makeSolid)
|
||||||
{
|
{
|
||||||
// Verify the previous code created the correct shape for this type of thing.
|
// 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);
|
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
|
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);
|
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);
|
CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
|
||||||
BSBody.collisionFilter = CollisionFilterGroups.VolumeDetectFilter;
|
PhysBody.collisionFilter = CollisionFilterGroups.VolumeDetectFilter;
|
||||||
BSBody.collisionMask = CollisionFilterGroups.VolumeDetectMask;
|
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.
|
// Turn on or off the flag controlling whether collision events are returned to the simulator.
|
||||||
private void EnableCollisions(bool wantsCollisionEvents)
|
private void EnableCollisions(bool wantsCollisionEvents)
|
||||||
{
|
{
|
||||||
if (wantsCollisionEvents)
|
if (wantsCollisionEvents)
|
||||||
{
|
{
|
||||||
CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
|
CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
|
||||||
}
|
}
|
||||||
else
|
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()
|
PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate()
|
||||||
{
|
{
|
||||||
if (_floatOnWater)
|
if (_floatOnWater)
|
||||||
CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
|
CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
|
||||||
else
|
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);
|
// m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
|
||||||
PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate()
|
PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate()
|
||||||
{
|
{
|
||||||
// DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
|
DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
|
||||||
BulletSimAPI.SetAngularVelocity2(BSBody.ptr, _rotationalVelocity);
|
BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -809,7 +874,7 @@ public sealed class BSPrim : BSPhysObject
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
_rotationalVelocity = value;
|
_rotationalVelocity = value;
|
||||||
BulletSimAPI.SetAngularVelocity2(BSBody.ptr, _rotationalVelocity);
|
BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public override bool Kinematic {
|
public override bool Kinematic {
|
||||||
|
@ -835,7 +900,7 @@ public sealed class BSPrim : BSPhysObject
|
||||||
// DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
|
// DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
|
||||||
// Buoyancy is faked by changing the gravity applied to the object
|
// Buoyancy is faked by changing the gravity applied to the object
|
||||||
float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
|
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);
|
m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
BSScene.TaintCallback addForceOperation = delegate()
|
PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate()
|
||||||
{
|
{
|
||||||
OMV.Vector3 fSum = OMV.Vector3.Zero;
|
OMV.Vector3 fSum = OMV.Vector3.Zero;
|
||||||
lock (m_accumulatedForces)
|
lock (m_accumulatedForces)
|
||||||
|
@ -900,20 +965,69 @@ public sealed class BSPrim : BSPhysObject
|
||||||
}
|
}
|
||||||
m_accumulatedForces.Clear();
|
m_accumulatedForces.Clear();
|
||||||
}
|
}
|
||||||
// DetailLog("{0},BSPrim.AddObjectForce,taint,force={1}", LocalID, fSum);
|
DetailLog("{0},BSPrim.AddForce,taint,force={1}", LocalID, fSum);
|
||||||
// For unknown reasons, "ApplyCentralForce" adds this force to the total force on the object.
|
if (fSum != OMV.Vector3.Zero)
|
||||||
BulletSimAPI.ApplyCentralForce2(BSBody.ptr, fSum);
|
BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, fSum);
|
||||||
};
|
});
|
||||||
if (inTaintTime)
|
|
||||||
addForceOperation();
|
|
||||||
else
|
|
||||||
PhysicsScene.TaintedObject("BSPrim.AddForce", addForceOperation);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
|
public void ApplyForceImpulse(OMV.Vector3 impulse, bool inTaintTime)
|
||||||
// DetailLog("{0},BSPrim.AddAngularForce,call,angForce={1},push={2}", LocalID, force, pushforce);
|
{
|
||||||
// m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce);
|
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) {
|
public override void SetMomentum(OMV.Vector3 momentum) {
|
||||||
// DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum);
|
// DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum);
|
||||||
}
|
}
|
||||||
|
@ -1195,9 +1309,7 @@ public sealed class BSPrim : BSPhysObject
|
||||||
|
|
||||||
returnMass = _density * volume;
|
returnMass = _density * volume;
|
||||||
|
|
||||||
/*
|
/* Comment out code that computes the mass of the linkset. That is done in the Linkset class.
|
||||||
* This change means each object keeps its own mass and the Mass property
|
|
||||||
* will return the sum if we're part of a linkset.
|
|
||||||
if (IsRootOfLinkset)
|
if (IsRootOfLinkset)
|
||||||
{
|
{
|
||||||
foreach (BSPrim prim in _childrenPrims)
|
foreach (BSPrim prim in _childrenPrims)
|
||||||
|
@ -1217,49 +1329,27 @@ public sealed class BSPrim : BSPhysObject
|
||||||
}// end CalculateMass
|
}// end CalculateMass
|
||||||
#endregion Mass Calculation
|
#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.
|
// Rebuild the geometry and object.
|
||||||
// This is called when the shape changes so we need to recreate the mesh/hull.
|
// This is called when the shape changes so we need to recreate the mesh/hull.
|
||||||
// Called at taint-time!!!
|
// Called at taint-time!!!
|
||||||
private void CreateGeomAndObject(bool forceRebuild)
|
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
|
// If this prim is part of a linkset, we must remove and restore the physical
|
||||||
// links if the body is rebuilt.
|
// links if the body is rebuilt.
|
||||||
bool needToRestoreLinkset = false;
|
bool needToRestoreLinkset = false;
|
||||||
|
bool needToRestoreVehicle = false;
|
||||||
|
|
||||||
// Create the correct physical representation for this type of object.
|
// Create the correct physical representation for this type of object.
|
||||||
// Updates BSBody and BSShape with the new information.
|
// Updates PhysBody and PhysShape with the new information.
|
||||||
// Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary.
|
// Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary.
|
||||||
// Returns 'true' if either the body or the shape was changed.
|
// Returns 'true' if either the body or the shape was changed.
|
||||||
PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, shapeData, BaseShape,
|
PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody)
|
||||||
null, delegate(BulletBody dBody)
|
|
||||||
{
|
{
|
||||||
// Called if the current prim body is about to be destroyed.
|
// Called if the current prim body is about to be destroyed.
|
||||||
// Remove all the physical dependencies on the old body.
|
// Remove all the physical dependencies on the old body.
|
||||||
// (Maybe someday make the changing of BSShape an event handled by BSLinkset.)
|
// (Maybe someday make the changing of BSShape an event handled by BSLinkset.)
|
||||||
needToRestoreLinkset = Linkset.RemoveBodyDependencies(this);
|
needToRestoreLinkset = Linkset.RemoveBodyDependencies(this);
|
||||||
|
needToRestoreVehicle = _vehicle.RemoveBodyDependencies(this);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (needToRestoreLinkset)
|
if (needToRestoreLinkset)
|
||||||
|
@ -1267,6 +1357,11 @@ public sealed class BSPrim : BSPhysObject
|
||||||
// If physical body dependencies were removed, restore them
|
// If physical body dependencies were removed, restore them
|
||||||
Linkset.RestoreBodyDependencies(this);
|
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
|
// Make sure the properties are set on the new object
|
||||||
UpdatePhysicalParameters();
|
UpdatePhysicalParameters();
|
||||||
|
@ -1353,8 +1448,9 @@ public sealed class BSPrim : BSPhysObject
|
||||||
|
|
||||||
PositionSanityCheck(true);
|
PositionSanityCheck(true);
|
||||||
|
|
||||||
DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
|
OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation;
|
||||||
LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
|
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
|
// BulletSimAPI.DumpRigidBody2(PhysicsScene.World.ptr, BSBody.ptr); // DEBUG DEBUG DEBUG
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@ using OpenMetaverse;
|
||||||
//
|
//
|
||||||
namespace OpenSim.Region.Physics.BulletSPlugin
|
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 ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
private static readonly string LogHeader = "[BULLETS SCENE]";
|
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
|
// True if initialized and ready to do simulation steps
|
||||||
private bool m_initialized = false;
|
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
|
// Pinned memory used to pass step information between managed and unmanaged
|
||||||
private int m_maxCollisionsPerFrame;
|
private int m_maxCollisionsPerFrame;
|
||||||
private CollisionDesc[] m_collisionArray;
|
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 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
|
// A pointer to an instance if this structure is passed to the C++ code
|
||||||
// Used to pass basic configuration values to the unmanaged 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)
|
public override void Initialise(IMesher meshmerizer, IConfigSource config)
|
||||||
{
|
{
|
||||||
mesher = meshmerizer;
|
mesher = meshmerizer;
|
||||||
_taintedObjects = new List<TaintCallbackEntry>();
|
_taintOperations = new List<TaintCallbackEntry>();
|
||||||
|
_postTaintOperations = new Dictionary<string, TaintCallbackEntry>();
|
||||||
|
_postStepOperations = new List<TaintCallbackEntry>();
|
||||||
PhysObjects = new Dictionary<uint, BSPhysObject>();
|
PhysObjects = new Dictionary<uint, BSPhysObject>();
|
||||||
Shapes = new BSShapeCollection(this);
|
Shapes = new BSShapeCollection(this);
|
||||||
|
|
||||||
|
@ -266,6 +274,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
TerrainManager = new BSTerrainManager(this);
|
TerrainManager = new BSTerrainManager(this);
|
||||||
TerrainManager.CreateInitialGroundPlaneAndTerrain();
|
TerrainManager.CreateInitialGroundPlaneAndTerrain();
|
||||||
|
|
||||||
|
m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)Params.linksetImplementation);
|
||||||
|
|
||||||
|
InTaintTime = false;
|
||||||
m_initialized = true;
|
m_initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -475,23 +486,20 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
if (!m_initialized) return 5.0f;
|
if (!m_initialized) return 5.0f;
|
||||||
|
|
||||||
// update the prim states while we know the physics engine is not busy
|
// update the prim states while we know the physics engine is not busy
|
||||||
int numTaints = _taintedObjects.Count;
|
int numTaints = _taintOperations.Count;
|
||||||
ProcessTaints();
|
ProcessTaints();
|
||||||
|
|
||||||
// Some of the prims operate with special vehicle properties
|
// Some of the prims operate with special vehicle properties
|
||||||
ProcessVehicles(timeStep);
|
ProcessVehicles(timeStep);
|
||||||
numTaints += _taintedObjects.Count;
|
|
||||||
ProcessTaints(); // the vehicles might have added taints
|
ProcessTaints(); // the vehicles might have added taints
|
||||||
|
|
||||||
// step the physical world one interval
|
// step the physical world one interval
|
||||||
m_simulationStep++;
|
m_simulationStep++;
|
||||||
int numSubSteps = 0;
|
int numSubSteps = 0;
|
||||||
|
|
||||||
// DEBUG
|
|
||||||
// DetailLog("{0},BSScene.Simulate,beforeStep,ntaimts={1},step={2}", DetailLogZero, numTaints, m_simulationStep);
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG
|
||||||
if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount();
|
if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount();
|
||||||
|
|
||||||
numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep,
|
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);
|
if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime);
|
||||||
DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}",
|
DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}",
|
||||||
DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount);
|
DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount);
|
||||||
|
if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -511,7 +520,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
collidersCount = 0;
|
collidersCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Don't have to use the pointers passed back since we know it is the same pinned memory we passed in
|
// 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
|
// 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.
|
// 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.
|
// Only enable this in a limited test world with few objects.
|
||||||
// BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG
|
// BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG
|
||||||
|
@ -670,6 +680,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
|
|
||||||
public override bool IsThreaded { get { return false; } }
|
public override bool IsThreaded { get { return false; } }
|
||||||
|
|
||||||
|
#region Taints
|
||||||
|
|
||||||
// Calls to the PhysicsActors can't directly call into the physics engine
|
// Calls to the PhysicsActors can't directly call into the physics engine
|
||||||
// because it might be busy. We delay changes to a known time.
|
// 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.
|
// 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)
|
lock (_taintLock)
|
||||||
{
|
{
|
||||||
_taintedObjects.Add(new TaintCallbackEntry(ident, callback));
|
_taintOperations.Add(new TaintCallbackEntry(ident, callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
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
|
// 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
|
// 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.
|
// here just before the physics engine is called to step the simulation.
|
||||||
public void ProcessTaints()
|
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;
|
int taintCount = m_taintsToProcessPerStep;
|
||||||
TaintCallbackEntry oneCallback = new TaintCallbackEntry();
|
TaintCallbackEntry oneCallback = new TaintCallbackEntry();
|
||||||
while (_taintedObjects.Count > 0 && taintCount-- > 0)
|
while (_taintOperations.Count > 0 && taintCount-- > 0)
|
||||||
{
|
{
|
||||||
bool gotOne = false;
|
bool gotOne = false;
|
||||||
lock (_taintLock)
|
lock (_taintLock)
|
||||||
{
|
{
|
||||||
if (_taintedObjects.Count > 0)
|
if (_taintOperations.Count > 0)
|
||||||
{
|
{
|
||||||
oneCallback = _taintedObjects[0];
|
oneCallback = _taintOperations[0];
|
||||||
_taintedObjects.RemoveAt(0);
|
_taintOperations.RemoveAt(0);
|
||||||
gotOne = true;
|
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
|
// swizzle a new list into the list location so we can process what's there
|
||||||
List<TaintCallbackEntry> oldList;
|
List<TaintCallbackEntry> oldList;
|
||||||
lock (_taintLock)
|
lock (_taintLock)
|
||||||
{
|
{
|
||||||
oldList = _taintedObjects;
|
oldList = _taintOperations;
|
||||||
_taintedObjects = new List<TaintCallbackEntry>();
|
_taintOperations = new List<TaintCallbackEntry>();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (TaintCallbackEntry tcbe in oldList)
|
foreach (TaintCallbackEntry tcbe in oldList)
|
||||||
|
@ -742,10 +779,104 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
oldList.Clear();
|
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
|
#region Vehicles
|
||||||
|
|
||||||
public void VehicleInSceneTypeChanged(BSPrim vehic, Vehicle newType)
|
public void VehicleInSceneTypeChanged(BSPrim vehic, Vehicle newType)
|
||||||
|
@ -916,7 +1047,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
(s) => { return (float)s.m_maxUpdatesPerFrame; },
|
(s) => { return (float)s.m_maxUpdatesPerFrame; },
|
||||||
(s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
|
(s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
|
||||||
new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step",
|
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,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); },
|
||||||
(s) => { return (float)s.m_taintsToProcessPerStep; },
|
(s) => { return (float)s.m_taintsToProcessPerStep; },
|
||||||
(s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ),
|
(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,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); },
|
||||||
(s) => { return s.m_params[0].linearDamping; },
|
(s) => { return s.m_params[0].linearDamping; },
|
||||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearDamping, p, l, v); },
|
(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)",
|
new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
|
||||||
0f,
|
0f,
|
||||||
(s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); },
|
(s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); },
|
||||||
(s) => { return s.m_params[0].angularDamping; },
|
(s) => { return s.m_params[0].angularDamping; },
|
||||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularDamping, p, l, v); },
|
(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",
|
new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
|
||||||
0.2f,
|
0.2f,
|
||||||
(s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); },
|
(s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); },
|
||||||
(s) => { return s.m_params[0].deactivationTime; },
|
(s) => { return s.m_params[0].deactivationTime; },
|
||||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].deactivationTime, p, l, v); },
|
(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",
|
new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
|
||||||
0.8f,
|
0.8f,
|
||||||
(s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); },
|
(s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); },
|
||||||
(s) => { return s.m_params[0].linearSleepingThreshold; },
|
(s) => { return s.m_params[0].linearSleepingThreshold; },
|
||||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearSleepingThreshold, p, l, v); },
|
(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",
|
new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
|
||||||
1.0f,
|
1.0f,
|
||||||
(s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); },
|
(s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); },
|
||||||
(s) => { return s.m_params[0].angularSleepingThreshold; },
|
(s) => { return s.m_params[0].angularSleepingThreshold; },
|
||||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularSleepingThreshold, p, l, v); },
|
(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)" ,
|
new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
|
||||||
0f, // set to zero to disable
|
0f, // set to zero to disable
|
||||||
(s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); },
|
(s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); },
|
||||||
(s) => { return s.m_params[0].ccdMotionThreshold; },
|
(s) => { return s.m_params[0].ccdMotionThreshold; },
|
||||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdMotionThreshold, p, l, v); },
|
(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" ,
|
new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
|
||||||
0f,
|
0f,
|
||||||
(s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); },
|
(s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); },
|
||||||
(s) => { return s.m_params[0].ccdSweptSphereRadius; },
|
(s) => { return s.m_params[0].ccdSweptSphereRadius; },
|
||||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); },
|
(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" ,
|
new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" ,
|
||||||
0.1f,
|
0.1f,
|
||||||
(s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); },
|
(s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); },
|
||||||
(s) => { return s.m_params[0].contactProcessingThreshold; },
|
(s) => { return s.m_params[0].contactProcessingThreshold; },
|
||||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); },
|
(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" ,
|
new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
|
||||||
0.5f,
|
0.5f,
|
||||||
|
@ -1107,6 +1238,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
(s) => { return s.m_params[0].numberOfSolverIterations; },
|
(s) => { return s.m_params[0].numberOfSolverIterations; },
|
||||||
(s,p,l,v) => { s.m_params[0].numberOfSolverIterations = v; } ),
|
(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.",
|
new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
|
||||||
ConfigurationParameters.numericFalse,
|
ConfigurationParameters.numericFalse,
|
||||||
(s,cf,p,v) => { s.m_params[0].linkConstraintUseFrameOffset = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
|
(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) => { return s.m_params[0].linkConstraintTransMotorMaxForce; },
|
||||||
(s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ),
|
(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",
|
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,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); },
|
||||||
(s) => { return s.m_params[0].linkConstraintCFM; },
|
(s) => { return s.m_params[0].linkConstraintCFM; },
|
||||||
(s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ),
|
(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",
|
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,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); },
|
||||||
(s) => { return s.m_params[0].linkConstraintERP; },
|
(s) => { return s.m_params[0].linkConstraintERP; },
|
||||||
(s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ),
|
(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 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 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
|
// 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>();
|
List<uint> objectIDs = new List<uint>();
|
||||||
switch (localID)
|
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
|
// 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;
|
float xval = val;
|
||||||
List<uint> xlIDs = lIDs;
|
List<uint> xlIDs = lIDs;
|
||||||
|
@ -1326,11 +1462,21 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
|
|
||||||
#endregion Runtime settable parameters
|
#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.
|
// Invoke the detailed logger and output something if it's enabled.
|
||||||
public void DetailLog(string msg, params Object[] args)
|
public void DetailLog(string msg, params Object[] args)
|
||||||
{
|
{
|
||||||
PhysicsLogging.Write(msg, 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();
|
// PhysicsLogging.Flush();
|
||||||
}
|
}
|
||||||
// Used to fill in the LocalID when there isn't one. It's the correct number of characters.
|
// Used to fill in the LocalID when there isn't one. It's the correct number of characters.
|
||||||
|
|
|
@ -34,11 +34,11 @@ using OpenSim.Region.Physics.ConvexDecompositionDotNet;
|
||||||
|
|
||||||
namespace OpenSim.Region.Physics.BulletSPlugin
|
namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
{
|
{
|
||||||
public class BSShapeCollection : IDisposable
|
public sealed class BSShapeCollection : IDisposable
|
||||||
{
|
{
|
||||||
private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]";
|
private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]";
|
||||||
|
|
||||||
protected BSScene PhysicsScene { get; set; }
|
private BSScene PhysicsScene { get; set; }
|
||||||
|
|
||||||
private Object m_collectionActivityLock = new Object();
|
private Object m_collectionActivityLock = new Object();
|
||||||
|
|
||||||
|
@ -48,6 +48,7 @@ public class BSShapeCollection : IDisposable
|
||||||
public IntPtr ptr;
|
public IntPtr ptr;
|
||||||
public int referenceCount;
|
public int referenceCount;
|
||||||
public DateTime lastReferenced;
|
public DateTime lastReferenced;
|
||||||
|
public UInt64 shapeKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Description of a hull.
|
// Description of a hull.
|
||||||
|
@ -57,6 +58,7 @@ public class BSShapeCollection : IDisposable
|
||||||
public IntPtr ptr;
|
public IntPtr ptr;
|
||||||
public int referenceCount;
|
public int referenceCount;
|
||||||
public DateTime lastReferenced;
|
public DateTime lastReferenced;
|
||||||
|
public UInt64 shapeKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The sharable set of meshes and hulls. Indexed by their shape hash.
|
// 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.
|
// remove the physical constraints before the body is destroyed.
|
||||||
// Called at taint-time!!
|
// Called at taint-time!!
|
||||||
public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim,
|
public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim,
|
||||||
ShapeData shapeData, PrimitiveBaseShape pbs,
|
|
||||||
ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
|
ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
|
||||||
{
|
{
|
||||||
|
PhysicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape");
|
||||||
|
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
// This lock could probably be pushed down lower but building shouldn't take long
|
// 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?
|
// Do we have the correct geometry for this type of object?
|
||||||
// Updates prim.BSShape with information/pointers to shape.
|
// Updates prim.BSShape with information/pointers to shape.
|
||||||
// CreateGeom returns 'true' of BSShape as changed to a new shape.
|
// Returns 'true' of BSShape is changed to a new shape.
|
||||||
bool newGeom = CreateGeom(forceRebuild, prim, shapeData, pbs, shapeCallback);
|
bool newGeom = CreateGeom(forceRebuild, prim, shapeCallback);
|
||||||
// If we had to select a new shape geometry for the object,
|
// If we had to select a new shape geometry for the object,
|
||||||
// rebuild the body around it.
|
// rebuild the body around it.
|
||||||
// Updates prim.BSBody with information/pointers to requested body
|
// Updates prim.BSBody with information/pointers to requested body
|
||||||
|
// Returns 'true' if BSBody was changed.
|
||||||
bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World,
|
bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World,
|
||||||
prim.BSShape, shapeData, bodyCallback);
|
prim.PhysShape, bodyCallback);
|
||||||
ret = newGeom || newBody;
|
ret = newGeom || newBody;
|
||||||
}
|
}
|
||||||
DetailLog("{0},BSShapeCollection.GetBodyAndShape,force={1},ret={2},body={3},shape={4}",
|
DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}",
|
||||||
prim.LocalID, forceRebuild, ret, prim.BSBody, prim.BSShape);
|
prim.LocalID, forceRebuild, ret, prim.PhysBody, prim.PhysShape);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Track another user of a body
|
// Track another user of a body.
|
||||||
// We presume the caller has allocated the 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.
|
// 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)
|
public void ReferenceBody(BulletBody body, bool inTaintTime)
|
||||||
{
|
{
|
||||||
lock (m_collectionActivityLock)
|
lock (m_collectionActivityLock)
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSShapeCollection.ReferenceBody,newBody", body.ID, body);
|
DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body);
|
||||||
BSScene.TaintCallback createOperation = delegate()
|
PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate()
|
||||||
{
|
{
|
||||||
if (!BulletSimAPI.IsInWorld2(body.ptr))
|
if (!BulletSimAPI.IsInWorld2(body.ptr))
|
||||||
{
|
{
|
||||||
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr);
|
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr);
|
||||||
DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
|
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)
|
lock (m_collectionActivityLock)
|
||||||
{
|
{
|
||||||
BSScene.TaintCallback removeOperation = delegate()
|
PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate()
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}, inTaintTime={2}",
|
DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}",
|
||||||
body.ID, body.ptr.ToString("X"), inTaintTime);
|
body.ID, body, inTaintTime);
|
||||||
// If the caller needs to know the old body is going away, pass the event up.
|
// If the caller needs to know the old body is going away, pass the event up.
|
||||||
if (bodyCallback != null) bodyCallback(body);
|
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);
|
{
|
||||||
|
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.
|
// 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.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero);
|
||||||
BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr);
|
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.
|
// 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.
|
// 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.
|
// 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;
|
bool ret = false;
|
||||||
switch (shape.type)
|
switch (shape.type)
|
||||||
|
@ -193,6 +191,7 @@ public class BSShapeCollection : IDisposable
|
||||||
{
|
{
|
||||||
// This is a new reference to a mesh
|
// This is a new reference to a mesh
|
||||||
meshDesc.ptr = shape.ptr;
|
meshDesc.ptr = shape.ptr;
|
||||||
|
meshDesc.shapeKey = shape.shapeKey;
|
||||||
// We keep a reference to the underlying IMesh data so a hull can be built
|
// We keep a reference to the underlying IMesh data so a hull can be built
|
||||||
meshDesc.referenceCount = 1;
|
meshDesc.referenceCount = 1;
|
||||||
DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}",
|
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
|
// This is a new reference to a hull
|
||||||
hullDesc.ptr = shape.ptr;
|
hullDesc.ptr = shape.ptr;
|
||||||
|
hullDesc.shapeKey = shape.shapeKey;
|
||||||
hullDesc.referenceCount = 1;
|
hullDesc.referenceCount = 1;
|
||||||
DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}",
|
DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}",
|
||||||
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
|
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
|
||||||
|
@ -239,7 +239,7 @@ public class BSShapeCollection : IDisposable
|
||||||
if (shape.ptr == IntPtr.Zero)
|
if (shape.ptr == IntPtr.Zero)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
BSScene.TaintCallback dereferenceOperation = delegate()
|
PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate()
|
||||||
{
|
{
|
||||||
if (shape.ptr != IntPtr.Zero)
|
if (shape.ptr != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
|
@ -261,6 +261,9 @@ public class BSShapeCollection : IDisposable
|
||||||
case ShapeData.PhysicsShapeType.SHAPE_MESH:
|
case ShapeData.PhysicsShapeType.SHAPE_MESH:
|
||||||
DereferenceMesh(shape, shapeCallback);
|
DereferenceMesh(shape, shapeCallback);
|
||||||
break;
|
break;
|
||||||
|
case ShapeData.PhysicsShapeType.SHAPE_COMPOUND:
|
||||||
|
DereferenceCompound(shape, shapeCallback);
|
||||||
|
break;
|
||||||
case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN:
|
case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN:
|
||||||
break;
|
break;
|
||||||
default:
|
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
|
// Count down the reference count for a mesh shape
|
||||||
|
@ -294,8 +286,8 @@ public class BSShapeCollection : IDisposable
|
||||||
if (shapeCallback != null) shapeCallback(shape);
|
if (shapeCallback != null) shapeCallback(shape);
|
||||||
meshDesc.lastReferenced = System.DateTime.Now;
|
meshDesc.lastReferenced = System.DateTime.Now;
|
||||||
Meshes[shape.shapeKey] = meshDesc;
|
Meshes[shape.shapeKey] = meshDesc;
|
||||||
DetailLog("{0},BSShapeCollection.DereferenceMesh,key={1},refCnt={2}",
|
DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}",
|
||||||
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
|
BSScene.DetailLogZero, shape, meshDesc.referenceCount);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -309,11 +301,94 @@ public class BSShapeCollection : IDisposable
|
||||||
{
|
{
|
||||||
hullDesc.referenceCount--;
|
hullDesc.referenceCount--;
|
||||||
// TODO: release the Bullet storage (aging old entries?)
|
// 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);
|
if (shapeCallback != null) shapeCallback(shape);
|
||||||
|
|
||||||
hullDesc.lastReferenced = System.DateTime.Now;
|
hullDesc.lastReferenced = System.DateTime.Now;
|
||||||
Hulls[shape.shapeKey] = hullDesc;
|
Hulls[shape.shapeKey] = hullDesc;
|
||||||
DetailLog("{0},BSShapeCollection.DereferenceHull,key={1},refCnt={2}",
|
DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}",
|
||||||
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
|
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.
|
// Info in prim.BSShape is updated to the new shape.
|
||||||
// Returns 'true' if the geometry was rebuilt.
|
// Returns 'true' if the geometry was rebuilt.
|
||||||
// Called at taint-time!
|
// Called at taint-time!
|
||||||
private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeData shapeData,
|
private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback)
|
||||||
PrimitiveBaseShape pbs, 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 ret = false;
|
||||||
bool haveShape = false;
|
bool haveShape = false;
|
||||||
bool nativeShapePossible = true;
|
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 the prim attributes are simple, this could be a simple Bullet native shape
|
||||||
if (!haveShape
|
if (!haveShape
|
||||||
&& pbs != null
|
&& pbs != null
|
||||||
|
@ -354,98 +453,110 @@ public class BSShapeCollection : IDisposable
|
||||||
&& pbs.PathScaleX == 100 && pbs.PathScaleY == 100
|
&& pbs.PathScaleX == 100 && pbs.PathScaleY == 100
|
||||||
&& pbs.PathShearX == 0 && pbs.PathShearY == 0) ) )
|
&& 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)
|
if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
|
||||||
&& pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)
|
&& pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)
|
||||||
{
|
{
|
||||||
haveShape = true;
|
haveShape = true;
|
||||||
if (forceRebuild
|
if (forceRebuild
|
||||||
|| prim.Scale != shapeData.Size
|
|| prim.Scale != prim.Size
|
||||||
|| prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_SPHERE
|
|| 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);
|
ShapeData.FixedShapeKey.KEY_SPHERE, shapeCallback);
|
||||||
DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
|
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;
|
haveShape = true;
|
||||||
if (forceRebuild
|
if (forceRebuild
|
||||||
|| prim.Scale != shapeData.Size
|
|| prim.Scale != prim.Size
|
||||||
|| prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_BOX
|
|| 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);
|
ShapeData.FixedShapeKey.KEY_BOX, shapeCallback);
|
||||||
DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
|
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.
|
// 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)
|
if (!haveShape && pbs != null)
|
||||||
{
|
{
|
||||||
if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects)
|
ret = CreateGeomMeshOrHull(prim, shapeCallback);
|
||||||
{
|
}
|
||||||
// Update prim.BSShape to reference a hull of this shape.
|
|
||||||
ret = GetReferenceToHull(prim, shapeData, pbs, shapeCallback);
|
return ret;
|
||||||
DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
|
}
|
||||||
shapeData.ID, prim.BSShape, prim.BSShape.shapeKey.ToString("X"));
|
|
||||||
}
|
public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
|
||||||
else
|
{
|
||||||
{
|
|
||||||
ret = GetReferenceToMesh(prim, shapeData, pbs, shapeCallback);
|
bool ret = false;
|
||||||
DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
|
// Note that if it's a native shape, the check for physical/non-physical is not
|
||||||
shapeData.ID, prim.BSShape, prim.BSShape.shapeKey.ToString("X"));
|
// 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,shapeCallback);
|
||||||
|
DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
|
||||||
|
prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = GetReferenceToMesh(prim, shapeCallback);
|
||||||
|
DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
|
||||||
|
prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates a native shape and assignes it to prim.BSShape.
|
// Creates a native shape and assignes it to prim.BSShape.
|
||||||
// "Native" shapes are never shared. they are created here and destroyed in DereferenceShape().
|
// "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,
|
ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey,
|
||||||
ShapeDestructionCallback shapeCallback)
|
ShapeDestructionCallback shapeCallback)
|
||||||
{
|
{
|
||||||
// release any previous shape
|
// 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
|
// Bullet native objects are scaled by the Bullet engine so pass the size in
|
||||||
prim.Scale = shapeData.Size;
|
prim.Scale = prim.Size;
|
||||||
shapeData.Scale = shapeData.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.
|
// Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
|
||||||
DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
|
DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
|
||||||
shapeData.ID, newShape, shapeData.Scale);
|
prim.LocalID, newShape, prim.Scale);
|
||||||
|
|
||||||
prim.BSShape = newShape;
|
prim.PhysShape = newShape;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private BulletShape BuildPhysicalNativeShape(ShapeData.PhysicsShapeType shapeType,
|
private BulletShape BuildPhysicalNativeShape(BSPhysObject prim, ShapeData.PhysicsShapeType shapeType,
|
||||||
ShapeData shapeData, ShapeData.FixedShapeKey shapeKey)
|
ShapeData.FixedShapeKey shapeKey)
|
||||||
{
|
{
|
||||||
BulletShape newShape;
|
BulletShape newShape;
|
||||||
// Need to make sure the passed shape information is for the native type.
|
// Need to make sure the passed shape information is for the native type.
|
||||||
ShapeData nativeShapeData = shapeData;
|
ShapeData nativeShapeData = new ShapeData();
|
||||||
nativeShapeData.Type = shapeType;
|
nativeShapeData.Type = shapeType;
|
||||||
|
nativeShapeData.ID = prim.LocalID;
|
||||||
|
nativeShapeData.Scale = prim.Scale;
|
||||||
|
nativeShapeData.Size = prim.Scale;
|
||||||
nativeShapeData.MeshKey = (ulong)shapeKey;
|
nativeShapeData.MeshKey = (ulong)shapeKey;
|
||||||
nativeShapeData.HullKey = (ulong)shapeKey;
|
nativeShapeData.HullKey = (ulong)shapeKey;
|
||||||
|
|
||||||
if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR)
|
if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR)
|
||||||
{
|
{
|
||||||
newShape = new BulletShape(
|
newShape = new BulletShape(
|
||||||
BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, nativeShapeData.Scale)
|
BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale)
|
||||||
, shapeType);
|
, shapeType);
|
||||||
DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", nativeShapeData.ID, nativeShapeData.Scale);
|
DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -454,7 +565,7 @@ public class BSShapeCollection : IDisposable
|
||||||
if (newShape.ptr == IntPtr.Zero)
|
if (newShape.ptr == IntPtr.Zero)
|
||||||
{
|
{
|
||||||
PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
|
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.shapeKey = (System.UInt64)shapeKey;
|
||||||
newShape.isNativeShape = true;
|
newShape.isNativeShape = true;
|
||||||
|
@ -466,33 +577,32 @@ public class BSShapeCollection : IDisposable
|
||||||
// Dereferences previous shape in BSShape and adds a reference for this new shape.
|
// Dereferences previous shape in BSShape and adds a reference for this new shape.
|
||||||
// Returns 'true' of a mesh was actually built. Otherwise .
|
// Returns 'true' of a mesh was actually built. Otherwise .
|
||||||
// Called at taint-time!
|
// Called at taint-time!
|
||||||
private bool GetReferenceToMesh(BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs,
|
private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
|
||||||
ShapeDestructionCallback shapeCallback)
|
|
||||||
{
|
{
|
||||||
BulletShape newShape = new BulletShape(IntPtr.Zero);
|
BulletShape newShape = new BulletShape(IntPtr.Zero);
|
||||||
|
|
||||||
float lod;
|
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 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;
|
return false;
|
||||||
|
|
||||||
DetailLog("{0},BSShapeCollection.CreateGeomMesh,create,oldKey={1},newKey={2}",
|
DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}",
|
||||||
prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newMeshKey.ToString("X"));
|
prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"));
|
||||||
|
|
||||||
// Since we're recreating new, get rid of the reference to the previous shape
|
// 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.
|
// Take evasive action if the mesh was not constructed.
|
||||||
newShape = VerifyMeshCreated(newShape, prim, shapeData, pbs);
|
newShape = VerifyMeshCreated(newShape, prim);
|
||||||
|
|
||||||
ReferenceShape(newShape);
|
ReferenceShape(newShape);
|
||||||
|
|
||||||
// meshes are already scaled by the meshmerizer
|
// meshes are already scaled by the meshmerizer
|
||||||
prim.Scale = new OMV.Vector3(1f, 1f, 1f);
|
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
|
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;
|
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);
|
// LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count);
|
||||||
|
|
||||||
meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
|
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.
|
// See that hull shape exists in the physical world and update prim.BSShape.
|
||||||
// We could be creating the hull because scale changed or whatever.
|
// We could be creating the hull because scale changed or whatever.
|
||||||
private bool GetReferenceToHull(BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs,
|
private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
|
||||||
ShapeDestructionCallback shapeCallback)
|
|
||||||
{
|
{
|
||||||
BulletShape newShape;
|
BulletShape newShape;
|
||||||
|
|
||||||
float lod;
|
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 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;
|
return false;
|
||||||
|
|
||||||
DetailLog("{0},BSShapeCollection.CreateGeomHull,create,oldKey={1},newKey={2}",
|
DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}",
|
||||||
prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
|
prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
|
||||||
|
|
||||||
// Remove usage of the previous shape.
|
// 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 = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod);
|
||||||
newShape = VerifyMeshCreated(newShape, prim, shapeData, pbs);
|
newShape = VerifyMeshCreated(newShape, prim);
|
||||||
|
|
||||||
ReferenceShape(newShape);
|
ReferenceShape(newShape);
|
||||||
|
|
||||||
// hulls are already scaled by the meshmerizer
|
// hulls are already scaled by the meshmerizer
|
||||||
prim.Scale = new OMV.Vector3(1f, 1f, 1f);
|
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
|
return true; // 'true' means a new shape has been added to this prim
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -685,9 +794,31 @@ public class BSShapeCollection : IDisposable
|
||||||
return;
|
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
|
// Create a hash of all the shape parameters to be used as a key
|
||||||
// for this particular shape.
|
// 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
|
// level of detail based on size and type of the object
|
||||||
float lod = PhysicsScene.MeshLOD;
|
float lod = PhysicsScene.MeshLOD;
|
||||||
|
@ -695,40 +826,40 @@ public class BSShapeCollection : IDisposable
|
||||||
lod = PhysicsScene.SculptLOD;
|
lod = PhysicsScene.SculptLOD;
|
||||||
|
|
||||||
// Mega prims usually get more detail because one can interact with shape approximations at this size.
|
// 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)
|
if (maxAxis > PhysicsScene.MeshMegaPrimThreshold)
|
||||||
lod = PhysicsScene.MeshMegaPrimLOD;
|
lod = PhysicsScene.MeshMegaPrimLOD;
|
||||||
|
|
||||||
retLod = lod;
|
retLod = lod;
|
||||||
return pbs.GetMeshKey(shapeData.Size, lod);
|
return pbs.GetMeshKey(size, lod);
|
||||||
}
|
}
|
||||||
// For those who don't want the 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;
|
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.
|
// 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;
|
// 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).
|
// and 2) the asset cannot be converted (like failed decompression of JPEG2000s).
|
||||||
// The first case causes the asset to be fetched. The second case just requires
|
// The first case causes the asset to be fetched. The second case requires
|
||||||
// us to not loop forever.
|
// us to not loop forever.
|
||||||
// Called after creating a physical mesh or hull. If the physical shape was created,
|
// Called after creating a physical mesh or hull. If the physical shape was created,
|
||||||
// just return.
|
// 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 the shape was successfully created, nothing more to do
|
||||||
if (newShape.ptr != IntPtr.Zero)
|
if (newShape.ptr != IntPtr.Zero)
|
||||||
return newShape;
|
return newShape;
|
||||||
|
|
||||||
// If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
|
// If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
|
||||||
if (pbs.SculptEntry && !prim.LastAssetBuildFailed && pbs.SculptTexture != OMV.UUID.Zero)
|
if (prim.BaseShape.SculptEntry && !prim.LastAssetBuildFailed && prim.BaseShape.SculptTexture != OMV.UUID.Zero)
|
||||||
{
|
{
|
||||||
prim.LastAssetBuildFailed = true;
|
prim.LastAssetBuildFailed = true;
|
||||||
BSPhysObject xprim = prim;
|
BSPhysObject xprim = prim;
|
||||||
DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lID={1},lastFailed={2}",
|
DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lID={1},lastFailed={2}",
|
||||||
LogHeader, shapeData.ID.ToString("X"), prim.LastAssetBuildFailed);
|
LogHeader, prim.LocalID, prim.LastAssetBuildFailed);
|
||||||
Util.FireAndForget(delegate
|
Util.FireAndForget(delegate
|
||||||
{
|
{
|
||||||
RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
|
RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
|
||||||
|
@ -745,7 +876,7 @@ public class BSShapeCollection : IDisposable
|
||||||
yprim.BaseShape.SculptData = asset.Data;
|
yprim.BaseShape.SculptData = asset.Data;
|
||||||
// This will cause the prim to see that the filler shape is not the right
|
// This will cause the prim to see that the filler shape is not the right
|
||||||
// one and try again to build the object.
|
// one and try again to build the object.
|
||||||
// No race condition with the native sphere setting since the rebuild is at taint time.
|
// No race condition with the normal shape setting since the rebuild is at taint time.
|
||||||
yprim.ForceBodyShapeRebuild(false);
|
yprim.ForceBodyShapeRebuild(false);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -757,13 +888,13 @@ public class BSShapeCollection : IDisposable
|
||||||
if (prim.LastAssetBuildFailed)
|
if (prim.LastAssetBuildFailed)
|
||||||
{
|
{
|
||||||
PhysicsScene.Logger.ErrorFormat("{0} Mesh failed to fetch asset. lID={1}, texture={2}",
|
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.
|
// While we figure out the real problem, stick a simple native shape on the object.
|
||||||
BulletShape fillinShape =
|
BulletShape fillinShape =
|
||||||
BuildPhysicalNativeShape(ShapeData.PhysicsShapeType.SHAPE_BOX, shapeData, ShapeData.FixedShapeKey.KEY_BOX);
|
BuildPhysicalNativeShape(prim, ShapeData.PhysicsShapeType.SHAPE_BOX, ShapeData.FixedShapeKey.KEY_BOX);
|
||||||
|
|
||||||
return fillinShape;
|
return fillinShape;
|
||||||
}
|
}
|
||||||
|
@ -773,18 +904,18 @@ public class BSShapeCollection : IDisposable
|
||||||
// Returns 'true' if an object was actually created.
|
// Returns 'true' if an object was actually created.
|
||||||
// Called at taint-time.
|
// Called at taint-time.
|
||||||
private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape,
|
private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape,
|
||||||
ShapeData shapeData, BodyDestructionCallback bodyCallback)
|
BodyDestructionCallback bodyCallback)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
// the mesh, hull or native shape must have already been created in Bullet
|
// 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 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 not a solid object, body is a GhostObject. Otherwise a RigidBody.
|
||||||
if (!mustRebuild)
|
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
|
if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY
|
||||||
|| !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT)
|
|| !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT)
|
||||||
{
|
{
|
||||||
|
@ -796,27 +927,27 @@ public class BSShapeCollection : IDisposable
|
||||||
if (mustRebuild || forceRebuild)
|
if (mustRebuild || forceRebuild)
|
||||||
{
|
{
|
||||||
// Free any old body
|
// Free any old body
|
||||||
DereferenceBody(prim.BSBody, true, bodyCallback);
|
DereferenceBody(prim.PhysBody, true, bodyCallback);
|
||||||
|
|
||||||
BulletBody aBody;
|
BulletBody aBody;
|
||||||
IntPtr bodyPtr = IntPtr.Zero;
|
IntPtr bodyPtr = IntPtr.Zero;
|
||||||
if (prim.IsSolid)
|
if (prim.IsSolid)
|
||||||
{
|
{
|
||||||
bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr,
|
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"));
|
DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr,
|
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"));
|
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);
|
ReferenceBody(aBody, true);
|
||||||
|
|
||||||
prim.BSBody = aBody;
|
prim.PhysBody = aBody;
|
||||||
|
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
|
@ -824,6 +955,42 @@ public class BSShapeCollection : IDisposable
|
||||||
return ret;
|
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)
|
private void DetailLog(string msg, params Object[] args)
|
||||||
{
|
{
|
||||||
if (PhysicsScene.PhysicsLogging.Enabled)
|
if (PhysicsScene.PhysicsLogging.Enabled)
|
||||||
|
|
|
@ -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) { }
|
||||||
|
}
|
||||||
|
}
|
|
@ -40,7 +40,7 @@ using OpenMetaverse;
|
||||||
|
|
||||||
namespace OpenSim.Region.Physics.BulletSPlugin
|
namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
{
|
{
|
||||||
public class BSTerrainManager
|
public sealed class BSTerrainManager
|
||||||
{
|
{
|
||||||
static string LogHeader = "[BULLETSIM TERRAIN MANAGER]";
|
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}",
|
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.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY);
|
||||||
|
|
||||||
BSScene.TaintCallback rebuildOperation = delegate()
|
PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateOrCreateTerrain:UpdateExisting", delegate()
|
||||||
{
|
{
|
||||||
if (MegaRegionParentPhysicsScene != null)
|
if (MegaRegionParentPhysicsScene != null)
|
||||||
{
|
{
|
||||||
|
@ -337,14 +337,7 @@ public class BSTerrainManager
|
||||||
BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
|
BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
|
||||||
|
|
||||||
m_terrainModified = true;
|
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
|
else
|
||||||
{
|
{
|
||||||
|
@ -364,7 +357,7 @@ public class BSTerrainManager
|
||||||
BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
|
BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
|
||||||
|
|
||||||
// Code that must happen at taint-time
|
// 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);
|
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
|
// 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);
|
UpdateOrCreateTerrain(newTerrainID, heightMap, minCoords, maxCoords, true);
|
||||||
|
|
||||||
m_terrainModified = 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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -194,6 +194,7 @@ public struct ShapeData
|
||||||
// following defined by BulletSim
|
// following defined by BulletSim
|
||||||
SHAPE_GROUNDPLANE = 20,
|
SHAPE_GROUNDPLANE = 20,
|
||||||
SHAPE_TERRAIN = 21,
|
SHAPE_TERRAIN = 21,
|
||||||
|
SHAPE_COMPOUND = 22,
|
||||||
};
|
};
|
||||||
public uint ID;
|
public uint ID;
|
||||||
public PhysicsShapeType Type;
|
public PhysicsShapeType Type;
|
||||||
|
@ -299,6 +300,7 @@ public struct ConfigurationParameters
|
||||||
public float shouldEnableFrictionCaching;
|
public float shouldEnableFrictionCaching;
|
||||||
public float numberOfSolverIterations;
|
public float numberOfSolverIterations;
|
||||||
|
|
||||||
|
public float linksetImplementation;
|
||||||
public float linkConstraintUseFrameOffset;
|
public float linkConstraintUseFrameOffset;
|
||||||
public float linkConstraintEnableTransMotor;
|
public float linkConstraintEnableTransMotor;
|
||||||
public float linkConstraintTransMotorMaxVel;
|
public float linkConstraintTransMotorMaxVel;
|
||||||
|
@ -378,6 +380,7 @@ public enum CollisionFilterGroups : uint
|
||||||
BTerrainFilter = 1 << 11,
|
BTerrainFilter = 1 << 11,
|
||||||
BRaycastFilter = 1 << 12,
|
BRaycastFilter = 1 << 12,
|
||||||
BSolidFilter = 1 << 13,
|
BSolidFilter = 1 << 13,
|
||||||
|
BLinksetFilter = 1 << 14,
|
||||||
|
|
||||||
// The collsion filters and masked are defined in one place -- don't want them scattered
|
// The collsion filters and masked are defined in one place -- don't want them scattered
|
||||||
AvatarFilter = BCharacterFilter,
|
AvatarFilter = BCharacterFilter,
|
||||||
|
@ -386,6 +389,8 @@ public enum CollisionFilterGroups : uint
|
||||||
ObjectMask = BAllFilter,
|
ObjectMask = BAllFilter,
|
||||||
StaticObjectFilter = BStaticFilter,
|
StaticObjectFilter = BStaticFilter,
|
||||||
StaticObjectMask = BAllFilter,
|
StaticObjectMask = BAllFilter,
|
||||||
|
LinksetFilter = BLinksetFilter,
|
||||||
|
LinksetMask = BAllFilter & ~BLinksetFilter,
|
||||||
VolumeDetectFilter = BSensorTrigger,
|
VolumeDetectFilter = BSensorTrigger,
|
||||||
VolumeDetectMask = ~BSensorTrigger,
|
VolumeDetectMask = ~BSensorTrigger,
|
||||||
TerrainFilter = BTerrainFilter,
|
TerrainFilter = BTerrainFilter,
|
||||||
|
@ -395,8 +400,6 @@ public enum CollisionFilterGroups : uint
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0
|
// 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.
|
// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2.
|
||||||
public enum ConstraintParams : int
|
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);
|
public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale);
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
[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]
|
[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]
|
[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]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id);
|
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);
|
public static extern void SetCcdMotionThreshold2(IntPtr obj, float val);
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
[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]
|
[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]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
public static extern IntPtr GetUserPointer2(IntPtr obj);
|
public static extern IntPtr GetUserPointer2(IntPtr obj);
|
||||||
|
@ -906,6 +921,12 @@ public static extern Vector3 GetGravity2(IntPtr obj);
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
public static extern void SetDamping2(IntPtr obj, float lin_damping, float ang_damping);
|
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]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
public static extern float GetLinearDamping2(IntPtr obj);
|
public static extern float GetLinearDamping2(IntPtr obj);
|
||||||
|
|
||||||
|
|
|
@ -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,
|
/// Getting this returns the velocity calculated by physics scene updates, using factors such as target velocity,
|
||||||
/// time to accelerate and collisions.
|
/// time to accelerate and collisions.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
|
public virtual Vector3 TargetVelocity
|
||||||
|
{
|
||||||
|
get { return Velocity; }
|
||||||
|
set { Velocity = value; }
|
||||||
|
}
|
||||||
|
|
||||||
public abstract Vector3 Velocity { get; set; }
|
public abstract Vector3 Velocity { get; set; }
|
||||||
|
|
||||||
public abstract Vector3 Torque { get; set; }
|
public abstract Vector3 Torque { get; set; }
|
||||||
|
|
|
@ -661,6 +661,20 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
set { return; }
|
set { return; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Vector3 TargetVelocity
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return m_taintTargetVelocity;
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
Velocity = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public override Vector3 Velocity
|
public override Vector3 Velocity
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
@ -1394,4 +1408,4 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
m_eventsubscription += p;
|
m_eventsubscription += p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3963,17 +3963,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
|
|
||||||
if (m_TransferModule != null)
|
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,
|
GridInstantMessage msg = new GridInstantMessage(World,
|
||||||
m_host.UUID, m_host.Name + ", an object owned by " +
|
m_host.OwnerID, m_host.Name, destId,
|
||||||
resolveName(m_host.OwnerID) + ",", destId,
|
|
||||||
(byte)InstantMessageDialog.TaskInventoryOffered,
|
(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+" "+
|
World.RegionInfo.RegionName+" "+
|
||||||
m_host.AbsolutePosition.ToString(),
|
m_host.AbsolutePosition.ToString(),
|
||||||
agentItem.ID, true, m_host.AbsolutePosition,
|
agentItem.ID, true, m_host.AbsolutePosition,
|
||||||
bucket, true); // TODO: May actually send no timestamp
|
bucket, true);
|
||||||
|
|
||||||
m_TransferModule.SendInstantMessage(msg, delegate(bool success) {});
|
m_TransferModule.SendInstantMessage(msg, delegate(bool success) {});
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
throw new Exception(String.Format("Failed to load AssetService from {0}; config is {1}", assetService, m_ConfigName));
|
||||||
|
|
||||||
bool allowDelete = serverConfig.GetBoolean("AllowRemoteDelete", false);
|
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 AssetServerGetHandler(m_AssetService));
|
||||||
server.AddStreamHandler(new AssetServerPostHandler(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,
|
MainConsole.Instance.Commands.AddCommand("Assets", false,
|
||||||
"show asset",
|
"show asset",
|
||||||
|
|
|
@ -42,18 +42,32 @@ using OpenSim.Framework.Servers.HttpServer;
|
||||||
|
|
||||||
namespace OpenSim.Server.Handlers.Asset
|
namespace OpenSim.Server.Handlers.Asset
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Remote deletes allowed.
|
||||||
|
/// </summary>
|
||||||
|
public enum AllowedRemoteDeleteTypes
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
MapTile,
|
||||||
|
All
|
||||||
|
}
|
||||||
|
|
||||||
public class AssetServerDeleteHandler : BaseStreamHandler
|
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;
|
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")
|
base("DELETE", "/assets")
|
||||||
{
|
{
|
||||||
m_AssetService = service;
|
m_AssetService = service;
|
||||||
m_allowDelete = allowDelete;
|
m_allowedTypes = allowedTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override byte[] Handle(string path, Stream request,
|
public override byte[] Handle(string path, Stream request,
|
||||||
|
@ -63,13 +77,32 @@ namespace OpenSim.Server.Handlers.Asset
|
||||||
|
|
||||||
string[] p = SplitParams(path);
|
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));
|
XmlSerializer xs = new XmlSerializer(typeof(bool));
|
||||||
return ServerUtils.SerializeResult(xs, result);
|
return ServerUtils.SerializeResult(xs, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -70,7 +70,7 @@ namespace OpenSim.Services.AssetService
|
||||||
|
|
||||||
if (assetLoaderEnabled)
|
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(
|
m_AssetLoader.ForEachDefaultXmlAsset(
|
||||||
loaderArgs,
|
loaderArgs,
|
||||||
|
@ -197,20 +197,7 @@ namespace OpenSim.Services.AssetService
|
||||||
if (!UUID.TryParse(id, out assetID))
|
if (!UUID.TryParse(id, out assetID))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
AssetBase asset = m_Database.GetAsset(assetID);
|
return m_Database.Delete(id);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -194,21 +194,7 @@ namespace OpenSim.Services.AssetService
|
||||||
if (!UUID.TryParse(id, out assetID))
|
if (!UUID.TryParse(id, out assetID))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
AssetBase asset = m_Database.GetAsset(assetID);
|
return m_Database.Delete(id);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -321,7 +321,7 @@ namespace OpenSim.Services.Connectors.Hypergrid
|
||||||
args["destination_uuid"] = OSD.FromString(destination.RegionID.ToString());
|
args["destination_uuid"] = OSD.FromString(destination.RegionID.ToString());
|
||||||
args["teleport_flags"] = OSD.FromString(flags.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())
|
if (result["Success"].AsBoolean())
|
||||||
{
|
{
|
||||||
OSDMap unpacked = (OSDMap)result["_Result"];
|
OSDMap unpacked = (OSDMap)result["_Result"];
|
||||||
|
|
|
@ -68,6 +68,7 @@ namespace OpenSim.Services.HypergridService
|
||||||
private static UUID m_ScopeID;
|
private static UUID m_ScopeID;
|
||||||
private static bool m_AllowTeleportsToAnyRegion;
|
private static bool m_AllowTeleportsToAnyRegion;
|
||||||
private static string m_ExternalName;
|
private static string m_ExternalName;
|
||||||
|
private static Uri m_Uri;
|
||||||
private static GridRegion m_DefaultGatewayRegion;
|
private static GridRegion m_DefaultGatewayRegion;
|
||||||
|
|
||||||
public GatekeeperService(IConfigSource config, ISimulationService simService)
|
public GatekeeperService(IConfigSource config, ISimulationService simService)
|
||||||
|
@ -99,6 +100,15 @@ namespace OpenSim.Services.HypergridService
|
||||||
if (m_ExternalName != string.Empty && !m_ExternalName.EndsWith("/"))
|
if (m_ExternalName != string.Empty && !m_ExternalName.EndsWith("/"))
|
||||||
m_ExternalName = m_ExternalName + "/";
|
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 };
|
Object[] args = new Object[] { config };
|
||||||
m_GridService = ServerUtils.LoadPlugin<IGridService>(gridService, args);
|
m_GridService = ServerUtils.LoadPlugin<IGridService>(gridService, args);
|
||||||
m_PresenceService = ServerUtils.LoadPlugin<IPresenceService>(presenceService, args);
|
m_PresenceService = ServerUtils.LoadPlugin<IPresenceService>(presenceService, args);
|
||||||
|
@ -433,7 +443,18 @@ namespace OpenSim.Services.HypergridService
|
||||||
string externalname = m_ExternalName.TrimEnd(trailing_slash);
|
string externalname = m_ExternalName.TrimEnd(trailing_slash);
|
||||||
m_log.DebugFormat("[GATEKEEPER SERVICE]: Verifying {0} against {1}", addressee, externalname);
|
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
|
#endregion
|
||||||
|
|
|
@ -71,7 +71,7 @@ namespace OpenSim.Services.HypergridService
|
||||||
m_ConfigName = configName;
|
m_ConfigName = configName;
|
||||||
|
|
||||||
if (m_Database == null)
|
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
|
// Try reading the [InventoryService] section, if it exists
|
||||||
|
@ -301,7 +301,7 @@ namespace OpenSim.Services.HypergridService
|
||||||
|
|
||||||
public override bool AddFolder(InventoryFolderBase folder)
|
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
|
// 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
|
// 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)
|
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))
|
if (!IsWithinSuitcaseTree(folder.Owner, folder.ID))
|
||||||
{
|
{
|
||||||
m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: folder {0} not within Suitcase tree", folder.Name);
|
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)
|
if (folders != null && folders.Length > 0)
|
||||||
return folders[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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -584,7 +593,7 @@ namespace OpenSim.Services.HypergridService
|
||||||
{
|
{
|
||||||
if (a.Wearables[i][j].ItemID == itemID)
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -593,7 +602,7 @@ namespace OpenSim.Services.HypergridService
|
||||||
// Check attachments
|
// Check attachments
|
||||||
if (a.GetAttachmentForItem(itemID) != null)
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -400,16 +400,7 @@ namespace OpenSim.Services.InventoryService
|
||||||
|
|
||||||
public virtual bool MoveFolder(InventoryFolderBase folder)
|
public virtual bool MoveFolder(InventoryFolderBase folder)
|
||||||
{
|
{
|
||||||
XInventoryFolder[] x = m_Database.GetFolders(
|
return m_Database.MoveFolder(folder.ID.ToString(), folder.ParentID.ToString());
|
||||||
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]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't check the principal's ID here
|
// We don't check the principal's ID here
|
||||||
|
|
|
@ -125,6 +125,7 @@ namespace OpenSim.Tests.Common.Mock
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool MoveItem(string id, string newParent) { throw new NotImplementedException(); }
|
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 XInventoryItem[] GetActiveGestures(UUID principalID) { throw new NotImplementedException(); }
|
||||||
public int GetAssetPermissions(UUID principalID, UUID assetID) { throw new NotImplementedException(); }
|
public int GetAssetPermissions(UUID principalID, UUID assetID) { throw new NotImplementedException(); }
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
*/
|
|
@ -484,8 +484,15 @@ IntegrationService = "8002/OpenSim.Server.Handlers.dll:IntegrationServiceConnect
|
||||||
; *
|
; *
|
||||||
[HGInventoryService]
|
[HGInventoryService]
|
||||||
; For the InventoryServiceInConnector
|
; 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"
|
UserAccountsService = "OpenSim.Services.UserAccountService.dll:UserAccountService"
|
||||||
|
AvatarService = "OpenSim.Services.AvatarService.dll:AvatarService"
|
||||||
HomeURI = "http://127.0.0.1:8002"
|
HomeURI = "http://127.0.0.1:8002"
|
||||||
|
|
||||||
; * The interface that local users get when they are in other grids.
|
; * The interface that local users get when they are in other grids.
|
||||||
|
|
|
@ -77,7 +77,19 @@ IntegrationService = "8002/OpenSim.Server.Handlers.dll:IntegrationServiceConnect
|
||||||
LocalServiceModule = "OpenSim.Services.AssetService.dll:AssetService"
|
LocalServiceModule = "OpenSim.Services.AssetService.dll:AssetService"
|
||||||
DefaultAssetLoader = "OpenSim.Framework.AssetLoader.Filesystem.dll"
|
DefaultAssetLoader = "OpenSim.Framework.AssetLoader.Filesystem.dll"
|
||||||
AssetLoaderArgs = "./assets/AssetSets.xml"
|
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
|
; * This configuration loads the inventory server modules. It duplicates
|
||||||
; * the function of the legacy inventory server
|
; * the function of the legacy inventory server
|
||||||
|
|
|
@ -47,36 +47,6 @@
|
||||||
DefaultAssetLoader = "OpenSim.Framework.AssetLoader.Filesystem.dll"
|
DefaultAssetLoader = "OpenSim.Framework.AssetLoader.Filesystem.dll"
|
||||||
AssetLoaderArgs = "assets/AssetSets.xml"
|
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]
|
[GridService]
|
||||||
;; For in-memory region storage (default)
|
;; For in-memory region storage (default)
|
||||||
|
@ -97,11 +67,6 @@
|
||||||
;; change this to the address of your simulator
|
;; change this to the address of your simulator
|
||||||
Gatekeeper="http://127.0.0.1:9000"
|
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]
|
[LibraryModule]
|
||||||
; Set this if you want to change the name of the OpenSim Library
|
; Set this if you want to change the name of the OpenSim Library
|
||||||
;LibraryName = "My World's Library"
|
;LibraryName = "My World's Library"
|
||||||
|
@ -140,41 +105,6 @@
|
||||||
;AllowedClients = ""
|
;AllowedClients = ""
|
||||||
;DeniedClients = ""
|
;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]
|
[FreeswitchService]
|
||||||
;; If FreeSWITCH is not being used then you don't need to set any of these parameters
|
;; If FreeSWITCH is not being used then you don't need to set any of these parameters
|
||||||
|
@ -279,6 +209,44 @@
|
||||||
; Example:
|
; Example:
|
||||||
; Region_Test_1 = "DisallowForeigners"
|
; 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]
|
[UserAgentService]
|
||||||
;; User level required to be contacted from other grids
|
;; User level required to be contacted from other grids
|
||||||
;LevelOutsideContacts = 0
|
;LevelOutsideContacts = 0
|
||||||
|
@ -299,3 +267,57 @@
|
||||||
;; If ForeignTripsAllowed is true, make exceptions using AllowExcept.
|
;; If ForeignTripsAllowed is true, make exceptions using AllowExcept.
|
||||||
;; Leave blank or commented for no exceptions.
|
;; Leave blank or commented for no exceptions.
|
||||||
; AllowExcept_Level_200 = "http://griefer.com:8002, http://enemy.com:8002"
|
; 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"
|
||||||
|
|
|
@ -152,7 +152,13 @@
|
||||||
;; This greatly restricts the inventory operations while in other grids
|
;; This greatly restricts the inventory operations while in other grids
|
||||||
[HGInventoryService]
|
[HGInventoryService]
|
||||||
; For the InventoryServiceInConnector
|
; 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"
|
UserAccountsService = "OpenSim.Services.UserAccountService.dll:UserAccountService"
|
||||||
AvatarService = "OpenSim.Services.AvatarService.dll:AvatarService"
|
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.
Loading…
Reference in New Issue