Compare commits
	
		
			89 Commits 
		
	
	
		
			master
			...
			0.7.5-pf-b
		
	
	| Author | SHA1 | Date | 
|---|---|---|
|  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; |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -30,7 +30,7 @@ namespace OpenSim | ||||||
|     public class VersionInfo |     public class VersionInfo | ||||||
|     { |     { | ||||||
|         private const string VERSION_NUMBER = "0.7.5"; |         private const string VERSION_NUMBER = "0.7.5"; | ||||||
|         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 | ||||||
|  |  | ||||||
|  | @ -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; | ||||||
|  |  | ||||||
|  | @ -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); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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) | ||||||
|                     { |                     { | ||||||
|  |  | ||||||
|  | @ -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); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -126,7 +126,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>", | ||||||
|  |  | ||||||
|  | @ -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; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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"; |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // |         // | ||||||
|  |  | ||||||
|  | @ -280,8 +280,11 @@ namespace OpenSim.Server.Base | ||||||
|                             { |                             { | ||||||
|                                 if (!(e is System.MissingMethodException)) |                                 if (!(e is System.MissingMethodException)) | ||||||
|                                 { |                                 { | ||||||
|                                     m_log.ErrorFormat("Error loading plugin {0} from {1}. Exception: {2}", |                                     m_log.ErrorFormat("Error loading plugin {0} from {1}. Exception: {2}, {3}", | ||||||
|                                         interfaceName, dllName, e.InnerException == null ? e.Message : e.InnerException.Message); |                                         interfaceName,  | ||||||
|  |                                         dllName,  | ||||||
|  |                                         e.InnerException == null ? e.Message : e.InnerException.Message,  | ||||||
|  |                                         e.StackTrace); | ||||||
|                                 } |                                 } | ||||||
|                                 return null; |                                 return null; | ||||||
|                             } |                             } | ||||||
|  |  | ||||||
|  | @ -545,7 +545,7 @@ namespace OpenSim.Services.UserAccountService | ||||||
|             return account; |             return account; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         private void CreateDefaultAppearanceEntries(UUID principalID) |         protected void CreateDefaultAppearanceEntries(UUID principalID) | ||||||
|         { |         { | ||||||
|             m_log.DebugFormat("[USER ACCOUNT SERVICE]: Creating default appearance items for {0}", principalID); |             m_log.DebugFormat("[USER ACCOUNT SERVICE]: Creating default appearance items for {0}", principalID); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -60,6 +60,11 @@ namespace OpenSim.Tests.Common.Mock | ||||||
|         public List<ImagePacketPacket> SentImagePacketPackets { get; private set; } |         public List<ImagePacketPacket> SentImagePacketPackets { get; private set; } | ||||||
|         public List<ImageNotInDatabasePacket> SentImageNotInDatabasePackets { get; private set; } |         public List<ImageNotInDatabasePacket> SentImageNotInDatabasePackets { get; private set; } | ||||||
| 
 | 
 | ||||||
|  |         // Test client specific events - for use by tests to implement some IClientAPI behaviour. | ||||||
|  |         public event Action<RegionInfo, Vector3, Vector3> OnReceivedMoveAgentIntoRegion; | ||||||
|  |         public event Action<ulong, IPEndPoint> OnTestClientInformClientOfNeighbour; | ||||||
|  |         public event Action<GridInstantMessage> OnReceivedInstantMessage; | ||||||
|  | 
 | ||||||
| // disable warning: public events, part of the public API | // disable warning: public events, part of the public API | ||||||
| #pragma warning disable 67 | #pragma warning disable 67 | ||||||
| 
 | 
 | ||||||
|  | @ -482,6 +487,18 @@ namespace OpenSim.Tests.Common.Mock | ||||||
|             OnCompleteMovementToRegion(this, true); |             OnCompleteMovementToRegion(this, true); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         /// <summary> | ||||||
|  |         /// Emulate sending an IM from the viewer to the simulator. | ||||||
|  |         /// </summary> | ||||||
|  |         /// <param name='im'></param> | ||||||
|  |         public void HandleImprovedInstantMessage(GridInstantMessage im) | ||||||
|  |         { | ||||||
|  |             ImprovedInstantMessage handlerInstantMessage = OnInstantMessage; | ||||||
|  | 
 | ||||||
|  |             if (handlerInstantMessage != null) | ||||||
|  |                 handlerInstantMessage(this, im); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         public virtual void ActivateGesture(UUID assetId, UUID gestureId) |         public virtual void ActivateGesture(UUID assetId, UUID gestureId) | ||||||
|         { |         { | ||||||
|         } |         } | ||||||
|  | @ -536,7 +553,8 @@ namespace OpenSim.Tests.Common.Mock | ||||||
| 
 | 
 | ||||||
|         public void SendInstantMessage(GridInstantMessage im) |         public void SendInstantMessage(GridInstantMessage im) | ||||||
|         { |         { | ||||||
| 
 |             if (OnReceivedInstantMessage != null) | ||||||
|  |                 OnReceivedInstantMessage(im); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public void SendGenericMessage(string method, List<string> message) |         public void SendGenericMessage(string method, List<string> message) | ||||||
|  |  | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue