Compare commits
106 Commits
master
...
0.7.5-post
Author | SHA1 | Date |
---|---|---|
Justin Clark-Casey (justincc) | 28e68329b6 | |
Justin Clark-Casey (justincc) | 0d88c3d4dc | |
Justin Clark-Casey (justincc) | 0387725fe2 | |
Justin Clark-Casey (justincc) | c97f16a89b | |
Justin Clark-Casey (justincc) | a29c2fe8fe | |
Justin Clark-Casey (justincc) | 9760cd47f1 | |
Justin Clark-Casey (justincc) | 40cee9b836 | |
Melanie | 12c2b3e983 | |
Kevin Cozens | bfaa24f02d | |
Diva Canto | 98b65bd5f4 | |
Diva Canto | 0e772c6516 | |
Diva Canto | 5be83d47be | |
Diva Canto | 028947f7b8 | |
Diva Canto | 5e094bcd46 | |
Justin Clark-Casey (justincc) | 2c54659ca8 | |
Diva Canto | f5343e4b07 | |
Robert Adams | 764f6dd5e9 | |
Robert Adams | 5444b3b1a5 | |
Robert Adams | cfbb4f52e4 | |
Vegaslon | 00d125dada | |
Robert Adams | 5b3e7156a3 | |
Robert Adams | 783e8e4bab | |
Robert Adams | 921f911b21 | |
Robert Adams | bd9b5927d8 | |
Robert Adams | d48c9b433a | |
Robert Adams | 43f3459c3a | |
Robert Adams | e8c01eff40 | |
Robert Adams | 10a1a6ad3c | |
Robert Adams | 90bdb36e89 | |
Robert Adams | eb0687f5af | |
Justin Clark-Casey (justincc) | aeb5ccaa0a | |
Justin Clark-Casey (justincc) | 6b06157126 | |
Justin Clark-Casey (justincc) | 326522dc3d | |
Justin Clark-Casey (justincc) | 40ed5433bd | |
Justin Clark-Casey (justincc) | a6722abbed | |
Kevin Cozens | 8b1ca7b35e | |
Diva Canto | 00904a0b56 | |
Diva Canto | a830e09bad | |
Justin Clark-Casey (justincc) | 685a3c3c73 | |
Justin Clark-Casey (justincc) | a2d327b70b | |
Justin Clark-Casey (justincc) | 30638317ab | |
Justin Clark-Casey (justincc) | 689da0f14d | |
Justin Clark-Casey (justincc) | 6d3b2d2cf7 | |
teravus | 78debc981f | |
Melanie | e3f01f23af | |
Dan Lake | f28a592310 | |
Justin Clark-Casey (justincc) | 4c4cc917b4 | |
Justin Clark-Casey (justincc) | 430000ad24 | |
Melanie | eab57cdd13 | |
Justin Clark-Casey (justincc) | 5b60f632c9 | |
Talun | d1320993a4 | |
Oren Hurvitz | 319069d193 | |
Justin Clark-Casey (justincc) | 82268d715e | |
Talun | efcbae372b | |
Diva Canto | 6e5d352bf6 | |
Justin Clark-Casey (justincc) | 8f32e16497 | |
Justin Clark-Casey (justincc) | c42e2c6906 | |
Justin Clark-Casey (justincc) | 6bd57f2455 | |
Justin Clark-Casey (justincc) | af5a3f2d73 | |
Justin Clark-Casey (justincc) | 0ba01ce699 | |
Talun | 70e1dd54fa | |
Justin Clark-Casey (justincc) | c42bff5388 | |
Justin Clark-Casey (justincc) | 10b3c6b5aa | |
Robert Adams | 8ecf6ed08e | |
Diva Canto | 09450448b0 | |
dahlia | e2823bfefe | |
Justin Clark-Casey (justincc) | 795009cae2 | |
Robert Adams | cc8fbf76e6 | |
dahlia | af27180131 | |
Justin Clark-Casey (justincc) | c182157d4d | |
Justin Clark-Casey (justincc) | 1cda887d9b | |
Justin Clark-Casey (justincc) | 0ba0ac4669 | |
Justin Clark-Casey (justincc) | ce8b30d868 | |
Justin Clark-Casey (justincc) | d4c4cb3e67 | |
Justin Clark-Casey (justincc) | ac4300664e | |
Justin Clark-Casey (justincc) | 069e2d6443 | |
Justin Clark-Casey (justincc) | 30eded2bda | |
Justin Clark-Casey (justincc) | 2563553f80 | |
Justin Clark-Casey (justincc) | 9ddddde42e | |
Justin Clark-Casey (justincc) | 99a5ea9f90 | |
Justin Clark-Casey (justincc) | 880b2361f5 | |
Justin Clark-Casey (justincc) | f47f3dd8b9 | |
Justin Clark-Casey (justincc) | 8ee078c86b | |
Melanie | 17d54a7c37 | |
Justin Clark-Casey (justincc) | 6f928f52dd | |
Justin Clark-Casey (justincc) | 7199ac09ee | |
Justin Clark-Casey (justincc) | 59263fe78e | |
Justin Clark-Casey (justincc) | 3c631fea9e | |
Justin Clark-Casey (justincc) | ebfcb9d4e4 | |
Justin Clark-Casey (justincc) | 03142980ee | |
Justin Clark-Casey (justincc) | ae355720ab | |
Justin Clark-Casey (justincc) | d87d9af1a5 | |
Justin Clark-Casey (justincc) | b00935015a | |
SignpostMarv | 0022f48d42 | |
SignpostMarv | ce448adf91 | |
SignpostMarv | c4fd1c6297 | |
SignpostMarv | bbe5018b95 | |
Oren Hurvitz | eeeb787f36 | |
Justin Clark-Casey (justincc) | 70e46ba815 | |
Justin Clark-Casey (justincc) | f69731b955 | |
Oren Hurvitz | e5e6fe8c41 | |
Justin Clark-Casey (justincc) | 226d655f23 | |
Justin Clark-Casey (justincc) | afcf5a7591 | |
Oren Hurvitz | 39d2cafb5c | |
Justin Clark-Casey (justincc) | 2b6f12a1d3 | |
Justin Clark-Casey (justincc) | acd9d62af2 |
|
@ -95,3 +95,5 @@ OpenSim/Region/ScriptEngine/test-results/
|
||||||
OpenSim/Tests/Common/test-results/
|
OpenSim/Tests/Common/test-results/
|
||||||
OpenSim/Tests/test-results/
|
OpenSim/Tests/test-results/
|
||||||
test-results/
|
test-results/
|
||||||
|
doc/html
|
||||||
|
doc/doxygen.error.log
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
<delete dir="${distbindir}/Prebuild"/>
|
<delete dir="${distbindir}/Prebuild"/>
|
||||||
<delete dir="${distbindir}/%temp%"/>
|
<delete dir="${distbindir}/%temp%"/>
|
||||||
<delete dir="${distbindir}/.nant"/>
|
<delete dir="${distbindir}/.nant"/>
|
||||||
|
<delete dir="${distbindir}/ThirdParty"/>
|
||||||
<delete>
|
<delete>
|
||||||
<fileset basedir="${distbindir}">
|
<fileset basedir="${distbindir}">
|
||||||
<include name="compile.bat"/>
|
<include name="compile.bat"/>
|
||||||
|
|
|
@ -113,11 +113,14 @@ namespace OpenSim.Data.Null
|
||||||
// Find region data
|
// Find region data
|
||||||
List<RegionData> ret = new List<RegionData>();
|
List<RegionData> ret = new List<RegionData>();
|
||||||
|
|
||||||
foreach (RegionData r in m_regionData.Values)
|
lock (m_regionData)
|
||||||
{
|
{
|
||||||
// m_log.DebugFormat("[NULL REGION DATA]: comparing {0} to {1}", cleanName, r.RegionName.ToLower());
|
foreach (RegionData r in m_regionData.Values)
|
||||||
|
{
|
||||||
|
// m_log.DebugFormat("[NULL REGION DATA]: comparing {0} to {1}", cleanName, r.RegionName.ToLower());
|
||||||
if (queryMatch(r.RegionName.ToLower()))
|
if (queryMatch(r.RegionName.ToLower()))
|
||||||
ret.Add(r);
|
ret.Add(r);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret.Count > 0)
|
if (ret.Count > 0)
|
||||||
|
@ -133,10 +136,13 @@ namespace OpenSim.Data.Null
|
||||||
|
|
||||||
List<RegionData> ret = new List<RegionData>();
|
List<RegionData> ret = new List<RegionData>();
|
||||||
|
|
||||||
foreach (RegionData r in m_regionData.Values)
|
lock (m_regionData)
|
||||||
{
|
{
|
||||||
if (r.posX == posX && r.posY == posY)
|
foreach (RegionData r in m_regionData.Values)
|
||||||
ret.Add(r);
|
{
|
||||||
|
if (r.posX == posX && r.posY == posY)
|
||||||
|
ret.Add(r);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret.Count > 0)
|
if (ret.Count > 0)
|
||||||
|
@ -150,8 +156,11 @@ namespace OpenSim.Data.Null
|
||||||
if (m_useStaticInstance && Instance != this)
|
if (m_useStaticInstance && Instance != this)
|
||||||
return Instance.Get(regionID, scopeID);
|
return Instance.Get(regionID, scopeID);
|
||||||
|
|
||||||
if (m_regionData.ContainsKey(regionID))
|
lock (m_regionData)
|
||||||
return m_regionData[regionID];
|
{
|
||||||
|
if (m_regionData.ContainsKey(regionID))
|
||||||
|
return m_regionData[regionID];
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -163,10 +172,13 @@ namespace OpenSim.Data.Null
|
||||||
|
|
||||||
List<RegionData> ret = new List<RegionData>();
|
List<RegionData> ret = new List<RegionData>();
|
||||||
|
|
||||||
foreach (RegionData r in m_regionData.Values)
|
lock (m_regionData)
|
||||||
{
|
{
|
||||||
if (r.posX >= startX && r.posX <= endX && r.posY >= startY && r.posY <= endY)
|
foreach (RegionData r in m_regionData.Values)
|
||||||
ret.Add(r);
|
{
|
||||||
|
if (r.posX >= startX && r.posX <= endX && r.posY >= startY && r.posY <= endY)
|
||||||
|
ret.Add(r);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -180,7 +192,10 @@ namespace OpenSim.Data.Null
|
||||||
// m_log.DebugFormat(
|
// m_log.DebugFormat(
|
||||||
// "[NULL REGION DATA]: Storing region {0} {1}, scope {2}", data.RegionName, data.RegionID, data.ScopeID);
|
// "[NULL REGION DATA]: Storing region {0} {1}, scope {2}", data.RegionName, data.RegionID, data.ScopeID);
|
||||||
|
|
||||||
m_regionData[data.RegionID] = data;
|
lock (m_regionData)
|
||||||
|
{
|
||||||
|
m_regionData[data.RegionID] = data;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -190,10 +205,13 @@ namespace OpenSim.Data.Null
|
||||||
if (m_useStaticInstance && Instance != this)
|
if (m_useStaticInstance && Instance != this)
|
||||||
return Instance.SetDataItem(regionID, item, value);
|
return Instance.SetDataItem(regionID, item, value);
|
||||||
|
|
||||||
if (!m_regionData.ContainsKey(regionID))
|
lock (m_regionData)
|
||||||
return false;
|
{
|
||||||
|
if (!m_regionData.ContainsKey(regionID))
|
||||||
|
return false;
|
||||||
|
|
||||||
m_regionData[regionID].Data[item] = value;
|
m_regionData[regionID].Data[item] = value;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -205,10 +223,13 @@ namespace OpenSim.Data.Null
|
||||||
|
|
||||||
// m_log.DebugFormat("[NULL REGION DATA]: Deleting region {0}", regionID);
|
// m_log.DebugFormat("[NULL REGION DATA]: Deleting region {0}", regionID);
|
||||||
|
|
||||||
if (!m_regionData.ContainsKey(regionID))
|
lock (m_regionData)
|
||||||
return false;
|
{
|
||||||
|
if (!m_regionData.ContainsKey(regionID))
|
||||||
|
return false;
|
||||||
|
|
||||||
m_regionData.Remove(regionID);
|
m_regionData.Remove(regionID);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -238,10 +259,13 @@ namespace OpenSim.Data.Null
|
||||||
|
|
||||||
List<RegionData> ret = new List<RegionData>();
|
List<RegionData> ret = new List<RegionData>();
|
||||||
|
|
||||||
foreach (RegionData r in m_regionData.Values)
|
lock (m_regionData)
|
||||||
{
|
{
|
||||||
if ((Convert.ToInt32(r.Data["flags"]) & regionFlags) != 0)
|
foreach (RegionData r in m_regionData.Values)
|
||||||
ret.Add(r);
|
{
|
||||||
|
if ((Convert.ToInt32(r.Data["flags"]) & regionFlags) != 0)
|
||||||
|
ret.Add(r);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -110,10 +110,11 @@ namespace OpenSim.Framework.Console
|
||||||
// Remove initial help keyword
|
// Remove initial help keyword
|
||||||
helpParts.RemoveAt(0);
|
helpParts.RemoveAt(0);
|
||||||
|
|
||||||
|
help.Add(""); // Will become a newline.
|
||||||
|
|
||||||
// General help
|
// General help
|
||||||
if (helpParts.Count == 0)
|
if (helpParts.Count == 0)
|
||||||
{
|
{
|
||||||
help.Add(""); // Will become a newline.
|
|
||||||
help.Add(GeneralHelpText);
|
help.Add(GeneralHelpText);
|
||||||
help.Add(ItemHelpText);
|
help.Add(ItemHelpText);
|
||||||
help.AddRange(CollectModulesHelp(tree));
|
help.AddRange(CollectModulesHelp(tree));
|
||||||
|
@ -127,6 +128,8 @@ namespace OpenSim.Framework.Console
|
||||||
help.AddRange(CollectHelp(helpParts));
|
help.AddRange(CollectHelp(helpParts));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
help.Add(""); // Will become a newline.
|
||||||
|
|
||||||
return help;
|
return help;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,14 +197,11 @@ namespace OpenSim.Framework.Console
|
||||||
|
|
||||||
string descriptiveHelp = commandInfo.descriptive_help;
|
string descriptiveHelp = commandInfo.descriptive_help;
|
||||||
|
|
||||||
// If we do have some descriptive help then insert a spacing line before and after for readability.
|
// If we do have some descriptive help then insert a spacing line before for readability.
|
||||||
if (descriptiveHelp != string.Empty)
|
if (descriptiveHelp != string.Empty)
|
||||||
help.Add(string.Empty);
|
help.Add(string.Empty);
|
||||||
|
|
||||||
help.Add(commandInfo.descriptive_help);
|
help.Add(commandInfo.descriptive_help);
|
||||||
|
|
||||||
if (descriptiveHelp != string.Empty)
|
|
||||||
help.Add(string.Empty);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -56,7 +56,7 @@ namespace OpenSim.Framework.Console
|
||||||
public List<ConsoleDisplayTableRow> Rows { get; private set; }
|
public List<ConsoleDisplayTableRow> Rows { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Number of spaces to indent the table.
|
/// Number of spaces to indent the whole table.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Indent { get; set; }
|
public int Indent { get; set; }
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ namespace OpenSim.Framework.Console
|
||||||
Columns.Add(new ConsoleDisplayTableColumn(name, width));
|
Columns.Add(new ConsoleDisplayTableColumn(name, width));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddRow(params string[] cells)
|
public void AddRow(params object[] cells)
|
||||||
{
|
{
|
||||||
Rows.Add(new ConsoleDisplayTableRow(cells));
|
Rows.Add(new ConsoleDisplayTableRow(cells));
|
||||||
}
|
}
|
||||||
|
@ -113,7 +113,8 @@ namespace OpenSim.Framework.Console
|
||||||
|
|
||||||
for (int i = 0; i < Columns.Count; i++)
|
for (int i = 0; i < Columns.Count; i++)
|
||||||
{
|
{
|
||||||
formatSb.Append(' ', TableSpacing);
|
if (i != 0)
|
||||||
|
formatSb.Append(' ', TableSpacing);
|
||||||
|
|
||||||
// Can only do left formatting for now
|
// Can only do left formatting for now
|
||||||
formatSb.AppendFormat("{{{0},-{1}}}", i, Columns[i].Width);
|
formatSb.AppendFormat("{{{0},-{1}}}", i, Columns[i].Width);
|
||||||
|
@ -139,16 +140,16 @@ namespace OpenSim.Framework.Console
|
||||||
|
|
||||||
public struct ConsoleDisplayTableRow
|
public struct ConsoleDisplayTableRow
|
||||||
{
|
{
|
||||||
public List<string> Cells { get; private set; }
|
public List<object> Cells { get; private set; }
|
||||||
|
|
||||||
public ConsoleDisplayTableRow(List<string> cells) : this()
|
public ConsoleDisplayTableRow(List<object> cells) : this()
|
||||||
{
|
{
|
||||||
Cells = cells;
|
Cells = cells;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConsoleDisplayTableRow(params string[] cells) : this()
|
public ConsoleDisplayTableRow(params object[] cells) : this()
|
||||||
{
|
{
|
||||||
Cells = new List<string>(cells);
|
Cells = new List<object>(cells);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1623,6 +1623,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
|
|
||||||
// Long Poll Service Manager with 3 worker threads a 25 second timeout for no events
|
// Long Poll Service Manager with 3 worker threads a 25 second timeout for no events
|
||||||
m_PollServiceManager = new PollServiceRequestManager(this, 3, 25000);
|
m_PollServiceManager = new PollServiceRequestManager(this, 3, 25000);
|
||||||
|
m_PollServiceManager.Start();
|
||||||
HTTPDRunning = true;
|
HTTPDRunning = true;
|
||||||
|
|
||||||
//HttpListenerContext context;
|
//HttpListenerContext context;
|
||||||
|
@ -1673,6 +1674,8 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
HTTPDRunning = false;
|
HTTPDRunning = false;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
m_PollServiceManager.Stop();
|
||||||
|
|
||||||
m_httpListener2.ExceptionThrown -= httpServerException;
|
m_httpListener2.ExceptionThrown -= httpServerException;
|
||||||
//m_httpListener2.DisconnectHandler = null;
|
//m_httpListener2.DisconnectHandler = null;
|
||||||
|
|
||||||
|
|
|
@ -45,19 +45,26 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
private uint m_WorkerThreadCount = 0;
|
private uint m_WorkerThreadCount = 0;
|
||||||
private Thread[] m_workerThreads;
|
private Thread[] m_workerThreads;
|
||||||
private PollServiceWorkerThread[] m_PollServiceWorkerThreads;
|
private PollServiceWorkerThread[] m_PollServiceWorkerThreads;
|
||||||
private bool m_running = true;
|
private volatile bool m_running = true;
|
||||||
|
private int m_pollTimeout;
|
||||||
|
|
||||||
public PollServiceRequestManager(BaseHttpServer pSrv, uint pWorkerThreadCount, int pTimeout)
|
public PollServiceRequestManager(BaseHttpServer pSrv, uint pWorkerThreadCount, int pTimeout)
|
||||||
{
|
{
|
||||||
m_server = pSrv;
|
m_server = pSrv;
|
||||||
m_WorkerThreadCount = pWorkerThreadCount;
|
m_WorkerThreadCount = pWorkerThreadCount;
|
||||||
|
m_pollTimeout = pTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
m_running = true;
|
||||||
m_workerThreads = new Thread[m_WorkerThreadCount];
|
m_workerThreads = new Thread[m_WorkerThreadCount];
|
||||||
m_PollServiceWorkerThreads = new PollServiceWorkerThread[m_WorkerThreadCount];
|
m_PollServiceWorkerThreads = new PollServiceWorkerThread[m_WorkerThreadCount];
|
||||||
|
|
||||||
//startup worker threads
|
//startup worker threads
|
||||||
for (uint i = 0; i < m_WorkerThreadCount; i++)
|
for (uint i = 0; i < m_WorkerThreadCount; i++)
|
||||||
{
|
{
|
||||||
m_PollServiceWorkerThreads[i] = new PollServiceWorkerThread(m_server, pTimeout);
|
m_PollServiceWorkerThreads[i] = new PollServiceWorkerThread(m_server, m_pollTimeout);
|
||||||
m_PollServiceWorkerThreads[i].ReQueue += ReQueueEvent;
|
m_PollServiceWorkerThreads[i].ReQueue += ReQueueEvent;
|
||||||
|
|
||||||
m_workerThreads[i]
|
m_workerThreads[i]
|
||||||
|
@ -136,8 +143,10 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~PollServiceRequestManager()
|
public void Stop()
|
||||||
{
|
{
|
||||||
|
m_running = false;
|
||||||
|
|
||||||
foreach (object o in m_requests)
|
foreach (object o in m_requests)
|
||||||
{
|
{
|
||||||
PollServiceHttpRequest req = (PollServiceHttpRequest) o;
|
PollServiceHttpRequest req = (PollServiceHttpRequest) o;
|
||||||
|
@ -151,8 +160,6 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
{
|
{
|
||||||
t.Abort();
|
t.Abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_running = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -29,8 +29,8 @@ namespace OpenSim
|
||||||
{
|
{
|
||||||
public class VersionInfo
|
public class VersionInfo
|
||||||
{
|
{
|
||||||
private const string VERSION_NUMBER = "0.7.5";
|
private const string VERSION_NUMBER = "0.7.5.2";
|
||||||
private const Flavour VERSION_FLAVOUR = Flavour.Dev;
|
private const Flavour VERSION_FLAVOUR = Flavour.Post_Fixes;
|
||||||
|
|
||||||
public enum Flavour
|
public enum Flavour
|
||||||
{
|
{
|
||||||
|
|
|
@ -299,6 +299,18 @@ namespace OpenSim.Framework
|
||||||
x;
|
x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clamp the maximum magnitude of a vector
|
||||||
|
public static Vector3 ClampV(Vector3 x, float max)
|
||||||
|
{
|
||||||
|
Vector3 ret = x;
|
||||||
|
float lenSq = x.LengthSquared();
|
||||||
|
if (lenSq > (max * max))
|
||||||
|
{
|
||||||
|
x = x / x.Length() * max;
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
// Inclusive, within range test (true if equal to the endpoints)
|
// Inclusive, within range test (true if equal to the endpoints)
|
||||||
public static bool InRange<T>(T x, T min, T max)
|
public static bool InRange<T>(T x, T min, T max)
|
||||||
where T : IComparable<T>
|
where T : IComparable<T>
|
||||||
|
@ -1646,8 +1658,13 @@ namespace OpenSim.Framework
|
||||||
if (m_ThreadPool != null)
|
if (m_ThreadPool != null)
|
||||||
throw new InvalidOperationException("SmartThreadPool is already initialized");
|
throw new InvalidOperationException("SmartThreadPool is already initialized");
|
||||||
|
|
||||||
m_ThreadPool = new SmartThreadPool(2000, maxThreads, 2);
|
STPStartInfo startInfo = new STPStartInfo();
|
||||||
m_ThreadPool.Name = "Util";
|
startInfo.ThreadPoolName = "Util";
|
||||||
|
startInfo.IdleTimeout = 2000;
|
||||||
|
startInfo.MaxWorkerThreads = maxThreads;
|
||||||
|
startInfo.MinWorkerThreads = 2;
|
||||||
|
|
||||||
|
m_ThreadPool = new SmartThreadPool(startInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int FireAndForgetCount()
|
public static int FireAndForgetCount()
|
||||||
|
|
|
@ -236,18 +236,6 @@ namespace OpenSim
|
||||||
+ "If an avatar name is given then only packets from that avatar are logged",
|
+ "If an avatar name is given then only packets from that avatar are logged",
|
||||||
Debug);
|
Debug);
|
||||||
|
|
||||||
m_console.Commands.AddCommand("Debug", false, "debug teleport", "debug teleport", "Toggle teleport route debugging", Debug);
|
|
||||||
|
|
||||||
m_console.Commands.AddCommand("Debug", false, "debug scene",
|
|
||||||
"debug scene active|collisions|physics|scripting|teleport true|false",
|
|
||||||
"Turn on scene debugging.",
|
|
||||||
"If active is false then main scene update and maintenance loops are suspended.\n"
|
|
||||||
+ "If collisions is false then collisions with other objects are turned off.\n"
|
|
||||||
+ "If physics is false then all physics objects are non-physical.\n"
|
|
||||||
+ "If scripting is false then no scripting operations happen.\n"
|
|
||||||
+ "If teleport is true then some extra teleport debug information is logged.",
|
|
||||||
Debug);
|
|
||||||
|
|
||||||
m_console.Commands.AddCommand("General", false, "change region",
|
m_console.Commands.AddCommand("General", false, "change region",
|
||||||
"change region <region name>",
|
"change region <region name>",
|
||||||
"Change current console region", ChangeSelectedRegion);
|
"Change current console region", ChangeSelectedRegion);
|
||||||
|
@ -744,31 +732,6 @@ namespace OpenSim
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "scene":
|
|
||||||
if (args.Length == 4)
|
|
||||||
{
|
|
||||||
if (SceneManager.CurrentScene == null)
|
|
||||||
{
|
|
||||||
MainConsole.Instance.Output("Please use 'change region <regioname>' first");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
string key = args[2];
|
|
||||||
string value = args[3];
|
|
||||||
SceneManager.CurrentScene.SetSceneCoreDebug(
|
|
||||||
new Dictionary<string, string>() { { key, value } });
|
|
||||||
|
|
||||||
MainConsole.Instance.OutputFormat("Set debug scene {0} = {1}", key, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MainConsole.Instance.Output(
|
|
||||||
"Usage: debug scene active|scripting|collisions|physics|teleport true|false");
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
MainConsole.Instance.Output("Unknown debug command");
|
MainConsole.Instance.Output("Unknown debug command");
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -96,8 +96,8 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||||
// private static readonly string m_fetchInventoryPath = "0006/";
|
// private static readonly string m_fetchInventoryPath = "0006/";
|
||||||
private static readonly string m_copyFromNotecardPath = "0007/";
|
private static readonly string m_copyFromNotecardPath = "0007/";
|
||||||
// private static readonly string m_remoteParcelRequestPath = "0009/";// This is in the LandManagementModule.
|
// private static readonly string m_remoteParcelRequestPath = "0009/";// This is in the LandManagementModule.
|
||||||
|
private static readonly string m_UpdateAgentInformationPath = "0500/";
|
||||||
|
|
||||||
// These are callbacks which will be setup by the scene so that we can update scene data when we
|
// These are callbacks which will be setup by the scene so that we can update scene data when we
|
||||||
// receive capability calls
|
// receive capability calls
|
||||||
public NewInventoryItem AddNewInventoryItem = null;
|
public NewInventoryItem AddNewInventoryItem = null;
|
||||||
|
@ -204,6 +204,8 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||||
m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req);
|
m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req);
|
||||||
m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req);
|
m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req);
|
||||||
m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req);
|
m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req);
|
||||||
|
IRequestHandler UpdateAgentInformationHandler = new RestStreamHandler("POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation);
|
||||||
|
m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler);
|
||||||
|
|
||||||
m_HostCapsObj.RegisterHandler(
|
m_HostCapsObj.RegisterHandler(
|
||||||
"CopyInventoryFromNotecard",
|
"CopyInventoryFromNotecard",
|
||||||
|
@ -615,7 +617,7 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||||
= new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero);
|
= new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero);
|
||||||
|
|
||||||
prim.Scale = scale;
|
prim.Scale = scale;
|
||||||
prim.OffsetPosition = position;
|
//prim.OffsetPosition = position;
|
||||||
rotations.Add(rotation);
|
rotations.Add(rotation);
|
||||||
positions.Add(position);
|
positions.Add(position);
|
||||||
prim.UUID = UUID.Random();
|
prim.UUID = UUID.Random();
|
||||||
|
@ -639,25 +641,40 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||||
grp.AddPart(prim);
|
grp.AddPart(prim);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fix first link number
|
Vector3 rootPos = positions[0];
|
||||||
|
|
||||||
if (grp.Parts.Length > 1)
|
if (grp.Parts.Length > 1)
|
||||||
|
{
|
||||||
|
// Fix first link number
|
||||||
grp.RootPart.LinkNum++;
|
grp.RootPart.LinkNum++;
|
||||||
|
|
||||||
Vector3 rootPos = positions[0];
|
Quaternion rootRotConj = Quaternion.Conjugate(rotations[0]);
|
||||||
grp.AbsolutePosition = rootPos;
|
Quaternion tmprot;
|
||||||
for (int i = 0; i < positions.Count; i++)
|
Vector3 offset;
|
||||||
|
|
||||||
|
// fix children rotations and positions
|
||||||
|
for (int i = 1; i < rotations.Count; i++)
|
||||||
|
{
|
||||||
|
tmprot = rotations[i];
|
||||||
|
tmprot = rootRotConj * tmprot;
|
||||||
|
|
||||||
|
grp.Parts[i].RotationOffset = tmprot;
|
||||||
|
|
||||||
|
offset = positions[i] - rootPos;
|
||||||
|
|
||||||
|
offset *= rootRotConj;
|
||||||
|
grp.Parts[i].OffsetPosition = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
grp.AbsolutePosition = rootPos;
|
||||||
|
grp.UpdateGroupRotationR(rotations[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
Vector3 offset = positions[i] - rootPos;
|
grp.AbsolutePosition = rootPos;
|
||||||
grp.Parts[i].OffsetPosition = offset;
|
grp.UpdateGroupRotationR(rotations[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < rotations.Count; i++)
|
|
||||||
{
|
|
||||||
if (i != 0)
|
|
||||||
grp.Parts[i].RotationOffset = rotations[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
grp.UpdateGroupRotationR(rotations[0]);
|
|
||||||
data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp));
|
data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -855,6 +872,22 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||||
response["int_response_code"] = 200;
|
response["int_response_code"] = 200;
|
||||||
return LLSDHelpers.SerialiseLLSDReply(response);
|
return LLSDHelpers.SerialiseLLSDReply(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string UpdateAgentInformation(string request, string path,
|
||||||
|
string param, IOSHttpRequest httpRequest,
|
||||||
|
IOSHttpResponse httpResponse)
|
||||||
|
{
|
||||||
|
OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
|
||||||
|
OSDMap resp = new OSDMap();
|
||||||
|
|
||||||
|
OSDMap accessPrefs = new OSDMap();
|
||||||
|
accessPrefs["max"] = "A";
|
||||||
|
|
||||||
|
resp["access_prefs"] = accessPrefs;
|
||||||
|
|
||||||
|
string response = OSDParser.SerializeLLSDXmlString(resp);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AssetUploader
|
public class AssetUploader
|
||||||
|
|
|
@ -57,7 +57,6 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||||
public bool Enabled { get; private set; }
|
public bool Enabled { get; private set; }
|
||||||
|
|
||||||
private Scene m_scene;
|
private Scene m_scene;
|
||||||
private UUID m_agentID;
|
|
||||||
|
|
||||||
#region ISharedRegionModule Members
|
#region ISharedRegionModule Members
|
||||||
|
|
||||||
|
@ -118,25 +117,26 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||||
public void RegisterCaps(UUID agentID, Caps caps)
|
public void RegisterCaps(UUID agentID, Caps caps)
|
||||||
{
|
{
|
||||||
IRequestHandler reqHandler
|
IRequestHandler reqHandler
|
||||||
= new RestHTTPHandler("GET", "/CAPS/" + UUID.Random(), MeshUploadFlag, "MeshUploadFlag", agentID.ToString());
|
= new RestHTTPHandler(
|
||||||
|
"GET", "/CAPS/" + UUID.Random(), ht => MeshUploadFlag(ht, agentID), "MeshUploadFlag", agentID.ToString());
|
||||||
|
|
||||||
caps.RegisterHandler("MeshUploadFlag", reqHandler);
|
caps.RegisterHandler("MeshUploadFlag", reqHandler);
|
||||||
m_agentID = agentID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Hashtable MeshUploadFlag(Hashtable mDhttpMethod)
|
private Hashtable MeshUploadFlag(Hashtable mDhttpMethod, UUID agentID)
|
||||||
{
|
{
|
||||||
// m_log.DebugFormat("[MESH UPLOAD FLAG MODULE]: MeshUploadFlag request");
|
// m_log.DebugFormat("[MESH UPLOAD FLAG MODULE]: MeshUploadFlag request");
|
||||||
|
|
||||||
OSDMap data = new OSDMap();
|
OSDMap data = new OSDMap();
|
||||||
ScenePresence sp = m_scene.GetScenePresence(m_agentID);
|
ScenePresence sp = m_scene.GetScenePresence(agentID);
|
||||||
data["username"] = sp.Firstname + "." + sp.Lastname;
|
data["username"] = sp.Firstname + "." + sp.Lastname;
|
||||||
data["display_name_next_update"] = new OSDDate(DateTime.Now);
|
data["display_name_next_update"] = new OSDDate(DateTime.Now);
|
||||||
data["legacy_first_name"] = sp.Firstname;
|
data["legacy_first_name"] = sp.Firstname;
|
||||||
data["mesh_upload_status"] = "valid";
|
data["mesh_upload_status"] = "valid";
|
||||||
data["display_name"] = sp.Firstname + " " + sp.Lastname;
|
data["display_name"] = sp.Firstname + " " + sp.Lastname;
|
||||||
data["legacy_last_name"] = sp.Lastname;
|
data["legacy_last_name"] = sp.Lastname;
|
||||||
data["id"] = m_agentID;
|
data["id"] = agentID;
|
||||||
data["is_display_name_default"] = true;
|
data["is_display_name_default"] = true;
|
||||||
|
|
||||||
//Send back data
|
//Send back data
|
||||||
|
|
|
@ -3530,7 +3530,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
|
|
||||||
AvatarAppearancePacket avp = (AvatarAppearancePacket)PacketPool.Instance.GetPacket(PacketType.AvatarAppearance);
|
AvatarAppearancePacket avp = (AvatarAppearancePacket)PacketPool.Instance.GetPacket(PacketType.AvatarAppearance);
|
||||||
// TODO: don't create new blocks if recycling an old packet
|
// TODO: don't create new blocks if recycling an old packet
|
||||||
avp.VisualParam = new AvatarAppearancePacket.VisualParamBlock[218];
|
avp.VisualParam = new AvatarAppearancePacket.VisualParamBlock[visualParams.Length];
|
||||||
avp.ObjectData.TextureEntry = textureEntry;
|
avp.ObjectData.TextureEntry = textureEntry;
|
||||||
|
|
||||||
AvatarAppearancePacket.VisualParamBlock avblock = null;
|
AvatarAppearancePacket.VisualParamBlock avblock = null;
|
||||||
|
@ -6427,6 +6427,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
AgentRequestSit handlerAgentRequestSit = OnAgentRequestSit;
|
AgentRequestSit handlerAgentRequestSit = OnAgentRequestSit;
|
||||||
|
|
||||||
if (handlerAgentRequestSit != null)
|
if (handlerAgentRequestSit != null)
|
||||||
handlerAgentRequestSit(this, agentRequestSit.AgentData.AgentID,
|
handlerAgentRequestSit(this, agentRequestSit.AgentData.AgentID,
|
||||||
agentRequestSit.TargetObject.TargetID, agentRequestSit.TargetObject.Offset);
|
agentRequestSit.TargetObject.TargetID, agentRequestSit.TargetObject.Offset);
|
||||||
|
|
|
@ -214,9 +214,9 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
|
||||||
public void HandleTaskItemUpdateFromTransaction(
|
public void HandleTaskItemUpdateFromTransaction(
|
||||||
IClientAPI remoteClient, SceneObjectPart part, UUID transactionID, TaskInventoryItem item)
|
IClientAPI remoteClient, SceneObjectPart part, UUID transactionID, TaskInventoryItem item)
|
||||||
{
|
{
|
||||||
m_log.DebugFormat(
|
// m_log.DebugFormat(
|
||||||
"[ASSET TRANSACTION MODULE] Called HandleTaskItemUpdateFromTransaction with item {0} in {1} for {2} in {3}",
|
// "[ASSET TRANSACTION MODULE]: Called HandleTaskItemUpdateFromTransaction with item {0} in {1} for {2} in {3}",
|
||||||
item.Name, part.Name, remoteClient.Name, m_Scene.RegionInfo.RegionName);
|
// item.Name, part.Name, remoteClient.Name, m_Scene.RegionInfo.RegionName);
|
||||||
|
|
||||||
AgentAssetTransactions transactions =
|
AgentAssetTransactions transactions =
|
||||||
GetUserTransactions(remoteClient.AgentId);
|
GetUserTransactions(remoteClient.AgentId);
|
||||||
|
@ -230,15 +230,17 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="remoteClient"></param>
|
/// <param name="remoteClient"></param>
|
||||||
/// <param name="assetID"></param>
|
/// <param name="assetID"></param>
|
||||||
/// <param name="transaction"></param>
|
/// <param name="transactionID"></param>
|
||||||
/// <param name="type"></param>
|
/// <param name="type"></param>
|
||||||
/// <param name="data"></param></param>
|
/// <param name="data"></param></param>
|
||||||
/// <param name="tempFile"></param>
|
/// <param name="tempFile"></param>
|
||||||
public void HandleUDPUploadRequest(IClientAPI remoteClient,
|
public void HandleUDPUploadRequest(IClientAPI remoteClient,
|
||||||
UUID assetID, UUID transaction, sbyte type, byte[] data,
|
UUID assetID, UUID transactionID, sbyte type, byte[] data,
|
||||||
bool storeLocal, bool tempFile)
|
bool storeLocal, bool tempFile)
|
||||||
{
|
{
|
||||||
// m_log.Debug("HandleUDPUploadRequest - assetID: " + assetID.ToString() + " transaction: " + transaction.ToString() + " type: " + type.ToString() + " storelocal: " + storeLocal + " tempFile: " + tempFile);
|
// m_log.DebugFormat(
|
||||||
|
// "[ASSET TRANSACTION MODULE]: HandleUDPUploadRequest - assetID: {0}, transaction {1}, type {2}, storeLocal {3}, tempFile {4}, data.Length {5}",
|
||||||
|
// assetID, transactionID, type, storeLocal, tempFile, data.Length);
|
||||||
|
|
||||||
if (((AssetType)type == AssetType.Texture ||
|
if (((AssetType)type == AssetType.Texture ||
|
||||||
(AssetType)type == AssetType.Sound ||
|
(AssetType)type == AssetType.Sound ||
|
||||||
|
@ -274,8 +276,8 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
|
||||||
}
|
}
|
||||||
|
|
||||||
AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId);
|
AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId);
|
||||||
AssetXferUploader uploader = transactions.RequestXferUploader(transaction);
|
AssetXferUploader uploader = transactions.RequestXferUploader(transactionID);
|
||||||
uploader.StartUpload(remoteClient, assetID, transaction, type, data, storeLocal, tempFile);
|
uploader.StartUpload(remoteClient, assetID, transactionID, type, data, storeLocal, tempFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -321,7 +321,8 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
|
||||||
// to avoid a race condition when the appearance module retrieves the item to set the asset id in
|
// to avoid a race condition when the appearance module retrieves the item to set the asset id in
|
||||||
// the AvatarAppearance structure.
|
// the AvatarAppearance structure.
|
||||||
item.AssetID = m_asset.FullID;
|
item.AssetID = m_asset.FullID;
|
||||||
m_Scene.InventoryService.UpdateItem(item);
|
if (item.AssetID != UUID.Zero)
|
||||||
|
m_Scene.InventoryService.UpdateItem(item);
|
||||||
|
|
||||||
if (m_uploadState == UploadState.Complete)
|
if (m_uploadState == UploadState.Complete)
|
||||||
{
|
{
|
||||||
|
|
|
@ -654,15 +654,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||||
|
|
||||||
if (!silent)
|
if (!silent)
|
||||||
{
|
{
|
||||||
// Killing it here will cause the client to deselect it
|
if (so.HasPrivateAttachmentPoint)
|
||||||
// It then reappears on the avatar, deselected
|
|
||||||
// through the full update below
|
|
||||||
//
|
|
||||||
if (so.IsSelected)
|
|
||||||
{
|
|
||||||
m_scene.SendKillObject(new List<uint> { so.RootPart.LocalId });
|
|
||||||
}
|
|
||||||
else if (so.HasPrivateAttachmentPoint)
|
|
||||||
{
|
{
|
||||||
// m_log.DebugFormat(
|
// m_log.DebugFormat(
|
||||||
// "[ATTACHMENTS MODULE]: Killing private HUD {0} for avatars other than {1} at attachment point {2}",
|
// "[ATTACHMENTS MODULE]: Killing private HUD {0} for avatars other than {1} at attachment point {2}",
|
||||||
|
@ -677,7 +669,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
so.IsSelected = false; // fudge....
|
// Fudge below is an extremely unhelpful comment. It's probably here so that the scheduled full update
|
||||||
|
// will succeed, as that will not update if an attachment is selected.
|
||||||
|
so.IsSelected = false; // fudge....
|
||||||
|
|
||||||
so.ScheduleGroupForFullUpdate();
|
so.ScheduleGroupForFullUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -487,6 +487,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
|
||||||
{
|
{
|
||||||
// m_log.DebugFormat(
|
// m_log.DebugFormat(
|
||||||
// "[INVENTORY ARCHIVER]: Loaded coalescence {0} has {1} objects", assetId, coa.Count);
|
// "[INVENTORY ARCHIVER]: Loaded coalescence {0} has {1} objects", assetId, coa.Count);
|
||||||
|
|
||||||
|
if (coa.Objects.Count == 0)
|
||||||
|
{
|
||||||
|
m_log.WarnFormat(
|
||||||
|
"[INVENTORY ARCHIVE READ REQUEST]: Aborting load of coalesced object from asset {0} as it has zero loaded components",
|
||||||
|
assetId);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
sceneObjects.AddRange(coa.Objects);
|
sceneObjects.AddRange(coa.Objects);
|
||||||
}
|
}
|
||||||
|
@ -495,7 +503,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
|
||||||
SceneObjectGroup deserializedObject = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
|
SceneObjectGroup deserializedObject = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
|
||||||
|
|
||||||
if (deserializedObject != null)
|
if (deserializedObject != null)
|
||||||
|
{
|
||||||
sceneObjects.Add(deserializedObject);
|
sceneObjects.Add(deserializedObject);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_log.WarnFormat(
|
||||||
|
"[INVENTORY ARCHIVE READ REQUEST]: Aborting load of object from asset {0} as deserialization failed",
|
||||||
|
assetId);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (SceneObjectGroup sog in sceneObjects)
|
foreach (SceneObjectGroup sog in sceneObjects)
|
||||||
|
|
|
@ -47,10 +47,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
private List<Scene> m_Scenelist = new List<Scene>();
|
private List<Scene> m_Scenelist = new List<Scene>();
|
||||||
// private Dictionary<UUID, Scene> m_AgentRegions =
|
|
||||||
// new Dictionary<UUID, Scene>();
|
|
||||||
|
|
||||||
private IMessageTransferModule m_TransferModule = null;
|
private IMessageTransferModule m_TransferModule;
|
||||||
private bool m_Enabled = true;
|
private bool m_Enabled = true;
|
||||||
|
|
||||||
#region Region Module interface
|
#region Region Module interface
|
||||||
|
@ -81,9 +79,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
|
||||||
// scene.RegisterModuleInterface<IInventoryTransferModule>(this);
|
// scene.RegisterModuleInterface<IInventoryTransferModule>(this);
|
||||||
|
|
||||||
scene.EventManager.OnNewClient += OnNewClient;
|
scene.EventManager.OnNewClient += OnNewClient;
|
||||||
// scene.EventManager.OnClientClosed += ClientLoggedOut;
|
|
||||||
scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage;
|
scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage;
|
||||||
// scene.EventManager.OnSetRootAgentScene += OnSetRootAgentScene;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RegionLoaded(Scene scene)
|
public void RegionLoaded(Scene scene)
|
||||||
|
@ -96,11 +92,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
|
||||||
m_log.Error("[INVENTORY TRANSFER]: No Message transfer module found, transfers will be local only");
|
m_log.Error("[INVENTORY TRANSFER]: No Message transfer module found, transfers will be local only");
|
||||||
m_Enabled = false;
|
m_Enabled = false;
|
||||||
|
|
||||||
m_Scenelist.Clear();
|
// m_Scenelist.Clear();
|
||||||
scene.EventManager.OnNewClient -= OnNewClient;
|
// scene.EventManager.OnNewClient -= OnNewClient;
|
||||||
// scene.EventManager.OnClientClosed -= ClientLoggedOut;
|
|
||||||
scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage;
|
scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage;
|
||||||
// scene.EventManager.OnSetRootAgentScene -= OnSetRootAgentScene;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,9 +102,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
|
||||||
public void RemoveRegion(Scene scene)
|
public void RemoveRegion(Scene scene)
|
||||||
{
|
{
|
||||||
scene.EventManager.OnNewClient -= OnNewClient;
|
scene.EventManager.OnNewClient -= OnNewClient;
|
||||||
// scene.EventManager.OnClientClosed -= ClientLoggedOut;
|
|
||||||
scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage;
|
scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage;
|
||||||
// scene.EventManager.OnSetRootAgentScene -= OnSetRootAgentScene;
|
|
||||||
m_Scenelist.Remove(scene);
|
m_Scenelist.Remove(scene);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,11 +131,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
|
||||||
// Inventory giving is conducted via instant message
|
// Inventory giving is conducted via instant message
|
||||||
client.OnInstantMessage += OnInstantMessage;
|
client.OnInstantMessage += OnInstantMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
// protected void OnSetRootAgentScene(UUID id, Scene scene)
|
|
||||||
// {
|
|
||||||
// m_AgentRegions[id] = scene;
|
|
||||||
// }
|
|
||||||
|
|
||||||
private Scene FindClientScene(UUID agentId)
|
private Scene FindClientScene(UUID agentId)
|
||||||
{
|
{
|
||||||
|
@ -213,7 +200,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
|
||||||
user.ControllingClient.SendBulkUpdateInventory(folderCopy);
|
user.ControllingClient.SendBulkUpdateInventory(folderCopy);
|
||||||
|
|
||||||
// HACK!!
|
// HACK!!
|
||||||
im.imSessionID = folderID.Guid;
|
// Insert the ID of the copied item into the IM so that we know which item to move to trash if it
|
||||||
|
// is rejected.
|
||||||
|
// XXX: This is probably a misuse of the session ID slot.
|
||||||
|
im.imSessionID = copyID.Guid;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -243,7 +233,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
|
||||||
user.ControllingClient.SendBulkUpdateInventory(itemCopy);
|
user.ControllingClient.SendBulkUpdateInventory(itemCopy);
|
||||||
|
|
||||||
// HACK!!
|
// HACK!!
|
||||||
im.imSessionID = itemID.Guid;
|
// Insert the ID of the copied item into the IM so that we know which item to move to trash if it
|
||||||
|
// is rejected.
|
||||||
|
// XXX: This is probably a misuse of the session ID slot.
|
||||||
|
im.imSessionID = copyID.Guid;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send the IM to the recipient. The item is already
|
// Send the IM to the recipient. The item is already
|
||||||
|
@ -454,70 +447,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// public bool NeedSceneCacheClear(UUID agentID, Scene scene)
|
|
||||||
// {
|
|
||||||
// if (!m_AgentRegions.ContainsKey(agentID))
|
|
||||||
// {
|
|
||||||
// // Since we can get here two ways, we need to scan
|
|
||||||
// // the scenes here. This is somewhat more expensive
|
|
||||||
// // but helps avoid a nasty bug
|
|
||||||
// //
|
|
||||||
//
|
|
||||||
// foreach (Scene s in m_Scenelist)
|
|
||||||
// {
|
|
||||||
// ScenePresence presence;
|
|
||||||
//
|
|
||||||
// if (s.TryGetScenePresence(agentID, out presence))
|
|
||||||
// {
|
|
||||||
// // If the agent is in this scene, then we
|
|
||||||
// // are being called twice in a single
|
|
||||||
// // teleport. This is wasteful of cycles
|
|
||||||
// // but harmless due to this 2nd level check
|
|
||||||
// //
|
|
||||||
// // If the agent is found in another scene
|
|
||||||
// // then the list wasn't current
|
|
||||||
// //
|
|
||||||
// // If the agent is totally unknown, then what
|
|
||||||
// // are we even doing here??
|
|
||||||
// //
|
|
||||||
// if (s == scene)
|
|
||||||
// {
|
|
||||||
// //m_log.Debug("[INVTRANSFERMOD]: s == scene. Returning true in " + scene.RegionInfo.RegionName);
|
|
||||||
// return true;
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// //m_log.Debug("[INVTRANSFERMOD]: s != scene. Returning false in " + scene.RegionInfo.RegionName);
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// //m_log.Debug("[INVTRANSFERMOD]: agent not in scene. Returning true in " + scene.RegionInfo.RegionName);
|
|
||||||
// return true;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // The agent is left in current Scene, so we must be
|
|
||||||
// // going to another instance
|
|
||||||
// //
|
|
||||||
// if (m_AgentRegions[agentID] == scene)
|
|
||||||
// {
|
|
||||||
// //m_log.Debug("[INVTRANSFERMOD]: m_AgentRegions[agentID] == scene. Returning true in " + scene.RegionInfo.RegionName);
|
|
||||||
// m_AgentRegions.Remove(agentID);
|
|
||||||
// return true;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // Another region has claimed the agent
|
|
||||||
// //
|
|
||||||
// //m_log.Debug("[INVTRANSFERMOD]: last resort. Returning false in " + scene.RegionInfo.RegionName);
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public void ClientLoggedOut(UUID agentID, Scene scene)
|
|
||||||
// {
|
|
||||||
// if (m_AgentRegions.ContainsKey(agentID))
|
|
||||||
// m_AgentRegions.Remove(agentID);
|
|
||||||
// }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -0,0 +1,256 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Contributors, http://opensimulator.org/
|
||||||
|
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the OpenSimulator Project nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using log4net.Config;
|
||||||
|
using Nini.Config;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using OpenMetaverse;
|
||||||
|
using OpenMetaverse.Assets;
|
||||||
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Region.CoreModules.Avatar.Inventory.Transfer;
|
||||||
|
using OpenSim.Region.Framework.Interfaces;
|
||||||
|
using OpenSim.Region.Framework.Scenes;
|
||||||
|
using OpenSim.Services.Interfaces;
|
||||||
|
using OpenSim.Tests.Common;
|
||||||
|
using OpenSim.Tests.Common.Mock;
|
||||||
|
|
||||||
|
namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer.Tests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class InventoryTransferModuleTests : OpenSimTestCase
|
||||||
|
{
|
||||||
|
protected TestScene m_scene;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public override void SetUp()
|
||||||
|
{
|
||||||
|
base.SetUp();
|
||||||
|
|
||||||
|
IConfigSource config = new IniConfigSource();
|
||||||
|
config.AddConfig("Messaging");
|
||||||
|
config.Configs["Messaging"].Set("InventoryTransferModule", "InventoryTransferModule");
|
||||||
|
|
||||||
|
m_scene = new SceneHelpers().SetupScene();
|
||||||
|
SceneHelpers.SetupSceneModules(m_scene, config, new InventoryTransferModule());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestAcceptGivenItem()
|
||||||
|
{
|
||||||
|
// TestHelpers.EnableLogging();
|
||||||
|
|
||||||
|
UUID initialSessionId = TestHelpers.ParseTail(0x10);
|
||||||
|
UUID itemId = TestHelpers.ParseTail(0x100);
|
||||||
|
UUID assetId = TestHelpers.ParseTail(0x200);
|
||||||
|
|
||||||
|
UserAccount ua1
|
||||||
|
= UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "One", TestHelpers.ParseTail(0x1), "pw");
|
||||||
|
UserAccount ua2
|
||||||
|
= UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "Two", TestHelpers.ParseTail(0x2), "pw");
|
||||||
|
|
||||||
|
ScenePresence giverSp = SceneHelpers.AddScenePresence(m_scene, ua1);
|
||||||
|
TestClient giverClient = (TestClient)giverSp.ControllingClient;
|
||||||
|
|
||||||
|
ScenePresence receiverSp = SceneHelpers.AddScenePresence(m_scene, ua2);
|
||||||
|
TestClient receiverClient = (TestClient)receiverSp.ControllingClient;
|
||||||
|
|
||||||
|
// Create the object to test give
|
||||||
|
InventoryItemBase originalItem
|
||||||
|
= UserInventoryHelpers.CreateInventoryItem(
|
||||||
|
m_scene, "givenObj", itemId, assetId, giverSp.UUID, InventoryType.Object);
|
||||||
|
|
||||||
|
byte[] giveImBinaryBucket = new byte[17];
|
||||||
|
byte[] itemIdBytes = itemId.GetBytes();
|
||||||
|
Array.Copy(itemIdBytes, 0, giveImBinaryBucket, 1, itemIdBytes.Length);
|
||||||
|
|
||||||
|
GridInstantMessage giveIm
|
||||||
|
= new GridInstantMessage(
|
||||||
|
m_scene,
|
||||||
|
giverSp.UUID,
|
||||||
|
giverSp.Name,
|
||||||
|
receiverSp.UUID,
|
||||||
|
(byte)InstantMessageDialog.InventoryOffered,
|
||||||
|
false,
|
||||||
|
"inventory offered msg",
|
||||||
|
initialSessionId,
|
||||||
|
false,
|
||||||
|
Vector3.Zero,
|
||||||
|
giveImBinaryBucket,
|
||||||
|
true);
|
||||||
|
|
||||||
|
giverClient.HandleImprovedInstantMessage(giveIm);
|
||||||
|
|
||||||
|
// These details might not all be correct.
|
||||||
|
GridInstantMessage acceptIm
|
||||||
|
= new GridInstantMessage(
|
||||||
|
m_scene,
|
||||||
|
receiverSp.UUID,
|
||||||
|
receiverSp.Name,
|
||||||
|
giverSp.UUID,
|
||||||
|
(byte)InstantMessageDialog.InventoryAccepted,
|
||||||
|
false,
|
||||||
|
"inventory accepted msg",
|
||||||
|
initialSessionId,
|
||||||
|
false,
|
||||||
|
Vector3.Zero,
|
||||||
|
null,
|
||||||
|
true);
|
||||||
|
|
||||||
|
receiverClient.HandleImprovedInstantMessage(acceptIm);
|
||||||
|
|
||||||
|
// Test for item remaining in the giver's inventory (here we assume a copy item)
|
||||||
|
// TODO: Test no-copy items.
|
||||||
|
InventoryItemBase originalItemAfterGive
|
||||||
|
= UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, giverSp.UUID, "Objects/givenObj");
|
||||||
|
|
||||||
|
Assert.That(originalItemAfterGive, Is.Not.Null);
|
||||||
|
Assert.That(originalItemAfterGive.ID, Is.EqualTo(originalItem.ID));
|
||||||
|
|
||||||
|
// Test for item successfully making it into the receiver's inventory
|
||||||
|
InventoryItemBase receivedItem
|
||||||
|
= UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, receiverSp.UUID, "Objects/givenObj");
|
||||||
|
|
||||||
|
Assert.That(receivedItem, Is.Not.Null);
|
||||||
|
Assert.That(receivedItem.ID, Is.Not.EqualTo(originalItem.ID));
|
||||||
|
|
||||||
|
// Test that on a delete, item still exists and is accessible for the giver.
|
||||||
|
m_scene.InventoryService.DeleteItems(receiverSp.UUID, new List<UUID>() { receivedItem.ID });
|
||||||
|
|
||||||
|
InventoryItemBase originalItemAfterDelete
|
||||||
|
= UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, giverSp.UUID, "Objects/givenObj");
|
||||||
|
|
||||||
|
Assert.That(originalItemAfterDelete, Is.Not.Null);
|
||||||
|
|
||||||
|
// TODO: Test scenario where giver deletes their item first.
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test user rejection of a given item.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// A rejected item still ends up in the user's trash folder.
|
||||||
|
/// </remarks>
|
||||||
|
[Test]
|
||||||
|
public void TestRejectGivenItem()
|
||||||
|
{
|
||||||
|
// TestHelpers.EnableLogging();
|
||||||
|
|
||||||
|
UUID initialSessionId = TestHelpers.ParseTail(0x10);
|
||||||
|
UUID itemId = TestHelpers.ParseTail(0x100);
|
||||||
|
UUID assetId = TestHelpers.ParseTail(0x200);
|
||||||
|
|
||||||
|
UserAccount ua1
|
||||||
|
= UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "One", TestHelpers.ParseTail(0x1), "pw");
|
||||||
|
UserAccount ua2
|
||||||
|
= UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "Two", TestHelpers.ParseTail(0x2), "pw");
|
||||||
|
|
||||||
|
ScenePresence giverSp = SceneHelpers.AddScenePresence(m_scene, ua1);
|
||||||
|
TestClient giverClient = (TestClient)giverSp.ControllingClient;
|
||||||
|
|
||||||
|
ScenePresence receiverSp = SceneHelpers.AddScenePresence(m_scene, ua2);
|
||||||
|
TestClient receiverClient = (TestClient)receiverSp.ControllingClient;
|
||||||
|
|
||||||
|
// Create the object to test give
|
||||||
|
InventoryItemBase originalItem
|
||||||
|
= UserInventoryHelpers.CreateInventoryItem(
|
||||||
|
m_scene, "givenObj", itemId, assetId, giverSp.UUID, InventoryType.Object);
|
||||||
|
|
||||||
|
GridInstantMessage receivedIm = null;
|
||||||
|
receiverClient.OnReceivedInstantMessage += im => receivedIm = im;
|
||||||
|
|
||||||
|
byte[] giveImBinaryBucket = new byte[17];
|
||||||
|
byte[] itemIdBytes = itemId.GetBytes();
|
||||||
|
Array.Copy(itemIdBytes, 0, giveImBinaryBucket, 1, itemIdBytes.Length);
|
||||||
|
|
||||||
|
GridInstantMessage giveIm
|
||||||
|
= new GridInstantMessage(
|
||||||
|
m_scene,
|
||||||
|
giverSp.UUID,
|
||||||
|
giverSp.Name,
|
||||||
|
receiverSp.UUID,
|
||||||
|
(byte)InstantMessageDialog.InventoryOffered,
|
||||||
|
false,
|
||||||
|
"inventory offered msg",
|
||||||
|
initialSessionId,
|
||||||
|
false,
|
||||||
|
Vector3.Zero,
|
||||||
|
giveImBinaryBucket,
|
||||||
|
true);
|
||||||
|
|
||||||
|
giverClient.HandleImprovedInstantMessage(giveIm);
|
||||||
|
|
||||||
|
// These details might not all be correct.
|
||||||
|
// Session ID is now the created item ID (!)
|
||||||
|
GridInstantMessage rejectIm
|
||||||
|
= new GridInstantMessage(
|
||||||
|
m_scene,
|
||||||
|
receiverSp.UUID,
|
||||||
|
receiverSp.Name,
|
||||||
|
giverSp.UUID,
|
||||||
|
(byte)InstantMessageDialog.InventoryDeclined,
|
||||||
|
false,
|
||||||
|
"inventory declined msg",
|
||||||
|
new UUID(receivedIm.imSessionID),
|
||||||
|
false,
|
||||||
|
Vector3.Zero,
|
||||||
|
null,
|
||||||
|
true);
|
||||||
|
|
||||||
|
receiverClient.HandleImprovedInstantMessage(rejectIm);
|
||||||
|
|
||||||
|
// Test for item remaining in the giver's inventory (here we assume a copy item)
|
||||||
|
// TODO: Test no-copy items.
|
||||||
|
InventoryItemBase originalItemAfterGive
|
||||||
|
= UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, giverSp.UUID, "Objects/givenObj");
|
||||||
|
|
||||||
|
Assert.That(originalItemAfterGive, Is.Not.Null);
|
||||||
|
Assert.That(originalItemAfterGive.ID, Is.EqualTo(originalItem.ID));
|
||||||
|
|
||||||
|
// Test for item successfully making it into the receiver's inventory
|
||||||
|
InventoryItemBase receivedItem
|
||||||
|
= UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, receiverSp.UUID, "Trash/givenObj");
|
||||||
|
|
||||||
|
InventoryFolderBase trashFolder
|
||||||
|
= m_scene.InventoryService.GetFolderForType(receiverSp.UUID, AssetType.TrashFolder);
|
||||||
|
|
||||||
|
Assert.That(receivedItem, Is.Not.Null);
|
||||||
|
Assert.That(receivedItem.ID, Is.Not.EqualTo(originalItem.ID));
|
||||||
|
Assert.That(receivedItem.Folder, Is.EqualTo(trashFolder.ID));
|
||||||
|
|
||||||
|
// Test that on a delete, item still exists and is accessible for the giver.
|
||||||
|
m_scene.InventoryService.PurgeFolder(trashFolder);
|
||||||
|
|
||||||
|
InventoryItemBase originalItemAfterDelete
|
||||||
|
= UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, giverSp.UUID, "Objects/givenObj");
|
||||||
|
|
||||||
|
Assert.That(originalItemAfterDelete, Is.Not.Null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -212,11 +212,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
protected override GridRegion GetFinalDestination(GridRegion region)
|
protected override GridRegion GetFinalDestination(GridRegion region)
|
||||||
{
|
{
|
||||||
int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, region.RegionID);
|
int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, region.RegionID);
|
||||||
m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: region {0} flags: {1}", region.RegionID, flags);
|
m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: region {0} flags: {1}", region.RegionName, flags);
|
||||||
|
|
||||||
if ((flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0)
|
if ((flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0)
|
||||||
{
|
{
|
||||||
m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Destination region {0} is hyperlink", region.RegionID);
|
m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Destination region is hyperlink");
|
||||||
GridRegion real_destination = m_GatekeeperConnector.GetHyperlinkRegion(region, region.RegionID);
|
GridRegion real_destination = m_GatekeeperConnector.GetHyperlinkRegion(region, region.RegionID);
|
||||||
if (real_destination != null)
|
if (real_destination != null)
|
||||||
m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: GetFinalDestination serveruri -> {0}", real_destination.ServerURI);
|
m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: GetFinalDestination serveruri -> {0}", real_destination.ServerURI);
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using OpenSim.Region.Framework.Interfaces;
|
using OpenSim.Region.Framework.Interfaces;
|
||||||
|
using OpenMetaverse;
|
||||||
|
|
||||||
namespace OpenSim.Region.CoreModules.Framework.InterfaceCommander
|
namespace OpenSim.Region.CoreModules.Framework.InterfaceCommander
|
||||||
{
|
{
|
||||||
|
@ -152,6 +153,9 @@ namespace OpenSim.Region.CoreModules.Framework.InterfaceCommander
|
||||||
case "Boolean":
|
case "Boolean":
|
||||||
m_args[i].ArgumentValue = Boolean.Parse(arg.ToString());
|
m_args[i].ArgumentValue = Boolean.Parse(arg.ToString());
|
||||||
break;
|
break;
|
||||||
|
case "UUID":
|
||||||
|
m_args[i].ArgumentValue = UUID.Parse(arg.ToString());
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
Console.WriteLine("ERROR: Unknown desired type for argument " + m_args[i].Name + " on command " + m_name);
|
Console.WriteLine("ERROR: Unknown desired type for argument " + m_args[i].Name + " on command " + m_name);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -346,7 +346,15 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
|
||||||
InventoryFolderBase root = m_Scene.InventoryService.GetRootFolder(client.AgentId);
|
InventoryFolderBase root = m_Scene.InventoryService.GetRootFolder(client.AgentId);
|
||||||
InventoryCollection content = m_Scene.InventoryService.GetFolderContent(client.AgentId, root.ID);
|
InventoryCollection content = m_Scene.InventoryService.GetFolderContent(client.AgentId, root.ID);
|
||||||
|
|
||||||
inv.SendBulkUpdateInventory(content.Folders.ToArray(), content.Items.ToArray());
|
List<InventoryFolderBase> keep = new List<InventoryFolderBase>();
|
||||||
|
|
||||||
|
foreach (InventoryFolderBase f in content.Folders)
|
||||||
|
{
|
||||||
|
if (f.Name != "My Suitcase" && f.Name != "Current Outfit")
|
||||||
|
keep.Add(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
inv.SendBulkUpdateInventory(keep.ToArray(), content.Items.ToArray());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -379,7 +387,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
|
||||||
|
|
||||||
foreach (InventoryFolderBase f in content.Folders)
|
foreach (InventoryFolderBase f in content.Folders)
|
||||||
{
|
{
|
||||||
if (f.Name != "My Suitcase")
|
if (f.Name != "My Suitcase" && f.Name != "Current Outfit")
|
||||||
{
|
{
|
||||||
f.Name = f.Name + " (Unavailable)";
|
f.Name = f.Name + " (Unavailable)";
|
||||||
keep.Add(f);
|
keep.Add(f);
|
||||||
|
|
|
@ -187,6 +187,45 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
|
||||||
case (int)HttpRequestConstants.HTTP_VERIFY_CERT:
|
case (int)HttpRequestConstants.HTTP_VERIFY_CERT:
|
||||||
htc.HttpVerifyCert = (int.Parse(parms[i + 1]) != 0);
|
htc.HttpVerifyCert = (int.Parse(parms[i + 1]) != 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case (int)HttpRequestConstants.HTTP_VERBOSE_THROTTLE:
|
||||||
|
|
||||||
|
// TODO implement me
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (int)HttpRequestConstants.HTTP_CUSTOM_HEADER:
|
||||||
|
//Parameters are in pairs and custom header takes
|
||||||
|
//arguments in pairs so adjust for header marker.
|
||||||
|
++i;
|
||||||
|
|
||||||
|
//Maximum of 8 headers are allowed based on the
|
||||||
|
//Second Life documentation for llHTTPRequest.
|
||||||
|
for (int count = 1; count <= 8; ++count)
|
||||||
|
{
|
||||||
|
//Not enough parameters remaining for a header?
|
||||||
|
if (parms.Length - i < 2)
|
||||||
|
break;
|
||||||
|
|
||||||
|
//Have we reached the end of the list of headers?
|
||||||
|
//End is marked by a string with a single digit.
|
||||||
|
//We already know we have at least one parameter
|
||||||
|
//so it is safe to do this check at top of loop.
|
||||||
|
if (Char.IsDigit(parms[i][0]))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (htc.HttpCustomHeaders == null)
|
||||||
|
htc.HttpCustomHeaders = new List<string>();
|
||||||
|
|
||||||
|
htc.HttpCustomHeaders.Add(parms[i]);
|
||||||
|
htc.HttpCustomHeaders.Add(parms[i+1]);
|
||||||
|
|
||||||
|
i += 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (int)HttpRequestConstants.HTTP_PRAGMA_NO_CACHE:
|
||||||
|
htc.HttpPragmaNoCache = (int.Parse(parms[i + 1]) != 0);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -328,9 +367,12 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
|
||||||
// public const int HTTP_METHOD = 0;
|
// public const int HTTP_METHOD = 0;
|
||||||
// public const int HTTP_MIMETYPE = 1;
|
// public const int HTTP_MIMETYPE = 1;
|
||||||
// public const int HTTP_VERIFY_CERT = 3;
|
// public const int HTTP_VERIFY_CERT = 3;
|
||||||
|
// public const int HTTP_VERBOSE_THROTTLE = 4;
|
||||||
|
// public const int HTTP_CUSTOM_HEADER = 5;
|
||||||
|
// public const int HTTP_PRAGMA_NO_CACHE = 6;
|
||||||
private bool _finished;
|
private bool _finished;
|
||||||
public bool Finished
|
public bool Finished
|
||||||
{
|
{
|
||||||
get { return _finished; }
|
get { return _finished; }
|
||||||
}
|
}
|
||||||
// public int HttpBodyMaxLen = 2048; // not implemented
|
// public int HttpBodyMaxLen = 2048; // not implemented
|
||||||
|
@ -340,11 +382,14 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
|
||||||
public string HttpMIMEType = "text/plain;charset=utf-8";
|
public string HttpMIMEType = "text/plain;charset=utf-8";
|
||||||
public int HttpTimeout;
|
public int HttpTimeout;
|
||||||
public bool HttpVerifyCert = true;
|
public bool HttpVerifyCert = true;
|
||||||
|
//public bool HttpVerboseThrottle = true; // not implemented
|
||||||
|
public List<string> HttpCustomHeaders = null;
|
||||||
|
public bool HttpPragmaNoCache = true;
|
||||||
private Thread httpThread;
|
private Thread httpThread;
|
||||||
|
|
||||||
// Request info
|
// Request info
|
||||||
private UUID _itemID;
|
private UUID _itemID;
|
||||||
public UUID ItemID
|
public UUID ItemID
|
||||||
{
|
{
|
||||||
get { return _itemID; }
|
get { return _itemID; }
|
||||||
set { _itemID = value; }
|
set { _itemID = value; }
|
||||||
|
@ -360,7 +405,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
|
||||||
public string proxyexcepts;
|
public string proxyexcepts;
|
||||||
public string OutboundBody;
|
public string OutboundBody;
|
||||||
private UUID _reqID;
|
private UUID _reqID;
|
||||||
public UUID ReqID
|
public UUID ReqID
|
||||||
{
|
{
|
||||||
get { return _reqID; }
|
get { return _reqID; }
|
||||||
set { _reqID = value; }
|
set { _reqID = value; }
|
||||||
|
@ -401,7 +446,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
|
||||||
Request.Method = HttpMethod;
|
Request.Method = HttpMethod;
|
||||||
Request.ContentType = HttpMIMEType;
|
Request.ContentType = HttpMIMEType;
|
||||||
|
|
||||||
if(!HttpVerifyCert)
|
if (!HttpVerifyCert)
|
||||||
{
|
{
|
||||||
// We could hijack Connection Group Name to identify
|
// We could hijack Connection Group Name to identify
|
||||||
// a desired security exception. But at the moment we'll use a dummy header instead.
|
// a desired security exception. But at the moment we'll use a dummy header instead.
|
||||||
|
@ -412,14 +457,24 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
|
||||||
// {
|
// {
|
||||||
// Request.ConnectionGroupName="Verify";
|
// Request.ConnectionGroupName="Verify";
|
||||||
// }
|
// }
|
||||||
if (proxyurl != null && proxyurl.Length > 0)
|
if (!HttpPragmaNoCache)
|
||||||
{
|
{
|
||||||
if (proxyexcepts != null && proxyexcepts.Length > 0)
|
Request.Headers.Add("Pragma", "no-cache");
|
||||||
|
}
|
||||||
|
if (HttpCustomHeaders != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < HttpCustomHeaders.Count; i += 2)
|
||||||
|
Request.Headers.Add(HttpCustomHeaders[i],
|
||||||
|
HttpCustomHeaders[i+1]);
|
||||||
|
}
|
||||||
|
if (proxyurl != null && proxyurl.Length > 0)
|
||||||
|
{
|
||||||
|
if (proxyexcepts != null && proxyexcepts.Length > 0)
|
||||||
{
|
{
|
||||||
string[] elist = proxyexcepts.Split(';');
|
string[] elist = proxyexcepts.Split(';');
|
||||||
Request.Proxy = new WebProxy(proxyurl, true, elist);
|
Request.Proxy = new WebProxy(proxyurl, true, elist);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Request.Proxy = new WebProxy(proxyurl, true);
|
Request.Proxy = new WebProxy(proxyurl, true);
|
||||||
}
|
}
|
||||||
|
@ -432,7 +487,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
|
||||||
Request.Headers[entry.Key] = entry.Value;
|
Request.Headers[entry.Key] = entry.Value;
|
||||||
|
|
||||||
// Encode outbound data
|
// Encode outbound data
|
||||||
if (OutboundBody.Length > 0)
|
if (OutboundBody.Length > 0)
|
||||||
{
|
{
|
||||||
byte[] data = Util.UTF8.GetBytes(OutboundBody);
|
byte[] data = Util.UTF8.GetBytes(OutboundBody);
|
||||||
|
|
||||||
|
|
|
@ -152,7 +152,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests
|
||||||
TestHelpers.InMethod();
|
TestHelpers.InMethod();
|
||||||
|
|
||||||
string dtText
|
string dtText
|
||||||
= "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World; Image http://localhost/shouldnotexist.png";
|
= "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World; Image http://0.0.0.0/shouldnotexist.png";
|
||||||
|
|
||||||
SetupScene(false);
|
SetupScene(false);
|
||||||
SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
|
SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
|
||||||
|
@ -307,7 +307,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests
|
||||||
TestHelpers.InMethod();
|
TestHelpers.InMethod();
|
||||||
|
|
||||||
string dtText
|
string dtText
|
||||||
= "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World; Image http://localhost/shouldnotexist.png";
|
= "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World; Image http://0.0.0.0/shouldnotexist.png";
|
||||||
|
|
||||||
SetupScene(true);
|
SetupScene(true);
|
||||||
SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
|
SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
|
||||||
|
|
|
@ -117,7 +117,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
|
||||||
|
|
||||||
m_module.Scene.RegionInfo.RegionSettings.Save();
|
m_module.Scene.RegionInfo.RegionSettings.Save();
|
||||||
m_module.TriggerRegionInfoChange();
|
m_module.TriggerRegionInfoChange();
|
||||||
m_module.sendRegionInfoPacketToAll();
|
m_module.sendRegionHandshakeToAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -753,13 +753,18 @@ namespace OpenSim.Region.CoreModules.World.Estate
|
||||||
Scene.RegionInfo.RegionSettings.Save();
|
Scene.RegionInfo.RegionSettings.Save();
|
||||||
TriggerRegionInfoChange();
|
TriggerRegionInfoChange();
|
||||||
|
|
||||||
Scene.SetSceneCoreDebug(
|
ISceneCommandsModule scm = Scene.RequestModuleInterface<ISceneCommandsModule>();
|
||||||
new Dictionary<string, string>() {
|
|
||||||
{ "scripting", (!disableScripts).ToString() },
|
if (scm != null)
|
||||||
{ "collisions", (!disableCollisions).ToString() },
|
{
|
||||||
{ "physics", (!disablePhysics).ToString() }
|
scm.SetSceneDebugOptions(
|
||||||
}
|
new Dictionary<string, string>() {
|
||||||
);
|
{ "scripting", (!disableScripts).ToString() },
|
||||||
|
{ "collisions", (!disableCollisions).ToString() },
|
||||||
|
{ "physics", (!disablePhysics).ToString() }
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleEstateTeleportOneUserHomeRequest(IClientAPI remover_client, UUID invoice, UUID senderID, UUID prey)
|
private void handleEstateTeleportOneUserHomeRequest(IClientAPI remover_client, UUID invoice, UUID senderID, UUID prey)
|
||||||
|
|
|
@ -133,6 +133,7 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||||
m_scene.EventManager.OnValidateLandBuy += EventManagerOnValidateLandBuy;
|
m_scene.EventManager.OnValidateLandBuy += EventManagerOnValidateLandBuy;
|
||||||
m_scene.EventManager.OnLandBuy += EventManagerOnLandBuy;
|
m_scene.EventManager.OnLandBuy += EventManagerOnLandBuy;
|
||||||
m_scene.EventManager.OnNewClient += EventManagerOnNewClient;
|
m_scene.EventManager.OnNewClient += EventManagerOnNewClient;
|
||||||
|
m_scene.EventManager.OnMakeChildAgent += EventMakeChildAgent;
|
||||||
m_scene.EventManager.OnSignificantClientMovement += EventManagerOnSignificantClientMovement;
|
m_scene.EventManager.OnSignificantClientMovement += EventManagerOnSignificantClientMovement;
|
||||||
m_scene.EventManager.OnNoticeNoLandDataFromStorage += EventManagerOnNoLandDataFromStorage;
|
m_scene.EventManager.OnNoticeNoLandDataFromStorage += EventManagerOnNoLandDataFromStorage;
|
||||||
m_scene.EventManager.OnIncomingLandDataFromStorage += EventManagerOnIncomingLandDataFromStorage;
|
m_scene.EventManager.OnIncomingLandDataFromStorage += EventManagerOnIncomingLandDataFromStorage;
|
||||||
|
@ -218,6 +219,11 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void EventMakeChildAgent(ScenePresence avatar)
|
||||||
|
{
|
||||||
|
avatar.currentParcelUUID = UUID.Zero;
|
||||||
|
}
|
||||||
|
|
||||||
void ClientOnPreAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData)
|
void ClientOnPreAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData)
|
||||||
{
|
{
|
||||||
//If we are forcing a position for them to go
|
//If we are forcing a position for them to go
|
||||||
|
@ -1395,15 +1401,65 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||||
|
|
||||||
public void ReturnObjectsInParcel(int localID, uint returnType, UUID[] agentIDs, UUID[] taskIDs, IClientAPI remoteClient)
|
public void ReturnObjectsInParcel(int localID, uint returnType, UUID[] agentIDs, UUID[] taskIDs, IClientAPI remoteClient)
|
||||||
{
|
{
|
||||||
ILandObject selectedParcel = null;
|
if (localID != -1)
|
||||||
lock (m_landList)
|
|
||||||
{
|
{
|
||||||
m_landList.TryGetValue(localID, out selectedParcel);
|
ILandObject selectedParcel = null;
|
||||||
|
lock (m_landList)
|
||||||
|
{
|
||||||
|
m_landList.TryGetValue(localID, out selectedParcel);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedParcel == null) return;
|
||||||
|
|
||||||
|
selectedParcel.ReturnLandObjects(returnType, agentIDs, taskIDs, remoteClient);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (returnType != 1)
|
||||||
|
{
|
||||||
|
m_log.WarnFormat("[LAND MANAGEMENT MODULE] ReturnObjectsInParcel: unknown return type {0}", returnType);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (selectedParcel == null) return;
|
// We get here when the user returns objects from the list of Top Colliders or Top Scripts.
|
||||||
|
// In that case we receive specific object UUID's, but no parcel ID.
|
||||||
|
|
||||||
selectedParcel.ReturnLandObjects(returnType, agentIDs, taskIDs, remoteClient);
|
Dictionary<UUID, HashSet<SceneObjectGroup>> returns = new Dictionary<UUID, HashSet<SceneObjectGroup>>();
|
||||||
|
|
||||||
|
foreach (UUID groupID in taskIDs)
|
||||||
|
{
|
||||||
|
SceneObjectGroup obj = m_scene.GetSceneObjectGroup(groupID);
|
||||||
|
if (obj != null)
|
||||||
|
{
|
||||||
|
if (!returns.ContainsKey(obj.OwnerID))
|
||||||
|
returns[obj.OwnerID] = new HashSet<SceneObjectGroup>();
|
||||||
|
returns[obj.OwnerID].Add(obj);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_log.WarnFormat("[LAND MANAGEMENT MODULE] ReturnObjectsInParcel: unknown object {0}", groupID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int num = 0;
|
||||||
|
foreach (HashSet<SceneObjectGroup> objs in returns.Values)
|
||||||
|
num += objs.Count;
|
||||||
|
m_log.DebugFormat("[LAND MANAGEMENT MODULE] Returning {0} specific object(s)", num);
|
||||||
|
|
||||||
|
foreach (HashSet<SceneObjectGroup> objs in returns.Values)
|
||||||
|
{
|
||||||
|
List<SceneObjectGroup> objs2 = new List<SceneObjectGroup>(objs);
|
||||||
|
if (m_scene.Permissions.CanReturnObjects(null, remoteClient.AgentId, objs2))
|
||||||
|
{
|
||||||
|
m_scene.returnObjects(objs2.ToArray(), remoteClient.AgentId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_log.WarnFormat("[LAND MANAGEMENT MODULE] ReturnObjectsInParcel: not permitted to return {0} object(s) belonging to user {1}",
|
||||||
|
objs2.Count, objs2[0].OwnerID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void EventManagerOnNoLandDataFromStorage()
|
public void EventManagerOnNoLandDataFromStorage()
|
||||||
|
|
|
@ -592,11 +592,11 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
|
||||||
cdl.AddRow(
|
cdl.AddRow(
|
||||||
"LightColor",
|
"LightColor",
|
||||||
string.Format("<{0},{1},{2},{3}>", s.LightColorR, s.LightColorB, s.LightColorG, s.LightColorA));
|
string.Format("<{0},{1},{2},{3}>", s.LightColorR, s.LightColorB, s.LightColorG, s.LightColorA));
|
||||||
cdl.AddRow("FlexiDrag", s.LightCutoff);
|
cdl.AddRow("LightCutoff", s.LightCutoff);
|
||||||
cdl.AddRow("FlexiDrag", s.LightEntry);
|
cdl.AddRow("LightEntry", s.LightEntry);
|
||||||
cdl.AddRow("FlexiDrag", s.LightFalloff);
|
cdl.AddRow("LightFalloff", s.LightFalloff);
|
||||||
cdl.AddRow("FlexiDrag", s.LightIntensity);
|
cdl.AddRow("LightIntensity", s.LightIntensity);
|
||||||
cdl.AddRow("FlexiDrag", s.LightRadius);
|
cdl.AddRow("LightRadius", s.LightRadius);
|
||||||
cdl.AddRow("Media", string.Format("{0} entries", s.Media != null ? s.Media.Count.ToString() : "n/a"));
|
cdl.AddRow("Media", string.Format("{0} entries", s.Media != null ? s.Media.Count.ToString() : "n/a"));
|
||||||
cdl.AddRow("PathBegin", s.PathBegin);
|
cdl.AddRow("PathBegin", s.PathBegin);
|
||||||
cdl.AddRow("PathEnd", s.PathEnd);
|
cdl.AddRow("PathEnd", s.PathEnd);
|
||||||
|
|
|
@ -480,7 +480,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_plugineffects[pluginName] = effect;
|
m_plugineffects[pluginName] = effect;
|
||||||
m_log.Warn("E ... " + pluginName + " (Replaced)");
|
m_log.Info("E ... " + pluginName + " (Replaced)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,8 +140,6 @@ namespace OpenSim.Region.DataSnapshot
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_enabled)
|
|
||||||
m_snapStore = new SnapshotStore(m_snapsDir, m_gridinfo, m_listener_port, m_hostname);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -155,8 +153,22 @@ namespace OpenSim.Region.DataSnapshot
|
||||||
|
|
||||||
m_log.DebugFormat("[DATASNAPSHOT]: Module added to Scene {0}.", scene.RegionInfo.RegionName);
|
m_log.DebugFormat("[DATASNAPSHOT]: Module added to Scene {0}.", scene.RegionInfo.RegionName);
|
||||||
|
|
||||||
m_snapStore.AddScene(scene);
|
if (!m_servicesNotified)
|
||||||
|
{
|
||||||
|
m_hostname = scene.RegionInfo.ExternalHostName;
|
||||||
|
m_snapStore = new SnapshotStore(m_snapsDir, m_gridinfo, m_listener_port, m_hostname);
|
||||||
|
|
||||||
|
//Hand it the first scene, assuming that all scenes have the same BaseHTTPServer
|
||||||
|
new DataRequestHandler(scene, this);
|
||||||
|
|
||||||
|
if (m_dataServices != "" && m_dataServices != "noservices")
|
||||||
|
NotifyDataServices(m_dataServices, "online");
|
||||||
|
|
||||||
|
m_servicesNotified = true;
|
||||||
|
}
|
||||||
|
|
||||||
m_scenes.Add(scene);
|
m_scenes.Add(scene);
|
||||||
|
m_snapStore.AddScene(scene);
|
||||||
|
|
||||||
Assembly currentasm = Assembly.GetExecutingAssembly();
|
Assembly currentasm = Assembly.GetExecutingAssembly();
|
||||||
|
|
||||||
|
@ -181,22 +193,6 @@ namespace OpenSim.Region.DataSnapshot
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must be done here because on shared modules, PostInitialise() will run
|
|
||||||
// BEFORE any scenes are registered. There is no "all scenes have been loaded"
|
|
||||||
// kind of callback because scenes may be created dynamically, so we cannot
|
|
||||||
// have that info, ever.
|
|
||||||
if (!m_servicesNotified)
|
|
||||||
{
|
|
||||||
//Hand it the first scene, assuming that all scenes have the same BaseHTTPServer
|
|
||||||
new DataRequestHandler(m_scenes[0], this);
|
|
||||||
|
|
||||||
m_hostname = m_scenes[0].RegionInfo.ExternalHostName;
|
|
||||||
|
|
||||||
if (m_dataServices != "" && m_dataServices != "noservices")
|
|
||||||
NotifyDataServices(m_dataServices, "online");
|
|
||||||
|
|
||||||
m_servicesNotified = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveRegion(Scene scene)
|
public void RemoveRegion(Scene scene)
|
||||||
|
|
|
@ -36,6 +36,9 @@ namespace OpenSim.Region.Framework.Interfaces
|
||||||
HTTP_MIMETYPE = 1,
|
HTTP_MIMETYPE = 1,
|
||||||
HTTP_BODY_MAXLENGTH = 2,
|
HTTP_BODY_MAXLENGTH = 2,
|
||||||
HTTP_VERIFY_CERT = 3,
|
HTTP_VERIFY_CERT = 3,
|
||||||
|
HTTP_VERBOSE_THROTTLE = 4,
|
||||||
|
HTTP_CUSTOM_HEADER = 5,
|
||||||
|
HTTP_PRAGMA_NO_CACHE = 6
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IHttpRequestModule
|
public interface IHttpRequestModule
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Contributors, http://opensimulator.org/
|
||||||
|
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the OpenSim 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 OpenMetaverse;
|
||||||
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Region.Framework.Scenes;
|
||||||
|
|
||||||
|
namespace OpenSim.Region.Framework.Interfaces
|
||||||
|
{
|
||||||
|
public interface ISceneCommandsModule
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the scene debug options.
|
||||||
|
/// </summary>
|
||||||
|
void SetSceneDebugOptions(Dictionary<string, string> options);
|
||||||
|
}
|
||||||
|
}
|
|
@ -87,13 +87,24 @@ namespace OpenSim.Region.Framework.Scenes.Animation
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Remove(UUID animID)
|
/// <summary>
|
||||||
|
/// Remove the specified animation
|
||||||
|
/// </summary>
|
||||||
|
/// <param name='animID'></param>
|
||||||
|
/// <param name='allowNoDefault'>
|
||||||
|
/// If true, then the default animation can be entirely removed.
|
||||||
|
/// If false, then removing the default animation will reset it to the simulator default (currently STAND).
|
||||||
|
/// </param>
|
||||||
|
public bool Remove(UUID animID, bool allowNoDefault)
|
||||||
{
|
{
|
||||||
lock (m_animations)
|
lock (m_animations)
|
||||||
{
|
{
|
||||||
if (m_defaultAnimation.AnimID == animID)
|
if (m_defaultAnimation.AnimID == animID)
|
||||||
{
|
{
|
||||||
m_defaultAnimation = new OpenSim.Framework.Animation(UUID.Zero, 1, UUID.Zero);
|
if (allowNoDefault)
|
||||||
|
m_defaultAnimation = new OpenSim.Framework.Animation(UUID.Zero, 1, UUID.Zero);
|
||||||
|
else
|
||||||
|
ResetDefaultAnimation();
|
||||||
}
|
}
|
||||||
else if (HasAnimation(animID))
|
else if (HasAnimation(animID))
|
||||||
{
|
{
|
||||||
|
|
|
@ -86,7 +86,10 @@ namespace OpenSim.Region.Framework.Scenes.Animation
|
||||||
if (m_scenePresence.IsChildAgent)
|
if (m_scenePresence.IsChildAgent)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// m_log.DebugFormat("[SCENE PRESENCE ANIMATOR]: Adding animation {0} for {1}", animID, m_scenePresence.Name);
|
if (m_scenePresence.Scene.DebugAnimations)
|
||||||
|
m_log.DebugFormat(
|
||||||
|
"[SCENE PRESENCE ANIMATOR]: Adding animation {0} {1} for {2}",
|
||||||
|
GetAnimName(animID), animID, m_scenePresence.Name);
|
||||||
|
|
||||||
if (m_animations.Add(animID, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, objectID))
|
if (m_animations.Add(animID, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, objectID))
|
||||||
SendAnimPack();
|
SendAnimPack();
|
||||||
|
@ -109,14 +112,25 @@ namespace OpenSim.Region.Framework.Scenes.Animation
|
||||||
AddAnimation(animID, objectID);
|
AddAnimation(animID, objectID);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveAnimation(UUID animID)
|
/// <summary>
|
||||||
|
/// Remove the specified animation
|
||||||
|
/// </summary>
|
||||||
|
/// <param name='animID'></param>
|
||||||
|
/// <param name='allowNoDefault'>
|
||||||
|
/// If true, then the default animation can be entirely removed.
|
||||||
|
/// If false, then removing the default animation will reset it to the simulator default (currently STAND).
|
||||||
|
/// </param>
|
||||||
|
public void RemoveAnimation(UUID animID, bool allowNoDefault)
|
||||||
{
|
{
|
||||||
if (m_scenePresence.IsChildAgent)
|
if (m_scenePresence.IsChildAgent)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// m_log.DebugFormat("[SCENE PRESENCE ANIMATOR]: Removing animation {0} for {1}", animID, m_scenePresence.Name);
|
if (m_scenePresence.Scene.DebugAnimations)
|
||||||
|
m_log.DebugFormat(
|
||||||
|
"[SCENE PRESENCE ANIMATOR]: Removing animation {0} {1} for {2}",
|
||||||
|
GetAnimName(animID), animID, m_scenePresence.Name);
|
||||||
|
|
||||||
if (m_animations.Remove(animID))
|
if (m_animations.Remove(animID, allowNoDefault))
|
||||||
SendAnimPack();
|
SendAnimPack();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,14 +146,15 @@ namespace OpenSim.Region.Framework.Scenes.Animation
|
||||||
if (animID == UUID.Zero)
|
if (animID == UUID.Zero)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
RemoveAnimation(animID);
|
RemoveAnimation(animID, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ResetAnimations()
|
public void ResetAnimations()
|
||||||
{
|
{
|
||||||
// m_log.DebugFormat(
|
if (m_scenePresence.Scene.DebugAnimations)
|
||||||
// "[SCENE PRESENCE ANIMATOR]: Resetting animations for {0} in {1}",
|
m_log.DebugFormat(
|
||||||
// m_scenePresence.Name, m_scenePresence.Scene.RegionInfo.RegionName);
|
"[SCENE PRESENCE ANIMATOR]: Resetting animations for {0} in {1}",
|
||||||
|
m_scenePresence.Name, m_scenePresence.Scene.RegionInfo.RegionName);
|
||||||
|
|
||||||
m_animations.Clear();
|
m_animations.Clear();
|
||||||
}
|
}
|
||||||
|
@ -550,5 +565,21 @@ namespace OpenSim.Region.Framework.Scenes.Animation
|
||||||
|
|
||||||
SendAnimPack(animIDs, sequenceNums, objectIDs);
|
SendAnimPack(animIDs, sequenceNums, objectIDs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string GetAnimName(UUID animId)
|
||||||
|
{
|
||||||
|
string animName;
|
||||||
|
|
||||||
|
if (!DefaultAvatarAnimations.AnimsNames.TryGetValue(animId, out animName))
|
||||||
|
{
|
||||||
|
AssetMetadata amd = m_scenePresence.Scene.AssetService.GetMetadata(animId.ToString());
|
||||||
|
if (amd != null)
|
||||||
|
animName = amd.Name;
|
||||||
|
else
|
||||||
|
animName = "Unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
return animName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -407,16 +407,16 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
if (item.Owner != remoteClient.AgentId)
|
if (item.Owner != remoteClient.AgentId)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (UUID.Zero == transactionID)
|
item.Name = itemUpd.Name;
|
||||||
{
|
item.Description = itemUpd.Description;
|
||||||
item.Name = itemUpd.Name;
|
|
||||||
item.Description = itemUpd.Description;
|
|
||||||
|
|
||||||
// m_log.DebugFormat(
|
// m_log.DebugFormat(
|
||||||
// "[USER INVENTORY]: itemUpd {0} {1} {2} {3}, item {4} {5} {6} {7}",
|
// "[USER INVENTORY]: itemUpd {0} {1} {2} {3}, item {4} {5} {6} {7}",
|
||||||
// itemUpd.NextPermissions, itemUpd.GroupPermissions, itemUpd.EveryOnePermissions, item.Flags,
|
// itemUpd.NextPermissions, itemUpd.GroupPermissions, itemUpd.EveryOnePermissions, item.Flags,
|
||||||
// item.NextPermissions, item.GroupPermissions, item.EveryOnePermissions, item.CurrentPermissions);
|
// item.NextPermissions, item.GroupPermissions, item.EveryOnePermissions, item.CurrentPermissions);
|
||||||
|
|
||||||
|
if (itemUpd.NextPermissions != 0) // Use this to determine validity. Can never be 0 if valid
|
||||||
|
{
|
||||||
if (item.NextPermissions != (itemUpd.NextPermissions & item.BasePermissions))
|
if (item.NextPermissions != (itemUpd.NextPermissions & item.BasePermissions))
|
||||||
item.Flags |= (uint)InventoryItemFlags.ObjectOverwriteNextOwner;
|
item.Flags |= (uint)InventoryItemFlags.ObjectOverwriteNextOwner;
|
||||||
item.NextPermissions = itemUpd.NextPermissions & item.BasePermissions;
|
item.NextPermissions = itemUpd.NextPermissions & item.BasePermissions;
|
||||||
|
@ -451,7 +451,8 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
InventoryService.UpdateItem(item);
|
InventoryService.UpdateItem(item);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (UUID.Zero != transactionID)
|
||||||
{
|
{
|
||||||
if (AgentTransactionsModule != null)
|
if (AgentTransactionsModule != null)
|
||||||
{
|
{
|
||||||
|
@ -1800,8 +1801,11 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
/// Rez a script into a prim's inventory from another prim
|
/// Rez a script into a prim's inventory from another prim
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="remoteClient"></param>
|
/// <param name="remoteClient"></param>
|
||||||
/// <param name="itemID"> </param>
|
/// <param name="srcPart"> </param>
|
||||||
/// <param name="localID"></param>
|
/// <param name="destId"> </param>
|
||||||
|
/// <param name="pin"></param>
|
||||||
|
/// <param name="running"></param>
|
||||||
|
/// <param name="start_param"></param>
|
||||||
public void RezScriptFromPrim(UUID srcId, SceneObjectPart srcPart, UUID destId, int pin, int running, int start_param)
|
public void RezScriptFromPrim(UUID srcId, SceneObjectPart srcPart, UUID destId, int pin, int running, int start_param)
|
||||||
{
|
{
|
||||||
TaskInventoryItem srcTaskItem = srcPart.Inventory.GetInventoryItem(srcId);
|
TaskInventoryItem srcTaskItem = srcPart.Inventory.GetInventoryItem(srcId);
|
||||||
|
@ -1821,12 +1825,11 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
if (destPart == null)
|
if (destPart == null)
|
||||||
{
|
{
|
||||||
m_log.ErrorFormat(
|
m_log.ErrorFormat(
|
||||||
"[PRIM INVENTORY]: " +
|
"[PRIM INVENTORY]: Could not find part {0} to insert script item {1} from {2} {3} in {4}",
|
||||||
"Could not find script for ID {0}",
|
destId, srcId, srcPart.Name, srcPart.UUID, Name);
|
||||||
destId);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must own the object, and have modify rights
|
// Must own the object, and have modify rights
|
||||||
if (srcPart.OwnerID != destPart.OwnerID)
|
if (srcPart.OwnerID != destPart.OwnerID)
|
||||||
{
|
{
|
||||||
|
@ -1834,12 +1837,14 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
if ((destPart.GroupID == UUID.Zero) || (destPart.GroupID != srcPart.GroupID) ||
|
if ((destPart.GroupID == UUID.Zero) || (destPart.GroupID != srcPart.GroupID) ||
|
||||||
((destPart.GroupMask & (uint)PermissionMask.Modify) == 0))
|
((destPart.GroupMask & (uint)PermissionMask.Modify) == 0))
|
||||||
return;
|
return;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if ((destPart.OwnerMask & (uint)PermissionMask.Modify) == 0)
|
if ((destPart.OwnerMask & (uint)PermissionMask.Modify) == 0)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (destPart.ScriptAccessPin != pin)
|
if (destPart.ScriptAccessPin == 0 || destPart.ScriptAccessPin != pin)
|
||||||
{
|
{
|
||||||
m_log.WarnFormat(
|
m_log.WarnFormat(
|
||||||
"[PRIM INVENTORY]: " +
|
"[PRIM INVENTORY]: " +
|
||||||
|
|
|
@ -67,15 +67,85 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
public bool EmergencyMonitoring = false;
|
public bool EmergencyMonitoring = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Show debug information about animations.
|
||||||
|
/// </summary>
|
||||||
|
public bool DebugAnimations { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Show debug information about teleports.
|
/// Show debug information about teleports.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool DebugTeleporting { get; private set; }
|
public bool DebugTeleporting { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Show debug information about the scene loop.
|
/// Show debug information about the scene loop.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool DebugUpdates { get; private set; }
|
public bool DebugUpdates { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If true then the scene is saved to persistent storage periodically, every m_update_backup frames and
|
||||||
|
/// if objects meet required conditions (m_dontPersistBefore and m_dontPersistAfter).
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Even if false, the scene will still be saved on clean shutdown.
|
||||||
|
/// FIXME: Currently, setting this to false will mean that objects are not periodically returned from parcels.
|
||||||
|
/// This needs to be fixed.
|
||||||
|
/// </remarks>
|
||||||
|
public bool PeriodicBackup { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If false then the scene is never saved to persistence storage even if PeriodicBackup == true and even
|
||||||
|
/// if the scene is being shut down for the final time.
|
||||||
|
/// </summary>
|
||||||
|
public bool UseBackup { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If false then physical objects are disabled, though collisions will continue as normal.
|
||||||
|
/// </summary>
|
||||||
|
public bool PhysicsEnabled { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If false then scripts are not enabled on the smiulator
|
||||||
|
/// </summary>
|
||||||
|
public bool ScriptsEnabled
|
||||||
|
{
|
||||||
|
get { return m_scripts_enabled; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (m_scripts_enabled != value)
|
||||||
|
{
|
||||||
|
if (!value)
|
||||||
|
{
|
||||||
|
m_log.Info("Stopping all Scripts in Scene");
|
||||||
|
|
||||||
|
EntityBase[] entities = Entities.GetEntities();
|
||||||
|
foreach (EntityBase ent in entities)
|
||||||
|
{
|
||||||
|
if (ent is SceneObjectGroup)
|
||||||
|
((SceneObjectGroup)ent).RemoveScriptInstances(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_log.Info("Starting all Scripts in Scene");
|
||||||
|
|
||||||
|
EntityBase[] entities = Entities.GetEntities();
|
||||||
|
foreach (EntityBase ent in entities)
|
||||||
|
{
|
||||||
|
if (ent is SceneObjectGroup)
|
||||||
|
{
|
||||||
|
SceneObjectGroup sog = (SceneObjectGroup)ent;
|
||||||
|
sog.CreateScriptInstances(0, false, DefaultScriptEngine, 0);
|
||||||
|
sog.ResumeScripts();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_scripts_enabled = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private bool m_scripts_enabled;
|
||||||
|
|
||||||
public SynchronizeSceneHandler SynchronizeScene;
|
public SynchronizeSceneHandler SynchronizeScene;
|
||||||
|
|
||||||
|
@ -282,8 +352,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
private Dictionary<UUID, ReturnInfo> m_returns = new Dictionary<UUID, ReturnInfo>();
|
private Dictionary<UUID, ReturnInfo> m_returns = new Dictionary<UUID, ReturnInfo>();
|
||||||
private Dictionary<UUID, SceneObjectGroup> m_groupsWithTargets = new Dictionary<UUID, SceneObjectGroup>();
|
private Dictionary<UUID, SceneObjectGroup> m_groupsWithTargets = new Dictionary<UUID, SceneObjectGroup>();
|
||||||
|
|
||||||
private bool m_physics_enabled = true;
|
|
||||||
private bool m_scripts_enabled = true;
|
|
||||||
private string m_defaultScriptEngine;
|
private string m_defaultScriptEngine;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -341,7 +409,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
private Timer m_mapGenerationTimer = new Timer();
|
private Timer m_mapGenerationTimer = new Timer();
|
||||||
private bool m_generateMaptiles;
|
private bool m_generateMaptiles;
|
||||||
private bool m_useBackup = true;
|
|
||||||
|
|
||||||
#endregion Fields
|
#endregion Fields
|
||||||
|
|
||||||
|
@ -594,11 +661,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
get { return m_authenticateHandler; }
|
get { return m_authenticateHandler; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool UseBackup
|
|
||||||
{
|
|
||||||
get { return m_useBackup; }
|
|
||||||
}
|
|
||||||
|
|
||||||
// an instance to the physics plugin's Scene object.
|
// an instance to the physics plugin's Scene object.
|
||||||
public PhysicsScene PhysicsScene
|
public PhysicsScene PhysicsScene
|
||||||
{
|
{
|
||||||
|
@ -751,9 +813,11 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
DumpAssetsToFile = dumpAssetsToFile;
|
DumpAssetsToFile = dumpAssetsToFile;
|
||||||
|
|
||||||
|
// XXX: Don't set the public property since we don't want to activate here. This needs to be handled
|
||||||
|
// better in the future.
|
||||||
m_scripts_enabled = !RegionInfo.RegionSettings.DisableScripts;
|
m_scripts_enabled = !RegionInfo.RegionSettings.DisableScripts;
|
||||||
|
|
||||||
m_physics_enabled = !RegionInfo.RegionSettings.DisablePhysics;
|
PhysicsEnabled = !RegionInfo.RegionSettings.DisablePhysics;
|
||||||
|
|
||||||
m_simulatorVersion = simulatorVersion + " (" + Util.GetRuntimeInformation() + ")";
|
m_simulatorVersion = simulatorVersion + " (" + Util.GetRuntimeInformation() + ")";
|
||||||
|
|
||||||
|
@ -768,8 +832,8 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
StartDisabled = startupConfig.GetBoolean("StartDisabled", false);
|
StartDisabled = startupConfig.GetBoolean("StartDisabled", false);
|
||||||
|
|
||||||
m_defaultDrawDistance = startupConfig.GetFloat("DefaultDrawDistance", m_defaultDrawDistance);
|
m_defaultDrawDistance = startupConfig.GetFloat("DefaultDrawDistance", m_defaultDrawDistance);
|
||||||
m_useBackup = startupConfig.GetBoolean("UseSceneBackup", m_useBackup);
|
UseBackup = startupConfig.GetBoolean("UseSceneBackup", UseBackup);
|
||||||
if (!m_useBackup)
|
if (!UseBackup)
|
||||||
m_log.InfoFormat("[SCENE]: Backup has been disabled for {0}", RegionInfo.RegionName);
|
m_log.InfoFormat("[SCENE]: Backup has been disabled for {0}", RegionInfo.RegionName);
|
||||||
|
|
||||||
//Animation states
|
//Animation states
|
||||||
|
@ -937,6 +1001,10 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
{
|
{
|
||||||
PhysicalPrims = true;
|
PhysicalPrims = true;
|
||||||
CollidablePrims = true;
|
CollidablePrims = true;
|
||||||
|
PhysicsEnabled = true;
|
||||||
|
|
||||||
|
PeriodicBackup = true;
|
||||||
|
UseBackup = true;
|
||||||
|
|
||||||
BordersLocked = true;
|
BordersLocked = true;
|
||||||
Border northBorder = new Border();
|
Border northBorder = new Border();
|
||||||
|
@ -1179,83 +1247,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetSceneCoreDebug(Dictionary<string, string> options)
|
|
||||||
{
|
|
||||||
if (options.ContainsKey("active"))
|
|
||||||
{
|
|
||||||
bool active;
|
|
||||||
|
|
||||||
if (bool.TryParse(options["active"], out active))
|
|
||||||
Active = active;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.ContainsKey("scripting"))
|
|
||||||
{
|
|
||||||
bool enableScripts = true;
|
|
||||||
if (bool.TryParse(options["scripting"], out enableScripts) && m_scripts_enabled != enableScripts)
|
|
||||||
{
|
|
||||||
if (!enableScripts)
|
|
||||||
{
|
|
||||||
m_log.Info("Stopping all Scripts in Scene");
|
|
||||||
|
|
||||||
EntityBase[] entities = Entities.GetEntities();
|
|
||||||
foreach (EntityBase ent in entities)
|
|
||||||
{
|
|
||||||
if (ent is SceneObjectGroup)
|
|
||||||
((SceneObjectGroup)ent).RemoveScriptInstances(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_log.Info("Starting all Scripts in Scene");
|
|
||||||
|
|
||||||
EntityBase[] entities = Entities.GetEntities();
|
|
||||||
foreach (EntityBase ent in entities)
|
|
||||||
{
|
|
||||||
if (ent is SceneObjectGroup)
|
|
||||||
{
|
|
||||||
SceneObjectGroup sog = (SceneObjectGroup)ent;
|
|
||||||
sog.CreateScriptInstances(0, false, DefaultScriptEngine, 0);
|
|
||||||
sog.ResumeScripts();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_scripts_enabled = enableScripts;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.ContainsKey("physics"))
|
|
||||||
{
|
|
||||||
bool enablePhysics;
|
|
||||||
if (bool.TryParse(options["physics"], out enablePhysics))
|
|
||||||
m_physics_enabled = enablePhysics;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (options.ContainsKey("collisions"))
|
|
||||||
// {
|
|
||||||
// // TODO: Implement. If false, should stop objects colliding, though possibly should still allow
|
|
||||||
// // the avatar themselves to collide with the ground.
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (options.ContainsKey("teleport"))
|
|
||||||
{
|
|
||||||
bool enableTeleportDebugging;
|
|
||||||
if (bool.TryParse(options["teleport"], out enableTeleportDebugging))
|
|
||||||
DebugTeleporting = enableTeleportDebugging;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.ContainsKey("updates"))
|
|
||||||
{
|
|
||||||
bool enableUpdateDebugging;
|
|
||||||
if (bool.TryParse(options["updates"], out enableUpdateDebugging))
|
|
||||||
{
|
|
||||||
DebugUpdates = enableUpdateDebugging;
|
|
||||||
GcNotify.Enabled = DebugUpdates;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int GetInaccurateNeighborCount()
|
public int GetInaccurateNeighborCount()
|
||||||
{
|
{
|
||||||
return m_neighbours.Count;
|
return m_neighbours.Count;
|
||||||
|
@ -1514,7 +1505,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpMS = Util.EnvironmentTickCount();
|
tmpMS = Util.EnvironmentTickCount();
|
||||||
if ((Frame % m_update_physics == 0) && m_physics_enabled)
|
if (PhysicsEnabled && Frame % m_update_physics == 0)
|
||||||
m_sceneGraph.UpdatePreparePhysics();
|
m_sceneGraph.UpdatePreparePhysics();
|
||||||
physicsMS2 = Util.EnvironmentTickCountSubtract(tmpMS);
|
physicsMS2 = Util.EnvironmentTickCountSubtract(tmpMS);
|
||||||
|
|
||||||
|
@ -1529,7 +1520,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
tmpMS = Util.EnvironmentTickCount();
|
tmpMS = Util.EnvironmentTickCount();
|
||||||
if (Frame % m_update_physics == 0)
|
if (Frame % m_update_physics == 0)
|
||||||
{
|
{
|
||||||
if (m_physics_enabled)
|
if (PhysicsEnabled)
|
||||||
physicsFPS = m_sceneGraph.UpdatePhysics(MinFrameTime);
|
physicsFPS = m_sceneGraph.UpdatePhysics(MinFrameTime);
|
||||||
|
|
||||||
if (SynchronizeScene != null)
|
if (SynchronizeScene != null)
|
||||||
|
@ -1570,7 +1561,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
eventMS = Util.EnvironmentTickCountSubtract(tmpMS);
|
eventMS = Util.EnvironmentTickCountSubtract(tmpMS);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Frame % m_update_backup == 0)
|
if (PeriodicBackup && Frame % m_update_backup == 0)
|
||||||
{
|
{
|
||||||
tmpMS = Util.EnvironmentTickCount();
|
tmpMS = Util.EnvironmentTickCount();
|
||||||
UpdateStorageBackup();
|
UpdateStorageBackup();
|
||||||
|
|
|
@ -647,6 +647,18 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public UUID FromFolderID { get; set; }
|
public UUID FromFolderID { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// IDs of all avatars sat on this scene object.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// We need this so that we can maintain a linkset wide ordering of avatars sat on different parts.
|
||||||
|
/// This must be locked before it is read or written.
|
||||||
|
/// SceneObjectPart sitting avatar add/remove code also locks on this object to avoid race conditions.
|
||||||
|
/// No avatar should appear more than once in this list.
|
||||||
|
/// Do not manipulate this list directly - use the Add/Remove sitting avatar methods on SceneObjectPart.
|
||||||
|
/// </remarks>
|
||||||
|
protected internal List<UUID> m_sittingAvatars = new List<UUID>();
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
// ~SceneObjectGroup()
|
// ~SceneObjectGroup()
|
||||||
|
@ -3563,6 +3575,20 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a copy of the list of sitting avatars on all prims of this object.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This is sorted by the order in which avatars sat down. If an avatar stands up then all avatars that sat
|
||||||
|
/// down after it move one place down the list.
|
||||||
|
/// </remarks>
|
||||||
|
/// <returns>A list of the sitting avatars. Returns an empty list if there are no sitting avatars.</returns>
|
||||||
|
public List<UUID> GetSittingAvatars()
|
||||||
|
{
|
||||||
|
lock (m_sittingAvatars)
|
||||||
|
return new List<UUID>(m_sittingAvatars);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the number of sitting avatars.
|
/// Gets the number of sitting avatars.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -3570,11 +3596,8 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public int GetSittingAvatarsCount()
|
public int GetSittingAvatarsCount()
|
||||||
{
|
{
|
||||||
int count = 0;
|
lock (m_sittingAvatars)
|
||||||
|
return m_sittingAvatars.Count;
|
||||||
Array.ForEach<SceneObjectPart>(m_parts.GetArray(), p => count += p.GetSittingAvatarsCount());
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
|
@ -3583,7 +3606,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
}
|
}
|
||||||
|
|
||||||
#region ISceneObject
|
#region ISceneObject
|
||||||
|
|
||||||
public virtual ISceneObject CloneForNewScene()
|
public virtual ISceneObject CloneForNewScene()
|
||||||
{
|
{
|
||||||
SceneObjectGroup sog = Copy(false);
|
SceneObjectGroup sog = Copy(false);
|
||||||
|
|
|
@ -1256,7 +1256,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
public UUID SitTargetAvatar { get; set; }
|
public UUID SitTargetAvatar { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// IDs of all avatars start on this object part.
|
/// IDs of all avatars sat on this part.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// We need to track this so that we can stop sat upon prims from being attached.
|
/// We need to track this so that we can stop sat upon prims from being attached.
|
||||||
|
@ -4050,9 +4050,9 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
rigidBody,
|
rigidBody,
|
||||||
m_localId);
|
m_localId);
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
m_log.ErrorFormat("[SCENE]: caught exception meshing object {0}. Object set to phantom.", m_uuid);
|
m_log.ErrorFormat("[SCENE]: caught exception meshing object {0}. Object set to phantom. e={1}", m_uuid, e);
|
||||||
pa = null;
|
pa = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4504,18 +4504,22 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
/// <param name='avatarId'></param>
|
/// <param name='avatarId'></param>
|
||||||
protected internal bool AddSittingAvatar(UUID avatarId)
|
protected internal bool AddSittingAvatar(UUID avatarId)
|
||||||
{
|
{
|
||||||
if (IsSitTargetSet && SitTargetAvatar == UUID.Zero)
|
lock (ParentGroup.m_sittingAvatars)
|
||||||
SitTargetAvatar = avatarId;
|
|
||||||
|
|
||||||
HashSet<UUID> sittingAvatars = m_sittingAvatars;
|
|
||||||
|
|
||||||
if (sittingAvatars == null)
|
|
||||||
sittingAvatars = new HashSet<UUID>();
|
|
||||||
|
|
||||||
lock (sittingAvatars)
|
|
||||||
{
|
{
|
||||||
m_sittingAvatars = sittingAvatars;
|
if (IsSitTargetSet && SitTargetAvatar == UUID.Zero)
|
||||||
return m_sittingAvatars.Add(avatarId);
|
SitTargetAvatar = avatarId;
|
||||||
|
|
||||||
|
if (m_sittingAvatars == null)
|
||||||
|
m_sittingAvatars = new HashSet<UUID>();
|
||||||
|
|
||||||
|
if (m_sittingAvatars.Add(avatarId))
|
||||||
|
{
|
||||||
|
ParentGroup.m_sittingAvatars.Add(avatarId);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4529,27 +4533,26 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
/// <param name='avatarId'></param>
|
/// <param name='avatarId'></param>
|
||||||
protected internal bool RemoveSittingAvatar(UUID avatarId)
|
protected internal bool RemoveSittingAvatar(UUID avatarId)
|
||||||
{
|
{
|
||||||
if (SitTargetAvatar == avatarId)
|
lock (ParentGroup.m_sittingAvatars)
|
||||||
SitTargetAvatar = UUID.Zero;
|
|
||||||
|
|
||||||
HashSet<UUID> sittingAvatars = m_sittingAvatars;
|
|
||||||
|
|
||||||
// This can occur under a race condition where another thread
|
|
||||||
if (sittingAvatars == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
lock (sittingAvatars)
|
|
||||||
{
|
{
|
||||||
if (sittingAvatars.Remove(avatarId))
|
if (SitTargetAvatar == avatarId)
|
||||||
|
SitTargetAvatar = UUID.Zero;
|
||||||
|
|
||||||
|
if (m_sittingAvatars == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (m_sittingAvatars.Remove(avatarId))
|
||||||
{
|
{
|
||||||
if (sittingAvatars.Count == 0)
|
if (m_sittingAvatars.Count == 0)
|
||||||
m_sittingAvatars = null;
|
m_sittingAvatars = null;
|
||||||
|
|
||||||
|
ParentGroup.m_sittingAvatars.Remove(avatarId);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -4559,16 +4562,12 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
/// <returns>A hashset of the sitting avatars. Returns null if there are no sitting avatars.</returns>
|
/// <returns>A hashset of the sitting avatars. Returns null if there are no sitting avatars.</returns>
|
||||||
public HashSet<UUID> GetSittingAvatars()
|
public HashSet<UUID> GetSittingAvatars()
|
||||||
{
|
{
|
||||||
HashSet<UUID> sittingAvatars = m_sittingAvatars;
|
lock (ParentGroup.m_sittingAvatars)
|
||||||
|
|
||||||
if (sittingAvatars == null)
|
|
||||||
{
|
{
|
||||||
return null;
|
if (m_sittingAvatars == null)
|
||||||
}
|
return null;
|
||||||
else
|
else
|
||||||
{
|
return new HashSet<UUID>(m_sittingAvatars);
|
||||||
lock (sittingAvatars)
|
|
||||||
return new HashSet<UUID>(sittingAvatars);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4579,13 +4578,13 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public int GetSittingAvatarsCount()
|
public int GetSittingAvatarsCount()
|
||||||
{
|
{
|
||||||
HashSet<UUID> sittingAvatars = m_sittingAvatars;
|
lock (ParentGroup.m_sittingAvatars)
|
||||||
|
{
|
||||||
if (sittingAvatars == null)
|
if (m_sittingAvatars == null)
|
||||||
return 0;
|
return 0;
|
||||||
|
else
|
||||||
lock (sittingAvatars)
|
return m_sittingAvatars.Count;
|
||||||
return sittingAvatars.Count;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1954,6 +1954,9 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
{
|
{
|
||||||
if (ParentID != 0)
|
if (ParentID != 0)
|
||||||
{
|
{
|
||||||
|
if (ParentPart.UUID == targetID)
|
||||||
|
return; // already sitting here, ignore
|
||||||
|
|
||||||
StandUp();
|
StandUp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2256,7 +2259,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
public void HandleStopAnim(IClientAPI remoteClient, UUID animID)
|
public void HandleStopAnim(IClientAPI remoteClient, UUID animID)
|
||||||
{
|
{
|
||||||
Animator.RemoveAnimation(animID);
|
Animator.RemoveAnimation(animID, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -42,9 +42,6 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Serialize and deserialize coalesced scene objects.
|
/// Serialize and deserialize coalesced scene objects.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
|
||||||
/// Deserialization not yet here.
|
|
||||||
/// </remarks>
|
|
||||||
public class CoalescedSceneObjectsSerializer
|
public class CoalescedSceneObjectsSerializer
|
||||||
{
|
{
|
||||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
@ -128,6 +125,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
|
||||||
// m_log.DebugFormat("[COALESCED SCENE OBJECTS SERIALIZER]: TryFromXml() deserializing {0}", xml);
|
// m_log.DebugFormat("[COALESCED SCENE OBJECTS SERIALIZER]: TryFromXml() deserializing {0}", xml);
|
||||||
|
|
||||||
coa = null;
|
coa = null;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
using (StringReader sr = new StringReader(xml))
|
using (StringReader sr = new StringReader(xml))
|
||||||
{
|
{
|
||||||
|
@ -153,7 +151,23 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
|
||||||
if (reader.Name == "SceneObjectGroup")
|
if (reader.Name == "SceneObjectGroup")
|
||||||
{
|
{
|
||||||
string soXml = reader.ReadOuterXml();
|
string soXml = reader.ReadOuterXml();
|
||||||
coa.Add(SceneObjectSerializer.FromOriginalXmlFormat(soXml));
|
|
||||||
|
SceneObjectGroup so = SceneObjectSerializer.FromOriginalXmlFormat(soXml);
|
||||||
|
|
||||||
|
if (so != null)
|
||||||
|
{
|
||||||
|
coa.Add(so);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// XXX: Possibly we should fail outright here rather than continuing if a particular component of the
|
||||||
|
// coalesced object fails to load.
|
||||||
|
m_log.WarnFormat(
|
||||||
|
"[COALESCED SCENE OBJECTS SERIALIZER]: Deserialization of xml for component {0} failed. Continuing.",
|
||||||
|
i);
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -289,6 +289,9 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
private void statsHeartBeat(object sender, EventArgs e)
|
private void statsHeartBeat(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
|
if (!m_scene.Active)
|
||||||
|
return;
|
||||||
|
|
||||||
SimStatsPacket.StatBlock[] sb = new SimStatsPacket.StatBlock[22];
|
SimStatsPacket.StatBlock[] sb = new SimStatsPacket.StatBlock[22];
|
||||||
SimStatsPacket.RegionBlock rb = new SimStatsPacket.RegionBlock();
|
SimStatsPacket.RegionBlock rb = new SimStatsPacket.RegionBlock();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,200 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Contributors, http://opensimulator.org/
|
||||||
|
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the OpenSimulator Project nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using log4net;
|
||||||
|
using Mono.Addins;
|
||||||
|
using Nini.Config;
|
||||||
|
using OpenMetaverse;
|
||||||
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Framework.Console;
|
||||||
|
using OpenSim.Framework.Monitoring;
|
||||||
|
using OpenSim.Region.ClientStack.LindenUDP;
|
||||||
|
using OpenSim.Region.Framework.Interfaces;
|
||||||
|
using OpenSim.Region.Framework.Scenes;
|
||||||
|
using OpenSim.Region.Framework.Scenes.Animation;
|
||||||
|
using OpenSim.Services.Interfaces;
|
||||||
|
|
||||||
|
namespace OpenSim.Region.OptionalModules.Avatar.Animations
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A module that just holds commands for inspecting avatar animations.
|
||||||
|
/// </summary>
|
||||||
|
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AnimationsCommandModule")]
|
||||||
|
public class AnimationsCommandModule : ISharedRegionModule
|
||||||
|
{
|
||||||
|
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
|
private List<Scene> m_scenes = new List<Scene>();
|
||||||
|
|
||||||
|
public string Name { get { return "Animations Command Module"; } }
|
||||||
|
|
||||||
|
public Type ReplaceableInterface { get { return null; } }
|
||||||
|
|
||||||
|
public void Initialise(IConfigSource source)
|
||||||
|
{
|
||||||
|
// m_log.DebugFormat("[ANIMATIONS COMMAND MODULE]: INITIALIZED MODULE");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PostInitialise()
|
||||||
|
{
|
||||||
|
// m_log.DebugFormat("[ANIMATIONS COMMAND MODULE]: POST INITIALIZED MODULE");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Close()
|
||||||
|
{
|
||||||
|
// m_log.DebugFormat("[ANIMATIONS COMMAND MODULE]: CLOSED MODULE");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddRegion(Scene scene)
|
||||||
|
{
|
||||||
|
// m_log.DebugFormat("[ANIMATIONS COMMAND MODULE]: REGION {0} ADDED", scene.RegionInfo.RegionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveRegion(Scene scene)
|
||||||
|
{
|
||||||
|
// m_log.DebugFormat("[ATTACHMENTS COMMAND MODULE]: REGION {0} REMOVED", scene.RegionInfo.RegionName);
|
||||||
|
|
||||||
|
lock (m_scenes)
|
||||||
|
m_scenes.Remove(scene);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RegionLoaded(Scene scene)
|
||||||
|
{
|
||||||
|
// m_log.DebugFormat("[ANIMATIONS COMMAND MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName);
|
||||||
|
|
||||||
|
lock (m_scenes)
|
||||||
|
m_scenes.Add(scene);
|
||||||
|
|
||||||
|
scene.AddCommand(
|
||||||
|
"Users", this, "show animations",
|
||||||
|
"show animations [<first-name> <last-name>]",
|
||||||
|
"Show animation information for avatars in this simulator.",
|
||||||
|
"If no name is supplied then information for all avatars is shown.\n"
|
||||||
|
+ "Please note that for inventory animations, the animation name is the name under which the animation was originally uploaded\n"
|
||||||
|
+ ", which is not necessarily the current inventory name.",
|
||||||
|
HandleShowAnimationsCommand);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void HandleShowAnimationsCommand(string module, string[] cmd)
|
||||||
|
{
|
||||||
|
if (cmd.Length != 2 && cmd.Length < 4)
|
||||||
|
{
|
||||||
|
MainConsole.Instance.OutputFormat("Usage: show animations [<first-name> <last-name>]");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool targetNameSupplied = false;
|
||||||
|
string optionalTargetFirstName = null;
|
||||||
|
string optionalTargetLastName = null;
|
||||||
|
|
||||||
|
if (cmd.Length >= 4)
|
||||||
|
{
|
||||||
|
targetNameSupplied = true;
|
||||||
|
optionalTargetFirstName = cmd[2];
|
||||||
|
optionalTargetLastName = cmd[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
lock (m_scenes)
|
||||||
|
{
|
||||||
|
foreach (Scene scene in m_scenes)
|
||||||
|
{
|
||||||
|
if (targetNameSupplied)
|
||||||
|
{
|
||||||
|
ScenePresence sp = scene.GetScenePresence(optionalTargetFirstName, optionalTargetLastName);
|
||||||
|
if (sp != null && !sp.IsChildAgent)
|
||||||
|
GetAttachmentsReport(sp, sb);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scene.ForEachRootScenePresence(sp => GetAttachmentsReport(sp, sb));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MainConsole.Instance.Output(sb.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GetAttachmentsReport(ScenePresence sp, StringBuilder sb)
|
||||||
|
{
|
||||||
|
sb.AppendFormat("Animations for {0}\n", sp.Name);
|
||||||
|
|
||||||
|
ConsoleDisplayList cdl = new ConsoleDisplayList() { Indent = 2 };
|
||||||
|
ScenePresenceAnimator spa = sp.Animator;
|
||||||
|
AnimationSet anims = sp.Animator.Animations;
|
||||||
|
|
||||||
|
string cma = spa.CurrentMovementAnimation;
|
||||||
|
cdl.AddRow(
|
||||||
|
"Current movement anim",
|
||||||
|
string.Format("{0}, {1}", DefaultAvatarAnimations.GetDefaultAnimation(cma), cma));
|
||||||
|
|
||||||
|
UUID defaultAnimId = anims.DefaultAnimation.AnimID;
|
||||||
|
cdl.AddRow(
|
||||||
|
"Default anim",
|
||||||
|
string.Format("{0}, {1}", defaultAnimId, sp.Animator.GetAnimName(defaultAnimId)));
|
||||||
|
|
||||||
|
UUID implicitDefaultAnimId = anims.ImplicitDefaultAnimation.AnimID;
|
||||||
|
cdl.AddRow(
|
||||||
|
"Implicit default anim",
|
||||||
|
string.Format("{0}, {1}",
|
||||||
|
implicitDefaultAnimId, sp.Animator.GetAnimName(implicitDefaultAnimId)));
|
||||||
|
|
||||||
|
cdl.AddToStringBuilder(sb);
|
||||||
|
|
||||||
|
ConsoleDisplayTable cdt = new ConsoleDisplayTable() { Indent = 2 };
|
||||||
|
cdt.AddColumn("Animation ID", 36);
|
||||||
|
cdt.AddColumn("Name", 20);
|
||||||
|
cdt.AddColumn("Seq", 3);
|
||||||
|
cdt.AddColumn("Object ID", 36);
|
||||||
|
|
||||||
|
UUID[] animIds;
|
||||||
|
int[] sequenceNumbers;
|
||||||
|
UUID[] objectIds;
|
||||||
|
|
||||||
|
sp.Animator.Animations.GetArrays(out animIds, out sequenceNumbers, out objectIds);
|
||||||
|
|
||||||
|
for (int i = 0; i < animIds.Length; i++)
|
||||||
|
{
|
||||||
|
UUID animId = animIds[i];
|
||||||
|
string animName = sp.Animator.GetAnimName(animId);
|
||||||
|
int seq = sequenceNumbers[i];
|
||||||
|
UUID objectId = objectIds[i];
|
||||||
|
|
||||||
|
cdt.AddRow(animId, animName, seq, objectId);
|
||||||
|
}
|
||||||
|
|
||||||
|
cdt.AddToStringBuilder(sb);
|
||||||
|
sb.Append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -97,6 +97,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments
|
||||||
"Users", this, "attachments show",
|
"Users", this, "attachments show",
|
||||||
"attachments show [<first-name> <last-name>]",
|
"attachments show [<first-name> <last-name>]",
|
||||||
"Show attachment information for avatars in this simulator.",
|
"Show attachment information for avatars in this simulator.",
|
||||||
|
"If no name is supplied then information for all avatars is shown.",
|
||||||
HandleShowAttachmentsCommand);
|
HandleShowAttachmentsCommand);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ using OpenSim.Framework.Communications;
|
||||||
using OpenSim.Region.Framework.Interfaces;
|
using OpenSim.Region.Framework.Interfaces;
|
||||||
using OpenSim.Region.Framework.Scenes;
|
using OpenSim.Region.Framework.Scenes;
|
||||||
using OpenSim.Services.Interfaces;
|
using OpenSim.Services.Interfaces;
|
||||||
|
using System.Text;
|
||||||
using DirFindFlags = OpenMetaverse.DirectoryManager.DirFindFlags;
|
using DirFindFlags = OpenMetaverse.DirectoryManager.DirFindFlags;
|
||||||
|
|
||||||
namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
|
@ -50,19 +51,19 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
/// ; To use this module, you must specify the following in your OpenSim.ini
|
/// ; To use this module, you must specify the following in your OpenSim.ini
|
||||||
/// [GROUPS]
|
/// [GROUPS]
|
||||||
/// Enabled = true
|
/// Enabled = true
|
||||||
///
|
///
|
||||||
/// Module = GroupsModule
|
/// Module = GroupsModule
|
||||||
/// NoticesEnabled = true
|
/// NoticesEnabled = true
|
||||||
/// DebugEnabled = true
|
/// DebugEnabled = true
|
||||||
///
|
///
|
||||||
/// GroupsServicesConnectorModule = XmlRpcGroupsServicesConnector
|
/// GroupsServicesConnectorModule = XmlRpcGroupsServicesConnector
|
||||||
/// XmlRpcServiceURL = http://osflotsam.org/xmlrpc.php
|
/// XmlRpcServiceURL = http://osflotsam.org/xmlrpc.php
|
||||||
/// XmlRpcServiceReadKey = 1234
|
/// XmlRpcServiceReadKey = 1234
|
||||||
/// XmlRpcServiceWriteKey = 1234
|
/// XmlRpcServiceWriteKey = 1234
|
||||||
///
|
///
|
||||||
/// MessagingModule = GroupsMessagingModule
|
/// MessagingModule = GroupsMessagingModule
|
||||||
/// MessagingEnabled = true
|
/// MessagingEnabled = true
|
||||||
///
|
///
|
||||||
/// ; Disables HTTP Keep-Alive for Groups Module HTTP Requests, work around for
|
/// ; Disables HTTP Keep-Alive for Groups Module HTTP Requests, work around for
|
||||||
/// ; a problem discovered on some Windows based region servers. Only disable
|
/// ; a problem discovered on some Windows based region servers. Only disable
|
||||||
/// ; if you see a large number (dozens) of the following Exceptions:
|
/// ; if you see a large number (dozens) of the following Exceptions:
|
||||||
|
@ -77,7 +78,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
private List<Scene> m_sceneList = new List<Scene>();
|
private List<Scene> m_sceneList = new List<Scene>();
|
||||||
|
|
||||||
private IMessageTransferModule m_msgTransferModule = null;
|
private IMessageTransferModule m_msgTransferModule = null;
|
||||||
|
|
||||||
private IGroupsServicesConnector m_groupData = null;
|
private IGroupsServicesConnector m_groupData = null;
|
||||||
|
|
||||||
// Configuration settings
|
// Configuration settings
|
||||||
|
@ -126,7 +127,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
{
|
{
|
||||||
scene.RegisterModuleInterface<IGroupsModule>(this);
|
scene.RegisterModuleInterface<IGroupsModule>(this);
|
||||||
scene.AddCommand(
|
scene.AddCommand(
|
||||||
"debug",
|
"Debug",
|
||||||
this,
|
this,
|
||||||
"debug groups verbose",
|
"debug groups verbose",
|
||||||
"debug groups verbose <true|false>",
|
"debug groups verbose <true|false>",
|
||||||
|
@ -195,10 +196,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
|
|
||||||
scene.EventManager.OnNewClient += OnNewClient;
|
scene.EventManager.OnNewClient += OnNewClient;
|
||||||
scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage;
|
scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage;
|
||||||
// The InstantMessageModule itself doesn't do this,
|
// The InstantMessageModule itself doesn't do this,
|
||||||
// so lets see if things explode if we don't do it
|
// so lets see if things explode if we don't do it
|
||||||
// scene.EventManager.OnClientClosed += OnClientClosed;
|
// scene.EventManager.OnClientClosed += OnClientClosed;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveRegion(Scene scene)
|
public void RemoveRegion(Scene scene)
|
||||||
|
@ -222,7 +222,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
if (m_debugEnabled) m_log.Debug("[GROUPS]: Shutting down Groups module.");
|
if (m_debugEnabled) m_log.Debug("[GROUPS]: Shutting down Groups module.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public Type ReplaceableInterface
|
public Type ReplaceableInterface
|
||||||
{
|
{
|
||||||
get { return null; }
|
get { return null; }
|
||||||
}
|
}
|
||||||
|
@ -274,7 +274,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
* reference to IClientAPI's, one for 0 or 1 root connections, and 0 or more child connections.
|
* reference to IClientAPI's, one for 0 or 1 root connections, and 0 or more child connections.
|
||||||
* The OnClientClosed event does not provide anything to indicate which one of those should be closed
|
* The OnClientClosed event does not provide anything to indicate which one of those should be closed
|
||||||
* nor does it provide what scene it was from so that the specific reference can be looked up.
|
* nor does it provide what scene it was from so that the specific reference can be looked up.
|
||||||
* The InstantMessageModule.cs does not currently worry about unregistering the handles,
|
* The InstantMessageModule.cs does not currently worry about unregistering the handles,
|
||||||
* and it should be an issue, since it's the client that references us not the other way around
|
* and it should be an issue, since it's the client that references us not the other way around
|
||||||
* , so as long as we don't keep a reference to the client laying around, the client can still be GC'ed
|
* , so as long as we don't keep a reference to the client laying around, the client can still be GC'ed
|
||||||
private void OnClientClosed(UUID AgentId)
|
private void OnClientClosed(UUID AgentId)
|
||||||
|
@ -297,8 +297,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
{
|
{
|
||||||
if (m_debugEnabled) m_log.WarnFormat("[GROUPS]: Client closed that wasn't registered here.");
|
if (m_debugEnabled) m_log.WarnFormat("[GROUPS]: Client closed that wasn't registered here.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
@ -307,15 +305,15 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
{
|
{
|
||||||
if (((DirFindFlags)queryFlags & DirFindFlags.Groups) == DirFindFlags.Groups)
|
if (((DirFindFlags)queryFlags & DirFindFlags.Groups) == DirFindFlags.Groups)
|
||||||
{
|
{
|
||||||
if (m_debugEnabled)
|
if (m_debugEnabled)
|
||||||
m_log.DebugFormat(
|
m_log.DebugFormat(
|
||||||
"[GROUPS]: {0} called with queryText({1}) queryFlags({2}) queryStart({3})",
|
"[GROUPS]: {0} called with queryText({1}) queryFlags({2}) queryStart({3})",
|
||||||
System.Reflection.MethodBase.GetCurrentMethod().Name, queryText, (DirFindFlags)queryFlags, queryStart);
|
System.Reflection.MethodBase.GetCurrentMethod().Name, queryText, (DirFindFlags)queryFlags, queryStart);
|
||||||
|
|
||||||
// TODO: This currently ignores pretty much all the query flags including Mature and sort order
|
// TODO: This currently ignores pretty much all the query flags including Mature and sort order
|
||||||
remoteClient.SendDirGroupsReply(queryID, m_groupData.FindGroups(GetRequestingAgentID(remoteClient), queryText).ToArray());
|
remoteClient.SendDirGroupsReply(queryID, m_groupData.FindGroups(GetRequestingAgentID(remoteClient), queryText).ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnAgentDataUpdateRequest(IClientAPI remoteClient, UUID dataForAgentID, UUID sessionID)
|
private void OnAgentDataUpdateRequest(IClientAPI remoteClient, UUID dataForAgentID, UUID sessionID)
|
||||||
|
@ -345,7 +343,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
|
if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
|
||||||
|
|
||||||
string GroupName;
|
string GroupName;
|
||||||
|
|
||||||
GroupRecord group = m_groupData.GetGroupRecord(GetRequestingAgentID(remoteClient), GroupID, null);
|
GroupRecord group = m_groupData.GetGroupRecord(GetRequestingAgentID(remoteClient), GroupID, null);
|
||||||
if (group != null)
|
if (group != null)
|
||||||
{
|
{
|
||||||
|
@ -407,7 +405,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
|
|
||||||
UpdateAllClientsWithGroupInfo(inviteInfo.AgentID);
|
UpdateAllClientsWithGroupInfo(inviteInfo.AgentID);
|
||||||
|
|
||||||
// TODO: If the inviter is still online, they need an agent dataupdate
|
// TODO: If the inviter is still online, they need an agent dataupdate
|
||||||
// and maybe group membership updates for the invitee
|
// and maybe group membership updates for the invitee
|
||||||
|
|
||||||
m_groupData.RemoveAgentToGroupInvite(GetRequestingAgentID(remoteClient), inviteID);
|
m_groupData.RemoveAgentToGroupInvite(GetRequestingAgentID(remoteClient), inviteID);
|
||||||
|
@ -437,44 +435,75 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
string Subject = im.message.Substring(0, im.message.IndexOf('|'));
|
string Subject = im.message.Substring(0, im.message.IndexOf('|'));
|
||||||
string Message = im.message.Substring(Subject.Length + 1);
|
string Message = im.message.Substring(Subject.Length + 1);
|
||||||
|
|
||||||
|
InventoryItemBase item = null;
|
||||||
|
bool hasAttachment = false;
|
||||||
|
UUID itemID = UUID.Zero; //Assignment to quiet compiler
|
||||||
|
UUID ownerID = UUID.Zero; //Assignment to quiet compiler
|
||||||
byte[] bucket;
|
byte[] bucket;
|
||||||
|
|
||||||
if ((im.binaryBucket.Length == 1) && (im.binaryBucket[0] == 0))
|
if (im.binaryBucket.Length >= 1 && im.binaryBucket[0] > 0)
|
||||||
{
|
|
||||||
bucket = new byte[19];
|
|
||||||
bucket[0] = 0; //dunno
|
|
||||||
bucket[1] = 0; //dunno
|
|
||||||
GroupID.ToBytes(bucket, 2);
|
|
||||||
bucket[18] = 0; //dunno
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
string binBucket = OpenMetaverse.Utils.BytesToString(im.binaryBucket);
|
string binBucket = OpenMetaverse.Utils.BytesToString(im.binaryBucket);
|
||||||
binBucket = binBucket.Remove(0, 14).Trim();
|
binBucket = binBucket.Remove(0, 14).Trim();
|
||||||
if (m_debugEnabled)
|
|
||||||
{
|
|
||||||
m_log.WarnFormat("I don't understand a group notice binary bucket of: {0}", binBucket);
|
|
||||||
|
|
||||||
OSDMap binBucketOSD = (OSDMap)OSDParser.DeserializeLLSDXml(binBucket);
|
OSDMap binBucketOSD = (OSDMap)OSDParser.DeserializeLLSDXml(binBucket);
|
||||||
|
if (binBucketOSD is OSD)
|
||||||
foreach (string key in binBucketOSD.Keys)
|
{
|
||||||
|
OSDMap binBucketMap = (OSDMap)binBucketOSD;
|
||||||
|
|
||||||
|
itemID = binBucketMap["item_id"].AsUUID();
|
||||||
|
ownerID = binBucketMap["owner_id"].AsUUID();
|
||||||
|
|
||||||
|
//Attempt to get the details of the attached item.
|
||||||
|
//If sender doesn't own the attachment, the item
|
||||||
|
//variable will be set to null and attachment will
|
||||||
|
//not be included with the group notice.
|
||||||
|
Scene scene = (Scene)remoteClient.Scene;
|
||||||
|
item = new InventoryItemBase(itemID, ownerID);
|
||||||
|
item = scene.InventoryService.GetItem(item);
|
||||||
|
|
||||||
|
if (item != null)
|
||||||
{
|
{
|
||||||
if (binBucketOSD.ContainsKey(key))
|
//Got item details so include the attachment.
|
||||||
{
|
hasAttachment = true;
|
||||||
m_log.WarnFormat("{0}: {1}", key, binBucketOSD[key].ToString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
// treat as if no attachment
|
{
|
||||||
bucket = new byte[19];
|
m_log.DebugFormat("[Groups]: Received OSD with unexpected type: {0}", binBucketOSD.GetType());
|
||||||
bucket[0] = 0; //dunno
|
}
|
||||||
bucket[1] = 0; //dunno
|
}
|
||||||
GroupID.ToBytes(bucket, 2);
|
|
||||||
bucket[18] = 0; //dunno
|
if (hasAttachment)
|
||||||
|
{
|
||||||
|
//Bucket contains information about attachment.
|
||||||
|
//
|
||||||
|
//Byte offset and description of bucket data:
|
||||||
|
//0: 1 byte indicating if attachment is present
|
||||||
|
//1: 1 byte indicating the type of attachment
|
||||||
|
//2: 16 bytes - Group UUID
|
||||||
|
//18: 16 bytes - UUID of the attachment owner
|
||||||
|
//34: 16 bytes - UUID of the attachment
|
||||||
|
//50: variable - Name of the attachment
|
||||||
|
//??: NUL byte to terminate the attachment name
|
||||||
|
byte[] name = Encoding.UTF8.GetBytes(item.Name);
|
||||||
|
bucket = new byte[51 + name.Length];//3 bytes, 3 UUIDs, and name
|
||||||
|
bucket[0] = 1; //Has attachment flag
|
||||||
|
bucket[1] = (byte)item.InvType; //Type of Attachment
|
||||||
|
GroupID.ToBytes(bucket, 2);
|
||||||
|
ownerID.ToBytes(bucket, 18);
|
||||||
|
itemID.ToBytes(bucket, 34);
|
||||||
|
name.CopyTo(bucket, 50);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bucket = new byte[19];
|
||||||
|
bucket[0] = 0; //Has attachment flag
|
||||||
|
bucket[1] = 0; //Type of attachment
|
||||||
|
GroupID.ToBytes(bucket, 2);
|
||||||
|
bucket[18] = 0; //NUL terminate name of attachment
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
m_groupData.AddGroupNotice(GetRequestingAgentID(remoteClient), GroupID, NoticeID, im.fromAgentName, Subject, Message, bucket);
|
m_groupData.AddGroupNotice(GetRequestingAgentID(remoteClient), GroupID, NoticeID, im.fromAgentName, Subject, Message, bucket);
|
||||||
if (OnNewGroupNotice != null)
|
if (OnNewGroupNotice != null)
|
||||||
{
|
{
|
||||||
|
@ -484,22 +513,24 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
// Send notice out to everyone that wants notices
|
// Send notice out to everyone that wants notices
|
||||||
foreach (GroupMembersData member in m_groupData.GetGroupMembers(GetRequestingAgentID(remoteClient), GroupID))
|
foreach (GroupMembersData member in m_groupData.GetGroupMembers(GetRequestingAgentID(remoteClient), GroupID))
|
||||||
{
|
{
|
||||||
if (m_debugEnabled)
|
if (m_debugEnabled)
|
||||||
{
|
{
|
||||||
UserAccount targetUser = m_sceneList[0].UserAccountService.GetUserAccount(remoteClient.Scene.RegionInfo.ScopeID, member.AgentID);
|
UserAccount targetUser = m_sceneList[0].UserAccountService.GetUserAccount(remoteClient.Scene.RegionInfo.ScopeID, member.AgentID);
|
||||||
if (targetUser != null)
|
if (targetUser != null)
|
||||||
{
|
{
|
||||||
m_log.DebugFormat("[GROUPS]: Prepping group notice {0} for agent: {1} who Accepts Notices ({2})", NoticeID, targetUser.FirstName + " " + targetUser.LastName, member.AcceptNotices);
|
m_log.DebugFormat("[GROUPS]: Prepping group notice {0} for agent: {1} who Accepts Notices ({2})",
|
||||||
|
NoticeID, targetUser.FirstName + " " + targetUser.LastName, member.AcceptNotices);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_log.DebugFormat("[GROUPS]: Prepping group notice {0} for agent: {1} who Accepts Notices ({2})", NoticeID, member.AgentID, member.AcceptNotices);
|
m_log.DebugFormat("[GROUPS]: Prepping group notice {0} for agent: {1} who Accepts Notices ({2})",
|
||||||
|
NoticeID, member.AgentID, member.AcceptNotices);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (member.AcceptNotices)
|
if (member.AcceptNotices)
|
||||||
{
|
{
|
||||||
// Build notice IIM
|
// Build notice IM
|
||||||
GridInstantMessage msg = CreateGroupNoticeIM(UUID.Zero, NoticeID, (byte)OpenMetaverse.InstantMessageDialog.GroupNotice);
|
GridInstantMessage msg = CreateGroupNoticeIM(UUID.Zero, NoticeID, (byte)OpenMetaverse.InstantMessageDialog.GroupNotice);
|
||||||
|
|
||||||
msg.toAgentID = member.AgentID.Guid;
|
msg.toAgentID = member.AgentID.Guid;
|
||||||
|
@ -508,10 +539,40 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (im.dialog == (byte)InstantMessageDialog.GroupNoticeInventoryAccepted)
|
||||||
|
{
|
||||||
|
//Is bucket large enough to hold UUID of the attachment?
|
||||||
|
if (im.binaryBucket.Length < 16)
|
||||||
|
return;
|
||||||
|
|
||||||
|
UUID noticeID = new UUID(im.imSessionID);
|
||||||
|
|
||||||
|
GroupNoticeInfo notice = m_groupData.GetGroupNotice(GetRequestingAgentID(remoteClient), noticeID);
|
||||||
|
if (notice != null)
|
||||||
|
{
|
||||||
|
UUID giver = new UUID(notice.BinaryBucket, 18);
|
||||||
|
UUID attachmentUUID = new UUID(notice.BinaryBucket, 34);
|
||||||
|
|
||||||
|
if (m_debugEnabled)
|
||||||
|
m_log.DebugFormat("[Groups]: Giving inventory from {0} to {1}", giver, remoteClient.AgentId);
|
||||||
|
|
||||||
|
InventoryItemBase itemCopy = ((Scene)(remoteClient.Scene)).GiveInventoryItem(remoteClient.AgentId,
|
||||||
|
giver, attachmentUUID);
|
||||||
|
|
||||||
|
if (itemCopy == null)
|
||||||
|
{
|
||||||
|
remoteClient.SendAgentAlertMessage("Can't find item to give. Nothing given.", false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
remoteClient.SendInventoryItemCreateUpdate(itemCopy, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Interop, received special 210 code for ejecting a group member
|
// Interop, received special 210 code for ejecting a group member
|
||||||
// this only works within the comms servers domain, and won't work hypergrid
|
// this only works within the comms servers domain, and won't work hypergrid
|
||||||
// TODO:FIXME: Use a presense server of some kind to find out where the
|
// TODO:FIXME: Use a presense server of some kind to find out where the
|
||||||
// client actually is, and try contacting that region directly to notify them,
|
// client actually is, and try contacting that region directly to notify them,
|
||||||
// or provide the notification via xmlrpc update queue
|
// or provide the notification via xmlrpc update queue
|
||||||
if ((im.dialog == 210))
|
if ((im.dialog == 210))
|
||||||
|
@ -574,7 +635,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
{
|
{
|
||||||
return m_groupData.GetGroupRecord(UUID.Zero, UUID.Zero, name);
|
return m_groupData.GetGroupRecord(UUID.Zero, UUID.Zero, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ActivateGroup(IClientAPI remoteClient, UUID groupID)
|
public void ActivateGroup(IClientAPI remoteClient, UUID groupID)
|
||||||
{
|
{
|
||||||
if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
|
if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
|
||||||
|
@ -582,7 +643,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
m_groupData.SetAgentActiveGroup(GetRequestingAgentID(remoteClient), GetRequestingAgentID(remoteClient), groupID);
|
m_groupData.SetAgentActiveGroup(GetRequestingAgentID(remoteClient), GetRequestingAgentID(remoteClient), groupID);
|
||||||
|
|
||||||
// Changing active group changes title, active powers, all kinds of things
|
// Changing active group changes title, active powers, all kinds of things
|
||||||
// anyone who is in any region that can see this client, should probably be
|
// anyone who is in any region that can see this client, should probably be
|
||||||
// updated with new group info. At a minimum, they should get ScenePresence
|
// updated with new group info. At a minimum, they should get ScenePresence
|
||||||
// updated with new title.
|
// updated with new title.
|
||||||
UpdateAllClientsWithGroupInfo(GetRequestingAgentID(remoteClient));
|
UpdateAllClientsWithGroupInfo(GetRequestingAgentID(remoteClient));
|
||||||
|
@ -618,10 +679,10 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
|
|
||||||
public List<GroupMembersData> GroupMembersRequest(IClientAPI remoteClient, UUID groupID)
|
public List<GroupMembersData> GroupMembersRequest(IClientAPI remoteClient, UUID groupID)
|
||||||
{
|
{
|
||||||
if (m_debugEnabled)
|
if (m_debugEnabled)
|
||||||
m_log.DebugFormat(
|
m_log.DebugFormat(
|
||||||
"[GROUPS]: GroupMembersRequest called for {0} from client {1}", groupID, remoteClient.Name);
|
"[GROUPS]: GroupMembersRequest called for {0} from client {1}", groupID, remoteClient.Name);
|
||||||
|
|
||||||
List<GroupMembersData> data = m_groupData.GetGroupMembers(GetRequestingAgentID(remoteClient), groupID);
|
List<GroupMembersData> data = m_groupData.GetGroupMembers(GetRequestingAgentID(remoteClient), groupID);
|
||||||
|
|
||||||
if (m_debugEnabled)
|
if (m_debugEnabled)
|
||||||
|
@ -706,7 +767,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
|
|
||||||
public GroupMembershipData GetMembershipData(UUID groupID, UUID agentID)
|
public GroupMembershipData GetMembershipData(UUID groupID, UUID agentID)
|
||||||
{
|
{
|
||||||
if (m_debugEnabled)
|
if (m_debugEnabled)
|
||||||
m_log.DebugFormat(
|
m_log.DebugFormat(
|
||||||
"[GROUPS]: {0} called with groupID={1}, agentID={2}",
|
"[GROUPS]: {0} called with groupID={1}, agentID={2}",
|
||||||
System.Reflection.MethodBase.GetCurrentMethod().Name, groupID, agentID);
|
System.Reflection.MethodBase.GetCurrentMethod().Name, groupID, agentID);
|
||||||
|
@ -796,7 +857,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
if (membership != null)
|
if (membership != null)
|
||||||
{
|
{
|
||||||
return membership.GroupTitle;
|
return membership.GroupTitle;
|
||||||
}
|
}
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -812,7 +873,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
// TODO: Not sure what all is needed here, but if the active group role change is for the group
|
// TODO: Not sure what all is needed here, but if the active group role change is for the group
|
||||||
// the client currently has set active, then we need to do a scene presence update too
|
// the client currently has set active, then we need to do a scene presence update too
|
||||||
// if (m_groupData.GetAgentActiveMembership(GetRequestingAgentID(remoteClient)).GroupID == GroupID)
|
// if (m_groupData.GetAgentActiveMembership(GetRequestingAgentID(remoteClient)).GroupID == GroupID)
|
||||||
|
|
||||||
UpdateAllClientsWithGroupInfo(GetRequestingAgentID(remoteClient));
|
UpdateAllClientsWithGroupInfo(GetRequestingAgentID(remoteClient));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -870,7 +931,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
case 1:
|
case 1:
|
||||||
// Remove
|
// Remove
|
||||||
m_groupData.RemoveAgentFromGroupRole(GetRequestingAgentID(remoteClient), memberID, groupID, roleID);
|
m_groupData.RemoveAgentFromGroupRole(GetRequestingAgentID(remoteClient), memberID, groupID, roleID);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
m_log.ErrorFormat("[GROUPS]: {0} does not understand changes == {1}", System.Reflection.MethodBase.GetCurrentMethod().Name, changes);
|
m_log.ErrorFormat("[GROUPS]: {0} does not understand changes == {1}", System.Reflection.MethodBase.GetCurrentMethod().Name, changes);
|
||||||
|
@ -889,26 +950,10 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
|
|
||||||
if (data != null)
|
if (data != null)
|
||||||
{
|
{
|
||||||
GroupRecord groupInfo = m_groupData.GetGroupRecord(GetRequestingAgentID(remoteClient), data.GroupID, null);
|
GridInstantMessage msg = CreateGroupNoticeIM(remoteClient.AgentId, groupNoticeID, (byte)InstantMessageDialog.GroupNoticeRequested);
|
||||||
|
|
||||||
GridInstantMessage msg = new GridInstantMessage();
|
|
||||||
msg.imSessionID = UUID.Zero.Guid;
|
|
||||||
msg.fromAgentID = data.GroupID.Guid;
|
|
||||||
msg.toAgentID = GetRequestingAgentID(remoteClient).Guid;
|
|
||||||
msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
|
|
||||||
msg.fromAgentName = "Group Notice : " + groupInfo == null ? "Unknown" : groupInfo.GroupName;
|
|
||||||
msg.message = data.noticeData.Subject + "|" + data.Message;
|
|
||||||
msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.GroupNoticeRequested;
|
|
||||||
msg.fromGroup = true;
|
|
||||||
msg.offline = (byte)0;
|
|
||||||
msg.ParentEstateID = 0;
|
|
||||||
msg.Position = Vector3.Zero;
|
|
||||||
msg.RegionID = UUID.Zero.Guid;
|
|
||||||
msg.binaryBucket = data.BinaryBucket;
|
|
||||||
|
|
||||||
OutgoingInstantMessage(msg, GetRequestingAgentID(remoteClient));
|
OutgoingInstantMessage(msg, GetRequestingAgentID(remoteClient));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public GridInstantMessage CreateGroupNoticeIM(UUID agentID, UUID groupNoticeID, byte dialog)
|
public GridInstantMessage CreateGroupNoticeIM(UUID agentID, UUID groupNoticeID, byte dialog)
|
||||||
|
@ -916,10 +961,11 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
|
if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
|
||||||
|
|
||||||
GridInstantMessage msg = new GridInstantMessage();
|
GridInstantMessage msg = new GridInstantMessage();
|
||||||
msg.imSessionID = UUID.Zero.Guid;
|
byte[] bucket;
|
||||||
|
|
||||||
|
msg.imSessionID = groupNoticeID.Guid;
|
||||||
msg.toAgentID = agentID.Guid;
|
msg.toAgentID = agentID.Guid;
|
||||||
msg.dialog = dialog;
|
msg.dialog = dialog;
|
||||||
// msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.GroupNotice;
|
|
||||||
msg.fromGroup = true;
|
msg.fromGroup = true;
|
||||||
msg.offline = (byte)0;
|
msg.offline = (byte)0;
|
||||||
msg.ParentEstateID = 0;
|
msg.ParentEstateID = 0;
|
||||||
|
@ -933,13 +979,38 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
msg.timestamp = info.noticeData.Timestamp;
|
msg.timestamp = info.noticeData.Timestamp;
|
||||||
msg.fromAgentName = info.noticeData.FromName;
|
msg.fromAgentName = info.noticeData.FromName;
|
||||||
msg.message = info.noticeData.Subject + "|" + info.Message;
|
msg.message = info.noticeData.Subject + "|" + info.Message;
|
||||||
msg.binaryBucket = info.BinaryBucket;
|
|
||||||
|
if (info.BinaryBucket[0] > 0)
|
||||||
|
{
|
||||||
|
//32 is due to not needing space for two of the UUIDs.
|
||||||
|
//(Don't need UUID of attachment or its owner in IM)
|
||||||
|
//50 offset gets us to start of attachment name.
|
||||||
|
//We are skipping the attachment flag, type, and
|
||||||
|
//the three UUID fields at the start of the bucket.
|
||||||
|
bucket = new byte[info.BinaryBucket.Length-32];
|
||||||
|
bucket[0] = 1; //Has attachment
|
||||||
|
bucket[1] = info.BinaryBucket[1];
|
||||||
|
Array.Copy(info.BinaryBucket, 50,
|
||||||
|
bucket, 18, info.BinaryBucket.Length-50);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bucket = new byte[19];
|
||||||
|
bucket[0] = 0; //No attachment
|
||||||
|
bucket[1] = 0; //Attachment type
|
||||||
|
bucket[18] = 0; //NUL terminate name
|
||||||
|
}
|
||||||
|
|
||||||
|
info.GroupID.ToBytes(bucket, 2);
|
||||||
|
msg.binaryBucket = bucket;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: Group Notice {0} not found, composing empty message.", groupNoticeID);
|
if (m_debugEnabled)
|
||||||
|
m_log.DebugFormat("[GROUPS]: Group Notice {0} not found, composing empty message.", groupNoticeID);
|
||||||
|
|
||||||
msg.fromAgentID = UUID.Zero.Guid;
|
msg.fromAgentID = UUID.Zero.Guid;
|
||||||
msg.timestamp = (uint)Util.UnixTimeSinceEpoch(); ;
|
msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
|
||||||
msg.fromAgentName = string.Empty;
|
msg.fromAgentName = string.Empty;
|
||||||
msg.message = string.Empty;
|
msg.message = string.Empty;
|
||||||
msg.binaryBucket = new byte[0];
|
msg.binaryBucket = new byte[0];
|
||||||
|
@ -1042,7 +1113,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
|
|
||||||
// Send Message to Ejectee
|
// Send Message to Ejectee
|
||||||
GridInstantMessage msg = new GridInstantMessage();
|
GridInstantMessage msg = new GridInstantMessage();
|
||||||
|
|
||||||
msg.imSessionID = UUID.Zero.Guid;
|
msg.imSessionID = UUID.Zero.Guid;
|
||||||
msg.fromAgentID = agentID.Guid;
|
msg.fromAgentID = agentID.Guid;
|
||||||
// msg.fromAgentID = info.GroupID;
|
// msg.fromAgentID = info.GroupID;
|
||||||
|
@ -1063,7 +1134,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
// Message to ejector
|
// Message to ejector
|
||||||
// Interop, received special 210 code for ejecting a group member
|
// Interop, received special 210 code for ejecting a group member
|
||||||
// this only works within the comms servers domain, and won't work hypergrid
|
// this only works within the comms servers domain, and won't work hypergrid
|
||||||
// TODO:FIXME: Use a presense server of some kind to find out where the
|
// TODO:FIXME: Use a presense server of some kind to find out where the
|
||||||
// client actually is, and try contacting that region directly to notify them,
|
// client actually is, and try contacting that region directly to notify them,
|
||||||
// or provide the notification via xmlrpc update queue
|
// or provide the notification via xmlrpc update queue
|
||||||
|
|
||||||
|
@ -1232,7 +1303,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
{
|
{
|
||||||
if (!membership.ListInProfile)
|
if (!membership.ListInProfile)
|
||||||
{
|
{
|
||||||
// If we're sending group info to remoteclient about another agent,
|
// If we're sending group info to remoteclient about another agent,
|
||||||
// filter out groups the other agent doesn't want to share.
|
// filter out groups the other agent doesn't want to share.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1269,7 +1340,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
{
|
{
|
||||||
queue.Enqueue(queue.BuildEvent("AgentGroupDataUpdate", llDataStruct), GetRequestingAgentID(remoteClient));
|
queue.Enqueue(queue.BuildEvent("AgentGroupDataUpdate", llDataStruct), GetRequestingAgentID(remoteClient));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SendScenePresenceUpdate(UUID AgentID, string Title)
|
private void SendScenePresenceUpdate(UUID AgentID, string Title)
|
||||||
|
@ -1373,7 +1443,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
membershipArray = membershipData.ToArray();
|
membershipArray = membershipData.ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_debugEnabled)
|
if (m_debugEnabled)
|
||||||
{
|
{
|
||||||
m_log.InfoFormat("[GROUPS]: Get group membership information for {0} requested by {1}", dataForAgentID, requestingClient.AgentId);
|
m_log.InfoFormat("[GROUPS]: Get group membership information for {0} requested by {1}", dataForAgentID, requestingClient.AgentId);
|
||||||
|
@ -1386,7 +1456,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
return membershipArray;
|
return membershipArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void SendAgentDataUpdate(IClientAPI remoteClient, UUID dataForAgentID, UUID activeGroupID, string activeGroupName, ulong activeGroupPowers, string activeGroupTitle)
|
private void SendAgentDataUpdate(IClientAPI remoteClient, UUID dataForAgentID, UUID activeGroupID, string activeGroupName, ulong activeGroupPowers, string activeGroupTitle)
|
||||||
{
|
{
|
||||||
if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
|
if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
|
||||||
|
|
|
@ -146,7 +146,7 @@ namespace OpenSim.Region.OptionalModules.PhysicsParameters
|
||||||
{
|
{
|
||||||
foreach (PhysParameterEntry ppe in physScene.GetParameterList())
|
foreach (PhysParameterEntry ppe in physScene.GetParameterList())
|
||||||
{
|
{
|
||||||
float val = 0.0f;
|
string val = string.Empty;
|
||||||
if (physScene.GetPhysicsParameter(ppe.name, out val))
|
if (physScene.GetPhysicsParameter(ppe.name, out val))
|
||||||
{
|
{
|
||||||
WriteOut(" {0}/{1} = {2}", scene.RegionInfo.RegionName, ppe.name, val);
|
WriteOut(" {0}/{1} = {2}", scene.RegionInfo.RegionName, ppe.name, val);
|
||||||
|
@ -159,7 +159,7 @@ namespace OpenSim.Region.OptionalModules.PhysicsParameters
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
float val = 0.0f;
|
string val = string.Empty;
|
||||||
if (physScene.GetPhysicsParameter(parm, out val))
|
if (physScene.GetPhysicsParameter(parm, out val))
|
||||||
{
|
{
|
||||||
WriteOut(" {0}/{1} = {2}", scene.RegionInfo.RegionName, parm, val);
|
WriteOut(" {0}/{1} = {2}", scene.RegionInfo.RegionName, parm, val);
|
||||||
|
@ -185,21 +185,12 @@ namespace OpenSim.Region.OptionalModules.PhysicsParameters
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
string parm = "xxx";
|
string parm = "xxx";
|
||||||
float val = 0f;
|
string valparm = String.Empty;
|
||||||
uint localID = (uint)PhysParameterEntry.APPLY_TO_NONE; // set default value
|
uint localID = (uint)PhysParameterEntry.APPLY_TO_NONE; // set default value
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
parm = cmdparms[2];
|
parm = cmdparms[2];
|
||||||
string valparm = cmdparms[3].ToLower();
|
valparm = cmdparms[3].ToLower();
|
||||||
if (valparm == "true")
|
|
||||||
val = PhysParameterEntry.NUMERIC_TRUE;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (valparm == "false")
|
|
||||||
val = PhysParameterEntry.NUMERIC_FALSE;
|
|
||||||
else
|
|
||||||
val = float.Parse(valparm, Culture.NumberFormatInfo);
|
|
||||||
}
|
|
||||||
if (cmdparms.Length > 4)
|
if (cmdparms.Length > 4)
|
||||||
{
|
{
|
||||||
if (cmdparms[4].ToLower() == "all")
|
if (cmdparms[4].ToLower() == "all")
|
||||||
|
@ -224,7 +215,7 @@ namespace OpenSim.Region.OptionalModules.PhysicsParameters
|
||||||
IPhysicsParameters physScene = scene.PhysicsScene as IPhysicsParameters;
|
IPhysicsParameters physScene = scene.PhysicsScene as IPhysicsParameters;
|
||||||
if (physScene != null)
|
if (physScene != null)
|
||||||
{
|
{
|
||||||
if (!physScene.SetPhysicsParameter(parm, val, localID))
|
if (!physScene.SetPhysicsParameter(parm, valparm, localID))
|
||||||
{
|
{
|
||||||
WriteError("Failed set of parameter '{0}' for region '{1}'", parm, scene.RegionInfo.RegionName);
|
WriteError("Failed set of parameter '{0}' for region '{1}'", parm, scene.RegionInfo.RegionName);
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
|
||||||
/// (such as land transfers). There is no money code here! Use FORGE as an example for money code.
|
/// (such as land transfers). There is no money code here! Use FORGE as an example for money code.
|
||||||
/// Demo Economy/Money Module. This is a purposely crippled module!
|
/// Demo Economy/Money Module. This is a purposely crippled module!
|
||||||
/// // To land transfer you need to add:
|
/// // To land transfer you need to add:
|
||||||
/// -helperuri <ADDRESS TO THIS SERVER>
|
/// -helperuri http://serveraddress:port/
|
||||||
/// to the command line parameters you use to start up your client
|
/// to the command line parameters you use to start up your client
|
||||||
/// This commonly looks like -helperuri http://127.0.0.1:9000/
|
/// This commonly looks like -helperuri http://127.0.0.1:9000/
|
||||||
///
|
///
|
||||||
|
@ -116,10 +116,9 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Startup
|
/// Called on startup so the module can be configured.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="scene"></param>
|
/// <param name="config">Configuration source.</param>
|
||||||
/// <param name="config"></param>
|
|
||||||
public void Initialise(IConfigSource config)
|
public void Initialise(IConfigSource config)
|
||||||
{
|
{
|
||||||
m_gConfig = config;
|
m_gConfig = config;
|
||||||
|
@ -674,9 +673,12 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// When the client closes the connection we remove their accounting info from memory to free up resources.
|
/// When the client closes the connection we remove their accounting
|
||||||
|
/// info from memory to free up resources.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="AgentID"></param>
|
/// <param name="AgentID">UUID of agent</param>
|
||||||
|
/// <param name="scene">Scene the agent was connected to.</param>
|
||||||
|
/// <see cref="OpenSim.Region.Framework.Scenes.EventManager.ClientClosed"/>
|
||||||
public void ClientClosed(UUID AgentID, Scene scene)
|
public void ClientClosed(UUID AgentID, Scene scene)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -74,6 +74,8 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void Init()
|
public void Init()
|
||||||
{
|
{
|
||||||
|
base.SetUp();
|
||||||
|
|
||||||
IConfigSource config = new IniConfigSource();
|
IConfigSource config = new IniConfigSource();
|
||||||
config.AddConfig("NPC");
|
config.AddConfig("NPC");
|
||||||
config.Configs["NPC"].Set("Enabled", "true");
|
config.Configs["NPC"].Set("Enabled", "true");
|
||||||
|
|
|
@ -0,0 +1,235 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Contributors, http://opensimulator.org/
|
||||||
|
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the OpenSimulator Project nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using log4net;
|
||||||
|
using Mono.Addins;
|
||||||
|
using Nini.Config;
|
||||||
|
using OpenMetaverse;
|
||||||
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Framework.Console;
|
||||||
|
using OpenSim.Framework.Monitoring;
|
||||||
|
using OpenSim.Region.Framework.Interfaces;
|
||||||
|
using OpenSim.Region.Framework.Scenes;
|
||||||
|
|
||||||
|
namespace OpenSim.Region.OptionalModules.Avatar.Attachments
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A module that just holds commands for inspecting avatar appearance.
|
||||||
|
/// </summary>
|
||||||
|
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SceneCommandsModule")]
|
||||||
|
public class SceneCommandsModule : ISceneCommandsModule, INonSharedRegionModule
|
||||||
|
{
|
||||||
|
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
|
private Scene m_scene;
|
||||||
|
|
||||||
|
public string Name { get { return "Scene Commands Module"; } }
|
||||||
|
|
||||||
|
public Type ReplaceableInterface { get { return null; } }
|
||||||
|
|
||||||
|
public void Initialise(IConfigSource source)
|
||||||
|
{
|
||||||
|
// m_log.DebugFormat("[SCENE COMMANDS MODULE]: INITIALIZED MODULE");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PostInitialise()
|
||||||
|
{
|
||||||
|
// m_log.DebugFormat("[SCENE COMMANDS MODULE]: POST INITIALIZED MODULE");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Close()
|
||||||
|
{
|
||||||
|
// m_log.DebugFormat("[SCENE COMMANDS MODULE]: CLOSED MODULE");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddRegion(Scene scene)
|
||||||
|
{
|
||||||
|
// m_log.DebugFormat("[SCENE COMMANDS MODULE]: REGION {0} ADDED", scene.RegionInfo.RegionName);
|
||||||
|
|
||||||
|
m_scene = scene;
|
||||||
|
|
||||||
|
m_scene.RegisterModuleInterface<ISceneCommandsModule>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveRegion(Scene scene)
|
||||||
|
{
|
||||||
|
// m_log.DebugFormat("[SCENE COMMANDS MODULE]: REGION {0} REMOVED", scene.RegionInfo.RegionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RegionLoaded(Scene scene)
|
||||||
|
{
|
||||||
|
// m_log.DebugFormat("[ATTACHMENTS COMMAND MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName);
|
||||||
|
|
||||||
|
scene.AddCommand(
|
||||||
|
"Debug", this, "debug scene get",
|
||||||
|
"debug scene get",
|
||||||
|
"List current scene options.",
|
||||||
|
"If active is false then main scene update and maintenance loops are suspended.\n"
|
||||||
|
+ "If animations is true then extra animations debug information is logged.\n"
|
||||||
|
+ "If collisions is false then collisions with other objects are turned off.\n"
|
||||||
|
+ "If pbackup is false then periodic scene backup is turned off.\n"
|
||||||
|
+ "If physics is false then all physics objects are non-physical.\n"
|
||||||
|
+ "If scripting is false then no scripting operations happen.\n"
|
||||||
|
+ "If teleport is true then some extra teleport debug information is logged.\n"
|
||||||
|
+ "If updates is true then any frame which exceeds double the maximum desired frame time is logged.",
|
||||||
|
HandleDebugSceneGetCommand);
|
||||||
|
|
||||||
|
scene.AddCommand(
|
||||||
|
"Debug", this, "debug scene set",
|
||||||
|
"debug scene set active|collisions|pbackup|physics|scripting|teleport|updates true|false",
|
||||||
|
"Turn on scene debugging options.",
|
||||||
|
"If active is false then main scene update and maintenance loops are suspended.\n"
|
||||||
|
+ "If animations is true then extra animations debug information is logged.\n"
|
||||||
|
+ "If collisions is false then collisions with other objects are turned off.\n"
|
||||||
|
+ "If pbackup is false then periodic scene backup is turned off.\n"
|
||||||
|
+ "If physics is false then all physics objects are non-physical.\n"
|
||||||
|
+ "If scripting is false then no scripting operations happen.\n"
|
||||||
|
+ "If teleport is true then some extra teleport debug information is logged.\n"
|
||||||
|
+ "If updates is true then any frame which exceeds double the maximum desired frame time is logged.",
|
||||||
|
HandleDebugSceneSetCommand);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleDebugSceneGetCommand(string module, string[] args)
|
||||||
|
{
|
||||||
|
if (args.Length == 3)
|
||||||
|
{
|
||||||
|
if (MainConsole.Instance.ConsoleScene != m_scene && MainConsole.Instance.ConsoleScene != null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
OutputSceneDebugOptions();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MainConsole.Instance.Output("Usage: debug scene get");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OutputSceneDebugOptions()
|
||||||
|
{
|
||||||
|
ConsoleDisplayList cdl = new ConsoleDisplayList();
|
||||||
|
cdl.AddRow("active", m_scene.Active);
|
||||||
|
cdl.AddRow("animations", m_scene.DebugAnimations);
|
||||||
|
cdl.AddRow("pbackup", m_scene.PeriodicBackup);
|
||||||
|
cdl.AddRow("physics", m_scene.PhysicsEnabled);
|
||||||
|
cdl.AddRow("scripting", m_scene.ScriptsEnabled);
|
||||||
|
cdl.AddRow("teleport", m_scene.DebugTeleporting);
|
||||||
|
cdl.AddRow("updates", m_scene.DebugUpdates);
|
||||||
|
|
||||||
|
MainConsole.Instance.OutputFormat("Scene {0} options:", m_scene.Name);
|
||||||
|
MainConsole.Instance.Output(cdl.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleDebugSceneSetCommand(string module, string[] args)
|
||||||
|
{
|
||||||
|
if (args.Length == 5)
|
||||||
|
{
|
||||||
|
if (MainConsole.Instance.ConsoleScene != m_scene && MainConsole.Instance.ConsoleScene != null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
string key = args[3];
|
||||||
|
string value = args[4];
|
||||||
|
SetSceneDebugOptions(new Dictionary<string, string>() { { key, value } });
|
||||||
|
|
||||||
|
MainConsole.Instance.OutputFormat("Set {0} debug scene {1} = {2}", m_scene.Name, key, value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MainConsole.Instance.Output(
|
||||||
|
"Usage: debug scene set active|collisions|pbackup|physics|scripting|teleport|updates true|false");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetSceneDebugOptions(Dictionary<string, string> options)
|
||||||
|
{
|
||||||
|
if (options.ContainsKey("active"))
|
||||||
|
{
|
||||||
|
bool active;
|
||||||
|
|
||||||
|
if (bool.TryParse(options["active"], out active))
|
||||||
|
m_scene.Active = active;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.ContainsKey("animations"))
|
||||||
|
{
|
||||||
|
bool active;
|
||||||
|
|
||||||
|
if (bool.TryParse(options["animations"], out active))
|
||||||
|
m_scene.DebugAnimations = active;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.ContainsKey("pbackup"))
|
||||||
|
{
|
||||||
|
bool active;
|
||||||
|
|
||||||
|
if (bool.TryParse(options["pbackup"], out active))
|
||||||
|
m_scene.PeriodicBackup = active;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.ContainsKey("scripting"))
|
||||||
|
{
|
||||||
|
bool enableScripts = true;
|
||||||
|
if (bool.TryParse(options["scripting"], out enableScripts))
|
||||||
|
m_scene.ScriptsEnabled = enableScripts;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.ContainsKey("physics"))
|
||||||
|
{
|
||||||
|
bool enablePhysics;
|
||||||
|
if (bool.TryParse(options["physics"], out enablePhysics))
|
||||||
|
m_scene.PhysicsEnabled = enablePhysics;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (options.ContainsKey("collisions"))
|
||||||
|
// {
|
||||||
|
// // TODO: Implement. If false, should stop objects colliding, though possibly should still allow
|
||||||
|
// // the avatar themselves to collide with the ground.
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (options.ContainsKey("teleport"))
|
||||||
|
{
|
||||||
|
bool enableTeleportDebugging;
|
||||||
|
if (bool.TryParse(options["teleport"], out enableTeleportDebugging))
|
||||||
|
m_scene.DebugTeleporting = enableTeleportDebugging;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.ContainsKey("updates"))
|
||||||
|
{
|
||||||
|
bool enableUpdateDebugging;
|
||||||
|
if (bool.TryParse(options["updates"], out enableUpdateDebugging))
|
||||||
|
{
|
||||||
|
m_scene.DebugUpdates = enableUpdateDebugging;
|
||||||
|
GcNotify.Enabled = enableUpdateDebugging;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -75,11 +75,11 @@ private sealed class BulletBodyUnman : BulletBody
|
||||||
private sealed class BulletShapeUnman : BulletShape
|
private sealed class BulletShapeUnman : BulletShape
|
||||||
{
|
{
|
||||||
public IntPtr ptr;
|
public IntPtr ptr;
|
||||||
public BulletShapeUnman(IntPtr xx, BSPhysicsShapeType typ)
|
public BulletShapeUnman(IntPtr xx, BSPhysicsShapeType typ)
|
||||||
: base()
|
: base()
|
||||||
{
|
{
|
||||||
ptr = xx;
|
ptr = xx;
|
||||||
type = typ;
|
shapeType = typ;
|
||||||
}
|
}
|
||||||
public override bool HasPhysicalShape
|
public override bool HasPhysicalShape
|
||||||
{
|
{
|
||||||
|
@ -91,7 +91,7 @@ private sealed class BulletShapeUnman : BulletShape
|
||||||
}
|
}
|
||||||
public override BulletShape Clone()
|
public override BulletShape Clone()
|
||||||
{
|
{
|
||||||
return new BulletShapeUnman(ptr, type);
|
return new BulletShapeUnman(ptr, shapeType);
|
||||||
}
|
}
|
||||||
public override bool ReferenceSame(BulletShape other)
|
public override bool ReferenceSame(BulletShape other)
|
||||||
{
|
{
|
||||||
|
@ -166,7 +166,7 @@ public override BulletWorld Initialize(Vector3 maxPosition, ConfigurationParamet
|
||||||
|
|
||||||
// If Debug logging level, enable logging from the unmanaged code
|
// If Debug logging level, enable logging from the unmanaged code
|
||||||
m_DebugLogCallbackHandle = null;
|
m_DebugLogCallbackHandle = null;
|
||||||
if (BSScene.m_log.IsDebugEnabled || PhysicsScene.PhysicsLogging.Enabled)
|
if (BSScene.m_log.IsDebugEnabled && PhysicsScene.PhysicsLogging.Enabled)
|
||||||
{
|
{
|
||||||
BSScene.m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", BSScene.LogHeader);
|
BSScene.m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", BSScene.LogHeader);
|
||||||
if (PhysicsScene.PhysicsLogging.Enabled)
|
if (PhysicsScene.PhysicsLogging.Enabled)
|
||||||
|
@ -202,7 +202,7 @@ private void BulletLoggerPhysLog(string msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep,
|
public override int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep,
|
||||||
out int updatedEntityCount, out int collidersCount)
|
out int updatedEntityCount, out int collidersCount)
|
||||||
{
|
{
|
||||||
BulletWorldUnman worldu = world as BulletWorldUnman;
|
BulletWorldUnman worldu = world as BulletWorldUnman;
|
||||||
return BSAPICPP.PhysicsStep2(worldu.ptr, timeStep, maxSubSteps, fixedTimeStep, out updatedEntityCount, out collidersCount);
|
return BSAPICPP.PhysicsStep2(worldu.ptr, timeStep, maxSubSteps, fixedTimeStep, out updatedEntityCount, out collidersCount);
|
||||||
|
@ -212,6 +212,19 @@ public override void Shutdown(BulletWorld world)
|
||||||
{
|
{
|
||||||
BulletWorldUnman worldu = world as BulletWorldUnman;
|
BulletWorldUnman worldu = world as BulletWorldUnman;
|
||||||
BSAPICPP.Shutdown2(worldu.ptr);
|
BSAPICPP.Shutdown2(worldu.ptr);
|
||||||
|
|
||||||
|
if (m_paramsHandle.IsAllocated)
|
||||||
|
{
|
||||||
|
m_paramsHandle.Free();
|
||||||
|
}
|
||||||
|
if (m_collisionArrayPinnedHandle.IsAllocated)
|
||||||
|
{
|
||||||
|
m_collisionArrayPinnedHandle.Free();
|
||||||
|
}
|
||||||
|
if (m_updateArrayPinnedHandle.IsAllocated)
|
||||||
|
{
|
||||||
|
m_updateArrayPinnedHandle.Free();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool PushUpdate(BulletBody obj)
|
public override bool PushUpdate(BulletBody obj)
|
||||||
|
@ -242,19 +255,38 @@ public override BulletShape CreateHullShape(BulletWorld world, int hullCount, fl
|
||||||
{
|
{
|
||||||
BulletWorldUnman worldu = world as BulletWorldUnman;
|
BulletWorldUnman worldu = world as BulletWorldUnman;
|
||||||
return new BulletShapeUnman(
|
return new BulletShapeUnman(
|
||||||
BSAPICPP.CreateHullShape2(worldu.ptr, hullCount, hulls),
|
BSAPICPP.CreateHullShape2(worldu.ptr, hullCount, hulls),
|
||||||
BSPhysicsShapeType.SHAPE_HULL);
|
BSPhysicsShapeType.SHAPE_HULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape)
|
public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms)
|
||||||
{
|
{
|
||||||
BulletWorldUnman worldu = world as BulletWorldUnman;
|
BulletWorldUnman worldu = world as BulletWorldUnman;
|
||||||
BulletShapeUnman shapeu = meshShape as BulletShapeUnman;
|
BulletShapeUnman shapeu = meshShape as BulletShapeUnman;
|
||||||
return new BulletShapeUnman(
|
return new BulletShapeUnman(
|
||||||
BSAPICPP.BuildHullShapeFromMesh2(worldu.ptr, shapeu.ptr),
|
BSAPICPP.BuildHullShapeFromMesh2(worldu.ptr, shapeu.ptr, parms),
|
||||||
BSPhysicsShapeType.SHAPE_HULL);
|
BSPhysicsShapeType.SHAPE_HULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape)
|
||||||
|
{
|
||||||
|
BulletWorldUnman worldu = world as BulletWorldUnman;
|
||||||
|
BulletShapeUnman shapeu = meshShape as BulletShapeUnman;
|
||||||
|
return new BulletShapeUnman(
|
||||||
|
BSAPICPP.BuildConvexHullShapeFromMesh2(worldu.ptr, shapeu.ptr),
|
||||||
|
BSPhysicsShapeType.SHAPE_CONVEXHULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override BulletShape CreateConvexHullShape(BulletWorld world,
|
||||||
|
int indicesCount, int[] indices,
|
||||||
|
int verticesCount, float[] vertices)
|
||||||
|
{
|
||||||
|
BulletWorldUnman worldu = world as BulletWorldUnman;
|
||||||
|
return new BulletShapeUnman(
|
||||||
|
BSAPICPP.CreateConvexHullShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices),
|
||||||
|
BSPhysicsShapeType.SHAPE_CONVEXHULL);
|
||||||
|
}
|
||||||
|
|
||||||
public override BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData)
|
public override BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData)
|
||||||
{
|
{
|
||||||
BulletWorldUnman worldu = world as BulletWorldUnman;
|
BulletWorldUnman worldu = world as BulletWorldUnman;
|
||||||
|
@ -273,7 +305,7 @@ public override void SetShapeCollisionMargin(BulletShape shape, float margin)
|
||||||
{
|
{
|
||||||
BulletShapeUnman shapeu = shape as BulletShapeUnman;
|
BulletShapeUnman shapeu = shape as BulletShapeUnman;
|
||||||
if (shapeu != null && shapeu.HasPhysicalShape)
|
if (shapeu != null && shapeu.HasPhysicalShape)
|
||||||
BSAPICPP.SetShapeCollisionMargin2(shapeu.ptr, margin);
|
BSAPICPP.SetShapeCollisionMargin(shapeu.ptr, margin);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale)
|
public override BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale)
|
||||||
|
@ -327,6 +359,12 @@ public override void RemoveChildShapeFromCompoundShape(BulletShape shape, Bullet
|
||||||
BSAPICPP.RemoveChildShapeFromCompoundShape2(shapeu.ptr, removeShapeu.ptr);
|
BSAPICPP.RemoveChildShapeFromCompoundShape2(shapeu.ptr, removeShapeu.ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb)
|
||||||
|
{
|
||||||
|
BulletShapeUnman shapeu = pShape as BulletShapeUnman;
|
||||||
|
BSAPICPP.UpdateChildTransform2(shapeu.ptr, childIndex, pos, rot, shouldRecalculateLocalAabb);
|
||||||
|
}
|
||||||
|
|
||||||
public override void RecalculateCompoundShapeLocalAabb(BulletShape shape)
|
public override void RecalculateCompoundShapeLocalAabb(BulletShape shape)
|
||||||
{
|
{
|
||||||
BulletShapeUnman shapeu = shape as BulletShapeUnman;
|
BulletShapeUnman shapeu = shape as BulletShapeUnman;
|
||||||
|
@ -337,7 +375,7 @@ public override BulletShape DuplicateCollisionShape(BulletWorld world, BulletSha
|
||||||
{
|
{
|
||||||
BulletWorldUnman worldu = world as BulletWorldUnman;
|
BulletWorldUnman worldu = world as BulletWorldUnman;
|
||||||
BulletShapeUnman srcShapeu = srcShape as BulletShapeUnman;
|
BulletShapeUnman srcShapeu = srcShape as BulletShapeUnman;
|
||||||
return new BulletShapeUnman(BSAPICPP.DuplicateCollisionShape2(worldu.ptr, srcShapeu.ptr, id), srcShape.type);
|
return new BulletShapeUnman(BSAPICPP.DuplicateCollisionShape2(worldu.ptr, srcShapeu.ptr, id), srcShape.shapeType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool DeleteCollisionShape(BulletWorld world, BulletShape shape)
|
public override bool DeleteCollisionShape(BulletWorld world, BulletShape shape)
|
||||||
|
@ -419,6 +457,28 @@ public override BulletConstraint Create6DofConstraintToPoint(BulletWorld world,
|
||||||
joinPoint, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
|
joinPoint, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1,
|
||||||
|
Vector3 frameInBloc, Quaternion frameInBrot,
|
||||||
|
bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies)
|
||||||
|
{
|
||||||
|
BulletWorldUnman worldu = world as BulletWorldUnman;
|
||||||
|
BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
|
||||||
|
return new BulletConstraintUnman(BSAPICPP.Create6DofConstraintFixed2(worldu.ptr, bodyu1.ptr,
|
||||||
|
frameInBloc, frameInBrot, useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
|
||||||
|
Vector3 frame1loc, Quaternion frame1rot,
|
||||||
|
Vector3 frame2loc, Quaternion frame2rot,
|
||||||
|
bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
|
||||||
|
{
|
||||||
|
BulletWorldUnman worldu = world as BulletWorldUnman;
|
||||||
|
BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
|
||||||
|
BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
|
||||||
|
return new BulletConstraintUnman(BSAPICPP.Create6DofSpringConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot,
|
||||||
|
frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
|
||||||
|
}
|
||||||
|
|
||||||
public override BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
|
public override BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
|
||||||
Vector3 pivotinA, Vector3 pivotinB,
|
Vector3 pivotinA, Vector3 pivotinB,
|
||||||
Vector3 axisInA, Vector3 axisInB,
|
Vector3 axisInA, Vector3 axisInB,
|
||||||
|
@ -431,6 +491,52 @@ public override BulletConstraint CreateHingeConstraint(BulletWorld world, Bullet
|
||||||
pivotinA, pivotinB, axisInA, axisInB, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
|
pivotinA, pivotinB, axisInA, axisInB, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override BulletConstraint CreateSliderConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
|
||||||
|
Vector3 frame1loc, Quaternion frame1rot,
|
||||||
|
Vector3 frame2loc, Quaternion frame2rot,
|
||||||
|
bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
|
||||||
|
{
|
||||||
|
BulletWorldUnman worldu = world as BulletWorldUnman;
|
||||||
|
BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
|
||||||
|
BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
|
||||||
|
return new BulletConstraintUnman(BSAPICPP.CreateSliderConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot,
|
||||||
|
frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override BulletConstraint CreateConeTwistConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
|
||||||
|
Vector3 frame1loc, Quaternion frame1rot,
|
||||||
|
Vector3 frame2loc, Quaternion frame2rot,
|
||||||
|
bool disableCollisionsBetweenLinkedBodies)
|
||||||
|
{
|
||||||
|
BulletWorldUnman worldu = world as BulletWorldUnman;
|
||||||
|
BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
|
||||||
|
BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
|
||||||
|
return new BulletConstraintUnman(BSAPICPP.CreateConeTwistConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot,
|
||||||
|
frame2loc, frame2rot, disableCollisionsBetweenLinkedBodies));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override BulletConstraint CreateGearConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
|
||||||
|
Vector3 axisInA, Vector3 axisInB,
|
||||||
|
float ratio, bool disableCollisionsBetweenLinkedBodies)
|
||||||
|
{
|
||||||
|
BulletWorldUnman worldu = world as BulletWorldUnman;
|
||||||
|
BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
|
||||||
|
BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
|
||||||
|
return new BulletConstraintUnman(BSAPICPP.CreateGearConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, axisInA, axisInB,
|
||||||
|
ratio, disableCollisionsBetweenLinkedBodies));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override BulletConstraint CreatePoint2PointConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
|
||||||
|
Vector3 pivotInA, Vector3 pivotInB,
|
||||||
|
bool disableCollisionsBetweenLinkedBodies)
|
||||||
|
{
|
||||||
|
BulletWorldUnman worldu = world as BulletWorldUnman;
|
||||||
|
BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
|
||||||
|
BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
|
||||||
|
return new BulletConstraintUnman(BSAPICPP.CreatePoint2PointConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, pivotInA, pivotInB,
|
||||||
|
disableCollisionsBetweenLinkedBodies));
|
||||||
|
}
|
||||||
|
|
||||||
public override void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse)
|
public override void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse)
|
||||||
{
|
{
|
||||||
BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
|
BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
|
||||||
|
@ -530,12 +636,12 @@ public override void SetForceUpdateAllAabbs(BulletWorld world, bool force)
|
||||||
// btDynamicsWorld entries
|
// btDynamicsWorld entries
|
||||||
public override bool AddObjectToWorld(BulletWorld world, BulletBody obj)
|
public override bool AddObjectToWorld(BulletWorld world, BulletBody obj)
|
||||||
{
|
{
|
||||||
// Bullet resets several variables when an object is added to the world.
|
|
||||||
// Gravity is reset to world default depending on the static/dynamic
|
|
||||||
// type. Of course, the collision flags in the broadphase proxy are initialized to default.
|
|
||||||
BulletWorldUnman worldu = world as BulletWorldUnman;
|
BulletWorldUnman worldu = world as BulletWorldUnman;
|
||||||
BulletBodyUnman bodyu = obj as BulletBodyUnman;
|
BulletBodyUnman bodyu = obj as BulletBodyUnman;
|
||||||
|
|
||||||
|
// Bullet resets several variables when an object is added to the world.
|
||||||
|
// Gravity is reset to world default depending on the static/dynamic
|
||||||
|
// type. Of course, the collision flags in the broadphase proxy are initialized to default.
|
||||||
Vector3 origGrav = BSAPICPP.GetGravity2(bodyu.ptr);
|
Vector3 origGrav = BSAPICPP.GetGravity2(bodyu.ptr);
|
||||||
|
|
||||||
bool ret = BSAPICPP.AddObjectToWorld2(worldu.ptr, bodyu.ptr);
|
bool ret = BSAPICPP.AddObjectToWorld2(worldu.ptr, bodyu.ptr);
|
||||||
|
@ -921,6 +1027,7 @@ public override void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quater
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a force to the object as if its mass is one.
|
// Add a force to the object as if its mass is one.
|
||||||
|
// Deep down in Bullet: m_totalForce += force*m_linearFactor;
|
||||||
public override void ApplyCentralForce(BulletBody obj, Vector3 force)
|
public override void ApplyCentralForce(BulletBody obj, Vector3 force)
|
||||||
{
|
{
|
||||||
BulletBodyUnman bodyu = obj as BulletBodyUnman;
|
BulletBodyUnman bodyu = obj as BulletBodyUnman;
|
||||||
|
@ -964,6 +1071,7 @@ public override void SetSleepingThresholds(BulletBody obj, float lin_threshold,
|
||||||
BSAPICPP.SetSleepingThresholds2(bodyu.ptr, lin_threshold, ang_threshold);
|
BSAPICPP.SetSleepingThresholds2(bodyu.ptr, lin_threshold, ang_threshold);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deep down in Bullet: m_totalTorque += torque*m_angularFactor;
|
||||||
public override void ApplyTorque(BulletBody obj, Vector3 torque)
|
public override void ApplyTorque(BulletBody obj, Vector3 torque)
|
||||||
{
|
{
|
||||||
BulletBodyUnman bodyu = obj as BulletBodyUnman;
|
BulletBodyUnman bodyu = obj as BulletBodyUnman;
|
||||||
|
@ -971,6 +1079,8 @@ public override void ApplyTorque(BulletBody obj, Vector3 torque)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply force at the given point. Will add torque to the object.
|
// Apply force at the given point. Will add torque to the object.
|
||||||
|
// Deep down in Bullet: applyCentralForce(force);
|
||||||
|
// applyTorque(rel_pos.cross(force*m_linearFactor));
|
||||||
public override void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos)
|
public override void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos)
|
||||||
{
|
{
|
||||||
BulletBodyUnman bodyu = obj as BulletBodyUnman;
|
BulletBodyUnman bodyu = obj as BulletBodyUnman;
|
||||||
|
@ -978,6 +1088,7 @@ public override void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
|
// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
|
||||||
|
// Deep down in Bullet: m_linearVelocity += impulse *m_linearFactor * m_inverseMass;
|
||||||
public override void ApplyCentralImpulse(BulletBody obj, Vector3 imp)
|
public override void ApplyCentralImpulse(BulletBody obj, Vector3 imp)
|
||||||
{
|
{
|
||||||
BulletBodyUnman bodyu = obj as BulletBodyUnman;
|
BulletBodyUnman bodyu = obj as BulletBodyUnman;
|
||||||
|
@ -985,6 +1096,7 @@ public override void ApplyCentralImpulse(BulletBody obj, Vector3 imp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply impulse to the object's torque. Force is scaled by object's mass.
|
// Apply impulse to the object's torque. Force is scaled by object's mass.
|
||||||
|
// Deep down in Bullet: m_angularVelocity += m_invInertiaTensorWorld * torque * m_angularFactor;
|
||||||
public override void ApplyTorqueImpulse(BulletBody obj, Vector3 imp)
|
public override void ApplyTorqueImpulse(BulletBody obj, Vector3 imp)
|
||||||
{
|
{
|
||||||
BulletBodyUnman bodyu = obj as BulletBodyUnman;
|
BulletBodyUnman bodyu = obj as BulletBodyUnman;
|
||||||
|
@ -992,6 +1104,8 @@ public override void ApplyTorqueImpulse(BulletBody obj, Vector3 imp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
|
// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
|
||||||
|
// Deep down in Bullet: applyCentralImpulse(impulse);
|
||||||
|
// applyTorqueImpulse(rel_pos.cross(impulse*m_linearFactor));
|
||||||
public override void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos)
|
public override void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos)
|
||||||
{
|
{
|
||||||
BulletBodyUnman bodyu = obj as BulletBodyUnman;
|
BulletBodyUnman bodyu = obj as BulletBodyUnman;
|
||||||
|
@ -1259,6 +1373,16 @@ public override void DumpPhysicsStatistics(BulletWorld world)
|
||||||
BulletWorldUnman worldu = world as BulletWorldUnman;
|
BulletWorldUnman worldu = world as BulletWorldUnman;
|
||||||
BSAPICPP.DumpPhysicsStatistics2(worldu.ptr);
|
BSAPICPP.DumpPhysicsStatistics2(worldu.ptr);
|
||||||
}
|
}
|
||||||
|
public override void ResetBroadphasePool(BulletWorld world)
|
||||||
|
{
|
||||||
|
BulletWorldUnman worldu = world as BulletWorldUnman;
|
||||||
|
BSAPICPP.ResetBroadphasePool(worldu.ptr);
|
||||||
|
}
|
||||||
|
public override void ResetConstraintSolver(BulletWorld world)
|
||||||
|
{
|
||||||
|
BulletWorldUnman worldu = world as BulletWorldUnman;
|
||||||
|
BSAPICPP.ResetConstraintSolver(worldu.ptr);
|
||||||
|
}
|
||||||
|
|
||||||
// =====================================================================================
|
// =====================================================================================
|
||||||
// =====================================================================================
|
// =====================================================================================
|
||||||
|
@ -1306,7 +1430,15 @@ public static extern IntPtr CreateHullShape2(IntPtr world,
|
||||||
int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls);
|
int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls);
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape);
|
public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape, HACDParams parms);
|
||||||
|
|
||||||
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
|
public static extern IntPtr BuildConvexHullShapeFromMesh2(IntPtr world, IntPtr meshShape);
|
||||||
|
|
||||||
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
|
public static extern IntPtr CreateConvexHullShape2(IntPtr world,
|
||||||
|
int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
|
||||||
|
int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices );
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData);
|
public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData);
|
||||||
|
@ -1315,7 +1447,7 @@ public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData)
|
||||||
public static extern bool IsNativeShape2(IntPtr shape);
|
public static extern bool IsNativeShape2(IntPtr shape);
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
public static extern void SetShapeCollisionMargin2(IntPtr shape, float margin);
|
public static extern void SetShapeCollisionMargin(IntPtr shape, float margin);
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
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);
|
||||||
|
@ -1338,6 +1470,9 @@ public static extern IntPtr RemoveChildShapeFromCompoundShapeIndex2(IntPtr cShap
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape);
|
public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape);
|
||||||
|
|
||||||
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
|
public static extern void UpdateChildTransform2(IntPtr pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb);
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
public static extern void RecalculateCompoundShapeLocalAabb2(IntPtr cShape);
|
public static extern void RecalculateCompoundShapeLocalAabb2(IntPtr cShape);
|
||||||
|
|
||||||
|
@ -1368,7 +1503,7 @@ public static extern void DestroyObject2(IntPtr sim, IntPtr obj);
|
||||||
public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin);
|
public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin);
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight,
|
public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight,
|
||||||
[MarshalAs(UnmanagedType.LPArray)] float[] heightMap,
|
[MarshalAs(UnmanagedType.LPArray)] float[] heightMap,
|
||||||
float scaleFactor, float collisionMargin);
|
float scaleFactor, float collisionMargin);
|
||||||
|
|
||||||
|
@ -1385,12 +1520,46 @@ public static extern IntPtr Create6DofConstraintToPoint2(IntPtr world, IntPtr ob
|
||||||
Vector3 joinPoint,
|
Vector3 joinPoint,
|
||||||
bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
|
bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
|
||||||
|
|
||||||
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
|
public static extern IntPtr Create6DofConstraintFixed2(IntPtr world, IntPtr obj1,
|
||||||
|
Vector3 frameInBloc, Quaternion frameInBrot,
|
||||||
|
bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies);
|
||||||
|
|
||||||
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
|
public static extern IntPtr Create6DofSpringConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
|
||||||
|
Vector3 frame1loc, Quaternion frame1rot,
|
||||||
|
Vector3 frame2loc, Quaternion frame2rot,
|
||||||
|
bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
public static extern IntPtr CreateHingeConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
|
public static extern IntPtr CreateHingeConstraint2(IntPtr world, IntPtr obj1, IntPtr 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);
|
||||||
|
|
||||||
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
|
public static extern IntPtr CreateSliderConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
|
||||||
|
Vector3 frameInAloc, Quaternion frameInArot,
|
||||||
|
Vector3 frameInBloc, Quaternion frameInBrot,
|
||||||
|
bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
|
||||||
|
|
||||||
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
|
public static extern IntPtr CreateConeTwistConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
|
||||||
|
Vector3 frameInAloc, Quaternion frameInArot,
|
||||||
|
Vector3 frameInBloc, Quaternion frameInBrot,
|
||||||
|
bool disableCollisionsBetweenLinkedBodies);
|
||||||
|
|
||||||
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
|
public static extern IntPtr CreateGearConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
|
||||||
|
Vector3 axisInA, Vector3 axisInB,
|
||||||
|
float ratio, bool disableCollisionsBetweenLinkedBodies);
|
||||||
|
|
||||||
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
|
public static extern IntPtr CreatePoint2PointConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
|
||||||
|
Vector3 pivotInA, Vector3 pivotInB,
|
||||||
|
bool disableCollisionsBetweenLinkedBodies);
|
||||||
|
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
public static extern void SetConstraintEnable2(IntPtr constrain, float numericTrueFalse);
|
public static extern void SetConstraintEnable2(IntPtr constrain, float numericTrueFalse);
|
||||||
|
|
||||||
|
@ -1832,6 +2001,12 @@ public static extern void DumpAllInfo2(IntPtr sim);
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
public static extern void DumpPhysicsStatistics2(IntPtr sim);
|
public static extern void DumpPhysicsStatistics2(IntPtr sim);
|
||||||
|
|
||||||
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
|
public static extern void ResetBroadphasePool(IntPtr sim);
|
||||||
|
|
||||||
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
|
public static extern void ResetConstraintSolver(IntPtr sim);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,351 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
using OpenSim.Region.Physics.Manager;
|
||||||
|
|
||||||
|
using OMV = OpenMetaverse;
|
||||||
|
|
||||||
|
namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
|
{
|
||||||
|
public class BSActorAvatarMove : BSActor
|
||||||
|
{
|
||||||
|
BSVMotor m_velocityMotor;
|
||||||
|
|
||||||
|
// Set to true if we think we're going up stairs.
|
||||||
|
// This state is remembered because collisions will turn on and off as we go up stairs.
|
||||||
|
int m_walkingUpStairs;
|
||||||
|
float m_lastStepUp;
|
||||||
|
|
||||||
|
public BSActorAvatarMove(BSScene physicsScene, BSPhysObject pObj, string actorName)
|
||||||
|
: base(physicsScene, pObj, actorName)
|
||||||
|
{
|
||||||
|
m_velocityMotor = null;
|
||||||
|
m_walkingUpStairs = 0;
|
||||||
|
m_physicsScene.DetailLog("{0},BSActorAvatarMove,constructor", m_controllingPrim.LocalID);
|
||||||
|
}
|
||||||
|
|
||||||
|
// BSActor.isActive
|
||||||
|
public override bool isActive
|
||||||
|
{
|
||||||
|
get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release any connections and resources used by the actor.
|
||||||
|
// BSActor.Dispose()
|
||||||
|
public override void Dispose()
|
||||||
|
{
|
||||||
|
Enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called when physical parameters (properties set in Bullet) need to be re-applied.
|
||||||
|
// Called at taint-time.
|
||||||
|
// BSActor.Refresh()
|
||||||
|
public override void Refresh()
|
||||||
|
{
|
||||||
|
m_physicsScene.DetailLog("{0},BSActorAvatarMove,refresh", m_controllingPrim.LocalID);
|
||||||
|
|
||||||
|
// If the object is physically active, add the hoverer prestep action
|
||||||
|
if (isActive)
|
||||||
|
{
|
||||||
|
ActivateAvatarMove();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DeactivateAvatarMove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
|
||||||
|
// Register a prestep action to restore physical requirements before the next simulation step.
|
||||||
|
// Called at taint-time.
|
||||||
|
// BSActor.RemoveDependencies()
|
||||||
|
public override void RemoveDependencies()
|
||||||
|
{
|
||||||
|
// Nothing to do for the hoverer since it is all software at pre-step action time.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Usually called when target velocity changes to set the current velocity and the target
|
||||||
|
// into the movement motor.
|
||||||
|
public void SetVelocityAndTarget(OMV.Vector3 vel, OMV.Vector3 targ, bool inTaintTime)
|
||||||
|
{
|
||||||
|
m_physicsScene.TaintedObject(inTaintTime, "BSActorAvatarMove.setVelocityAndTarget", delegate()
|
||||||
|
{
|
||||||
|
if (m_velocityMotor != null)
|
||||||
|
{
|
||||||
|
m_velocityMotor.Reset();
|
||||||
|
m_velocityMotor.SetTarget(targ);
|
||||||
|
m_velocityMotor.SetCurrent(vel);
|
||||||
|
m_velocityMotor.Enabled = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a hover motor has not been created, create one and start the hovering.
|
||||||
|
private void ActivateAvatarMove()
|
||||||
|
{
|
||||||
|
if (m_velocityMotor == null)
|
||||||
|
{
|
||||||
|
// Infinite decay and timescale values so motor only changes current to target values.
|
||||||
|
m_velocityMotor = new BSVMotor("BSCharacter.Velocity",
|
||||||
|
0.2f, // time scale
|
||||||
|
BSMotor.Infinite, // decay time scale
|
||||||
|
1f // efficiency
|
||||||
|
);
|
||||||
|
// _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
|
||||||
|
SetVelocityAndTarget(m_controllingPrim.RawVelocity, m_controllingPrim.TargetVelocity, true /* inTaintTime */);
|
||||||
|
|
||||||
|
m_physicsScene.BeforeStep += Mover;
|
||||||
|
|
||||||
|
m_walkingUpStairs = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DeactivateAvatarMove()
|
||||||
|
{
|
||||||
|
if (m_velocityMotor != null)
|
||||||
|
{
|
||||||
|
m_physicsScene.BeforeStep -= Mover;
|
||||||
|
m_velocityMotor = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called just before the simulation step. Update the vertical position for hoverness.
|
||||||
|
private void Mover(float timeStep)
|
||||||
|
{
|
||||||
|
// Don't do movement while the object is selected.
|
||||||
|
if (!isActive)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// TODO: Decide if the step parameters should be changed depending on the avatar's
|
||||||
|
// state (flying, colliding, ...). There is code in ODE to do this.
|
||||||
|
|
||||||
|
// COMMENTARY: when the user is making the avatar walk, except for falling, the velocity
|
||||||
|
// specified for the avatar is the one that should be used. For falling, if the avatar
|
||||||
|
// is not flying and is not colliding then it is presumed to be falling and the Z
|
||||||
|
// component is not fooled with (thus allowing gravity to do its thing).
|
||||||
|
// When the avatar is standing, though, the user has specified a velocity of zero and
|
||||||
|
// the avatar should be standing. But if the avatar is pushed by something in the world
|
||||||
|
// (raising elevator platform, moving vehicle, ...) the avatar should be allowed to
|
||||||
|
// move. Thus, the velocity cannot be forced to zero. The problem is that small velocity
|
||||||
|
// errors can creap in and the avatar will slowly float off in some direction.
|
||||||
|
// So, the problem is that, when an avatar is standing, we cannot tell creaping error
|
||||||
|
// from real pushing.
|
||||||
|
// The code below uses whether the collider is static or moving to decide whether to zero motion.
|
||||||
|
|
||||||
|
m_velocityMotor.Step(timeStep);
|
||||||
|
m_controllingPrim.IsStationary = false;
|
||||||
|
|
||||||
|
// If we're not supposed to be moving, make sure things are zero.
|
||||||
|
if (m_velocityMotor.ErrorIsZero() && m_velocityMotor.TargetValue == OMV.Vector3.Zero)
|
||||||
|
{
|
||||||
|
// The avatar shouldn't be moving
|
||||||
|
m_velocityMotor.Zero();
|
||||||
|
|
||||||
|
if (m_controllingPrim.IsColliding)
|
||||||
|
{
|
||||||
|
// If we are colliding with a stationary object, presume we're standing and don't move around
|
||||||
|
if (!m_controllingPrim.ColliderIsMoving)
|
||||||
|
{
|
||||||
|
m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", m_controllingPrim.LocalID);
|
||||||
|
m_controllingPrim.IsStationary = true;
|
||||||
|
m_controllingPrim.ZeroMotion(true /* inTaintTime */);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Standing has more friction on the ground
|
||||||
|
if (m_controllingPrim.Friction != BSParam.AvatarStandingFriction)
|
||||||
|
{
|
||||||
|
m_controllingPrim.Friction = BSParam.AvatarStandingFriction;
|
||||||
|
m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (m_controllingPrim.Flying)
|
||||||
|
{
|
||||||
|
// Flying and not collising and velocity nearly zero.
|
||||||
|
m_controllingPrim.ZeroMotion(true /* inTaintTime */);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2}",
|
||||||
|
m_controllingPrim.LocalID, m_velocityMotor.TargetValue, m_controllingPrim.IsColliding);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Supposed to be moving.
|
||||||
|
OMV.Vector3 stepVelocity = m_velocityMotor.CurrentValue;
|
||||||
|
|
||||||
|
if (m_controllingPrim.Friction != BSParam.AvatarFriction)
|
||||||
|
{
|
||||||
|
// Probably starting up walking. Set friction to moving friction.
|
||||||
|
m_controllingPrim.Friction = BSParam.AvatarFriction;
|
||||||
|
m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If falling, we keep the world's downward vector no matter what the other axis specify.
|
||||||
|
// The check for RawVelocity.Z < 0 makes jumping work (temporary upward force).
|
||||||
|
if (!m_controllingPrim.Flying && !m_controllingPrim.IsColliding)
|
||||||
|
{
|
||||||
|
if (m_controllingPrim.RawVelocity.Z < 0)
|
||||||
|
stepVelocity.Z = m_controllingPrim.RawVelocity.Z;
|
||||||
|
// DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force.
|
||||||
|
OMV.Vector3 moveForce = (stepVelocity - m_controllingPrim.RawVelocity) * m_controllingPrim.Mass;
|
||||||
|
|
||||||
|
// Add special movement force to allow avatars to walk up stepped surfaces.
|
||||||
|
moveForce += WalkUpStairs();
|
||||||
|
|
||||||
|
m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}",
|
||||||
|
m_controllingPrim.LocalID, stepVelocity, m_controllingPrim.RawVelocity, m_controllingPrim.Mass, moveForce);
|
||||||
|
m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, moveForce);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decide if the character is colliding with a low object and compute a force to pop the
|
||||||
|
// avatar up so it can walk up and over the low objects.
|
||||||
|
private OMV.Vector3 WalkUpStairs()
|
||||||
|
{
|
||||||
|
OMV.Vector3 ret = OMV.Vector3.Zero;
|
||||||
|
|
||||||
|
m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4},avHeight={5}",
|
||||||
|
m_controllingPrim.LocalID, m_controllingPrim.IsColliding, m_controllingPrim.Flying,
|
||||||
|
m_controllingPrim.TargetVelocitySpeed, m_controllingPrim.CollisionsLastTick.Count, m_controllingPrim.Size.Z);
|
||||||
|
// This test is done if moving forward, not flying and is colliding with something.
|
||||||
|
// Check for stairs climbing if colliding, not flying and moving forward
|
||||||
|
if ( m_controllingPrim.IsColliding
|
||||||
|
&& !m_controllingPrim.Flying
|
||||||
|
&& m_controllingPrim.TargetVelocitySpeed > 0.1f )
|
||||||
|
{
|
||||||
|
// The range near the character's feet where we will consider stairs
|
||||||
|
// float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) + 0.05f;
|
||||||
|
// Note: there is a problem with the computation of the capsule height. Thus RawPosition is off
|
||||||
|
// from the height. Revisit size and this computation when height is scaled properly.
|
||||||
|
float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) - 0.05f;
|
||||||
|
float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight;
|
||||||
|
|
||||||
|
// Look for a collision point that is near the character's feet and is oriented the same as the charactor is.
|
||||||
|
// Find the highest 'good' collision.
|
||||||
|
OMV.Vector3 highestTouchPosition = OMV.Vector3.Zero;
|
||||||
|
foreach (KeyValuePair<uint, ContactPoint> kvp in m_controllingPrim.CollisionsLastTick.m_objCollisionList)
|
||||||
|
{
|
||||||
|
// Don't care about collisions with the terrain
|
||||||
|
if (kvp.Key > m_physicsScene.TerrainManager.HighestTerrainID)
|
||||||
|
{
|
||||||
|
OMV.Vector3 touchPosition = kvp.Value.Position;
|
||||||
|
m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}",
|
||||||
|
m_controllingPrim.LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition);
|
||||||
|
if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax)
|
||||||
|
{
|
||||||
|
// This contact is within the 'near the feet' range.
|
||||||
|
// The normal should be our contact point to the object so it is pointing away
|
||||||
|
// thus the difference between our facing orientation and the normal should be small.
|
||||||
|
OMV.Vector3 directionFacing = OMV.Vector3.UnitX * m_controllingPrim.RawOrientation;
|
||||||
|
OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal);
|
||||||
|
float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal));
|
||||||
|
if (diff < BSParam.AvatarStepApproachFactor)
|
||||||
|
{
|
||||||
|
if (highestTouchPosition.Z < touchPosition.Z)
|
||||||
|
highestTouchPosition = touchPosition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_walkingUpStairs = 0;
|
||||||
|
// If there is a good step sensing, move the avatar over the step.
|
||||||
|
if (highestTouchPosition != OMV.Vector3.Zero)
|
||||||
|
{
|
||||||
|
// Remember that we are going up stairs. This is needed because collisions
|
||||||
|
// will stop when we move up so this smoothes out that effect.
|
||||||
|
m_walkingUpStairs = BSParam.AvatarStepSmoothingSteps;
|
||||||
|
|
||||||
|
m_lastStepUp = highestTouchPosition.Z - nearFeetHeightMin;
|
||||||
|
ret = ComputeStairCorrection(m_lastStepUp);
|
||||||
|
m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},ret={3}",
|
||||||
|
m_controllingPrim.LocalID, highestTouchPosition, nearFeetHeightMin, ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If we used to be going up stairs but are not now, smooth the case where collision goes away while
|
||||||
|
// we are bouncing up the stairs.
|
||||||
|
if (m_walkingUpStairs > 0)
|
||||||
|
{
|
||||||
|
m_walkingUpStairs--;
|
||||||
|
ret = ComputeStairCorrection(m_lastStepUp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private OMV.Vector3 ComputeStairCorrection(float stepUp)
|
||||||
|
{
|
||||||
|
OMV.Vector3 ret = OMV.Vector3.Zero;
|
||||||
|
OMV.Vector3 displacement = OMV.Vector3.Zero;
|
||||||
|
|
||||||
|
if (stepUp > 0f)
|
||||||
|
{
|
||||||
|
// Found the stairs contact point. Push up a little to raise the character.
|
||||||
|
if (BSParam.AvatarStepForceFactor > 0f)
|
||||||
|
{
|
||||||
|
float upForce = stepUp * m_controllingPrim.Mass * BSParam.AvatarStepForceFactor;
|
||||||
|
ret = new OMV.Vector3(0f, 0f, upForce);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also move the avatar up for the new height
|
||||||
|
if (BSParam.AvatarStepUpCorrectionFactor > 0f)
|
||||||
|
{
|
||||||
|
// Move the avatar up related to the height of the collision
|
||||||
|
displacement = new OMV.Vector3(0f, 0f, stepUp * BSParam.AvatarStepUpCorrectionFactor);
|
||||||
|
m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (BSParam.AvatarStepUpCorrectionFactor < 0f)
|
||||||
|
{
|
||||||
|
// Move the avatar up about the specified step height
|
||||||
|
displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight);
|
||||||
|
m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs.ComputeStairCorrection,disp={1},force={2}",
|
||||||
|
m_controllingPrim.LocalID, displacement, ret);
|
||||||
|
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,173 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
using OpenSim.Region.Physics.Manager;
|
||||||
|
|
||||||
|
using OMV = OpenMetaverse;
|
||||||
|
|
||||||
|
namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
|
{
|
||||||
|
public class BSActorHover : BSActor
|
||||||
|
{
|
||||||
|
private BSFMotor m_hoverMotor;
|
||||||
|
|
||||||
|
public BSActorHover(BSScene physicsScene, BSPhysObject pObj, string actorName)
|
||||||
|
: base(physicsScene, pObj, actorName)
|
||||||
|
{
|
||||||
|
m_hoverMotor = null;
|
||||||
|
m_physicsScene.DetailLog("{0},BSActorHover,constructor", m_controllingPrim.LocalID);
|
||||||
|
}
|
||||||
|
|
||||||
|
// BSActor.isActive
|
||||||
|
public override bool isActive
|
||||||
|
{
|
||||||
|
get { return Enabled; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release any connections and resources used by the actor.
|
||||||
|
// BSActor.Dispose()
|
||||||
|
public override void Dispose()
|
||||||
|
{
|
||||||
|
Enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called when physical parameters (properties set in Bullet) need to be re-applied.
|
||||||
|
// Called at taint-time.
|
||||||
|
// BSActor.Refresh()
|
||||||
|
public override void Refresh()
|
||||||
|
{
|
||||||
|
m_physicsScene.DetailLog("{0},BSActorHover,refresh", m_controllingPrim.LocalID);
|
||||||
|
|
||||||
|
// If not active any more, turn me off
|
||||||
|
if (!m_controllingPrim.HoverActive)
|
||||||
|
{
|
||||||
|
SetEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the object is physically active, add the hoverer prestep action
|
||||||
|
if (isActive)
|
||||||
|
{
|
||||||
|
ActivateHover();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DeactivateHover();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
|
||||||
|
// Register a prestep action to restore physical requirements before the next simulation step.
|
||||||
|
// Called at taint-time.
|
||||||
|
// BSActor.RemoveDependencies()
|
||||||
|
public override void RemoveDependencies()
|
||||||
|
{
|
||||||
|
// Nothing to do for the hoverer since it is all software at pre-step action time.
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a hover motor has not been created, create one and start the hovering.
|
||||||
|
private void ActivateHover()
|
||||||
|
{
|
||||||
|
if (m_hoverMotor == null)
|
||||||
|
{
|
||||||
|
// Turning the target on
|
||||||
|
m_hoverMotor = new BSFMotor("BSActorHover",
|
||||||
|
m_controllingPrim.HoverTau, // timeScale
|
||||||
|
BSMotor.Infinite, // decay time scale
|
||||||
|
1f // efficiency
|
||||||
|
);
|
||||||
|
m_hoverMotor.SetTarget(ComputeCurrentHoverHeight());
|
||||||
|
m_hoverMotor.SetCurrent(m_controllingPrim.RawPosition.Z);
|
||||||
|
m_hoverMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG so motor will output detail log messages.
|
||||||
|
|
||||||
|
m_physicsScene.BeforeStep += Hoverer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DeactivateHover()
|
||||||
|
{
|
||||||
|
if (m_hoverMotor != null)
|
||||||
|
{
|
||||||
|
m_physicsScene.BeforeStep -= Hoverer;
|
||||||
|
m_hoverMotor = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called just before the simulation step. Update the vertical position for hoverness.
|
||||||
|
private void Hoverer(float timeStep)
|
||||||
|
{
|
||||||
|
// Don't do hovering while the object is selected.
|
||||||
|
if (!isActive)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_hoverMotor.SetCurrent(m_controllingPrim.RawPosition.Z);
|
||||||
|
m_hoverMotor.SetTarget(ComputeCurrentHoverHeight());
|
||||||
|
float targetHeight = m_hoverMotor.Step(timeStep);
|
||||||
|
|
||||||
|
// 'targetHeight' is where we'd like the Z of the prim to be at this moment.
|
||||||
|
// Compute the amount of force to push us there.
|
||||||
|
float moveForce = (targetHeight - m_controllingPrim.RawPosition.Z) * m_controllingPrim.RawMass;
|
||||||
|
// Undo anything the object thinks it's doing at the moment
|
||||||
|
moveForce = -m_controllingPrim.RawVelocity.Z * m_controllingPrim.Mass;
|
||||||
|
|
||||||
|
m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, new OMV.Vector3(0f, 0f, moveForce));
|
||||||
|
m_physicsScene.DetailLog("{0},BSPrim.Hover,move,targHt={1},moveForce={2},mass={3}",
|
||||||
|
m_controllingPrim.LocalID, targetHeight, moveForce, m_controllingPrim.RawMass);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Based on current position, determine what we should be hovering at now.
|
||||||
|
// Must recompute often. What if we walked offa cliff>
|
||||||
|
private float ComputeCurrentHoverHeight()
|
||||||
|
{
|
||||||
|
float ret = m_controllingPrim.HoverHeight;
|
||||||
|
float groundHeight = m_physicsScene.TerrainManager.GetTerrainHeightAtXYZ(m_controllingPrim.RawPosition);
|
||||||
|
|
||||||
|
switch (m_controllingPrim.HoverType)
|
||||||
|
{
|
||||||
|
case PIDHoverType.Ground:
|
||||||
|
ret = groundHeight + m_controllingPrim.HoverHeight;
|
||||||
|
break;
|
||||||
|
case PIDHoverType.GroundAndWater:
|
||||||
|
float waterHeight = m_physicsScene.TerrainManager.GetWaterLevelAtXYZ(m_controllingPrim.RawPosition);
|
||||||
|
if (groundHeight > waterHeight)
|
||||||
|
{
|
||||||
|
ret = groundHeight + m_controllingPrim.HoverHeight;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = waterHeight + m_controllingPrim.HoverHeight;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,187 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
using OMV = OpenMetaverse;
|
||||||
|
|
||||||
|
namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
|
{
|
||||||
|
public class BSActorLockAxis : BSActor
|
||||||
|
{
|
||||||
|
BSConstraint LockAxisConstraint = null;
|
||||||
|
|
||||||
|
public BSActorLockAxis(BSScene physicsScene, BSPhysObject pObj, string actorName)
|
||||||
|
: base(physicsScene, pObj, actorName)
|
||||||
|
{
|
||||||
|
m_physicsScene.DetailLog("{0},BSActorLockAxis,constructor", m_controllingPrim.LocalID);
|
||||||
|
LockAxisConstraint = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BSActor.isActive
|
||||||
|
public override bool isActive
|
||||||
|
{
|
||||||
|
get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release any connections and resources used by the actor.
|
||||||
|
// BSActor.Dispose()
|
||||||
|
public override void Dispose()
|
||||||
|
{
|
||||||
|
RemoveAxisLockConstraint();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called when physical parameters (properties set in Bullet) need to be re-applied.
|
||||||
|
// Called at taint-time.
|
||||||
|
// BSActor.Refresh()
|
||||||
|
public override void Refresh()
|
||||||
|
{
|
||||||
|
m_physicsScene.DetailLog("{0},BSActorLockAxis,refresh,lockedAxis={1},enabled={2},pActive={3}",
|
||||||
|
m_controllingPrim.LocalID, m_controllingPrim.LockedAngularAxis, Enabled, m_controllingPrim.IsPhysicallyActive);
|
||||||
|
// If all the axis are free, we don't need to exist
|
||||||
|
if (m_controllingPrim.LockedAngularAxis == m_controllingPrim.LockedAxisFree)
|
||||||
|
{
|
||||||
|
Enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the object is physically active, add the axis locking constraint
|
||||||
|
if (isActive)
|
||||||
|
{
|
||||||
|
AddAxisLockConstraint();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RemoveAxisLockConstraint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
|
||||||
|
// Register a prestep action to restore physical requirements before the next simulation step.
|
||||||
|
// Called at taint-time.
|
||||||
|
// BSActor.RemoveDependencies()
|
||||||
|
public override void RemoveDependencies()
|
||||||
|
{
|
||||||
|
if (LockAxisConstraint != null)
|
||||||
|
{
|
||||||
|
// If a constraint is set up, remove it from the physical scene
|
||||||
|
RemoveAxisLockConstraint();
|
||||||
|
// Schedule a call before the next simulation step to restore the constraint.
|
||||||
|
m_physicsScene.PostTaintObject("BSActorLockAxis:" + ActorName, m_controllingPrim.LocalID, delegate()
|
||||||
|
{
|
||||||
|
Refresh();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddAxisLockConstraint()
|
||||||
|
{
|
||||||
|
if (LockAxisConstraint == null)
|
||||||
|
{
|
||||||
|
// Lock that axis by creating a 6DOF constraint that has one end in the world and
|
||||||
|
// the other in the object.
|
||||||
|
// http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=20817
|
||||||
|
// http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=26380
|
||||||
|
|
||||||
|
// Remove any existing axis constraint (just to be sure)
|
||||||
|
RemoveAxisLockConstraint();
|
||||||
|
|
||||||
|
BSConstraint6Dof axisConstrainer = new BSConstraint6Dof(m_physicsScene.World, m_controllingPrim.PhysBody,
|
||||||
|
OMV.Vector3.Zero, OMV.Quaternion.Identity,
|
||||||
|
false /* useLinearReferenceFrameB */, true /* disableCollisionsBetweenLinkedBodies */);
|
||||||
|
LockAxisConstraint = axisConstrainer;
|
||||||
|
m_physicsScene.Constraints.AddConstraint(LockAxisConstraint);
|
||||||
|
|
||||||
|
// The constraint is tied to the world and oriented to the prim.
|
||||||
|
|
||||||
|
// Free to move linearly in the region
|
||||||
|
OMV.Vector3 linearLow = OMV.Vector3.Zero;
|
||||||
|
OMV.Vector3 linearHigh = m_physicsScene.TerrainManager.DefaultRegionSize;
|
||||||
|
if (m_controllingPrim.LockedLinearAxis.X != BSPhysObject.FreeAxis)
|
||||||
|
{
|
||||||
|
linearLow.X = m_controllingPrim.RawPosition.X;
|
||||||
|
linearHigh.X = m_controllingPrim.RawPosition.X;
|
||||||
|
}
|
||||||
|
if (m_controllingPrim.LockedLinearAxis.Y != BSPhysObject.FreeAxis)
|
||||||
|
{
|
||||||
|
linearLow.Y = m_controllingPrim.RawPosition.Y;
|
||||||
|
linearHigh.Y = m_controllingPrim.RawPosition.Y;
|
||||||
|
}
|
||||||
|
if (m_controllingPrim.LockedLinearAxis.Z != BSPhysObject.FreeAxis)
|
||||||
|
{
|
||||||
|
linearLow.Z = m_controllingPrim.RawPosition.Z;
|
||||||
|
linearHigh.Z = m_controllingPrim.RawPosition.Z;
|
||||||
|
}
|
||||||
|
axisConstrainer.SetLinearLimits(linearLow, linearHigh);
|
||||||
|
|
||||||
|
// Angular with some axis locked
|
||||||
|
float fPI = (float)Math.PI;
|
||||||
|
OMV.Vector3 angularLow = new OMV.Vector3(-fPI, -fPI, -fPI);
|
||||||
|
OMV.Vector3 angularHigh = new OMV.Vector3(fPI, fPI, fPI);
|
||||||
|
if (m_controllingPrim.LockedAngularAxis.X != BSPhysObject.FreeAxis)
|
||||||
|
{
|
||||||
|
angularLow.X = 0f;
|
||||||
|
angularHigh.X = 0f;
|
||||||
|
}
|
||||||
|
if (m_controllingPrim.LockedAngularAxis.Y != BSPhysObject.FreeAxis)
|
||||||
|
{
|
||||||
|
angularLow.Y = 0f;
|
||||||
|
angularHigh.Y = 0f;
|
||||||
|
}
|
||||||
|
if (m_controllingPrim.LockedAngularAxis.Z != BSPhysObject.FreeAxis)
|
||||||
|
{
|
||||||
|
angularLow.Z = 0f;
|
||||||
|
angularHigh.Z = 0f;
|
||||||
|
}
|
||||||
|
if (!axisConstrainer.SetAngularLimits(angularLow, angularHigh))
|
||||||
|
{
|
||||||
|
m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,failedSetAngularLimits", m_controllingPrim.LocalID);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,create,linLow={1},linHi={2},angLow={3},angHi={4}",
|
||||||
|
m_controllingPrim.LocalID, linearLow, linearHigh, angularLow, angularHigh);
|
||||||
|
|
||||||
|
// Constants from one of the posts mentioned above and used in Bullet's ConstraintDemo.
|
||||||
|
axisConstrainer.TranslationalLimitMotor(true /* enable */, 5.0f, 0.1f);
|
||||||
|
|
||||||
|
axisConstrainer.RecomputeConstraintVariables(m_controllingPrim.RawMass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveAxisLockConstraint()
|
||||||
|
{
|
||||||
|
if (LockAxisConstraint != null)
|
||||||
|
{
|
||||||
|
m_physicsScene.Constraints.RemoveAndDestroyConstraint(LockAxisConstraint);
|
||||||
|
LockAxisConstraint = null;
|
||||||
|
m_physicsScene.DetailLog("{0},BSActorLockAxis.RemoveAxisLockConstraint,destroyingConstraint", m_controllingPrim.LocalID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,157 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
using OpenSim.Region.Physics.Manager;
|
||||||
|
|
||||||
|
using OMV = OpenMetaverse;
|
||||||
|
|
||||||
|
namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
|
{
|
||||||
|
public class BSActorMoveToTarget : BSActor
|
||||||
|
{
|
||||||
|
private BSVMotor m_targetMotor;
|
||||||
|
|
||||||
|
public BSActorMoveToTarget(BSScene physicsScene, BSPhysObject pObj, string actorName)
|
||||||
|
: base(physicsScene, pObj, actorName)
|
||||||
|
{
|
||||||
|
m_targetMotor = null;
|
||||||
|
m_physicsScene.DetailLog("{0},BSActorMoveToTarget,constructor", m_controllingPrim.LocalID);
|
||||||
|
}
|
||||||
|
|
||||||
|
// BSActor.isActive
|
||||||
|
public override bool isActive
|
||||||
|
{
|
||||||
|
get { return Enabled; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release any connections and resources used by the actor.
|
||||||
|
// BSActor.Dispose()
|
||||||
|
public override void Dispose()
|
||||||
|
{
|
||||||
|
Enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called when physical parameters (properties set in Bullet) need to be re-applied.
|
||||||
|
// Called at taint-time.
|
||||||
|
// BSActor.Refresh()
|
||||||
|
public override void Refresh()
|
||||||
|
{
|
||||||
|
m_physicsScene.DetailLog("{0},BSActorMoveToTarget,refresh,enabled={1},active={2},target={3},tau={4}",
|
||||||
|
m_controllingPrim.LocalID, Enabled, m_controllingPrim.MoveToTargetActive,
|
||||||
|
m_controllingPrim.MoveToTargetTarget, m_controllingPrim.MoveToTargetTau );
|
||||||
|
|
||||||
|
// If not active any more...
|
||||||
|
if (!m_controllingPrim.MoveToTargetActive)
|
||||||
|
{
|
||||||
|
Enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isActive)
|
||||||
|
{
|
||||||
|
ActivateMoveToTarget();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DeactivateMoveToTarget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
|
||||||
|
// Register a prestep action to restore physical requirements before the next simulation step.
|
||||||
|
// Called at taint-time.
|
||||||
|
// BSActor.RemoveDependencies()
|
||||||
|
public override void RemoveDependencies()
|
||||||
|
{
|
||||||
|
// Nothing to do for the moveToTarget since it is all software at pre-step action time.
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a hover motor has not been created, create one and start the hovering.
|
||||||
|
private void ActivateMoveToTarget()
|
||||||
|
{
|
||||||
|
if (m_targetMotor == null)
|
||||||
|
{
|
||||||
|
// We're taking over after this.
|
||||||
|
m_controllingPrim.ZeroMotion(true);
|
||||||
|
|
||||||
|
m_targetMotor = new BSVMotor("BSActorMoveToTargget.Activate",
|
||||||
|
m_controllingPrim.MoveToTargetTau, // timeScale
|
||||||
|
BSMotor.Infinite, // decay time scale
|
||||||
|
1f // efficiency
|
||||||
|
);
|
||||||
|
m_targetMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG so motor will output detail log messages.
|
||||||
|
m_targetMotor.SetTarget(m_controllingPrim.MoveToTargetTarget);
|
||||||
|
m_targetMotor.SetCurrent(m_controllingPrim.RawPosition);
|
||||||
|
|
||||||
|
m_physicsScene.BeforeStep += Mover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DeactivateMoveToTarget()
|
||||||
|
{
|
||||||
|
if (m_targetMotor != null)
|
||||||
|
{
|
||||||
|
m_physicsScene.BeforeStep -= Mover;
|
||||||
|
m_targetMotor = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called just before the simulation step. Update the vertical position for hoverness.
|
||||||
|
private void Mover(float timeStep)
|
||||||
|
{
|
||||||
|
// Don't do hovering while the object is selected.
|
||||||
|
if (!isActive)
|
||||||
|
return;
|
||||||
|
|
||||||
|
OMV.Vector3 origPosition = m_controllingPrim.RawPosition; // DEBUG DEBUG (for printout below)
|
||||||
|
|
||||||
|
// 'movePosition' is where we'd like the prim to be at this moment.
|
||||||
|
OMV.Vector3 movePosition = m_controllingPrim.RawPosition + m_targetMotor.Step(timeStep);
|
||||||
|
|
||||||
|
// If we are very close to our target, turn off the movement motor.
|
||||||
|
if (m_targetMotor.ErrorIsZero())
|
||||||
|
{
|
||||||
|
m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover,zeroMovement,movePos={1},pos={2},mass={3}",
|
||||||
|
m_controllingPrim.LocalID, movePosition, m_controllingPrim.RawPosition, m_controllingPrim.Mass);
|
||||||
|
m_controllingPrim.ForcePosition = m_targetMotor.TargetValue;
|
||||||
|
// Setting the position does not cause the physics engine to generate a property update. Force it.
|
||||||
|
m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_controllingPrim.ForcePosition = movePosition;
|
||||||
|
// Setting the position does not cause the physics engine to generate a property update. Force it.
|
||||||
|
m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody);
|
||||||
|
}
|
||||||
|
m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover,move,fromPos={1},movePos={2}", m_controllingPrim.LocalID, origPosition, movePosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,137 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
using OpenSim.Region.Physics.Manager;
|
||||||
|
|
||||||
|
using OMV = OpenMetaverse;
|
||||||
|
|
||||||
|
namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
|
{
|
||||||
|
public class BSActorSetForce : BSActor
|
||||||
|
{
|
||||||
|
BSFMotor m_forceMotor;
|
||||||
|
|
||||||
|
public BSActorSetForce(BSScene physicsScene, BSPhysObject pObj, string actorName)
|
||||||
|
: base(physicsScene, pObj, actorName)
|
||||||
|
{
|
||||||
|
m_forceMotor = null;
|
||||||
|
m_physicsScene.DetailLog("{0},BSActorSetForce,constructor", m_controllingPrim.LocalID);
|
||||||
|
}
|
||||||
|
|
||||||
|
// BSActor.isActive
|
||||||
|
public override bool isActive
|
||||||
|
{
|
||||||
|
get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release any connections and resources used by the actor.
|
||||||
|
// BSActor.Dispose()
|
||||||
|
public override void Dispose()
|
||||||
|
{
|
||||||
|
Enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called when physical parameters (properties set in Bullet) need to be re-applied.
|
||||||
|
// Called at taint-time.
|
||||||
|
// BSActor.Refresh()
|
||||||
|
public override void Refresh()
|
||||||
|
{
|
||||||
|
m_physicsScene.DetailLog("{0},BSActorSetForce,refresh", m_controllingPrim.LocalID);
|
||||||
|
|
||||||
|
// If not active any more, get rid of me (shouldn't ever happen, but just to be safe)
|
||||||
|
if (m_controllingPrim.RawForce == OMV.Vector3.Zero)
|
||||||
|
{
|
||||||
|
m_physicsScene.DetailLog("{0},BSActorSetForce,refresh,notSetForce,removing={1}", m_controllingPrim.LocalID, ActorName);
|
||||||
|
Enabled = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the object is physically active, add the hoverer prestep action
|
||||||
|
if (isActive)
|
||||||
|
{
|
||||||
|
ActivateSetForce();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DeactivateSetForce();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
|
||||||
|
// Register a prestep action to restore physical requirements before the next simulation step.
|
||||||
|
// Called at taint-time.
|
||||||
|
// BSActor.RemoveDependencies()
|
||||||
|
public override void RemoveDependencies()
|
||||||
|
{
|
||||||
|
// Nothing to do for the hoverer since it is all software at pre-step action time.
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a hover motor has not been created, create one and start the hovering.
|
||||||
|
private void ActivateSetForce()
|
||||||
|
{
|
||||||
|
if (m_forceMotor == null)
|
||||||
|
{
|
||||||
|
// A fake motor that might be used someday
|
||||||
|
m_forceMotor = new BSFMotor("setForce", 1f, 1f, 1f);
|
||||||
|
|
||||||
|
m_physicsScene.BeforeStep += Mover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DeactivateSetForce()
|
||||||
|
{
|
||||||
|
if (m_forceMotor != null)
|
||||||
|
{
|
||||||
|
m_physicsScene.BeforeStep -= Mover;
|
||||||
|
m_forceMotor = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called just before the simulation step. Update the vertical position for hoverness.
|
||||||
|
private void Mover(float timeStep)
|
||||||
|
{
|
||||||
|
// Don't do force while the object is selected.
|
||||||
|
if (!isActive)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_physicsScene.DetailLog("{0},BSActorSetForce,preStep,force={1}", m_controllingPrim.LocalID, m_controllingPrim.RawForce);
|
||||||
|
if (m_controllingPrim.PhysBody.HasPhysicalBody)
|
||||||
|
{
|
||||||
|
m_physicsScene.PE.ApplyCentralForce(m_controllingPrim.PhysBody, m_controllingPrim.RawForce);
|
||||||
|
m_controllingPrim.ActivateIfPhysical(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,138 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
using OpenSim.Region.Physics.Manager;
|
||||||
|
|
||||||
|
using OMV = OpenMetaverse;
|
||||||
|
|
||||||
|
namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
|
{
|
||||||
|
public class BSActorSetTorque : BSActor
|
||||||
|
{
|
||||||
|
BSFMotor m_torqueMotor;
|
||||||
|
|
||||||
|
public BSActorSetTorque(BSScene physicsScene, BSPhysObject pObj, string actorName)
|
||||||
|
: base(physicsScene, pObj, actorName)
|
||||||
|
{
|
||||||
|
m_torqueMotor = null;
|
||||||
|
m_physicsScene.DetailLog("{0},BSActorSetTorque,constructor", m_controllingPrim.LocalID);
|
||||||
|
}
|
||||||
|
|
||||||
|
// BSActor.isActive
|
||||||
|
public override bool isActive
|
||||||
|
{
|
||||||
|
get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release any connections and resources used by the actor.
|
||||||
|
// BSActor.Dispose()
|
||||||
|
public override void Dispose()
|
||||||
|
{
|
||||||
|
Enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called when physical parameters (properties set in Bullet) need to be re-applied.
|
||||||
|
// Called at taint-time.
|
||||||
|
// BSActor.Refresh()
|
||||||
|
public override void Refresh()
|
||||||
|
{
|
||||||
|
m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh,torque={1}", m_controllingPrim.LocalID, m_controllingPrim.RawTorque);
|
||||||
|
|
||||||
|
// If not active any more, get rid of me (shouldn't ever happen, but just to be safe)
|
||||||
|
if (m_controllingPrim.RawTorque == OMV.Vector3.Zero)
|
||||||
|
{
|
||||||
|
m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh,notSetTorque,disabling={1}", m_controllingPrim.LocalID, ActorName);
|
||||||
|
Enabled = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the object is physically active, add the hoverer prestep action
|
||||||
|
if (isActive)
|
||||||
|
{
|
||||||
|
ActivateSetTorque();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DeactivateSetTorque();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
|
||||||
|
// Register a prestep action to restore physical requirements before the next simulation step.
|
||||||
|
// Called at taint-time.
|
||||||
|
// BSActor.RemoveDependencies()
|
||||||
|
public override void RemoveDependencies()
|
||||||
|
{
|
||||||
|
// Nothing to do for the hoverer since it is all software at pre-step action time.
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a hover motor has not been created, create one and start the hovering.
|
||||||
|
private void ActivateSetTorque()
|
||||||
|
{
|
||||||
|
if (m_torqueMotor == null)
|
||||||
|
{
|
||||||
|
// A fake motor that might be used someday
|
||||||
|
m_torqueMotor = new BSFMotor("setTorque", 1f, 1f, 1f);
|
||||||
|
|
||||||
|
m_physicsScene.BeforeStep += Mover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DeactivateSetTorque()
|
||||||
|
{
|
||||||
|
if (m_torqueMotor != null)
|
||||||
|
{
|
||||||
|
m_physicsScene.BeforeStep -= Mover;
|
||||||
|
m_torqueMotor = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called just before the simulation step. Update the vertical position for hoverness.
|
||||||
|
private void Mover(float timeStep)
|
||||||
|
{
|
||||||
|
// Don't do force while the object is selected.
|
||||||
|
if (!isActive)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_physicsScene.DetailLog("{0},BSActorSetTorque,preStep,force={1}", m_controllingPrim.LocalID, m_controllingPrim.RawTorque);
|
||||||
|
if (m_controllingPrim.PhysBody.HasPhysicalBody)
|
||||||
|
{
|
||||||
|
m_controllingPrim.AddAngularForce(m_controllingPrim.RawTorque, false, true);
|
||||||
|
m_controllingPrim.ActivateIfPhysical(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,160 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
|
{
|
||||||
|
public class BSActorCollection
|
||||||
|
{
|
||||||
|
private BSScene m_physicsScene { get; set; }
|
||||||
|
private Dictionary<string, BSActor> m_actors;
|
||||||
|
|
||||||
|
public BSActorCollection(BSScene physicsScene)
|
||||||
|
{
|
||||||
|
m_physicsScene = physicsScene;
|
||||||
|
m_actors = new Dictionary<string, BSActor>();
|
||||||
|
}
|
||||||
|
public void Add(string name, BSActor actor)
|
||||||
|
{
|
||||||
|
lock (m_actors)
|
||||||
|
{
|
||||||
|
if (!m_actors.ContainsKey(name))
|
||||||
|
{
|
||||||
|
m_actors[name] = actor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool RemoveAndRelease(string name)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
lock (m_actors)
|
||||||
|
{
|
||||||
|
if (m_actors.ContainsKey(name))
|
||||||
|
{
|
||||||
|
BSActor beingRemoved = m_actors[name];
|
||||||
|
m_actors.Remove(name);
|
||||||
|
beingRemoved.Dispose();
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
lock (m_actors)
|
||||||
|
{
|
||||||
|
Release();
|
||||||
|
m_actors.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
}
|
||||||
|
public bool HasActor(string name)
|
||||||
|
{
|
||||||
|
return m_actors.ContainsKey(name);
|
||||||
|
}
|
||||||
|
public bool TryGetActor(string actorName, out BSActor theActor)
|
||||||
|
{
|
||||||
|
return m_actors.TryGetValue(actorName, out theActor);
|
||||||
|
}
|
||||||
|
public void ForEachActor(Action<BSActor> act)
|
||||||
|
{
|
||||||
|
lock (m_actors)
|
||||||
|
{
|
||||||
|
foreach (KeyValuePair<string, BSActor> kvp in m_actors)
|
||||||
|
act(kvp.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Enable(bool enabl)
|
||||||
|
{
|
||||||
|
ForEachActor(a => a.SetEnabled(enabl));
|
||||||
|
}
|
||||||
|
public void Release()
|
||||||
|
{
|
||||||
|
ForEachActor(a => a.Dispose());
|
||||||
|
}
|
||||||
|
public void Refresh()
|
||||||
|
{
|
||||||
|
ForEachActor(a => a.Refresh());
|
||||||
|
}
|
||||||
|
public void RemoveDependencies()
|
||||||
|
{
|
||||||
|
ForEachActor(a => a.RemoveDependencies());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
/// <summary>
|
||||||
|
/// Each physical object can have 'actors' who are pushing the object around.
|
||||||
|
/// This can be used for hover, locking axis, making vehicles, etc.
|
||||||
|
/// Each physical object can have multiple actors acting on it.
|
||||||
|
///
|
||||||
|
/// An actor usually registers itself with physics scene events (pre-step action)
|
||||||
|
/// and modifies the parameters on the host physical object.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class BSActor
|
||||||
|
{
|
||||||
|
protected BSScene m_physicsScene { get; private set; }
|
||||||
|
protected BSPhysObject m_controllingPrim { get; private set; }
|
||||||
|
public virtual bool Enabled { get; set; }
|
||||||
|
public string ActorName { get; private set; }
|
||||||
|
|
||||||
|
public BSActor(BSScene physicsScene, BSPhysObject pObj, string actorName)
|
||||||
|
{
|
||||||
|
m_physicsScene = physicsScene;
|
||||||
|
m_controllingPrim = pObj;
|
||||||
|
ActorName = actorName;
|
||||||
|
Enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return 'true' if activily updating the prim
|
||||||
|
public virtual bool isActive
|
||||||
|
{
|
||||||
|
get { return Enabled; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Turn the actor on an off. Only used by ActorCollection to set all enabled/disabled.
|
||||||
|
// Anyone else should assign true/false to 'Enabled'.
|
||||||
|
public void SetEnabled(bool setEnabled)
|
||||||
|
{
|
||||||
|
Enabled = setEnabled;
|
||||||
|
}
|
||||||
|
// Release any connections and resources used by the actor.
|
||||||
|
public abstract void Dispose();
|
||||||
|
// Called when physical parameters (properties set in Bullet) need to be re-applied.
|
||||||
|
public abstract void Refresh();
|
||||||
|
// The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
|
||||||
|
// Register a prestep action to restore physical requirements before the next simulation step.
|
||||||
|
public abstract void RemoveDependencies();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,7 +6,7 @@
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyrightD
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name of the OpenSimulator Project nor the
|
* * Neither the name of the OpenSimulator Project nor the
|
||||||
|
@ -70,6 +70,7 @@ public enum BSPhysicsShapeType
|
||||||
SHAPE_COMPOUND = 22,
|
SHAPE_COMPOUND = 22,
|
||||||
SHAPE_HEIGHTMAP = 23,
|
SHAPE_HEIGHTMAP = 23,
|
||||||
SHAPE_AVATAR = 24,
|
SHAPE_AVATAR = 24,
|
||||||
|
SHAPE_CONVEXHULL= 25,
|
||||||
};
|
};
|
||||||
|
|
||||||
// The native shapes have predefined shape hash keys
|
// The native shapes have predefined shape hash keys
|
||||||
|
@ -87,7 +88,7 @@ public enum FixedShapeKey : ulong
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public struct ShapeData
|
public struct ShapeData
|
||||||
{
|
{
|
||||||
public uint ID;
|
public UInt32 ID;
|
||||||
public BSPhysicsShapeType Type;
|
public BSPhysicsShapeType Type;
|
||||||
public Vector3 Position;
|
public Vector3 Position;
|
||||||
public Quaternion Rotation;
|
public Quaternion Rotation;
|
||||||
|
@ -111,7 +112,7 @@ public struct ShapeData
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public struct SweepHit
|
public struct SweepHit
|
||||||
{
|
{
|
||||||
public uint ID;
|
public UInt32 ID;
|
||||||
public float Fraction;
|
public float Fraction;
|
||||||
public Vector3 Normal;
|
public Vector3 Normal;
|
||||||
public Vector3 Point;
|
public Vector3 Point;
|
||||||
|
@ -119,27 +120,47 @@ public struct SweepHit
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public struct RaycastHit
|
public struct RaycastHit
|
||||||
{
|
{
|
||||||
public uint ID;
|
public UInt32 ID;
|
||||||
public float Fraction;
|
public float Fraction;
|
||||||
public Vector3 Normal;
|
public Vector3 Normal;
|
||||||
}
|
}
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public struct CollisionDesc
|
public struct CollisionDesc
|
||||||
{
|
{
|
||||||
public uint aID;
|
public UInt32 aID;
|
||||||
public uint bID;
|
public UInt32 bID;
|
||||||
public Vector3 point;
|
public Vector3 point;
|
||||||
public Vector3 normal;
|
public Vector3 normal;
|
||||||
|
public float penetration;
|
||||||
}
|
}
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public struct EntityProperties
|
public struct EntityProperties
|
||||||
{
|
{
|
||||||
public uint ID;
|
public UInt32 ID;
|
||||||
public Vector3 Position;
|
public Vector3 Position;
|
||||||
public Quaternion Rotation;
|
public Quaternion Rotation;
|
||||||
public Vector3 Velocity;
|
public Vector3 Velocity;
|
||||||
public Vector3 Acceleration;
|
public Vector3 Acceleration;
|
||||||
public Vector3 RotationalVelocity;
|
public Vector3 RotationalVelocity;
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
StringBuilder buff = new StringBuilder();
|
||||||
|
buff.Append("<i=");
|
||||||
|
buff.Append(ID.ToString());
|
||||||
|
buff.Append(",p=");
|
||||||
|
buff.Append(Position.ToString());
|
||||||
|
buff.Append(",r=");
|
||||||
|
buff.Append(Rotation.ToString());
|
||||||
|
buff.Append(",v=");
|
||||||
|
buff.Append(Velocity.ToString());
|
||||||
|
buff.Append(",a=");
|
||||||
|
buff.Append(Acceleration.ToString());
|
||||||
|
buff.Append(",rv=");
|
||||||
|
buff.Append(RotationalVelocity.ToString());
|
||||||
|
buff.Append(">");
|
||||||
|
return buff.ToString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format of this structure must match the definition in the C++ code
|
// Format of this structure must match the definition in the C++ code
|
||||||
|
@ -154,32 +175,6 @@ public struct ConfigurationParameters
|
||||||
public float collisionMargin;
|
public float collisionMargin;
|
||||||
public float gravity;
|
public float gravity;
|
||||||
|
|
||||||
public float XlinearDamping;
|
|
||||||
public float XangularDamping;
|
|
||||||
public float XdeactivationTime;
|
|
||||||
public float XlinearSleepingThreshold;
|
|
||||||
public float XangularSleepingThreshold;
|
|
||||||
public float XccdMotionThreshold;
|
|
||||||
public float XccdSweptSphereRadius;
|
|
||||||
public float XcontactProcessingThreshold;
|
|
||||||
|
|
||||||
public float XterrainImplementation;
|
|
||||||
public float XterrainFriction;
|
|
||||||
public float XterrainHitFraction;
|
|
||||||
public float XterrainRestitution;
|
|
||||||
public float XterrainCollisionMargin;
|
|
||||||
|
|
||||||
public float XavatarFriction;
|
|
||||||
public float XavatarStandingFriction;
|
|
||||||
public float XavatarDensity;
|
|
||||||
public float XavatarRestitution;
|
|
||||||
public float XavatarCapsuleWidth;
|
|
||||||
public float XavatarCapsuleDepth;
|
|
||||||
public float XavatarCapsuleHeight;
|
|
||||||
public float XavatarContactProcessingThreshold;
|
|
||||||
|
|
||||||
public float XvehicleAngularDamping;
|
|
||||||
|
|
||||||
public float maxPersistantManifoldPoolSize;
|
public float maxPersistantManifoldPoolSize;
|
||||||
public float maxCollisionAlgorithmPoolSize;
|
public float maxCollisionAlgorithmPoolSize;
|
||||||
public float shouldDisableContactPoolDynamicAllocation;
|
public float shouldDisableContactPoolDynamicAllocation;
|
||||||
|
@ -188,22 +183,30 @@ public struct ConfigurationParameters
|
||||||
public float shouldSplitSimulationIslands;
|
public float shouldSplitSimulationIslands;
|
||||||
public float shouldEnableFrictionCaching;
|
public float shouldEnableFrictionCaching;
|
||||||
public float numberOfSolverIterations;
|
public float numberOfSolverIterations;
|
||||||
|
public float useSingleSidedMeshes;
|
||||||
|
public float globalContactBreakingThreshold;
|
||||||
|
|
||||||
public float XlinksetImplementation;
|
public float physicsLoggingFrames;
|
||||||
public float XlinkConstraintUseFrameOffset;
|
|
||||||
public float XlinkConstraintEnableTransMotor;
|
|
||||||
public float XlinkConstraintTransMotorMaxVel;
|
|
||||||
public float XlinkConstraintTransMotorMaxForce;
|
|
||||||
public float XlinkConstraintERP;
|
|
||||||
public float XlinkConstraintCFM;
|
|
||||||
public float XlinkConstraintSolverIterations;
|
|
||||||
|
|
||||||
public float XphysicsLoggingFrames;
|
|
||||||
|
|
||||||
public const float numericTrue = 1f;
|
public const float numericTrue = 1f;
|
||||||
public const float numericFalse = 0f;
|
public const float numericFalse = 0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parameters passed for the conversion of a mesh to a hull using Bullet's HACD library.
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct HACDParams
|
||||||
|
{
|
||||||
|
// usual default values
|
||||||
|
public float maxVerticesPerHull; // 100
|
||||||
|
public float minClusters; // 2
|
||||||
|
public float compacityWeight; // 0.1
|
||||||
|
public float volumeWeight; // 0.0
|
||||||
|
public float concavity; // 100
|
||||||
|
public float addExtraDistPoints; // false
|
||||||
|
public float addNeighboursDistPoints; // false
|
||||||
|
public float addFacesPoints; // false
|
||||||
|
public float shouldAdjustCollisionMargin; // false
|
||||||
|
}
|
||||||
|
|
||||||
// The states a bullet collision object can have
|
// The states a bullet collision object can have
|
||||||
public enum ActivationState : uint
|
public enum ActivationState : uint
|
||||||
|
@ -238,9 +241,10 @@ public enum CollisionFlags : uint
|
||||||
CF_DISABLE_VISUALIZE_OBJECT = 1 << 5,
|
CF_DISABLE_VISUALIZE_OBJECT = 1 << 5,
|
||||||
CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
|
CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
|
||||||
// Following used by BulletSim to control collisions and updates
|
// Following used by BulletSim to control collisions and updates
|
||||||
BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10,
|
BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, // return collision events from unmanaged to managed
|
||||||
BS_FLOATS_ON_WATER = 1 << 11,
|
BS_FLOATS_ON_WATER = 1 << 11, // the object should float at water level
|
||||||
BS_VEHICLE_COLLISIONS = 1 << 12,
|
BS_VEHICLE_COLLISIONS = 1 << 12, // return collisions for vehicle ground checking
|
||||||
|
BS_RETURN_ROOT_COMPOUND_SHAPE = 1 << 13, // return the pos/rot of the root shape in a compound shape
|
||||||
BS_NONE = 0,
|
BS_NONE = 0,
|
||||||
BS_ALL = 0xFFFFFFFF
|
BS_ALL = 0xFFFFFFFF
|
||||||
};
|
};
|
||||||
|
@ -294,7 +298,7 @@ public abstract class BSAPITemplate
|
||||||
{
|
{
|
||||||
// Returns the name of the underlying Bullet engine
|
// Returns the name of the underlying Bullet engine
|
||||||
public abstract string BulletEngineName { get; }
|
public abstract string BulletEngineName { get; }
|
||||||
public abstract string BulletEngineVersion { get; protected set;}
|
public abstract string BulletEngineVersion { get; protected set;}
|
||||||
|
|
||||||
// Initialization and simulation
|
// Initialization and simulation
|
||||||
public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms,
|
public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms,
|
||||||
|
@ -305,7 +309,7 @@ public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParamet
|
||||||
public abstract int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep,
|
public abstract int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep,
|
||||||
out int updatedEntityCount, out int collidersCount);
|
out int updatedEntityCount, out int collidersCount);
|
||||||
|
|
||||||
public abstract bool UpdateParameter(BulletWorld world, uint localID, String parm, float value);
|
public abstract bool UpdateParameter(BulletWorld world, UInt32 localID, String parm, float value);
|
||||||
|
|
||||||
public abstract void Shutdown(BulletWorld sim);
|
public abstract void Shutdown(BulletWorld sim);
|
||||||
|
|
||||||
|
@ -320,7 +324,13 @@ public abstract BulletShape CreateMeshShape(BulletWorld world,
|
||||||
public abstract BulletShape CreateHullShape(BulletWorld world,
|
public abstract BulletShape CreateHullShape(BulletWorld world,
|
||||||
int hullCount, float[] hulls);
|
int hullCount, float[] hulls);
|
||||||
|
|
||||||
public abstract BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape);
|
public abstract BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms);
|
||||||
|
|
||||||
|
public abstract BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape);
|
||||||
|
|
||||||
|
public abstract BulletShape CreateConvexHullShape(BulletWorld world,
|
||||||
|
int indicesCount, int[] indices,
|
||||||
|
int verticesCount, float[] vertices );
|
||||||
|
|
||||||
public abstract BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData);
|
public abstract BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData);
|
||||||
|
|
||||||
|
@ -342,26 +352,28 @@ public abstract BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape c
|
||||||
|
|
||||||
public abstract void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape);
|
public abstract void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape);
|
||||||
|
|
||||||
|
public abstract void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb);
|
||||||
|
|
||||||
public abstract void RecalculateCompoundShapeLocalAabb(BulletShape cShape);
|
public abstract void RecalculateCompoundShapeLocalAabb(BulletShape cShape);
|
||||||
|
|
||||||
public abstract BulletShape DuplicateCollisionShape(BulletWorld sim, BulletShape srcShape, uint id);
|
public abstract BulletShape DuplicateCollisionShape(BulletWorld sim, BulletShape srcShape, UInt32 id);
|
||||||
|
|
||||||
public abstract bool DeleteCollisionShape(BulletWorld world, BulletShape shape);
|
public abstract bool DeleteCollisionShape(BulletWorld world, BulletShape shape);
|
||||||
|
|
||||||
public abstract CollisionObjectTypes GetBodyType(BulletBody obj);
|
public abstract CollisionObjectTypes GetBodyType(BulletBody obj);
|
||||||
|
|
||||||
public abstract BulletBody CreateBodyFromShape(BulletWorld sim, BulletShape shape, uint id, Vector3 pos, Quaternion rot);
|
public abstract BulletBody CreateBodyFromShape(BulletWorld sim, BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot);
|
||||||
|
|
||||||
public abstract BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, uint id, Vector3 pos, Quaternion rot);
|
public abstract BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot);
|
||||||
|
|
||||||
public abstract BulletBody CreateGhostFromShape(BulletWorld sim, BulletShape shape, uint id, Vector3 pos, Quaternion rot);
|
public abstract BulletBody CreateGhostFromShape(BulletWorld sim, BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot);
|
||||||
|
|
||||||
public abstract void DestroyObject(BulletWorld sim, BulletBody obj);
|
public abstract void DestroyObject(BulletWorld sim, BulletBody obj);
|
||||||
|
|
||||||
// =====================================================================================
|
// =====================================================================================
|
||||||
public abstract BulletShape CreateGroundPlaneShape(uint id, float height, float collisionMargin);
|
public abstract BulletShape CreateGroundPlaneShape(UInt32 id, float height, float collisionMargin);
|
||||||
|
|
||||||
public abstract BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
|
public abstract BulletShape CreateTerrainShape(UInt32 id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
|
||||||
float scaleFactor, float collisionMargin);
|
float scaleFactor, float collisionMargin);
|
||||||
|
|
||||||
// =====================================================================================
|
// =====================================================================================
|
||||||
|
@ -375,11 +387,38 @@ public abstract BulletConstraint Create6DofConstraintToPoint(BulletWorld world,
|
||||||
Vector3 joinPoint,
|
Vector3 joinPoint,
|
||||||
bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
|
bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
|
||||||
|
|
||||||
|
public abstract BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1,
|
||||||
|
Vector3 frameInBloc, Quaternion frameInBrot,
|
||||||
|
bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies);
|
||||||
|
|
||||||
|
public abstract BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
|
||||||
|
Vector3 frame1loc, Quaternion frame1rot,
|
||||||
|
Vector3 frame2loc, Quaternion frame2rot,
|
||||||
|
bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
|
||||||
|
|
||||||
public abstract BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
|
public abstract BulletConstraint CreateHingeConstraint(BulletWorld 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);
|
||||||
|
|
||||||
|
public abstract BulletConstraint CreateSliderConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
|
||||||
|
Vector3 frameInAloc, Quaternion frameInArot,
|
||||||
|
Vector3 frameInBloc, Quaternion frameInBrot,
|
||||||
|
bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
|
||||||
|
|
||||||
|
public abstract BulletConstraint CreateConeTwistConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
|
||||||
|
Vector3 frameInAloc, Quaternion frameInArot,
|
||||||
|
Vector3 frameInBloc, Quaternion frameInBrot,
|
||||||
|
bool disableCollisionsBetweenLinkedBodies);
|
||||||
|
|
||||||
|
public abstract BulletConstraint CreateGearConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
|
||||||
|
Vector3 axisInA, Vector3 axisInB,
|
||||||
|
float ratio, bool disableCollisionsBetweenLinkedBodies);
|
||||||
|
|
||||||
|
public abstract BulletConstraint CreatePoint2PointConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
|
||||||
|
Vector3 pivotInA, Vector3 pivotInB,
|
||||||
|
bool disableCollisionsBetweenLinkedBodies);
|
||||||
|
|
||||||
public abstract void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse);
|
public abstract void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse);
|
||||||
|
|
||||||
public abstract void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations);
|
public abstract void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations);
|
||||||
|
@ -607,7 +646,7 @@ public abstract BulletConstraint GetConstraintRef(BulletBody obj, int index);
|
||||||
|
|
||||||
public abstract int GetNumConstraintRefs(BulletBody obj);
|
public abstract int GetNumConstraintRefs(BulletBody obj);
|
||||||
|
|
||||||
public abstract bool SetCollisionGroupMask(BulletBody body, uint filter, uint mask);
|
public abstract bool SetCollisionGroupMask(BulletBody body, UInt32 filter, UInt32 mask);
|
||||||
|
|
||||||
// =====================================================================================
|
// =====================================================================================
|
||||||
// btCollisionShape entries
|
// btCollisionShape entries
|
||||||
|
@ -646,17 +685,21 @@ public abstract float GetMargin(BulletShape shape);
|
||||||
|
|
||||||
// =====================================================================================
|
// =====================================================================================
|
||||||
// Debugging
|
// Debugging
|
||||||
public abstract void DumpRigidBody(BulletWorld sim, BulletBody collisionObject);
|
public virtual void DumpRigidBody(BulletWorld sim, BulletBody collisionObject) { }
|
||||||
|
|
||||||
public abstract void DumpCollisionShape(BulletWorld sim, BulletShape collisionShape);
|
public virtual void DumpCollisionShape(BulletWorld sim, BulletShape collisionShape) { }
|
||||||
|
|
||||||
public abstract void DumpConstraint(BulletWorld sim, BulletConstraint constrain);
|
public virtual void DumpConstraint(BulletWorld sim, BulletConstraint constrain) { }
|
||||||
|
|
||||||
public abstract void DumpActivationInfo(BulletWorld sim);
|
public virtual void DumpActivationInfo(BulletWorld sim) { }
|
||||||
|
|
||||||
public abstract void DumpAllInfo(BulletWorld sim);
|
public virtual void DumpAllInfo(BulletWorld sim) { }
|
||||||
|
|
||||||
public abstract void DumpPhysicsStatistics(BulletWorld sim);
|
public virtual void DumpPhysicsStatistics(BulletWorld sim) { }
|
||||||
|
|
||||||
|
public virtual void ResetBroadphasePool(BulletWorld sim) { }
|
||||||
|
|
||||||
|
public virtual void ResetConstraintSolver(BulletWorld sim) { }
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
*
|
*
|
||||||
|
@ -45,11 +45,7 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
private bool _selected;
|
private bool _selected;
|
||||||
private OMV.Vector3 _position;
|
private OMV.Vector3 _position;
|
||||||
private float _mass;
|
private float _mass;
|
||||||
private float _avatarDensity;
|
|
||||||
private float _avatarVolume;
|
private float _avatarVolume;
|
||||||
private OMV.Vector3 _force;
|
|
||||||
private OMV.Vector3 _velocity;
|
|
||||||
private OMV.Vector3 _torque;
|
|
||||||
private float _collisionScore;
|
private float _collisionScore;
|
||||||
private OMV.Vector3 _acceleration;
|
private OMV.Vector3 _acceleration;
|
||||||
private OMV.Quaternion _orientation;
|
private OMV.Quaternion _orientation;
|
||||||
|
@ -58,25 +54,17 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
private bool _flying;
|
private bool _flying;
|
||||||
private bool _setAlwaysRun;
|
private bool _setAlwaysRun;
|
||||||
private bool _throttleUpdates;
|
private bool _throttleUpdates;
|
||||||
private bool _isColliding;
|
|
||||||
private bool _collidingObj;
|
|
||||||
private bool _floatOnWater;
|
private bool _floatOnWater;
|
||||||
private OMV.Vector3 _rotationalVelocity;
|
private OMV.Vector3 _rotationalVelocity;
|
||||||
private bool _kinematic;
|
private bool _kinematic;
|
||||||
private float _buoyancy;
|
private float _buoyancy;
|
||||||
|
|
||||||
// The friction and velocity of the avatar is modified depending on whether walking or not.
|
private BSActorAvatarMove m_moveActor;
|
||||||
private float _currentFriction; // the friction currently being used (changed by setVelocity).
|
private const string AvatarMoveActorName = "BSCharacter.AvatarMove";
|
||||||
|
|
||||||
private BSVMotor _velocityMotor;
|
|
||||||
|
|
||||||
private OMV.Vector3 _PIDTarget;
|
private OMV.Vector3 _PIDTarget;
|
||||||
private bool _usePID;
|
private bool _usePID;
|
||||||
private float _PIDTau;
|
private float _PIDTau;
|
||||||
private bool _useHoverPID;
|
|
||||||
private float _PIDHoverHeight;
|
|
||||||
private PIDHoverType _PIDHoverType;
|
|
||||||
private float _PIDHoverTao;
|
|
||||||
|
|
||||||
public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying)
|
public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying)
|
||||||
: base(parent_scene, localID, avName, "BSCharacter")
|
: base(parent_scene, localID, avName, "BSCharacter")
|
||||||
|
@ -86,10 +74,10 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
|
|
||||||
_flying = isFlying;
|
_flying = isFlying;
|
||||||
_orientation = OMV.Quaternion.Identity;
|
_orientation = OMV.Quaternion.Identity;
|
||||||
_velocity = OMV.Vector3.Zero;
|
RawVelocity = OMV.Vector3.Zero;
|
||||||
_buoyancy = ComputeBuoyancyFromFlying(isFlying);
|
_buoyancy = ComputeBuoyancyFromFlying(isFlying);
|
||||||
_currentFriction = BSParam.AvatarStandingFriction;
|
Friction = BSParam.AvatarStandingFriction;
|
||||||
_avatarDensity = BSParam.AvatarDensity;
|
Density = BSParam.AvatarDensity / BSParam.DensityScaleFactor;
|
||||||
|
|
||||||
// Old versions of ScenePresence passed only the height. If width and/or depth are zero,
|
// Old versions of ScenePresence passed only the height. If width and/or depth are zero,
|
||||||
// replace with the default values.
|
// replace with the default values.
|
||||||
|
@ -103,17 +91,22 @@ public sealed 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();
|
||||||
|
|
||||||
SetupMovementMotor();
|
// The avatar's movement is controlled by this motor that speeds up and slows down
|
||||||
|
// the avatar seeking to reach the motor's target speed.
|
||||||
|
// This motor runs as a prestep action for the avatar so it will keep the avatar
|
||||||
|
// standing as well as moving. Destruction of the avatar will destroy the pre-step action.
|
||||||
|
m_moveActor = new BSActorAvatarMove(PhysScene, this, AvatarMoveActorName);
|
||||||
|
PhysicalActors.Add(AvatarMoveActorName, m_moveActor);
|
||||||
|
|
||||||
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, RawMass);
|
LocalID, _size, Scale, Density, _avatarVolume, RawMass);
|
||||||
|
|
||||||
// do actual creation in taint time
|
// do actual creation in taint time
|
||||||
PhysicsScene.TaintedObject("BSCharacter.create", delegate()
|
PhysScene.TaintedObject("BSCharacter.create", delegate()
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSCharacter.create,taint", LocalID);
|
DetailLog("{0},BSCharacter.create,taint", LocalID);
|
||||||
// New body and shape into PhysBody and PhysShape
|
// New body and shape into PhysBody and PhysShape
|
||||||
PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this);
|
PhysScene.Shapes.GetBodyAndShape(true, PhysScene.World, this);
|
||||||
|
|
||||||
SetPhysicalProperties();
|
SetPhysicalProperties();
|
||||||
});
|
});
|
||||||
|
@ -126,114 +119,63 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
base.Destroy();
|
base.Destroy();
|
||||||
|
|
||||||
DetailLog("{0},BSCharacter.Destroy", LocalID);
|
DetailLog("{0},BSCharacter.Destroy", LocalID);
|
||||||
PhysicsScene.TaintedObject("BSCharacter.destroy", delegate()
|
PhysScene.TaintedObject("BSCharacter.destroy", delegate()
|
||||||
{
|
{
|
||||||
PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null);
|
PhysScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */);
|
||||||
PhysBody.Clear();
|
PhysBody.Clear();
|
||||||
PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null);
|
PhysShape.Dereference(PhysScene);
|
||||||
PhysShape.Clear();
|
PhysShape = new BSShapeNull();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetPhysicalProperties()
|
private void SetPhysicalProperties()
|
||||||
{
|
{
|
||||||
PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody);
|
PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
|
||||||
|
|
||||||
ZeroMotion(true);
|
ZeroMotion(true);
|
||||||
ForcePosition = _position;
|
ForcePosition = _position;
|
||||||
|
|
||||||
// Set the velocity and compute the proper friction
|
// Set the velocity
|
||||||
_velocityMotor.Reset();
|
if (m_moveActor != null)
|
||||||
_velocityMotor.SetTarget(_velocity);
|
m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, false);
|
||||||
_velocityMotor.SetCurrent(_velocity);
|
|
||||||
ForceVelocity = _velocity;
|
ForceVelocity = RawVelocity;
|
||||||
|
|
||||||
// This will enable or disable the flying buoyancy of the avatar.
|
// This will enable or disable the flying buoyancy of the avatar.
|
||||||
// Needs to be reset especially when an avatar is recreated after crossing a region boundry.
|
// Needs to be reset especially when an avatar is recreated after crossing a region boundry.
|
||||||
Flying = _flying;
|
Flying = _flying;
|
||||||
|
|
||||||
PhysicsScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution);
|
PhysScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution);
|
||||||
PhysicsScene.PE.SetMargin(PhysShape, PhysicsScene.Params.collisionMargin);
|
PhysScene.PE.SetMargin(PhysShape.physShapeInfo, PhysScene.Params.collisionMargin);
|
||||||
PhysicsScene.PE.SetLocalScaling(PhysShape, Scale);
|
PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale);
|
||||||
PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
|
PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
|
||||||
if (BSParam.CcdMotionThreshold > 0f)
|
if (BSParam.CcdMotionThreshold > 0f)
|
||||||
{
|
{
|
||||||
PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
|
PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
|
||||||
PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
|
PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdatePhysicalMassProperties(RawMass, false);
|
UpdatePhysicalMassProperties(RawMass, false);
|
||||||
|
|
||||||
// Make so capsule does not fall over
|
// Make so capsule does not fall over
|
||||||
PhysicsScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero);
|
PhysScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero);
|
||||||
|
|
||||||
PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT);
|
// The avatar mover sets some parameters.
|
||||||
|
PhysicalActors.Refresh();
|
||||||
|
|
||||||
PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody);
|
PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT);
|
||||||
|
|
||||||
|
PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody);
|
||||||
|
|
||||||
// PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
|
// PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
|
||||||
PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION);
|
PhysScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION);
|
||||||
PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody);
|
PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody);
|
||||||
|
|
||||||
// Do this after the object has been added to the world
|
// Do this after the object has been added to the world
|
||||||
PhysBody.collisionType = CollisionType.Avatar;
|
PhysBody.collisionType = CollisionType.Avatar;
|
||||||
PhysBody.ApplyCollisionMask(PhysicsScene);
|
PhysBody.ApplyCollisionMask(PhysScene);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The avatar's movement is controlled by this motor that speeds up and slows down
|
|
||||||
// the avatar seeking to reach the motor's target speed.
|
|
||||||
// This motor runs as a prestep action for the avatar so it will keep the avatar
|
|
||||||
// standing as well as moving. Destruction of the avatar will destroy the pre-step action.
|
|
||||||
private void SetupMovementMotor()
|
|
||||||
{
|
|
||||||
|
|
||||||
// Someday, use a PID motor for asymmetric speed up and slow down
|
|
||||||
// _velocityMotor = new BSPIDVMotor("BSCharacter.Velocity", 3f, 5f, BSMotor.InfiniteVector, 1f);
|
|
||||||
|
|
||||||
// Infinite decay and timescale values so motor only changes current to target values.
|
|
||||||
_velocityMotor = new BSVMotor("BSCharacter.Velocity",
|
|
||||||
0.2f, // time scale
|
|
||||||
BSMotor.Infinite, // decay time scale
|
|
||||||
BSMotor.InfiniteVector, // friction timescale
|
|
||||||
1f // efficiency
|
|
||||||
);
|
|
||||||
// _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
|
|
||||||
|
|
||||||
RegisterPreStepAction("BSCharactor.Movement", LocalID, delegate(float timeStep)
|
|
||||||
{
|
|
||||||
// TODO: Decide if the step parameters should be changed depending on the avatar's
|
|
||||||
// state (flying, colliding, ...). There is code in ODE to do this.
|
|
||||||
|
|
||||||
OMV.Vector3 stepVelocity = _velocityMotor.Step(timeStep);
|
|
||||||
|
|
||||||
// If falling, we keep the world's downward vector no matter what the other axis specify.
|
|
||||||
if (!Flying && !IsColliding)
|
|
||||||
{
|
|
||||||
stepVelocity.Z = _velocity.Z;
|
|
||||||
// DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force.
|
|
||||||
OMV.Vector3 moveForce = (stepVelocity - _velocity) * Mass / PhysicsScene.LastTimeStep;
|
|
||||||
|
|
||||||
/*
|
|
||||||
// If moveForce is very small, zero things so we don't keep sending microscopic updates to the user
|
|
||||||
float moveForceMagnitudeSquared = moveForce.LengthSquared();
|
|
||||||
if (moveForceMagnitudeSquared < 0.0001)
|
|
||||||
{
|
|
||||||
DetailLog("{0},BSCharacter.MoveMotor,zeroMovement,stepVel={1},vel={2},mass={3},magSq={4},moveForce={5}",
|
|
||||||
LocalID, stepVelocity, _velocity, Mass, moveForceMagnitudeSquared, moveForce);
|
|
||||||
ForceVelocity = OMV.Vector3.Zero;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AddForce(moveForce, false, true);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
// DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", LocalID, stepVelocity, _velocity, Mass, moveForce);
|
|
||||||
AddForce(moveForce, false, true);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void RequestPhysicsterseUpdate()
|
public override void RequestPhysicsterseUpdate()
|
||||||
{
|
{
|
||||||
|
@ -259,16 +201,16 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
Scale = ComputeAvatarScale(_size);
|
Scale = ComputeAvatarScale(_size);
|
||||||
ComputeAvatarVolumeAndMass();
|
ComputeAvatarVolumeAndMass();
|
||||||
DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}",
|
DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}",
|
||||||
LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
|
LocalID, _size, Scale, Density, _avatarVolume, RawMass);
|
||||||
|
|
||||||
PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
|
PhysScene.TaintedObject("BSCharacter.setSize", delegate()
|
||||||
{
|
{
|
||||||
if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape)
|
if (PhysBody.HasPhysicalBody && PhysShape.physShapeInfo.HasPhysicalShape)
|
||||||
{
|
{
|
||||||
PhysicsScene.PE.SetLocalScaling(PhysShape, Scale);
|
PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale);
|
||||||
UpdatePhysicalMassProperties(RawMass, true);
|
UpdatePhysicalMassProperties(RawMass, true);
|
||||||
// Make sure this change appears as a property update event
|
// Make sure this change appears as a property update event
|
||||||
PhysicsScene.PE.PushUpdate(PhysBody);
|
PhysScene.PE.PushUpdate(PhysBody);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -279,11 +221,6 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
{
|
{
|
||||||
set { BaseShape = value; }
|
set { BaseShape = value; }
|
||||||
}
|
}
|
||||||
// I want the physics engine to make an avatar capsule
|
|
||||||
public override BSPhysicsShapeType PreferredPhysicalShape
|
|
||||||
{
|
|
||||||
get {return BSPhysicsShapeType.SHAPE_CAPSULE; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Grabbed {
|
public override bool Grabbed {
|
||||||
set { _grabbed = value; }
|
set { _grabbed = value; }
|
||||||
|
@ -291,6 +228,10 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
public override bool Selected {
|
public override bool Selected {
|
||||||
set { _selected = value; }
|
set { _selected = value; }
|
||||||
}
|
}
|
||||||
|
public override bool IsSelected
|
||||||
|
{
|
||||||
|
get { return _selected; }
|
||||||
|
}
|
||||||
public override void CrossingFailure() { return; }
|
public override void CrossingFailure() { return; }
|
||||||
public override void link(PhysicsActor obj) { return; }
|
public override void link(PhysicsActor obj) { return; }
|
||||||
public override void delink() { return; }
|
public override void delink() { return; }
|
||||||
|
@ -301,29 +242,29 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
// Called at taint time!
|
// Called at taint time!
|
||||||
public override void ZeroMotion(bool inTaintTime)
|
public override void ZeroMotion(bool inTaintTime)
|
||||||
{
|
{
|
||||||
_velocity = OMV.Vector3.Zero;
|
RawVelocity = 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
|
||||||
PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
|
PhysScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
|
||||||
{
|
{
|
||||||
if (PhysBody.HasPhysicalBody)
|
if (PhysBody.HasPhysicalBody)
|
||||||
PhysicsScene.PE.ClearAllForces(PhysBody);
|
PhysScene.PE.ClearAllForces(PhysBody);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public override void ZeroAngularMotion(bool inTaintTime)
|
public override void ZeroAngularMotion(bool inTaintTime)
|
||||||
{
|
{
|
||||||
_rotationalVelocity = OMV.Vector3.Zero;
|
_rotationalVelocity = OMV.Vector3.Zero;
|
||||||
|
|
||||||
PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
|
PhysScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
|
||||||
{
|
{
|
||||||
if (PhysBody.HasPhysicalBody)
|
if (PhysBody.HasPhysicalBody)
|
||||||
{
|
{
|
||||||
PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero);
|
PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero);
|
||||||
PhysicsScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero);
|
PhysScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero);
|
||||||
// The next also get rid of applied linear force but the linear velocity is untouched.
|
// The next also get rid of applied linear force but the linear velocity is untouched.
|
||||||
PhysicsScene.PE.ClearForces(PhysBody);
|
PhysScene.PE.ClearForces(PhysBody);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -344,25 +285,26 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
_position = value;
|
_position = value;
|
||||||
PositionSanityCheck();
|
|
||||||
|
|
||||||
PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate()
|
PhysScene.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);
|
||||||
if (PhysBody.HasPhysicalBody)
|
PositionSanityCheck();
|
||||||
PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
|
ForcePosition = _position;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public override OMV.Vector3 ForcePosition {
|
public override OMV.Vector3 ForcePosition {
|
||||||
get {
|
get {
|
||||||
_position = PhysicsScene.PE.GetPosition(PhysBody);
|
_position = PhysScene.PE.GetPosition(PhysBody);
|
||||||
return _position;
|
return _position;
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
_position = value;
|
_position = value;
|
||||||
PositionSanityCheck();
|
if (PhysBody.HasPhysicalBody)
|
||||||
PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
|
{
|
||||||
|
PhysScene.PE.SetTranslation(PhysBody, _position, _orientation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -375,25 +317,27 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
// TODO: check for out of bounds
|
// TODO: check for out of bounds
|
||||||
if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position))
|
if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition))
|
||||||
{
|
{
|
||||||
// The character is out of the known/simulated area.
|
// The character is out of the known/simulated area.
|
||||||
// Upper levels of code will handle the transition to other areas so, for
|
// Force the avatar position to be within known. ScenePresence will use the position
|
||||||
// the time, we just ignore the position.
|
// plus the velocity to decide if the avatar is moving out of the region.
|
||||||
return ret;
|
RawPosition = PhysScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition);
|
||||||
|
DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If below the ground, move the avatar up
|
// If below the ground, move the avatar up
|
||||||
float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
|
float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
|
||||||
if (Position.Z < terrainHeight)
|
if (Position.Z < terrainHeight)
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
|
DetailLog("{0},BSCharacter.PositionSanityCheck,adjustForUnderGround,pos={1},terrain={2}", LocalID, _position, terrainHeight);
|
||||||
_position.Z = terrainHeight + 2.0f;
|
_position.Z = terrainHeight + BSParam.AvatarBelowGroundUpCorrectionMeters;
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
|
if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
|
||||||
{
|
{
|
||||||
float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
|
float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(_position);
|
||||||
if (Position.Z < waterHeight)
|
if (Position.Z < waterHeight)
|
||||||
{
|
{
|
||||||
_position.Z = waterHeight;
|
_position.Z = waterHeight;
|
||||||
|
@ -414,11 +358,10 @@ public sealed 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.
|
||||||
PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate()
|
PhysScene.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);
|
||||||
if (PhysBody.HasPhysicalBody)
|
ForcePosition = _position;
|
||||||
PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
|
|
||||||
});
|
});
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
|
@ -428,25 +371,25 @@ public sealed 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 RawMass {
|
public override float RawMass {
|
||||||
get {return _mass; }
|
get {return _mass; }
|
||||||
}
|
}
|
||||||
public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
|
public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
|
||||||
{
|
{
|
||||||
OMV.Vector3 localInertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass);
|
OMV.Vector3 localInertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass);
|
||||||
PhysicsScene.PE.SetMassProps(PhysBody, physMass, localInertia);
|
PhysScene.PE.SetMassProps(PhysBody, physMass, localInertia);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override OMV.Vector3 Force {
|
public override OMV.Vector3 Force {
|
||||||
get { return _force; }
|
get { return RawForce; }
|
||||||
set {
|
set {
|
||||||
_force = value;
|
RawForce = value;
|
||||||
// m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
|
// m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
|
||||||
PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate()
|
PhysScene.TaintedObject("BSCharacter.SetForce", delegate()
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
|
DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, RawForce);
|
||||||
if (PhysBody.HasPhysicalBody)
|
if (PhysBody.HasPhysicalBody)
|
||||||
PhysicsScene.PE.SetObjectForce(PhysBody, _force);
|
PhysScene.PE.SetObjectForce(PhysBody, RawForce);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -469,77 +412,49 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return _velocityMotor.TargetValue;
|
return base.m_targetVelocity;
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value);
|
DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value);
|
||||||
|
m_targetVelocity = value;
|
||||||
OMV.Vector3 targetVel = value;
|
OMV.Vector3 targetVel = value;
|
||||||
if (_setAlwaysRun)
|
if (_setAlwaysRun && !_flying)
|
||||||
targetVel *= BSParam.AvatarAlwaysRunFactor;
|
targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 0f);
|
||||||
|
|
||||||
PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate()
|
if (m_moveActor != null)
|
||||||
{
|
m_moveActor.SetVelocityAndTarget(RawVelocity, targetVel, false /* inTaintTime */);
|
||||||
_velocityMotor.Reset();
|
|
||||||
_velocityMotor.SetTarget(targetVel);
|
|
||||||
_velocityMotor.SetCurrent(_velocity);
|
|
||||||
_velocityMotor.Enabled = true;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Directly setting velocity means this is what the user really wants now.
|
// Directly setting velocity means this is what the user really wants now.
|
||||||
public override OMV.Vector3 Velocity {
|
public override OMV.Vector3 Velocity {
|
||||||
get { return _velocity; }
|
get { return RawVelocity; }
|
||||||
set {
|
set {
|
||||||
_velocity = value;
|
RawVelocity = value;
|
||||||
// m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity);
|
// m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, RawVelocity);
|
||||||
PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate()
|
PhysScene.TaintedObject("BSCharacter.setVelocity", delegate()
|
||||||
{
|
{
|
||||||
_velocityMotor.Reset();
|
if (m_moveActor != null)
|
||||||
_velocityMotor.SetCurrent(_velocity);
|
m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, true /* inTaintTime */);
|
||||||
_velocityMotor.SetTarget(_velocity);
|
|
||||||
// Even though the motor is initialized, it's not used and the velocity goes straight into the avatar.
|
|
||||||
_velocityMotor.Enabled = false;
|
|
||||||
|
|
||||||
DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity);
|
DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, RawVelocity);
|
||||||
ForceVelocity = _velocity;
|
ForceVelocity = RawVelocity;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public override OMV.Vector3 ForceVelocity {
|
public override OMV.Vector3 ForceVelocity {
|
||||||
get { return _velocity; }
|
get { return RawVelocity; }
|
||||||
set {
|
set {
|
||||||
PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity");
|
PhysScene.AssertInTaintTime("BSCharacter.ForceVelocity");
|
||||||
|
|
||||||
_velocity = value;
|
RawVelocity = value;
|
||||||
// Depending on whether the avatar is moving or not, change the friction
|
PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity);
|
||||||
// to keep the avatar from slipping around
|
PhysScene.PE.Activate(PhysBody, true);
|
||||||
if (_velocity.Length() == 0)
|
|
||||||
{
|
|
||||||
if (_currentFriction != BSParam.AvatarStandingFriction)
|
|
||||||
{
|
|
||||||
_currentFriction = BSParam.AvatarStandingFriction;
|
|
||||||
if (PhysBody.HasPhysicalBody)
|
|
||||||
PhysicsScene.PE.SetFriction(PhysBody, _currentFriction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (_currentFriction != BSParam.AvatarFriction)
|
|
||||||
{
|
|
||||||
_currentFriction = BSParam.AvatarFriction;
|
|
||||||
if (PhysBody.HasPhysicalBody)
|
|
||||||
PhysicsScene.PE.SetFriction(PhysBody, _currentFriction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity);
|
|
||||||
PhysicsScene.PE.Activate(PhysBody, true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public override OMV.Vector3 Torque {
|
public override OMV.Vector3 Torque {
|
||||||
get { return _torque; }
|
get { return RawTorque; }
|
||||||
set { _torque = value;
|
set { RawTorque = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public override float CollisionScore {
|
public override float CollisionScore {
|
||||||
|
@ -564,9 +479,19 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
if (_orientation != value)
|
if (_orientation != value)
|
||||||
{
|
{
|
||||||
_orientation = value;
|
_orientation = value;
|
||||||
PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate()
|
PhysScene.TaintedObject("BSCharacter.setOrientation", delegate()
|
||||||
{
|
{
|
||||||
ForceOrientation = _orientation;
|
// Bullet assumes we know what we are doing when forcing orientation
|
||||||
|
// so it lets us go against all the rules and just compensates for them later.
|
||||||
|
// This forces rotation to be only around the Z axis and doesn't change any of the other axis.
|
||||||
|
// This keeps us from flipping the capsule over which the veiwer does not understand.
|
||||||
|
float oRoll, oPitch, oYaw;
|
||||||
|
_orientation.GetEulerAngles(out oRoll, out oPitch, out oYaw);
|
||||||
|
OMV.Quaternion trimmedOrientation = OMV.Quaternion.CreateFromEulers(0f, 0f, oYaw);
|
||||||
|
// DetailLog("{0},BSCharacter.setOrientation,taint,val={1},valDir={2},conv={3},convDir={4}",
|
||||||
|
// LocalID, _orientation, OMV.Vector3.UnitX * _orientation,
|
||||||
|
// trimmedOrientation, OMV.Vector3.UnitX * trimmedOrientation);
|
||||||
|
ForceOrientation = trimmedOrientation;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -576,7 +501,7 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
_orientation = PhysicsScene.PE.GetOrientation(PhysBody);
|
_orientation = PhysScene.PE.GetOrientation(PhysBody);
|
||||||
return _orientation;
|
return _orientation;
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
|
@ -585,7 +510,7 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
if (PhysBody.HasPhysicalBody)
|
if (PhysBody.HasPhysicalBody)
|
||||||
{
|
{
|
||||||
// _position = PhysicsScene.PE.GetPosition(BSBody);
|
// _position = PhysicsScene.PE.GetPosition(BSBody);
|
||||||
PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
|
PhysScene.PE.SetTranslation(PhysBody, _position, _orientation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -605,6 +530,9 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
public override bool IsStatic {
|
public override bool IsStatic {
|
||||||
get { return false; }
|
get { return false; }
|
||||||
}
|
}
|
||||||
|
public override bool IsPhysicallyActive {
|
||||||
|
get { return true; }
|
||||||
|
}
|
||||||
public override bool Flying {
|
public override bool Flying {
|
||||||
get { return _flying; }
|
get { return _flying; }
|
||||||
set {
|
set {
|
||||||
|
@ -631,14 +559,14 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
public override bool FloatOnWater {
|
public override bool FloatOnWater {
|
||||||
set {
|
set {
|
||||||
_floatOnWater = value;
|
_floatOnWater = value;
|
||||||
PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate()
|
PhysScene.TaintedObject("BSCharacter.setFloatOnWater", delegate()
|
||||||
{
|
{
|
||||||
if (PhysBody.HasPhysicalBody)
|
if (PhysBody.HasPhysicalBody)
|
||||||
{
|
{
|
||||||
if (_floatOnWater)
|
if (_floatOnWater)
|
||||||
CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
|
CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
|
||||||
else
|
else
|
||||||
CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
|
CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -659,7 +587,7 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
public override float Buoyancy {
|
public override float Buoyancy {
|
||||||
get { return _buoyancy; }
|
get { return _buoyancy; }
|
||||||
set { _buoyancy = value;
|
set { _buoyancy = value;
|
||||||
PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate()
|
PhysScene.TaintedObject("BSCharacter.setBuoyancy", delegate()
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
|
DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
|
||||||
ForceBuoyancy = _buoyancy;
|
ForceBuoyancy = _buoyancy;
|
||||||
|
@ -668,15 +596,16 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
}
|
}
|
||||||
public override float ForceBuoyancy {
|
public override float ForceBuoyancy {
|
||||||
get { return _buoyancy; }
|
get { return _buoyancy; }
|
||||||
set {
|
set {
|
||||||
PhysicsScene.AssertInTaintTime("BSCharacter.ForceBuoyancy");
|
PhysScene.AssertInTaintTime("BSCharacter.ForceBuoyancy");
|
||||||
|
|
||||||
_buoyancy = value;
|
_buoyancy = value;
|
||||||
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 = BSParam.Gravity * (1f - _buoyancy);
|
||||||
|
Gravity = new OMV.Vector3(0f, 0f, grav);
|
||||||
if (PhysBody.HasPhysicalBody)
|
if (PhysBody.HasPhysicalBody)
|
||||||
PhysicsScene.PE.SetGravity(PhysBody, new OMV.Vector3(0f, 0f, grav));
|
PhysScene.PE.SetGravity(PhysBody, Gravity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -691,53 +620,25 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
set { _PIDTau = value; }
|
set { _PIDTau = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used for llSetHoverHeight and maybe vehicle height
|
|
||||||
// Hover Height will override MoveTo target's Z
|
|
||||||
public override bool PIDHoverActive {
|
|
||||||
set { _useHoverPID = value; }
|
|
||||||
}
|
|
||||||
public override float PIDHoverHeight {
|
|
||||||
set { _PIDHoverHeight = value; }
|
|
||||||
}
|
|
||||||
public override PIDHoverType PIDHoverType {
|
|
||||||
set { _PIDHoverType = value; }
|
|
||||||
}
|
|
||||||
public override float PIDHoverTau {
|
|
||||||
set { _PIDHoverTao = value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
// For RotLookAt
|
|
||||||
public override OMV.Quaternion APIDTarget { set { return; } }
|
|
||||||
public override bool APIDActive { set { return; } }
|
|
||||||
public override float APIDStrength { set { return; } }
|
|
||||||
public override float APIDDamping { set { return; } }
|
|
||||||
|
|
||||||
public override void AddForce(OMV.Vector3 force, bool pushforce)
|
public override void AddForce(OMV.Vector3 force, bool pushforce)
|
||||||
{
|
{
|
||||||
// Since this force is being applied in only one step, make this a force per second.
|
// Since this force is being applied in only one step, make this a force per second.
|
||||||
OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep;
|
OMV.Vector3 addForce = force / PhysScene.LastTimeStep;
|
||||||
AddForce(addForce, pushforce, false);
|
AddForce(addForce, pushforce, false);
|
||||||
}
|
}
|
||||||
private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
|
private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
|
||||||
if (force.IsFinite())
|
if (force.IsFinite())
|
||||||
{
|
{
|
||||||
float magnitude = force.Length();
|
OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);
|
||||||
if (magnitude > BSParam.MaxAddForceMagnitude)
|
|
||||||
{
|
|
||||||
// Force has a limit
|
|
||||||
force = force / magnitude * BSParam.MaxAddForceMagnitude;
|
|
||||||
}
|
|
||||||
|
|
||||||
OMV.Vector3 addForce = force;
|
|
||||||
// DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce);
|
// DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce);
|
||||||
|
|
||||||
PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate()
|
PhysScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate()
|
||||||
{
|
{
|
||||||
// Bullet adds this central force to the total force for this tick
|
// Bullet adds this central force to the total force for this tick
|
||||||
// DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce);
|
// DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce);
|
||||||
if (PhysBody.HasPhysicalBody)
|
if (PhysBody.HasPhysicalBody)
|
||||||
{
|
{
|
||||||
PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce);
|
PhysScene.PE.ApplyCentralForce(PhysBody, addForce);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -748,7 +649,7 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
|
public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
|
||||||
}
|
}
|
||||||
public override void SetMomentum(OMV.Vector3 momentum) {
|
public override void SetMomentum(OMV.Vector3 momentum) {
|
||||||
}
|
}
|
||||||
|
@ -756,14 +657,14 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size)
|
private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size)
|
||||||
{
|
{
|
||||||
OMV.Vector3 newScale;
|
OMV.Vector3 newScale;
|
||||||
|
|
||||||
// Bullet's capsule total height is the "passed height + radius * 2";
|
// Bullet's capsule total height is the "passed height + radius * 2";
|
||||||
// The base capsule is 1 diameter and 2 height (passed radius=0.5, passed height = 1)
|
// The base capsule is 1 unit in diameter and 2 units in height (passed radius=0.5, passed height = 1)
|
||||||
// The number we pass in for 'scaling' is the multiplier to get that base
|
// The number we pass in for 'scaling' is the multiplier to get that base
|
||||||
// shape to be the size desired.
|
// shape to be the size desired.
|
||||||
// So, when creating the scale for the avatar height, we take the passed height
|
// So, when creating the scale for the avatar height, we take the passed height
|
||||||
// (size.Z) and remove the caps.
|
// (size.Z) and remove the caps.
|
||||||
// Another oddity of the Bullet capsule implementation is that it presumes the Y
|
// An oddity of the Bullet capsule implementation is that it presumes the Y
|
||||||
// dimension is the radius of the capsule. Even though some of the code allows
|
// dimension is the radius of the capsule. Even though some of the code allows
|
||||||
// for a asymmetrical capsule, other parts of the code presume it is cylindrical.
|
// for a asymmetrical capsule, other parts of the code presume it is cylindrical.
|
||||||
|
|
||||||
|
@ -771,8 +672,27 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
newScale.X = size.X / 2f;
|
newScale.X = size.X / 2f;
|
||||||
newScale.Y = size.Y / 2f;
|
newScale.Y = size.Y / 2f;
|
||||||
|
|
||||||
|
float heightAdjust = BSParam.AvatarHeightMidFudge;
|
||||||
|
if (BSParam.AvatarHeightLowFudge != 0f || BSParam.AvatarHeightHighFudge != 0f)
|
||||||
|
{
|
||||||
|
// An avatar is between 1.61 and 2.12 meters. Midpoint is 1.87m.
|
||||||
|
// The "times 4" relies on the fact that the difference from the midpoint to the extremes is exactly 0.25
|
||||||
|
float midHeightOffset = size.Z - 1.87f;
|
||||||
|
if (midHeightOffset < 0f)
|
||||||
|
{
|
||||||
|
// Small avatar. Add the adjustment based on the distance from midheight
|
||||||
|
heightAdjust += -1f * midHeightOffset * 4f * BSParam.AvatarHeightLowFudge;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Large avatar. Add the adjustment based on the distance from midheight
|
||||||
|
heightAdjust += midHeightOffset * 4f * BSParam.AvatarHeightHighFudge;
|
||||||
|
}
|
||||||
|
}
|
||||||
// The total scale height is the central cylindar plus the caps on the two ends.
|
// The total scale height is the central cylindar plus the caps on the two ends.
|
||||||
newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2)) / 2f;
|
newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2) + heightAdjust) / 2f;
|
||||||
|
// m_log.DebugFormat("{0} ComputeAvatarScale: size={1},adj={2},scale={3}", LogHeader, size, heightAdjust, newScale);
|
||||||
|
|
||||||
// If smaller than the endcaps, just fake like we're almost that small
|
// If smaller than the endcaps, just fake like we're almost that small
|
||||||
if (newScale.Z < 0)
|
if (newScale.Z < 0)
|
||||||
newScale.Z = 0.1f;
|
newScale.Z = 0.1f;
|
||||||
|
@ -794,34 +714,48 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
* Math.Min(Size.X, Size.Y) / 2
|
* Math.Min(Size.X, Size.Y) / 2
|
||||||
* Size.Y / 2f // plus the volume of the capsule end caps
|
* Size.Y / 2f // plus the volume of the capsule end caps
|
||||||
);
|
);
|
||||||
_mass = _avatarDensity * _avatarVolume;
|
_mass = Density * BSParam.DensityScaleFactor * _avatarVolume;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The physics engine says that properties have updated. Update same and inform
|
// The physics engine says that properties have updated. Update same and inform
|
||||||
// the world that things have changed.
|
// the world that things have changed.
|
||||||
public override void UpdateProperties(EntityProperties entprop)
|
public override void UpdateProperties(EntityProperties entprop)
|
||||||
{
|
{
|
||||||
_position = entprop.Position;
|
// Don't change position if standing on a stationary object.
|
||||||
|
if (!IsStationary)
|
||||||
|
_position = entprop.Position;
|
||||||
|
|
||||||
_orientation = entprop.Rotation;
|
_orientation = entprop.Rotation;
|
||||||
_velocity = entprop.Velocity;
|
|
||||||
|
// Smooth velocity. OpenSimulator is VERY sensitive to changes in velocity of the avatar
|
||||||
|
// and will send agent updates to the clients if velocity changes by more than
|
||||||
|
// 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many
|
||||||
|
// extra updates.
|
||||||
|
if (!entprop.Velocity.ApproxEquals(RawVelocity, 0.1f))
|
||||||
|
RawVelocity = entprop.Velocity;
|
||||||
|
|
||||||
_acceleration = entprop.Acceleration;
|
_acceleration = entprop.Acceleration;
|
||||||
_rotationalVelocity = entprop.RotationalVelocity;
|
_rotationalVelocity = entprop.RotationalVelocity;
|
||||||
|
|
||||||
// Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
|
// Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
|
||||||
PositionSanityCheck(true);
|
if (PositionSanityCheck(true))
|
||||||
|
{
|
||||||
|
DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, _position);
|
||||||
|
entprop.Position = _position;
|
||||||
|
}
|
||||||
|
|
||||||
// remember the current and last set values
|
// remember the current and last set values
|
||||||
LastEntityProperties = CurrentEntityProperties;
|
LastEntityProperties = CurrentEntityProperties;
|
||||||
CurrentEntityProperties = entprop;
|
CurrentEntityProperties = entprop;
|
||||||
|
|
||||||
// Tell the linkset about value changes
|
// Tell the linkset about value changes
|
||||||
Linkset.UpdateProperties(this, true);
|
// Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this);
|
||||||
|
|
||||||
// Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
|
// Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
|
||||||
// base.RequestPhysicsterseUpdate();
|
// base.RequestPhysicsterseUpdate();
|
||||||
|
|
||||||
DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
|
DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
|
||||||
LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
|
LocalID, _position, _orientation, RawVelocity, _acceleration, _rotationalVelocity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,7 +85,9 @@ public abstract class BSConstraint : IDisposable
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
if (m_enabled)
|
if (m_enabled)
|
||||||
|
{
|
||||||
ret = PhysicsScene.PE.SetAngularLimits(m_constraint, low, high);
|
ret = PhysicsScene.PE.SetAngularLimits(m_constraint, low, high);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,7 @@ public sealed class BSConstraint6Dof : BSConstraint
|
||||||
obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
|
obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 6 Dof constraint based on a midpoint between the two constrained bodies
|
||||||
public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2,
|
public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2,
|
||||||
Vector3 joinPoint,
|
Vector3 joinPoint,
|
||||||
bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
|
bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
|
||||||
|
@ -94,6 +95,21 @@ public sealed class BSConstraint6Dof : BSConstraint
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A 6 Dof constraint that is fixed in the world and constrained to a on-the-fly created static object
|
||||||
|
public BSConstraint6Dof(BulletWorld world, BulletBody obj1, Vector3 frameInBloc, Quaternion frameInBrot,
|
||||||
|
bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies)
|
||||||
|
: base(world)
|
||||||
|
{
|
||||||
|
m_body1 = obj1;
|
||||||
|
m_body2 = obj1; // Look out for confusion down the road
|
||||||
|
m_constraint = PhysicsScene.PE.Create6DofConstraintFixed(m_world, m_body1,
|
||||||
|
frameInBloc, frameInBrot,
|
||||||
|
useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies);
|
||||||
|
m_enabled = true;
|
||||||
|
world.physicsScene.DetailLog("{0},BS6DofConstraint,createFixed,wID={1},rID={2},rBody={3}",
|
||||||
|
BSScene.DetailLogZero, world.worldID, obj1.ID, obj1.AddrString);
|
||||||
|
}
|
||||||
|
|
||||||
public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot)
|
public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
|
@ -117,8 +117,7 @@ public sealed class BSConstraintCollection : IDisposable
|
||||||
if (this.TryGetConstraint(body1, body2, out constrain))
|
if (this.TryGetConstraint(body1, body2, out constrain))
|
||||||
{
|
{
|
||||||
// remove the constraint from our collection
|
// remove the constraint from our collection
|
||||||
RemoveAndDestroyConstraint(constrain);
|
ret = RemoveAndDestroyConstraint(constrain);
|
||||||
ret = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,17 +125,19 @@ public sealed class BSConstraintCollection : IDisposable
|
||||||
}
|
}
|
||||||
|
|
||||||
// The constraint MUST exist in the collection
|
// The constraint MUST exist in the collection
|
||||||
|
// Could be called if the constraint was previously removed.
|
||||||
|
// Return 'true' if the constraint was actually removed and disposed.
|
||||||
public bool RemoveAndDestroyConstraint(BSConstraint constrain)
|
public bool RemoveAndDestroyConstraint(BSConstraint constrain)
|
||||||
{
|
{
|
||||||
|
bool removed = false;
|
||||||
lock (m_constraints)
|
lock (m_constraints)
|
||||||
{
|
{
|
||||||
// remove the constraint from our collection
|
// remove the constraint from our collection
|
||||||
m_constraints.Remove(constrain);
|
removed = m_constraints.Remove(constrain);
|
||||||
}
|
}
|
||||||
// tell the engine that all its structures need to be freed
|
// Dispose() is safe to call multiple times
|
||||||
constrain.Dispose();
|
constrain.Dispose();
|
||||||
// we destroyed something
|
return removed;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove all constraints that reference the passed body.
|
// Remove all constraints that reference the passed body.
|
||||||
|
|
|
@ -45,7 +45,7 @@ public sealed class BSConstraintHinge : BSConstraint
|
||||||
m_body1 = obj1;
|
m_body1 = obj1;
|
||||||
m_body2 = obj2;
|
m_body2 = obj2;
|
||||||
m_constraint = PhysicsScene.PE.CreateHingeConstraint(world, obj1, obj2,
|
m_constraint = PhysicsScene.PE.CreateHingeConstraint(world, obj1, obj2,
|
||||||
pivotInA, pivotInB, axisInA, axisInB,
|
pivotInA, pivotInB, axisInA, axisInB,
|
||||||
useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
|
useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
|
||||||
m_enabled = true;
|
m_enabled = true;
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -52,7 +52,7 @@ public abstract class BSLinkset
|
||||||
Manual = 2 // linkset tied together manually (code moves all the pieces)
|
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, BSPrimLinkable parent)
|
||||||
{
|
{
|
||||||
BSLinkset ret = null;
|
BSLinkset ret = null;
|
||||||
|
|
||||||
|
@ -71,31 +71,28 @@ public abstract class BSLinkset
|
||||||
ret = new BSLinksetCompound(physScene, parent);
|
ret = new BSLinksetCompound(physScene, parent);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (ret == null)
|
||||||
|
{
|
||||||
|
physScene.Logger.ErrorFormat("[BULLETSIM LINKSET] Factory could not create linkset. Parent name={1}, ID={2}", parent.Name, parent.LocalID);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BSPhysObject LinksetRoot { get; protected set; }
|
public BSPrimLinkable LinksetRoot { get; protected set; }
|
||||||
|
|
||||||
public BSScene PhysicsScene { get; private set; }
|
protected BSScene m_physicsScene { get; private set; }
|
||||||
|
|
||||||
static int m_nextLinksetID = 1;
|
static int m_nextLinksetID = 1;
|
||||||
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.
|
||||||
protected HashSet<BSPhysObject> m_children;
|
protected HashSet<BSPrimLinkable> m_children;
|
||||||
|
|
||||||
// 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 BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor)
|
|
||||||
{
|
|
||||||
return BSPhysicsShapeType.SHAPE_UNKNOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
||||||
public float LinksetMass { get; protected set; }
|
public float LinksetMass { get; protected set; }
|
||||||
|
|
||||||
|
@ -111,25 +108,27 @@ public abstract class BSLinkset
|
||||||
get { return ComputeLinksetGeometricCenter(); }
|
get { return ComputeLinksetGeometricCenter(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
protected BSLinkset(BSScene scene, BSPhysObject parent)
|
protected BSLinkset(BSScene scene, BSPrimLinkable parent)
|
||||||
{
|
{
|
||||||
// A simple linkset of one (no children)
|
// A simple linkset of one (no children)
|
||||||
LinksetID = m_nextLinksetID++;
|
LinksetID = m_nextLinksetID++;
|
||||||
// We create LOTS of linksets.
|
// We create LOTS of linksets.
|
||||||
if (m_nextLinksetID <= 0)
|
if (m_nextLinksetID <= 0)
|
||||||
m_nextLinksetID = 1;
|
m_nextLinksetID = 1;
|
||||||
PhysicsScene = scene;
|
m_physicsScene = scene;
|
||||||
LinksetRoot = parent;
|
LinksetRoot = parent;
|
||||||
m_children = new HashSet<BSPhysObject>();
|
m_children = new HashSet<BSPrimLinkable>();
|
||||||
LinksetMass = parent.RawMass;
|
LinksetMass = parent.RawMass;
|
||||||
Rebuilding = false;
|
Rebuilding = false;
|
||||||
|
|
||||||
|
parent.ClearDisplacement();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Link to a linkset where the child knows the parent.
|
// Link to a linkset where the child knows the parent.
|
||||||
// Parent changing should not happen so do some sanity checking.
|
// Parent changing should not happen so do some sanity checking.
|
||||||
// We return the parent's linkset so the child can track its membership.
|
// We return the parent's linkset so the child can track its membership.
|
||||||
// Called at runtime.
|
// Called at runtime.
|
||||||
public BSLinkset AddMeToLinkset(BSPhysObject child)
|
public BSLinkset AddMeToLinkset(BSPrimLinkable child)
|
||||||
{
|
{
|
||||||
lock (m_linksetActivityLock)
|
lock (m_linksetActivityLock)
|
||||||
{
|
{
|
||||||
|
@ -145,7 +144,7 @@ public abstract class BSLinkset
|
||||||
// Returns a new linkset for the child which is a linkset of one (just the
|
// Returns a new linkset for the child which is a linkset of one (just the
|
||||||
// orphened child).
|
// orphened child).
|
||||||
// Called at runtime.
|
// Called at runtime.
|
||||||
public BSLinkset RemoveMeFromLinkset(BSPhysObject child)
|
public BSLinkset RemoveMeFromLinkset(BSPrimLinkable child)
|
||||||
{
|
{
|
||||||
lock (m_linksetActivityLock)
|
lock (m_linksetActivityLock)
|
||||||
{
|
{
|
||||||
|
@ -159,11 +158,11 @@ public abstract class BSLinkset
|
||||||
}
|
}
|
||||||
|
|
||||||
// The child is down to a linkset of just itself
|
// The child is down to a linkset of just itself
|
||||||
return BSLinkset.Factory(PhysicsScene, child);
|
return BSLinkset.Factory(m_physicsScene, child);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return 'true' if the passed object is the root object of this linkset
|
// Return 'true' if the passed object is the root object of this linkset
|
||||||
public bool IsRoot(BSPhysObject requestor)
|
public bool IsRoot(BSPrimLinkable requestor)
|
||||||
{
|
{
|
||||||
return (requestor.LocalID == LinksetRoot.LocalID);
|
return (requestor.LocalID == LinksetRoot.LocalID);
|
||||||
}
|
}
|
||||||
|
@ -174,14 +173,14 @@ public abstract class BSLinkset
|
||||||
public bool HasAnyChildren { get { return (m_children.Count > 0); } }
|
public bool HasAnyChildren { get { return (m_children.Count > 0); } }
|
||||||
|
|
||||||
// Return 'true' if this child is in this linkset
|
// Return 'true' if this child is in this linkset
|
||||||
public bool HasChild(BSPhysObject child)
|
public bool HasChild(BSPrimLinkable child)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
lock (m_linksetActivityLock)
|
lock (m_linksetActivityLock)
|
||||||
{
|
{
|
||||||
ret = m_children.Contains(child);
|
ret = m_children.Contains(child);
|
||||||
/* Safer version but the above should work
|
/* Safer version but the above should work
|
||||||
foreach (BSPhysObject bp in m_children)
|
foreach (BSPrimLinkable bp in m_children)
|
||||||
{
|
{
|
||||||
if (child.LocalID == bp.LocalID)
|
if (child.LocalID == bp.LocalID)
|
||||||
{
|
{
|
||||||
|
@ -196,14 +195,14 @@ public abstract class BSLinkset
|
||||||
|
|
||||||
// Perform an action on each member of the linkset including root prim.
|
// 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.
|
// Depends on the action on whether this should be done at taint time.
|
||||||
public delegate bool ForEachMemberAction(BSPhysObject obj);
|
public delegate bool ForEachMemberAction(BSPrimLinkable obj);
|
||||||
public virtual bool ForEachMember(ForEachMemberAction action)
|
public virtual bool ForEachMember(ForEachMemberAction action)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
lock (m_linksetActivityLock)
|
lock (m_linksetActivityLock)
|
||||||
{
|
{
|
||||||
action(LinksetRoot);
|
action(LinksetRoot);
|
||||||
foreach (BSPhysObject po in m_children)
|
foreach (BSPrimLinkable po in m_children)
|
||||||
{
|
{
|
||||||
if (action(po))
|
if (action(po))
|
||||||
break;
|
break;
|
||||||
|
@ -214,16 +213,16 @@ public abstract class BSLinkset
|
||||||
|
|
||||||
// I am the root of a linkset and a new child is being added
|
// I am the root of a linkset and a new child is being added
|
||||||
// Called while LinkActivity is locked.
|
// Called while LinkActivity is locked.
|
||||||
protected abstract void AddChildToLinkset(BSPhysObject child);
|
protected abstract void AddChildToLinkset(BSPrimLinkable child);
|
||||||
|
|
||||||
// I am the root of a linkset and one of my children is being removed.
|
// I am the root of a linkset and one of my children is being removed.
|
||||||
// Safe to call even if the child is not really in my linkset.
|
// Safe to call even if the child is not really in my linkset.
|
||||||
protected abstract void RemoveChildFromLinkset(BSPhysObject child);
|
protected abstract void RemoveChildFromLinkset(BSPrimLinkable 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.
|
// May be called at runtime or taint-time.
|
||||||
public virtual void Refresh(BSPhysObject requestor)
|
public virtual void Refresh(BSPrimLinkable requestor)
|
||||||
{
|
{
|
||||||
LinksetMass = ComputeLinksetMass();
|
LinksetMass = ComputeLinksetMass();
|
||||||
}
|
}
|
||||||
|
@ -238,31 +237,26 @@ public abstract class BSLinkset
|
||||||
// has not yet been fully constructed.
|
// has not yet been fully constructed.
|
||||||
// Return 'true' if any properties updated on the passed object.
|
// Return 'true' if any properties updated on the passed object.
|
||||||
// Called at taint-time!
|
// Called at taint-time!
|
||||||
public abstract bool MakeDynamic(BSPhysObject child);
|
public abstract bool MakeDynamic(BSPrimLinkable child);
|
||||||
|
|
||||||
// The object is going static (non-physical). Do any setup necessary
|
// The object is going static (non-physical). Do any setup necessary
|
||||||
// for a static linkset.
|
// for a static linkset.
|
||||||
// Return 'true' if any properties updated on the passed object.
|
// Return 'true' if any properties updated on the passed object.
|
||||||
// Called at taint-time!
|
// Called at taint-time!
|
||||||
public abstract bool MakeStatic(BSPhysObject child);
|
public abstract bool MakeStatic(BSPrimLinkable child);
|
||||||
|
|
||||||
// Called when a parameter update comes from the physics engine for any object
|
// Called when a parameter update comes from the physics engine for any object
|
||||||
// of the linkset is received.
|
// of the linkset is received.
|
||||||
// Passed flag is update came from physics engine (true) or the user (false).
|
// Passed flag is update came from physics engine (true) or the user (false).
|
||||||
// Called at taint-time!!
|
// Called at taint-time!!
|
||||||
public abstract void UpdateProperties(BSPhysObject physObject, bool physicalUpdate);
|
public abstract void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable physObject);
|
||||||
|
|
||||||
// Routine used when rebuilding the body of the root of the linkset
|
// Routine used when rebuilding the body of the root of the linkset
|
||||||
// Destroy all the constraints have have been made to root.
|
// Destroy all the constraints have have been made to root.
|
||||||
// This is called when the root body is changing.
|
// This is called when the root body is changing.
|
||||||
// Returns 'true' of something was actually removed and would need restoring
|
// Returns 'true' of something was actually removed and would need restoring
|
||||||
// Called at taint-time!!
|
// Called at taint-time!!
|
||||||
public abstract bool RemoveBodyDependencies(BSPrim child);
|
public abstract bool RemoveDependencies(BSPrimLinkable child);
|
||||||
|
|
||||||
// Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
|
|
||||||
// this routine will restore the removed constraints.
|
|
||||||
// Called at taint-time!!
|
|
||||||
public abstract void RestoreBodyDependencies(BSPrim child);
|
|
||||||
|
|
||||||
// ================================================================
|
// ================================================================
|
||||||
protected virtual float ComputeLinksetMass()
|
protected virtual float ComputeLinksetMass()
|
||||||
|
@ -272,7 +266,7 @@ public abstract class BSLinkset
|
||||||
{
|
{
|
||||||
lock (m_linksetActivityLock)
|
lock (m_linksetActivityLock)
|
||||||
{
|
{
|
||||||
foreach (BSPhysObject bp in m_children)
|
foreach (BSPrimLinkable bp in m_children)
|
||||||
{
|
{
|
||||||
mass += bp.RawMass;
|
mass += bp.RawMass;
|
||||||
}
|
}
|
||||||
|
@ -281,6 +275,7 @@ public abstract class BSLinkset
|
||||||
return mass;
|
return mass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Computes linkset's center of mass in world coordinates.
|
||||||
protected virtual OMV.Vector3 ComputeLinksetCenterOfMass()
|
protected virtual OMV.Vector3 ComputeLinksetCenterOfMass()
|
||||||
{
|
{
|
||||||
OMV.Vector3 com;
|
OMV.Vector3 com;
|
||||||
|
@ -289,7 +284,7 @@ public abstract class BSLinkset
|
||||||
com = LinksetRoot.Position * LinksetRoot.RawMass;
|
com = LinksetRoot.Position * LinksetRoot.RawMass;
|
||||||
float totalMass = LinksetRoot.RawMass;
|
float totalMass = LinksetRoot.RawMass;
|
||||||
|
|
||||||
foreach (BSPhysObject bp in m_children)
|
foreach (BSPrimLinkable bp in m_children)
|
||||||
{
|
{
|
||||||
com += bp.Position * bp.RawMass;
|
com += bp.Position * bp.RawMass;
|
||||||
totalMass += bp.RawMass;
|
totalMass += bp.RawMass;
|
||||||
|
@ -308,9 +303,9 @@ public abstract class BSLinkset
|
||||||
{
|
{
|
||||||
com = LinksetRoot.Position;
|
com = LinksetRoot.Position;
|
||||||
|
|
||||||
foreach (BSPhysObject bp in m_children)
|
foreach (BSPrimLinkable bp in m_children)
|
||||||
{
|
{
|
||||||
com += bp.Position * bp.RawMass;
|
com += bp.Position;
|
||||||
}
|
}
|
||||||
com /= (m_children.Count + 1);
|
com /= (m_children.Count + 1);
|
||||||
}
|
}
|
||||||
|
@ -321,8 +316,8 @@ public abstract class BSLinkset
|
||||||
// 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)
|
||||||
{
|
{
|
||||||
if (PhysicsScene.PhysicsLogging.Enabled)
|
if (m_physicsScene.PhysicsLogging.Enabled)
|
||||||
PhysicsScene.DetailLog(msg, args);
|
m_physicsScene.DetailLog(msg, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,59 +35,74 @@ using OMV = OpenMetaverse;
|
||||||
namespace OpenSim.Region.Physics.BulletSPlugin
|
namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/*
|
||||||
// When a child is linked, the relationship position of the child to the parent
|
// When a child is linked, the relationship position of the child to the parent
|
||||||
// is remembered so the child's world position can be recomputed when it is
|
// is remembered so the child's world position can be recomputed when it is
|
||||||
// removed from the linkset.
|
// removed from the linkset.
|
||||||
sealed class BSLinksetCompoundInfo : BSLinksetInfo
|
sealed class BSLinksetCompoundInfo : BSLinksetInfo
|
||||||
{
|
{
|
||||||
public OMV.Vector3 OffsetPos;
|
public int Index;
|
||||||
|
public OMV.Vector3 OffsetFromRoot;
|
||||||
|
public OMV.Vector3 OffsetFromCenterOfMass;
|
||||||
public OMV.Quaternion OffsetRot;
|
public OMV.Quaternion OffsetRot;
|
||||||
public BSLinksetCompoundInfo(OMV.Vector3 p, OMV.Quaternion r)
|
public BSLinksetCompoundInfo(int indx, OMV.Vector3 p, OMV.Quaternion r)
|
||||||
{
|
{
|
||||||
OffsetPos = p;
|
Index = indx;
|
||||||
|
OffsetFromRoot = p;
|
||||||
|
OffsetFromCenterOfMass = p;
|
||||||
OffsetRot = r;
|
OffsetRot = r;
|
||||||
}
|
}
|
||||||
|
// 'centerDisplacement' is the distance from the root the the center-of-mass (Bullet 'zero' of the shape)
|
||||||
|
public BSLinksetCompoundInfo(int indx, BSPrimLinkable root, BSPrimLinkable child, OMV.Vector3 centerDisplacement)
|
||||||
|
{
|
||||||
|
// Each child position and rotation is given relative to the center-of-mass.
|
||||||
|
OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(root.RawOrientation);
|
||||||
|
OMV.Vector3 displacementFromRoot = (child.RawPosition - root.RawPosition) * invRootOrientation;
|
||||||
|
OMV.Vector3 displacementFromCOM = displacementFromRoot - centerDisplacement;
|
||||||
|
OMV.Quaternion displacementRot = child.RawOrientation * invRootOrientation;
|
||||||
|
|
||||||
|
// Save relative position for recomputing child's world position after moving linkset.
|
||||||
|
Index = indx;
|
||||||
|
OffsetFromRoot = displacementFromRoot;
|
||||||
|
OffsetFromCenterOfMass = displacementFromCOM;
|
||||||
|
OffsetRot = displacementRot;
|
||||||
|
}
|
||||||
public override void Clear()
|
public override void Clear()
|
||||||
{
|
{
|
||||||
OffsetPos = OMV.Vector3.Zero;
|
Index = 0;
|
||||||
|
OffsetFromRoot = OMV.Vector3.Zero;
|
||||||
|
OffsetFromCenterOfMass = OMV.Vector3.Zero;
|
||||||
OffsetRot = OMV.Quaternion.Identity;
|
OffsetRot = OMV.Quaternion.Identity;
|
||||||
}
|
}
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
StringBuilder buff = new StringBuilder();
|
StringBuilder buff = new StringBuilder();
|
||||||
buff.Append("<p=");
|
buff.Append("<i=");
|
||||||
buff.Append(OffsetPos.ToString());
|
buff.Append(Index.ToString());
|
||||||
|
buff.Append(",p=");
|
||||||
|
buff.Append(OffsetFromRoot.ToString());
|
||||||
|
buff.Append(",m=");
|
||||||
|
buff.Append(OffsetFromCenterOfMass.ToString());
|
||||||
buff.Append(",r=");
|
buff.Append(",r=");
|
||||||
buff.Append(OffsetRot.ToString());
|
buff.Append(OffsetRot.ToString());
|
||||||
buff.Append(">");
|
buff.Append(">");
|
||||||
return buff.ToString();
|
return buff.ToString();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
public sealed class BSLinksetCompound : BSLinkset
|
public sealed class BSLinksetCompound : BSLinkset
|
||||||
{
|
{
|
||||||
private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]";
|
private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]";
|
||||||
|
|
||||||
public BSLinksetCompound(BSScene scene, BSPhysObject parent) : base(scene, parent)
|
public BSLinksetCompound(BSScene scene, BSPrimLinkable parent)
|
||||||
|
: base(scene, parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// For compound implimented linksets, if there are children, use compound shape for the root.
|
|
||||||
public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor)
|
|
||||||
{
|
|
||||||
// Returning 'unknown' means we don't have a preference.
|
|
||||||
BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
|
|
||||||
if (IsRoot(requestor) && HasAnyChildren)
|
|
||||||
{
|
|
||||||
ret = BSPhysicsShapeType.SHAPE_COMPOUND;
|
|
||||||
}
|
|
||||||
// DetailLog("{0},BSLinksetCompound.PreferredPhysicalShape,call,shape={1}", LinksetRoot.LocalID, ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.
|
||||||
public override void Refresh(BSPhysObject requestor)
|
public override void Refresh(BSPrimLinkable requestor)
|
||||||
{
|
{
|
||||||
base.Refresh(requestor);
|
base.Refresh(requestor);
|
||||||
|
|
||||||
|
@ -96,16 +111,16 @@ public sealed class BSLinksetCompound : BSLinkset
|
||||||
}
|
}
|
||||||
|
|
||||||
// Schedule a refresh to happen after all the other taint processing.
|
// Schedule a refresh to happen after all the other taint processing.
|
||||||
private void ScheduleRebuild(BSPhysObject requestor)
|
private void ScheduleRebuild(BSPrimLinkable requestor)
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2}",
|
DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}",
|
||||||
requestor.LocalID, Rebuilding, HasAnyChildren);
|
requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren));
|
||||||
// When rebuilding, it is possible to set properties that would normally require a rebuild.
|
// When rebuilding, it is possible to set properties that would normally require a rebuild.
|
||||||
// If already rebuilding, don't request another rebuild.
|
// If already rebuilding, don't request another rebuild.
|
||||||
// If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding.
|
// If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding.
|
||||||
if (!Rebuilding && HasAnyChildren)
|
if (!Rebuilding && HasAnyChildren)
|
||||||
{
|
{
|
||||||
PhysicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate()
|
m_physicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate()
|
||||||
{
|
{
|
||||||
if (HasAnyChildren)
|
if (HasAnyChildren)
|
||||||
RecomputeLinksetCompound();
|
RecomputeLinksetCompound();
|
||||||
|
@ -118,7 +133,7 @@ public sealed class BSLinksetCompound : BSLinkset
|
||||||
// has not yet been fully constructed.
|
// has not yet been fully constructed.
|
||||||
// Return 'true' if any properties updated on the passed object.
|
// Return 'true' if any properties updated on the passed object.
|
||||||
// Called at taint-time!
|
// Called at taint-time!
|
||||||
public override bool MakeDynamic(BSPhysObject child)
|
public override bool MakeDynamic(BSPrimLinkable child)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
|
DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
|
||||||
|
@ -127,138 +142,131 @@ public sealed class BSLinksetCompound : BSLinkset
|
||||||
// The root is going dynamic. Rebuild the linkset so parts and mass get computed properly.
|
// The root is going dynamic. Rebuild the linkset so parts and mass get computed properly.
|
||||||
ScheduleRebuild(LinksetRoot);
|
ScheduleRebuild(LinksetRoot);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// The origional prims are removed from the world as the shape of the root compound
|
|
||||||
// shape takes over.
|
|
||||||
PhysicsScene.PE.AddToCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
|
|
||||||
PhysicsScene.PE.ForceActivationState(child.PhysBody, ActivationState.DISABLE_SIMULATION);
|
|
||||||
// We don't want collisions from the old linkset children.
|
|
||||||
PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
|
|
||||||
|
|
||||||
child.PhysBody.collisionType = CollisionType.LinksetChild;
|
|
||||||
|
|
||||||
ret = true;
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The object is going static (non-physical). Do any setup necessary for a static linkset.
|
// The object is going static (non-physical). We do not do anything for static linksets.
|
||||||
// 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(BSPrimLinkable child)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
|
DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
|
||||||
if (IsRoot(child))
|
if (IsRoot(child))
|
||||||
{
|
{
|
||||||
|
// Schedule a rebuild to verify that the root shape is set to the real shape.
|
||||||
ScheduleRebuild(LinksetRoot);
|
ScheduleRebuild(LinksetRoot);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// The non-physical children can come back to life.
|
|
||||||
PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
|
|
||||||
|
|
||||||
child.PhysBody.collisionType = CollisionType.LinksetChild;
|
|
||||||
|
|
||||||
// Don't force activation so setting of DISABLE_SIMULATION can stay if used.
|
|
||||||
PhysicsScene.PE.Activate(child.PhysBody, false);
|
|
||||||
ret = true;
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void UpdateProperties(BSPhysObject updated, bool physicalUpdate)
|
// 'physicalUpdate' is true if these changes came directly from the physics engine. Don't need to rebuild then.
|
||||||
|
// Called at taint-time.
|
||||||
|
public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable updated)
|
||||||
{
|
{
|
||||||
|
if (!LinksetRoot.IsPhysicallyActive)
|
||||||
|
{
|
||||||
|
// No reason to do this physical stuff for static linksets.
|
||||||
|
DetailLog("{0},BSLinksetCompound.UpdateProperties,notPhysical", LinksetRoot.LocalID);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// The user moving a child around requires the rebuilding of the linkset compound shape
|
// The user moving a child around requires the rebuilding of the linkset compound shape
|
||||||
// One problem is this happens when a border is crossed -- the simulator implementation
|
// One problem is this happens when a border is crossed -- the simulator implementation
|
||||||
// is to store the position into the group which causes the move of the object
|
// stores the position into the group which causes the move of the object
|
||||||
// but it also means all the child positions get updated.
|
// but it also means all the child positions get updated.
|
||||||
// What would cause an unnecessary rebuild so we make sure the linkset is in a
|
// What would cause an unnecessary rebuild so we make sure the linkset is in a
|
||||||
// region before bothering to do a rebuild.
|
// region before bothering to do a rebuild.
|
||||||
if (!IsRoot(updated)
|
if (!IsRoot(updated) && m_physicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition))
|
||||||
&& !physicalUpdate
|
|
||||||
&& PhysicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition))
|
|
||||||
{
|
{
|
||||||
updated.LinksetInfo = null;
|
// If a child of the linkset is updating only the position or rotation, that can be done
|
||||||
ScheduleRebuild(updated);
|
// without rebuilding the linkset.
|
||||||
|
// If a handle for the child can be fetch, we update the child here. If a rebuild was
|
||||||
|
// scheduled by someone else, the rebuild will just replace this setting.
|
||||||
|
|
||||||
|
bool updatedChild = false;
|
||||||
|
// Anything other than updating position or orientation usually means a physical update
|
||||||
|
// and that is caused by us updating the object.
|
||||||
|
if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0)
|
||||||
|
{
|
||||||
|
// Find the physical instance of the child
|
||||||
|
if (LinksetRoot.PhysShape.HasPhysicalShape && m_physicsScene.PE.IsCompound(LinksetRoot.PhysShape.physShapeInfo))
|
||||||
|
{
|
||||||
|
// It is possible that the linkset is still under construction and the child is not yet
|
||||||
|
// inserted into the compound shape. A rebuild of the linkset in a pre-step action will
|
||||||
|
// build the whole thing with the new position or rotation.
|
||||||
|
// The index must be checked because Bullet references the child array but does no validity
|
||||||
|
// checking of the child index passed.
|
||||||
|
int numLinksetChildren = m_physicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape.physShapeInfo);
|
||||||
|
if (updated.LinksetChildIndex < numLinksetChildren)
|
||||||
|
{
|
||||||
|
BulletShape linksetChildShape = m_physicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex);
|
||||||
|
if (linksetChildShape.HasPhysicalShape)
|
||||||
|
{
|
||||||
|
// Found the child shape within the compound shape
|
||||||
|
m_physicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex,
|
||||||
|
updated.RawPosition - LinksetRoot.RawPosition,
|
||||||
|
updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation),
|
||||||
|
true /* shouldRecalculateLocalAabb */);
|
||||||
|
updatedChild = true;
|
||||||
|
DetailLog("{0},BSLinksetCompound.UpdateProperties,changeChildPosRot,whichUpdated={1},pos={2},rot={3}",
|
||||||
|
updated.LocalID, whichUpdated, updated.RawPosition, updated.RawOrientation);
|
||||||
|
}
|
||||||
|
else // DEBUG DEBUG
|
||||||
|
{ // DEBUG DEBUG
|
||||||
|
DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noChildShape,shape={1}",
|
||||||
|
updated.LocalID, linksetChildShape);
|
||||||
|
} // DEBUG DEBUG
|
||||||
|
}
|
||||||
|
else // DEBUG DEBUG
|
||||||
|
{ // DEBUG DEBUG
|
||||||
|
// the child is not yet in the compound shape. This is non-fatal.
|
||||||
|
DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,childNotInCompoundShape,numChildren={1},index={2}",
|
||||||
|
updated.LocalID, numLinksetChildren, updated.LinksetChildIndex);
|
||||||
|
} // DEBUG DEBUG
|
||||||
|
}
|
||||||
|
else // DEBUG DEBUG
|
||||||
|
{ // DEBUG DEBUG
|
||||||
|
DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noBodyOrNotCompound", updated.LocalID);
|
||||||
|
} // DEBUG DEBUG
|
||||||
|
|
||||||
|
if (!updatedChild)
|
||||||
|
{
|
||||||
|
// If couldn't do the individual child, the linkset needs a rebuild to incorporate the new child info.
|
||||||
|
// Note: there are several ways through this code that will not update the child if
|
||||||
|
// the linkset is being rebuilt. In this case, scheduling a rebuild is a NOOP since
|
||||||
|
// there will already be a rebuild scheduled.
|
||||||
|
DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild.schedulingRebuild,whichUpdated={1}",
|
||||||
|
updated.LocalID, whichUpdated);
|
||||||
|
updated.LinksetInfo = null; // setting to 'null' causes relative position to be recomputed.
|
||||||
|
ScheduleRebuild(updated);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Routine called when rebuilding the body of some member of the linkset.
|
// 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.
|
// If one of the bodies is being changed, the linkset needs rebuilding.
|
||||||
|
// For instance, a linkset is built and then a mesh asset is read in and the mesh is recreated.
|
||||||
// Returns 'true' of something was actually removed and would need restoring
|
// Returns 'true' of something was actually removed and would need restoring
|
||||||
// Called at taint-time!!
|
// Called at taint-time!!
|
||||||
public override bool RemoveBodyDependencies(BSPrim child)
|
public override bool RemoveDependencies(BSPrimLinkable child)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}",
|
DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}",
|
||||||
child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, IsRoot(child));
|
child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child));
|
||||||
|
|
||||||
if (!IsRoot(child))
|
ScheduleRebuild(child);
|
||||||
{
|
|
||||||
// Because it is a convenient time, recompute child world position and rotation based on
|
|
||||||
// its position in the linkset.
|
|
||||||
RecomputeChildWorldPosition(child, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cannot schedule a refresh/rebuild here because this routine is called when
|
|
||||||
// the linkset is being rebuilt.
|
|
||||||
// InternalRefresh(LinksetRoot);
|
|
||||||
|
|
||||||
return ret;
|
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)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// When the linkset is built, the child shape is added to the compound shape relative to the
|
|
||||||
// root shape. The linkset then moves around but this does not move the actual child
|
|
||||||
// prim. The child prim's location must be recomputed based on the location of the root shape.
|
|
||||||
private void RecomputeChildWorldPosition(BSPhysObject child, bool inTaintTime)
|
|
||||||
{
|
|
||||||
BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo;
|
|
||||||
if (lci != null)
|
|
||||||
{
|
|
||||||
if (inTaintTime)
|
|
||||||
{
|
|
||||||
OMV.Vector3 oldPos = child.RawPosition;
|
|
||||||
child.ForcePosition = LinksetRoot.RawPosition + lci.OffsetPos;
|
|
||||||
child.ForceOrientation = LinksetRoot.RawOrientation * lci.OffsetRot;
|
|
||||||
DetailLog("{0},BSLinksetCompound.RecomputeChildWorldPosition,oldPos={1},lci={2},newPos={3}",
|
|
||||||
child.LocalID, oldPos, lci, child.RawPosition);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// TaintedObject is not used here so the raw position is set now and not at taint-time.
|
|
||||||
child.Position = LinksetRoot.RawPosition + lci.OffsetPos;
|
|
||||||
child.Orientation = LinksetRoot.RawOrientation * lci.OffsetRot;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// This happens when children have been added to the linkset but the linkset
|
|
||||||
// has not been constructed yet. So like, at taint time, adding children to a linkset
|
|
||||||
// and then changing properties of the children (makePhysical, for instance)
|
|
||||||
// but the post-print action of actually rebuilding the linkset has not yet happened.
|
|
||||||
// PhysicsScene.Logger.WarnFormat("{0} Restoring linkset child position failed because of no relative position computed. ID={1}",
|
|
||||||
// LogHeader, child.LocalID);
|
|
||||||
DetailLog("{0},BSLinksetCompound.recomputeChildWorldPosition,noRelativePositonInfo", child.LocalID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ================================================================
|
// ================================================================
|
||||||
|
|
||||||
// Add a new child to the linkset.
|
// 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(BSPrimLinkable child)
|
||||||
{
|
{
|
||||||
if (!HasChild(child))
|
if (!HasChild(child))
|
||||||
{
|
{
|
||||||
|
@ -274,8 +282,10 @@ public sealed class BSLinksetCompound : BSLinkset
|
||||||
|
|
||||||
// Remove the specified child from the linkset.
|
// Remove the specified child from the linkset.
|
||||||
// Safe to call even if the child is not really in the linkset.
|
// Safe to call even if the child is not really in the linkset.
|
||||||
protected override void RemoveChildFromLinkset(BSPhysObject child)
|
protected override void RemoveChildFromLinkset(BSPrimLinkable child)
|
||||||
{
|
{
|
||||||
|
child.ClearDisplacement();
|
||||||
|
|
||||||
if (m_children.Remove(child))
|
if (m_children.Remove(child))
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
|
DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
|
||||||
|
@ -284,7 +294,7 @@ public sealed class BSLinksetCompound : BSLinkset
|
||||||
child.LocalID, child.PhysBody.AddrString);
|
child.LocalID, child.PhysBody.AddrString);
|
||||||
|
|
||||||
// Cause the child's body to be rebuilt and thus restored to normal operation
|
// Cause the child's body to be rebuilt and thus restored to normal operation
|
||||||
RecomputeChildWorldPosition(child, false);
|
child.LinksetInfo = null;
|
||||||
child.ForceBodyShapeRebuild(false);
|
child.ForceBodyShapeRebuild(false);
|
||||||
|
|
||||||
if (!HasAnyChildren)
|
if (!HasAnyChildren)
|
||||||
|
@ -295,7 +305,7 @@ public sealed class BSLinksetCompound : BSLinkset
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Rebuild the compound shape with the child removed
|
// Rebuild the compound shape with the child removed
|
||||||
ScheduleRebuild(child);
|
ScheduleRebuild(LinksetRoot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -306,87 +316,113 @@ public sealed class BSLinksetCompound : BSLinkset
|
||||||
// Constraint linksets are rebuilt every time.
|
// Constraint linksets are rebuilt every time.
|
||||||
// Note that this works for rebuilding just the root after a linkset is taken apart.
|
// Note that this works for rebuilding just the root after a linkset is taken apart.
|
||||||
// Called at taint time!!
|
// Called at taint time!!
|
||||||
|
private bool UseBulletSimRootOffsetHack = false; // Attempt to have Bullet track the coords of root compound shape
|
||||||
|
private bool disableCOM = true; // For basic linkset debugging, turn off the center-of-mass setting
|
||||||
private void RecomputeLinksetCompound()
|
private void RecomputeLinksetCompound()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Suppress rebuilding while rebuilding
|
|
||||||
Rebuilding = true;
|
Rebuilding = true;
|
||||||
|
|
||||||
// Cause the root shape to be rebuilt as a compound object with just the root in it
|
// No matter what is being done, force the root prim's PhysBody and PhysShape to get set
|
||||||
|
// to what they should be as if the root was not in a linkset.
|
||||||
|
// Not that bad since we only get into this routine if there are children in the linkset and
|
||||||
|
// something has been updated/changed.
|
||||||
LinksetRoot.ForceBodyShapeRebuild(true);
|
LinksetRoot.ForceBodyShapeRebuild(true);
|
||||||
|
|
||||||
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}",
|
// There is no reason to build all this physical stuff for a non-physical linkset.
|
||||||
LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren);
|
if (!LinksetRoot.IsPhysicallyActive)
|
||||||
|
|
||||||
// Add a shape for each of the other children in the linkset
|
|
||||||
ForEachMember(delegate(BSPhysObject cPrim)
|
|
||||||
{
|
{
|
||||||
|
// Clean up any old linkset shape and make sure the root shape is set to the root object.
|
||||||
|
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,notPhysical", LinksetRoot.LocalID);
|
||||||
|
|
||||||
|
return; // Note the 'finally' clause at the botton which will get executed.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a new compound shape to build the linkset shape in.
|
||||||
|
BSShape linksetShape = BSShapeCompound.GetReference(m_physicsScene);
|
||||||
|
|
||||||
|
// The center of mass for the linkset is the geometric center of the group.
|
||||||
|
// Compute a displacement for each component so it is relative to the center-of-mass.
|
||||||
|
// Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass
|
||||||
|
OMV.Vector3 centerOfMassW = ComputeLinksetCenterOfMass();
|
||||||
|
|
||||||
|
OMV.Quaternion invRootOrientation = OMV.Quaternion.Normalize(OMV.Quaternion.Inverse(LinksetRoot.RawOrientation));
|
||||||
|
|
||||||
|
// 'centerDisplacement' is the value to subtract from children to give physical offset position
|
||||||
|
OMV.Vector3 centerDisplacementV = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation;
|
||||||
|
if (UseBulletSimRootOffsetHack || disableCOM)
|
||||||
|
{
|
||||||
|
centerDisplacementV = OMV.Vector3.Zero;
|
||||||
|
LinksetRoot.ClearDisplacement();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LinksetRoot.SetEffectiveCenterOfMassDisplacement(centerDisplacementV);
|
||||||
|
}
|
||||||
|
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,rootPos={1},com={2},comDisp={3}",
|
||||||
|
LinksetRoot.LocalID, LinksetRoot.RawPosition, centerOfMassW, centerDisplacementV);
|
||||||
|
|
||||||
|
// Add the shapes of all the components of the linkset
|
||||||
|
int memberIndex = 1;
|
||||||
|
ForEachMember(delegate(BSPrimLinkable cPrim)
|
||||||
|
{
|
||||||
|
// Root shape is always index zero.
|
||||||
|
cPrim.LinksetChildIndex = IsRoot(cPrim) ? 0 : memberIndex;
|
||||||
|
|
||||||
|
// Get a reference to the shape of the child and add that shape to the linkset compound shape
|
||||||
|
BSShape childShape = cPrim.PhysShape.GetReference(m_physicsScene, cPrim);
|
||||||
|
OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacementV;
|
||||||
|
OMV.Quaternion offsetRot = OMV.Quaternion.Normalize(cPrim.RawOrientation) * invRootOrientation;
|
||||||
|
m_physicsScene.PE.AddChildShapeToCompoundShape(linksetShape.physShapeInfo, childShape.physShapeInfo, offsetPos, offsetRot);
|
||||||
|
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChild,indx={1},cShape={2},offPos={3},offRot={4}",
|
||||||
|
LinksetRoot.LocalID, memberIndex, childShape, offsetPos, offsetRot);
|
||||||
|
|
||||||
|
// Since we are borrowing the shape of the child, disable the origional child body
|
||||||
if (!IsRoot(cPrim))
|
if (!IsRoot(cPrim))
|
||||||
{
|
{
|
||||||
// Compute the displacement of the child from the root of the linkset.
|
m_physicsScene.PE.AddToCollisionFlags(cPrim.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
|
||||||
// This info is saved in the child prim so the relationship does not
|
m_physicsScene.PE.ForceActivationState(cPrim.PhysBody, ActivationState.DISABLE_SIMULATION);
|
||||||
// change over time and the new child position can be computed
|
// We don't want collisions from the old linkset children.
|
||||||
// when the linkset is being disassembled (the linkset may have moved).
|
m_physicsScene.PE.RemoveFromCollisionFlags(cPrim.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
|
||||||
BSLinksetCompoundInfo lci = cPrim.LinksetInfo as BSLinksetCompoundInfo;
|
cPrim.PhysBody.collisionType = CollisionType.LinksetChild;
|
||||||
if (lci == null)
|
|
||||||
{
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
// Save relative position for recomputing child's world position after moving linkset.
|
|
||||||
lci = new BSLinksetCompoundInfo(displacementPos, displacementRot);
|
|
||||||
cPrim.LinksetInfo = lci;
|
|
||||||
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,creatingRelPos,lci={1}", cPrim.LocalID, lci);
|
|
||||||
}
|
|
||||||
|
|
||||||
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}",
|
|
||||||
LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, lci.OffsetPos, lci.OffsetRot);
|
|
||||||
|
|
||||||
if (cPrim.PhysShape.isNativeShape)
|
|
||||||
{
|
|
||||||
// A native shape is turning into a hull collision shape because native
|
|
||||||
// shapes are not shared so we have to hullify it so it will be tracked
|
|
||||||
// and freed at the correct time. This also solves the scaling problem
|
|
||||||
// (native shapes scaled but hull/meshes are assumed to not be).
|
|
||||||
// TODO: decide of the native shape can just be used in the compound shape.
|
|
||||||
// Use call to CreateGeomNonSpecial().
|
|
||||||
BulletShape saveShape = cPrim.PhysShape;
|
|
||||||
cPrim.PhysShape.Clear(); // Don't let the create free the child's shape
|
|
||||||
// PhysicsScene.Shapes.CreateGeomNonSpecial(true, cPrim, null);
|
|
||||||
PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
|
|
||||||
BulletShape newShape = cPrim.PhysShape;
|
|
||||||
cPrim.PhysShape = saveShape;
|
|
||||||
PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, newShape, lci.OffsetPos, lci.OffsetRot);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// For the shared shapes (meshes and hulls), just use the shape in the child.
|
|
||||||
// The reference count added here will be decremented when the compound shape
|
|
||||||
// is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced).
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, cPrim.PhysShape, lci.OffsetPos, lci.OffsetRot);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memberIndex++;
|
||||||
|
|
||||||
return false; // 'false' says to move onto the next child in the list
|
return false; // 'false' says to move onto the next child in the list
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Replace the root shape with the built compound shape.
|
||||||
|
// Object removed and added to world to get collision cache rebuilt for new shape.
|
||||||
|
LinksetRoot.PhysShape.Dereference(m_physicsScene);
|
||||||
|
LinksetRoot.PhysShape = linksetShape;
|
||||||
|
m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, LinksetRoot.PhysBody);
|
||||||
|
m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, LinksetRoot.PhysBody, linksetShape.physShapeInfo);
|
||||||
|
m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, LinksetRoot.PhysBody);
|
||||||
|
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addBody,body={1},shape={2}",
|
||||||
|
LinksetRoot.LocalID, LinksetRoot.PhysBody, linksetShape);
|
||||||
|
|
||||||
// With all of the linkset packed into the root prim, it has the mass of everyone.
|
// With all of the linkset packed into the root prim, it has the mass of everyone.
|
||||||
LinksetMass = ComputeLinksetMass();
|
LinksetMass = ComputeLinksetMass();
|
||||||
LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true);
|
LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true);
|
||||||
|
|
||||||
|
if (UseBulletSimRootOffsetHack)
|
||||||
|
{
|
||||||
|
// Enable the physical position updator to return the position and rotation of the root shape.
|
||||||
|
// This enables a feature in the C++ code to return the world coordinates of the first shape in the
|
||||||
|
// compound shape. This eleviates the need to offset the returned physical position by the
|
||||||
|
// center-of-mass offset.
|
||||||
|
m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
Rebuilding = false;
|
Rebuilding = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
PhysicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape);
|
// See that the Aabb surrounds the new shape
|
||||||
|
m_physicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape.physShapeInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -36,7 +36,7 @@ public sealed class BSLinksetConstraints : BSLinkset
|
||||||
{
|
{
|
||||||
// private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]";
|
// private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]";
|
||||||
|
|
||||||
public BSLinksetConstraints(BSScene scene, BSPhysObject parent) : base(scene, parent)
|
public BSLinksetConstraints(BSScene scene, BSPrimLinkable parent) : base(scene, parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,14 +44,14 @@ public sealed class BSLinksetConstraints : BSLinkset
|
||||||
// its internal properties.
|
// its internal properties.
|
||||||
// This is queued in the 'post taint' queue so the
|
// This is queued in the 'post taint' queue so the
|
||||||
// refresh will happen once after all the other taints are applied.
|
// refresh will happen once after all the other taints are applied.
|
||||||
public override void Refresh(BSPhysObject requestor)
|
public override void Refresh(BSPrimLinkable requestor)
|
||||||
{
|
{
|
||||||
base.Refresh(requestor);
|
base.Refresh(requestor);
|
||||||
|
|
||||||
if (HasAnyChildren && IsRoot(requestor))
|
if (HasAnyChildren && IsRoot(requestor))
|
||||||
{
|
{
|
||||||
// Queue to happen after all the other taint processing
|
// Queue to happen after all the other taint processing
|
||||||
PhysicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate()
|
m_physicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate()
|
||||||
{
|
{
|
||||||
if (HasAnyChildren && IsRoot(requestor))
|
if (HasAnyChildren && IsRoot(requestor))
|
||||||
RecomputeLinksetConstraints();
|
RecomputeLinksetConstraints();
|
||||||
|
@ -65,7 +65,7 @@ public sealed class BSLinksetConstraints : BSLinkset
|
||||||
// has not yet been fully constructed.
|
// has not yet been fully constructed.
|
||||||
// Return 'true' if any properties updated on the passed object.
|
// Return 'true' if any properties updated on the passed object.
|
||||||
// Called at taint-time!
|
// Called at taint-time!
|
||||||
public override bool MakeDynamic(BSPhysObject child)
|
public override bool MakeDynamic(BSPrimLinkable child)
|
||||||
{
|
{
|
||||||
// What is done for each object in BSPrim is what we want.
|
// What is done for each object in BSPrim is what we want.
|
||||||
return false;
|
return false;
|
||||||
|
@ -76,14 +76,14 @@ public sealed class BSLinksetConstraints : BSLinkset
|
||||||
// This doesn't normally happen -- OpenSim removes the objects from the physical
|
// This doesn't normally happen -- OpenSim removes the objects from the physical
|
||||||
// world if it is a static linkset.
|
// 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(BSPrimLinkable child)
|
||||||
{
|
{
|
||||||
// What is done for each object in BSPrim is what we want.
|
// What is done for each object in BSPrim is what we want.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called at taint-time!!
|
// Called at taint-time!!
|
||||||
public override void UpdateProperties(BSPhysObject updated, bool inTaintTime)
|
public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable pObj)
|
||||||
{
|
{
|
||||||
// Nothing to do for constraints on property updates
|
// Nothing to do for constraints on property updates
|
||||||
}
|
}
|
||||||
|
@ -93,11 +93,11 @@ public sealed class BSLinksetConstraints : BSLinkset
|
||||||
// up to rebuild the constraints before the next simulation step.
|
// up to rebuild the constraints before the next simulation step.
|
||||||
// Returns 'true' of something was actually removed and would need restoring
|
// Returns 'true' of something was actually removed and would need restoring
|
||||||
// Called at taint-time!!
|
// Called at taint-time!!
|
||||||
public override bool RemoveBodyDependencies(BSPrim child)
|
public override bool RemoveDependencies(BSPrimLinkable child)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
DetailLog("{0},BSLinksetConstraint.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}",
|
DetailLog("{0},BSLinksetConstraint.RemoveDependencies,removeChildrenForRoot,rID={1},rBody={2}",
|
||||||
child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString);
|
child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString);
|
||||||
|
|
||||||
lock (m_linksetActivityLock)
|
lock (m_linksetActivityLock)
|
||||||
|
@ -110,19 +110,11 @@ public sealed class BSLinksetConstraints : BSLinkset
|
||||||
return ret;
|
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.
|
// 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(BSPrimLinkable child)
|
||||||
{
|
{
|
||||||
if (!HasChild(child))
|
if (!HasChild(child))
|
||||||
{
|
{
|
||||||
|
@ -138,19 +130,19 @@ public sealed class BSLinksetConstraints : BSLinkset
|
||||||
|
|
||||||
// Remove the specified child from the linkset.
|
// Remove the specified child from the linkset.
|
||||||
// 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(BSPrimLinkable child)
|
||||||
{
|
{
|
||||||
if (m_children.Remove(child))
|
if (m_children.Remove(child))
|
||||||
{
|
{
|
||||||
BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
|
BSPrimLinkable rootx = LinksetRoot; // capture the root and body as of now
|
||||||
BSPhysObject childx = child;
|
BSPrimLinkable childx = child;
|
||||||
|
|
||||||
DetailLog("{0},BSLinksetConstraints.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.PhysBody.AddrString,
|
rootx.LocalID, rootx.PhysBody.AddrString,
|
||||||
childx.LocalID, childx.PhysBody.AddrString);
|
childx.LocalID, childx.PhysBody.AddrString);
|
||||||
|
|
||||||
PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate()
|
m_physicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate()
|
||||||
{
|
{
|
||||||
PhysicallyUnlinkAChildFromRoot(rootx, childx);
|
PhysicallyUnlinkAChildFromRoot(rootx, childx);
|
||||||
});
|
});
|
||||||
|
@ -167,13 +159,13 @@ public sealed 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(BSPrimLinkable rootPrim, BSPrimLinkable childPrim)
|
||||||
{
|
{
|
||||||
// Don't build the constraint when asked. Put it off until just before the simulation step.
|
// Don't build the constraint when asked. Put it off until just before the simulation step.
|
||||||
Refresh(rootPrim);
|
Refresh(rootPrim);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BSConstraint BuildConstraint(BSPhysObject rootPrim, BSPhysObject childPrim)
|
private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSPrimLinkable childPrim)
|
||||||
{
|
{
|
||||||
// Zero motion for children so they don't interpolate
|
// Zero motion for children so they don't interpolate
|
||||||
childPrim.ZeroMotion(true);
|
childPrim.ZeroMotion(true);
|
||||||
|
@ -195,7 +187,7 @@ public sealed class BSLinksetConstraints : BSLinkset
|
||||||
// http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
|
// http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
|
||||||
|
|
||||||
BSConstraint6Dof constrain = new BSConstraint6Dof(
|
BSConstraint6Dof constrain = new BSConstraint6Dof(
|
||||||
PhysicsScene.World, rootPrim.PhysBody, childPrim.PhysBody, midPoint, true, true );
|
m_physicsScene.World, rootPrim.PhysBody, childPrim.PhysBody, midPoint, true, true );
|
||||||
// PhysicsScene.World, childPrim.BSBody, rootPrim.BSBody, 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.
|
||||||
|
@ -224,15 +216,15 @@ public sealed class BSLinksetConstraints : BSLinkset
|
||||||
// ==================================================================================
|
// ==================================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
PhysicsScene.Constraints.AddConstraint(constrain);
|
m_physicsScene.Constraints.AddConstraint(constrain);
|
||||||
|
|
||||||
// zero linear and angular limits makes the objects unable to move in relation to each other
|
// zero linear and angular limits makes the objects unable to move in relation to each other
|
||||||
constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
|
constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
|
||||||
constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
|
constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
|
||||||
|
|
||||||
// tweek the constraint to increase stability
|
// tweek the constraint to increase stability
|
||||||
constrain.UseFrameOffset(BSParam.BoolNumeric(BSParam.LinkConstraintUseFrameOffset));
|
constrain.UseFrameOffset(BSParam.LinkConstraintUseFrameOffset);
|
||||||
constrain.TranslationalLimitMotor(BSParam.BoolNumeric(BSParam.LinkConstraintEnableTransMotor),
|
constrain.TranslationalLimitMotor(BSParam.LinkConstraintEnableTransMotor,
|
||||||
BSParam.LinkConstraintTransMotorMaxVel,
|
BSParam.LinkConstraintTransMotorMaxVel,
|
||||||
BSParam.LinkConstraintTransMotorMaxForce);
|
BSParam.LinkConstraintTransMotorMaxForce);
|
||||||
constrain.SetCFMAndERP(BSParam.LinkConstraintCFM, BSParam.LinkConstraintERP);
|
constrain.SetCFMAndERP(BSParam.LinkConstraintCFM, BSParam.LinkConstraintERP);
|
||||||
|
@ -247,7 +239,7 @@ public sealed class BSLinksetConstraints : BSLinkset
|
||||||
// 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 present 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(BSPrimLinkable rootPrim, BSPrimLinkable childPrim)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
|
DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
|
||||||
|
@ -256,10 +248,10 @@ public sealed class BSLinksetConstraints : BSLinkset
|
||||||
childPrim.LocalID, childPrim.PhysBody.AddrString);
|
childPrim.LocalID, childPrim.PhysBody.AddrString);
|
||||||
|
|
||||||
// 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.PhysBody, childPrim.PhysBody))
|
if (m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody))
|
||||||
{
|
{
|
||||||
// Make the child refresh its location
|
// Make the child refresh its location
|
||||||
PhysicsScene.PE.PushUpdate(childPrim.PhysBody);
|
m_physicsScene.PE.PushUpdate(childPrim.PhysBody);
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,11 +261,11 @@ public sealed 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.
|
// Returns 'true' of any constraints were destroyed.
|
||||||
// Called at taint time!
|
// Called at taint time!
|
||||||
private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
|
private bool PhysicallyUnlinkAllChildrenFromRoot(BSPrimLinkable rootPrim)
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
|
DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
|
||||||
|
|
||||||
return PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody);
|
return m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -289,7 +281,7 @@ public sealed class BSLinksetConstraints : BSLinkset
|
||||||
DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}",
|
DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}",
|
||||||
LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, linksetMass);
|
LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, linksetMass);
|
||||||
|
|
||||||
foreach (BSPhysObject child in m_children)
|
foreach (BSPrimLinkable child in m_children)
|
||||||
{
|
{
|
||||||
// A child in the linkset physically shows the mass of the whole linkset.
|
// 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.
|
// This allows Bullet to apply enough force on the child to move the whole linkset.
|
||||||
|
@ -297,7 +289,7 @@ public sealed class BSLinksetConstraints : BSLinkset
|
||||||
child.UpdatePhysicalMassProperties(linksetMass, true);
|
child.UpdatePhysicalMassProperties(linksetMass, true);
|
||||||
|
|
||||||
BSConstraint constrain;
|
BSConstraint constrain;
|
||||||
if (!PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain))
|
if (!m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain))
|
||||||
{
|
{
|
||||||
// If constraint doesn't exist yet, create it.
|
// If constraint doesn't exist yet, create it.
|
||||||
constrain = BuildConstraint(LinksetRoot, child);
|
constrain = BuildConstraint(LinksetRoot, child);
|
||||||
|
|
|
@ -180,11 +180,14 @@ public static class BSMaterials
|
||||||
// Use reflection to set the value in the attribute structure.
|
// Use reflection to set the value in the attribute structure.
|
||||||
private static void SetAttributeValue(int matType, string attribName, float val)
|
private static void SetAttributeValue(int matType, string attribName, float val)
|
||||||
{
|
{
|
||||||
|
// Get the current attribute values for this material
|
||||||
MaterialAttributes thisAttrib = Attributes[matType];
|
MaterialAttributes thisAttrib = Attributes[matType];
|
||||||
|
// Find the field for the passed attribute name (eg, find field named 'friction')
|
||||||
FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName.ToLower());
|
FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName.ToLower());
|
||||||
if (fieldInfo != null)
|
if (fieldInfo != null)
|
||||||
{
|
{
|
||||||
fieldInfo.SetValue(thisAttrib, val);
|
fieldInfo.SetValue(thisAttrib, val);
|
||||||
|
// Copy new attributes back to array -- since MaterialAttributes is 'struct', passed by value, not reference.
|
||||||
Attributes[matType] = thisAttrib;
|
Attributes[matType] = thisAttrib;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,22 +59,17 @@ public abstract class BSMotor
|
||||||
{
|
{
|
||||||
if (PhysicsScene != null)
|
if (PhysicsScene != null)
|
||||||
{
|
{
|
||||||
if (PhysicsScene.VehicleLoggingEnabled)
|
PhysicsScene.DetailLog(msg, parms);
|
||||||
{
|
|
||||||
PhysicsScene.DetailLog(msg, parms);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Motor which moves CurrentValue to TargetValue over TimeScale seconds.
|
// Motor which moves CurrentValue to TargetValue over TimeScale seconds.
|
||||||
// The TargetValue decays in TargetValueDecayTimeScale and
|
// The TargetValue decays in TargetValueDecayTimeScale.
|
||||||
// the CurrentValue will be held back by FrictionTimeScale.
|
|
||||||
// This motor will "zero itself" over time in that the targetValue will
|
// This motor will "zero itself" over time in that the targetValue will
|
||||||
// decay to zero and the currentValue will follow it to that zero.
|
// decay to zero and the currentValue will follow it to that zero.
|
||||||
// The overall effect is for the returned correction value to go from large
|
// The overall effect is for the returned correction value to go from large
|
||||||
// values (the total difference between current and target minus friction)
|
// values to small and eventually zero values.
|
||||||
// to small and eventually zero values.
|
|
||||||
// TimeScale and TargetDelayTimeScale may be 'infinite' which means no decay.
|
// TimeScale and TargetDelayTimeScale may be 'infinite' which means no decay.
|
||||||
|
|
||||||
// For instance, if something is moving at speed X and the desired speed is Y,
|
// For instance, if something is moving at speed X and the desired speed is Y,
|
||||||
|
@ -91,7 +86,6 @@ public class BSVMotor : BSMotor
|
||||||
|
|
||||||
public virtual float TimeScale { get; set; }
|
public virtual float TimeScale { get; set; }
|
||||||
public virtual float TargetValueDecayTimeScale { get; set; }
|
public virtual float TargetValueDecayTimeScale { get; set; }
|
||||||
public virtual Vector3 FrictionTimescale { get; set; }
|
|
||||||
public virtual float Efficiency { get; set; }
|
public virtual float Efficiency { get; set; }
|
||||||
|
|
||||||
public virtual float ErrorZeroThreshold { get; set; }
|
public virtual float ErrorZeroThreshold { get; set; }
|
||||||
|
@ -100,10 +94,13 @@ public class BSVMotor : BSMotor
|
||||||
public virtual Vector3 CurrentValue { get; protected set; }
|
public virtual Vector3 CurrentValue { get; protected set; }
|
||||||
public virtual Vector3 LastError { get; protected set; }
|
public virtual Vector3 LastError { get; protected set; }
|
||||||
|
|
||||||
public virtual bool ErrorIsZero
|
public virtual bool ErrorIsZero()
|
||||||
{ get {
|
{
|
||||||
return (LastError == Vector3.Zero || LastError.LengthSquared() <= ErrorZeroThreshold);
|
return ErrorIsZero(LastError);
|
||||||
}
|
}
|
||||||
|
public virtual bool ErrorIsZero(Vector3 err)
|
||||||
|
{
|
||||||
|
return (err == Vector3.Zero || err.ApproxEquals(Vector3.Zero, ErrorZeroThreshold));
|
||||||
}
|
}
|
||||||
|
|
||||||
public BSVMotor(string useName)
|
public BSVMotor(string useName)
|
||||||
|
@ -111,16 +108,14 @@ public class BSVMotor : BSMotor
|
||||||
{
|
{
|
||||||
TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite;
|
TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite;
|
||||||
Efficiency = 1f;
|
Efficiency = 1f;
|
||||||
FrictionTimescale = BSMotor.InfiniteVector;
|
|
||||||
CurrentValue = TargetValue = Vector3.Zero;
|
CurrentValue = TargetValue = Vector3.Zero;
|
||||||
ErrorZeroThreshold = 0.001f;
|
ErrorZeroThreshold = 0.001f;
|
||||||
}
|
}
|
||||||
public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency)
|
public BSVMotor(string useName, float timeScale, float decayTimeScale, float efficiency)
|
||||||
: this(useName)
|
: this(useName)
|
||||||
{
|
{
|
||||||
TimeScale = timeScale;
|
TimeScale = timeScale;
|
||||||
TargetValueDecayTimeScale = decayTimeScale;
|
TargetValueDecayTimeScale = decayTimeScale;
|
||||||
FrictionTimescale = frictionTimeScale;
|
|
||||||
Efficiency = efficiency;
|
Efficiency = efficiency;
|
||||||
CurrentValue = TargetValue = Vector3.Zero;
|
CurrentValue = TargetValue = Vector3.Zero;
|
||||||
}
|
}
|
||||||
|
@ -138,7 +133,8 @@ public class BSVMotor : BSMotor
|
||||||
CurrentValue = TargetValue = Vector3.Zero;
|
CurrentValue = TargetValue = Vector3.Zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute the next step and return the new current value
|
// Compute the next step and return the new current value.
|
||||||
|
// Returns the correction needed to move 'current' to 'target'.
|
||||||
public virtual Vector3 Step(float timeStep)
|
public virtual Vector3 Step(float timeStep)
|
||||||
{
|
{
|
||||||
if (!Enabled) return TargetValue;
|
if (!Enabled) return TargetValue;
|
||||||
|
@ -148,9 +144,10 @@ public class BSVMotor : BSMotor
|
||||||
|
|
||||||
Vector3 correction = Vector3.Zero;
|
Vector3 correction = Vector3.Zero;
|
||||||
Vector3 error = TargetValue - CurrentValue;
|
Vector3 error = TargetValue - CurrentValue;
|
||||||
if (!error.ApproxEquals(Vector3.Zero, ErrorZeroThreshold))
|
LastError = error;
|
||||||
|
if (!ErrorIsZero(error))
|
||||||
{
|
{
|
||||||
correction = Step(timeStep, error);
|
correction = StepError(timeStep, error);
|
||||||
|
|
||||||
CurrentValue += correction;
|
CurrentValue += correction;
|
||||||
|
|
||||||
|
@ -163,44 +160,40 @@ public class BSVMotor : BSMotor
|
||||||
TargetValue *= (1f - decayFactor);
|
TargetValue *= (1f - decayFactor);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The amount we can correct the error is reduced by the friction
|
|
||||||
Vector3 frictionFactor = Vector3.Zero;
|
|
||||||
if (FrictionTimescale != BSMotor.InfiniteVector)
|
|
||||||
{
|
|
||||||
// frictionFactor = (Vector3.One / FrictionTimescale) * timeStep;
|
|
||||||
// Individual friction components can be 'infinite' so compute each separately.
|
|
||||||
frictionFactor.X = (FrictionTimescale.X == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.X);
|
|
||||||
frictionFactor.Y = (FrictionTimescale.Y == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Y);
|
|
||||||
frictionFactor.Z = (FrictionTimescale.Z == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Z);
|
|
||||||
frictionFactor *= timeStep;
|
|
||||||
CurrentValue *= (Vector3.One - frictionFactor);
|
|
||||||
}
|
|
||||||
|
|
||||||
MDetailLog("{0}, BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}",
|
MDetailLog("{0}, BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}",
|
||||||
BSScene.DetailLogZero, UseName, origCurrVal, origTarget,
|
BSScene.DetailLogZero, UseName, origCurrVal, origTarget,
|
||||||
timeStep, error, correction);
|
timeStep, error, correction);
|
||||||
MDetailLog("{0}, BSVMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},frictTS={4},frictFact={5},tgt={6},curr={7}",
|
MDetailLog("{0}, BSVMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},tgt={4},curr={5}",
|
||||||
BSScene.DetailLogZero, UseName,
|
BSScene.DetailLogZero, UseName, TargetValueDecayTimeScale, decayFactor, TargetValue, CurrentValue);
|
||||||
TargetValueDecayTimeScale, decayFactor, FrictionTimescale, frictionFactor,
|
|
||||||
TargetValue, CurrentValue);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Difference between what we have and target is small. Motor is done.
|
// Difference between what we have and target is small. Motor is done.
|
||||||
|
if (TargetValue.ApproxEquals(Vector3.Zero, ErrorZeroThreshold))
|
||||||
|
{
|
||||||
|
// The target can step down to nearly zero but not get there. If close to zero
|
||||||
|
// it is really zero.
|
||||||
|
TargetValue = Vector3.Zero;
|
||||||
|
}
|
||||||
CurrentValue = TargetValue;
|
CurrentValue = TargetValue;
|
||||||
MDetailLog("{0}, BSVMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={4}",
|
MDetailLog("{0}, BSVMotor.Step,zero,{1},origTgt={2},origCurr={3},currTgt={4},currCurr={5}",
|
||||||
BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue);
|
BSScene.DetailLogZero, UseName, origCurrVal, origTarget, TargetValue, CurrentValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
return CurrentValue;
|
return correction;
|
||||||
}
|
}
|
||||||
public virtual Vector3 Step(float timeStep, Vector3 error)
|
// version of step that sets the current value before doing the step
|
||||||
|
public virtual Vector3 Step(float timeStep, Vector3 current)
|
||||||
|
{
|
||||||
|
CurrentValue = current;
|
||||||
|
return Step(timeStep);
|
||||||
|
}
|
||||||
|
public virtual Vector3 StepError(float timeStep, Vector3 error)
|
||||||
{
|
{
|
||||||
if (!Enabled) return Vector3.Zero;
|
if (!Enabled) return Vector3.Zero;
|
||||||
|
|
||||||
LastError = error;
|
|
||||||
Vector3 returnCorrection = Vector3.Zero;
|
Vector3 returnCorrection = Vector3.Zero;
|
||||||
if (!error.ApproxEquals(Vector3.Zero, ErrorZeroThreshold))
|
if (!ErrorIsZero(error))
|
||||||
{
|
{
|
||||||
// correction = error / secondsItShouldTakeToCorrect
|
// correction = error / secondsItShouldTakeToCorrect
|
||||||
Vector3 correctionAmount;
|
Vector3 correctionAmount;
|
||||||
|
@ -222,9 +215,9 @@ public class BSVMotor : BSMotor
|
||||||
// maximum number of outputs to generate.
|
// maximum number of outputs to generate.
|
||||||
int maxOutput = 50;
|
int maxOutput = 50;
|
||||||
MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName);
|
MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName);
|
||||||
MDetailLog("{0},BSVMotor.Test,{1},timeScale={2},targDlyTS={3},frictTS={4},eff={5},curr={6},tgt={7}",
|
MDetailLog("{0},BSVMotor.Test,{1},timeScale={2},targDlyTS={3},eff={4},curr={5},tgt={6}",
|
||||||
BSScene.DetailLogZero, UseName,
|
BSScene.DetailLogZero, UseName,
|
||||||
TimeScale, TargetValueDecayTimeScale, FrictionTimescale, Efficiency,
|
TimeScale, TargetValueDecayTimeScale, Efficiency,
|
||||||
CurrentValue, TargetValue);
|
CurrentValue, TargetValue);
|
||||||
|
|
||||||
LastError = BSMotor.InfiniteVector;
|
LastError = BSMotor.InfiniteVector;
|
||||||
|
@ -235,43 +228,141 @@ public class BSVMotor : BSMotor
|
||||||
BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep);
|
BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep);
|
||||||
}
|
}
|
||||||
MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName);
|
MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4},frictTS={5}>",
|
return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4}>",
|
||||||
UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale, FrictionTimescale);
|
UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// ============================================================================
|
||||||
public class BSFMotor : BSMotor
|
public class BSFMotor : BSMotor
|
||||||
{
|
{
|
||||||
public float TimeScale { get; set; }
|
public virtual float TimeScale { get; set; }
|
||||||
public float DecayTimeScale { get; set; }
|
public virtual float TargetValueDecayTimeScale { get; set; }
|
||||||
public float Friction { get; set; }
|
public virtual float Efficiency { get; set; }
|
||||||
public float Efficiency { get; set; }
|
|
||||||
|
|
||||||
public float Target { get; private set; }
|
public virtual float ErrorZeroThreshold { get; set; }
|
||||||
public float CurrentValue { get; private set; }
|
|
||||||
|
|
||||||
public BSFMotor(string useName, float timeScale, float decayTimescale, float friction, float efficiency)
|
public virtual float TargetValue { get; protected set; }
|
||||||
|
public virtual float CurrentValue { get; protected set; }
|
||||||
|
public virtual float LastError { get; protected set; }
|
||||||
|
|
||||||
|
public virtual bool ErrorIsZero()
|
||||||
|
{
|
||||||
|
return ErrorIsZero(LastError);
|
||||||
|
}
|
||||||
|
public virtual bool ErrorIsZero(float err)
|
||||||
|
{
|
||||||
|
return (err >= -ErrorZeroThreshold && err <= ErrorZeroThreshold);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BSFMotor(string useName, float timeScale, float decayTimescale, float efficiency)
|
||||||
: base(useName)
|
: base(useName)
|
||||||
{
|
{
|
||||||
|
TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite;
|
||||||
|
Efficiency = 1f;
|
||||||
|
CurrentValue = TargetValue = 0f;
|
||||||
|
ErrorZeroThreshold = 0.01f;
|
||||||
}
|
}
|
||||||
public void SetCurrent(float target)
|
public void SetCurrent(float current)
|
||||||
{
|
{
|
||||||
|
CurrentValue = current;
|
||||||
}
|
}
|
||||||
public void SetTarget(float target)
|
public void SetTarget(float target)
|
||||||
{
|
{
|
||||||
|
TargetValue = target;
|
||||||
}
|
}
|
||||||
|
public override void Zero()
|
||||||
|
{
|
||||||
|
base.Zero();
|
||||||
|
CurrentValue = TargetValue = 0f;
|
||||||
|
}
|
||||||
|
|
||||||
public virtual float Step(float timeStep)
|
public virtual float Step(float timeStep)
|
||||||
{
|
{
|
||||||
return 0f;
|
if (!Enabled) return TargetValue;
|
||||||
|
|
||||||
|
float origTarget = TargetValue; // DEBUG
|
||||||
|
float origCurrVal = CurrentValue; // DEBUG
|
||||||
|
|
||||||
|
float correction = 0f;
|
||||||
|
float error = TargetValue - CurrentValue;
|
||||||
|
LastError = error;
|
||||||
|
if (!ErrorIsZero(error))
|
||||||
|
{
|
||||||
|
correction = StepError(timeStep, error);
|
||||||
|
|
||||||
|
CurrentValue += correction;
|
||||||
|
|
||||||
|
// The desired value reduces to zero which also reduces the difference with current.
|
||||||
|
// If the decay time is infinite, don't decay at all.
|
||||||
|
float decayFactor = 0f;
|
||||||
|
if (TargetValueDecayTimeScale != BSMotor.Infinite)
|
||||||
|
{
|
||||||
|
decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep;
|
||||||
|
TargetValue *= (1f - decayFactor);
|
||||||
|
}
|
||||||
|
|
||||||
|
MDetailLog("{0}, BSFMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}",
|
||||||
|
BSScene.DetailLogZero, UseName, origCurrVal, origTarget,
|
||||||
|
timeStep, error, correction);
|
||||||
|
MDetailLog("{0}, BSFMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},tgt={4},curr={5}",
|
||||||
|
BSScene.DetailLogZero, UseName, TargetValueDecayTimeScale, decayFactor, TargetValue, CurrentValue);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Difference between what we have and target is small. Motor is done.
|
||||||
|
if (Util.InRange<float>(TargetValue, -ErrorZeroThreshold, ErrorZeroThreshold))
|
||||||
|
{
|
||||||
|
// The target can step down to nearly zero but not get there. If close to zero
|
||||||
|
// it is really zero.
|
||||||
|
TargetValue = 0f;
|
||||||
|
}
|
||||||
|
CurrentValue = TargetValue;
|
||||||
|
MDetailLog("{0}, BSFMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={4}",
|
||||||
|
BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return CurrentValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual float StepError(float timeStep, float error)
|
||||||
|
{
|
||||||
|
if (!Enabled) return 0f;
|
||||||
|
|
||||||
|
float returnCorrection = 0f;
|
||||||
|
if (!ErrorIsZero(error))
|
||||||
|
{
|
||||||
|
// correction = error / secondsItShouldTakeToCorrect
|
||||||
|
float correctionAmount;
|
||||||
|
if (TimeScale == 0f || TimeScale == BSMotor.Infinite)
|
||||||
|
correctionAmount = error * timeStep;
|
||||||
|
else
|
||||||
|
correctionAmount = error / TimeScale * timeStep;
|
||||||
|
|
||||||
|
returnCorrection = correctionAmount;
|
||||||
|
MDetailLog("{0}, BSFMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5}",
|
||||||
|
BSScene.DetailLogZero, UseName, timeStep, TimeScale, error, correctionAmount);
|
||||||
|
}
|
||||||
|
return returnCorrection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4}>",
|
||||||
|
UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// ============================================================================
|
||||||
// Proportional, Integral, Derivitive Motor
|
// Proportional, Integral, Derivitive Motor
|
||||||
// Good description at http://www.answers.com/topic/pid-controller . Includes processes for choosing p, i and d factors.
|
// Good description at http://www.answers.com/topic/pid-controller . Includes processes for choosing p, i and d factors.
|
||||||
public class BSPIDVMotor : BSVMotor
|
public class BSPIDVMotor : BSVMotor
|
||||||
|
@ -281,6 +372,12 @@ public class BSPIDVMotor : BSVMotor
|
||||||
public Vector3 integralFactor { get; set; }
|
public Vector3 integralFactor { get; set; }
|
||||||
public Vector3 derivFactor { get; set; }
|
public Vector3 derivFactor { get; set; }
|
||||||
|
|
||||||
|
// The factors are vectors for the three dimensions. This is the proportional of each
|
||||||
|
// that is applied. This could be multiplied through the actual factors but it
|
||||||
|
// is sometimes easier to manipulate the factors and their mix separately.
|
||||||
|
// to
|
||||||
|
public Vector3 FactorMix;
|
||||||
|
|
||||||
// Arbritrary factor range.
|
// Arbritrary factor range.
|
||||||
// EfficiencyHigh means move quickly to the correct number. EfficiencyLow means might over correct.
|
// EfficiencyHigh means move quickly to the correct number. EfficiencyLow means might over correct.
|
||||||
public float EfficiencyHigh = 0.4f;
|
public float EfficiencyHigh = 0.4f;
|
||||||
|
@ -295,6 +392,7 @@ public class BSPIDVMotor : BSVMotor
|
||||||
proportionFactor = new Vector3(1.00f, 1.00f, 1.00f);
|
proportionFactor = new Vector3(1.00f, 1.00f, 1.00f);
|
||||||
integralFactor = new Vector3(1.00f, 1.00f, 1.00f);
|
integralFactor = new Vector3(1.00f, 1.00f, 1.00f);
|
||||||
derivFactor = new Vector3(1.00f, 1.00f, 1.00f);
|
derivFactor = new Vector3(1.00f, 1.00f, 1.00f);
|
||||||
|
FactorMix = new Vector3(0.5f, 0.25f, 0.25f);
|
||||||
RunningIntegration = Vector3.Zero;
|
RunningIntegration = Vector3.Zero;
|
||||||
LastError = Vector3.Zero;
|
LastError = Vector3.Zero;
|
||||||
}
|
}
|
||||||
|
@ -310,20 +408,24 @@ public class BSPIDVMotor : BSVMotor
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
base.Efficiency = Util.Clamp(value, 0f, 1f);
|
base.Efficiency = Util.Clamp(value, 0f, 1f);
|
||||||
|
|
||||||
// Compute factors based on efficiency.
|
// Compute factors based on efficiency.
|
||||||
// If efficiency is high (1f), use a factor value that moves the error value to zero with little overshoot.
|
// If efficiency is high (1f), use a factor value that moves the error value to zero with little overshoot.
|
||||||
// If efficiency is low (0f), use a factor value that overcorrects.
|
// If efficiency is low (0f), use a factor value that overcorrects.
|
||||||
// TODO: might want to vary contribution of different factor depending on efficiency.
|
// TODO: might want to vary contribution of different factor depending on efficiency.
|
||||||
float factor = ((1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow) / 3f;
|
float factor = ((1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow) / 3f;
|
||||||
// float factor = (1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow;
|
// float factor = (1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow;
|
||||||
|
|
||||||
proportionFactor = new Vector3(factor, factor, factor);
|
proportionFactor = new Vector3(factor, factor, factor);
|
||||||
integralFactor = new Vector3(factor, factor, factor);
|
integralFactor = new Vector3(factor, factor, factor);
|
||||||
derivFactor = new Vector3(factor, factor, factor);
|
derivFactor = new Vector3(factor, factor, factor);
|
||||||
|
|
||||||
|
MDetailLog("{0},BSPIDVMotor.setEfficiency,eff={1},factor={2}", BSScene.DetailLogZero, Efficiency, factor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore Current and Target Values and just advance the PID computation on this error.
|
// Advance the PID computation on this error.
|
||||||
public override Vector3 Step(float timeStep, Vector3 error)
|
public override Vector3 StepError(float timeStep, Vector3 error)
|
||||||
{
|
{
|
||||||
if (!Enabled) return Vector3.Zero;
|
if (!Enabled) return Vector3.Zero;
|
||||||
|
|
||||||
|
@ -331,15 +433,17 @@ public class BSPIDVMotor : BSVMotor
|
||||||
RunningIntegration += error * timeStep;
|
RunningIntegration += error * timeStep;
|
||||||
|
|
||||||
// A simple derivitive is the rate of change from the last error.
|
// A simple derivitive is the rate of change from the last error.
|
||||||
Vector3 derivFactor = (error - LastError) * timeStep;
|
Vector3 derivitive = (error - LastError) * timeStep;
|
||||||
LastError = error;
|
LastError = error;
|
||||||
|
|
||||||
// Correction = -(proportionOfPresentError + accumulationOfPastError + rateOfChangeOfError)
|
// Correction = (proportionOfPresentError + accumulationOfPastError + rateOfChangeOfError)
|
||||||
Vector3 ret = -(
|
Vector3 ret = error * timeStep * proportionFactor * FactorMix.X
|
||||||
error * proportionFactor
|
+ RunningIntegration * integralFactor * FactorMix.Y
|
||||||
+ RunningIntegration * integralFactor
|
+ derivitive * derivFactor * FactorMix.Z
|
||||||
+ derivFactor * derivFactor
|
;
|
||||||
);
|
|
||||||
|
MDetailLog("{0},BSPIDVMotor.step,ts={1},err={2},runnInt={3},deriv={4},ret={5}",
|
||||||
|
BSScene.DetailLogZero, timeStep, error, RunningIntegration, derivitive, ret);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -38,12 +38,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
* Class to wrap all objects.
|
* Class to wrap all objects.
|
||||||
* The rest of BulletSim doesn't need to keep checking for avatars or prims
|
* The rest of BulletSim doesn't need to keep checking for avatars or prims
|
||||||
* unless the difference is significant.
|
* unless the difference is significant.
|
||||||
*
|
*
|
||||||
* Variables in the physicsl objects are in three forms:
|
* Variables in the physicsl objects are in three forms:
|
||||||
* VariableName: used by the simulator and performs taint operations, etc
|
* VariableName: used by the simulator and performs taint operations, etc
|
||||||
* RawVariableName: direct reference to the BulletSim storage for the variable value
|
* RawVariableName: direct reference to the BulletSim storage for the variable value
|
||||||
* ForceVariableName: direct reference (store and fetch) to the value in the physics engine.
|
* 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.
|
* The last one should only be referenced in taint-time.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -52,9 +52,19 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
* SOP.ApplyImpulse SOP.ApplyAngularImpulse SOP.SetAngularImpulse SOP.SetForce
|
* SOP.ApplyImpulse SOP.ApplyAngularImpulse SOP.SetAngularImpulse SOP.SetForce
|
||||||
* SOG.ApplyImpulse SOG.ApplyAngularImpulse SOG.SetAngularImpulse
|
* SOG.ApplyImpulse SOG.ApplyAngularImpulse SOG.SetAngularImpulse
|
||||||
* PA.AddForce PA.AddAngularForce PA.Torque = v PA.Force = v
|
* PA.AddForce PA.AddAngularForce PA.Torque = v PA.Force = v
|
||||||
* BS.ApplyCentralForce BS.ApplyTorque
|
* BS.ApplyCentralForce BS.ApplyTorque
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Flags used to denote which properties updates when making UpdateProperties calls to linksets, etc.
|
||||||
|
public enum UpdatedProperties : uint
|
||||||
|
{
|
||||||
|
Position = 1 << 0,
|
||||||
|
Orientation = 1 << 1,
|
||||||
|
Velocity = 1 << 2,
|
||||||
|
Acceleration = 1 << 3,
|
||||||
|
RotationalVelocity = 1 << 4,
|
||||||
|
EntPropUpdates = Position | Orientation | Velocity | Acceleration | RotationalVelocity,
|
||||||
|
}
|
||||||
public abstract class BSPhysObject : PhysicsActor
|
public abstract class BSPhysObject : PhysicsActor
|
||||||
{
|
{
|
||||||
protected BSPhysObject()
|
protected BSPhysObject()
|
||||||
|
@ -62,41 +72,61 @@ public abstract class BSPhysObject : PhysicsActor
|
||||||
}
|
}
|
||||||
protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName)
|
protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName)
|
||||||
{
|
{
|
||||||
PhysicsScene = parentScene;
|
PhysScene = parentScene;
|
||||||
LocalID = localID;
|
LocalID = localID;
|
||||||
PhysObjectName = name;
|
PhysObjectName = name;
|
||||||
|
Name = name; // PhysicsActor also has the name of the object. Someday consolidate.
|
||||||
TypeName = typeName;
|
TypeName = typeName;
|
||||||
|
|
||||||
|
// The collection of things that push me around
|
||||||
|
PhysicalActors = new BSActorCollection(PhysScene);
|
||||||
|
|
||||||
|
// Initialize variables kept in base.
|
||||||
|
GravModifier = 1.0f;
|
||||||
|
Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity);
|
||||||
|
HoverActive = false;
|
||||||
|
|
||||||
// We don't have any physical representation yet.
|
// We don't have any physical representation yet.
|
||||||
PhysBody = new BulletBody(localID);
|
PhysBody = new BulletBody(localID);
|
||||||
PhysShape = new BulletShape();
|
PhysShape = new BSShapeNull();
|
||||||
|
|
||||||
// A linkset of just me
|
PrimAssetState = PrimAssetCondition.Unknown;
|
||||||
Linkset = BSLinkset.Factory(PhysicsScene, this);
|
|
||||||
LastAssetBuildFailed = false;
|
|
||||||
|
|
||||||
// Default material type
|
// Default material type. Also sets Friction, Restitution and Density.
|
||||||
Material = MaterialAttributes.Material.Wood;
|
SetMaterial((int)MaterialAttributes.Material.Wood);
|
||||||
|
|
||||||
CollisionCollection = new CollisionEventUpdate();
|
CollisionCollection = new CollisionEventUpdate();
|
||||||
|
CollisionsLastReported = CollisionCollection;
|
||||||
|
CollisionsLastTick = new CollisionEventUpdate();
|
||||||
|
CollisionsLastTickStep = -1;
|
||||||
|
|
||||||
SubscribedEventsMs = 0;
|
SubscribedEventsMs = 0;
|
||||||
CollidingStep = 0;
|
CollidingStep = 0;
|
||||||
CollidingGroundStep = 0;
|
CollidingGroundStep = 0;
|
||||||
|
CollisionAccumulation = 0;
|
||||||
|
ColliderIsMoving = false;
|
||||||
|
CollisionScore = 0;
|
||||||
|
|
||||||
|
// All axis free.
|
||||||
|
LockedLinearAxis = LockedAxisFree;
|
||||||
|
LockedAngularAxis = LockedAxisFree;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tell the object to clean up.
|
// Tell the object to clean up.
|
||||||
public virtual void Destroy()
|
public virtual void Destroy()
|
||||||
{
|
{
|
||||||
UnRegisterAllPreStepActions();
|
PhysicalActors.Enable(false);
|
||||||
|
PhysScene.TaintedObject("BSPhysObject.Destroy", delegate()
|
||||||
|
{
|
||||||
|
PhysicalActors.Dispose();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public BSScene PhysicsScene { get; protected set; }
|
public BSScene PhysScene { get; protected set; }
|
||||||
// public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor
|
// public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor
|
||||||
public string PhysObjectName { get; protected set; }
|
public string PhysObjectName { get; protected set; }
|
||||||
public string TypeName { get; protected set; }
|
public string TypeName { get; protected set; }
|
||||||
|
|
||||||
public BSLinkset Linkset { get; set; }
|
|
||||||
public BSLinksetInfo LinksetInfo { 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 RawMass { get; }
|
public abstract float RawMass { get; }
|
||||||
|
@ -104,26 +134,26 @@ public abstract class BSPhysObject : PhysicsActor
|
||||||
// 'inWorld' true if the object has already been added to the dynamic world.
|
// 'inWorld' true if the object has already been added to the dynamic world.
|
||||||
public abstract void UpdatePhysicalMassProperties(float mass, bool inWorld);
|
public abstract void UpdatePhysicalMassProperties(float mass, bool inWorld);
|
||||||
|
|
||||||
|
// The gravity being applied to the object. A function of default grav, GravityModifier and Buoyancy.
|
||||||
|
public virtual OMV.Vector3 Gravity { get; set; }
|
||||||
// The last value calculated for the prim's inertia
|
// The last value calculated for the prim's inertia
|
||||||
public OMV.Vector3 Inertia { get; set; }
|
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 PhysBody;
|
public BulletBody PhysBody;
|
||||||
// Reference to the physical shape (btCollisionShape) of this object
|
// Reference to the physical shape (btCollisionShape) of this object
|
||||||
public BulletShape PhysShape;
|
public BSShape PhysShape;
|
||||||
|
|
||||||
// 'true' if the mesh's underlying asset failed to build.
|
// The physical representation of the prim might require an asset fetch.
|
||||||
// This will keep us from looping after the first time the build failed.
|
// The asset state is first 'Unknown' then 'Waiting' then either 'Failed' or 'Fetched'.
|
||||||
public bool LastAssetBuildFailed { get; set; }
|
public enum PrimAssetCondition
|
||||||
|
{
|
||||||
|
Unknown, Waiting, Failed, Fetched
|
||||||
|
}
|
||||||
|
public PrimAssetCondition PrimAssetState { get; set; }
|
||||||
|
|
||||||
// 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 BSPhysicsShapeType PreferredPhysicalShape
|
|
||||||
{
|
|
||||||
get { return BSPhysicsShapeType.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
|
||||||
|
@ -132,23 +162,35 @@ public abstract class BSPhysObject : PhysicsActor
|
||||||
public EntityProperties LastEntityProperties { get; set; }
|
public EntityProperties LastEntityProperties { get; set; }
|
||||||
|
|
||||||
public virtual OMV.Vector3 Scale { get; set; }
|
public virtual OMV.Vector3 Scale { get; set; }
|
||||||
|
|
||||||
|
// It can be confusing for an actor to know if it should move or update an object
|
||||||
|
// depeneding on the setting of 'selected', 'physical, ...
|
||||||
|
// This flag is the true test -- if true, the object is being acted on in the physical world
|
||||||
|
public abstract bool IsPhysicallyActive { get; }
|
||||||
|
|
||||||
|
// Detailed state of the object.
|
||||||
public abstract bool IsSolid { get; }
|
public abstract bool IsSolid { get; }
|
||||||
public abstract bool IsStatic { get; }
|
public abstract bool IsStatic { get; }
|
||||||
|
public abstract bool IsSelected { get; }
|
||||||
|
|
||||||
// Materialness
|
// Materialness
|
||||||
public MaterialAttributes.Material Material { get; private set; }
|
public MaterialAttributes.Material Material { get; private set; }
|
||||||
public override void SetMaterial(int material)
|
public override void SetMaterial(int material)
|
||||||
{
|
{
|
||||||
Material = (MaterialAttributes.Material)material;
|
Material = (MaterialAttributes.Material)material;
|
||||||
|
|
||||||
|
// Setting the material sets the material attributes also.
|
||||||
|
MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false);
|
||||||
|
Friction = matAttrib.friction;
|
||||||
|
Restitution = matAttrib.restitution;
|
||||||
|
Density = matAttrib.density / BSParam.DensityScaleFactor;
|
||||||
|
// DetailLog("{0},{1}.SetMaterial,Mat={2},frict={3},rest={4},den={5}", LocalID, TypeName, Material, Friction, Restitution, Density);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop all physical motion.
|
// Stop all physical motion.
|
||||||
public abstract void ZeroMotion(bool inTaintTime);
|
public abstract void ZeroMotion(bool inTaintTime);
|
||||||
public abstract void ZeroAngularMotion(bool inTaintTime);
|
public abstract void ZeroAngularMotion(bool inTaintTime);
|
||||||
|
|
||||||
// Step the vehicle simulation for this object. A NOOP if the vehicle was not configured.
|
|
||||||
public virtual void StepVehicle(float timeStep) { }
|
|
||||||
|
|
||||||
// Update the physical location and motion of the object. Called with data from Bullet.
|
// Update the physical location and motion of the object. Called with data from Bullet.
|
||||||
public abstract void UpdateProperties(EntityProperties entprop);
|
public abstract void UpdateProperties(EntityProperties entprop);
|
||||||
|
|
||||||
|
@ -158,25 +200,122 @@ public abstract class BSPhysObject : PhysicsActor
|
||||||
public abstract OMV.Quaternion RawOrientation { get; set; }
|
public abstract OMV.Quaternion RawOrientation { get; set; }
|
||||||
public abstract OMV.Quaternion ForceOrientation { get; set; }
|
public abstract OMV.Quaternion ForceOrientation { get; set; }
|
||||||
|
|
||||||
// The system is telling us the velocity it wants to move at.
|
public OMV.Vector3 RawVelocity { get; set; }
|
||||||
// protected OMV.Vector3 m_targetVelocity; // use the definition in PhysicsActor
|
|
||||||
public override OMV.Vector3 TargetVelocity
|
|
||||||
{
|
|
||||||
get { return m_targetVelocity; }
|
|
||||||
set
|
|
||||||
{
|
|
||||||
m_targetVelocity = value;
|
|
||||||
Velocity = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public abstract OMV.Vector3 ForceVelocity { get; set; }
|
public abstract OMV.Vector3 ForceVelocity { get; set; }
|
||||||
|
|
||||||
|
public OMV.Vector3 RawForce { get; set; }
|
||||||
|
public OMV.Vector3 RawTorque { get; set; }
|
||||||
|
public override void AddAngularForce(OMV.Vector3 force, bool pushforce)
|
||||||
|
{
|
||||||
|
AddAngularForce(force, pushforce, false);
|
||||||
|
}
|
||||||
|
public abstract void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime);
|
||||||
|
|
||||||
public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
|
public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
|
||||||
|
|
||||||
public abstract float ForceBuoyancy { get; set; }
|
public abstract float ForceBuoyancy { get; set; }
|
||||||
|
|
||||||
public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; }
|
public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; }
|
||||||
|
|
||||||
|
public override bool PIDActive { set { MoveToTargetActive = value; } }
|
||||||
|
public override OMV.Vector3 PIDTarget { set { MoveToTargetTarget = value; } }
|
||||||
|
public override float PIDTau { set { MoveToTargetTau = value; } }
|
||||||
|
|
||||||
|
public bool MoveToTargetActive { get; set; }
|
||||||
|
public OMV.Vector3 MoveToTargetTarget { get; set; }
|
||||||
|
public float MoveToTargetTau { get; set; }
|
||||||
|
|
||||||
|
// Used for llSetHoverHeight and maybe vehicle height. Hover Height will override MoveTo target's Z
|
||||||
|
public override bool PIDHoverActive { set { HoverActive = value; } }
|
||||||
|
public override float PIDHoverHeight { set { HoverHeight = value; } }
|
||||||
|
public override PIDHoverType PIDHoverType { set { HoverType = value; } }
|
||||||
|
public override float PIDHoverTau { set { HoverTau = value; } }
|
||||||
|
|
||||||
|
public bool HoverActive { get; set; }
|
||||||
|
public float HoverHeight { get; set; }
|
||||||
|
public PIDHoverType HoverType { get; set; }
|
||||||
|
public float HoverTau { get; set; }
|
||||||
|
|
||||||
|
// For RotLookAt
|
||||||
|
public override OMV.Quaternion APIDTarget { set { return; } }
|
||||||
|
public override bool APIDActive { set { return; } }
|
||||||
|
public override float APIDStrength { set { return; } }
|
||||||
|
public override float APIDDamping { set { return; } }
|
||||||
|
|
||||||
|
// The current velocity forward
|
||||||
|
public virtual float ForwardSpeed
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
OMV.Vector3 characterOrientedVelocity = RawVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation));
|
||||||
|
return characterOrientedVelocity.X;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// The forward speed we are trying to achieve (TargetVelocity)
|
||||||
|
public virtual float TargetVelocitySpeed
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
OMV.Vector3 characterOrientedVelocity = TargetVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation));
|
||||||
|
return characterOrientedVelocity.X;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The user can optionally set the center of mass. The user's setting will override any
|
||||||
|
// computed center-of-mass (like in linksets).
|
||||||
|
// Note this is a displacement from the root's coordinates. Zero means use the root prim as center-of-mass.
|
||||||
|
public OMV.Vector3? UserSetCenterOfMassDisplacement { get; set; }
|
||||||
|
|
||||||
|
public OMV.Vector3 LockedLinearAxis { get; set; } // zero means locked. one means free.
|
||||||
|
public OMV.Vector3 LockedAngularAxis { get; set; } // zero means locked. one means free.
|
||||||
|
public const float FreeAxis = 1f;
|
||||||
|
public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(FreeAxis, FreeAxis, FreeAxis); // All axis are free
|
||||||
|
|
||||||
|
// Enable physical actions. Bullet will keep sleeping non-moving physical objects so
|
||||||
|
// they need waking up when parameters are changed.
|
||||||
|
// Called in taint-time!!
|
||||||
|
public void ActivateIfPhysical(bool forceIt)
|
||||||
|
{
|
||||||
|
if (IsPhysical && PhysBody.HasPhysicalBody)
|
||||||
|
PhysScene.PE.Activate(PhysBody, forceIt);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 'actors' act on the physical object to change or constrain its motion. These can range from
|
||||||
|
// hovering to complex vehicle motion.
|
||||||
|
// May be called at non-taint time as this just adds the actor to the action list and the real
|
||||||
|
// work is done during the simulation step.
|
||||||
|
// Note that, if the actor is already in the list and we are disabling same, the actor is just left
|
||||||
|
// in the list disabled.
|
||||||
|
public delegate BSActor CreateActor();
|
||||||
|
public void EnableActor(bool enableActor, string actorName, CreateActor creator)
|
||||||
|
{
|
||||||
|
lock (PhysicalActors)
|
||||||
|
{
|
||||||
|
BSActor theActor;
|
||||||
|
if (PhysicalActors.TryGetActor(actorName, out theActor))
|
||||||
|
{
|
||||||
|
// The actor already exists so just turn it on or off
|
||||||
|
DetailLog("{0},BSPhysObject.EnableActor,enablingExistingActor,name={1},enable={2}", LocalID, actorName, enableActor);
|
||||||
|
theActor.Enabled = enableActor;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// The actor does not exist. If it should, create it.
|
||||||
|
if (enableActor)
|
||||||
|
{
|
||||||
|
DetailLog("{0},BSPhysObject.EnableActor,creatingActor,name={1}", LocalID, actorName);
|
||||||
|
theActor = creator();
|
||||||
|
PhysicalActors.Add(actorName, theActor);
|
||||||
|
theActor.Enabled = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DetailLog("{0},BSPhysObject.EnableActor,notCreatingActorSinceNotEnabled,name={1}", LocalID, actorName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#region Collisions
|
#region Collisions
|
||||||
|
|
||||||
// Requested number of milliseconds between collision events. Zero means disabled.
|
// Requested number of milliseconds between collision events. Zero means disabled.
|
||||||
|
@ -191,41 +330,56 @@ public abstract class BSPhysObject : PhysicsActor
|
||||||
protected long CollidingObjectStep { get; set; }
|
protected long CollidingObjectStep { get; set; }
|
||||||
// The collision flags we think are set in Bullet
|
// The collision flags we think are set in Bullet
|
||||||
protected CollisionFlags CurrentCollisionFlags { get; set; }
|
protected CollisionFlags CurrentCollisionFlags { get; set; }
|
||||||
|
// On a collision, check the collider and remember if the last collider was moving
|
||||||
|
// Used to modify the standing of avatars (avatars on stationary things stand still)
|
||||||
|
public bool ColliderIsMoving;
|
||||||
|
// Used by BSCharacter to manage standing (and not slipping)
|
||||||
|
public bool IsStationary;
|
||||||
|
|
||||||
|
// Count of collisions for this object
|
||||||
|
protected long CollisionAccumulation { get; set; }
|
||||||
|
|
||||||
public override bool IsColliding {
|
public override bool IsColliding {
|
||||||
get { return (CollidingStep == PhysicsScene.SimulationStep); }
|
get { return (CollidingStep == PhysScene.SimulationStep); }
|
||||||
set {
|
set {
|
||||||
if (value)
|
if (value)
|
||||||
CollidingStep = PhysicsScene.SimulationStep;
|
CollidingStep = PhysScene.SimulationStep;
|
||||||
else
|
else
|
||||||
CollidingStep = 0;
|
CollidingStep = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public override bool CollidingGround {
|
public override bool CollidingGround {
|
||||||
get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
|
get { return (CollidingGroundStep == PhysScene.SimulationStep); }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value)
|
if (value)
|
||||||
CollidingGroundStep = PhysicsScene.SimulationStep;
|
CollidingGroundStep = PhysScene.SimulationStep;
|
||||||
else
|
else
|
||||||
CollidingGroundStep = 0;
|
CollidingGroundStep = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public override bool CollidingObj {
|
public override bool CollidingObj {
|
||||||
get { return (CollidingObjectStep == PhysicsScene.SimulationStep); }
|
get { return (CollidingObjectStep == PhysScene.SimulationStep); }
|
||||||
set {
|
set {
|
||||||
if (value)
|
if (value)
|
||||||
CollidingObjectStep = PhysicsScene.SimulationStep;
|
CollidingObjectStep = PhysScene.SimulationStep;
|
||||||
else
|
else
|
||||||
CollidingObjectStep = 0;
|
CollidingObjectStep = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The collisions that have been collected this tick
|
// The collisions that have been collected for the next collision reporting (throttled by subscription)
|
||||||
protected CollisionEventUpdate CollisionCollection;
|
protected CollisionEventUpdate CollisionCollection;
|
||||||
|
// This is the collision collection last reported to the Simulator.
|
||||||
|
public CollisionEventUpdate CollisionsLastReported;
|
||||||
|
// Remember the collisions recorded in the last tick for fancy collision checking
|
||||||
|
// (like a BSCharacter walking up stairs).
|
||||||
|
public CollisionEventUpdate CollisionsLastTick;
|
||||||
|
private long CollisionsLastTickStep = -1;
|
||||||
|
|
||||||
// The simulation step is telling this object about a collision.
|
// The simulation step is telling this object about a collision.
|
||||||
// Return 'true' if a collision was processed and should be sent up.
|
// Return 'true' if a collision was processed and should be sent up.
|
||||||
|
// Return 'false' if this object is not enabled/subscribed/appropriate for or has already seen this collision.
|
||||||
// Called at taint time from within the Step() function
|
// Called at taint time from within the Step() function
|
||||||
public virtual bool Collide(uint collidingWith, BSPhysObject collidee,
|
public virtual bool Collide(uint collidingWith, BSPhysObject collidee,
|
||||||
OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
|
OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
|
||||||
|
@ -233,27 +387,35 @@ public abstract class BSPhysObject : PhysicsActor
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
// The following lines make IsColliding(), CollidingGround() and CollidingObj work
|
// The following lines make IsColliding(), CollidingGround() and CollidingObj work
|
||||||
CollidingStep = PhysicsScene.SimulationStep;
|
CollidingStep = PhysScene.SimulationStep;
|
||||||
if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID)
|
if (collidingWith <= PhysScene.TerrainManager.HighestTerrainID)
|
||||||
{
|
{
|
||||||
CollidingGroundStep = PhysicsScene.SimulationStep;
|
CollidingGroundStep = PhysScene.SimulationStep;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CollidingObjectStep = PhysicsScene.SimulationStep;
|
CollidingObjectStep = PhysScene.SimulationStep;
|
||||||
}
|
}
|
||||||
|
|
||||||
// prims in the same linkset cannot collide with each other
|
CollisionAccumulation++;
|
||||||
if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID))
|
|
||||||
|
// For movement tests, remember if we are colliding with an object that is moving.
|
||||||
|
ColliderIsMoving = collidee != null ? (collidee.RawVelocity != OMV.Vector3.Zero) : false;
|
||||||
|
|
||||||
|
// Make a collection of the collisions that happened the last simulation tick.
|
||||||
|
// This is different than the collection created for sending up to the simulator as it is cleared every tick.
|
||||||
|
if (CollisionsLastTickStep != PhysScene.SimulationStep)
|
||||||
{
|
{
|
||||||
return ret;
|
CollisionsLastTick = new CollisionEventUpdate();
|
||||||
|
CollisionsLastTickStep = PhysScene.SimulationStep;
|
||||||
}
|
}
|
||||||
|
CollisionsLastTick.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
|
||||||
|
|
||||||
// if someone has subscribed for collision events....
|
// If someone has subscribed for collision events log the collision so it will be reported up
|
||||||
if (SubscribedEvents()) {
|
if (SubscribedEvents()) {
|
||||||
CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
|
CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
|
||||||
DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}",
|
DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5},colliderMoving={6}",
|
||||||
LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth);
|
LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth, ColliderIsMoving);
|
||||||
|
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
|
@ -267,13 +429,14 @@ public abstract class BSPhysObject : PhysicsActor
|
||||||
public virtual bool SendCollisions()
|
public virtual bool SendCollisions()
|
||||||
{
|
{
|
||||||
bool ret = true;
|
bool ret = true;
|
||||||
|
|
||||||
// If the 'no collision' call, force it to happen right now so quick collision_end
|
// If the 'no collision' call, force it to happen right now so quick collision_end
|
||||||
bool force = (CollisionCollection.Count == 0);
|
bool force = (CollisionCollection.Count == 0 && CollisionsLastReported.Count != 0);
|
||||||
|
|
||||||
// throttle the collisions to the number of milliseconds specified in the subscription
|
// throttle the collisions to the number of milliseconds specified in the subscription
|
||||||
if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime))
|
if (force || (PhysScene.SimulationNowTime >= NextCollisionOkTime))
|
||||||
{
|
{
|
||||||
NextCollisionOkTime = PhysicsScene.SimulationNowTime + SubscribedEventsMs;
|
NextCollisionOkTime = PhysScene.SimulationNowTime + SubscribedEventsMs;
|
||||||
|
|
||||||
// We are called if we previously had collisions. If there are no collisions
|
// We are called if we previously had collisions. If there are no collisions
|
||||||
// this time, send up one last empty event so OpenSim can sense collision end.
|
// this time, send up one last empty event so OpenSim can sense collision end.
|
||||||
|
@ -283,12 +446,15 @@ public abstract class BSPhysObject : PhysicsActor
|
||||||
ret = false;
|
ret = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count);
|
DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count);
|
||||||
base.SendCollisionUpdate(CollisionCollection);
|
base.SendCollisionUpdate(CollisionCollection);
|
||||||
|
|
||||||
|
// Remember the collisions from this tick for some collision specific processing.
|
||||||
|
CollisionsLastReported = CollisionCollection;
|
||||||
|
|
||||||
// The CollisionCollection instance is passed around in the simulator.
|
// The CollisionCollection instance is passed around in the simulator.
|
||||||
// Make sure we don't have a handle to that one and that a new one is used for next time.
|
// Make sure we don't have a handle to that one and that a new one is used for next time.
|
||||||
// This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here,
|
// This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here,
|
||||||
// a race condition is created for the other users of this instance.
|
// a race condition is created for the other users of this instance.
|
||||||
CollisionCollection = new CollisionEventUpdate();
|
CollisionCollection = new CollisionEventUpdate();
|
||||||
}
|
}
|
||||||
|
@ -305,10 +471,10 @@ public abstract class BSPhysObject : PhysicsActor
|
||||||
// make sure first collision happens
|
// make sure first collision happens
|
||||||
NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs);
|
NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs);
|
||||||
|
|
||||||
PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate()
|
PhysScene.TaintedObject(TypeName+".SubscribeEvents", delegate()
|
||||||
{
|
{
|
||||||
if (PhysBody.HasPhysicalBody)
|
if (PhysBody.HasPhysicalBody)
|
||||||
CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
|
CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -320,66 +486,53 @@ public abstract class BSPhysObject : PhysicsActor
|
||||||
public override void UnSubscribeEvents() {
|
public override void UnSubscribeEvents() {
|
||||||
// DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName);
|
// DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName);
|
||||||
SubscribedEventsMs = 0;
|
SubscribedEventsMs = 0;
|
||||||
PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate()
|
PhysScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate()
|
||||||
{
|
{
|
||||||
// Make sure there is a body there because sometimes destruction happens in an un-ideal order.
|
// Make sure there is a body there because sometimes destruction happens in an un-ideal order.
|
||||||
if (PhysBody.HasPhysicalBody)
|
if (PhysBody.HasPhysicalBody)
|
||||||
CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
|
CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// Return 'true' if the simulator wants collision events
|
// Return 'true' if the simulator wants collision events
|
||||||
public override bool SubscribedEvents() {
|
public override bool SubscribedEvents() {
|
||||||
return (SubscribedEventsMs > 0);
|
return (SubscribedEventsMs > 0);
|
||||||
}
|
}
|
||||||
|
// Because 'CollisionScore' is called many times while sorting, it should not be recomputed
|
||||||
|
// each time called. So this is built to be light weight for each collision and to do
|
||||||
|
// all the processing when the user asks for the info.
|
||||||
|
public void ComputeCollisionScore()
|
||||||
|
{
|
||||||
|
// Scale the collision count by the time since the last collision.
|
||||||
|
// The "+1" prevents dividing by zero.
|
||||||
|
long timeAgo = PhysScene.SimulationStep - CollidingStep + 1;
|
||||||
|
CollisionScore = CollisionAccumulation / timeAgo;
|
||||||
|
}
|
||||||
|
public override float CollisionScore { get; set; }
|
||||||
|
|
||||||
#endregion // Collisions
|
#endregion // Collisions
|
||||||
|
|
||||||
#region Per Simulation Step actions
|
#region Per Simulation Step actions
|
||||||
// There are some actions that must be performed for a physical object before each simulation step.
|
|
||||||
// These actions are optional so, rather than scanning all the physical objects and asking them
|
public BSActorCollection PhysicalActors;
|
||||||
// if they have anything to do, a physical object registers for an event call before the step is performed.
|
|
||||||
// This bookkeeping makes it easy to add, remove and clean up after all these registrations.
|
// When an update to the physical properties happens, this event is fired to let
|
||||||
private Dictionary<string, BSScene.PreStepAction> RegisteredActions = new Dictionary<string, BSScene.PreStepAction>();
|
// different actors to modify the update before it is passed around
|
||||||
protected void RegisterPreStepAction(string op, uint id, BSScene.PreStepAction actn)
|
public delegate void PreUpdatePropertyAction(ref EntityProperties entprop);
|
||||||
|
public event PreUpdatePropertyAction OnPreUpdateProperty;
|
||||||
|
protected void TriggerPreUpdatePropertyAction(ref EntityProperties entprop)
|
||||||
{
|
{
|
||||||
string identifier = op + "-" + id.ToString();
|
PreUpdatePropertyAction actions = OnPreUpdateProperty;
|
||||||
RegisteredActions[identifier] = actn;
|
if (actions != null)
|
||||||
PhysicsScene.BeforeStep += actn;
|
actions(ref entprop);
|
||||||
DetailLog("{0},BSPhysObject.RegisterPreStepAction,id={1}", LocalID, identifier);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unregister a pre step action. Safe to call if the action has not been registered.
|
|
||||||
protected void UnRegisterPreStepAction(string op, uint id)
|
|
||||||
{
|
|
||||||
string identifier = op + "-" + id.ToString();
|
|
||||||
bool removed = false;
|
|
||||||
if (RegisteredActions.ContainsKey(identifier))
|
|
||||||
{
|
|
||||||
PhysicsScene.BeforeStep -= RegisteredActions[identifier];
|
|
||||||
RegisteredActions.Remove(identifier);
|
|
||||||
removed = true;
|
|
||||||
}
|
|
||||||
DetailLog("{0},BSPhysObject.UnRegisterPreStepAction,id={1},removed={2}", LocalID, identifier, removed);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void UnRegisterAllPreStepActions()
|
|
||||||
{
|
|
||||||
foreach (KeyValuePair<string, BSScene.PreStepAction> kvp in RegisteredActions)
|
|
||||||
{
|
|
||||||
PhysicsScene.BeforeStep -= kvp.Value;
|
|
||||||
}
|
|
||||||
RegisteredActions.Clear();
|
|
||||||
DetailLog("{0},BSPhysObject.UnRegisterAllPreStepActions,", LocalID);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endregion // Per Simulation Step actions
|
#endregion // Per Simulation Step actions
|
||||||
|
|
||||||
// High performance detailed logging routine used by the physical objects.
|
// High performance detailed logging routine used by the physical objects.
|
||||||
protected void DetailLog(string msg, params Object[] args)
|
protected void DetailLog(string msg, params Object[] args)
|
||||||
{
|
{
|
||||||
if (PhysicsScene.PhysicsLogging.Enabled)
|
if (PhysScene.PhysicsLogging.Enabled)
|
||||||
PhysicsScene.DetailLog(msg, args);
|
PhysScene.DetailLog(msg, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ public class BSPlugin : IPhysicsPlugin
|
||||||
{
|
{
|
||||||
if (_mScene == null)
|
if (_mScene == null)
|
||||||
{
|
{
|
||||||
_mScene = new BSScene(sceneIdentifier);
|
_mScene = new BSScene(GetName(), sceneIdentifier);
|
||||||
}
|
}
|
||||||
return (_mScene);
|
return (_mScene);
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,165 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Contributors, http://opensimulator.org/
|
||||||
|
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the OpenSimulator Project nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* The quotations from http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial
|
||||||
|
* are Copyright (c) 2009 Linden Research, Inc and are used under their license
|
||||||
|
* of Creative Commons Attribution-Share Alike 3.0
|
||||||
|
* (http://creativecommons.org/licenses/by-sa/3.0/).
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using OpenMetaverse;
|
||||||
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Region.Physics.Manager;
|
||||||
|
|
||||||
|
using OMV = OpenMetaverse;
|
||||||
|
|
||||||
|
namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
|
{
|
||||||
|
public class BSPrimDisplaced : BSPrim
|
||||||
|
{
|
||||||
|
// The purpose of this module is to do any mapping between what the simulator thinks
|
||||||
|
// the prim position and orientation is and what the physical position/orientation.
|
||||||
|
// This difference happens because Bullet assumes the center-of-mass is the <0,0,0>
|
||||||
|
// of the prim/linkset. The simulator tracks the location of the prim/linkset by
|
||||||
|
// the location of the root prim. So, if center-of-mass is anywhere but the origin
|
||||||
|
// of the root prim, the physical origin is displaced from the simulator origin.
|
||||||
|
//
|
||||||
|
// This routine works by capturing the Force* setting of position/orientation/... and
|
||||||
|
// adjusting the simulator values (being set) into the physical values.
|
||||||
|
// The conversion is also done in the opposite direction (physical origin -> simulator origin).
|
||||||
|
//
|
||||||
|
// The updateParameter call is also captured and the values from the physics engine
|
||||||
|
// are converted into simulator origin values before being passed to the base
|
||||||
|
// class.
|
||||||
|
|
||||||
|
public virtual OMV.Vector3 PositionDisplacement { get; set; }
|
||||||
|
public virtual OMV.Quaternion OrientationDisplacement { get; set; }
|
||||||
|
|
||||||
|
public BSPrimDisplaced(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
|
||||||
|
OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
|
||||||
|
: base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical)
|
||||||
|
{
|
||||||
|
ClearDisplacement();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearDisplacement()
|
||||||
|
{
|
||||||
|
PositionDisplacement = OMV.Vector3.Zero;
|
||||||
|
OrientationDisplacement = OMV.Quaternion.Identity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set this sets and computes the displacement from the passed prim to the center-of-mass.
|
||||||
|
// A user set value for center-of-mass overrides whatever might be passed in here.
|
||||||
|
// The displacement is in local coordinates (relative to root prim in linkset oriented coordinates).
|
||||||
|
public virtual void SetEffectiveCenterOfMassDisplacement(Vector3 centerOfMassDisplacement)
|
||||||
|
{
|
||||||
|
Vector3 comDisp;
|
||||||
|
if (UserSetCenterOfMassDisplacement.HasValue)
|
||||||
|
comDisp = (OMV.Vector3)UserSetCenterOfMassDisplacement;
|
||||||
|
else
|
||||||
|
comDisp = centerOfMassDisplacement;
|
||||||
|
|
||||||
|
DetailLog("{0},BSPrimDisplaced.SetEffectiveCenterOfMassDisplacement,userSet={1},comDisp={2}",
|
||||||
|
LocalID, UserSetCenterOfMassDisplacement.HasValue, comDisp);
|
||||||
|
if (comDisp == Vector3.Zero)
|
||||||
|
{
|
||||||
|
// If there is no diplacement. Things get reset.
|
||||||
|
PositionDisplacement = OMV.Vector3.Zero;
|
||||||
|
OrientationDisplacement = OMV.Quaternion.Identity;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Remember the displacement from root as well as the origional rotation of the
|
||||||
|
// new center-of-mass.
|
||||||
|
PositionDisplacement = comDisp;
|
||||||
|
OrientationDisplacement = OMV.Quaternion.Identity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Vector3 ForcePosition
|
||||||
|
{
|
||||||
|
get { return base.ForcePosition; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (PositionDisplacement != OMV.Vector3.Zero)
|
||||||
|
{
|
||||||
|
OMV.Vector3 displacedPos = value - (PositionDisplacement * RawOrientation);
|
||||||
|
DetailLog("{0},BSPrimDisplaced.ForcePosition,val={1},disp={2},newPos={3}", LocalID, value, PositionDisplacement, displacedPos);
|
||||||
|
base.ForcePosition = displacedPos;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
base.ForcePosition = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Quaternion ForceOrientation
|
||||||
|
{
|
||||||
|
get { return base.ForceOrientation; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
base.ForceOrientation = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: decide if this is the right place for these variables.
|
||||||
|
// Somehow incorporate the optional settability by the user.
|
||||||
|
// Is this used?
|
||||||
|
public override OMV.Vector3 CenterOfMass
|
||||||
|
{
|
||||||
|
get { return RawPosition; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is this used?
|
||||||
|
public override OMV.Vector3 GeometricCenter
|
||||||
|
{
|
||||||
|
get { return RawPosition; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdateProperties(EntityProperties entprop)
|
||||||
|
{
|
||||||
|
// Undo any center-of-mass displacement that might have been done.
|
||||||
|
if (PositionDisplacement != OMV.Vector3.Zero || OrientationDisplacement != OMV.Quaternion.Identity)
|
||||||
|
{
|
||||||
|
// Correct for any rotation around the center-of-mass
|
||||||
|
// TODO!!!
|
||||||
|
|
||||||
|
OMV.Vector3 displacedPos = entprop.Position + (PositionDisplacement * entprop.Rotation);
|
||||||
|
DetailLog("{0},BSPrimDisplaced.ForcePosition,physPos={1},disp={2},newPos={3}", LocalID, entprop.Position, PositionDisplacement, displacedPos);
|
||||||
|
entprop.Position = displacedPos;
|
||||||
|
// entprop.Rotation = something;
|
||||||
|
}
|
||||||
|
|
||||||
|
base.UpdateProperties(entprop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,192 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
using OpenSim.Framework;
|
||||||
|
|
||||||
|
using OMV = OpenMetaverse;
|
||||||
|
|
||||||
|
namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
|
{
|
||||||
|
public class BSPrimLinkable : BSPrimDisplaced
|
||||||
|
{
|
||||||
|
public BSLinkset Linkset { get; set; }
|
||||||
|
// The index of this child prim.
|
||||||
|
public int LinksetChildIndex { get; set; }
|
||||||
|
|
||||||
|
public BSLinksetInfo LinksetInfo { get; set; }
|
||||||
|
|
||||||
|
public BSPrimLinkable(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
|
||||||
|
OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
|
||||||
|
: base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical)
|
||||||
|
{
|
||||||
|
Linkset = BSLinkset.Factory(PhysScene, this);
|
||||||
|
|
||||||
|
PhysScene.TaintedObject("BSPrimLinksetCompound.Refresh", delegate()
|
||||||
|
{
|
||||||
|
Linkset.Refresh(this);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Destroy()
|
||||||
|
{
|
||||||
|
Linkset = Linkset.RemoveMeFromLinkset(this);
|
||||||
|
base.Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void link(Manager.PhysicsActor obj)
|
||||||
|
{
|
||||||
|
BSPrimLinkable parent = obj as BSPrimLinkable;
|
||||||
|
if (parent != null)
|
||||||
|
{
|
||||||
|
BSPhysObject parentBefore = Linkset.LinksetRoot;
|
||||||
|
int childrenBefore = Linkset.NumberOfChildren;
|
||||||
|
|
||||||
|
Linkset = parent.Linkset.AddMeToLinkset(this);
|
||||||
|
|
||||||
|
DetailLog("{0},BSPrimLinkset.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}",
|
||||||
|
LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void delink()
|
||||||
|
{
|
||||||
|
// TODO: decide if this parent checking needs to happen at taint time
|
||||||
|
// Race condition here: if link() and delink() in same simulation tick, the delink will not happen
|
||||||
|
|
||||||
|
BSPhysObject parentBefore = Linkset.LinksetRoot;
|
||||||
|
int childrenBefore = Linkset.NumberOfChildren;
|
||||||
|
|
||||||
|
Linkset = Linkset.RemoveMeFromLinkset(this);
|
||||||
|
|
||||||
|
DetailLog("{0},BSPrimLinkset.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ",
|
||||||
|
LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When simulator changes position, this might be moving a child of the linkset.
|
||||||
|
public override OMV.Vector3 Position
|
||||||
|
{
|
||||||
|
get { return base.Position; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
base.Position = value;
|
||||||
|
PhysScene.TaintedObject("BSPrimLinkset.setPosition", delegate()
|
||||||
|
{
|
||||||
|
Linkset.UpdateProperties(UpdatedProperties.Position, this);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// When simulator changes orientation, this might be moving a child of the linkset.
|
||||||
|
public override OMV.Quaternion Orientation
|
||||||
|
{
|
||||||
|
get { return base.Orientation; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
base.Orientation = value;
|
||||||
|
PhysScene.TaintedObject("BSPrimLinkset.setOrientation", delegate()
|
||||||
|
{
|
||||||
|
Linkset.UpdateProperties(UpdatedProperties.Orientation, this);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override float TotalMass
|
||||||
|
{
|
||||||
|
get { return Linkset.LinksetMass; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdatePhysicalParameters()
|
||||||
|
{
|
||||||
|
base.UpdatePhysicalParameters();
|
||||||
|
// Recompute any linkset parameters.
|
||||||
|
// When going from non-physical to physical, this re-enables the constraints that
|
||||||
|
// had been automatically disabled when the mass was set to zero.
|
||||||
|
// For compound based linksets, this enables and disables interactions of the children.
|
||||||
|
if (Linkset != null) // null can happen during initialization
|
||||||
|
Linkset.Refresh(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void MakeDynamic(bool makeStatic)
|
||||||
|
{
|
||||||
|
base.MakeDynamic(makeStatic);
|
||||||
|
if (makeStatic)
|
||||||
|
Linkset.MakeStatic(this);
|
||||||
|
else
|
||||||
|
Linkset.MakeDynamic(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Body is being taken apart. Remove physical dependencies and schedule a rebuild.
|
||||||
|
protected override void RemoveDependencies()
|
||||||
|
{
|
||||||
|
Linkset.RemoveDependencies(this);
|
||||||
|
base.RemoveDependencies();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdateProperties(EntityProperties entprop)
|
||||||
|
{
|
||||||
|
if (Linkset.IsRoot(this))
|
||||||
|
{
|
||||||
|
// Properties are only updated for the roots of a linkset.
|
||||||
|
// TODO: this will have to change when linksets are articulated.
|
||||||
|
base.UpdateProperties(entprop);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// For debugging, report the movement of children
|
||||||
|
DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
|
||||||
|
LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
|
||||||
|
entprop.Acceleration, entprop.RotationalVelocity);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
// The linkset might like to know about changing locations
|
||||||
|
Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Collide(uint collidingWith, BSPhysObject collidee,
|
||||||
|
OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
|
||||||
|
{
|
||||||
|
// prims in the same linkset cannot collide with each other
|
||||||
|
BSPrimLinkable convCollidee = collidee as BSPrimLinkable;
|
||||||
|
if (convCollidee != null && (this.Linkset.LinksetID == convCollidee.Linkset.LinksetID))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: handle collisions of other objects with with children of linkset.
|
||||||
|
// This is a problem for LinksetCompound since the children are packed into the root.
|
||||||
|
|
||||||
|
return base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,6 +26,7 @@
|
||||||
*/
|
*/
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
@ -81,14 +82,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
internal long m_simulationStep = 0;
|
internal long m_simulationStep = 0;
|
||||||
internal float NominalFrameRate { get; set; }
|
internal float NominalFrameRate { get; set; }
|
||||||
public long SimulationStep { get { return m_simulationStep; } }
|
public long SimulationStep { get { return m_simulationStep; } }
|
||||||
internal int m_taintsToProcessPerStep;
|
|
||||||
internal float LastTimeStep { get; private set; }
|
internal float LastTimeStep { get; private set; }
|
||||||
|
|
||||||
// Physical objects can register for prestep or poststep events
|
// Physical objects can register for prestep or poststep events
|
||||||
public delegate void PreStepAction(float timeStep);
|
public delegate void PreStepAction(float timeStep);
|
||||||
public delegate void PostStepAction(float timeStep);
|
public delegate void PostStepAction(float timeStep);
|
||||||
public event PreStepAction BeforeStep;
|
public event PreStepAction BeforeStep;
|
||||||
public event PreStepAction AfterStep;
|
public event PostStepAction AfterStep;
|
||||||
|
|
||||||
// A value of the time now so all the collision and update routines do not have to get their own
|
// A value of the time now so all the collision and update routines do not have to get their own
|
||||||
// Set to 'now' just before all the prims and actors are called for collisions and updates
|
// Set to 'now' just before all the prims and actors are called for collisions and updates
|
||||||
|
@ -161,17 +161,22 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
private int m_physicsLoggingFileMinutes;
|
private int m_physicsLoggingFileMinutes;
|
||||||
private bool m_physicsLoggingDoFlush;
|
private bool m_physicsLoggingDoFlush;
|
||||||
private bool m_physicsPhysicalDumpEnabled;
|
private bool m_physicsPhysicalDumpEnabled;
|
||||||
public float PhysicsMetricDumpFrames { get; set; }
|
public int PhysicsMetricDumpFrames { get; set; }
|
||||||
// 'true' of the vehicle code is to log lots of details
|
// 'true' of the vehicle code is to log lots of details
|
||||||
public bool VehicleLoggingEnabled { get; private set; }
|
public bool VehicleLoggingEnabled { get; private set; }
|
||||||
public bool VehiclePhysicalLoggingEnabled { get; private set; }
|
public bool VehiclePhysicalLoggingEnabled { get; private set; }
|
||||||
|
|
||||||
#region Construction and Initialization
|
#region Construction and Initialization
|
||||||
public BSScene(string identifier)
|
public BSScene(string engineType, string identifier)
|
||||||
{
|
{
|
||||||
m_initialized = false;
|
m_initialized = false;
|
||||||
// we are passed the name of the region we're working for.
|
|
||||||
|
// The name of the region we're working for is passed to us. Keep for identification.
|
||||||
RegionName = identifier;
|
RegionName = identifier;
|
||||||
|
|
||||||
|
// Set identifying variables in the PhysicsScene interface.
|
||||||
|
EngineType = engineType;
|
||||||
|
Name = EngineType + "/" + RegionName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Initialise(IMesher meshmerizer, IConfigSource config)
|
public override void Initialise(IMesher meshmerizer, IConfigSource config)
|
||||||
|
@ -309,9 +314,15 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
case "bulletunmanaged":
|
case "bulletunmanaged":
|
||||||
ret = new BSAPIUnman(engineName, this);
|
ret = new BSAPIUnman(engineName, this);
|
||||||
break;
|
break;
|
||||||
|
/*
|
||||||
case "bulletxna":
|
case "bulletxna":
|
||||||
ret = new BSAPIXNA(engineName, this);
|
ret = new BSAPIXNA(engineName, this);
|
||||||
|
// Disable some features that are not implemented in BulletXNA
|
||||||
|
m_log.InfoFormat("{0} Disabling some physics features not implemented by BulletXNA", LogHeader);
|
||||||
|
BSParam.ShouldUseBulletHACD = false;
|
||||||
|
BSParam.ShouldUseSingleConvexHullForPrims = false;
|
||||||
break;
|
break;
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret == null)
|
if (ret == null)
|
||||||
|
@ -382,12 +393,14 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
if (!m_initialized) return null;
|
if (!m_initialized) return null;
|
||||||
|
|
||||||
BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying);
|
BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying);
|
||||||
lock (PhysObjects) PhysObjects.Add(localID, actor);
|
lock (PhysObjects)
|
||||||
|
PhysObjects.Add(localID, actor);
|
||||||
|
|
||||||
// TODO: Remove kludge someday.
|
// TODO: Remove kludge someday.
|
||||||
// We must generate a collision for avatars whether they collide or not.
|
// We must generate a collision for avatars whether they collide or not.
|
||||||
// This is required by OpenSim to update avatar animations, etc.
|
// This is required by OpenSim to update avatar animations, etc.
|
||||||
lock (m_avatars) m_avatars.Add(actor);
|
lock (m_avatars)
|
||||||
|
m_avatars.Add(actor);
|
||||||
|
|
||||||
return actor;
|
return actor;
|
||||||
}
|
}
|
||||||
|
@ -403,9 +416,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
lock (PhysObjects) PhysObjects.Remove(actor.LocalID);
|
lock (PhysObjects)
|
||||||
|
PhysObjects.Remove(bsactor.LocalID);
|
||||||
// Remove kludge someday
|
// Remove kludge someday
|
||||||
lock (m_avatars) m_avatars.Remove(bsactor);
|
lock (m_avatars)
|
||||||
|
m_avatars.Remove(bsactor);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -414,13 +429,18 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
bsactor.Destroy();
|
bsactor.Destroy();
|
||||||
// bsactor.dispose();
|
// bsactor.dispose();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_log.ErrorFormat("{0}: Requested to remove avatar that is not a BSCharacter. ID={1}, type={2}",
|
||||||
|
LogHeader, actor.LocalID, actor.GetType().Name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void RemovePrim(PhysicsActor prim)
|
public override void RemovePrim(PhysicsActor prim)
|
||||||
{
|
{
|
||||||
if (!m_initialized) return;
|
if (!m_initialized) return;
|
||||||
|
|
||||||
BSPrim bsprim = prim as BSPrim;
|
BSPhysObject bsprim = prim as BSPhysObject;
|
||||||
if (bsprim != null)
|
if (bsprim != null)
|
||||||
{
|
{
|
||||||
DetailLog("{0},RemovePrim,call", bsprim.LocalID);
|
DetailLog("{0},RemovePrim,call", bsprim.LocalID);
|
||||||
|
@ -449,9 +469,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
|
|
||||||
if (!m_initialized) return null;
|
if (!m_initialized) return null;
|
||||||
|
|
||||||
DetailLog("{0},AddPrimShape,call", localID);
|
// DetailLog("{0},BSScene.AddPrimShape,call", localID);
|
||||||
|
|
||||||
BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical);
|
BSPhysObject prim = new BSPrimLinkable(localID, primName, this, position, size, rotation, pbs, isPhysical);
|
||||||
lock (PhysObjects) PhysObjects.Add(localID, prim);
|
lock (PhysObjects) PhysObjects.Add(localID, prim);
|
||||||
return prim;
|
return prim;
|
||||||
}
|
}
|
||||||
|
@ -486,6 +506,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
ProcessTaints();
|
ProcessTaints();
|
||||||
|
|
||||||
// Some of the physical objects requre individual, pre-step calls
|
// Some of the physical objects requre individual, pre-step calls
|
||||||
|
// (vehicles and avatar movement, in particular)
|
||||||
TriggerPreStepEvent(timeStep);
|
TriggerPreStepEvent(timeStep);
|
||||||
|
|
||||||
// the prestep actions might have added taints
|
// the prestep actions might have added taints
|
||||||
|
@ -527,7 +548,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
collidersCount = 0;
|
collidersCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((m_simulationStep % PhysicsMetricDumpFrames) == 0)
|
if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0))
|
||||||
PE.DumpPhysicsStatistics(World);
|
PE.DumpPhysicsStatistics(World);
|
||||||
|
|
||||||
// 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.
|
||||||
|
@ -543,8 +564,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
uint cB = m_collisionArray[ii].bID;
|
uint cB = m_collisionArray[ii].bID;
|
||||||
Vector3 point = m_collisionArray[ii].point;
|
Vector3 point = m_collisionArray[ii].point;
|
||||||
Vector3 normal = m_collisionArray[ii].normal;
|
Vector3 normal = m_collisionArray[ii].normal;
|
||||||
SendCollision(cA, cB, point, normal, 0.01f);
|
float penetration = m_collisionArray[ii].penetration;
|
||||||
SendCollision(cB, cA, point, -normal, 0.01f);
|
SendCollision(cA, cB, point, normal, penetration);
|
||||||
|
SendCollision(cB, cA, point, -normal, penetration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -682,7 +704,21 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
|
|
||||||
public override Dictionary<uint, float> GetTopColliders()
|
public override Dictionary<uint, float> GetTopColliders()
|
||||||
{
|
{
|
||||||
return new Dictionary<uint, float>();
|
Dictionary<uint, float> topColliders;
|
||||||
|
|
||||||
|
lock (PhysObjects)
|
||||||
|
{
|
||||||
|
foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects)
|
||||||
|
{
|
||||||
|
kvp.Value.ComputeCollisionScore();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<BSPhysObject> orderedPrims = new List<BSPhysObject>(PhysObjects.Values);
|
||||||
|
orderedPrims.OrderByDescending(p => p.CollisionScore);
|
||||||
|
topColliders = orderedPrims.Take(25).ToDictionary(p => p.LocalID, p => p.CollisionScore);
|
||||||
|
}
|
||||||
|
|
||||||
|
return topColliders;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool IsThreaded { get { return false; } }
|
public override bool IsThreaded { get { return false; } }
|
||||||
|
@ -694,8 +730,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
// TriggerPreStepEvent
|
// TriggerPreStepEvent
|
||||||
// DoOneTimeTaints
|
// DoOneTimeTaints
|
||||||
// Step()
|
// Step()
|
||||||
// ProcessAndForwardCollisions
|
// ProcessAndSendToSimulatorCollisions
|
||||||
// ProcessAndForwardPropertyUpdates
|
// ProcessAndSendToSimulatorPropertyUpdates
|
||||||
// TriggerPostStepEvent
|
// TriggerPostStepEvent
|
||||||
|
|
||||||
// Calls to the PhysicsActors can't directly call into the physics engine
|
// Calls to the PhysicsActors can't directly call into the physics engine
|
||||||
|
@ -733,7 +769,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
|
|
||||||
private void TriggerPostStepEvent(float timeStep)
|
private void TriggerPostStepEvent(float timeStep)
|
||||||
{
|
{
|
||||||
PreStepAction actions = AfterStep;
|
PostStepAction actions = AfterStep;
|
||||||
if (actions != null)
|
if (actions != null)
|
||||||
actions(timeStep);
|
actions(timeStep);
|
||||||
|
|
||||||
|
@ -825,15 +861,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom);
|
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);
|
m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom);
|
||||||
Util.PrintCallStack(DetailLog);
|
// Util.PrintCallStack(DetailLog);
|
||||||
}
|
}
|
||||||
return InTaintTime;
|
return InTaintTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion // Taints
|
#endregion // Taints
|
||||||
|
|
||||||
#region INI and command line parameter processing
|
|
||||||
|
|
||||||
#region IPhysicsParameters
|
#region IPhysicsParameters
|
||||||
// Get the list of parameters this physics engine supports
|
// Get the list of parameters this physics engine supports
|
||||||
public PhysParameterEntry[] GetParameterList()
|
public PhysParameterEntry[] GetParameterList()
|
||||||
|
@ -848,64 +882,65 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
// will use the next time since it's pinned and shared memory.
|
// will use the next time since it's pinned and shared memory.
|
||||||
// Some of the values require calling into the physics engine to get the new
|
// Some of the values require calling into the physics engine to get the new
|
||||||
// value activated ('terrainFriction' for instance).
|
// value activated ('terrainFriction' for instance).
|
||||||
public bool SetPhysicsParameter(string parm, float val, uint localID)
|
public bool SetPhysicsParameter(string parm, string val, uint localID)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
BSParam.ParameterDefn theParam;
|
|
||||||
|
BSParam.ParameterDefnBase theParam;
|
||||||
if (BSParam.TryGetParameter(parm, out theParam))
|
if (BSParam.TryGetParameter(parm, out theParam))
|
||||||
{
|
{
|
||||||
theParam.setter(this, parm, localID, val);
|
// Set the value in the C# code
|
||||||
|
theParam.SetValue(this, val);
|
||||||
|
|
||||||
|
// Optionally set the parameter in the unmanaged code
|
||||||
|
if (theParam.HasSetOnObject)
|
||||||
|
{
|
||||||
|
// update all the localIDs specified
|
||||||
|
// If the local ID is APPLY_TO_NONE, just change the default value
|
||||||
|
// If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs
|
||||||
|
// If the localID is a specific object, apply the parameter change to only that object
|
||||||
|
List<uint> objectIDs = new List<uint>();
|
||||||
|
switch (localID)
|
||||||
|
{
|
||||||
|
case PhysParameterEntry.APPLY_TO_NONE:
|
||||||
|
// This will cause a call into the physical world if some operation is specified (SetOnObject).
|
||||||
|
objectIDs.Add(TERRAIN_ID);
|
||||||
|
TaintedUpdateParameter(parm, objectIDs, val);
|
||||||
|
break;
|
||||||
|
case PhysParameterEntry.APPLY_TO_ALL:
|
||||||
|
lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys);
|
||||||
|
TaintedUpdateParameter(parm, objectIDs, val);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// setting only one localID
|
||||||
|
objectIDs.Add(localID);
|
||||||
|
TaintedUpdateParameter(parm, objectIDs, val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// update all the localIDs specified
|
|
||||||
// If the local ID is APPLY_TO_NONE, just change the default value
|
|
||||||
// If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs
|
|
||||||
// If the localID is a specific object, apply the parameter change to only that object
|
|
||||||
internal delegate void AssignVal(float x);
|
|
||||||
internal void UpdateParameterObject(AssignVal setDefault, string parm, uint localID, float val)
|
|
||||||
{
|
|
||||||
List<uint> objectIDs = new List<uint>();
|
|
||||||
switch (localID)
|
|
||||||
{
|
|
||||||
case PhysParameterEntry.APPLY_TO_NONE:
|
|
||||||
setDefault(val); // setting only the default value
|
|
||||||
// This will cause a call into the physical world if some operation is specified (SetOnObject).
|
|
||||||
objectIDs.Add(TERRAIN_ID);
|
|
||||||
TaintedUpdateParameter(parm, objectIDs, val);
|
|
||||||
break;
|
|
||||||
case PhysParameterEntry.APPLY_TO_ALL:
|
|
||||||
setDefault(val); // setting ALL also sets the default value
|
|
||||||
lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys);
|
|
||||||
TaintedUpdateParameter(parm, objectIDs, val);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// setting only one localID
|
|
||||||
objectIDs.Add(localID);
|
|
||||||
TaintedUpdateParameter(parm, objectIDs, val);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
||||||
private void TaintedUpdateParameter(string parm, List<uint> lIDs, float val)
|
private void TaintedUpdateParameter(string parm, List<uint> lIDs, string val)
|
||||||
{
|
{
|
||||||
float xval = val;
|
string xval = val;
|
||||||
List<uint> xlIDs = lIDs;
|
List<uint> xlIDs = lIDs;
|
||||||
string xparm = parm;
|
string xparm = parm;
|
||||||
TaintedObject("BSScene.UpdateParameterSet", delegate() {
|
TaintedObject("BSScene.UpdateParameterSet", delegate() {
|
||||||
BSParam.ParameterDefn thisParam;
|
BSParam.ParameterDefnBase thisParam;
|
||||||
if (BSParam.TryGetParameter(xparm, out thisParam))
|
if (BSParam.TryGetParameter(xparm, out thisParam))
|
||||||
{
|
{
|
||||||
if (thisParam.onObject != null)
|
if (thisParam.HasSetOnObject)
|
||||||
{
|
{
|
||||||
foreach (uint lID in xlIDs)
|
foreach (uint lID in xlIDs)
|
||||||
{
|
{
|
||||||
BSPhysObject theObject = null;
|
BSPhysObject theObject = null;
|
||||||
PhysObjects.TryGetValue(lID, out theObject);
|
if (PhysObjects.TryGetValue(lID, out theObject))
|
||||||
thisParam.onObject(this, theObject, xval);
|
thisParam.SetOnObject(this, theObject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -914,14 +949,14 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
|
|
||||||
// Get parameter.
|
// Get parameter.
|
||||||
// Return 'false' if not able to get the parameter.
|
// Return 'false' if not able to get the parameter.
|
||||||
public bool GetPhysicsParameter(string parm, out float value)
|
public bool GetPhysicsParameter(string parm, out string value)
|
||||||
{
|
{
|
||||||
float val = 0f;
|
string val = String.Empty;
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
BSParam.ParameterDefn theParam;
|
BSParam.ParameterDefnBase theParam;
|
||||||
if (BSParam.TryGetParameter(parm, out theParam))
|
if (BSParam.TryGetParameter(parm, out theParam))
|
||||||
{
|
{
|
||||||
val = theParam.getter(this);
|
val = theParam.GetValue(this);
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
value = val;
|
value = val;
|
||||||
|
@ -930,8 +965,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
|
|
||||||
#endregion IPhysicsParameters
|
#endregion IPhysicsParameters
|
||||||
|
|
||||||
#endregion Runtime settable parameters
|
|
||||||
|
|
||||||
// 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)
|
||||||
{
|
{
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -68,7 +68,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
|
||||||
|
|
||||||
// This minCoords and maxCoords passed in give the size of the terrain (min and max Z
|
// This minCoords and maxCoords passed in give the size of the terrain (min and max Z
|
||||||
// are the high and low points of the heightmap).
|
// are the high and low points of the heightmap).
|
||||||
public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap,
|
public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap,
|
||||||
Vector3 minCoords, Vector3 maxCoords)
|
Vector3 minCoords, Vector3 maxCoords)
|
||||||
: base(physicsScene, regionBase, id)
|
: base(physicsScene, regionBase, id)
|
||||||
{
|
{
|
||||||
|
@ -92,7 +92,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
|
||||||
private void BuildHeightmapTerrain()
|
private void BuildHeightmapTerrain()
|
||||||
{
|
{
|
||||||
// Create the terrain shape from the mapInfo
|
// Create the terrain shape from the mapInfo
|
||||||
m_mapInfo.terrainShape = PhysicsScene.PE.CreateTerrainShape( m_mapInfo.ID,
|
m_mapInfo.terrainShape = m_physicsScene.PE.CreateTerrainShape( m_mapInfo.ID,
|
||||||
new Vector3(m_mapInfo.sizeX, m_mapInfo.sizeY, 0), m_mapInfo.minZ, m_mapInfo.maxZ,
|
new Vector3(m_mapInfo.sizeX, m_mapInfo.sizeY, 0), m_mapInfo.minZ, m_mapInfo.maxZ,
|
||||||
m_mapInfo.heightMap, 1f, BSParam.TerrainCollisionMargin);
|
m_mapInfo.heightMap, 1f, BSParam.TerrainCollisionMargin);
|
||||||
|
|
||||||
|
@ -103,26 +103,26 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
|
||||||
centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f);
|
centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f);
|
||||||
centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f);
|
centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f);
|
||||||
|
|
||||||
m_mapInfo.terrainBody = PhysicsScene.PE.CreateBodyWithDefaultMotionState(m_mapInfo.terrainShape,
|
m_mapInfo.terrainBody = m_physicsScene.PE.CreateBodyWithDefaultMotionState(m_mapInfo.terrainShape,
|
||||||
m_mapInfo.ID, centerPos, Quaternion.Identity);
|
m_mapInfo.ID, centerPos, Quaternion.Identity);
|
||||||
|
|
||||||
// Set current terrain attributes
|
// Set current terrain attributes
|
||||||
PhysicsScene.PE.SetFriction(m_mapInfo.terrainBody, BSParam.TerrainFriction);
|
m_physicsScene.PE.SetFriction(m_mapInfo.terrainBody, BSParam.TerrainFriction);
|
||||||
PhysicsScene.PE.SetHitFraction(m_mapInfo.terrainBody, BSParam.TerrainHitFraction);
|
m_physicsScene.PE.SetHitFraction(m_mapInfo.terrainBody, BSParam.TerrainHitFraction);
|
||||||
PhysicsScene.PE.SetRestitution(m_mapInfo.terrainBody, BSParam.TerrainRestitution);
|
m_physicsScene.PE.SetRestitution(m_mapInfo.terrainBody, BSParam.TerrainRestitution);
|
||||||
PhysicsScene.PE.SetCollisionFlags(m_mapInfo.terrainBody, CollisionFlags.CF_STATIC_OBJECT);
|
m_physicsScene.PE.SetCollisionFlags(m_mapInfo.terrainBody, CollisionFlags.CF_STATIC_OBJECT);
|
||||||
|
|
||||||
// Return the new terrain to the world of physical objects
|
// Return the new terrain to the world of physical objects
|
||||||
PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_mapInfo.terrainBody);
|
m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_mapInfo.terrainBody);
|
||||||
|
|
||||||
// redo its bounding box now that it is in the world
|
// redo its bounding box now that it is in the world
|
||||||
PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_mapInfo.terrainBody);
|
m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_mapInfo.terrainBody);
|
||||||
|
|
||||||
m_mapInfo.terrainBody.collisionType = CollisionType.Terrain;
|
m_mapInfo.terrainBody.collisionType = CollisionType.Terrain;
|
||||||
m_mapInfo.terrainBody.ApplyCollisionMask(PhysicsScene);
|
m_mapInfo.terrainBody.ApplyCollisionMask(m_physicsScene);
|
||||||
|
|
||||||
// Make it so the terrain will not move or be considered for movement.
|
// Make it so the terrain will not move or be considered for movement.
|
||||||
PhysicsScene.PE.ForceActivationState(m_mapInfo.terrainBody, ActivationState.DISABLE_SIMULATION);
|
m_physicsScene.PE.ForceActivationState(m_mapInfo.terrainBody, ActivationState.DISABLE_SIMULATION);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -134,9 +134,9 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
|
||||||
{
|
{
|
||||||
if (m_mapInfo.terrainBody.HasPhysicalBody)
|
if (m_mapInfo.terrainBody.HasPhysicalBody)
|
||||||
{
|
{
|
||||||
PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_mapInfo.terrainBody);
|
m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_mapInfo.terrainBody);
|
||||||
// Frees both the body and the shape.
|
// Frees both the body and the shape.
|
||||||
PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_mapInfo.terrainBody);
|
m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_mapInfo.terrainBody);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_mapInfo = null;
|
m_mapInfo = null;
|
||||||
|
@ -155,7 +155,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
// Sometimes they give us wonky values of X and Y. Give a warning and return something.
|
// Sometimes they give us wonky values of X and Y. Give a warning and return something.
|
||||||
PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}",
|
m_physicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}",
|
||||||
LogHeader, m_mapInfo.terrainRegionBase, pos);
|
LogHeader, m_mapInfo.terrainRegionBase, pos);
|
||||||
ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
|
ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
|
||||||
}
|
}
|
||||||
|
@ -165,7 +165,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
|
||||||
// The passed position is relative to the base of the region.
|
// The passed position is relative to the base of the region.
|
||||||
public override float GetWaterLevelAtXYZ(Vector3 pos)
|
public override float GetWaterLevelAtXYZ(Vector3 pos)
|
||||||
{
|
{
|
||||||
return PhysicsScene.SimpleWaterLevel;
|
return m_physicsScene.SimpleWaterLevel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,14 +50,14 @@ public abstract class BSTerrainPhys : IDisposable
|
||||||
Mesh = 1
|
Mesh = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
public BSScene PhysicsScene { get; private set; }
|
protected BSScene m_physicsScene { get; private set; }
|
||||||
// Base of the region in world coordinates. Coordinates inside the region are relative to this.
|
// Base of the region in world coordinates. Coordinates inside the region are relative to this.
|
||||||
public Vector3 TerrainBase { get; private set; }
|
public Vector3 TerrainBase { get; private set; }
|
||||||
public uint ID { get; private set; }
|
public uint ID { get; private set; }
|
||||||
|
|
||||||
public BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id)
|
public BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id)
|
||||||
{
|
{
|
||||||
PhysicsScene = physicsScene;
|
m_physicsScene = physicsScene;
|
||||||
TerrainBase = regionBase;
|
TerrainBase = regionBase;
|
||||||
ID = id;
|
ID = id;
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ public sealed class BSTerrainManager : IDisposable
|
||||||
public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
|
public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
|
||||||
|
|
||||||
// The scene that I am part of
|
// The scene that I am part of
|
||||||
private BSScene PhysicsScene { get; set; }
|
private BSScene m_physicsScene { get; set; }
|
||||||
|
|
||||||
// The ground plane created to keep thing from falling to infinity.
|
// The ground plane created to keep thing from falling to infinity.
|
||||||
private BulletBody m_groundPlane;
|
private BulletBody m_groundPlane;
|
||||||
|
@ -113,7 +113,7 @@ public sealed class BSTerrainManager : IDisposable
|
||||||
|
|
||||||
public BSTerrainManager(BSScene physicsScene)
|
public BSTerrainManager(BSScene physicsScene)
|
||||||
{
|
{
|
||||||
PhysicsScene = physicsScene;
|
m_physicsScene = physicsScene;
|
||||||
m_terrains = new Dictionary<Vector3,BSTerrainPhys>();
|
m_terrains = new Dictionary<Vector3,BSTerrainPhys>();
|
||||||
|
|
||||||
// Assume one region of default size
|
// Assume one region of default size
|
||||||
|
@ -132,32 +132,37 @@ public sealed class BSTerrainManager : IDisposable
|
||||||
// safe to call Bullet in real time. We hope no one is moving prims around yet.
|
// safe to call Bullet in real time. We hope no one is moving prims around yet.
|
||||||
public void CreateInitialGroundPlaneAndTerrain()
|
public void CreateInitialGroundPlaneAndTerrain()
|
||||||
{
|
{
|
||||||
|
DetailLog("{0},BSTerrainManager.CreateInitialGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName);
|
||||||
// The ground plane is here to catch things that are trying to drop to negative infinity
|
// The ground plane is here to catch things that are trying to drop to negative infinity
|
||||||
BulletShape groundPlaneShape = PhysicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin);
|
BulletShape groundPlaneShape = m_physicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin);
|
||||||
m_groundPlane = PhysicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape,
|
m_groundPlane = m_physicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape,
|
||||||
BSScene.GROUNDPLANE_ID, Vector3.Zero, Quaternion.Identity);
|
BSScene.GROUNDPLANE_ID, Vector3.Zero, Quaternion.Identity);
|
||||||
|
|
||||||
PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_groundPlane);
|
m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_groundPlane);
|
||||||
PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_groundPlane);
|
m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_groundPlane);
|
||||||
// Ground plane does not move
|
// Ground plane does not move
|
||||||
PhysicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION);
|
m_physicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION);
|
||||||
// Everything collides with the ground plane.
|
// Everything collides with the ground plane.
|
||||||
m_groundPlane.collisionType = CollisionType.Groundplane;
|
m_groundPlane.collisionType = CollisionType.Groundplane;
|
||||||
m_groundPlane.ApplyCollisionMask(PhysicsScene);
|
m_groundPlane.ApplyCollisionMask(m_physicsScene);
|
||||||
|
|
||||||
// Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
|
BSTerrainPhys initialTerrain = new BSTerrainHeightmap(m_physicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize);
|
||||||
BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize);
|
lock (m_terrains)
|
||||||
m_terrains.Add(Vector3.Zero, initialTerrain);
|
{
|
||||||
|
// Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
|
||||||
|
m_terrains.Add(Vector3.Zero, initialTerrain);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release all the terrain structures we might have allocated
|
// Release all the terrain structures we might have allocated
|
||||||
public void ReleaseGroundPlaneAndTerrain()
|
public void ReleaseGroundPlaneAndTerrain()
|
||||||
{
|
{
|
||||||
|
DetailLog("{0},BSTerrainManager.ReleaseGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName);
|
||||||
if (m_groundPlane.HasPhysicalBody)
|
if (m_groundPlane.HasPhysicalBody)
|
||||||
{
|
{
|
||||||
if (PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_groundPlane))
|
if (m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_groundPlane))
|
||||||
{
|
{
|
||||||
PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_groundPlane);
|
m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_groundPlane);
|
||||||
}
|
}
|
||||||
m_groundPlane.Clear();
|
m_groundPlane.Clear();
|
||||||
}
|
}
|
||||||
|
@ -183,7 +188,7 @@ public sealed class BSTerrainManager : IDisposable
|
||||||
float[] localHeightMap = heightMap;
|
float[] localHeightMap = heightMap;
|
||||||
// If there are multiple requests for changes to the same terrain between ticks,
|
// If there are multiple requests for changes to the same terrain between ticks,
|
||||||
// only do that last one.
|
// only do that last one.
|
||||||
PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate()
|
m_physicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate()
|
||||||
{
|
{
|
||||||
if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
|
if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
|
||||||
{
|
{
|
||||||
|
@ -193,11 +198,9 @@ public sealed class BSTerrainManager : IDisposable
|
||||||
// the terrain is added to our parent
|
// the terrain is added to our parent
|
||||||
if (MegaRegionParentPhysicsScene is BSScene)
|
if (MegaRegionParentPhysicsScene is BSScene)
|
||||||
{
|
{
|
||||||
DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}",
|
DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", BSScene.DetailLogZero, m_worldOffset, m_worldMax);
|
||||||
BSScene.DetailLogZero, m_worldOffset, m_worldMax);
|
((BSScene)MegaRegionParentPhysicsScene).TerrainManager.AddMegaRegionChildTerrain(
|
||||||
((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateTerrain(
|
BSScene.CHILDTERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize);
|
||||||
BSScene.CHILDTERRAIN_ID, localHeightMap,
|
|
||||||
m_worldOffset, m_worldOffset + DefaultRegionSize, true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -205,26 +208,36 @@ public sealed class BSTerrainManager : IDisposable
|
||||||
// If not doing the mega-prim thing, just change the terrain
|
// If not doing the mega-prim thing, just change the terrain
|
||||||
DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero);
|
DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero);
|
||||||
|
|
||||||
UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap,
|
UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize);
|
||||||
m_worldOffset, m_worldOffset + DefaultRegionSize, true);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// If called with no mapInfo for the terrain, this will create a new mapInfo and terrain
|
// Another region is calling this region and passing a terrain.
|
||||||
|
// A region that is not the mega-region root will pass its terrain to the root region so the root region
|
||||||
|
// physics engine will have all the terrains.
|
||||||
|
private void AddMegaRegionChildTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
|
||||||
|
{
|
||||||
|
// Since we are called by another region's thread, the action must be rescheduled onto our processing thread.
|
||||||
|
m_physicsScene.PostTaintObject("TerrainManager.AddMegaRegionChild" + minCoords.ToString(), id, delegate()
|
||||||
|
{
|
||||||
|
UpdateTerrain(id, heightMap, minCoords, maxCoords);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// If called for terrain has has not been previously allocated, a new terrain will be built
|
||||||
// based on the passed information. The 'id' should be either the terrain id or
|
// based on the passed information. The 'id' should be either the terrain id or
|
||||||
// BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used.
|
// BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used.
|
||||||
// The latter feature is for creating child terrains for mega-regions.
|
// The latter feature is for creating child terrains for mega-regions.
|
||||||
// If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new
|
// If there is an existing terrain body, a new
|
||||||
// terrain shape is created and added to the body.
|
// terrain shape is created and added to the body.
|
||||||
// This call is most often used to update the heightMap and parameters of the terrain.
|
// This call is most often used to update the heightMap and parameters of the terrain.
|
||||||
// (The above does suggest that some simplification/refactoring is in order.)
|
// (The above does suggest that some simplification/refactoring is in order.)
|
||||||
// Called during taint-time.
|
// Called during taint-time.
|
||||||
private void UpdateTerrain(uint id, float[] heightMap,
|
private void UpdateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
|
||||||
Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
|
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSTerrainManager.UpdateTerrain,call,minC={1},maxC={2},inTaintTime={3}",
|
DetailLog("{0},BSTerrainManager.UpdateTerrain,call,id={1},minC={2},maxC={3}",
|
||||||
BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime);
|
BSScene.DetailLogZero, id, minCoords, maxCoords);
|
||||||
|
|
||||||
// Find high and low points of passed heightmap.
|
// Find high and low points of passed heightmap.
|
||||||
// The min and max passed in is usually the area objects can be in (maximum
|
// The min and max passed in is usually the area objects can be in (maximum
|
||||||
|
@ -253,7 +266,7 @@ public sealed class BSTerrainManager : IDisposable
|
||||||
if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
|
if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
|
||||||
{
|
{
|
||||||
// There is already a terrain in this spot. Free the old and build the new.
|
// There is already a terrain in this spot. Free the old and build the new.
|
||||||
DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}",
|
DetailLog("{0},BSTErrainManager.UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}",
|
||||||
BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
|
BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
|
||||||
|
|
||||||
// Remove old terrain from the collection
|
// Remove old terrain from the collection
|
||||||
|
@ -263,6 +276,7 @@ public sealed class BSTerrainManager : IDisposable
|
||||||
|
|
||||||
if (MegaRegionParentPhysicsScene == null)
|
if (MegaRegionParentPhysicsScene == null)
|
||||||
{
|
{
|
||||||
|
// This terrain is not part of the mega-region scheme. Create vanilla terrain.
|
||||||
BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
|
BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
|
||||||
m_terrains.Add(terrainRegionBase, newTerrainPhys);
|
m_terrains.Add(terrainRegionBase, newTerrainPhys);
|
||||||
|
|
||||||
|
@ -291,8 +305,8 @@ public sealed class BSTerrainManager : IDisposable
|
||||||
if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
|
if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
|
||||||
newTerrainID = ++m_terrainCount;
|
newTerrainID = ++m_terrainCount;
|
||||||
|
|
||||||
DetailLog("{0},UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}",
|
DetailLog("{0},BSTerrainManager.UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}",
|
||||||
BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
|
BSScene.DetailLogZero, newTerrainID, minCoords, maxCoords);
|
||||||
BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
|
BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
|
||||||
m_terrains.Add(terrainRegionBase, newTerrainPhys);
|
m_terrains.Add(terrainRegionBase, newTerrainPhys);
|
||||||
|
|
||||||
|
@ -304,26 +318,26 @@ public sealed class BSTerrainManager : IDisposable
|
||||||
// TODO: redo terrain implementation selection to allow other base types than heightMap.
|
// TODO: redo terrain implementation selection to allow other base types than heightMap.
|
||||||
private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
|
private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
|
||||||
{
|
{
|
||||||
PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}",
|
m_physicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}",
|
||||||
LogHeader, PhysicsScene.RegionName, terrainRegionBase,
|
LogHeader, m_physicsScene.RegionName, terrainRegionBase,
|
||||||
(BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation);
|
(BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation);
|
||||||
BSTerrainPhys newTerrainPhys = null;
|
BSTerrainPhys newTerrainPhys = null;
|
||||||
switch ((int)BSParam.TerrainImplementation)
|
switch ((int)BSParam.TerrainImplementation)
|
||||||
{
|
{
|
||||||
case (int)BSTerrainPhys.TerrainImplementation.Heightmap:
|
case (int)BSTerrainPhys.TerrainImplementation.Heightmap:
|
||||||
newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id,
|
newTerrainPhys = new BSTerrainHeightmap(m_physicsScene, terrainRegionBase, id,
|
||||||
heightMap, minCoords, maxCoords);
|
heightMap, minCoords, maxCoords);
|
||||||
break;
|
break;
|
||||||
case (int)BSTerrainPhys.TerrainImplementation.Mesh:
|
case (int)BSTerrainPhys.TerrainImplementation.Mesh:
|
||||||
newTerrainPhys = new BSTerrainMesh(PhysicsScene, terrainRegionBase, id,
|
newTerrainPhys = new BSTerrainMesh(m_physicsScene, terrainRegionBase, id,
|
||||||
heightMap, minCoords, maxCoords);
|
heightMap, minCoords, maxCoords);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}",
|
m_physicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}",
|
||||||
LogHeader,
|
LogHeader,
|
||||||
(int)BSParam.TerrainImplementation,
|
(int)BSParam.TerrainImplementation,
|
||||||
BSParam.TerrainImplementation,
|
BSParam.TerrainImplementation,
|
||||||
PhysicsScene.RegionName, terrainRegionBase);
|
m_physicsScene.RegionName, terrainRegionBase);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return newTerrainPhys;
|
return newTerrainPhys;
|
||||||
|
@ -337,6 +351,53 @@ public sealed class BSTerrainManager : IDisposable
|
||||||
return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ);
|
return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return a new position that is over known terrain if the position is outside our terrain.
|
||||||
|
public Vector3 ClampPositionIntoKnownTerrain(Vector3 pPos)
|
||||||
|
{
|
||||||
|
Vector3 ret = pPos;
|
||||||
|
|
||||||
|
// First, base addresses are never negative so correct for that possible problem.
|
||||||
|
if (ret.X < 0f || ret.Y < 0f)
|
||||||
|
{
|
||||||
|
ret.X = Util.Clamp<float>(ret.X, 0f, 1000000f);
|
||||||
|
ret.Y = Util.Clamp<float>(ret.Y, 0f, 1000000f);
|
||||||
|
DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,zeroingNegXorY,oldPos={1},newPos={2}",
|
||||||
|
BSScene.DetailLogZero, pPos, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can't do this function if we don't know about any terrain.
|
||||||
|
if (m_terrains.Count == 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
int loopPrevention = 10;
|
||||||
|
Vector3 terrainBaseXYZ;
|
||||||
|
BSTerrainPhys physTerrain;
|
||||||
|
while (!GetTerrainPhysicalAtXYZ(ret, out physTerrain, out terrainBaseXYZ))
|
||||||
|
{
|
||||||
|
// The passed position is not within a known terrain area.
|
||||||
|
// NOTE that GetTerrainPhysicalAtXYZ will set 'terrainBaseXYZ' to the base of the unfound region.
|
||||||
|
|
||||||
|
// Must be off the top of a region. Find an adjacent region to move into.
|
||||||
|
Vector3 adjacentTerrainBase = FindAdjacentTerrainBase(terrainBaseXYZ);
|
||||||
|
|
||||||
|
ret.X = Math.Min(ret.X, adjacentTerrainBase.X + (ret.X % DefaultRegionSize.X));
|
||||||
|
ret.Y = Math.Min(ret.Y, adjacentTerrainBase.Y + (ret.X % DefaultRegionSize.Y));
|
||||||
|
DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,findingAdjacentRegion,adjacentRegBase={1},oldPos={2},newPos={3}",
|
||||||
|
BSScene.DetailLogZero, adjacentTerrainBase, pPos, ret);
|
||||||
|
|
||||||
|
if (loopPrevention-- < 0f)
|
||||||
|
{
|
||||||
|
// The 'while' is a little dangerous so this prevents looping forever if the
|
||||||
|
// mapping of the terrains ever gets messed up (like nothing at <0,0>) or
|
||||||
|
// the list of terrains is in transition.
|
||||||
|
DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,suppressingFindAdjacentRegionLoop", BSScene.DetailLogZero);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
// Given an X and Y, find the height of the terrain.
|
// Given an X and Y, find the height of the terrain.
|
||||||
// Since we could be handling multiple terrains for a mega-region,
|
// Since we could be handling multiple terrains for a mega-region,
|
||||||
// the base of the region is calcuated assuming all regions are
|
// the base of the region is calcuated assuming all regions are
|
||||||
|
@ -368,8 +429,8 @@ public sealed class BSTerrainManager : IDisposable
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
|
m_physicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
|
||||||
LogHeader, PhysicsScene.RegionName, tX, tY);
|
LogHeader, m_physicsScene.RegionName, tX, tY);
|
||||||
DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}",
|
DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}",
|
||||||
BSScene.DetailLogZero, pos, terrainBaseXYZ);
|
BSScene.DetailLogZero, pos, terrainBaseXYZ);
|
||||||
}
|
}
|
||||||
|
@ -390,8 +451,8 @@ public sealed class BSTerrainManager : IDisposable
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PhysicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}",
|
m_physicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}",
|
||||||
LogHeader, PhysicsScene.RegionName, pos, terrainBaseXYZ, ret);
|
LogHeader, m_physicsScene.RegionName, pos, terrainBaseXYZ, ret);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -400,18 +461,69 @@ public sealed class BSTerrainManager : IDisposable
|
||||||
// the descriptor class and the 'base' fo the addresses therein.
|
// the descriptor class and the 'base' fo the addresses therein.
|
||||||
private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase)
|
private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase)
|
||||||
{
|
{
|
||||||
int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
|
bool ret = false;
|
||||||
int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
|
|
||||||
Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
|
Vector3 terrainBaseXYZ = Vector3.Zero;
|
||||||
|
if (pos.X < 0f || pos.Y < 0f)
|
||||||
|
{
|
||||||
|
// We don't handle negative addresses so just make up a base that will not be found.
|
||||||
|
terrainBaseXYZ = new Vector3(-DefaultRegionSize.X, -DefaultRegionSize.Y, 0f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
|
||||||
|
int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
|
||||||
|
terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
|
||||||
|
}
|
||||||
|
|
||||||
BSTerrainPhys physTerrain = null;
|
BSTerrainPhys physTerrain = null;
|
||||||
lock (m_terrains)
|
lock (m_terrains)
|
||||||
{
|
{
|
||||||
m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain);
|
ret = m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain);
|
||||||
}
|
}
|
||||||
outTerrainBase = terrainBaseXYZ;
|
outTerrainBase = terrainBaseXYZ;
|
||||||
outPhysTerrain = physTerrain;
|
outPhysTerrain = physTerrain;
|
||||||
return (physTerrain != null);
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given a terrain base, return a terrain base for a terrain that is closer to <0,0> than
|
||||||
|
// this one. Usually used to return an out of bounds object to a known place.
|
||||||
|
private Vector3 FindAdjacentTerrainBase(Vector3 pTerrainBase)
|
||||||
|
{
|
||||||
|
Vector3 ret = pTerrainBase;
|
||||||
|
|
||||||
|
// Can't do this function if we don't know about any terrain.
|
||||||
|
if (m_terrains.Count == 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
// Just some sanity
|
||||||
|
ret.X = Util.Clamp<float>(ret.X, 0f, 1000000f);
|
||||||
|
ret.Y = Util.Clamp<float>(ret.Y, 0f, 1000000f);
|
||||||
|
ret.Z = 0f;
|
||||||
|
|
||||||
|
lock (m_terrains)
|
||||||
|
{
|
||||||
|
// Once down to the <0,0> region, we have to be done.
|
||||||
|
while (ret.X > 0f || ret.Y > 0f)
|
||||||
|
{
|
||||||
|
if (ret.X > 0f)
|
||||||
|
{
|
||||||
|
ret.X = Math.Max(0f, ret.X - DefaultRegionSize.X);
|
||||||
|
DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingX,terrainBase={1}", BSScene.DetailLogZero, ret);
|
||||||
|
if (m_terrains.ContainsKey(ret))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ret.Y > 0f)
|
||||||
|
{
|
||||||
|
ret.Y = Math.Max(0f, ret.Y - DefaultRegionSize.Y);
|
||||||
|
DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingY,terrainBase={1}", BSScene.DetailLogZero, ret);
|
||||||
|
if (m_terrains.ContainsKey(ret))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Although no one seems to check this, I do support combining.
|
// Although no one seems to check this, I do support combining.
|
||||||
|
@ -452,7 +564,7 @@ public sealed class BSTerrainManager : IDisposable
|
||||||
|
|
||||||
private void DetailLog(string msg, params Object[] args)
|
private void DetailLog(string msg, params Object[] args)
|
||||||
{
|
{
|
||||||
PhysicsScene.PhysicsLogging.Write(msg, args);
|
m_physicsScene.PhysicsLogging.Write(msg, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
|
||||||
BulletShape m_terrainShape;
|
BulletShape m_terrainShape;
|
||||||
BulletBody m_terrainBody;
|
BulletBody m_terrainBody;
|
||||||
|
|
||||||
public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize)
|
public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize)
|
||||||
: base(physicsScene, regionBase, id)
|
: base(physicsScene, regionBase, id)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create terrain mesh from a heightmap.
|
// Create terrain mesh from a heightmap.
|
||||||
public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap,
|
public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap,
|
||||||
Vector3 minCoords, Vector3 maxCoords)
|
Vector3 minCoords, Vector3 maxCoords)
|
||||||
: base(physicsScene, regionBase, id)
|
: base(physicsScene, regionBase, id)
|
||||||
{
|
{
|
||||||
|
@ -76,27 +76,43 @@ public sealed class BSTerrainMesh : BSTerrainPhys
|
||||||
m_sizeX = (int)(maxCoords.X - minCoords.X);
|
m_sizeX = (int)(maxCoords.X - minCoords.X);
|
||||||
m_sizeY = (int)(maxCoords.Y - minCoords.Y);
|
m_sizeY = (int)(maxCoords.Y - minCoords.Y);
|
||||||
|
|
||||||
if (!BSTerrainMesh.ConvertHeightmapToMesh(PhysicsScene, initialMap,
|
bool meshCreationSuccess = false;
|
||||||
m_sizeX, m_sizeY,
|
if (BSParam.TerrainMeshMagnification == 1)
|
||||||
(float)m_sizeX, (float)m_sizeY,
|
{
|
||||||
Vector3.Zero, 1.0f,
|
// If a magnification of one, use the old routine that is tried and true.
|
||||||
out indicesCount, out indices, out verticesCount, out vertices))
|
meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh(m_physicsScene,
|
||||||
|
initialMap, m_sizeX, m_sizeY, // input size
|
||||||
|
Vector3.Zero, // base for mesh
|
||||||
|
out indicesCount, out indices, out verticesCount, out vertices);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Other magnifications use the newer routine
|
||||||
|
meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh2(m_physicsScene,
|
||||||
|
initialMap, m_sizeX, m_sizeY, // input size
|
||||||
|
BSParam.TerrainMeshMagnification,
|
||||||
|
physicsScene.TerrainManager.DefaultRegionSize,
|
||||||
|
Vector3.Zero, // base for mesh
|
||||||
|
out indicesCount, out indices, out verticesCount, out vertices);
|
||||||
|
}
|
||||||
|
if (!meshCreationSuccess)
|
||||||
{
|
{
|
||||||
// DISASTER!!
|
// DISASTER!!
|
||||||
PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap", ID);
|
m_physicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap,id={1}", BSScene.DetailLogZero, ID);
|
||||||
PhysicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase);
|
m_physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase);
|
||||||
// Something is very messed up and a crash is in our future.
|
// Something is very messed up and a crash is in our future.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,indices={1},indSz={2},vertices={3},vertSz={4}",
|
|
||||||
ID, indicesCount, indices.Length, verticesCount, vertices.Length);
|
|
||||||
|
|
||||||
m_terrainShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World, indicesCount, indices, verticesCount, vertices);
|
m_physicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,id={1},indices={2},indSz={3},vertices={4},vertSz={5}",
|
||||||
|
BSScene.DetailLogZero, ID, indicesCount, indices.Length, verticesCount, vertices.Length);
|
||||||
|
|
||||||
|
m_terrainShape = m_physicsScene.PE.CreateMeshShape(m_physicsScene.World, indicesCount, indices, verticesCount, vertices);
|
||||||
if (!m_terrainShape.HasPhysicalShape)
|
if (!m_terrainShape.HasPhysicalShape)
|
||||||
{
|
{
|
||||||
// DISASTER!!
|
// DISASTER!!
|
||||||
PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID);
|
m_physicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape,id={1}", BSScene.DetailLogZero, ID);
|
||||||
physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase);
|
m_physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase);
|
||||||
// Something is very messed up and a crash is in our future.
|
// Something is very messed up and a crash is in our future.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -104,44 +120,54 @@ public sealed class BSTerrainMesh : BSTerrainPhys
|
||||||
Vector3 pos = regionBase;
|
Vector3 pos = regionBase;
|
||||||
Quaternion rot = Quaternion.Identity;
|
Quaternion rot = Quaternion.Identity;
|
||||||
|
|
||||||
m_terrainBody = PhysicsScene.PE.CreateBodyWithDefaultMotionState(m_terrainShape, ID, pos, rot);
|
m_terrainBody = m_physicsScene.PE.CreateBodyWithDefaultMotionState(m_terrainShape, ID, pos, rot);
|
||||||
if (!m_terrainBody.HasPhysicalBody)
|
if (!m_terrainBody.HasPhysicalBody)
|
||||||
{
|
{
|
||||||
// DISASTER!!
|
// DISASTER!!
|
||||||
physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase);
|
m_physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase);
|
||||||
// Something is very messed up and a crash is in our future.
|
// Something is very messed up and a crash is in our future.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
physicsScene.PE.SetShapeCollisionMargin(m_terrainShape, BSParam.TerrainCollisionMargin);
|
||||||
|
|
||||||
// Set current terrain attributes
|
// Set current terrain attributes
|
||||||
PhysicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction);
|
m_physicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction);
|
||||||
PhysicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction);
|
m_physicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction);
|
||||||
PhysicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution);
|
m_physicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution);
|
||||||
PhysicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT);
|
m_physicsScene.PE.SetContactProcessingThreshold(m_terrainBody, BSParam.TerrainContactProcessingThreshold);
|
||||||
|
m_physicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT);
|
||||||
|
|
||||||
// Static objects are not very massive.
|
// Static objects are not very massive.
|
||||||
PhysicsScene.PE.SetMassProps(m_terrainBody, 0f, Vector3.Zero);
|
m_physicsScene.PE.SetMassProps(m_terrainBody, 0f, Vector3.Zero);
|
||||||
|
|
||||||
// Put the new terrain to the world of physical objects
|
// Put the new terrain to the world of physical objects
|
||||||
PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_terrainBody);
|
m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_terrainBody);
|
||||||
|
|
||||||
// Redo its bounding box now that it is in the world
|
// Redo its bounding box now that it is in the world
|
||||||
PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_terrainBody);
|
m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_terrainBody);
|
||||||
|
|
||||||
m_terrainBody.collisionType = CollisionType.Terrain;
|
m_terrainBody.collisionType = CollisionType.Terrain;
|
||||||
m_terrainBody.ApplyCollisionMask(PhysicsScene);
|
m_terrainBody.ApplyCollisionMask(m_physicsScene);
|
||||||
|
|
||||||
|
if (BSParam.UseSingleSidedMeshes)
|
||||||
|
{
|
||||||
|
m_physicsScene.DetailLog("{0},BSTerrainMesh.settingCustomMaterial,id={1}", BSScene.DetailLogZero, id);
|
||||||
|
m_physicsScene.PE.AddToCollisionFlags(m_terrainBody, CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK);
|
||||||
|
}
|
||||||
|
|
||||||
// Make it so the terrain will not move or be considered for movement.
|
// Make it so the terrain will not move or be considered for movement.
|
||||||
PhysicsScene.PE.ForceActivationState(m_terrainBody, ActivationState.DISABLE_SIMULATION);
|
m_physicsScene.PE.ForceActivationState(m_terrainBody, ActivationState.DISABLE_SIMULATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Dispose()
|
public override void Dispose()
|
||||||
{
|
{
|
||||||
if (m_terrainBody.HasPhysicalBody)
|
if (m_terrainBody.HasPhysicalBody)
|
||||||
{
|
{
|
||||||
PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_terrainBody);
|
m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_terrainBody);
|
||||||
// Frees both the body and the shape.
|
// Frees both the body and the shape.
|
||||||
PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_terrainBody);
|
m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_terrainBody);
|
||||||
|
m_terrainBody.Clear();
|
||||||
|
m_terrainShape.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,7 +185,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
// Sometimes they give us wonky values of X and Y. Give a warning and return something.
|
// Sometimes they give us wonky values of X and Y. Give a warning and return something.
|
||||||
PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}",
|
m_physicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}",
|
||||||
LogHeader, TerrainBase, pos);
|
LogHeader, TerrainBase, pos);
|
||||||
ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
|
ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
|
||||||
}
|
}
|
||||||
|
@ -169,17 +195,14 @@ public sealed class BSTerrainMesh : BSTerrainPhys
|
||||||
// The passed position is relative to the base of the region.
|
// The passed position is relative to the base of the region.
|
||||||
public override float GetWaterLevelAtXYZ(Vector3 pos)
|
public override float GetWaterLevelAtXYZ(Vector3 pos)
|
||||||
{
|
{
|
||||||
return PhysicsScene.SimpleWaterLevel;
|
return m_physicsScene.SimpleWaterLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
|
// Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
|
||||||
// Return 'true' if successfully created.
|
// Return 'true' if successfully created.
|
||||||
public static bool ConvertHeightmapToMesh(
|
public static bool ConvertHeightmapToMesh( BSScene physicsScene,
|
||||||
BSScene physicsScene,
|
|
||||||
float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap
|
float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap
|
||||||
float extentX, float extentY, // zero based range for output vertices
|
|
||||||
Vector3 extentBase, // base to be added to all vertices
|
Vector3 extentBase, // base to be added to all vertices
|
||||||
float magnification, // number of vertices to create between heightMap coords
|
|
||||||
out int indicesCountO, out int[] indicesO,
|
out int indicesCountO, out int[] indicesO,
|
||||||
out int verticesCountO, out float[] verticesO)
|
out int verticesCountO, out float[] verticesO)
|
||||||
{
|
{
|
||||||
|
@ -200,16 +223,15 @@ public sealed class BSTerrainMesh : BSTerrainPhys
|
||||||
// of the heightmap.
|
// of the heightmap.
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// One vertice per heightmap value plus the vertices off the top and bottom edge.
|
// One vertice per heightmap value plus the vertices off the side and bottom edge.
|
||||||
int totalVertices = (sizeX + 1) * (sizeY + 1);
|
int totalVertices = (sizeX + 1) * (sizeY + 1);
|
||||||
vertices = new float[totalVertices * 3];
|
vertices = new float[totalVertices * 3];
|
||||||
int totalIndices = sizeX * sizeY * 6;
|
int totalIndices = sizeX * sizeY * 6;
|
||||||
indices = new int[totalIndices];
|
indices = new int[totalIndices];
|
||||||
|
|
||||||
float magX = (float)sizeX / extentX;
|
if (physicsScene != null)
|
||||||
float magY = (float)sizeY / extentY;
|
physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3}",
|
||||||
physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}",
|
BSScene.DetailLogZero, totalVertices, totalIndices, extentBase);
|
||||||
BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY);
|
|
||||||
float minHeight = float.MaxValue;
|
float minHeight = float.MaxValue;
|
||||||
// Note that sizeX+1 vertices are created since there is land between this and the next region.
|
// Note that sizeX+1 vertices are created since there is land between this and the next region.
|
||||||
for (int yy = 0; yy <= sizeY; yy++)
|
for (int yy = 0; yy <= sizeY; yy++)
|
||||||
|
@ -222,8 +244,8 @@ public sealed class BSTerrainMesh : BSTerrainPhys
|
||||||
if (xx == sizeX) offset -= 1;
|
if (xx == sizeX) offset -= 1;
|
||||||
float height = heightMap[offset];
|
float height = heightMap[offset];
|
||||||
minHeight = Math.Min(minHeight, height);
|
minHeight = Math.Min(minHeight, height);
|
||||||
vertices[verticesCount + 0] = (float)xx * magX + extentBase.X;
|
vertices[verticesCount + 0] = (float)xx + extentBase.X;
|
||||||
vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y;
|
vertices[verticesCount + 1] = (float)yy + extentBase.Y;
|
||||||
vertices[verticesCount + 2] = height + extentBase.Z;
|
vertices[verticesCount + 2] = height + extentBase.Z;
|
||||||
verticesCount += 3;
|
verticesCount += 3;
|
||||||
}
|
}
|
||||||
|
@ -250,7 +272,161 @@ public sealed class BSTerrainMesh : BSTerrainPhys
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}",
|
if (physicsScene != null)
|
||||||
|
physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}",
|
||||||
|
LogHeader, physicsScene.RegionName, extentBase, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
indicesCountO = indicesCount;
|
||||||
|
indicesO = indices;
|
||||||
|
verticesCountO = verticesCount;
|
||||||
|
verticesO = vertices;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class HeightMapGetter
|
||||||
|
{
|
||||||
|
private float[] m_heightMap;
|
||||||
|
private int m_sizeX;
|
||||||
|
private int m_sizeY;
|
||||||
|
public HeightMapGetter(float[] pHeightMap, int pSizeX, int pSizeY)
|
||||||
|
{
|
||||||
|
m_heightMap = pHeightMap;
|
||||||
|
m_sizeX = pSizeX;
|
||||||
|
m_sizeY = pSizeY;
|
||||||
|
}
|
||||||
|
// The heightmap is extended as an infinite plane at the last height
|
||||||
|
public float GetHeight(int xx, int yy)
|
||||||
|
{
|
||||||
|
int offset = 0;
|
||||||
|
// Extend the height with the height from the last row or column
|
||||||
|
if (yy >= m_sizeY)
|
||||||
|
if (xx >= m_sizeX)
|
||||||
|
offset = (m_sizeY - 1) * m_sizeX + (m_sizeX - 1);
|
||||||
|
else
|
||||||
|
offset = (m_sizeY - 1) * m_sizeX + xx;
|
||||||
|
else
|
||||||
|
if (xx >= m_sizeX)
|
||||||
|
offset = yy * m_sizeX + (m_sizeX - 1);
|
||||||
|
else
|
||||||
|
offset = yy * m_sizeX + xx;
|
||||||
|
|
||||||
|
return m_heightMap[offset];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
|
||||||
|
// Version that handles magnification.
|
||||||
|
// Return 'true' if successfully created.
|
||||||
|
public static bool ConvertHeightmapToMesh2( BSScene physicsScene,
|
||||||
|
float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap
|
||||||
|
int magnification, // number of vertices per heighmap step
|
||||||
|
Vector3 extent, // dimensions of the output mesh
|
||||||
|
Vector3 extentBase, // base to be added to all vertices
|
||||||
|
out int indicesCountO, out int[] indicesO,
|
||||||
|
out int verticesCountO, out float[] verticesO)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
int indicesCount = 0;
|
||||||
|
int verticesCount = 0;
|
||||||
|
int[] indices = new int[0];
|
||||||
|
float[] vertices = new float[0];
|
||||||
|
|
||||||
|
HeightMapGetter hmap = new HeightMapGetter(heightMap, sizeX, sizeY);
|
||||||
|
|
||||||
|
// The vertices dimension of the output mesh
|
||||||
|
int meshX = sizeX * magnification;
|
||||||
|
int meshY = sizeY * magnification;
|
||||||
|
// The output size of one mesh step
|
||||||
|
float meshXStep = extent.X / meshX;
|
||||||
|
float meshYStep = extent.Y / meshY;
|
||||||
|
|
||||||
|
// Create an array of vertices that is meshX+1 by meshY+1 (note the loop
|
||||||
|
// from zero to <= meshX). The triangle indices are then generated as two triangles
|
||||||
|
// per heightmap point. There are meshX by meshY of these squares. The extra row and
|
||||||
|
// column of vertices are used to complete the triangles of the last row and column
|
||||||
|
// of the heightmap.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Vertices for the output heightmap plus one on the side and bottom to complete triangles
|
||||||
|
int totalVertices = (meshX + 1) * (meshY + 1);
|
||||||
|
vertices = new float[totalVertices * 3];
|
||||||
|
int totalIndices = meshX * meshY * 6;
|
||||||
|
indices = new int[totalIndices];
|
||||||
|
|
||||||
|
if (physicsScene != null)
|
||||||
|
physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,inSize={1},outSize={2},totVert={3},totInd={4},extentBase={5}",
|
||||||
|
BSScene.DetailLogZero, new Vector2(sizeX, sizeY), new Vector2(meshX, meshY),
|
||||||
|
totalVertices, totalIndices, extentBase);
|
||||||
|
|
||||||
|
float minHeight = float.MaxValue;
|
||||||
|
// Note that sizeX+1 vertices are created since there is land between this and the next region.
|
||||||
|
// Loop through the output vertices and compute the mediun height in between the input vertices
|
||||||
|
for (int yy = 0; yy <= meshY; yy++)
|
||||||
|
{
|
||||||
|
for (int xx = 0; xx <= meshX; xx++) // Hint: the "<=" means we go around sizeX + 1 times
|
||||||
|
{
|
||||||
|
float offsetY = (float)yy * (float)sizeY / (float)meshY; // The Y that is closest to the mesh point
|
||||||
|
int stepY = (int)offsetY;
|
||||||
|
float fractionalY = offsetY - (float)stepY;
|
||||||
|
float offsetX = (float)xx * (float)sizeX / (float)meshX; // The X that is closest to the mesh point
|
||||||
|
int stepX = (int)offsetX;
|
||||||
|
float fractionalX = offsetX - (float)stepX;
|
||||||
|
|
||||||
|
// physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,xx={1},yy={2},offX={3},stepX={4},fractX={5},offY={6},stepY={7},fractY={8}",
|
||||||
|
// BSScene.DetailLogZero, xx, yy, offsetX, stepX, fractionalX, offsetY, stepY, fractionalY);
|
||||||
|
|
||||||
|
// get the four corners of the heightmap square the mesh point is in
|
||||||
|
float heightUL = hmap.GetHeight(stepX , stepY );
|
||||||
|
float heightUR = hmap.GetHeight(stepX + 1, stepY );
|
||||||
|
float heightLL = hmap.GetHeight(stepX , stepY + 1);
|
||||||
|
float heightLR = hmap.GetHeight(stepX + 1, stepY + 1);
|
||||||
|
|
||||||
|
// bilinear interplolation
|
||||||
|
float height = heightUL * (1 - fractionalX) * (1 - fractionalY)
|
||||||
|
+ heightUR * fractionalX * (1 - fractionalY)
|
||||||
|
+ heightLL * (1 - fractionalX) * fractionalY
|
||||||
|
+ heightLR * fractionalX * fractionalY;
|
||||||
|
|
||||||
|
// physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,heightUL={1},heightUR={2},heightLL={3},heightLR={4},heightMap={5}",
|
||||||
|
// BSScene.DetailLogZero, heightUL, heightUR, heightLL, heightLR, height);
|
||||||
|
|
||||||
|
minHeight = Math.Min(minHeight, height);
|
||||||
|
|
||||||
|
vertices[verticesCount + 0] = (float)xx * meshXStep + extentBase.X;
|
||||||
|
vertices[verticesCount + 1] = (float)yy * meshYStep + extentBase.Y;
|
||||||
|
vertices[verticesCount + 2] = height + extentBase.Z;
|
||||||
|
verticesCount += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// The number of vertices generated
|
||||||
|
verticesCount /= 3;
|
||||||
|
|
||||||
|
// Loop through all the heightmap squares and create indices for the two triangles for that square
|
||||||
|
for (int yy = 0; yy < meshY; yy++)
|
||||||
|
{
|
||||||
|
for (int xx = 0; xx < meshX; xx++)
|
||||||
|
{
|
||||||
|
int offset = yy * (meshX + 1) + xx;
|
||||||
|
// Each vertices is presumed to be the upper left corner of a box of two triangles
|
||||||
|
indices[indicesCount + 0] = offset;
|
||||||
|
indices[indicesCount + 1] = offset + 1;
|
||||||
|
indices[indicesCount + 2] = offset + meshX + 1; // accounting for the extra column
|
||||||
|
indices[indicesCount + 3] = offset + 1;
|
||||||
|
indices[indicesCount + 4] = offset + meshX + 2;
|
||||||
|
indices[indicesCount + 5] = offset + meshX + 1;
|
||||||
|
indicesCount += 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
if (physicsScene != null)
|
||||||
|
physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}",
|
||||||
LogHeader, physicsScene.RegionName, extentBase, e);
|
LogHeader, physicsScene.RegionName, extentBase, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -104,18 +104,20 @@ public class BulletShape
|
||||||
{
|
{
|
||||||
public BulletShape()
|
public BulletShape()
|
||||||
{
|
{
|
||||||
type = BSPhysicsShapeType.SHAPE_UNKNOWN;
|
shapeType = BSPhysicsShapeType.SHAPE_UNKNOWN;
|
||||||
shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE;
|
shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE;
|
||||||
isNativeShape = false;
|
isNativeShape = false;
|
||||||
}
|
}
|
||||||
public BSPhysicsShapeType type;
|
public BSPhysicsShapeType shapeType;
|
||||||
public System.UInt64 shapeKey;
|
public System.UInt64 shapeKey;
|
||||||
public bool isNativeShape;
|
public bool isNativeShape;
|
||||||
|
|
||||||
public virtual void Clear() { }
|
public virtual void Clear() { }
|
||||||
public virtual bool HasPhysicalShape { get { return false; } }
|
public virtual bool HasPhysicalShape { get { return false; } }
|
||||||
|
|
||||||
// Make another reference to this physical object.
|
// Make another reference to this physical object.
|
||||||
public virtual BulletShape Clone() { return new BulletShape(); }
|
public virtual BulletShape Clone() { return new BulletShape(); }
|
||||||
|
|
||||||
// Return 'true' if this and other refer to the same physical object
|
// Return 'true' if this and other refer to the same physical object
|
||||||
public virtual bool ReferenceSame(BulletShape xx) { return false; }
|
public virtual bool ReferenceSame(BulletShape xx) { return false; }
|
||||||
|
|
||||||
|
@ -131,7 +133,7 @@ public class BulletShape
|
||||||
buff.Append("<p=");
|
buff.Append("<p=");
|
||||||
buff.Append(AddrString);
|
buff.Append(AddrString);
|
||||||
buff.Append(",s=");
|
buff.Append(",s=");
|
||||||
buff.Append(type.ToString());
|
buff.Append(shapeType.ToString());
|
||||||
buff.Append(",k=");
|
buff.Append(",k=");
|
||||||
buff.Append(shapeKey.ToString("X"));
|
buff.Append(shapeKey.ToString("X"));
|
||||||
buff.Append(",n=");
|
buff.Append(",n=");
|
||||||
|
@ -215,45 +217,49 @@ public static class BulletSimData
|
||||||
{
|
{
|
||||||
|
|
||||||
// Map of collisionTypes to flags for collision groups and masks.
|
// Map of collisionTypes to flags for collision groups and masks.
|
||||||
|
// An object's 'group' is the collison groups this object belongs to
|
||||||
|
// An object's 'filter' is the groups another object has to belong to in order to collide with me
|
||||||
|
// A collision happens if ((obj1.group & obj2.filter) != 0) || ((obj2.group & obj1.filter) != 0)
|
||||||
|
//
|
||||||
// As mentioned above, don't use the CollisionFilterGroups definitions directly in the code
|
// As mentioned above, don't use the CollisionFilterGroups definitions directly in the code
|
||||||
// but, instead, use references to this dictionary. Finding and debugging
|
// but, instead, use references to this dictionary. Finding and debugging
|
||||||
// collision flag problems will be made easier.
|
// collision flag problems will be made easier.
|
||||||
public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks
|
public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks
|
||||||
= new Dictionary<CollisionType, CollisionTypeFilterGroup>()
|
= new Dictionary<CollisionType, CollisionTypeFilterGroup>()
|
||||||
{
|
{
|
||||||
{ CollisionType.Avatar,
|
{ CollisionType.Avatar,
|
||||||
new CollisionTypeFilterGroup(CollisionType.Avatar,
|
new CollisionTypeFilterGroup(CollisionType.Avatar,
|
||||||
(uint)CollisionFilterGroups.BCharacterGroup,
|
(uint)CollisionFilterGroups.BCharacterGroup,
|
||||||
(uint)CollisionFilterGroups.BAllGroup)
|
(uint)CollisionFilterGroups.BAllGroup)
|
||||||
},
|
},
|
||||||
{ CollisionType.Groundplane,
|
{ CollisionType.Groundplane,
|
||||||
new CollisionTypeFilterGroup(CollisionType.Groundplane,
|
new CollisionTypeFilterGroup(CollisionType.Groundplane,
|
||||||
(uint)CollisionFilterGroups.BGroundPlaneGroup,
|
(uint)CollisionFilterGroups.BGroundPlaneGroup,
|
||||||
(uint)CollisionFilterGroups.BAllGroup)
|
(uint)CollisionFilterGroups.BAllGroup)
|
||||||
},
|
},
|
||||||
{ CollisionType.Terrain,
|
{ CollisionType.Terrain,
|
||||||
new CollisionTypeFilterGroup(CollisionType.Terrain,
|
new CollisionTypeFilterGroup(CollisionType.Terrain,
|
||||||
(uint)CollisionFilterGroups.BTerrainGroup,
|
(uint)CollisionFilterGroups.BTerrainGroup,
|
||||||
(uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup))
|
(uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup))
|
||||||
},
|
},
|
||||||
{ CollisionType.Static,
|
{ CollisionType.Static,
|
||||||
new CollisionTypeFilterGroup(CollisionType.Static,
|
new CollisionTypeFilterGroup(CollisionType.Static,
|
||||||
(uint)CollisionFilterGroups.BStaticGroup,
|
(uint)CollisionFilterGroups.BStaticGroup,
|
||||||
(uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
|
(uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
|
||||||
},
|
},
|
||||||
{ CollisionType.Dynamic,
|
{ CollisionType.Dynamic,
|
||||||
new CollisionTypeFilterGroup(CollisionType.Dynamic,
|
new CollisionTypeFilterGroup(CollisionType.Dynamic,
|
||||||
(uint)CollisionFilterGroups.BSolidGroup,
|
(uint)CollisionFilterGroups.BSolidGroup,
|
||||||
(uint)(CollisionFilterGroups.BAllGroup))
|
(uint)(CollisionFilterGroups.BAllGroup))
|
||||||
},
|
},
|
||||||
{ CollisionType.VolumeDetect,
|
{ CollisionType.VolumeDetect,
|
||||||
new CollisionTypeFilterGroup(CollisionType.VolumeDetect,
|
new CollisionTypeFilterGroup(CollisionType.VolumeDetect,
|
||||||
(uint)CollisionFilterGroups.BSensorTrigger,
|
(uint)CollisionFilterGroups.BSensorTrigger,
|
||||||
(uint)(~CollisionFilterGroups.BSensorTrigger))
|
(uint)(~CollisionFilterGroups.BSensorTrigger))
|
||||||
},
|
},
|
||||||
{ CollisionType.LinksetChild,
|
{ CollisionType.LinksetChild,
|
||||||
new CollisionTypeFilterGroup(CollisionType.LinksetChild,
|
new CollisionTypeFilterGroup(CollisionType.LinksetChild,
|
||||||
(uint)CollisionFilterGroups.BLinksetChildGroup,
|
(uint)CollisionFilterGroups.BLinksetChildGroup,
|
||||||
(uint)(CollisionFilterGroups.BNoneGroup))
|
(uint)(CollisionFilterGroups.BNoneGroup))
|
||||||
// (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
|
// (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,68 +1,113 @@
|
||||||
|
PROBLEMS TO LOOK INTO
|
||||||
|
=================================================
|
||||||
|
Nebadon vehicle ride, get up, ride again. Second time vehicle does not act correctly.
|
||||||
|
Have to rez new vehicle and delete the old to fix situation.
|
||||||
|
Hitting RESET on Nebadon's vehicle while riding causes vehicle to get into odd
|
||||||
|
position state where it will not settle onto ground properly, etc
|
||||||
|
Two of Nebadon vehicles in a sim max the CPU. This is new.
|
||||||
|
A sitting, active vehicle bobs up and down a small amount.
|
||||||
|
|
||||||
CURRENT PRIORITIES
|
CURRENT PRIORITIES
|
||||||
=================================================
|
=================================================
|
||||||
Redo BulletSimAPI to allow native C# implementation of Bullet option.
|
Use the HACD convex hull routine in Bullet rather than the C# version.
|
||||||
Avatar movement
|
Speed up hullifying large meshes.
|
||||||
flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle
|
|
||||||
walking up stairs is not calibrated correctly (stairs out of Kepler cabin)
|
|
||||||
avatar capsule rotation completed
|
|
||||||
llMoveToTarget
|
|
||||||
Enable vehicle border crossings (at least as poorly as ODE)
|
Enable vehicle border crossings (at least as poorly as ODE)
|
||||||
Terrain skirts
|
Terrain skirts
|
||||||
Avatar created in previous region and not new region when crossing border
|
Avatar created in previous region and not new region when crossing border
|
||||||
Vehicle recreated in new sim at small Z value (offset from root value?) (DONE)
|
Vehicle recreated in new sim at small Z value (offset from root value?) (DONE)
|
||||||
Vehicle movement on terrain smoothness
|
Deleting a linkset while standing on the root will leave the physical shape of the root behind.
|
||||||
|
Not sure if it is because standing on it. Done with large prim linksets.
|
||||||
|
Linkset child rotations.
|
||||||
|
Nebadon spiral tube has middle sections which are rotated wrong.
|
||||||
|
Select linked spiral tube. Delink and note where the middle section ends up.
|
||||||
|
Refarb compound linkset creation to create a pseudo-root for center-of-mass
|
||||||
|
Let children change their shape to physical indendently and just add shapes to compound
|
||||||
|
Vehicle angular vertical attraction
|
||||||
|
vehicle angular banking
|
||||||
|
Center-of-gravity
|
||||||
|
Vehicle angular deflection
|
||||||
|
Preferred orientation angular correction fix
|
||||||
|
when should angular and linear motor targets be zeroed? when selected?
|
||||||
|
Need a vehicle.clear()? Or an 'else' in prestep if not physical.
|
||||||
|
Teravus llMoveToTarget script debug
|
||||||
|
Mixing of hover, buoyancy/gravity, moveToTarget, into one force
|
||||||
|
Setting hover height to zero disables hover even if hover flags are on (from SL wiki)
|
||||||
|
limitMotorUp calibration (more down?)
|
||||||
|
llRotLookAt
|
||||||
|
llLookAt
|
||||||
|
Avatars walking up stairs (HALF DONE)
|
||||||
|
Avatar movement
|
||||||
|
flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle (DONE)
|
||||||
|
walking up stairs is not calibrated correctly (stairs out of Kepler cabin) (DONE)
|
||||||
|
avatar capsule rotation completed (NOT DONE - Bullet's capsule shape is not the solution)
|
||||||
Vehicle script tuning/debugging
|
Vehicle script tuning/debugging
|
||||||
Avanti speed script
|
Avanti speed script
|
||||||
Weapon shooter script
|
Weapon shooter script
|
||||||
limitMotorUp calibration (more down?)
|
Move material definitions (friction, ...) into simulator.
|
||||||
Boats float low in the water
|
|
||||||
Add material densities to the material types.
|
Add material densities to the material types.
|
||||||
|
One sided meshes? Should terrain be built into a closed shape?
|
||||||
CRASHES
|
When meshes get partially wedged into the terrain, they cannot push themselves out.
|
||||||
=================================================
|
It is possible that Bullet processes collisions whether entering or leaving a mesh.
|
||||||
20121129.1411: editting/moving phys object across region boundries causes crash
|
Ref: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4869
|
||||||
getPos-> btRigidBody::upcast -> getBodyType -> BOOM
|
|
||||||
20121128.1600: mesh object not rezzing (no physics mesh).
|
|
||||||
Causes many errors. Doesn't stop after first error with box shape.
|
|
||||||
Eventually crashes when deleting the object.
|
|
||||||
20121206.1434: rez Sam-pan into OSGrid BulletSim11 region
|
|
||||||
Immediate simulator crash. Mono does not output any stacktrace and
|
|
||||||
log just stops after reporting taint-time linking of the linkset.
|
|
||||||
|
|
||||||
VEHICLES TODO LIST:
|
VEHICLES TODO LIST:
|
||||||
=================================================
|
=================================================
|
||||||
Angular motor direction is global coordinates rather than local coordinates
|
LINEAR_MOTOR_DIRECTION values should be clamped to reasonable numbers.
|
||||||
|
What are the limits in SL?
|
||||||
|
Same for other velocity settings.
|
||||||
|
UBit improvements to remove rubber-banding of avatars sitting on vehicle child prims:
|
||||||
|
https://github.com/UbitUmarov/Ubit-opensim
|
||||||
Border crossing with linked vehicle causes crash
|
Border crossing with linked vehicle causes crash
|
||||||
|
20121129.1411: editting/moving phys object across region boundries causes crash
|
||||||
|
getPos-> btRigidBody::upcast -> getBodyType -> BOOM
|
||||||
Vehicles (Move smoothly)
|
Vehicles (Move smoothly)
|
||||||
Add vehicle collisions so IsColliding is properly reported.
|
|
||||||
Needed for banking, limitMotorUp, movementLimiting, ...
|
|
||||||
VehicleAddForce is not scaled by the simulation step but it is only
|
|
||||||
applied for one step. Should it be scaled?
|
|
||||||
Some vehicles should not be able to turn if no speed or off ground.
|
Some vehicles should not be able to turn if no speed or off ground.
|
||||||
|
What to do if vehicle and prim buoyancy differ?
|
||||||
Cannot edit/move a vehicle being ridden: it jumps back to the origional position.
|
Cannot edit/move a vehicle being ridden: it jumps back to the origional position.
|
||||||
Neb car jiggling left and right
|
Neb car jiggling left and right
|
||||||
Happens on terrain and any other mesh object. Flat cubes are much smoother.
|
Happens on terrain and any other mesh object. Flat cubes are much smoother.
|
||||||
This has been reduced but not eliminated.
|
This has been reduced but not eliminated.
|
||||||
Implement referenceFrame for all the motion routines.
|
Implement referenceFrame for all the motion routines.
|
||||||
Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE.
|
For limitMotorUp, use raycast down to find if vehicle is in the air.
|
||||||
Verify that angular motion specified around Z moves in the vehicle coordinates.
|
|
||||||
Verify llGetVel() is returning a smooth and good value for vehicle movement.
|
Verify llGetVel() is returning a smooth and good value for vehicle movement.
|
||||||
llGetVel() should return the root's velocity if requested in a child prim.
|
llGetVel() should return the root's velocity if requested in a child prim.
|
||||||
Implement function efficiency for lineaar and angular motion.
|
Implement function efficiency for lineaar and angular motion.
|
||||||
After getting off a vehicle, the root prim is phantom (can be walked through)
|
After getting off a vehicle, the root prim is phantom (can be walked through)
|
||||||
Need to force a position update for the root prim after compound shape destruction
|
Need to force a position update for the root prim after compound shape destruction
|
||||||
Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint)
|
Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint)
|
||||||
For limitMotorUp, use raycast down to find if vehicle is in the air.
|
|
||||||
Remove vehicle angular velocity zeroing in BSPrim.UpdateProperties().
|
Remove vehicle angular velocity zeroing in BSPrim.UpdateProperties().
|
||||||
A kludge that isn't fixing the real problem of Bullet adding extra motion.
|
A kludge that isn't fixing the real problem of Bullet adding extra motion.
|
||||||
Incorporate inter-relationship of angular corrections. For instance, angularDeflection
|
Incorporate inter-relationship of angular corrections. For instance, angularDeflection
|
||||||
and angularMotorUp will compute same X or Y correction. When added together
|
and angularMotorUp will compute same X or Y correction. When added together
|
||||||
creates over-correction and over-shoot and wabbling.
|
creates over-correction and over-shoot and wabbling.
|
||||||
|
Vehicle attributes are not restored when a vehicle is rezzed on region creation
|
||||||
|
Create vehicle, setup vehicle properties, restart region, vehicle is not reinitialized.
|
||||||
|
|
||||||
BULLETSIM TODO LIST:
|
GENERAL TODO LIST:
|
||||||
=================================================
|
=================================================
|
||||||
|
Explore btGImpactMeshShape as alternative to convex hulls for simplified physical objects.
|
||||||
|
Regular triangle meshes don't do physical collisions.
|
||||||
|
Resitution of a prim works on another prim but not on terrain.
|
||||||
|
The dropped prim doesn't bounce properly on the terrain.
|
||||||
|
Add a sanity check for PIDTarget location.
|
||||||
|
Level-of-detail for mesh creation. Prims with circular interiors require lod of 32.
|
||||||
|
Is much saved with lower LODs? At the moment, all set to 32.
|
||||||
|
Collisions are inconsistant: arrows are supposed to hit and report collision. Often don't.
|
||||||
|
If arrow show at prim, collision reported about 1/3 of time. If collision reported,
|
||||||
|
both arrow and prim report it. The arrow bounces off the prim 9 out of 10 times.
|
||||||
|
Shooting 5m sphere "arrows" at 60m/s.
|
||||||
|
llMoveToTarget objects are not effected by gravity until target is removed.
|
||||||
|
Compute CCD parameters based on body size
|
||||||
|
Can solver iterations be changed per body/shape? Can be for constraints but what
|
||||||
|
about regular vehicles?
|
||||||
|
Implement llSetPhysicalMaterial.
|
||||||
|
extend it with Center-of-mass, rolling friction, density
|
||||||
|
Implement llSetForceAndTorque.
|
||||||
|
Change BSPrim.moveToTarget to used forces rather than changing position
|
||||||
|
Changing position allows one to move through walls
|
||||||
Implement an avatar mesh shape. The Bullet capsule is way too limited.
|
Implement an avatar mesh shape. The Bullet capsule is way too limited.
|
||||||
Consider just hand creating a vertex/index array in a new BSShapeAvatar.
|
Consider just hand creating a vertex/index array in a new BSShapeAvatar.
|
||||||
|
Verify/fix phantom, volume-detect objects do not fall to infinity. Should stop at terrain.
|
||||||
Revisit CollisionMargin. Builders notice the 0.04 spacing between prims.
|
Revisit CollisionMargin. Builders notice the 0.04 spacing between prims.
|
||||||
Duplicating a physical prim causes old prim to jump away
|
Duplicating a physical prim causes old prim to jump away
|
||||||
Dup a phys prim and the original become unselected and thus interacts w/ selected prim.
|
Dup a phys prim and the original become unselected and thus interacts w/ selected prim.
|
||||||
|
@ -86,6 +131,8 @@ setForce should set a constant force. Different than AddImpulse.
|
||||||
Implement raycast.
|
Implement raycast.
|
||||||
Implement ShapeCollection.Dispose()
|
Implement ShapeCollection.Dispose()
|
||||||
Implement water as a plain so raycasting and collisions can happen with same.
|
Implement water as a plain so raycasting and collisions can happen with same.
|
||||||
|
Add collision penetration return
|
||||||
|
Add field passed back by BulletSim.dll and fill with info in ManifoldConstact.GetDistance()
|
||||||
Add osGetPhysicsEngineName() so scripters can tell whether BulletSim or ODE
|
Add osGetPhysicsEngineName() so scripters can tell whether BulletSim or ODE
|
||||||
Also osGetPhysicsEngineVerion() maybe.
|
Also osGetPhysicsEngineVerion() maybe.
|
||||||
Linkset.Position and Linkset.Orientation requre rewrite to properly return
|
Linkset.Position and Linkset.Orientation requre rewrite to properly return
|
||||||
|
@ -107,6 +154,12 @@ Physical and phantom will drop through the terrain
|
||||||
|
|
||||||
LINKSETS
|
LINKSETS
|
||||||
======================================================
|
======================================================
|
||||||
|
Child prims do not report collisions
|
||||||
|
Allow children of a linkset to be phantom:
|
||||||
|
http://opensim-dev.2196679.n2.nabble.com/Setting-a-single-child-prim-to-Phantom-tp7578513.html
|
||||||
|
Add OS_STATUS_PHANTOM_PRIM to llSetLinkPrimitaveParamsFast.
|
||||||
|
Editing a child of a linkset causes the child to go phantom
|
||||||
|
Move a child prim once when it is physical and can never move it again without it going phantom
|
||||||
Offset the center of the linkset to be the geometric center of all the prims
|
Offset the center of the linkset to be the geometric center of all the prims
|
||||||
Not quite the same as the center-of-gravity
|
Not quite the same as the center-of-gravity
|
||||||
Linksets should allow collisions to individual children
|
Linksets should allow collisions to individual children
|
||||||
|
@ -117,11 +170,9 @@ LinksetCompound: when one of the children changes orientation (like tires
|
||||||
Verify/think through scripts in children of linksets. What do they reference
|
Verify/think through scripts in children of linksets. What do they reference
|
||||||
and return when getting position, velocity, ...
|
and return when getting position, velocity, ...
|
||||||
Confirm constraint linksets still work after making all the changes for compound linksets.
|
Confirm constraint linksets still work after making all the changes for compound linksets.
|
||||||
|
Use PostTaint callback to do rebuilds for constraint linksets to reduce rebuilding
|
||||||
Add 'changed' flag or similar to reduce the number of times a linkset is rebuilt.
|
Add 'changed' flag or similar to reduce the number of times a linkset is rebuilt.
|
||||||
For compound linksets, add ability to remove or reposition individual child shapes.
|
For compound linksets, add ability to remove or reposition individual child shapes.
|
||||||
Disable activity of passive linkset children.
|
|
||||||
Since the linkset is a compound object, the old prims are left lying
|
|
||||||
around and need to be phantomized so they don't collide, ...
|
|
||||||
Speed up creation of large physical linksets
|
Speed up creation of large physical linksets
|
||||||
For instance, sitting in Neb's car (130 prims) takes several seconds to become physical.
|
For instance, sitting in Neb's car (130 prims) takes several seconds to become physical.
|
||||||
REALLY bad for very large physical linksets (freezes the sim for many seconds).
|
REALLY bad for very large physical linksets (freezes the sim for many seconds).
|
||||||
|
@ -131,25 +182,28 @@ Eliminate collisions between objects in a linkset. (LinksetConstraint)
|
||||||
|
|
||||||
MORE
|
MORE
|
||||||
======================================================
|
======================================================
|
||||||
Test avatar walking up stairs. How does compare with SL.
|
Compute avatar size and scale correctly. Now it is a bit off from the capsule size.
|
||||||
Radius of the capsule affects ability to climb edges.
|
Create tests for different interface components
|
||||||
|
Have test objects/scripts measure themselves and turn color if correct/bad
|
||||||
|
Test functions in SL and calibrate correctness there
|
||||||
|
Create auto rezzer and tracker to run through the tests
|
||||||
|
Do we need to do convex hulls all the time? Can complex meshes be left meshes?
|
||||||
|
There is some problem with meshes and collisions
|
||||||
|
Hulls are not as detailed as meshes. Hulled vehicles insides are different shape.
|
||||||
Debounce avatar contact so legs don't keep folding up when standing.
|
Debounce avatar contact so legs don't keep folding up when standing.
|
||||||
Implement LSL physics controls. Like STATUS_ROTATE_X.
|
Implement LSL physics controls. Like STATUS_ROTATE_X.
|
||||||
Add border extensions to terrain to help region crossings and objects leaving region.
|
Add border extensions to terrain to help region crossings and objects leaving region.
|
||||||
Use a different capsule shape for avatar when sitting
|
Use a different capsule shape for avatar when sitting
|
||||||
LL uses a pyrimidal shape scaled by the avatar's bounding box
|
LL uses a pyrimidal shape scaled by the avatar's bounding box
|
||||||
http://wiki.secondlife.com/wiki/File:Avmeshforms.png
|
http://wiki.secondlife.com/wiki/File:Avmeshforms.png
|
||||||
|
|
||||||
Performance test with lots of avatars. Can BulletSim support a thousand?
|
Performance test with lots of avatars. Can BulletSim support a thousand?
|
||||||
Optimize collisions in C++: only send up to the object subscribed to collisions.
|
Optimize collisions in C++: only send up to the object subscribed to collisions.
|
||||||
Use collision subscription and remove the collsion(A,B) and collision(B,A)
|
Use collision subscription and remove the collsion(A,B) and collision(B,A)
|
||||||
Check whether SimMotionState needs large if statement (see TODO).
|
Check whether SimMotionState needs large if statement (see TODO).
|
||||||
|
|
||||||
Implement 'top colliders' info.
|
Implement 'top colliders' info.
|
||||||
Avatar jump
|
Avatar jump
|
||||||
Performance measurement and changes to make quicker.
|
Performance measurement and changes to make quicker.
|
||||||
Implement detailed physics stats (GetStats()).
|
Implement detailed physics stats (GetStats()).
|
||||||
|
|
||||||
Measure performance improvement from hulls
|
Measure performance improvement from hulls
|
||||||
Test not using ghost objects for volume detect implementation.
|
Test not using ghost objects for volume detect implementation.
|
||||||
Performance of closures and delegates for taint processing
|
Performance of closures and delegates for taint processing
|
||||||
|
@ -157,9 +211,7 @@ Performance of closures and delegates for taint processing
|
||||||
Is any slowdown introduced by the existing implementation significant?
|
Is any slowdown introduced by the existing implementation significant?
|
||||||
Is there are more efficient method of implementing pre and post step actions?
|
Is there are more efficient method of implementing pre and post step actions?
|
||||||
See http://www.codeproject.com/Articles/29922/Weak-Events-in-C
|
See http://www.codeproject.com/Articles/29922/Weak-Events-in-C
|
||||||
|
|
||||||
Physics Arena central pyramid: why is one side permiable?
|
Physics Arena central pyramid: why is one side permiable?
|
||||||
|
|
||||||
In SL, perfect spheres don't seem to have rolling friction. Add special case.
|
In SL, perfect spheres don't seem to have rolling friction. Add special case.
|
||||||
Enforce physical parameter min/max:
|
Enforce physical parameter min/max:
|
||||||
Gravity: [-1, 28]
|
Gravity: [-1, 28]
|
||||||
|
@ -168,9 +220,12 @@ Enforce physical parameter min/max:
|
||||||
Restitution [0, 1]
|
Restitution [0, 1]
|
||||||
http://wiki.secondlife.com/wiki/Physics_Material_Settings_test
|
http://wiki.secondlife.com/wiki/Physics_Material_Settings_test
|
||||||
Avatar attachments have no mass? http://forums-archive.secondlife.com/54/f0/31796/1.html
|
Avatar attachments have no mass? http://forums-archive.secondlife.com/54/f0/31796/1.html
|
||||||
|
Keep avatar scaling correct. http://pennycow.blogspot.fr/2011/07/matter-of-scale.html
|
||||||
|
|
||||||
INTERNAL IMPROVEMENT/CLEANUP
|
INTERNAL IMPROVEMENT/CLEANUP
|
||||||
=================================================
|
=================================================
|
||||||
|
Can the 'inTaintTime' flag be cleaned up and used? For instance, a call to
|
||||||
|
BSScene.TaintedObject() could immediately execute the callback if already in taint time.
|
||||||
Create the physical wrapper classes (BulletBody, BulletShape) by methods on
|
Create the physical wrapper classes (BulletBody, BulletShape) by methods on
|
||||||
BSAPITemplate and make their actual implementation Bullet engine specific.
|
BSAPITemplate and make their actual implementation Bullet engine specific.
|
||||||
For the short term, just call the existing functions in ShapeCollection.
|
For the short term, just call the existing functions in ShapeCollection.
|
||||||
|
@ -190,22 +245,19 @@ Generalize Dynamics and PID with standardized motors.
|
||||||
Generalize Linkset and vehicles into PropertyManagers
|
Generalize Linkset and vehicles into PropertyManagers
|
||||||
Methods for Refresh, RemoveBodyDependencies, RestoreBodyDependencies
|
Methods for Refresh, RemoveBodyDependencies, RestoreBodyDependencies
|
||||||
Potentially add events for shape destruction, etc.
|
Potentially add events for shape destruction, etc.
|
||||||
Complete implemention of preStepActions
|
Better mechanism for resetting linkset set and vehicle parameters when body rebuilt.
|
||||||
Replace vehicle step call with prestep event.
|
BSPrim.CreateGeomAndObject is kludgy with the callbacks, etc.
|
||||||
Is there a need for postStepActions? postStepTaints?
|
|
||||||
Implement linkset by setting position of children when root updated. (LinksetManual)
|
Implement linkset by setting position of children when root updated. (LinksetManual)
|
||||||
Linkset implementation using manual prim movement.
|
Linkset implementation using manual prim movement.
|
||||||
LinkablePrim class? Would that simplify/centralize the linkset logic?
|
LinkablePrim class? Would that simplify/centralize the linkset logic?
|
||||||
BSScene.UpdateParameterSet() is broken. How to set params on objects?
|
BSScene.UpdateParameterSet() is broken. How to set params on objects?
|
||||||
Remove HeightmapInfo from terrain specification
|
|
||||||
Since C++ code does not need terrain height, this structure et al are not needed.
|
|
||||||
Add floating motor for BS_FLOATS_ON_WATER so prim and avatar will
|
Add floating motor for BS_FLOATS_ON_WATER so prim and avatar will
|
||||||
bob at the water level. BSPrim.PositionSanityCheck().
|
bob at the water level. BSPrim.PositionSanityCheck()
|
||||||
Should taints check for existance or activeness of target?
|
Should taints check for existance or activeness of target?
|
||||||
When destroying linksets/etc, taints can be generated for objects that are
|
When destroying linksets/etc, taints can be generated for objects that are
|
||||||
actually gone when the taint happens. Crashes don't happen because the taint closure
|
actually gone when the taint happens. Crashes don't happen because the taint closure
|
||||||
keeps the object from being freed, but that is just an accident.
|
keeps the object from being freed, but that is just an accident.
|
||||||
Possibly have and 'active' flag that is checked by the taint processor?
|
Possibly have an 'active' flag that is checked by the taint processor?
|
||||||
Parameters for physics logging should be moved from BSScene to BSParam (at least boolean ones)
|
Parameters for physics logging should be moved from BSScene to BSParam (at least boolean ones)
|
||||||
Can some of the physical wrapper classes (BulletBody, BulletWorld, BulletShape) be 'sealed'?
|
Can some of the physical wrapper classes (BulletBody, BulletWorld, BulletShape) be 'sealed'?
|
||||||
There are TOO MANY interfaces from BulletSim core to Bullet itself
|
There are TOO MANY interfaces from BulletSim core to Bullet itself
|
||||||
|
@ -270,3 +322,43 @@ llSetBuoyancy() (DONE)
|
||||||
(Resolution: Bullet resets object gravity when added to world. Moved set gravity)
|
(Resolution: Bullet resets object gravity when added to world. Moved set gravity)
|
||||||
Avatar density is WAY off. Compare and calibrate with what's in SL. (DONE)
|
Avatar density is WAY off. Compare and calibrate with what's in SL. (DONE)
|
||||||
(Resolution: set default density to 3.5 (from 60) which is closer to SL)
|
(Resolution: set default density to 3.5 (from 60) which is closer to SL)
|
||||||
|
Redo BulletSimAPI to allow native C# implementation of Bullet option (DONE)
|
||||||
|
(Resolution: added BSAPITemplate and then interfaces for C++ Bullet and C# BulletXNA
|
||||||
|
Meshes rendering as bounding boxes (DONE)
|
||||||
|
(Resolution: Added test for mesh/sculpties in native shapes so it didn't think it was a box)
|
||||||
|
llMoveToTarget (Resolution: added simple motor to update the position.)
|
||||||
|
Angular motor direction is global coordinates rather than local coordinates (DONE)
|
||||||
|
Add vehicle collisions so IsColliding is properly reported. (DONE)
|
||||||
|
Needed for banking, limitMotorUp, movementLimiting, ...
|
||||||
|
(Resolution: added CollisionFlags.BS_VEHICLE_COLLISION and code to use it)
|
||||||
|
VehicleAddForce is not scaled by the simulation step but it is only
|
||||||
|
applied for one step. Should it be scaled? (DONE)
|
||||||
|
(Resolution: use force for timed things, Impulse for immediate, non-timed things)
|
||||||
|
Complete implemention of preStepActions (DONE)
|
||||||
|
Replace vehicle step call with prestep event.
|
||||||
|
Is there a need for postStepActions? postStepTaints?
|
||||||
|
Disable activity of passive linkset children. (DONE)
|
||||||
|
Since the linkset is a compound object, the old prims are left lying
|
||||||
|
around and need to be phantomized so they don't collide, ...
|
||||||
|
Remove HeightmapInfo from terrain specification (DONE)
|
||||||
|
Since C++ code does not need terrain height, this structure et al are not needed.
|
||||||
|
Surfboard go wonky when turning (DONE)
|
||||||
|
Angular motor direction is global coordinates rather than local coordinates?
|
||||||
|
(Resolution: made angular motor direction correct coordinate system)
|
||||||
|
Mantis 6040 script http://opensimulator.org/mantis/view.php?id=6040 (DONE)
|
||||||
|
Msg Kayaker on OSGrid when working
|
||||||
|
(Resolution: LINEAR_DIRECTION is in vehicle coords. Test script does the
|
||||||
|
same in SL as in OS/BulletSim)
|
||||||
|
Boats float low in the water (DONE)
|
||||||
|
Boats floating at proper level (DONE)
|
||||||
|
When is force introduced by SetForce removed? The prestep action could go forever. (DONE)
|
||||||
|
(Resolution: setForce registers a prestep action which keeps applying the force)
|
||||||
|
Child movement in linkset (don't rebuild linkset) (DONE 20130122))
|
||||||
|
Avatar standing on a moving object should start to move with the object. (DONE 20130125)
|
||||||
|
Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE.
|
||||||
|
Verify that angular motion specified around Z moves in the vehicle coordinates.
|
||||||
|
DONE 20130120: BulletSim properly applies force in vehicle relative coordinates.
|
||||||
|
Nebadon vehicles turning funny in arena (DONE)
|
||||||
|
Lock axis (DONE 20130401)
|
||||||
|
Terrain detail: double terrain mesh detail (DONE)
|
||||||
|
|
||||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
||||||
// Build Number
|
// Build Number
|
||||||
// Revision
|
// Revision
|
||||||
//
|
//
|
||||||
[assembly: AssemblyVersion("0.7.5.*")]
|
[assembly: AssemblyVersion("0.7.6.*")]
|
||||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
||||||
|
|
|
@ -0,0 +1,150 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Contributors, http://opensimulator.org/
|
||||||
|
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the OpenSimulator Project nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using NUnit.Framework;
|
||||||
|
using log4net;
|
||||||
|
|
||||||
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Region.Physics.BulletSPlugin;
|
||||||
|
using OpenSim.Region.Physics.Manager;
|
||||||
|
using OpenSim.Tests.Common;
|
||||||
|
|
||||||
|
using OpenMetaverse;
|
||||||
|
|
||||||
|
namespace OpenSim.Region.Physics.BulletSPlugin.Tests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class BasicVehicles : OpenSimTestCase
|
||||||
|
{
|
||||||
|
// Documentation on attributes: http://www.nunit.org/index.php?p=attributes&r=2.6.1
|
||||||
|
// Documentation on assertions: http://www.nunit.org/index.php?p=assertions&r=2.6.1
|
||||||
|
|
||||||
|
BSScene PhysicsScene { get; set; }
|
||||||
|
BSPrim TestVehicle { get; set; }
|
||||||
|
Vector3 TestVehicleInitPosition { get; set; }
|
||||||
|
float simulationTimeStep = 0.089f;
|
||||||
|
|
||||||
|
[TestFixtureSetUp]
|
||||||
|
public void Init()
|
||||||
|
{
|
||||||
|
Dictionary<string, string> engineParams = new Dictionary<string, string>();
|
||||||
|
PhysicsScene = BulletSimTestsUtil.CreateBasicPhysicsEngine(engineParams);
|
||||||
|
|
||||||
|
PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateSphere();
|
||||||
|
Vector3 pos = new Vector3(100.0f, 100.0f, 0f);
|
||||||
|
pos.Z = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 2f;
|
||||||
|
TestVehicleInitPosition = pos;
|
||||||
|
Vector3 size = new Vector3(1f, 1f, 1f);
|
||||||
|
pbs.Scale = size;
|
||||||
|
Quaternion rot = Quaternion.Identity;
|
||||||
|
bool isPhys = false;
|
||||||
|
uint localID = 123;
|
||||||
|
|
||||||
|
PhysicsScene.AddPrimShape("testPrim", pbs, pos, size, rot, isPhys, localID);
|
||||||
|
TestVehicle = (BSPrim)PhysicsScene.PhysObjects[localID];
|
||||||
|
// The actual prim shape creation happens at taint time
|
||||||
|
PhysicsScene.ProcessTaints();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestFixtureTearDown]
|
||||||
|
public void TearDown()
|
||||||
|
{
|
||||||
|
if (PhysicsScene != null)
|
||||||
|
{
|
||||||
|
// The Dispose() will also free any physical objects in the scene
|
||||||
|
PhysicsScene.Dispose();
|
||||||
|
PhysicsScene = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCase(2f, 0.2f, 0.25f, 0.25f, 0.25f)]
|
||||||
|
[TestCase(2f, 0.2f, -0.25f, 0.25f, 0.25f)]
|
||||||
|
[TestCase(2f, 0.2f, 0.25f, -0.25f, 0.25f)]
|
||||||
|
[TestCase(2f, 0.2f, -0.25f, -0.25f, 0.25f)]
|
||||||
|
// [TestCase(2f, 0.2f, 0.785f, 0.0f, 0.25f) /*, "Leaning 45 degrees to the side" */]
|
||||||
|
// [TestCase(2f, 0.2f, 1.650f, 0.0f, 0.25f) /*, "Leaning more than 90 degrees to the side" */]
|
||||||
|
// [TestCase(2f, 0.2f, 2.750f, 0.0f, 0.25f) /*, "Almost upside down, tipped right" */]
|
||||||
|
// [TestCase(2f, 0.2f,-2.750f, 0.0f, 0.25f) /*, "Almost upside down, tipped left" */]
|
||||||
|
// [TestCase(2f, 0.2f, 0.0f, 0.785f, 0.25f) /*, "Tipped back 45 degrees" */]
|
||||||
|
// [TestCase(2f, 0.2f, 0.0f, 1.650f, 0.25f) /*, "Tipped back more than 90 degrees" */]
|
||||||
|
// [TestCase(2f, 0.2f, 0.0f, 2.750f, 0.25f) /*, "Almost upside down, tipped back" */]
|
||||||
|
// [TestCase(2f, 0.2f, 0.0f,-2.750f, 0.25f) /*, "Almost upside down, tipped forward" */]
|
||||||
|
public void AngularVerticalAttraction(float timeScale, float efficiency, float initRoll, float initPitch, float initYaw)
|
||||||
|
{
|
||||||
|
// Enough simulation steps to cover the timescale the operation should take
|
||||||
|
int simSteps = (int)(timeScale / simulationTimeStep) + 1;
|
||||||
|
|
||||||
|
// Tip the vehicle
|
||||||
|
Quaternion initOrientation = Quaternion.CreateFromEulers(initRoll, initPitch, initYaw);
|
||||||
|
TestVehicle.Orientation = initOrientation;
|
||||||
|
|
||||||
|
TestVehicle.Position = TestVehicleInitPosition;
|
||||||
|
|
||||||
|
// The vehicle controller is not enabled directly (by setting a vehicle type).
|
||||||
|
// Instead the appropriate values are set and calls are made just the parts of the
|
||||||
|
// controller we want to exercise. Stepping the physics engine then applies
|
||||||
|
// the actions of that one feature.
|
||||||
|
TestVehicle.VehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_EFFICIENCY, efficiency);
|
||||||
|
TestVehicle.VehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_TIMESCALE, timeScale);
|
||||||
|
TestVehicle.VehicleActor.enableAngularVerticalAttraction = true;
|
||||||
|
|
||||||
|
TestVehicle.IsPhysical = true;
|
||||||
|
PhysicsScene.ProcessTaints();
|
||||||
|
|
||||||
|
// Step the simulator a bunch of times and vertical attraction should orient the vehicle up
|
||||||
|
for (int ii = 0; ii < simSteps; ii++)
|
||||||
|
{
|
||||||
|
TestVehicle.VehicleActor.ForgetKnownVehicleProperties();
|
||||||
|
TestVehicle.VehicleActor.ComputeAngularVerticalAttraction();
|
||||||
|
TestVehicle.VehicleActor.PushKnownChanged();
|
||||||
|
|
||||||
|
PhysicsScene.Simulate(simulationTimeStep);
|
||||||
|
}
|
||||||
|
|
||||||
|
TestVehicle.IsPhysical = false;
|
||||||
|
PhysicsScene.ProcessTaints();
|
||||||
|
|
||||||
|
// After these steps, the vehicle should be upright
|
||||||
|
/*
|
||||||
|
float finalRoll, finalPitch, finalYaw;
|
||||||
|
TestVehicle.Orientation.GetEulerAngles(out finalRoll, out finalPitch, out finalYaw);
|
||||||
|
Assert.That(finalRoll, Is.InRange(-0.01f, 0.01f));
|
||||||
|
Assert.That(finalPitch, Is.InRange(-0.01f, 0.01f));
|
||||||
|
Assert.That(finalYaw, Is.InRange(initYaw - 0.1f, initYaw + 0.1f));
|
||||||
|
*/
|
||||||
|
|
||||||
|
Vector3 upPointer = Vector3.UnitZ * TestVehicle.Orientation;
|
||||||
|
Assert.That(upPointer.Z, Is.GreaterThan(0.99f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Contributors, http://opensimulator.org/
|
||||||
|
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the OpenSimulator Project nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using NUnit.Framework;
|
||||||
|
using log4net;
|
||||||
|
|
||||||
|
using OpenSim.Tests.Common;
|
||||||
|
|
||||||
|
namespace OpenSim.Region.Physics.BulletSPlugin.Tests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class BulletSimTests : OpenSimTestCase
|
||||||
|
{
|
||||||
|
// Documentation on attributes: http://www.nunit.org/index.php?p=attributes&r=2.6.1
|
||||||
|
// Documentation on assertions: http://www.nunit.org/index.php?p=assertions&r=2.6.1
|
||||||
|
|
||||||
|
[TestFixtureSetUp]
|
||||||
|
public void Init()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestFixtureTearDown]
|
||||||
|
public void TearDown()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Contributors, http://opensimulator.org/
|
||||||
|
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the OpenSimulator Project nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using Nini.Config;
|
||||||
|
|
||||||
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Region.Physics.BulletSPlugin;
|
||||||
|
using OpenSim.Region.Physics.Meshing;
|
||||||
|
|
||||||
|
namespace OpenSim.Region.Physics.BulletSPlugin.Tests
|
||||||
|
{
|
||||||
|
// Utility functions for building up and tearing down the sample physics environments
|
||||||
|
public static class BulletSimTestsUtil
|
||||||
|
{
|
||||||
|
// 'engineName' is the Bullet engine to use. Either null (for unmanaged), "BulletUnmanaged" or "BulletXNA"
|
||||||
|
// 'params' is a set of keyValue pairs to set in the engine's configuration file (override defaults)
|
||||||
|
// May be 'null' if there are no overrides.
|
||||||
|
public static BSScene CreateBasicPhysicsEngine(Dictionary<string,string> paramOverrides)
|
||||||
|
{
|
||||||
|
IConfigSource openSimINI = new IniConfigSource();
|
||||||
|
IConfig startupConfig = openSimINI.AddConfig("Startup");
|
||||||
|
startupConfig.Set("physics", "BulletSim");
|
||||||
|
startupConfig.Set("meshing", "Meshmerizer");
|
||||||
|
startupConfig.Set("cacheSculptMaps", "false"); // meshmerizer shouldn't save maps
|
||||||
|
|
||||||
|
IConfig bulletSimConfig = openSimINI.AddConfig("BulletSim");
|
||||||
|
// If the caller cares, specify the bullet engine otherwise it will default to "BulletUnmanaged".
|
||||||
|
// bulletSimConfig.Set("BulletEngine", "BulletUnmanaged");
|
||||||
|
// bulletSimConfig.Set("BulletEngine", "BulletXNA");
|
||||||
|
bulletSimConfig.Set("MeshSculptedPrim", "false");
|
||||||
|
bulletSimConfig.Set("ForceSimplePrimMeshing", "true");
|
||||||
|
if (paramOverrides != null)
|
||||||
|
{
|
||||||
|
foreach (KeyValuePair<string, string> kvp in paramOverrides)
|
||||||
|
{
|
||||||
|
bulletSimConfig.Set(kvp.Key, kvp.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a special directory exists, put detailed logging therein.
|
||||||
|
// This allows local testing/debugging without having to worry that the build engine will output logs.
|
||||||
|
if (Directory.Exists("physlogs"))
|
||||||
|
{
|
||||||
|
bulletSimConfig.Set("PhysicsLoggingDir","./physlogs");
|
||||||
|
bulletSimConfig.Set("PhysicsLoggingEnabled","True");
|
||||||
|
bulletSimConfig.Set("PhysicsLoggingDoFlush","True");
|
||||||
|
bulletSimConfig.Set("VehicleLoggingEnabled","True");
|
||||||
|
}
|
||||||
|
|
||||||
|
BSPlugin bsPlugin = new BSPlugin();
|
||||||
|
|
||||||
|
BSScene bsScene = (BSScene)bsPlugin.GetScene("BSTestRegion");
|
||||||
|
|
||||||
|
// Since the asset requestor is not initialized, any mesh or sculptie will be a cube.
|
||||||
|
// In the future, add a fake asset fetcher to get meshes and sculpts.
|
||||||
|
// bsScene.RequestAssetMethod = ???;
|
||||||
|
|
||||||
|
Meshing.Meshmerizer mesher = new Meshmerizer(openSimINI);
|
||||||
|
bsScene.Initialise(mesher, openSimINI);
|
||||||
|
|
||||||
|
return bsScene;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -59,6 +59,7 @@ namespace OpenSim.Region.Physics.Manager
|
||||||
List<Vector3> getVertexList();
|
List<Vector3> getVertexList();
|
||||||
int[] getIndexListAsInt();
|
int[] getIndexListAsInt();
|
||||||
int[] getIndexListAsIntLocked();
|
int[] getIndexListAsIntLocked();
|
||||||
|
float[] getVertexListAsFloat();
|
||||||
float[] getVertexListAsFloatLocked();
|
float[] getVertexListAsFloatLocked();
|
||||||
void getIndexListAsPtrToIntArray(out IntPtr indices, out int triStride, out int indexCount);
|
void getIndexListAsPtrToIntArray(out IntPtr indices, out int triStride, out int indexCount);
|
||||||
void getVertexListAsPtrToFloatArray(out IntPtr vertexList, out int vertexStride, out int vertexCount);
|
void getVertexListAsPtrToFloatArray(out IntPtr vertexList, out int vertexStride, out int vertexCount);
|
||||||
|
|
|
@ -60,14 +60,14 @@ namespace OpenSim.Region.Physics.Manager
|
||||||
|
|
||||||
// Set parameter on a specific or all instances.
|
// Set parameter on a specific or all instances.
|
||||||
// Return 'false' if not able to set the parameter.
|
// Return 'false' if not able to set the parameter.
|
||||||
bool SetPhysicsParameter(string parm, float value, uint localID);
|
bool SetPhysicsParameter(string parm, string value, uint localID);
|
||||||
|
|
||||||
// Get parameter.
|
// Get parameter.
|
||||||
// Return 'false' if not able to get the parameter.
|
// Return 'false' if not able to get the parameter.
|
||||||
bool GetPhysicsParameter(string parm, out float value);
|
bool GetPhysicsParameter(string parm, out string value);
|
||||||
|
|
||||||
// Get parameter from a particular object
|
// Get parameter from a particular object
|
||||||
// TODO:
|
// TODO:
|
||||||
// bool GetPhysicsParameter(string parm, out float value, uint localID);
|
// bool GetPhysicsParameter(string parm, out string value, uint localID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -147,6 +147,8 @@ namespace OpenSim.Region.Physics.Manager
|
||||||
|
|
||||||
public abstract Vector3 Size { get; set; }
|
public abstract Vector3 Size { get; set; }
|
||||||
|
|
||||||
|
public virtual byte PhysicsShapeType { get; set; }
|
||||||
|
|
||||||
public abstract PrimitiveBaseShape Shape { set; }
|
public abstract PrimitiveBaseShape Shape { set; }
|
||||||
|
|
||||||
uint m_baseLocalID;
|
uint m_baseLocalID;
|
||||||
|
@ -218,9 +220,11 @@ namespace OpenSim.Region.Physics.Manager
|
||||||
handler(e);
|
handler(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void SetMaterial (int material)
|
public virtual void SetMaterial (int material) { }
|
||||||
{
|
public virtual float Density { get; set; }
|
||||||
}
|
public virtual float GravModifier { get; set; }
|
||||||
|
public virtual float Friction { get; set; }
|
||||||
|
public virtual float Restitution { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Position of this actor.
|
/// Position of this actor.
|
||||||
|
|
|
@ -43,6 +43,35 @@ namespace OpenSim.Region.Physics.Manager
|
||||||
public delegate void JointDeactivated(PhysicsJoint joint);
|
public delegate void JointDeactivated(PhysicsJoint joint);
|
||||||
public delegate void JointErrorMessage(PhysicsJoint joint, string message); // this refers to an "error message due to a problem", not "amount of joint constraint violation"
|
public delegate void JointErrorMessage(PhysicsJoint joint, string message); // this refers to an "error message due to a problem", not "amount of joint constraint violation"
|
||||||
|
|
||||||
|
public enum RayFilterFlags : ushort
|
||||||
|
{
|
||||||
|
// the flags
|
||||||
|
water = 0x01,
|
||||||
|
land = 0x02,
|
||||||
|
agent = 0x04,
|
||||||
|
nonphysical = 0x08,
|
||||||
|
physical = 0x10,
|
||||||
|
phantom = 0x20,
|
||||||
|
volumedtc = 0x40,
|
||||||
|
|
||||||
|
// ray cast colision control (may only work for meshs)
|
||||||
|
ContactsUnImportant = 0x2000,
|
||||||
|
BackFaceCull = 0x4000,
|
||||||
|
ClosestHit = 0x8000,
|
||||||
|
|
||||||
|
// some combinations
|
||||||
|
LSLPhantom = phantom | volumedtc,
|
||||||
|
PrimsNonPhantom = nonphysical | physical,
|
||||||
|
PrimsNonPhantomAgents = nonphysical | physical | agent,
|
||||||
|
|
||||||
|
AllPrims = nonphysical | phantom | volumedtc | physical,
|
||||||
|
AllButLand = agent | nonphysical | physical | phantom | volumedtc,
|
||||||
|
|
||||||
|
ClosestAndBackCull = ClosestHit | BackFaceCull,
|
||||||
|
|
||||||
|
All = 0x3f
|
||||||
|
}
|
||||||
|
|
||||||
public delegate void RequestAssetDelegate(UUID assetID, AssetReceivedDelegate callback);
|
public delegate void RequestAssetDelegate(UUID assetID, AssetReceivedDelegate callback);
|
||||||
public delegate void AssetReceivedDelegate(AssetBase asset);
|
public delegate void AssetReceivedDelegate(AssetBase asset);
|
||||||
|
|
||||||
|
@ -62,13 +91,20 @@ namespace OpenSim.Region.Physics.Manager
|
||||||
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Name of this scene. Useful in debug messages to distinguish one OdeScene instance from another.
|
/// A unique identifying string for this instance of the physics engine.
|
||||||
|
/// Useful in debug messages to distinguish one OdeScene instance from another.
|
||||||
|
/// Usually set to include the region name that the physics engine is acting for.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Name { get; protected set; }
|
public string Name { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A string identifying the family of this physics engine. Most common values returned
|
||||||
|
/// are "OpenDynamicsEngine" and "BulletSim" but others are possible.
|
||||||
|
/// </summary>
|
||||||
|
public string EngineType { get; protected set; }
|
||||||
|
|
||||||
// The only thing that should register for this event is the SceneGraph
|
// The only thing that should register for this event is the SceneGraph
|
||||||
// Anything else could cause problems.
|
// Anything else could cause problems.
|
||||||
|
|
||||||
public event physicsCrash OnPhysicsCrash;
|
public event physicsCrash OnPhysicsCrash;
|
||||||
|
|
||||||
public static PhysicsScene Null
|
public static PhysicsScene Null
|
||||||
|
@ -130,6 +166,12 @@ namespace OpenSim.Region.Physics.Manager
|
||||||
public abstract PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
|
public abstract PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
|
||||||
Vector3 size, Quaternion rotation, bool isPhysical, uint localid);
|
Vector3 size, Quaternion rotation, bool isPhysical, uint localid);
|
||||||
|
|
||||||
|
public virtual PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
|
||||||
|
Vector3 size, Quaternion rotation, bool isPhysical, bool isPhantom, byte shapetype, uint localid)
|
||||||
|
{
|
||||||
|
return AddPrimShape(primName, pbs, position, size, rotation, isPhysical, localid);
|
||||||
|
}
|
||||||
|
|
||||||
public virtual float TimeDilation
|
public virtual float TimeDilation
|
||||||
{
|
{
|
||||||
get { return 1.0f; }
|
get { return 1.0f; }
|
||||||
|
@ -279,5 +321,15 @@ namespace OpenSim.Region.Physics.Manager
|
||||||
{
|
{
|
||||||
return new List<ContactResult>();
|
return new List<ContactResult>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual object RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayFilterFlags filter)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool SupportsRaycastWorldFiltered()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,7 +152,7 @@ namespace OpenSim.Region.Physics.Meshing
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private float[] getVertexListAsFloat()
|
public float[] getVertexListAsFloat()
|
||||||
{
|
{
|
||||||
if (m_vertices == null)
|
if (m_vertices == null)
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
|
|
|
@ -66,6 +66,7 @@ using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
|
||||||
using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
|
using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
|
||||||
using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
|
using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace OpenSim.Region.ScriptEngine.Shared.Api
|
namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
{
|
{
|
||||||
|
@ -110,6 +111,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
protected int EMAIL_PAUSE_TIME = 20; // documented delay value for smtp.
|
protected int EMAIL_PAUSE_TIME = 20; // documented delay value for smtp.
|
||||||
protected ISoundModule m_SoundModule = null;
|
protected ISoundModule m_SoundModule = null;
|
||||||
|
|
||||||
|
//An array of HTTP/1.1 headers that are not allowed to be used
|
||||||
|
//as custom headers by llHTTPRequest.
|
||||||
|
private string[] HttpStandardHeaders =
|
||||||
|
{
|
||||||
|
"Accept", "Accept-Charset", "Accept-Encoding", "Accept-Language",
|
||||||
|
"Accept-Ranges", "Age", "Allow", "Authorization", "Cache-Control",
|
||||||
|
"Connection", "Content-Encoding", "Content-Language",
|
||||||
|
"Content-Length", "Content-Location", "Content-MD5",
|
||||||
|
"Content-Range", "Content-Type", "Date", "ETag", "Expect",
|
||||||
|
"Expires", "From", "Host", "If-Match", "If-Modified-Since",
|
||||||
|
"If-None-Match", "If-Range", "If-Unmodified-Since", "Last-Modified",
|
||||||
|
"Location", "Max-Forwards", "Pragma", "Proxy-Authenticate",
|
||||||
|
"Proxy-Authorization", "Range", "Referer", "Retry-After", "Server",
|
||||||
|
"TE", "Trailer", "Transfer-Encoding", "Upgrade", "User-Agent",
|
||||||
|
"Vary", "Via", "Warning", "WWW-Authenticate"
|
||||||
|
};
|
||||||
|
|
||||||
public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item)
|
public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item)
|
||||||
{
|
{
|
||||||
m_ScriptEngine = ScriptEngine;
|
m_ScriptEngine = ScriptEngine;
|
||||||
|
@ -1522,7 +1540,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
if (tex.FaceTextures[i] != null)
|
if (tex.FaceTextures[i] != null)
|
||||||
{
|
{
|
||||||
tex.FaceTextures[i].Shiny = sval;
|
tex.FaceTextures[i].Shiny = sval;
|
||||||
tex.FaceTextures[i].Bump = bump;;
|
tex.FaceTextures[i].Bump = bump;
|
||||||
}
|
}
|
||||||
tex.DefaultTexture.Shiny = sval;
|
tex.DefaultTexture.Shiny = sval;
|
||||||
tex.DefaultTexture.Bump = bump;
|
tex.DefaultTexture.Bump = bump;
|
||||||
|
@ -1631,7 +1649,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
|
texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
|
||||||
tex.DefaultTexture.RGBA = texcolor;
|
tex.DefaultTexture.RGBA = texcolor;
|
||||||
}
|
}
|
||||||
|
|
||||||
part.UpdateTextureEntry(tex.GetBytes());
|
part.UpdateTextureEntry(tex.GetBytes());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1668,10 +1686,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
part.Shape.FlexiForceX = (float)Force.x;
|
part.Shape.FlexiForceX = (float)Force.x;
|
||||||
part.Shape.FlexiForceY = (float)Force.y;
|
part.Shape.FlexiForceY = (float)Force.y;
|
||||||
part.Shape.FlexiForceZ = (float)Force.z;
|
part.Shape.FlexiForceZ = (float)Force.z;
|
||||||
part.Shape.PathCurve = 0x80;
|
part.Shape.PathCurve = (byte)Extrusion.Flexible;
|
||||||
part.ParentGroup.HasGroupChanged = true;
|
|
||||||
part.ScheduleFullUpdate();
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Other values not set, they do not seem to be sent to the viewer
|
||||||
|
// Setting PathCurve appears to be what actually toggles the check box and turns Flexi on and off
|
||||||
|
part.Shape.PathCurve = (byte)Extrusion.Straight;
|
||||||
|
part.Shape.FlexiEntry = false;
|
||||||
|
}
|
||||||
|
part.ParentGroup.HasGroupChanged = true;
|
||||||
|
part.ScheduleFullUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1745,7 +1770,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
rgb.x = texcolor.R;
|
rgb.x = texcolor.R;
|
||||||
rgb.y = texcolor.G;
|
rgb.y = texcolor.G;
|
||||||
rgb.z = texcolor.B;
|
rgb.z = texcolor.B;
|
||||||
|
|
||||||
return rgb;
|
return rgb;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1777,12 +1802,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
{
|
{
|
||||||
UUID textureID = new UUID();
|
UUID textureID = new UUID();
|
||||||
|
|
||||||
textureID = InventoryKey(texture, (int)AssetType.Texture);
|
textureID = InventoryKey(texture, (int)AssetType.Texture);
|
||||||
if (textureID == UUID.Zero)
|
if (textureID == UUID.Zero)
|
||||||
{
|
{
|
||||||
if (!UUID.TryParse(texture, out textureID))
|
if (!UUID.TryParse(texture, out textureID))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Primitive.TextureEntry tex = part.Shape.Textures;
|
Primitive.TextureEntry tex = part.Shape.Textures;
|
||||||
|
|
||||||
|
@ -1979,7 +2004,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
// IF YOU GET REGION CROSSINGS WORKING WITH THIS FUNCTION, REPLACE THE WORKAROUND.
|
// IF YOU GET REGION CROSSINGS WORKING WITH THIS FUNCTION, REPLACE THE WORKAROUND.
|
||||||
//
|
//
|
||||||
// This workaround is to prevent silent failure of this function.
|
// This workaround is to prevent silent failure of this function.
|
||||||
// According to the specification on the SL Wiki, providing a position outside of the
|
// According to the specification on the SL Wiki, providing a position outside of the
|
||||||
if (pos.x < 0 || pos.x > Constants.RegionSize || pos.y < 0 || pos.y > Constants.RegionSize)
|
if (pos.x < 0 || pos.x > Constants.RegionSize || pos.y < 0 || pos.y > Constants.RegionSize)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2188,7 +2213,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
{
|
{
|
||||||
return llGetRootRotation();
|
return llGetRootRotation();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_host.AddScriptLPS(1);
|
m_host.AddScriptLPS(1);
|
||||||
Quaternion q = m_host.GetWorldRotation();
|
Quaternion q = m_host.GetWorldRotation();
|
||||||
return new LSL_Rotation(q.X, q.Y, q.Z, q.W);
|
return new LSL_Rotation(q.X, q.Y, q.Z, q.W);
|
||||||
|
@ -2875,7 +2900,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
// we need to convert from a vector describing
|
// we need to convert from a vector describing
|
||||||
// the angles of rotation in radians into rotation value
|
// the angles of rotation in radians into rotation value
|
||||||
LSL_Rotation rot = llEuler2Rot(angle);
|
LSL_Rotation rot = llEuler2Rot(angle);
|
||||||
|
|
||||||
// Per discussion with Melanie, for non-physical objects llLookAt appears to simply
|
// Per discussion with Melanie, for non-physical objects llLookAt appears to simply
|
||||||
// set the rotation of the object, copy that behavior
|
// set the rotation of the object, copy that behavior
|
||||||
PhysicsActor pa = m_host.PhysActor;
|
PhysicsActor pa = m_host.PhysActor;
|
||||||
|
@ -2951,7 +2976,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
|
|
||||||
if (!UUID.TryParse(id, out objectID))
|
if (!UUID.TryParse(id, out objectID))
|
||||||
objectID = UUID.Zero;
|
objectID = UUID.Zero;
|
||||||
|
|
||||||
if (objectID == UUID.Zero && name == "")
|
if (objectID == UUID.Zero && name == "")
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -3007,7 +3032,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attach the object containing this script to the avatar that owns it.
|
/// Attach the object containing this script to the avatar that owns it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name='attachment'>The attachment point (e.g. ATTACH_CHEST)</param>
|
/// <param name='attachmentPoint'>
|
||||||
|
/// The attachment point (e.g. <see cref="OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass.ATTACH_CHEST">ATTACH_CHEST</see>)
|
||||||
|
/// </param>
|
||||||
/// <returns>true if the attach suceeded, false if it did not</returns>
|
/// <returns>true if the attach suceeded, false if it did not</returns>
|
||||||
public bool AttachToAvatar(int attachmentPoint)
|
public bool AttachToAvatar(int attachmentPoint)
|
||||||
{
|
{
|
||||||
|
@ -3133,19 +3160,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
msg.ParentEstateID = 0; //ParentEstateID;
|
msg.ParentEstateID = 0; //ParentEstateID;
|
||||||
msg.Position = new Vector3(m_host.AbsolutePosition);
|
msg.Position = new Vector3(m_host.AbsolutePosition);
|
||||||
msg.RegionID = World.RegionInfo.RegionID.Guid;//RegionID.Guid;
|
msg.RegionID = World.RegionInfo.RegionID.Guid;//RegionID.Guid;
|
||||||
msg.binaryBucket
|
msg.binaryBucket
|
||||||
= Util.StringToBytes256(
|
= Util.StringToBytes256(
|
||||||
"{0}/{1}/{2}/{3}",
|
"{0}/{1}/{2}/{3}",
|
||||||
World.RegionInfo.RegionName,
|
World.RegionInfo.RegionName,
|
||||||
(int)Math.Floor(m_host.AbsolutePosition.X),
|
(int)Math.Floor(m_host.AbsolutePosition.X),
|
||||||
(int)Math.Floor(m_host.AbsolutePosition.Y),
|
(int)Math.Floor(m_host.AbsolutePosition.Y),
|
||||||
(int)Math.Floor(m_host.AbsolutePosition.Z));
|
(int)Math.Floor(m_host.AbsolutePosition.Z));
|
||||||
|
|
||||||
if (m_TransferModule != null)
|
if (m_TransferModule != null)
|
||||||
{
|
{
|
||||||
m_TransferModule.SendInstantMessage(msg, delegate(bool success) {});
|
m_TransferModule.SendInstantMessage(msg, delegate(bool success) {});
|
||||||
}
|
}
|
||||||
|
|
||||||
ScriptSleep(2000);
|
ScriptSleep(2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3270,7 +3297,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
public void llRotLookAt(LSL_Rotation target, double strength, double damping)
|
public void llRotLookAt(LSL_Rotation target, double strength, double damping)
|
||||||
{
|
{
|
||||||
m_host.AddScriptLPS(1);
|
m_host.AddScriptLPS(1);
|
||||||
|
|
||||||
// Per discussion with Melanie, for non-physical objects llLookAt appears to simply
|
// Per discussion with Melanie, for non-physical objects llLookAt appears to simply
|
||||||
// set the rotation of the object, copy that behavior
|
// set the rotation of the object, copy that behavior
|
||||||
PhysicsActor pa = m_host.PhysActor;
|
PhysicsActor pa = m_host.PhysActor;
|
||||||
|
@ -3339,7 +3366,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
if (animID == UUID.Zero)
|
if (animID == UUID.Zero)
|
||||||
presence.Animator.RemoveAnimation(anim);
|
presence.Animator.RemoveAnimation(anim);
|
||||||
else
|
else
|
||||||
presence.Animator.RemoveAnimation(animID);
|
presence.Animator.RemoveAnimation(animID, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3410,21 +3437,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bool sitting = false;
|
if (m_host.ParentGroup.GetSittingAvatars().Contains(agentID))
|
||||||
if (m_host.SitTargetAvatar == agentID)
|
|
||||||
{
|
|
||||||
sitting = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (SceneObjectPart p in m_host.ParentGroup.Parts)
|
|
||||||
{
|
|
||||||
if (p.SitTargetAvatar == agentID)
|
|
||||||
sitting = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sitting)
|
|
||||||
{
|
{
|
||||||
// When agent is sitting, certain permissions are implicit if requested from sitting agent
|
// When agent is sitting, certain permissions are implicit if requested from sitting agent
|
||||||
implicitPerms = ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION |
|
implicitPerms = ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION |
|
||||||
|
@ -3463,7 +3476,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
INPCModule npcModule = World.RequestModuleInterface<INPCModule>();
|
INPCModule npcModule = World.RequestModuleInterface<INPCModule>();
|
||||||
if (npcModule != null && npcModule.IsNPC(agentID, World))
|
if (npcModule != null && npcModule.IsNPC(agentID, World))
|
||||||
{
|
{
|
||||||
if (agentID == m_host.ParentGroup.OwnerID || npcModule.GetOwner(agentID) == m_host.ParentGroup.OwnerID)
|
if (npcModule.CheckPermissions(agentID, m_host.OwnerID))
|
||||||
{
|
{
|
||||||
lock (m_host.TaskInventory)
|
lock (m_host.TaskInventory)
|
||||||
{
|
{
|
||||||
|
@ -3736,33 +3749,47 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
public LSL_String llGetLinkKey(int linknum)
|
public LSL_String llGetLinkKey(int linknum)
|
||||||
{
|
{
|
||||||
m_host.AddScriptLPS(1);
|
m_host.AddScriptLPS(1);
|
||||||
List<UUID> keytable = new List<UUID>();
|
|
||||||
// parse for sitting avatare-uuids
|
|
||||||
World.ForEachRootScenePresence(delegate(ScenePresence presence)
|
|
||||||
{
|
|
||||||
if (presence.ParentID != 0 && m_host.ParentGroup.ContainsPart(presence.ParentID))
|
|
||||||
keytable.Add(presence.UUID);
|
|
||||||
});
|
|
||||||
|
|
||||||
int totalprims = m_host.ParentGroup.PrimCount + keytable.Count;
|
if (linknum < 0)
|
||||||
if (linknum > m_host.ParentGroup.PrimCount && linknum <= totalprims)
|
|
||||||
{
|
{
|
||||||
return keytable[totalprims - linknum].ToString();
|
if (linknum == ScriptBaseClass.LINK_THIS)
|
||||||
|
return m_host.UUID.ToString();
|
||||||
|
else
|
||||||
|
return ScriptBaseClass.NULL_KEY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (linknum == 1 && m_host.ParentGroup.PrimCount == 1 && keytable.Count == 1)
|
int actualPrimCount = m_host.ParentGroup.PrimCount;
|
||||||
{
|
List<UUID> sittingAvatarIds = m_host.ParentGroup.GetSittingAvatars();
|
||||||
return m_host.UUID.ToString();
|
int adjustedPrimCount = actualPrimCount + sittingAvatarIds.Count;
|
||||||
}
|
|
||||||
|
|
||||||
SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(linknum);
|
// Special case for a single prim. In this case the linknum is zero. However, this will not match a single
|
||||||
if (part != null)
|
// prim that has any avatars sat upon it (in which case the root prim is link 1).
|
||||||
|
if (linknum == 0)
|
||||||
{
|
{
|
||||||
return part.UUID.ToString();
|
if (actualPrimCount == 1 && sittingAvatarIds.Count == 0)
|
||||||
|
return m_host.UUID.ToString();
|
||||||
|
|
||||||
|
return ScriptBaseClass.NULL_KEY;
|
||||||
|
}
|
||||||
|
// Special case to handle a single prim with sitting avatars. GetLinkPart() would only match zero but
|
||||||
|
// here we must match 1 (ScriptBaseClass.LINK_ROOT).
|
||||||
|
else if (linknum == 1 && actualPrimCount == 1)
|
||||||
|
{
|
||||||
|
if (sittingAvatarIds.Count > 0)
|
||||||
|
return m_host.ParentGroup.RootPart.UUID.ToString();
|
||||||
|
else
|
||||||
|
return ScriptBaseClass.NULL_KEY;
|
||||||
|
}
|
||||||
|
else if (linknum <= adjustedPrimCount)
|
||||||
|
{
|
||||||
|
if (linknum <= actualPrimCount)
|
||||||
|
return m_host.ParentGroup.GetLinkNumPart(linknum).UUID.ToString();
|
||||||
|
else
|
||||||
|
return sittingAvatarIds[linknum - actualPrimCount - 1].ToString();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return UUID.Zero.ToString();
|
return ScriptBaseClass.NULL_KEY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3808,62 +3835,56 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
public LSL_String llGetLinkName(int linknum)
|
public LSL_String llGetLinkName(int linknum)
|
||||||
{
|
{
|
||||||
m_host.AddScriptLPS(1);
|
m_host.AddScriptLPS(1);
|
||||||
// simplest case, this prims link number
|
|
||||||
if (linknum == m_host.LinkNum || linknum == ScriptBaseClass.LINK_THIS)
|
|
||||||
return m_host.Name;
|
|
||||||
|
|
||||||
// parse for sitting avatare-names
|
if (linknum < 0)
|
||||||
List<String> nametable = new List<String>();
|
|
||||||
World.ForEachRootScenePresence(delegate(ScenePresence presence)
|
|
||||||
{
|
{
|
||||||
SceneObjectPart sitPart = presence.ParentPart;
|
if (linknum == ScriptBaseClass.LINK_THIS)
|
||||||
if (sitPart != null && m_host.ParentGroup.ContainsPart(sitPart.LocalId))
|
|
||||||
nametable.Add(presence.ControllingClient.Name);
|
|
||||||
});
|
|
||||||
|
|
||||||
int totalprims = m_host.ParentGroup.PrimCount + nametable.Count;
|
|
||||||
if (totalprims > m_host.ParentGroup.PrimCount)
|
|
||||||
{
|
|
||||||
// sitting Avatar-Name with negativ linknum / SinglePrim
|
|
||||||
if (linknum < 0 && m_host.ParentGroup.PrimCount == 1 && nametable.Count == 1)
|
|
||||||
return nametable[0];
|
|
||||||
// Prim-Name / SinglePrim Sitting Avatar
|
|
||||||
if (linknum == 1 && m_host.ParentGroup.PrimCount == 1 && nametable.Count == 1)
|
|
||||||
return m_host.Name;
|
|
||||||
// LinkNumber > of Real PrimSet = AvatarName
|
|
||||||
if (linknum > m_host.ParentGroup.PrimCount && linknum <= totalprims)
|
|
||||||
return nametable[totalprims - linknum];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Single prim
|
|
||||||
if (m_host.LinkNum == 0)
|
|
||||||
{
|
|
||||||
if (linknum == 0 || linknum == ScriptBaseClass.LINK_ROOT)
|
|
||||||
return m_host.Name;
|
return m_host.Name;
|
||||||
else
|
else
|
||||||
return UUID.Zero.ToString();
|
return ScriptBaseClass.NULL_KEY;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Link set
|
int actualPrimCount = m_host.ParentGroup.PrimCount;
|
||||||
SceneObjectPart part = null;
|
List<UUID> sittingAvatarIds = m_host.ParentGroup.GetSittingAvatars();
|
||||||
if (m_host.LinkNum == 1) // this is the Root prim
|
int adjustedPrimCount = actualPrimCount + sittingAvatarIds.Count;
|
||||||
|
|
||||||
|
// Special case for a single prim. In this case the linknum is zero. However, this will not match a single
|
||||||
|
// prim that has any avatars sat upon it (in which case the root prim is link 1).
|
||||||
|
if (linknum == 0)
|
||||||
{
|
{
|
||||||
if (linknum < 0)
|
if (actualPrimCount == 1 && sittingAvatarIds.Count == 0)
|
||||||
part = m_host.ParentGroup.GetLinkNumPart(2);
|
return m_host.Name;
|
||||||
else
|
|
||||||
part = m_host.ParentGroup.GetLinkNumPart(linknum);
|
return ScriptBaseClass.NULL_KEY;
|
||||||
}
|
}
|
||||||
else // this is a child prim
|
// Special case to handle a single prim with sitting avatars. GetLinkPart() would only match zero but
|
||||||
|
// here we must match 1 (ScriptBaseClass.LINK_ROOT).
|
||||||
|
else if (linknum == 1 && actualPrimCount == 1)
|
||||||
{
|
{
|
||||||
if (linknum < 2)
|
if (sittingAvatarIds.Count > 0)
|
||||||
part = m_host.ParentGroup.GetLinkNumPart(1);
|
return m_host.ParentGroup.RootPart.Name;
|
||||||
else
|
else
|
||||||
part = m_host.ParentGroup.GetLinkNumPart(linknum);
|
return ScriptBaseClass.NULL_KEY;
|
||||||
|
}
|
||||||
|
else if (linknum <= adjustedPrimCount)
|
||||||
|
{
|
||||||
|
if (linknum <= actualPrimCount)
|
||||||
|
{
|
||||||
|
return m_host.ParentGroup.GetLinkNumPart(linknum).Name;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ScenePresence sp = World.GetScenePresence(sittingAvatarIds[linknum - actualPrimCount - 1]);
|
||||||
|
if (sp != null)
|
||||||
|
return sp.Name;
|
||||||
|
else
|
||||||
|
return ScriptBaseClass.NULL_KEY;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (part != null)
|
|
||||||
return part.Name;
|
|
||||||
else
|
else
|
||||||
return UUID.Zero.ToString();
|
{
|
||||||
|
return ScriptBaseClass.NULL_KEY;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public LSL_Integer llGetInventoryNumber(int type)
|
public LSL_Integer llGetInventoryNumber(int type)
|
||||||
|
@ -4350,7 +4371,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
public void llCollisionSound(string impact_sound, double impact_volume)
|
public void llCollisionSound(string impact_sound, double impact_volume)
|
||||||
{
|
{
|
||||||
m_host.AddScriptLPS(1);
|
m_host.AddScriptLPS(1);
|
||||||
|
|
||||||
// TODO: Parameter check logic required.
|
// TODO: Parameter check logic required.
|
||||||
m_host.CollisionSound = KeyOrName(impact_sound, AssetType.Sound);
|
m_host.CollisionSound = KeyOrName(impact_sound, AssetType.Sound);
|
||||||
m_host.CollisionSoundVolume = (float)impact_volume;
|
m_host.CollisionSoundVolume = (float)impact_volume;
|
||||||
|
@ -5040,7 +5061,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
// SL spits out an empty string for types other than key & string
|
// SL spits out an empty string for types other than key & string
|
||||||
// At the time of patching, LSL_Key is currently LSL_String,
|
// At the time of patching, LSL_Key is currently LSL_String,
|
||||||
// so the OR check may be a little redundant, but it's being done
|
// so the OR check may be a little redundant, but it's being done
|
||||||
// for completion and should LSL_Key ever be implemented
|
// for completion and should LSL_Key ever be implemented
|
||||||
// as it's own struct
|
// as it's own struct
|
||||||
else if (!(src.Data[index] is LSL_String ||
|
else if (!(src.Data[index] is LSL_String ||
|
||||||
src.Data[index] is LSL_Key))
|
src.Data[index] is LSL_Key))
|
||||||
|
@ -5176,8 +5197,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
{
|
{
|
||||||
m_host.AddScriptLPS(1);
|
m_host.AddScriptLPS(1);
|
||||||
|
|
||||||
return string.Join(", ",
|
return string.Join(", ",
|
||||||
(new List<object>(src.Data)).ConvertAll<string>(o =>
|
(new List<object>(src.Data)).ConvertAll<string>(o =>
|
||||||
{
|
{
|
||||||
return o.ToString();
|
return o.ToString();
|
||||||
}).ToArray());
|
}).ToArray());
|
||||||
|
@ -5418,9 +5439,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Insert the list identified by <src> into the
|
/// Insert the list identified by <paramref name="src"/> into the
|
||||||
/// list designated by <dest> such that the first
|
/// list designated by <paramref name="dest"/> such that the first
|
||||||
/// new element has the index specified by <index>
|
/// new element has the index specified by <paramref name="index"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
||||||
public LSL_List llListInsertList(LSL_List dest, LSL_List src, int index)
|
public LSL_List llListInsertList(LSL_List dest, LSL_List src, int index)
|
||||||
|
@ -5774,13 +5795,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
if (parcelOwned && land.LandData.OwnerID == id ||
|
if (parcelOwned && land.LandData.OwnerID == id ||
|
||||||
parcel && land.LandData.GlobalID == id)
|
parcel && land.LandData.GlobalID == id)
|
||||||
{
|
{
|
||||||
result.Add(ssp.UUID.ToString());
|
result.Add(new LSL_Key(ssp.UUID.ToString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
result.Add(ssp.UUID.ToString());
|
result.Add(new LSL_Key(ssp.UUID.ToString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Maximum of 100 results
|
// Maximum of 100 results
|
||||||
|
@ -6198,6 +6219,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
ps.BurstSpeedMax = 1.0f;
|
ps.BurstSpeedMax = 1.0f;
|
||||||
ps.BurstRate = 0.1f;
|
ps.BurstRate = 0.1f;
|
||||||
ps.PartMaxAge = 10.0f;
|
ps.PartMaxAge = 10.0f;
|
||||||
|
ps.BurstPartCount = 1;
|
||||||
return ps;
|
return ps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6219,9 +6241,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
SetParticleSystem(m_host, rules);
|
SetParticleSystem(m_host, rules);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetParticleSystem(SceneObjectPart part, LSL_List rules) {
|
private void SetParticleSystem(SceneObjectPart part, LSL_List rules)
|
||||||
|
{
|
||||||
|
|
||||||
if (rules.Length == 0)
|
if (rules.Length == 0)
|
||||||
{
|
{
|
||||||
part.RemoveParticleSystem();
|
part.RemoveParticleSystem();
|
||||||
|
@ -6457,7 +6478,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
m_host.OwnerID, m_host.Name, destID,
|
m_host.OwnerID, m_host.Name, destID,
|
||||||
(byte)InstantMessageDialog.TaskInventoryOffered,
|
(byte)InstantMessageDialog.TaskInventoryOffered,
|
||||||
false, string.Format("'{0}'", category),
|
false, string.Format("'{0}'", category),
|
||||||
// We won't go so far as to add a SLURL, but this is the format used by LL as of 2012-10-06
|
// We won't go so far as to add a SLURL, but this is the format used by LL as of 2012-10-06
|
||||||
// false, string.Format("'{0}' ( http://slurl.com/secondlife/{1}/{2}/{3}/{4} )", category, World.Name, (int)pos.X, (int)pos.Y, (int)pos.Z),
|
// false, string.Format("'{0}' ( http://slurl.com/secondlife/{1}/{2}/{3}/{4} )", category, World.Name, (int)pos.X, (int)pos.Y, (int)pos.Z),
|
||||||
folderID, false, pos,
|
folderID, false, pos,
|
||||||
bucket, false);
|
bucket, false);
|
||||||
|
@ -6572,12 +6593,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
public LSL_String llAvatarOnLinkSitTarget(int linknum)
|
public LSL_String llAvatarOnLinkSitTarget(int linknum)
|
||||||
{
|
{
|
||||||
m_host.AddScriptLPS(1);
|
m_host.AddScriptLPS(1);
|
||||||
if(linknum == ScriptBaseClass.LINK_SET ||
|
if(linknum == ScriptBaseClass.LINK_SET ||
|
||||||
linknum == ScriptBaseClass.LINK_ALL_CHILDREN ||
|
linknum == ScriptBaseClass.LINK_ALL_CHILDREN ||
|
||||||
linknum == ScriptBaseClass.LINK_ALL_OTHERS) return UUID.Zero.ToString();
|
linknum == ScriptBaseClass.LINK_ALL_OTHERS) return UUID.Zero.ToString();
|
||||||
|
|
||||||
List<SceneObjectPart> parts = GetLinkParts(linknum);
|
List<SceneObjectPart> parts = GetLinkParts(linknum);
|
||||||
if (parts.Count == 0) return UUID.Zero.ToString();
|
if (parts.Count == 0) return UUID.Zero.ToString();
|
||||||
return parts[0].SitTargetAvatar.ToString();
|
return parts[0].SitTargetAvatar.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6949,7 +6970,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
hollow = 0.70f;
|
hollow = 0.70f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Otherwise, hollow is limited to 95%.
|
// Otherwise, hollow is limited to 95%.
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (hollow > 0.95f)
|
if (hollow > 0.95f)
|
||||||
|
@ -7881,14 +7902,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
public LSL_Integer llGetNumberOfPrims()
|
public LSL_Integer llGetNumberOfPrims()
|
||||||
{
|
{
|
||||||
m_host.AddScriptLPS(1);
|
m_host.AddScriptLPS(1);
|
||||||
int avatarCount = 0;
|
|
||||||
World.ForEachRootScenePresence(delegate(ScenePresence presence)
|
|
||||||
{
|
|
||||||
if (presence.ParentID != 0 && m_host.ParentGroup.ContainsPart(presence.ParentID))
|
|
||||||
avatarCount++;
|
|
||||||
});
|
|
||||||
|
|
||||||
return m_host.ParentGroup.PrimCount + avatarCount;
|
return m_host.ParentGroup.PrimCount + m_host.ParentGroup.GetSittingAvatarsCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -8136,16 +8151,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
res.Add(new LSL_Vector(Shape.PathTaperX / 100.0, Shape.PathTaperY / 100.0, 0));
|
res.Add(new LSL_Vector(Shape.PathTaperX / 100.0, Shape.PathTaperY / 100.0, 0));
|
||||||
|
|
||||||
// float revolutions
|
// float revolutions
|
||||||
res.Add(new LSL_Float(Math.Round(Shape.PathRevolutions * 0.015d, 2, MidpointRounding.AwayFromZero)) + 1.0d);
|
res.Add(new LSL_Float(Math.Round(Shape.PathRevolutions * 0.015d, 2, MidpointRounding.AwayFromZero)) + 1.0d);
|
||||||
// Slightly inaccurate, because an unsigned byte is being used to represent
|
// Slightly inaccurate, because an unsigned byte is being used to represent
|
||||||
// the entire range of floating-point values from 1.0 through 4.0 (which is how
|
// the entire range of floating-point values from 1.0 through 4.0 (which is how
|
||||||
// SL does it).
|
// SL does it).
|
||||||
//
|
//
|
||||||
// Using these formulas to store and retrieve PathRevolutions, it is not
|
// Using these formulas to store and retrieve PathRevolutions, it is not
|
||||||
// possible to use all values between 1.00 and 4.00. For instance, you can't
|
// possible to use all values between 1.00 and 4.00. For instance, you can't
|
||||||
// represent 1.10. You can represent 1.09 and 1.11, but not 1.10. So, if you
|
// represent 1.10. You can represent 1.09 and 1.11, but not 1.10. So, if you
|
||||||
// use llSetPrimitiveParams to set revolutions to 1.10 and then retreive them
|
// use llSetPrimitiveParams to set revolutions to 1.10 and then retreive them
|
||||||
// with llGetPrimitiveParams, you'll retrieve 1.09. You can also see a similar
|
// with llGetPrimitiveParams, you'll retrieve 1.09. You can also see a similar
|
||||||
// behavior in the viewer as you cannot set 1.10. The viewer jumps to 1.11.
|
// behavior in the viewer as you cannot set 1.10. The viewer jumps to 1.11.
|
||||||
// In SL, llSetPrimitveParams and llGetPrimitiveParams can set and get a value
|
// In SL, llSetPrimitveParams and llGetPrimitiveParams can set and get a value
|
||||||
// such as 1.10. So, SL must store and retreive the actual user input rather
|
// such as 1.10. So, SL must store and retreive the actual user input rather
|
||||||
|
@ -10267,9 +10282,60 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
IHttpRequestModule httpScriptMod =
|
IHttpRequestModule httpScriptMod =
|
||||||
m_ScriptEngine.World.RequestModuleInterface<IHttpRequestModule>();
|
m_ScriptEngine.World.RequestModuleInterface<IHttpRequestModule>();
|
||||||
List<string> param = new List<string>();
|
List<string> param = new List<string>();
|
||||||
foreach (object o in parameters.Data)
|
bool ok;
|
||||||
|
Int32 flag;
|
||||||
|
|
||||||
|
for (int i = 0; i < parameters.Data.Length; i += 2)
|
||||||
{
|
{
|
||||||
param.Add(o.ToString());
|
ok = Int32.TryParse(parameters.Data[i].ToString(), out flag);
|
||||||
|
if (!ok || flag < 0 ||
|
||||||
|
flag > (int)HttpRequestConstants.HTTP_PRAGMA_NO_CACHE)
|
||||||
|
{
|
||||||
|
throw new ScriptException("Parameter " + i.ToString() + " is an invalid flag");
|
||||||
|
}
|
||||||
|
|
||||||
|
param.Add(parameters.Data[i].ToString()); //Add parameter flag
|
||||||
|
|
||||||
|
if (flag != (int)HttpRequestConstants.HTTP_CUSTOM_HEADER)
|
||||||
|
{
|
||||||
|
param.Add(parameters.Data[i+1].ToString()); //Add parameter value
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Parameters are in pairs and custom header takes
|
||||||
|
//arguments in pairs so adjust for header marker.
|
||||||
|
++i;
|
||||||
|
|
||||||
|
//Maximum of 8 headers are allowed based on the
|
||||||
|
//Second Life documentation for llHTTPRequest.
|
||||||
|
for (int count = 1; count <= 8; ++count)
|
||||||
|
{
|
||||||
|
//Enough parameters remaining for (another) header?
|
||||||
|
if (parameters.Data.Length - i < 2)
|
||||||
|
{
|
||||||
|
//There must be at least one name/value pair for custom header
|
||||||
|
if (count == 1)
|
||||||
|
throw new ScriptException("Missing name/value for custom header at parameter " + i.ToString());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HttpStandardHeaders.Contains(parameters.Data[i].ToString(), StringComparer.OrdinalIgnoreCase))
|
||||||
|
throw new ScriptException("Name is invalid as a custom header at parameter " + i.ToString());
|
||||||
|
|
||||||
|
param.Add(parameters.Data[i].ToString());
|
||||||
|
param.Add(parameters.Data[i+1].ToString());
|
||||||
|
|
||||||
|
//Have we reached the end of the list of headers?
|
||||||
|
//End is marked by a string with a single digit.
|
||||||
|
if (i+2 >= parameters.Data.Length ||
|
||||||
|
Char.IsDigit(parameters.Data[i].ToString()[0]))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
i += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 position = m_host.AbsolutePosition;
|
Vector3 position = m_host.AbsolutePosition;
|
||||||
|
@ -10379,12 +10445,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
public LSL_Integer llGetParcelPrimCount(LSL_Vector pos, int category, int sim_wide)
|
public LSL_Integer llGetParcelPrimCount(LSL_Vector pos, int category, int sim_wide)
|
||||||
{
|
{
|
||||||
m_host.AddScriptLPS(1);
|
m_host.AddScriptLPS(1);
|
||||||
|
|
||||||
ILandObject lo = World.LandChannel.GetLandObject((float)pos.x, (float)pos.y);
|
ILandObject lo = World.LandChannel.GetLandObject((float)pos.x, (float)pos.y);
|
||||||
|
|
||||||
if (lo == null)
|
if (lo == null)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
IPrimCounts pc = lo.PrimCounts;
|
IPrimCounts pc = lo.PrimCounts;
|
||||||
|
|
||||||
if (sim_wide != ScriptBaseClass.FALSE)
|
if (sim_wide != ScriptBaseClass.FALSE)
|
||||||
|
@ -10414,7 +10480,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
else if (category == ScriptBaseClass.PARCEL_COUNT_TEMP)
|
else if (category == ScriptBaseClass.PARCEL_COUNT_TEMP)
|
||||||
return 0; // counts not implemented yet
|
return 0; // counts not implemented yet
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10577,6 +10643,35 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
case ScriptBaseClass.OBJECT_PHYSICS_COST:
|
case ScriptBaseClass.OBJECT_PHYSICS_COST:
|
||||||
ret.Add(new LSL_Float(0));
|
ret.Add(new LSL_Float(0));
|
||||||
break;
|
break;
|
||||||
|
case ScriptBaseClass.OBJECT_CHARACTER_TIME: // Pathfinding
|
||||||
|
ret.Add(new LSL_Float(0));
|
||||||
|
break;
|
||||||
|
case ScriptBaseClass.OBJECT_ROOT:
|
||||||
|
SceneObjectPart p = av.ParentPart;
|
||||||
|
if (p != null)
|
||||||
|
{
|
||||||
|
ret.Add(new LSL_String(p.ParentGroup.RootPart.UUID.ToString()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret.Add(new LSL_String(id));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ScriptBaseClass.OBJECT_ATTACHED_POINT:
|
||||||
|
ret.Add(new LSL_Integer(0));
|
||||||
|
break;
|
||||||
|
case ScriptBaseClass.OBJECT_PATHFINDING_TYPE: // Pathfinding
|
||||||
|
ret.Add(new LSL_Integer(ScriptBaseClass.OPT_AVATAR));
|
||||||
|
break;
|
||||||
|
case ScriptBaseClass.OBJECT_PHYSICS:
|
||||||
|
ret.Add(new LSL_Integer(0));
|
||||||
|
break;
|
||||||
|
case ScriptBaseClass.OBJECT_PHANTOM:
|
||||||
|
ret.Add(new LSL_Integer(0));
|
||||||
|
break;
|
||||||
|
case ScriptBaseClass.OBJECT_TEMP_ON_REZ:
|
||||||
|
ret.Add(new LSL_Integer(0));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
// Invalid or unhandled constant.
|
// Invalid or unhandled constant.
|
||||||
ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL));
|
ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL));
|
||||||
|
@ -10672,6 +10767,52 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
// The value returned in SL for normal prims looks like the prim count
|
// The value returned in SL for normal prims looks like the prim count
|
||||||
ret.Add(new LSL_Float(0));
|
ret.Add(new LSL_Float(0));
|
||||||
break;
|
break;
|
||||||
|
case ScriptBaseClass.OBJECT_CHARACTER_TIME: // Pathfinding
|
||||||
|
ret.Add(new LSL_Float(0));
|
||||||
|
break;
|
||||||
|
case ScriptBaseClass.OBJECT_ROOT:
|
||||||
|
ret.Add(new LSL_String(obj.ParentGroup.RootPart.UUID.ToString()));
|
||||||
|
break;
|
||||||
|
case ScriptBaseClass.OBJECT_ATTACHED_POINT:
|
||||||
|
ret.Add(new LSL_Integer(obj.ParentGroup.AttachmentPoint));
|
||||||
|
break;
|
||||||
|
case ScriptBaseClass.OBJECT_PATHFINDING_TYPE:
|
||||||
|
byte pcode = obj.Shape.PCode;
|
||||||
|
if (obj.ParentGroup.AttachmentPoint != 0
|
||||||
|
|| pcode == (byte)PCode.Grass
|
||||||
|
|| pcode == (byte)PCode.Tree
|
||||||
|
|| pcode == (byte)PCode.NewTree)
|
||||||
|
{
|
||||||
|
ret.Add(new LSL_Integer(ScriptBaseClass.OPT_OTHER));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret.Add(new LSL_Integer(ScriptBaseClass.OPT_LEGACY_LINKSET));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ScriptBaseClass.OBJECT_PHYSICS:
|
||||||
|
if (obj.ParentGroup.AttachmentPoint != 0)
|
||||||
|
{
|
||||||
|
ret.Add(new LSL_Integer(0)); // Always false if attached
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret.Add(new LSL_Integer(obj.ParentGroup.UsesPhysics ? 1 : 0));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ScriptBaseClass.OBJECT_PHANTOM:
|
||||||
|
if (obj.ParentGroup.AttachmentPoint != 0)
|
||||||
|
{
|
||||||
|
ret.Add(new LSL_Integer(0)); // Always false if attached
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret.Add(new LSL_Integer(obj.ParentGroup.IsPhantom ? 1 : 0));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ScriptBaseClass.OBJECT_TEMP_ON_REZ:
|
||||||
|
ret.Add(new LSL_Integer(obj.ParentGroup.IsTemporary ? 1 : 0));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
// Invalid or unhandled constant.
|
// Invalid or unhandled constant.
|
||||||
ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL));
|
ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL));
|
||||||
|
@ -10682,7 +10823,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new LSL_List();
|
return new LSL_List();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11309,7 +11450,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ScenePresence sp = World.GetScenePresence(result.ConsumerID);
|
ScenePresence sp = World.GetScenePresence(result.ConsumerID);
|
||||||
/// It it a boy? a girl?
|
/// It it a boy? a girl?
|
||||||
if (sp != null)
|
if (sp != null)
|
||||||
itemID = sp.UUID;
|
itemID = sp.UUID;
|
||||||
}
|
}
|
||||||
|
@ -11520,7 +11661,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
/// Get a notecard line.
|
/// Get a notecard line.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="assetID"></param>
|
/// <param name="assetID"></param>
|
||||||
/// <param name="line">Lines start at index 0</param>
|
/// <param name="lineNumber">Lines start at index 0</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static string GetLine(UUID assetID, int lineNumber)
|
public static string GetLine(UUID assetID, int lineNumber)
|
||||||
{
|
{
|
||||||
|
@ -11549,9 +11690,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
/// Get a notecard line.
|
/// Get a notecard line.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="assetID"></param>
|
/// <param name="assetID"></param>
|
||||||
/// <param name="line">Lines start at index 0</param>
|
/// <param name="lineNumber">Lines start at index 0</param>
|
||||||
/// <param name="maxLength">Maximum length of the returned line. Longer lines will be truncated</para>
|
/// <param name="maxLength">
|
||||||
/// <returns></returns>
|
/// Maximum length of the returned line.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>
|
||||||
|
/// If the line length is longer than <paramref name="maxLength"/>,
|
||||||
|
/// the return string will be truncated.
|
||||||
|
/// </returns>
|
||||||
public static string GetLine(UUID assetID, int lineNumber, int maxLength)
|
public static string GetLine(UUID assetID, int lineNumber, int maxLength)
|
||||||
{
|
{
|
||||||
string line = GetLine(assetID, lineNumber);
|
string line = GetLine(assetID, lineNumber);
|
||||||
|
|
|
@ -974,7 +974,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
if (animID == UUID.Zero)
|
if (animID == UUID.Zero)
|
||||||
target.Animator.RemoveAnimation(animation);
|
target.Animator.RemoveAnimation(animation);
|
||||||
else
|
else
|
||||||
target.Animator.RemoveAnimation(animID);
|
target.Animator.RemoveAnimation(animID, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,29 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
|
||||||
{
|
{
|
||||||
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used by one-off and repeated sensors
|
||||||
|
/// </summary>
|
||||||
|
public class SensorInfo
|
||||||
|
{
|
||||||
|
public uint localID;
|
||||||
|
public UUID itemID;
|
||||||
|
public double interval;
|
||||||
|
public DateTime next;
|
||||||
|
|
||||||
|
public string name;
|
||||||
|
public UUID keyID;
|
||||||
|
public int type;
|
||||||
|
public double range;
|
||||||
|
public double arc;
|
||||||
|
public SceneObjectPart host;
|
||||||
|
|
||||||
|
public SensorInfo Clone()
|
||||||
|
{
|
||||||
|
return (SensorInfo)this.MemberwiseClone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public AsyncCommandManager m_CmdManager;
|
public AsyncCommandManager m_CmdManager;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -78,24 +101,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
|
||||||
private double maximumRange = 96.0;
|
private double maximumRange = 96.0;
|
||||||
private int maximumToReturn = 16;
|
private int maximumToReturn = 16;
|
||||||
|
|
||||||
//
|
|
||||||
// SenseRepeater and Sensors
|
|
||||||
//
|
|
||||||
private class SenseRepeatClass
|
|
||||||
{
|
|
||||||
public uint localID;
|
|
||||||
public UUID itemID;
|
|
||||||
public double interval;
|
|
||||||
public DateTime next;
|
|
||||||
|
|
||||||
public string name;
|
|
||||||
public UUID keyID;
|
|
||||||
public int type;
|
|
||||||
public double range;
|
|
||||||
public double arc;
|
|
||||||
public SceneObjectPart host;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Sensed entity
|
// Sensed entity
|
||||||
//
|
//
|
||||||
|
@ -128,7 +133,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
|
||||||
///
|
///
|
||||||
/// Always lock SenseRepeatListLock when updating this list.
|
/// Always lock SenseRepeatListLock when updating this list.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
private List<SenseRepeatClass> SenseRepeaters = new List<SenseRepeatClass>();
|
private List<SensorInfo> SenseRepeaters = new List<SensorInfo>();
|
||||||
private object SenseRepeatListLock = new object();
|
private object SenseRepeatListLock = new object();
|
||||||
|
|
||||||
public void SetSenseRepeatEvent(uint m_localID, UUID m_itemID,
|
public void SetSenseRepeatEvent(uint m_localID, UUID m_itemID,
|
||||||
|
@ -142,7 +147,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Add to timer
|
// Add to timer
|
||||||
SenseRepeatClass ts = new SenseRepeatClass();
|
SensorInfo ts = new SensorInfo();
|
||||||
ts.localID = m_localID;
|
ts.localID = m_localID;
|
||||||
ts.itemID = m_itemID;
|
ts.itemID = m_itemID;
|
||||||
ts.interval = sec;
|
ts.interval = sec;
|
||||||
|
@ -161,11 +166,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
|
||||||
AddSenseRepeater(ts);
|
AddSenseRepeater(ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddSenseRepeater(SenseRepeatClass senseRepeater)
|
private void AddSenseRepeater(SensorInfo senseRepeater)
|
||||||
{
|
{
|
||||||
lock (SenseRepeatListLock)
|
lock (SenseRepeatListLock)
|
||||||
{
|
{
|
||||||
List<SenseRepeatClass> newSenseRepeaters = new List<SenseRepeatClass>(SenseRepeaters);
|
List<SensorInfo> newSenseRepeaters = new List<SensorInfo>(SenseRepeaters);
|
||||||
newSenseRepeaters.Add(senseRepeater);
|
newSenseRepeaters.Add(senseRepeater);
|
||||||
SenseRepeaters = newSenseRepeaters;
|
SenseRepeaters = newSenseRepeaters;
|
||||||
}
|
}
|
||||||
|
@ -176,8 +181,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
|
||||||
// Remove from timer
|
// Remove from timer
|
||||||
lock (SenseRepeatListLock)
|
lock (SenseRepeatListLock)
|
||||||
{
|
{
|
||||||
List<SenseRepeatClass> newSenseRepeaters = new List<SenseRepeatClass>();
|
List<SensorInfo> newSenseRepeaters = new List<SensorInfo>();
|
||||||
foreach (SenseRepeatClass ts in SenseRepeaters)
|
foreach (SensorInfo ts in SenseRepeaters)
|
||||||
{
|
{
|
||||||
if (ts.localID != m_localID || ts.itemID != m_itemID)
|
if (ts.localID != m_localID || ts.itemID != m_itemID)
|
||||||
{
|
{
|
||||||
|
@ -192,7 +197,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
|
||||||
public void CheckSenseRepeaterEvents()
|
public void CheckSenseRepeaterEvents()
|
||||||
{
|
{
|
||||||
// Go through all timers
|
// Go through all timers
|
||||||
foreach (SenseRepeatClass ts in SenseRepeaters)
|
foreach (SensorInfo ts in SenseRepeaters)
|
||||||
{
|
{
|
||||||
// Time has passed?
|
// Time has passed?
|
||||||
if (ts.next.ToUniversalTime() < DateTime.Now.ToUniversalTime())
|
if (ts.next.ToUniversalTime() < DateTime.Now.ToUniversalTime())
|
||||||
|
@ -209,7 +214,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
|
||||||
double range, double arc, SceneObjectPart host)
|
double range, double arc, SceneObjectPart host)
|
||||||
{
|
{
|
||||||
// Add to timer
|
// Add to timer
|
||||||
SenseRepeatClass ts = new SenseRepeatClass();
|
SensorInfo ts = new SensorInfo();
|
||||||
ts.localID = m_localID;
|
ts.localID = m_localID;
|
||||||
ts.itemID = m_itemID;
|
ts.itemID = m_itemID;
|
||||||
ts.interval = 0;
|
ts.interval = 0;
|
||||||
|
@ -225,7 +230,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
|
||||||
SensorSweep(ts);
|
SensorSweep(ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SensorSweep(SenseRepeatClass ts)
|
private void SensorSweep(SensorInfo ts)
|
||||||
{
|
{
|
||||||
if (ts.host == null)
|
if (ts.host == null)
|
||||||
{
|
{
|
||||||
|
@ -301,7 +306,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<SensedEntity> doObjectSensor(SenseRepeatClass ts)
|
private List<SensedEntity> doObjectSensor(SensorInfo ts)
|
||||||
{
|
{
|
||||||
List<EntityBase> Entities;
|
List<EntityBase> Entities;
|
||||||
List<SensedEntity> sensedEntities = new List<SensedEntity>();
|
List<SensedEntity> sensedEntities = new List<SensedEntity>();
|
||||||
|
@ -450,7 +455,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
|
||||||
return sensedEntities;
|
return sensedEntities;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<SensedEntity> doAgentSensor(SenseRepeatClass ts)
|
private List<SensedEntity> doAgentSensor(SensorInfo ts)
|
||||||
{
|
{
|
||||||
List<SensedEntity> sensedEntities = new List<SensedEntity>();
|
List<SensedEntity> sensedEntities = new List<SensedEntity>();
|
||||||
|
|
||||||
|
@ -626,7 +631,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
|
||||||
{
|
{
|
||||||
List<Object> data = new List<Object>();
|
List<Object> data = new List<Object>();
|
||||||
|
|
||||||
foreach (SenseRepeatClass ts in SenseRepeaters)
|
foreach (SensorInfo ts in SenseRepeaters)
|
||||||
{
|
{
|
||||||
if (ts.itemID == itemID)
|
if (ts.itemID == itemID)
|
||||||
{
|
{
|
||||||
|
@ -656,7 +661,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
|
||||||
|
|
||||||
while (idx < data.Length)
|
while (idx < data.Length)
|
||||||
{
|
{
|
||||||
SenseRepeatClass ts = new SenseRepeatClass();
|
SensorInfo ts = new SensorInfo();
|
||||||
|
|
||||||
ts.localID = localID;
|
ts.localID = localID;
|
||||||
ts.itemID = itemID;
|
ts.itemID = itemID;
|
||||||
|
@ -677,5 +682,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
|
||||||
idx += 6;
|
idx += 6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<SensorInfo> GetSensorInfo()
|
||||||
|
{
|
||||||
|
List<SensorInfo> retList = new List<SensorInfo>();
|
||||||
|
|
||||||
|
lock (SenseRepeatListLock)
|
||||||
|
{
|
||||||
|
foreach (SensorInfo i in SenseRepeaters)
|
||||||
|
retList.Add(i.Clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
return retList;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -35,6 +35,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
|
||||||
{
|
{
|
||||||
public class Timer
|
public class Timer
|
||||||
{
|
{
|
||||||
|
public class TimerInfo
|
||||||
|
{
|
||||||
|
public uint localID;
|
||||||
|
public UUID itemID;
|
||||||
|
//public double interval;
|
||||||
|
public long interval;
|
||||||
|
//public DateTime next;
|
||||||
|
public long next;
|
||||||
|
|
||||||
|
public TimerInfo Clone()
|
||||||
|
{
|
||||||
|
return (TimerInfo)this.MemberwiseClone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public AsyncCommandManager m_CmdManager;
|
public AsyncCommandManager m_CmdManager;
|
||||||
|
|
||||||
public int TimersCount
|
public int TimersCount
|
||||||
|
@ -59,17 +74,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
|
||||||
return localID.ToString() + itemID.ToString();
|
return localID.ToString() + itemID.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TimerClass
|
private Dictionary<string,TimerInfo> Timers = new Dictionary<string,TimerInfo>();
|
||||||
{
|
|
||||||
public uint localID;
|
|
||||||
public UUID itemID;
|
|
||||||
//public double interval;
|
|
||||||
public long interval;
|
|
||||||
//public DateTime next;
|
|
||||||
public long next;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Dictionary<string,TimerClass> Timers = new Dictionary<string,TimerClass>();
|
|
||||||
private object TimerListLock = new object();
|
private object TimerListLock = new object();
|
||||||
|
|
||||||
public void SetTimerEvent(uint m_localID, UUID m_itemID, double sec)
|
public void SetTimerEvent(uint m_localID, UUID m_itemID, double sec)
|
||||||
|
@ -81,7 +86,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add to timer
|
// Add to timer
|
||||||
TimerClass ts = new TimerClass();
|
TimerInfo ts = new TimerInfo();
|
||||||
ts.localID = m_localID;
|
ts.localID = m_localID;
|
||||||
ts.itemID = m_itemID;
|
ts.itemID = m_itemID;
|
||||||
ts.interval = Convert.ToInt64(sec * 10000000); // How many 100 nanoseconds (ticks) should we wait
|
ts.interval = Convert.ToInt64(sec * 10000000); // How many 100 nanoseconds (ticks) should we wait
|
||||||
|
@ -121,8 +126,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
|
||||||
lock (TimerListLock)
|
lock (TimerListLock)
|
||||||
{
|
{
|
||||||
// Go through all timers
|
// Go through all timers
|
||||||
Dictionary<string, TimerClass>.ValueCollection tvals = Timers.Values;
|
Dictionary<string, TimerInfo>.ValueCollection tvals = Timers.Values;
|
||||||
foreach (TimerClass ts in tvals)
|
foreach (TimerInfo ts in tvals)
|
||||||
{
|
{
|
||||||
// Time has passed?
|
// Time has passed?
|
||||||
if (ts.next < DateTime.Now.Ticks)
|
if (ts.next < DateTime.Now.Ticks)
|
||||||
|
@ -147,8 +152,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
|
||||||
|
|
||||||
lock (TimerListLock)
|
lock (TimerListLock)
|
||||||
{
|
{
|
||||||
Dictionary<string, TimerClass>.ValueCollection tvals = Timers.Values;
|
Dictionary<string, TimerInfo>.ValueCollection tvals = Timers.Values;
|
||||||
foreach (TimerClass ts in tvals)
|
foreach (TimerInfo ts in tvals)
|
||||||
{
|
{
|
||||||
if (ts.itemID == itemID)
|
if (ts.itemID == itemID)
|
||||||
{
|
{
|
||||||
|
@ -167,7 +172,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
|
||||||
|
|
||||||
while (idx < data.Length)
|
while (idx < data.Length)
|
||||||
{
|
{
|
||||||
TimerClass ts = new TimerClass();
|
TimerInfo ts = new TimerInfo();
|
||||||
|
|
||||||
ts.localID = localID;
|
ts.localID = localID;
|
||||||
ts.itemID = itemID;
|
ts.itemID = itemID;
|
||||||
|
@ -181,5 +186,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<TimerInfo> GetTimersInfo()
|
||||||
|
{
|
||||||
|
List<TimerInfo> retList = new List<TimerInfo>();
|
||||||
|
|
||||||
|
lock (TimerListLock)
|
||||||
|
{
|
||||||
|
foreach (TimerInfo i in Timers.Values)
|
||||||
|
retList.Add(i.Clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
return retList;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -355,6 +355,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
|
||||||
public const int HTTP_MIMETYPE = 1;
|
public const int HTTP_MIMETYPE = 1;
|
||||||
public const int HTTP_BODY_MAXLENGTH = 2;
|
public const int HTTP_BODY_MAXLENGTH = 2;
|
||||||
public const int HTTP_VERIFY_CERT = 3;
|
public const int HTTP_VERIFY_CERT = 3;
|
||||||
|
public const int HTTP_VERBOSE_THROTTLE = 4;
|
||||||
|
public const int HTTP_CUSTOM_HEADER = 5;
|
||||||
|
public const int HTTP_PRAGMA_NO_CACHE = 6;
|
||||||
|
|
||||||
public const int PRIM_MATERIAL = 2;
|
public const int PRIM_MATERIAL = 2;
|
||||||
public const int PRIM_PHYSICS = 3;
|
public const int PRIM_PHYSICS = 3;
|
||||||
|
@ -556,6 +559,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
|
||||||
public const int OBJECT_SERVER_COST = 14;
|
public const int OBJECT_SERVER_COST = 14;
|
||||||
public const int OBJECT_STREAMING_COST = 15;
|
public const int OBJECT_STREAMING_COST = 15;
|
||||||
public const int OBJECT_PHYSICS_COST = 16;
|
public const int OBJECT_PHYSICS_COST = 16;
|
||||||
|
public const int OBJECT_CHARACTER_TIME = 17;
|
||||||
|
public const int OBJECT_ROOT = 18;
|
||||||
|
public const int OBJECT_ATTACHED_POINT = 19;
|
||||||
|
public const int OBJECT_PATHFINDING_TYPE = 20;
|
||||||
|
public const int OBJECT_PHYSICS = 21;
|
||||||
|
public const int OBJECT_PHANTOM = 22;
|
||||||
|
public const int OBJECT_TEMP_ON_REZ = 23;
|
||||||
|
|
||||||
|
// Pathfinding types
|
||||||
|
public const int OPT_OTHER = -1;
|
||||||
|
public const int OPT_LEGACY_LINKSET = 0;
|
||||||
|
public const int OPT_AVATAR = 1;
|
||||||
|
public const int OPT_CHARACTER = 2;
|
||||||
|
public const int OPT_WALKABLE = 3;
|
||||||
|
public const int OPT_STATIC_OBSTACLE = 4;
|
||||||
|
public const int OPT_MATERIAL_VOLUME = 5;
|
||||||
|
public const int OPT_EXCLUSION_VOLUME = 6;
|
||||||
|
|
||||||
// for llGetAgentList
|
// for llGetAgentList
|
||||||
public const int AGENT_LIST_PARCEL = 1;
|
public const int AGENT_LIST_PARCEL = 1;
|
||||||
|
@ -618,7 +638,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
|
||||||
public const int TOUCH_INVALID_FACE = -1;
|
public const int TOUCH_INVALID_FACE = -1;
|
||||||
public static readonly vector TOUCH_INVALID_TEXCOORD = new vector(-1.0, -1.0, 0.0);
|
public static readonly vector TOUCH_INVALID_TEXCOORD = new vector(-1.0, -1.0, 0.0);
|
||||||
public static readonly vector TOUCH_INVALID_VECTOR = ZERO_VECTOR;
|
public static readonly vector TOUCH_INVALID_VECTOR = ZERO_VECTOR;
|
||||||
|
|
||||||
// constants for llGetPrimMediaParams/llSetPrimMediaParams
|
// constants for llGetPrimMediaParams/llSetPrimMediaParams
|
||||||
public const int PRIM_MEDIA_ALT_IMAGE_ENABLE = 0;
|
public const int PRIM_MEDIA_ALT_IMAGE_ENABLE = 0;
|
||||||
public const int PRIM_MEDIA_CONTROLS = 1;
|
public const int PRIM_MEDIA_CONTROLS = 1;
|
||||||
|
@ -635,15 +655,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
|
||||||
public const int PRIM_MEDIA_WHITELIST = 12;
|
public const int PRIM_MEDIA_WHITELIST = 12;
|
||||||
public const int PRIM_MEDIA_PERMS_INTERACT = 13;
|
public const int PRIM_MEDIA_PERMS_INTERACT = 13;
|
||||||
public const int PRIM_MEDIA_PERMS_CONTROL = 14;
|
public const int PRIM_MEDIA_PERMS_CONTROL = 14;
|
||||||
|
|
||||||
public const int PRIM_MEDIA_CONTROLS_STANDARD = 0;
|
public const int PRIM_MEDIA_CONTROLS_STANDARD = 0;
|
||||||
public const int PRIM_MEDIA_CONTROLS_MINI = 1;
|
public const int PRIM_MEDIA_CONTROLS_MINI = 1;
|
||||||
|
|
||||||
public const int PRIM_MEDIA_PERM_NONE = 0;
|
public const int PRIM_MEDIA_PERM_NONE = 0;
|
||||||
public const int PRIM_MEDIA_PERM_OWNER = 1;
|
public const int PRIM_MEDIA_PERM_OWNER = 1;
|
||||||
public const int PRIM_MEDIA_PERM_GROUP = 2;
|
public const int PRIM_MEDIA_PERM_GROUP = 2;
|
||||||
public const int PRIM_MEDIA_PERM_ANYONE = 4;
|
public const int PRIM_MEDIA_PERM_ANYONE = 4;
|
||||||
|
|
||||||
// extra constants for llSetPrimMediaParams
|
// extra constants for llSetPrimMediaParams
|
||||||
public static readonly LSLInteger LSL_STATUS_OK = new LSLInteger(0);
|
public static readonly LSLInteger LSL_STATUS_OK = new LSLInteger(0);
|
||||||
public static readonly LSLInteger LSL_STATUS_MALFORMED_PARAMS = new LSLInteger(1000);
|
public static readonly LSLInteger LSL_STATUS_MALFORMED_PARAMS = new LSLInteger(1000);
|
||||||
|
@ -660,7 +680,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
|
||||||
public const string TEXTURE_PLYWOOD = "89556747-24cb-43ed-920b-47caed15465f";
|
public const string TEXTURE_PLYWOOD = "89556747-24cb-43ed-920b-47caed15465f";
|
||||||
public const string TEXTURE_TRANSPARENT = "8dcd4a48-2d37-4909-9f78-f7a9eb4ef903";
|
public const string TEXTURE_TRANSPARENT = "8dcd4a48-2d37-4909-9f78-f7a9eb4ef903";
|
||||||
public const string TEXTURE_MEDIA = "8b5fec65-8d8d-9dc5-cda8-8fdf2716e361";
|
public const string TEXTURE_MEDIA = "8b5fec65-8d8d-9dc5-cda8-8fdf2716e361";
|
||||||
|
|
||||||
// Constants for osGetRegionStats
|
// Constants for osGetRegionStats
|
||||||
public const int STATS_TIME_DILATION = 0;
|
public const int STATS_TIME_DILATION = 0;
|
||||||
public const int STATS_SIM_FPS = 1;
|
public const int STATS_SIM_FPS = 1;
|
||||||
|
@ -713,7 +733,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
|
||||||
public static readonly LSLInteger RC_GET_ROOT_KEY = 2;
|
public static readonly LSLInteger RC_GET_ROOT_KEY = 2;
|
||||||
public static readonly LSLInteger RC_GET_LINK_NUM = 4;
|
public static readonly LSLInteger RC_GET_LINK_NUM = 4;
|
||||||
|
|
||||||
public static readonly LSLInteger RCERR_UNKNOWN = -1;
|
public static readonly LSLInteger RCERR_UNKNOWN = -1;
|
||||||
public static readonly LSLInteger RCERR_SIM_PERF_LOW = -2;
|
public static readonly LSLInteger RCERR_SIM_PERF_LOW = -2;
|
||||||
public static readonly LSLInteger RCERR_CAST_TIME_EXCEEDED = 3;
|
public static readonly LSLInteger RCERR_CAST_TIME_EXCEEDED = 3;
|
||||||
|
|
||||||
|
|
|
@ -166,5 +166,52 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
|
||||||
Assert.That(copiedItems[0].Name, Is.EqualTo(inventoryItemName));
|
Assert.That(copiedItems[0].Name, Is.EqualTo(inventoryItemName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestLlRemoteLoadScriptPin()
|
||||||
|
{
|
||||||
|
TestHelpers.InMethod();
|
||||||
|
// TestHelpers.EnableLogging();
|
||||||
|
|
||||||
|
UUID user1Id = TestHelpers.ParseTail(0x1);
|
||||||
|
UUID user2Id = TestHelpers.ParseTail(0x2);
|
||||||
|
|
||||||
|
SceneObjectGroup sourceSo = SceneHelpers.AddSceneObject(m_scene, "sourceSo", user1Id);
|
||||||
|
m_scene.AddSceneObject(sourceSo);
|
||||||
|
LSL_Api api = new LSL_Api();
|
||||||
|
api.Initialize(m_engine, sourceSo.RootPart, null);
|
||||||
|
TaskInventoryHelpers.AddScript(m_scene, sourceSo.RootPart, "script", "Hello World");
|
||||||
|
|
||||||
|
SceneObjectGroup targetSo = SceneHelpers.AddSceneObject(m_scene, "targetSo", user1Id);
|
||||||
|
SceneObjectGroup otherOwnedTargetSo = SceneHelpers.AddSceneObject(m_scene, "otherOwnedTargetSo", user2Id);
|
||||||
|
|
||||||
|
// Test that we cannot load a script when the target pin has never been set (i.e. it is zero)
|
||||||
|
api.llRemoteLoadScriptPin(targetSo.UUID.ToString(), "script", 0, 0, 0);
|
||||||
|
Assert.IsNull(targetSo.RootPart.Inventory.GetInventoryItem("script"));
|
||||||
|
|
||||||
|
// Test that we cannot load a script when the given pin does not match the target
|
||||||
|
targetSo.RootPart.ScriptAccessPin = 5;
|
||||||
|
api.llRemoteLoadScriptPin(targetSo.UUID.ToString(), "script", 3, 0, 0);
|
||||||
|
Assert.IsNull(targetSo.RootPart.Inventory.GetInventoryItem("script"));
|
||||||
|
|
||||||
|
// Test that we cannot load into a prim with a different owner
|
||||||
|
otherOwnedTargetSo.RootPart.ScriptAccessPin = 3;
|
||||||
|
api.llRemoteLoadScriptPin(otherOwnedTargetSo.UUID.ToString(), "script", 3, 0, 0);
|
||||||
|
Assert.IsNull(otherOwnedTargetSo.RootPart.Inventory.GetInventoryItem("script"));
|
||||||
|
|
||||||
|
// Test that we can load a script when given pin and dest pin match.
|
||||||
|
targetSo.RootPart.ScriptAccessPin = 3;
|
||||||
|
api.llRemoteLoadScriptPin(targetSo.UUID.ToString(), "script", 3, 0, 0);
|
||||||
|
TaskInventoryItem insertedItem = targetSo.RootPart.Inventory.GetInventoryItem("script");
|
||||||
|
Assert.IsNotNull(insertedItem);
|
||||||
|
|
||||||
|
// Test that we can no longer load if access pin is unset
|
||||||
|
targetSo.RootPart.Inventory.RemoveInventoryItem(insertedItem.ItemID);
|
||||||
|
Assert.IsNull(targetSo.RootPart.Inventory.GetInventoryItem("script"));
|
||||||
|
|
||||||
|
targetSo.RootPart.ScriptAccessPin = 0;
|
||||||
|
api.llRemoteLoadScriptPin(otherOwnedTargetSo.UUID.ToString(), "script", 3, 0, 0);
|
||||||
|
Assert.IsNull(otherOwnedTargetSo.RootPart.Inventory.GetInventoryItem("script"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,126 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Contributors, http://opensimulator.org/
|
||||||
|
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the OpenSimulator Project nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Framework.Console;
|
||||||
|
using OpenSim.Region.ScriptEngine.Interfaces;
|
||||||
|
using OpenSim.Region.ScriptEngine.Shared.Api;
|
||||||
|
using OpenSim.Region.ScriptEngine.Shared.Api.Plugins;
|
||||||
|
|
||||||
|
namespace OpenSim.Region.ScriptEngine.XEngine
|
||||||
|
{
|
||||||
|
public class ScriptEngineConsoleCommands
|
||||||
|
{
|
||||||
|
IScriptEngine m_engine;
|
||||||
|
|
||||||
|
public ScriptEngineConsoleCommands(IScriptEngine engine)
|
||||||
|
{
|
||||||
|
m_engine = engine;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RegisterCommands()
|
||||||
|
{
|
||||||
|
MainConsole.Instance.Commands.AddCommand(
|
||||||
|
"Scripts", false, "show script sensors", "show script sensors", "Show script sensors information",
|
||||||
|
HandleShowSensors);
|
||||||
|
|
||||||
|
MainConsole.Instance.Commands.AddCommand(
|
||||||
|
"Scripts", false, "show script timers", "show script timers", "Show script sensors information",
|
||||||
|
HandleShowTimers);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsSceneSelected()
|
||||||
|
{
|
||||||
|
return MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_engine.World;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleShowSensors(string module, string[] cmdparams)
|
||||||
|
{
|
||||||
|
if (!IsSceneSelected())
|
||||||
|
return;
|
||||||
|
|
||||||
|
SensorRepeat sr = AsyncCommandManager.GetSensorRepeatPlugin(m_engine);
|
||||||
|
|
||||||
|
if (sr == null)
|
||||||
|
{
|
||||||
|
MainConsole.Instance.Output("Plugin not yet initialized");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<SensorRepeat.SensorInfo> sensorInfo = sr.GetSensorInfo();
|
||||||
|
|
||||||
|
ConsoleDisplayTable cdt = new ConsoleDisplayTable();
|
||||||
|
cdt.AddColumn("Part name", 40);
|
||||||
|
cdt.AddColumn("Script item ID", 36);
|
||||||
|
cdt.AddColumn("Type", 4);
|
||||||
|
cdt.AddColumn("Interval", 8);
|
||||||
|
cdt.AddColumn("Range", 8);
|
||||||
|
cdt.AddColumn("Arc", 8);
|
||||||
|
|
||||||
|
foreach (SensorRepeat.SensorInfo s in sensorInfo)
|
||||||
|
{
|
||||||
|
cdt.AddRow(s.host.Name, s.itemID, s.type, s.interval, s.range, s.arc);
|
||||||
|
}
|
||||||
|
|
||||||
|
MainConsole.Instance.Output(cdt.ToString());
|
||||||
|
MainConsole.Instance.OutputFormat("Total: {0}", sensorInfo.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleShowTimers(string module, string[] cmdparams)
|
||||||
|
{
|
||||||
|
if (!IsSceneSelected())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Timer timerPlugin = AsyncCommandManager.GetTimerPlugin(m_engine);
|
||||||
|
|
||||||
|
if (timerPlugin == null)
|
||||||
|
{
|
||||||
|
MainConsole.Instance.Output("Plugin not yet initialized");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Timer.TimerInfo> timersInfo = timerPlugin.GetTimersInfo();
|
||||||
|
|
||||||
|
ConsoleDisplayTable cdt = new ConsoleDisplayTable();
|
||||||
|
cdt.AddColumn("Part local ID", 13);
|
||||||
|
cdt.AddColumn("Script item ID", 36);
|
||||||
|
cdt.AddColumn("Interval", 10);
|
||||||
|
cdt.AddColumn("Next", 8);
|
||||||
|
|
||||||
|
foreach (Timer.TimerInfo t in timersInfo)
|
||||||
|
{
|
||||||
|
// Convert from 100 ns ticks back to seconds
|
||||||
|
cdt.AddRow(t.localID, t.itemID, (double)t.interval / 10000000, t.next);
|
||||||
|
}
|
||||||
|
|
||||||
|
MainConsole.Instance.Output(cdt.ToString());
|
||||||
|
MainConsole.Instance.OutputFormat("Total: {0}", timersInfo.Count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -47,7 +47,6 @@ using OpenSim.Framework.Console;
|
||||||
using OpenSim.Region.Framework.Scenes;
|
using OpenSim.Region.Framework.Scenes;
|
||||||
using OpenSim.Region.Framework.Interfaces;
|
using OpenSim.Region.Framework.Interfaces;
|
||||||
using OpenSim.Region.ScriptEngine.Shared;
|
using OpenSim.Region.ScriptEngine.Shared;
|
||||||
using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
|
|
||||||
using OpenSim.Region.ScriptEngine.Shared.CodeTools;
|
using OpenSim.Region.ScriptEngine.Shared.CodeTools;
|
||||||
using OpenSim.Region.ScriptEngine.Shared.Instance;
|
using OpenSim.Region.ScriptEngine.Shared.Instance;
|
||||||
using OpenSim.Region.ScriptEngine.Shared.Api;
|
using OpenSim.Region.ScriptEngine.Shared.Api;
|
||||||
|
@ -169,6 +168,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||||
IWorkItemResult m_CurrentCompile = null;
|
IWorkItemResult m_CurrentCompile = null;
|
||||||
private Dictionary<UUID, int> m_CompileDict = new Dictionary<UUID, int>();
|
private Dictionary<UUID, int> m_CompileDict = new Dictionary<UUID, int>();
|
||||||
|
|
||||||
|
private ScriptEngineConsoleCommands m_consoleCommands;
|
||||||
|
|
||||||
public string ScriptEngineName
|
public string ScriptEngineName
|
||||||
{
|
{
|
||||||
get { return "XEngine"; }
|
get { return "XEngine"; }
|
||||||
|
@ -318,50 +319,53 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||||
OnObjectRemoved += m_XmlRpcRouter.ObjectRemoved;
|
OnObjectRemoved += m_XmlRpcRouter.ObjectRemoved;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_consoleCommands = new ScriptEngineConsoleCommands(this);
|
||||||
|
m_consoleCommands.RegisterCommands();
|
||||||
|
|
||||||
MainConsole.Instance.Commands.AddCommand(
|
MainConsole.Instance.Commands.AddCommand(
|
||||||
"Scripts", false, "xengine status", "xengine status", "Show status information",
|
"Scripts", false, "xengine status", "xengine status", "Show status information",
|
||||||
"Show status information on the script engine.",
|
"Show status information on the script engine.",
|
||||||
HandleShowStatus);
|
HandleShowStatus);
|
||||||
|
|
||||||
MainConsole.Instance.Commands.AddCommand(
|
MainConsole.Instance.Commands.AddCommand(
|
||||||
"Scripts", false, "scripts show", "scripts show [<script-item-uuid>]", "Show script information",
|
"Scripts", false, "scripts show", "scripts show [<script-item-uuid>+]", "Show script information",
|
||||||
"Show information on all scripts known to the script engine.\n"
|
"Show information on all scripts known to the script engine.\n"
|
||||||
+ "If a <script-item-uuid> is given then only information on that script will be shown.",
|
+ "If one or more <script-item-uuid>s are given then only information on that script will be shown.",
|
||||||
HandleShowScripts);
|
HandleShowScripts);
|
||||||
|
|
||||||
MainConsole.Instance.Commands.AddCommand(
|
MainConsole.Instance.Commands.AddCommand(
|
||||||
"Scripts", false, "show scripts", "show scripts [<script-item-uuid>]", "Show script information",
|
"Scripts", false, "show scripts", "show scripts [<script-item-uuid>+]", "Show script information",
|
||||||
"Synonym for scripts show command", HandleShowScripts);
|
"Synonym for scripts show command", HandleShowScripts);
|
||||||
|
|
||||||
MainConsole.Instance.Commands.AddCommand(
|
MainConsole.Instance.Commands.AddCommand(
|
||||||
"Scripts", false, "scripts suspend", "scripts suspend [<script-item-uuid>]", "Suspends all running scripts",
|
"Scripts", false, "scripts suspend", "scripts suspend [<script-item-uuid>+]", "Suspends all running scripts",
|
||||||
"Suspends all currently running scripts. This only suspends event delivery, it will not suspend a"
|
"Suspends all currently running scripts. This only suspends event delivery, it will not suspend a"
|
||||||
+ " script that is currently processing an event.\n"
|
+ " script that is currently processing an event.\n"
|
||||||
+ "Suspended scripts will continue to accumulate events but won't process them.\n"
|
+ "Suspended scripts will continue to accumulate events but won't process them.\n"
|
||||||
+ "If a <script-item-uuid> is given then only that script will be suspended. Otherwise, all suitable scripts are suspended.",
|
+ "If one or more <script-item-uuid>s are given then only that script will be suspended. Otherwise, all suitable scripts are suspended.",
|
||||||
(module, cmdparams) => HandleScriptsAction(cmdparams, HandleSuspendScript));
|
(module, cmdparams) => HandleScriptsAction(cmdparams, HandleSuspendScript));
|
||||||
|
|
||||||
MainConsole.Instance.Commands.AddCommand(
|
MainConsole.Instance.Commands.AddCommand(
|
||||||
"Scripts", false, "scripts resume", "scripts resume [<script-item-uuid>]", "Resumes all suspended scripts",
|
"Scripts", false, "scripts resume", "scripts resume [<script-item-uuid>+]", "Resumes all suspended scripts",
|
||||||
"Resumes all currently suspended scripts.\n"
|
"Resumes all currently suspended scripts.\n"
|
||||||
+ "Resumed scripts will process all events accumulated whilst suspended.\n"
|
+ "Resumed scripts will process all events accumulated whilst suspended.\n"
|
||||||
+ "If a <script-item-uuid> is given then only that script will be resumed. Otherwise, all suitable scripts are resumed.",
|
+ "If one or more <script-item-uuid>s are given then only that script will be resumed. Otherwise, all suitable scripts are resumed.",
|
||||||
(module, cmdparams) => HandleScriptsAction(cmdparams, HandleResumeScript));
|
(module, cmdparams) => HandleScriptsAction(cmdparams, HandleResumeScript));
|
||||||
|
|
||||||
MainConsole.Instance.Commands.AddCommand(
|
MainConsole.Instance.Commands.AddCommand(
|
||||||
"Scripts", false, "scripts stop", "scripts stop [<script-item-uuid>]", "Stops all running scripts",
|
"Scripts", false, "scripts stop", "scripts stop [<script-item-uuid>+]", "Stops all running scripts",
|
||||||
"Stops all running scripts.\n"
|
"Stops all running scripts.\n"
|
||||||
+ "If a <script-item-uuid> is given then only that script will be stopped. Otherwise, all suitable scripts are stopped.",
|
+ "If one or more <script-item-uuid>s are given then only that script will be stopped. Otherwise, all suitable scripts are stopped.",
|
||||||
(module, cmdparams) => HandleScriptsAction(cmdparams, HandleStopScript));
|
(module, cmdparams) => HandleScriptsAction(cmdparams, HandleStopScript));
|
||||||
|
|
||||||
MainConsole.Instance.Commands.AddCommand(
|
MainConsole.Instance.Commands.AddCommand(
|
||||||
"Scripts", false, "scripts start", "scripts start [<script-item-uuid>]", "Starts all stopped scripts",
|
"Scripts", false, "scripts start", "scripts start [<script-item-uuid>+]", "Starts all stopped scripts",
|
||||||
"Starts all stopped scripts.\n"
|
"Starts all stopped scripts.\n"
|
||||||
+ "If a <script-item-uuid> is given then only that script will be started. Otherwise, all suitable scripts are started.",
|
+ "If one or more <script-item-uuid>s are given then only that script will be started. Otherwise, all suitable scripts are started.",
|
||||||
(module, cmdparams) => HandleScriptsAction(cmdparams, HandleStartScript));
|
(module, cmdparams) => HandleScriptsAction(cmdparams, HandleStartScript));
|
||||||
|
|
||||||
MainConsole.Instance.Commands.AddCommand(
|
MainConsole.Instance.Commands.AddCommand(
|
||||||
"Scripts", false, "debug script log", "debug scripts log <item-id> <log-level>", "Extra debug logging for a script",
|
"Scripts", false, "debug scripts log", "debug scripts log <item-id> <log-level>", "Extra debug logging for a script",
|
||||||
"Activates or deactivates extra debug logging for the given script.\n"
|
"Activates or deactivates extra debug logging for the given script.\n"
|
||||||
+ "Level == 0, deactivate extra debug logging.\n"
|
+ "Level == 0, deactivate extra debug logging.\n"
|
||||||
+ "Level >= 1, log state changes.\n"
|
+ "Level >= 1, log state changes.\n"
|
||||||
|
@ -478,29 +482,31 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
rawItemId = cmdparams[2];
|
for (int i = 2; i < cmdparams.Length; i++)
|
||||||
|
|
||||||
if (!UUID.TryParse(rawItemId, out itemId))
|
|
||||||
{
|
{
|
||||||
MainConsole.Instance.OutputFormat("ERROR: {0} is not a valid UUID", rawItemId);
|
rawItemId = cmdparams[i];
|
||||||
return;
|
|
||||||
}
|
if (!UUID.TryParse(rawItemId, out itemId))
|
||||||
|
|
||||||
if (itemId != UUID.Zero)
|
|
||||||
{
|
|
||||||
IScriptInstance instance = GetInstance(itemId);
|
|
||||||
if (instance == null)
|
|
||||||
{
|
{
|
||||||
// Commented out for now since this will cause false reports on simulators with more than
|
MainConsole.Instance.OutputFormat("ERROR: {0} is not a valid UUID", rawItemId);
|
||||||
// one scene where the current command line set region is 'root' (which causes commands to
|
continue;
|
||||||
// go to both regions... (sigh)
|
|
||||||
// MainConsole.Instance.OutputFormat("Error - No item found with id {0}", itemId);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (itemId != UUID.Zero)
|
||||||
{
|
{
|
||||||
action(instance);
|
IScriptInstance instance = GetInstance(itemId);
|
||||||
return;
|
if (instance == null)
|
||||||
|
{
|
||||||
|
// Commented out for now since this will cause false reports on simulators with more than
|
||||||
|
// one scene where the current command line set region is 'root' (which causes commands to
|
||||||
|
// go to both regions... (sigh)
|
||||||
|
// MainConsole.Instance.OutputFormat("Error - No item found with id {0}", itemId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
action(instance);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -599,7 +605,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
Queue eq = instance.EventQueue;
|
|
||||||
|
|
||||||
sb.AppendFormat("Script name : {0}\n", instance.ScriptName);
|
sb.AppendFormat("Script name : {0}\n", instance.ScriptName);
|
||||||
sb.AppendFormat("Status : {0}\n", status);
|
sb.AppendFormat("Status : {0}\n", status);
|
||||||
|
@ -1479,7 +1484,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||||
m_MaxScriptQueue = maxScriptQueue;
|
m_MaxScriptQueue = maxScriptQueue;
|
||||||
|
|
||||||
STPStartInfo startInfo = new STPStartInfo();
|
STPStartInfo startInfo = new STPStartInfo();
|
||||||
startInfo.IdleTimeout = idleTimeout*1000; // convert to seconds as stated in .ini
|
startInfo.ThreadPoolName = "XEngine";
|
||||||
|
startInfo.IdleTimeout = idleTimeout * 1000; // convert to seconds as stated in .ini
|
||||||
startInfo.MaxWorkerThreads = maxThreads;
|
startInfo.MaxWorkerThreads = maxThreads;
|
||||||
startInfo.MinWorkerThreads = minThreads;
|
startInfo.MinWorkerThreads = minThreads;
|
||||||
startInfo.ThreadPriority = threadPriority;;
|
startInfo.ThreadPriority = threadPriority;;
|
||||||
|
@ -1487,7 +1493,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||||
startInfo.StartSuspended = true;
|
startInfo.StartSuspended = true;
|
||||||
|
|
||||||
m_ThreadPool = new SmartThreadPool(startInfo);
|
m_ThreadPool = new SmartThreadPool(startInfo);
|
||||||
m_ThreadPool.Name = "XEngine";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue