diff options
Diffstat (limited to 'OpenSim/Region')
170 files changed, 18061 insertions, 4335 deletions
diff --git a/OpenSim/Region/Application/Application.cs b/OpenSim/Region/Application/Application.cs index 3b261e7..c130038 100644 --- a/OpenSim/Region/Application/Application.cs +++ b/OpenSim/Region/Application/Application.cs | |||
@@ -73,6 +73,7 @@ namespace OpenSim | |||
73 | AppDomain.CurrentDomain.UnhandledException += | 73 | AppDomain.CurrentDomain.UnhandledException += |
74 | new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); | 74 | new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); |
75 | 75 | ||
76 | |||
76 | // Add the arguments supplied when running the application to the configuration | 77 | // Add the arguments supplied when running the application to the configuration |
77 | ArgvConfigSource configSource = new ArgvConfigSource(args); | 78 | ArgvConfigSource configSource = new ArgvConfigSource(args); |
78 | 79 | ||
@@ -91,6 +92,9 @@ namespace OpenSim | |||
91 | m_log.Info("[OPENSIM MAIN]: configured log4net using default OpenSim.exe.config"); | 92 | m_log.Info("[OPENSIM MAIN]: configured log4net using default OpenSim.exe.config"); |
92 | } | 93 | } |
93 | 94 | ||
95 | m_log.DebugFormat( | ||
96 | "[OPENSIM MAIN]: System Locale is {0}", System.Threading.Thread.CurrentThread.CurrentCulture); | ||
97 | |||
94 | // Increase the number of IOCP threads available. Mono defaults to a tragically low number | 98 | // Increase the number of IOCP threads available. Mono defaults to a tragically low number |
95 | int workerThreads, iocpThreads; | 99 | int workerThreads, iocpThreads; |
96 | System.Threading.ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads); | 100 | System.Threading.ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads); |
diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index 86975c9..fae8be7 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs | |||
@@ -130,7 +130,9 @@ namespace OpenSim | |||
130 | //m_log.InfoFormat("[OPENSIM MAIN]: GC Latency Mode: {0}", GCSettings.LatencyMode.ToString()); | 130 | //m_log.InfoFormat("[OPENSIM MAIN]: GC Latency Mode: {0}", GCSettings.LatencyMode.ToString()); |
131 | 131 | ||
132 | if (m_gui) // Driven by external GUI | 132 | if (m_gui) // Driven by external GUI |
133 | { | ||
133 | m_console = new CommandConsole("Region"); | 134 | m_console = new CommandConsole("Region"); |
135 | } | ||
134 | else | 136 | else |
135 | { | 137 | { |
136 | switch (m_consoleType) | 138 | switch (m_consoleType) |
@@ -547,6 +549,7 @@ namespace OpenSim | |||
547 | { | 549 | { |
548 | string regionName = string.Empty; | 550 | string regionName = string.Empty; |
549 | string regionFile = string.Empty; | 551 | string regionFile = string.Empty; |
552 | |||
550 | if (cmd.Length == 3) | 553 | if (cmd.Length == 3) |
551 | { | 554 | { |
552 | regionFile = cmd[2]; | 555 | regionFile = cmd[2]; |
@@ -556,14 +559,17 @@ namespace OpenSim | |||
556 | regionName = cmd[2]; | 559 | regionName = cmd[2]; |
557 | regionFile = cmd[3]; | 560 | regionFile = cmd[3]; |
558 | } | 561 | } |
562 | |||
559 | string extension = Path.GetExtension(regionFile).ToLower(); | 563 | string extension = Path.GetExtension(regionFile).ToLower(); |
560 | bool isXml = extension.Equals(".xml"); | 564 | bool isXml = extension.Equals(".xml"); |
561 | bool isIni = extension.Equals(".ini"); | 565 | bool isIni = extension.Equals(".ini"); |
566 | |||
562 | if (!isXml && !isIni) | 567 | if (!isXml && !isIni) |
563 | { | 568 | { |
564 | MainConsole.Instance.Output("Usage: create region [\"region name\"] <region_file.ini>"); | 569 | MainConsole.Instance.Output("Usage: create region [\"region name\"] <region_file.ini>"); |
565 | return; | 570 | return; |
566 | } | 571 | } |
572 | |||
567 | if (!Path.IsPathRooted(regionFile)) | 573 | if (!Path.IsPathRooted(regionFile)) |
568 | { | 574 | { |
569 | string regionsDir = ConfigSource.Source.Configs["Startup"].GetString("regionload_regionsdir", "Regions").Trim(); | 575 | string regionsDir = ConfigSource.Source.Configs["Startup"].GetString("regionload_regionsdir", "Regions").Trim(); |
@@ -580,8 +586,18 @@ namespace OpenSim | |||
580 | regInfo = new RegionInfo(regionName, regionFile, false, ConfigSource.Source, regionName); | 586 | regInfo = new RegionInfo(regionName, regionFile, false, ConfigSource.Source, regionName); |
581 | } | 587 | } |
582 | 588 | ||
583 | IScene scene; | 589 | Scene existingScene; |
590 | if (SceneManager.TryGetScene(regInfo.RegionID, out existingScene)) | ||
591 | { | ||
592 | MainConsole.Instance.OutputFormat( | ||
593 | "ERROR: Cannot create region {0} with ID {1}, this ID is already assigned to region {2}", | ||
594 | regInfo.RegionName, regInfo.RegionID, existingScene.RegionInfo.RegionName); | ||
595 | |||
596 | return; | ||
597 | } | ||
598 | |||
584 | PopulateRegionEstateInfo(regInfo); | 599 | PopulateRegionEstateInfo(regInfo); |
600 | IScene scene; | ||
585 | CreateRegion(regInfo, true, out scene); | 601 | CreateRegion(regInfo, true, out scene); |
586 | regInfo.EstateSettings.Save(); | 602 | regInfo.EstateSettings.Save(); |
587 | } | 603 | } |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs index d3bb0bc..d1ce5df 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs | |||
@@ -136,7 +136,6 @@ namespace OpenSim.Region.ClientStack.Linden | |||
136 | TaskScriptUpdatedCall = m_Scene.CapsUpdateTaskInventoryScriptAsset; | 136 | TaskScriptUpdatedCall = m_Scene.CapsUpdateTaskInventoryScriptAsset; |
137 | CAPSFetchInventoryDescendents = m_Scene.HandleFetchInventoryDescendentsCAPS; | 137 | CAPSFetchInventoryDescendents = m_Scene.HandleFetchInventoryDescendentsCAPS; |
138 | GetClient = m_Scene.SceneContents.GetControllingClient; | 138 | GetClient = m_Scene.SceneContents.GetControllingClient; |
139 | |||
140 | } | 139 | } |
141 | 140 | ||
142 | /// <summary> | 141 | /// <summary> |
@@ -232,7 +231,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
232 | public string SeedCapRequest(string request, string path, string param, | 231 | public string SeedCapRequest(string request, string path, string param, |
233 | OSHttpRequest httpRequest, OSHttpResponse httpResponse) | 232 | OSHttpRequest httpRequest, OSHttpResponse httpResponse) |
234 | { | 233 | { |
235 | m_log.Debug("[CAPS]: Seed Caps Request in region: " + m_regionName); | 234 | // m_log.Debug("[CAPS]: Seed Caps Request in region: " + m_regionName); |
236 | 235 | ||
237 | if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint)) | 236 | if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint)) |
238 | { | 237 | { |
@@ -331,14 +330,22 @@ namespace OpenSim.Region.ClientStack.Linden | |||
331 | } | 330 | } |
332 | } | 331 | } |
333 | 332 | ||
333 | /// <summary> | ||
334 | /// Handle a request from the client for a Uri to upload a baked texture. | ||
335 | /// </summary> | ||
336 | /// <param name="request"></param> | ||
337 | /// <param name="path"></param> | ||
338 | /// <param name="param"></param> | ||
339 | /// <param name="httpRequest"></param> | ||
340 | /// <param name="httpResponse"></param> | ||
341 | /// <returns>The upload response if the request is successful, null otherwise.</returns> | ||
334 | public string UploadBakedTexture(string request, string path, | 342 | public string UploadBakedTexture(string request, string path, |
335 | string param, OSHttpRequest httpRequest, | 343 | string param, OSHttpRequest httpRequest, |
336 | OSHttpResponse httpResponse) | 344 | OSHttpResponse httpResponse) |
337 | { | 345 | { |
338 | try | 346 | try |
339 | { | 347 | { |
340 | // m_log.Debug("[CAPS]: UploadBakedTexture Request in region: " + | 348 | // m_log.Debug("[CAPS]: UploadBakedTexture Request in region: " + m_regionName); |
341 | // m_regionName); | ||
342 | 349 | ||
343 | string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; | 350 | string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; |
344 | string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); | 351 | string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); |
@@ -374,6 +381,11 @@ namespace OpenSim.Region.ClientStack.Linden | |||
374 | return null; | 381 | return null; |
375 | } | 382 | } |
376 | 383 | ||
384 | /// <summary> | ||
385 | /// Called when a baked texture has been successfully uploaded by a client. | ||
386 | /// </summary> | ||
387 | /// <param name="assetID"></param> | ||
388 | /// <param name="data"></param> | ||
377 | public void BakedTextureUploaded(UUID assetID, byte[] data) | 389 | public void BakedTextureUploaded(UUID assetID, byte[] data) |
378 | { | 390 | { |
379 | // m_log.WarnFormat("[CAPS]: Received baked texture {0}", assetID.ToString()); | 391 | // m_log.WarnFormat("[CAPS]: Received baked texture {0}", assetID.ToString()); |
@@ -687,7 +699,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
687 | item.CurrentPermissions = (uint)PermissionMask.All; | 699 | item.CurrentPermissions = (uint)PermissionMask.All; |
688 | item.BasePermissions = (uint)PermissionMask.All; | 700 | item.BasePermissions = (uint)PermissionMask.All; |
689 | item.EveryOnePermissions = 0; | 701 | item.EveryOnePermissions = 0; |
690 | item.NextPermissions = (uint)(PermissionMask.Move | PermissionMask.Modify | PermissionMask.Transfer); | 702 | item.NextPermissions = (uint)PermissionMask.All; |
691 | item.CreationDate = Util.UnixTimeSinceEpoch(); | 703 | item.CreationDate = Util.UnixTimeSinceEpoch(); |
692 | 704 | ||
693 | if (AddNewInventoryItem != null) | 705 | if (AddNewInventoryItem != null) |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs index 14160ae..66b865f 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs | |||
@@ -48,8 +48,8 @@ namespace OpenSim.Region.ClientStack.Linden | |||
48 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] | 48 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] |
49 | public class BunchOfCapsModule : INonSharedRegionModule | 49 | public class BunchOfCapsModule : INonSharedRegionModule |
50 | { | 50 | { |
51 | private static readonly ILog m_log = | 51 | // private static readonly ILog m_log = |
52 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 52 | // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
53 | 53 | ||
54 | private Scene m_Scene; | 54 | private Scene m_Scene; |
55 | 55 | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs index e0807ee..e7bd2e7 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs | |||
@@ -50,8 +50,8 @@ namespace OpenSim.Region.ClientStack.Linden | |||
50 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] | 50 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] |
51 | public class GetMeshModule : INonSharedRegionModule | 51 | public class GetMeshModule : INonSharedRegionModule |
52 | { | 52 | { |
53 | private static readonly ILog m_log = | 53 | // private static readonly ILog m_log = |
54 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 54 | // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
55 | 55 | ||
56 | private Scene m_scene; | 56 | private Scene m_scene; |
57 | private IAssetService m_AssetService; | 57 | private IAssetService m_AssetService; |
@@ -113,12 +113,12 @@ namespace OpenSim.Region.ClientStack.Linden | |||
113 | 113 | ||
114 | public void RegisterCaps(UUID agentID, Caps caps) | 114 | public void RegisterCaps(UUID agentID, Caps caps) |
115 | { | 115 | { |
116 | UUID capID = UUID.Random(); | 116 | // UUID capID = UUID.Random(); |
117 | 117 | ||
118 | //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture)); | 118 | //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture)); |
119 | if (m_URL == "localhost") | 119 | if (m_URL == "localhost") |
120 | { | 120 | { |
121 | m_log.InfoFormat("[GETMESH]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); | 121 | // m_log.DebugFormat("[GETMESH]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); |
122 | GetMeshHandler gmeshHandler = new GetMeshHandler(m_AssetService); | 122 | GetMeshHandler gmeshHandler = new GetMeshHandler(m_AssetService); |
123 | IRequestHandler reqHandler = new RestHTTPHandler("GET", "/CAPS/" + UUID.Random(), | 123 | IRequestHandler reqHandler = new RestHTTPHandler("GET", "/CAPS/" + UUID.Random(), |
124 | delegate(Hashtable m_dhttpMethod) | 124 | delegate(Hashtable m_dhttpMethod) |
@@ -130,7 +130,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
130 | } | 130 | } |
131 | else | 131 | else |
132 | { | 132 | { |
133 | m_log.InfoFormat("[GETMESH]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName); | 133 | // m_log.DebugFormat("[GETMESH]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName); |
134 | caps.RegisterHandler("GetMesh", m_URL); | 134 | caps.RegisterHandler("GetMesh", m_URL); |
135 | } | 135 | } |
136 | } | 136 | } |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs index 35eedb4..fffcee2 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs | |||
@@ -54,8 +54,9 @@ namespace OpenSim.Region.ClientStack.Linden | |||
54 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] | 54 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] |
55 | public class GetTextureModule : INonSharedRegionModule | 55 | public class GetTextureModule : INonSharedRegionModule |
56 | { | 56 | { |
57 | private static readonly ILog m_log = | 57 | // private static readonly ILog m_log = |
58 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 58 | // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
59 | |||
59 | private Scene m_scene; | 60 | private Scene m_scene; |
60 | private IAssetService m_assetService; | 61 | private IAssetService m_assetService; |
61 | 62 | ||
@@ -128,12 +129,12 @@ namespace OpenSim.Region.ClientStack.Linden | |||
128 | //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture)); | 129 | //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture)); |
129 | if (m_URL == "localhost") | 130 | if (m_URL == "localhost") |
130 | { | 131 | { |
131 | m_log.InfoFormat("[GETTEXTURE]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); | 132 | // m_log.DebugFormat("[GETTEXTURE]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); |
132 | caps.RegisterHandler("GetTexture", new GetTextureHandler("/CAPS/" + capID + "/", m_assetService)); | 133 | caps.RegisterHandler("GetTexture", new GetTextureHandler("/CAPS/" + capID + "/", m_assetService)); |
133 | } | 134 | } |
134 | else | 135 | else |
135 | { | 136 | { |
136 | m_log.InfoFormat("[GETTEXTURE]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName); | 137 | // m_log.DebugFormat("[GETTEXTURE]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName); |
137 | caps.RegisterHandler("GetTexture", m_URL); | 138 | caps.RegisterHandler("GetTexture", m_URL); |
138 | } | 139 | } |
139 | } | 140 | } |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs index c9d7ae1..18c7eae 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs | |||
@@ -48,8 +48,8 @@ namespace OpenSim.Region.ClientStack.Linden | |||
48 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] | 48 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] |
49 | public class MeshUploadFlagModule : INonSharedRegionModule | 49 | public class MeshUploadFlagModule : INonSharedRegionModule |
50 | { | 50 | { |
51 | private static readonly ILog m_log = | 51 | // private static readonly ILog m_log = |
52 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 52 | // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
53 | 53 | ||
54 | /// <summary> | 54 | /// <summary> |
55 | /// Is this module enabled? | 55 | /// Is this module enabled? |
@@ -124,7 +124,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
124 | 124 | ||
125 | private Hashtable MeshUploadFlag(Hashtable mDhttpMethod) | 125 | private Hashtable MeshUploadFlag(Hashtable mDhttpMethod) |
126 | { | 126 | { |
127 | m_log.DebugFormat("[SIMULATOR FEATURES MODULE]: MeshUploadFlag request"); | 127 | // m_log.DebugFormat("[MESH UPLOAD FLAG MODULE]: MeshUploadFlag request"); |
128 | 128 | ||
129 | OSDMap data = new OSDMap(); | 129 | OSDMap data = new OSDMap(); |
130 | ScenePresence sp = m_scene.GetScenePresence(m_agentID); | 130 | ScenePresence sp = m_scene.GetScenePresence(m_agentID); |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs index b7e79cc..b2f04f9 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs | |||
@@ -160,8 +160,6 @@ namespace OpenSim.Region.ClientStack.Linden | |||
160 | } | 160 | } |
161 | } | 161 | } |
162 | // } | 162 | // } |
163 | |||
164 | |||
165 | 163 | ||
166 | string assetName = llsdRequest.name; | 164 | string assetName = llsdRequest.name; |
167 | string assetDes = llsdRequest.description; | 165 | string assetDes = llsdRequest.description; |
@@ -208,12 +206,10 @@ namespace OpenSim.Region.ClientStack.Linden | |||
208 | return uploadResponse; | 206 | return uploadResponse; |
209 | } | 207 | } |
210 | 208 | ||
211 | |||
212 | public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID, | 209 | public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID, |
213 | UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType, | 210 | UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType, |
214 | string assetType,UUID AgentID) | 211 | string assetType,UUID AgentID) |
215 | { | 212 | { |
216 | |||
217 | sbyte assType = 0; | 213 | sbyte assType = 0; |
218 | sbyte inType = 0; | 214 | sbyte inType = 0; |
219 | 215 | ||
@@ -266,10 +262,10 @@ namespace OpenSim.Region.ClientStack.Linden | |||
266 | item.CurrentPermissions = (uint)PermissionMask.All; | 262 | item.CurrentPermissions = (uint)PermissionMask.All; |
267 | item.BasePermissions = (uint)PermissionMask.All; | 263 | item.BasePermissions = (uint)PermissionMask.All; |
268 | item.EveryOnePermissions = 0; | 264 | item.EveryOnePermissions = 0; |
269 | item.NextPermissions = (uint)(PermissionMask.Move | PermissionMask.Modify | PermissionMask.Transfer); | 265 | item.NextPermissions = (uint)PermissionMask.All; |
270 | item.CreationDate = Util.UnixTimeSinceEpoch(); | 266 | item.CreationDate = Util.UnixTimeSinceEpoch(); |
271 | m_scene.AddInventoryItem(item); | 267 | m_scene.AddInventoryItem(item); |
272 | 268 | ||
273 | } | 269 | } |
274 | } | 270 | } |
275 | } | 271 | } \ No newline at end of file |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs index 15139a3..1c47f0e 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs | |||
@@ -322,8 +322,6 @@ namespace OpenSim.Region.ClientStack.Linden | |||
322 | rootpart.NextOwnerMask = next_owner_mask; | 322 | rootpart.NextOwnerMask = next_owner_mask; |
323 | rootpart.Material = (byte)material; | 323 | rootpart.Material = (byte)material; |
324 | 324 | ||
325 | |||
326 | |||
327 | m_scene.PhysicsScene.AddPhysicsActorTaint(rootpart.PhysActor); | 325 | m_scene.PhysicsScene.AddPhysicsActorTaint(rootpart.PhysActor); |
328 | 326 | ||
329 | responsedata["int_response_code"] = 200; //501; //410; //404; | 327 | responsedata["int_response_code"] = 200; //501; //410; //404; |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs index 15ed3b3..c07fc73 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs | |||
@@ -129,7 +129,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
129 | 129 | ||
130 | 130 | ||
131 | /// <summary> | 131 | /// <summary> |
132 | /// Parses ad request | 132 | /// Parses add request |
133 | /// </summary> | 133 | /// </summary> |
134 | /// <param name="request"></param> | 134 | /// <param name="request"></param> |
135 | /// <param name="AgentId"></param> | 135 | /// <param name="AgentId"></param> |
@@ -312,11 +312,11 @@ namespace OpenSim.Region.ClientStack.Linden | |||
312 | primFace.RepeatV = face.ScaleT; | 312 | primFace.RepeatV = face.ScaleT; |
313 | primFace.TexMapType = (MappingType) (face.MediaFlags & 6); | 313 | primFace.TexMapType = (MappingType) (face.MediaFlags & 6); |
314 | } | 314 | } |
315 | |||
315 | pbs.TextureEntry = tmp.GetBytes(); | 316 | pbs.TextureEntry = tmp.GetBytes(); |
316 | prim.Shape = pbs; | 317 | prim.Shape = pbs; |
317 | prim.Scale = obj.Scale; | 318 | prim.Scale = obj.Scale; |
318 | 319 | ||
319 | |||
320 | SceneObjectGroup grp = new SceneObjectGroup(); | 320 | SceneObjectGroup grp = new SceneObjectGroup(); |
321 | 321 | ||
322 | grp.SetRootPart(prim); | 322 | grp.SetRootPart(prim); |
@@ -330,7 +330,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
330 | grp.AbsolutePosition = obj.Position; | 330 | grp.AbsolutePosition = obj.Position; |
331 | prim.RotationOffset = obj.Rotation; | 331 | prim.RotationOffset = obj.Rotation; |
332 | 332 | ||
333 | grp.RootPart.IsAttachment = false; | 333 | grp.IsAttachment = false; |
334 | // Required for linking | 334 | // Required for linking |
335 | grp.RootPart.UpdateFlag = 0; | 335 | grp.RootPart.UpdateFlag = 0; |
336 | 336 | ||
@@ -339,8 +339,8 @@ namespace OpenSim.Region.ClientStack.Linden | |||
339 | m_scene.AddSceneObject(grp); | 339 | m_scene.AddSceneObject(grp); |
340 | grp.AbsolutePosition = obj.Position; | 340 | grp.AbsolutePosition = obj.Position; |
341 | } | 341 | } |
342 | |||
342 | allparts[i] = grp; | 343 | allparts[i] = grp; |
343 | |||
344 | } | 344 | } |
345 | 345 | ||
346 | for (int j = 1; j < allparts.Length; j++) | 346 | for (int j = 1; j < allparts.Length; j++) |
@@ -351,7 +351,9 @@ namespace OpenSim.Region.ClientStack.Linden | |||
351 | } | 351 | } |
352 | 352 | ||
353 | rootGroup.ScheduleGroupForFullUpdate(); | 353 | rootGroup.ScheduleGroupForFullUpdate(); |
354 | pos = m_scene.GetNewRezLocation(Vector3.Zero, rootpos, UUID.Zero, rot, (byte)1, 1, true, allparts[0].GroupScale(), false); | 354 | pos |
355 | = m_scene.GetNewRezLocation( | ||
356 | Vector3.Zero, rootpos, UUID.Zero, rot, (byte)1, 1, true, allparts[0].GroupScale, false); | ||
355 | 357 | ||
356 | responsedata["int_response_code"] = 200; //501; //410; //404; | 358 | responsedata["int_response_code"] = 200; //501; //410; //404; |
357 | responsedata["content_type"] = "text/plain"; | 359 | responsedata["content_type"] = "text/plain"; |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs index 9f78948..1dd8938 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs | |||
@@ -43,21 +43,29 @@ using Caps = OpenSim.Framework.Capabilities.Caps; | |||
43 | namespace OpenSim.Region.ClientStack.Linden | 43 | namespace OpenSim.Region.ClientStack.Linden |
44 | { | 44 | { |
45 | /// <summary> | 45 | /// <summary> |
46 | /// SimulatorFeatures capability. This is required for uploading Mesh. | 46 | /// SimulatorFeatures capability. |
47 | /// </summary> | ||
48 | /// <remarks> | ||
49 | /// This is required for uploading Mesh. | ||
47 | /// Since is accepts an open-ended response, we also send more information | 50 | /// Since is accepts an open-ended response, we also send more information |
48 | /// for viewers that care to interpret it. | 51 | /// for viewers that care to interpret it. |
49 | /// | 52 | /// |
50 | /// NOTE: Part of this code was adapted from the Aurora project, specifically | 53 | /// NOTE: Part of this code was adapted from the Aurora project, specifically |
51 | /// the normal part of the response in the capability handler. | 54 | /// the normal part of the response in the capability handler. |
52 | /// </summary> | 55 | /// </remarks> |
53 | /// | ||
54 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] | 56 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] |
55 | public class SimulatorFeaturesModule : ISharedRegionModule | 57 | public class SimulatorFeaturesModule : ISharedRegionModule, ISimulatorFeaturesModule |
56 | { | 58 | { |
57 | private static readonly ILog m_log = | 59 | // private static readonly ILog m_log = |
58 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 60 | // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
61 | |||
59 | private Scene m_scene; | 62 | private Scene m_scene; |
60 | 63 | ||
64 | /// <summary> | ||
65 | /// Simulator features | ||
66 | /// </summary> | ||
67 | private OSDMap m_features = new OSDMap(); | ||
68 | |||
61 | private string m_MapImageServerURL = string.Empty; | 69 | private string m_MapImageServerURL = string.Empty; |
62 | private string m_SearchURL = string.Empty; | 70 | private string m_SearchURL = string.Empty; |
63 | 71 | ||
@@ -66,18 +74,20 @@ namespace OpenSim.Region.ClientStack.Linden | |||
66 | public void Initialise(IConfigSource source) | 74 | public void Initialise(IConfigSource source) |
67 | { | 75 | { |
68 | IConfig config = source.Configs["SimulatorFeatures"]; | 76 | IConfig config = source.Configs["SimulatorFeatures"]; |
69 | if (config == null) | 77 | if (config != null) |
70 | return; | ||
71 | |||
72 | m_MapImageServerURL = config.GetString("MapImageServerURI", string.Empty); | ||
73 | if (m_MapImageServerURL != string.Empty) | ||
74 | { | 78 | { |
75 | m_MapImageServerURL = m_MapImageServerURL.Trim(); | 79 | m_MapImageServerURL = config.GetString("MapImageServerURI", string.Empty); |
76 | if (!m_MapImageServerURL.EndsWith("/")) | 80 | if (m_MapImageServerURL != string.Empty) |
77 | m_MapImageServerURL = m_MapImageServerURL + "/"; | 81 | { |
82 | m_MapImageServerURL = m_MapImageServerURL.Trim(); | ||
83 | if (!m_MapImageServerURL.EndsWith("/")) | ||
84 | m_MapImageServerURL = m_MapImageServerURL + "/"; | ||
85 | } | ||
86 | |||
87 | m_SearchURL = config.GetString("SearchServerURI", string.Empty); | ||
78 | } | 88 | } |
79 | 89 | ||
80 | m_SearchURL = config.GetString("SearchServerURI", string.Empty); | 90 | AddDefaultFeatures(); |
81 | } | 91 | } |
82 | 92 | ||
83 | public void AddRegion(Scene s) | 93 | public void AddRegion(Scene s) |
@@ -110,43 +120,83 @@ namespace OpenSim.Region.ClientStack.Linden | |||
110 | 120 | ||
111 | #endregion | 121 | #endregion |
112 | 122 | ||
123 | /// <summary> | ||
124 | /// Add default features | ||
125 | /// </summary> | ||
126 | /// <remarks> | ||
127 | /// TODO: These should be added from other modules rather than hardcoded. | ||
128 | /// </remarks> | ||
129 | private void AddDefaultFeatures() | ||
130 | { | ||
131 | lock (m_features) | ||
132 | { | ||
133 | m_features["MeshRezEnabled"] = true; | ||
134 | m_features["MeshUploadEnabled"] = true; | ||
135 | m_features["MeshXferEnabled"] = true; | ||
136 | m_features["PhysicsMaterialsEnabled"] = true; | ||
137 | |||
138 | OSDMap typesMap = new OSDMap(); | ||
139 | typesMap["convex"] = true; | ||
140 | typesMap["none"] = true; | ||
141 | typesMap["prim"] = true; | ||
142 | m_features["PhysicsShapeTypes"] = typesMap; | ||
143 | |||
144 | // Extra information for viewers that want to use it | ||
145 | OSDMap gridServicesMap = new OSDMap(); | ||
146 | if (m_MapImageServerURL != string.Empty) | ||
147 | gridServicesMap["map-server-url"] = m_MapImageServerURL; | ||
148 | if (m_SearchURL != string.Empty) | ||
149 | gridServicesMap["search"] = m_SearchURL; | ||
150 | m_features["GridServices"] = gridServicesMap; | ||
151 | } | ||
152 | } | ||
153 | |||
113 | public void RegisterCaps(UUID agentID, Caps caps) | 154 | public void RegisterCaps(UUID agentID, Caps caps) |
114 | { | 155 | { |
115 | IRequestHandler reqHandler = new RestHTTPHandler("GET", "/CAPS/" + UUID.Random(), SimulatorFeatures); | 156 | IRequestHandler reqHandler |
157 | = new RestHTTPHandler("GET", "/CAPS/" + UUID.Random(), HandleSimulatorFeaturesRequest); | ||
158 | |||
116 | caps.RegisterHandler("SimulatorFeatures", reqHandler); | 159 | caps.RegisterHandler("SimulatorFeatures", reqHandler); |
117 | } | 160 | } |
118 | 161 | ||
119 | private Hashtable SimulatorFeatures(Hashtable mDhttpMethod) | 162 | public void AddFeature(string name, OSD value) |
120 | { | 163 | { |
121 | m_log.DebugFormat("[SIMULATOR FEATURES MODULE]: SimulatorFeatures request"); | 164 | lock (m_features) |
122 | OSDMap data = new OSDMap(); | 165 | m_features[name] = value; |
123 | data["MeshRezEnabled"] = true; | 166 | } |
124 | data["MeshUploadEnabled"] = true; | 167 | |
125 | data["MeshXferEnabled"] = true; | 168 | public bool RemoveFeature(string name) |
126 | data["PhysicsMaterialsEnabled"] = true; | 169 | { |
127 | 170 | lock (m_features) | |
128 | OSDMap typesMap = new OSDMap(); | 171 | return m_features.Remove(name); |
129 | typesMap["convex"] = true; | 172 | } |
130 | typesMap["none"] = true; | 173 | |
131 | typesMap["prim"] = true; | 174 | public bool TryGetFeature(string name, out OSD value) |
132 | data["PhysicsShapeTypes"] = typesMap; | 175 | { |
133 | 176 | lock (m_features) | |
134 | // Extra information for viewers that want to use it | 177 | return m_features.TryGetValue(name, out value); |
135 | OSDMap gridServicesMap = new OSDMap(); | 178 | } |
136 | if (m_MapImageServerURL != string.Empty) | 179 | |
137 | gridServicesMap["map-server-url"] = m_MapImageServerURL; | 180 | public OSDMap GetFeatures() |
138 | if (m_SearchURL != string.Empty) | 181 | { |
139 | gridServicesMap["search"] = m_SearchURL; | 182 | lock (m_features) |
140 | data["GridServices"] = gridServicesMap; | 183 | return new OSDMap(m_features); |
184 | } | ||
185 | |||
186 | private Hashtable HandleSimulatorFeaturesRequest(Hashtable mDhttpMethod) | ||
187 | { | ||
188 | // m_log.DebugFormat("[SIMULATOR FEATURES MODULE]: SimulatorFeatures request"); | ||
141 | 189 | ||
142 | //Send back data | 190 | //Send back data |
143 | Hashtable responsedata = new Hashtable(); | 191 | Hashtable responsedata = new Hashtable(); |
144 | responsedata["int_response_code"] = 200; | 192 | responsedata["int_response_code"] = 200; |
145 | responsedata["content_type"] = "text/plain"; | 193 | responsedata["content_type"] = "text/plain"; |
146 | responsedata["keepalive"] = false; | 194 | responsedata["keepalive"] = false; |
147 | responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(data); | 195 | |
196 | lock (m_features) | ||
197 | responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(m_features); | ||
198 | |||
148 | return responsedata; | 199 | return responsedata; |
149 | } | 200 | } |
150 | |||
151 | } | 201 | } |
152 | } | 202 | } |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index d5419cc..5c94fba 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | |||
@@ -90,7 +90,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
90 | public event ObjectAttach OnObjectAttach; | 90 | public event ObjectAttach OnObjectAttach; |
91 | public event ObjectDeselect OnObjectDetach; | 91 | public event ObjectDeselect OnObjectDetach; |
92 | public event ObjectDrop OnObjectDrop; | 92 | public event ObjectDrop OnObjectDrop; |
93 | public event GenericCall1 OnCompleteMovementToRegion; | 93 | public event Action<IClientAPI, bool> OnCompleteMovementToRegion; |
94 | public event UpdateAgent OnPreAgentUpdate; | 94 | public event UpdateAgent OnPreAgentUpdate; |
95 | public event UpdateAgent OnAgentUpdate; | 95 | public event UpdateAgent OnAgentUpdate; |
96 | public event AgentRequestSit OnAgentRequestSit; | 96 | public event AgentRequestSit OnAgentRequestSit; |
@@ -232,7 +232,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
232 | public event ScriptReset OnScriptReset; | 232 | public event ScriptReset OnScriptReset; |
233 | public event GetScriptRunning OnGetScriptRunning; | 233 | public event GetScriptRunning OnGetScriptRunning; |
234 | public event SetScriptRunning OnSetScriptRunning; | 234 | public event SetScriptRunning OnSetScriptRunning; |
235 | public event UpdateVector OnAutoPilotGo; | 235 | public event Action<Vector3, bool> OnAutoPilotGo; |
236 | public event TerrainUnacked OnUnackedTerrain; | 236 | public event TerrainUnacked OnUnackedTerrain; |
237 | public event ActivateGesture OnActivateGesture; | 237 | public event ActivateGesture OnActivateGesture; |
238 | public event DeactivateGesture OnDeactivateGesture; | 238 | public event DeactivateGesture OnDeactivateGesture; |
@@ -534,7 +534,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
534 | m_udpServer.Flush(m_udpClient); | 534 | m_udpServer.Flush(m_udpClient); |
535 | 535 | ||
536 | // Remove ourselves from the scene | 536 | // Remove ourselves from the scene |
537 | m_scene.RemoveClient(AgentId); | 537 | m_scene.RemoveClient(AgentId, true); |
538 | 538 | ||
539 | // We can't reach into other scenes and close the connection | 539 | // We can't reach into other scenes and close the connection |
540 | // We need to do this over grid communications | 540 | // We need to do this over grid communications |
@@ -596,22 +596,42 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
596 | return result; | 596 | return result; |
597 | } | 597 | } |
598 | 598 | ||
599 | /// <summary> | ||
600 | /// Add a handler for the given packet type. | ||
601 | /// </summary> | ||
602 | /// <remarks>The packet is handled on its own thread. If packets must be handled in the order in which thye | ||
603 | /// are received then please us ethe synchronous version of this method.</remarks> | ||
604 | /// <param name="packetType"></param> | ||
605 | /// <param name="handler"></param> | ||
606 | /// <returns>true if the handler was added. This is currently always the case.</returns> | ||
599 | public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler) | 607 | public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler) |
600 | { | 608 | { |
601 | return AddLocalPacketHandler(packetType, handler, true); | 609 | return AddLocalPacketHandler(packetType, handler, true); |
602 | } | 610 | } |
603 | 611 | ||
604 | public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler, bool async) | 612 | /// <summary> |
613 | /// Add a handler for the given packet type. | ||
614 | /// </summary> | ||
615 | /// <param name="packetType"></param> | ||
616 | /// <param name="handler"></param> | ||
617 | /// <param name="doAsync"> | ||
618 | /// If true, when the packet is received it is handled on its own thread rather than on the main inward bound | ||
619 | /// packet handler thread. This vastly increases respnosiveness but some packets need to be handled | ||
620 | /// synchronously. | ||
621 | /// </param> | ||
622 | /// <returns>true if the handler was added. This is currently always the case.</returns> | ||
623 | public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler, bool doAsync) | ||
605 | { | 624 | { |
606 | bool result = false; | 625 | bool result = false; |
607 | lock (m_packetHandlers) | 626 | lock (m_packetHandlers) |
608 | { | 627 | { |
609 | if (!m_packetHandlers.ContainsKey(packetType)) | 628 | if (!m_packetHandlers.ContainsKey(packetType)) |
610 | { | 629 | { |
611 | m_packetHandlers.Add(packetType, new PacketProcessor() { method = handler, Async = async }); | 630 | m_packetHandlers.Add(packetType, new PacketProcessor() { method = handler, Async = doAsync }); |
612 | result = true; | 631 | result = true; |
613 | } | 632 | } |
614 | } | 633 | } |
634 | |||
615 | return result; | 635 | return result; |
616 | } | 636 | } |
617 | 637 | ||
@@ -694,7 +714,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
694 | 714 | ||
695 | public virtual void Start() | 715 | public virtual void Start() |
696 | { | 716 | { |
697 | m_scene.AddNewClient(this); | 717 | m_scene.AddNewClient(this, PresenceType.User); |
698 | 718 | ||
699 | RefreshGroupMembership(); | 719 | RefreshGroupMembership(); |
700 | } | 720 | } |
@@ -4800,7 +4820,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4800 | { | 4820 | { |
4801 | SceneObjectPart part = (SceneObjectPart)entity; | 4821 | SceneObjectPart part = (SceneObjectPart)entity; |
4802 | 4822 | ||
4803 | attachPoint = part.AttachmentPoint; | 4823 | attachPoint = part.ParentGroup.AttachmentPoint; |
4824 | |||
4825 | // m_log.DebugFormat( | ||
4826 | // "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}", | ||
4827 | // attachPoint, part.Name, part.LocalId, Name); | ||
4828 | |||
4804 | collisionPlane = Vector4.Zero; | 4829 | collisionPlane = Vector4.Zero; |
4805 | position = part.RelativePosition; | 4830 | position = part.RelativePosition; |
4806 | velocity = part.Velocity; | 4831 | velocity = part.Velocity; |
@@ -4957,17 +4982,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4957 | //update.JointType = 0; | 4982 | //update.JointType = 0; |
4958 | update.Material = data.Material; | 4983 | update.Material = data.Material; |
4959 | update.MediaURL = Utils.EmptyBytes; // FIXME: Support this in OpenSim | 4984 | update.MediaURL = Utils.EmptyBytes; // FIXME: Support this in OpenSim |
4960 | if (data.IsAttachment) | 4985 | if (data.ParentGroup.IsAttachment) |
4961 | { | 4986 | { |
4962 | update.NameValue = Util.StringToBytes256("AttachItemID STRING RW SV " + data.FromItemID); | 4987 | update.NameValue = Util.StringToBytes256("AttachItemID STRING RW SV " + data.FromItemID); |
4963 | update.State = (byte)((data.AttachmentPoint % 16) * 16 + (data.AttachmentPoint / 16)); | 4988 | update.State = (byte)((data.ParentGroup.AttachmentPoint % 16) * 16 + (data.ParentGroup.AttachmentPoint / 16)); |
4964 | } | 4989 | } |
4965 | else | 4990 | else |
4966 | { | 4991 | { |
4967 | update.NameValue = Utils.EmptyBytes; | 4992 | update.NameValue = Utils.EmptyBytes; |
4968 | update.State = data.Shape.State; | 4993 | |
4994 | // The root part state is the canonical state for all parts of the object. The other part states in the | ||
4995 | // case for attachments may contain conflicting values that can end up crashing the viewer. | ||
4996 | update.State = data.ParentGroup.RootPart.Shape.State; | ||
4969 | } | 4997 | } |
4970 | 4998 | ||
4999 | // m_log.DebugFormat( | ||
5000 | // "[LLCLIENTVIEW]: Sending state {0} for {1} {2} to {3}", | ||
5001 | // update.State, data.Name, data.LocalId, Name); | ||
5002 | |||
4971 | update.ObjectData = objectData; | 5003 | update.ObjectData = objectData; |
4972 | update.ParentID = data.ParentID; | 5004 | update.ParentID = data.ParentID; |
4973 | update.PathBegin = data.Shape.PathBegin; | 5005 | update.PathBegin = data.Shape.PathBegin; |
@@ -5311,6 +5343,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5311 | AddLocalPacketHandler(PacketType.GroupVoteHistoryRequest, HandleGroupVoteHistoryRequest); | 5343 | AddLocalPacketHandler(PacketType.GroupVoteHistoryRequest, HandleGroupVoteHistoryRequest); |
5312 | AddLocalPacketHandler(PacketType.SimWideDeletes, HandleSimWideDeletes); | 5344 | AddLocalPacketHandler(PacketType.SimWideDeletes, HandleSimWideDeletes); |
5313 | AddLocalPacketHandler(PacketType.SendPostcard, HandleSendPostcard); | 5345 | AddLocalPacketHandler(PacketType.SendPostcard, HandleSendPostcard); |
5346 | |||
5347 | AddGenericPacketHandler("autopilot", HandleAutopilot); | ||
5314 | } | 5348 | } |
5315 | 5349 | ||
5316 | #region Packet Handlers | 5350 | #region Packet Handlers |
@@ -5354,7 +5388,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5354 | ); | 5388 | ); |
5355 | } | 5389 | } |
5356 | else | 5390 | else |
5391 | { | ||
5357 | update = true; | 5392 | update = true; |
5393 | } | ||
5358 | 5394 | ||
5359 | // These should be ordered from most-likely to | 5395 | // These should be ordered from most-likely to |
5360 | // least likely to change. I've made an initial | 5396 | // least likely to change. I've made an initial |
@@ -5362,6 +5398,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5362 | 5398 | ||
5363 | if (update) | 5399 | if (update) |
5364 | { | 5400 | { |
5401 | // m_log.DebugFormat("[LLCLIENTVIEW]: Triggered AgentUpdate for {0}", sener.Name); | ||
5402 | |||
5365 | AgentUpdateArgs arg = new AgentUpdateArgs(); | 5403 | AgentUpdateArgs arg = new AgentUpdateArgs(); |
5366 | arg.AgentID = x.AgentID; | 5404 | arg.AgentID = x.AgentID; |
5367 | arg.BodyRotation = x.BodyRotation; | 5405 | arg.BodyRotation = x.BodyRotation; |
@@ -6235,10 +6273,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6235 | 6273 | ||
6236 | private bool HandleCompleteAgentMovement(IClientAPI sender, Packet Pack) | 6274 | private bool HandleCompleteAgentMovement(IClientAPI sender, Packet Pack) |
6237 | { | 6275 | { |
6238 | GenericCall1 handlerCompleteMovementToRegion = OnCompleteMovementToRegion; | 6276 | Action<IClientAPI, bool> handlerCompleteMovementToRegion = OnCompleteMovementToRegion; |
6239 | if (handlerCompleteMovementToRegion != null) | 6277 | if (handlerCompleteMovementToRegion != null) |
6240 | { | 6278 | { |
6241 | handlerCompleteMovementToRegion(sender); | 6279 | handlerCompleteMovementToRegion(sender, true); |
6242 | } | 6280 | } |
6243 | handlerCompleteMovementToRegion = null; | 6281 | handlerCompleteMovementToRegion = null; |
6244 | 6282 | ||
@@ -11316,8 +11354,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11316 | protected bool HandleMultipleObjUpdate(IClientAPI simClient, Packet packet) | 11354 | protected bool HandleMultipleObjUpdate(IClientAPI simClient, Packet packet) |
11317 | { | 11355 | { |
11318 | MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet; | 11356 | MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet; |
11319 | if (multipleupdate.AgentData.SessionID != SessionId) return false; | 11357 | |
11320 | // m_log.Debug("new multi update packet " + multipleupdate.ToString()); | 11358 | if (multipleupdate.AgentData.SessionID != SessionId) |
11359 | return false; | ||
11360 | |||
11361 | // m_log.DebugFormat( | ||
11362 | // "[CLIENT]: Incoming MultipleObjectUpdatePacket contained {0} blocks", multipleupdate.ObjectData.Length); | ||
11363 | |||
11321 | Scene tScene = (Scene)m_scene; | 11364 | Scene tScene = (Scene)m_scene; |
11322 | 11365 | ||
11323 | for (int i = 0; i < multipleupdate.ObjectData.Length; i++) | 11366 | for (int i = 0; i < multipleupdate.ObjectData.Length; i++) |
@@ -11338,7 +11381,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11338 | } | 11381 | } |
11339 | else | 11382 | else |
11340 | { | 11383 | { |
11341 | // UUID partId = part.UUID; | 11384 | // m_log.DebugFormat( |
11385 | // "[CLIENT]: Processing block {0} type {1} for {2} {3}", | ||
11386 | // i, block.Type, part.Name, part.LocalId); | ||
11387 | |||
11388 | // // Do this once since fetch parts creates a new array. | ||
11389 | // SceneObjectPart[] parts = part.ParentGroup.Parts; | ||
11390 | // for (int j = 0; j < parts.Length; j++) | ||
11391 | // { | ||
11392 | // part.StoreUndoState(); | ||
11393 | // parts[j].IgnoreUndoUpdate = true; | ||
11394 | // } | ||
11395 | |||
11342 | UpdatePrimGroupRotation handlerUpdatePrimGroupRotation; | 11396 | UpdatePrimGroupRotation handlerUpdatePrimGroupRotation; |
11343 | 11397 | ||
11344 | switch (block.Type) | 11398 | switch (block.Type) |
@@ -11353,6 +11407,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11353 | handlerUpdatePrimSinglePosition(localId, pos1, this); | 11407 | handlerUpdatePrimSinglePosition(localId, pos1, this); |
11354 | } | 11408 | } |
11355 | break; | 11409 | break; |
11410 | |||
11356 | case 2: | 11411 | case 2: |
11357 | Quaternion rot1 = new Quaternion(block.Data, 0, true); | 11412 | Quaternion rot1 = new Quaternion(block.Data, 0, true); |
11358 | 11413 | ||
@@ -11363,6 +11418,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11363 | handlerUpdatePrimSingleRotation(localId, rot1, this); | 11418 | handlerUpdatePrimSingleRotation(localId, rot1, this); |
11364 | } | 11419 | } |
11365 | break; | 11420 | break; |
11421 | |||
11366 | case 3: | 11422 | case 3: |
11367 | Vector3 rotPos = new Vector3(block.Data, 0); | 11423 | Vector3 rotPos = new Vector3(block.Data, 0); |
11368 | Quaternion rot2 = new Quaternion(block.Data, 12, true); | 11424 | Quaternion rot2 = new Quaternion(block.Data, 12, true); |
@@ -11375,6 +11431,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11375 | handlerUpdatePrimSingleRotationPosition(localId, rot2, rotPos, this); | 11431 | handlerUpdatePrimSingleRotationPosition(localId, rot2, rotPos, this); |
11376 | } | 11432 | } |
11377 | break; | 11433 | break; |
11434 | |||
11378 | case 4: | 11435 | case 4: |
11379 | case 20: | 11436 | case 20: |
11380 | Vector3 scale4 = new Vector3(block.Data, 0); | 11437 | Vector3 scale4 = new Vector3(block.Data, 0); |
@@ -11386,8 +11443,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11386 | handlerUpdatePrimScale(localId, scale4, this); | 11443 | handlerUpdatePrimScale(localId, scale4, this); |
11387 | } | 11444 | } |
11388 | break; | 11445 | break; |
11389 | case 5: | ||
11390 | 11446 | ||
11447 | case 5: | ||
11391 | Vector3 scale1 = new Vector3(block.Data, 12); | 11448 | Vector3 scale1 = new Vector3(block.Data, 12); |
11392 | Vector3 pos11 = new Vector3(block.Data, 0); | 11449 | Vector3 pos11 = new Vector3(block.Data, 0); |
11393 | 11450 | ||
@@ -11404,6 +11461,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11404 | } | 11461 | } |
11405 | } | 11462 | } |
11406 | break; | 11463 | break; |
11464 | |||
11407 | case 9: | 11465 | case 9: |
11408 | Vector3 pos2 = new Vector3(block.Data, 0); | 11466 | Vector3 pos2 = new Vector3(block.Data, 0); |
11409 | 11467 | ||
@@ -11411,10 +11469,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11411 | 11469 | ||
11412 | if (handlerUpdateVector != null) | 11470 | if (handlerUpdateVector != null) |
11413 | { | 11471 | { |
11414 | |||
11415 | handlerUpdateVector(localId, pos2, this); | 11472 | handlerUpdateVector(localId, pos2, this); |
11416 | } | 11473 | } |
11417 | break; | 11474 | break; |
11475 | |||
11418 | case 10: | 11476 | case 10: |
11419 | Quaternion rot3 = new Quaternion(block.Data, 0, true); | 11477 | Quaternion rot3 = new Quaternion(block.Data, 0, true); |
11420 | 11478 | ||
@@ -11425,6 +11483,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11425 | handlerUpdatePrimRotation(localId, rot3, this); | 11483 | handlerUpdatePrimRotation(localId, rot3, this); |
11426 | } | 11484 | } |
11427 | break; | 11485 | break; |
11486 | |||
11428 | case 11: | 11487 | case 11: |
11429 | Vector3 pos3 = new Vector3(block.Data, 0); | 11488 | Vector3 pos3 = new Vector3(block.Data, 0); |
11430 | Quaternion rot4 = new Quaternion(block.Data, 12, true); | 11489 | Quaternion rot4 = new Quaternion(block.Data, 12, true); |
@@ -11448,6 +11507,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11448 | handlerUpdatePrimGroupScale(localId, scale7, this); | 11507 | handlerUpdatePrimGroupScale(localId, scale7, this); |
11449 | } | 11508 | } |
11450 | break; | 11509 | break; |
11510 | |||
11451 | case 13: | 11511 | case 13: |
11452 | Vector3 scale2 = new Vector3(block.Data, 12); | 11512 | Vector3 scale2 = new Vector3(block.Data, 12); |
11453 | Vector3 pos4 = new Vector3(block.Data, 0); | 11513 | Vector3 pos4 = new Vector3(block.Data, 0); |
@@ -11467,6 +11527,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11467 | } | 11527 | } |
11468 | } | 11528 | } |
11469 | break; | 11529 | break; |
11530 | |||
11470 | case 29: | 11531 | case 29: |
11471 | Vector3 scale5 = new Vector3(block.Data, 12); | 11532 | Vector3 scale5 = new Vector3(block.Data, 12); |
11472 | Vector3 pos5 = new Vector3(block.Data, 0); | 11533 | Vector3 pos5 = new Vector3(block.Data, 0); |
@@ -11475,6 +11536,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11475 | if (handlerUpdatePrimGroupScale != null) | 11536 | if (handlerUpdatePrimGroupScale != null) |
11476 | { | 11537 | { |
11477 | // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z); | 11538 | // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z); |
11539 | part.StoreUndoState(true); | ||
11540 | part.IgnoreUndoUpdate = true; | ||
11478 | handlerUpdatePrimGroupScale(localId, scale5, this); | 11541 | handlerUpdatePrimGroupScale(localId, scale5, this); |
11479 | handlerUpdateVector = OnUpdatePrimGroupPosition; | 11542 | handlerUpdateVector = OnUpdatePrimGroupPosition; |
11480 | 11543 | ||
@@ -11482,8 +11545,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11482 | { | 11545 | { |
11483 | handlerUpdateVector(localId, pos5, this); | 11546 | handlerUpdateVector(localId, pos5, this); |
11484 | } | 11547 | } |
11548 | |||
11549 | part.IgnoreUndoUpdate = false; | ||
11485 | } | 11550 | } |
11551 | |||
11486 | break; | 11552 | break; |
11553 | |||
11487 | case 21: | 11554 | case 21: |
11488 | Vector3 scale6 = new Vector3(block.Data, 12); | 11555 | Vector3 scale6 = new Vector3(block.Data, 12); |
11489 | Vector3 pos6 = new Vector3(block.Data, 0); | 11556 | Vector3 pos6 = new Vector3(block.Data, 0); |
@@ -11491,6 +11558,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11491 | handlerUpdatePrimScale = OnUpdatePrimScale; | 11558 | handlerUpdatePrimScale = OnUpdatePrimScale; |
11492 | if (handlerUpdatePrimScale != null) | 11559 | if (handlerUpdatePrimScale != null) |
11493 | { | 11560 | { |
11561 | part.StoreUndoState(false); | ||
11562 | part.IgnoreUndoUpdate = true; | ||
11563 | |||
11494 | // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z); | 11564 | // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z); |
11495 | handlerUpdatePrimScale(localId, scale6, this); | 11565 | handlerUpdatePrimScale(localId, scale6, this); |
11496 | handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; | 11566 | handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; |
@@ -11498,15 +11568,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11498 | { | 11568 | { |
11499 | handlerUpdatePrimSinglePosition(localId, pos6, this); | 11569 | handlerUpdatePrimSinglePosition(localId, pos6, this); |
11500 | } | 11570 | } |
11571 | |||
11572 | part.IgnoreUndoUpdate = false; | ||
11501 | } | 11573 | } |
11502 | break; | 11574 | break; |
11575 | |||
11503 | default: | 11576 | default: |
11504 | m_log.Debug("[CLIENT] MultipleObjUpdate recieved an unknown packet type: " + (block.Type)); | 11577 | m_log.Debug("[CLIENT]: MultipleObjUpdate recieved an unknown packet type: " + (block.Type)); |
11505 | break; | 11578 | break; |
11506 | } | 11579 | } |
11580 | |||
11581 | // for (int j = 0; j < parts.Length; j++) | ||
11582 | // parts[j].IgnoreUndoUpdate = false; | ||
11507 | } | 11583 | } |
11508 | } | 11584 | } |
11509 | } | 11585 | } |
11586 | |||
11510 | return true; | 11587 | return true; |
11511 | } | 11588 | } |
11512 | 11589 | ||
@@ -11666,55 +11743,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11666 | return false; | 11743 | return false; |
11667 | } | 11744 | } |
11668 | 11745 | ||
11669 | /// <summary> | 11746 | protected void HandleAutopilot(Object sender, string method, List<String> args) |
11670 | /// Breaks down the genericMessagePacket into specific events | ||
11671 | /// </summary> | ||
11672 | /// <param name="gmMethod"></param> | ||
11673 | /// <param name="gmInvoice"></param> | ||
11674 | /// <param name="gmParams"></param> | ||
11675 | public void DecipherGenericMessage(string gmMethod, UUID gmInvoice, GenericMessagePacket.ParamListBlock[] gmParams) | ||
11676 | { | 11747 | { |
11677 | switch (gmMethod) | 11748 | float locx = 0; |
11678 | { | 11749 | float locy = 0; |
11679 | case "autopilot": | 11750 | float locz = 0; |
11680 | float locx; | 11751 | uint regionX = 0; |
11681 | float locy; | 11752 | uint regionY = 0; |
11682 | float locz; | ||
11683 | |||
11684 | try | ||
11685 | { | ||
11686 | uint regionX; | ||
11687 | uint regionY; | ||
11688 | Utils.LongToUInts(Scene.RegionInfo.RegionHandle, out regionX, out regionY); | ||
11689 | locx = Convert.ToSingle(Utils.BytesToString(gmParams[0].Parameter)) - regionX; | ||
11690 | locy = Convert.ToSingle(Utils.BytesToString(gmParams[1].Parameter)) - regionY; | ||
11691 | locz = Convert.ToSingle(Utils.BytesToString(gmParams[2].Parameter)); | ||
11692 | } | ||
11693 | catch (InvalidCastException) | ||
11694 | { | ||
11695 | m_log.Error("[CLIENT]: Invalid autopilot request"); | ||
11696 | return; | ||
11697 | } | ||
11698 | |||
11699 | UpdateVector handlerAutoPilotGo = OnAutoPilotGo; | ||
11700 | if (handlerAutoPilotGo != null) | ||
11701 | { | ||
11702 | handlerAutoPilotGo(0, new Vector3(locx, locy, locz), this); | ||
11703 | } | ||
11704 | m_log.InfoFormat("[CLIENT]: Client Requests autopilot to position <{0},{1},{2}>", locx, locy, locz); | ||
11705 | 11753 | ||
11754 | Utils.LongToUInts(m_scene.RegionInfo.RegionHandle, out regionX, out regionY); | ||
11755 | locx = Convert.ToSingle(args[0]) - (float)regionX; | ||
11756 | locy = Convert.ToSingle(args[1]) - (float)regionY; | ||
11757 | locz = Convert.ToSingle(args[2]); | ||
11706 | 11758 | ||
11707 | break; | 11759 | Action<Vector3, bool> handlerAutoPilotGo = OnAutoPilotGo; |
11708 | default: | 11760 | if (handlerAutoPilotGo != null) |
11709 | m_log.Debug("[CLIENT]: Unknown Generic Message, Method: " + gmMethod + ". Invoice: " + gmInvoice + ". Dumping Params:"); | 11761 | handlerAutoPilotGo(new Vector3(locx, locy, locz), false); |
11710 | for (int hi = 0; hi < gmParams.Length; hi++) | ||
11711 | { | ||
11712 | Console.WriteLine(gmParams[hi].ToString()); | ||
11713 | } | ||
11714 | //gmpack.MethodData. | ||
11715 | break; | ||
11716 | |||
11717 | } | ||
11718 | } | 11762 | } |
11719 | 11763 | ||
11720 | /// <summary> | 11764 | /// <summary> |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs index 29fd1a4..4c33db5 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs | |||
@@ -44,7 +44,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
44 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 44 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
45 | private static Int32 m_counter = 0; | 45 | private static Int32 m_counter = 0; |
46 | 46 | ||
47 | private Int32 m_identifier; | 47 | // private Int32 m_identifier; |
48 | 48 | ||
49 | /// <summary> | 49 | /// <summary> |
50 | /// Number of ticks (ms) per quantum, drip rate and max burst | 50 | /// Number of ticks (ms) per quantum, drip rate and max burst |
@@ -173,7 +173,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
173 | /// second. If zero, the bucket always remains full</param> | 173 | /// second. If zero, the bucket always remains full</param> |
174 | public TokenBucket(TokenBucket parent, Int64 dripRate) | 174 | public TokenBucket(TokenBucket parent, Int64 dripRate) |
175 | { | 175 | { |
176 | m_identifier = m_counter++; | 176 | // m_identifier = m_counter++; |
177 | m_counter++; | ||
177 | 178 | ||
178 | Parent = parent; | 179 | Parent = parent; |
179 | RequestedDripRate = dripRate; | 180 | RequestedDripRate = dripRate; |
@@ -320,7 +321,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
320 | 321 | ||
321 | public class AdaptiveTokenBucket : TokenBucket | 322 | public class AdaptiveTokenBucket : TokenBucket |
322 | { | 323 | { |
323 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 324 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
324 | 325 | ||
325 | /// <summary> | 326 | /// <summary> |
326 | /// The minimum rate for flow control. Minimum drip rate is one | 327 | /// The minimum rate for flow control. Minimum drip rate is one |
diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs index d85d727..a0648f7 100644 --- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs | |||
@@ -316,6 +316,12 @@ namespace Flotsam.RegionModules.AssetCache | |||
316 | LogException(e); | 316 | LogException(e); |
317 | } | 317 | } |
318 | } | 318 | } |
319 | catch (Exception e) | ||
320 | { | ||
321 | m_log.ErrorFormat( | ||
322 | "[FLOTSAM ASSET CACHE]: Failed to update cache for asset {0}. Exception {1} {2}", | ||
323 | asset.ID, e.Message, e.StackTrace); | ||
324 | } | ||
319 | } | 325 | } |
320 | 326 | ||
321 | public void Cache(AssetBase asset) | 327 | public void Cache(AssetBase asset) |
@@ -368,13 +374,13 @@ namespace Flotsam.RegionModules.AssetCache | |||
368 | 374 | ||
369 | asset = (AssetBase)bformatter.Deserialize(stream); | 375 | asset = (AssetBase)bformatter.Deserialize(stream); |
370 | 376 | ||
371 | UpdateMemoryCache(id, asset); | ||
372 | |||
373 | m_DiskHits++; | 377 | m_DiskHits++; |
374 | } | 378 | } |
375 | catch (System.Runtime.Serialization.SerializationException e) | 379 | catch (System.Runtime.Serialization.SerializationException e) |
376 | { | 380 | { |
377 | LogException(e); | 381 | m_log.ErrorFormat( |
382 | "[FLOTSAM ASSET CACHE]: Failed to get file {0} for asset {1}. Exception {2} {3}", | ||
383 | filename, id, e.Message, e.StackTrace); | ||
378 | 384 | ||
379 | // If there was a problem deserializing the asset, the asset may | 385 | // If there was a problem deserializing the asset, the asset may |
380 | // either be corrupted OR was serialized under an old format | 386 | // either be corrupted OR was serialized under an old format |
@@ -384,7 +390,9 @@ namespace Flotsam.RegionModules.AssetCache | |||
384 | } | 390 | } |
385 | catch (Exception e) | 391 | catch (Exception e) |
386 | { | 392 | { |
387 | LogException(e); | 393 | m_log.ErrorFormat( |
394 | "[FLOTSAM ASSET CACHE]: Failed to get file {0} for asset {1}. Exception {2} {3}", | ||
395 | filename, id, e.Message, e.StackTrace); | ||
388 | } | 396 | } |
389 | finally | 397 | finally |
390 | { | 398 | { |
@@ -393,7 +401,6 @@ namespace Flotsam.RegionModules.AssetCache | |||
393 | } | 401 | } |
394 | } | 402 | } |
395 | 403 | ||
396 | |||
397 | #if WAIT_ON_INPROGRESS_REQUESTS | 404 | #if WAIT_ON_INPROGRESS_REQUESTS |
398 | // Check if we're already downloading this asset. If so, try to wait for it to | 405 | // Check if we're already downloading this asset. If so, try to wait for it to |
399 | // download. | 406 | // download. |
@@ -416,7 +423,6 @@ namespace Flotsam.RegionModules.AssetCache | |||
416 | m_RequestsForInprogress++; | 423 | m_RequestsForInprogress++; |
417 | } | 424 | } |
418 | #endif | 425 | #endif |
419 | |||
420 | return asset; | 426 | return asset; |
421 | } | 427 | } |
422 | 428 | ||
@@ -428,9 +434,15 @@ namespace Flotsam.RegionModules.AssetCache | |||
428 | 434 | ||
429 | if (m_MemoryCacheEnabled) | 435 | if (m_MemoryCacheEnabled) |
430 | asset = GetFromMemoryCache(id); | 436 | asset = GetFromMemoryCache(id); |
431 | else if (m_FileCacheEnabled) | 437 | |
438 | if (asset == null && m_FileCacheEnabled) | ||
439 | { | ||
432 | asset = GetFromFileCache(id); | 440 | asset = GetFromFileCache(id); |
433 | 441 | ||
442 | if (m_MemoryCacheEnabled && asset != null) | ||
443 | UpdateMemoryCache(id, asset); | ||
444 | } | ||
445 | |||
434 | if (((m_LogLevel >= 1)) && (m_HitRateDisplay != 0) && (m_Requests % m_HitRateDisplay == 0)) | 446 | if (((m_LogLevel >= 1)) && (m_HitRateDisplay != 0) && (m_Requests % m_HitRateDisplay == 0)) |
435 | { | 447 | { |
436 | m_HitRateFile = (double)m_DiskHits / m_Requests * 100.0; | 448 | m_HitRateFile = (double)m_DiskHits / m_Requests * 100.0; |
@@ -445,7 +457,6 @@ namespace Flotsam.RegionModules.AssetCache | |||
445 | } | 457 | } |
446 | 458 | ||
447 | m_log.InfoFormat("[FLOTSAM ASSET CACHE]: {0} unnessesary requests due to requests for assets that are currently downloading.", m_RequestsForInprogress); | 459 | m_log.InfoFormat("[FLOTSAM ASSET CACHE]: {0} unnessesary requests due to requests for assets that are currently downloading.", m_RequestsForInprogress); |
448 | |||
449 | } | 460 | } |
450 | 461 | ||
451 | return asset; | 462 | return asset; |
@@ -459,7 +470,7 @@ namespace Flotsam.RegionModules.AssetCache | |||
459 | public void Expire(string id) | 470 | public void Expire(string id) |
460 | { | 471 | { |
461 | if (m_LogLevel >= 2) | 472 | if (m_LogLevel >= 2) |
462 | m_log.DebugFormat("[FLOTSAM ASSET CACHE]: Expiring Asset {0}.", id); | 473 | m_log.DebugFormat("[FLOTSAM ASSET CACHE]: Expiring Asset {0}", id); |
463 | 474 | ||
464 | try | 475 | try |
465 | { | 476 | { |
@@ -477,7 +488,9 @@ namespace Flotsam.RegionModules.AssetCache | |||
477 | } | 488 | } |
478 | catch (Exception e) | 489 | catch (Exception e) |
479 | { | 490 | { |
480 | LogException(e); | 491 | m_log.ErrorFormat( |
492 | "[FLOTSAM ASSET CACHE]: Failed to expire cached file {0}. Exception {1} {2}", | ||
493 | id, e.Message, e.StackTrace); | ||
481 | } | 494 | } |
482 | } | 495 | } |
483 | 496 | ||
@@ -597,31 +610,59 @@ namespace Flotsam.RegionModules.AssetCache | |||
597 | 610 | ||
598 | try | 611 | try |
599 | { | 612 | { |
600 | if (!Directory.Exists(directory)) | 613 | try |
601 | { | 614 | { |
602 | Directory.CreateDirectory(directory); | 615 | if (!Directory.Exists(directory)) |
616 | { | ||
617 | Directory.CreateDirectory(directory); | ||
618 | } | ||
619 | |||
620 | stream = File.Open(tempname, FileMode.Create); | ||
621 | BinaryFormatter bformatter = new BinaryFormatter(); | ||
622 | bformatter.Serialize(stream, asset); | ||
603 | } | 623 | } |
624 | catch (IOException e) | ||
625 | { | ||
626 | m_log.ErrorFormat( | ||
627 | "[FLOTSAM ASSET CACHE]: Failed to write asset {0} to temporary location {1} (final {2}) on cache in {3}. Exception {4} {5}.", | ||
628 | asset.ID, tempname, filename, directory, e.Message, e.StackTrace); | ||
604 | 629 | ||
605 | stream = File.Open(tempname, FileMode.Create); | 630 | return; |
606 | BinaryFormatter bformatter = new BinaryFormatter(); | 631 | } |
607 | bformatter.Serialize(stream, asset); | 632 | finally |
608 | stream.Close(); | 633 | { |
609 | 634 | if (stream != null) | |
610 | // Now that it's written, rename it so that it can be found. | 635 | stream.Close(); |
611 | File.Move(tempname, filename); | 636 | } |
612 | 637 | ||
613 | if (m_LogLevel >= 2) | 638 | try |
614 | m_log.DebugFormat("[FLOTSAM ASSET CACHE]: Cache Stored :: {0}", asset.ID); | 639 | { |
615 | } | 640 | // Now that it's written, rename it so that it can be found. |
616 | catch (Exception e) | 641 | // |
617 | { | 642 | // File.Copy(tempname, filename, true); |
618 | LogException(e); | 643 | // File.Delete(tempname); |
644 | // | ||
645 | // For a brief period, this was done as a separate copy and then temporary file delete operation to | ||
646 | // avoid an IOException caused by move if some competing thread had already written the file. | ||
647 | // However, this causes exceptions on Windows when other threads attempt to read a file | ||
648 | // which is still being copied. So instead, go back to moving the file and swallow any IOException. | ||
649 | // | ||
650 | // This situation occurs fairly rarely anyway. We assume in this that moves are atomic on the | ||
651 | // filesystem. | ||
652 | File.Move(tempname, filename); | ||
653 | |||
654 | if (m_LogLevel >= 2) | ||
655 | m_log.DebugFormat("[FLOTSAM ASSET CACHE]: Cache Stored :: {0}", asset.ID); | ||
656 | } | ||
657 | catch (IOException) | ||
658 | { | ||
659 | // If we see an IOException here it's likely that some other competing thread has written the | ||
660 | // cache file first, so ignore. Other IOException errors (e.g. filesystem full) should be | ||
661 | // signally by the earlier temporary file writing code. | ||
662 | } | ||
619 | } | 663 | } |
620 | finally | 664 | finally |
621 | { | 665 | { |
622 | if (stream != null) | ||
623 | stream.Close(); | ||
624 | |||
625 | // Even if the write fails with an exception, we need to make sure | 666 | // Even if the write fails with an exception, we need to make sure |
626 | // that we release the lock on that file, otherwise it'll never get | 667 | // that we release the lock on that file, otherwise it'll never get |
627 | // cached | 668 | // cached |
@@ -635,22 +676,9 @@ namespace Flotsam.RegionModules.AssetCache | |||
635 | waitEvent.Set(); | 676 | waitEvent.Set(); |
636 | } | 677 | } |
637 | #else | 678 | #else |
638 | if (m_CurrentlyWriting.Contains(filename)) | 679 | m_CurrentlyWriting.Remove(filename); |
639 | { | ||
640 | m_CurrentlyWriting.Remove(filename); | ||
641 | } | ||
642 | #endif | 680 | #endif |
643 | } | 681 | } |
644 | |||
645 | } | ||
646 | } | ||
647 | |||
648 | private static void LogException(Exception e) | ||
649 | { | ||
650 | string[] text = e.ToString().Split(new char[] { '\n' }); | ||
651 | foreach (string t in text) | ||
652 | { | ||
653 | m_log.ErrorFormat("[FLOTSAM ASSET CACHE]: {0} ", t); | ||
654 | } | 682 | } |
655 | } | 683 | } |
656 | 684 | ||
@@ -706,8 +734,7 @@ namespace Flotsam.RegionModules.AssetCache | |||
706 | s.ForEachSOG(delegate(SceneObjectGroup e) | 734 | s.ForEachSOG(delegate(SceneObjectGroup e) |
707 | { | 735 | { |
708 | gatherer.GatherAssetUuids(e, assets); | 736 | gatherer.GatherAssetUuids(e, assets); |
709 | } | 737 | }); |
710 | ); | ||
711 | } | 738 | } |
712 | 739 | ||
713 | foreach (UUID assetID in assets.Keys) | 740 | foreach (UUID assetID in assets.Keys) |
@@ -740,7 +767,9 @@ namespace Flotsam.RegionModules.AssetCache | |||
740 | } | 767 | } |
741 | catch (Exception e) | 768 | catch (Exception e) |
742 | { | 769 | { |
743 | LogException(e); | 770 | m_log.ErrorFormat( |
771 | "[FLOTSAM ASSET CACHE]: Couldn't clear asset cache directory {0} from {1}. Exception {2} {3}", | ||
772 | dir, m_CacheDirectory, e.Message, e.StackTrace); | ||
744 | } | 773 | } |
745 | } | 774 | } |
746 | 775 | ||
@@ -752,7 +781,9 @@ namespace Flotsam.RegionModules.AssetCache | |||
752 | } | 781 | } |
753 | catch (Exception e) | 782 | catch (Exception e) |
754 | { | 783 | { |
755 | LogException(e); | 784 | m_log.ErrorFormat( |
785 | "[FLOTSAM ASSET CACHE]: Couldn't clear asset cache file {0} from {1}. Exception {1} {2}", | ||
786 | file, m_CacheDirectory, e.Message, e.StackTrace); | ||
756 | } | 787 | } |
757 | } | 788 | } |
758 | } | 789 | } |
@@ -778,7 +809,7 @@ namespace Flotsam.RegionModules.AssetCache | |||
778 | 809 | ||
779 | foreach (string s in Directory.GetFiles(m_CacheDirectory, "*.fac")) | 810 | foreach (string s in Directory.GetFiles(m_CacheDirectory, "*.fac")) |
780 | { | 811 | { |
781 | m_log.Info("[FLOTSAM ASSET CACHE]: Deep Scans were performed on the following regions:"); | 812 | m_log.Info("[FLOTSAM ASSET CACHE]: Deep scans have previously been performed on the following regions:"); |
782 | 813 | ||
783 | string RegionID = s.Remove(0,s.IndexOf("_")).Replace(".fac",""); | 814 | string RegionID = s.Remove(0,s.IndexOf("_")).Replace(".fac",""); |
784 | DateTime RegionDeepScanTMStamp = File.GetLastWriteTime(s); | 815 | DateTime RegionDeepScanTMStamp = File.GetLastWriteTime(s); |
@@ -849,7 +880,6 @@ namespace Flotsam.RegionModules.AssetCache | |||
849 | Util.FireAndForget(delegate { | 880 | Util.FireAndForget(delegate { |
850 | int assetsCached = CacheScenes(); | 881 | int assetsCached = CacheScenes(); |
851 | m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Completed Scene Caching, {0} assets found.", assetsCached); | 882 | m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Completed Scene Caching, {0} assets found.", assetsCached); |
852 | |||
853 | }); | 883 | }); |
854 | 884 | ||
855 | break; | 885 | break; |
@@ -904,7 +934,6 @@ namespace Flotsam.RegionModules.AssetCache | |||
904 | 934 | ||
905 | #region IAssetService Members | 935 | #region IAssetService Members |
906 | 936 | ||
907 | |||
908 | public AssetMetadata GetMetadata(string id) | 937 | public AssetMetadata GetMetadata(string id) |
909 | { | 938 | { |
910 | AssetBase asset = Get(id); | 939 | AssetBase asset = Get(id); |
@@ -934,7 +963,6 @@ namespace Flotsam.RegionModules.AssetCache | |||
934 | Cache(asset); | 963 | Cache(asset); |
935 | 964 | ||
936 | return asset.ID; | 965 | return asset.ID; |
937 | |||
938 | } | 966 | } |
939 | 967 | ||
940 | public bool UpdateContent(string id, byte[] data) | 968 | public bool UpdateContent(string id, byte[] data) |
diff --git a/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs b/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs index 63b0c31..2ff1920 100644 --- a/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs +++ b/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs | |||
@@ -65,18 +65,18 @@ namespace OpenSim.Region.CoreModules.Asset.Tests | |||
65 | config.Configs["AssetCache"].Set("MemoryCacheEnabled", "true"); | 65 | config.Configs["AssetCache"].Set("MemoryCacheEnabled", "true"); |
66 | 66 | ||
67 | m_cache = new FlotsamAssetCache(); | 67 | m_cache = new FlotsamAssetCache(); |
68 | m_scene = SceneSetupHelpers.SetupScene(); | 68 | m_scene = SceneHelpers.SetupScene(); |
69 | SceneSetupHelpers.SetupSceneModules(m_scene, config, m_cache); | 69 | SceneHelpers.SetupSceneModules(m_scene, config, m_cache); |
70 | } | 70 | } |
71 | 71 | ||
72 | [Test] | 72 | [Test] |
73 | public void TestCacheAsset() | 73 | public void TestCacheAsset() |
74 | { | 74 | { |
75 | TestHelper.InMethod(); | 75 | TestHelpers.InMethod(); |
76 | // log4net.Config.XmlConfigurator.Configure(); | 76 | // log4net.Config.XmlConfigurator.Configure(); |
77 | 77 | ||
78 | AssetBase asset = AssetHelpers.CreateAsset(); | 78 | AssetBase asset = AssetHelpers.CreateAsset(); |
79 | asset.ID = TestHelper.ParseTail(0x1).ToString(); | 79 | asset.ID = TestHelpers.ParseTail(0x1).ToString(); |
80 | 80 | ||
81 | // Check we don't get anything before the asset is put in the cache | 81 | // Check we don't get anything before the asset is put in the cache |
82 | AssetBase retrievedAsset = m_cache.Get(asset.ID.ToString()); | 82 | AssetBase retrievedAsset = m_cache.Get(asset.ID.ToString()); |
@@ -93,11 +93,11 @@ namespace OpenSim.Region.CoreModules.Asset.Tests | |||
93 | [Test] | 93 | [Test] |
94 | public void TestExpireAsset() | 94 | public void TestExpireAsset() |
95 | { | 95 | { |
96 | TestHelper.InMethod(); | 96 | TestHelpers.InMethod(); |
97 | // log4net.Config.XmlConfigurator.Configure(); | 97 | // log4net.Config.XmlConfigurator.Configure(); |
98 | 98 | ||
99 | AssetBase asset = AssetHelpers.CreateAsset(); | 99 | AssetBase asset = AssetHelpers.CreateAsset(); |
100 | asset.ID = TestHelper.ParseTail(0x2).ToString(); | 100 | asset.ID = TestHelpers.ParseTail(0x2).ToString(); |
101 | 101 | ||
102 | m_cache.Store(asset); | 102 | m_cache.Store(asset); |
103 | 103 | ||
@@ -110,11 +110,11 @@ namespace OpenSim.Region.CoreModules.Asset.Tests | |||
110 | [Test] | 110 | [Test] |
111 | public void TestClearCache() | 111 | public void TestClearCache() |
112 | { | 112 | { |
113 | TestHelper.InMethod(); | 113 | TestHelpers.InMethod(); |
114 | // log4net.Config.XmlConfigurator.Configure(); | 114 | // log4net.Config.XmlConfigurator.Configure(); |
115 | 115 | ||
116 | AssetBase asset = AssetHelpers.CreateAsset(); | 116 | AssetBase asset = AssetHelpers.CreateAsset(); |
117 | asset.ID = TestHelper.ParseTail(0x2).ToString(); | 117 | asset.ID = TestHelpers.ParseTail(0x2).ToString(); |
118 | 118 | ||
119 | m_cache.Store(asset); | 119 | m_cache.Store(asset); |
120 | 120 | ||
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index 47476a9..8be0455 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs | |||
@@ -47,7 +47,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
47 | { | 47 | { |
48 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 48 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
49 | 49 | ||
50 | protected Scene m_scene = null; | 50 | private Scene m_scene; |
51 | private IDialogModule m_dialogModule; | ||
51 | 52 | ||
52 | public string Name { get { return "Attachments Module"; } } | 53 | public string Name { get { return "Attachments Module"; } } |
53 | public Type ReplaceableInterface { get { return null; } } | 54 | public Type ReplaceableInterface { get { return null; } } |
@@ -57,6 +58,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
57 | public void AddRegion(Scene scene) | 58 | public void AddRegion(Scene scene) |
58 | { | 59 | { |
59 | m_scene = scene; | 60 | m_scene = scene; |
61 | m_dialogModule = m_scene.RequestModuleInterface<IDialogModule>(); | ||
60 | m_scene.RegisterModuleInterface<IAttachmentsModule>(this); | 62 | m_scene.RegisterModuleInterface<IAttachmentsModule>(this); |
61 | m_scene.EventManager.OnNewClient += SubscribeToClientEvents; | 63 | m_scene.EventManager.OnNewClient += SubscribeToClientEvents; |
62 | // TODO: Should probably be subscribing to CloseClient too, but this doesn't yet give us IClientAPI | 64 | // TODO: Should probably be subscribing to CloseClient too, but this doesn't yet give us IClientAPI |
@@ -81,7 +83,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
81 | client.OnRezMultipleAttachmentsFromInv += RezMultipleAttachmentsFromInventory; | 83 | client.OnRezMultipleAttachmentsFromInv += RezMultipleAttachmentsFromInventory; |
82 | client.OnObjectAttach += AttachObject; | 84 | client.OnObjectAttach += AttachObject; |
83 | client.OnObjectDetach += DetachObject; | 85 | client.OnObjectDetach += DetachObject; |
84 | client.OnDetachAttachmentIntoInv += ShowDetachInUserInventory; | 86 | client.OnDetachAttachmentIntoInv += DetachSingleAttachmentToInv; |
87 | client.OnObjectDrop += DetachSingleAttachmentToGround; | ||
85 | } | 88 | } |
86 | 89 | ||
87 | public void UnsubscribeFromClientEvents(IClientAPI client) | 90 | public void UnsubscribeFromClientEvents(IClientAPI client) |
@@ -90,7 +93,77 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
90 | client.OnRezMultipleAttachmentsFromInv -= RezMultipleAttachmentsFromInventory; | 93 | client.OnRezMultipleAttachmentsFromInv -= RezMultipleAttachmentsFromInventory; |
91 | client.OnObjectAttach -= AttachObject; | 94 | client.OnObjectAttach -= AttachObject; |
92 | client.OnObjectDetach -= DetachObject; | 95 | client.OnObjectDetach -= DetachObject; |
93 | client.OnDetachAttachmentIntoInv -= ShowDetachInUserInventory; | 96 | client.OnDetachAttachmentIntoInv -= DetachSingleAttachmentToInv; |
97 | client.OnObjectDrop -= DetachSingleAttachmentToGround; | ||
98 | } | ||
99 | |||
100 | /// <summary> | ||
101 | /// RezAttachments. This should only be called upon login on the first region. | ||
102 | /// Attachment rezzings on crossings and TPs are done in a different way. | ||
103 | /// </summary> | ||
104 | public void RezAttachments(IScenePresence sp) | ||
105 | { | ||
106 | if (null == sp.Appearance) | ||
107 | { | ||
108 | m_log.WarnFormat("[ATTACHMENTS MODULE]: Appearance has not been initialized for agent {0}", sp.UUID); | ||
109 | return; | ||
110 | } | ||
111 | |||
112 | List<AvatarAttachment> attachments = sp.Appearance.GetAttachments(); | ||
113 | foreach (AvatarAttachment attach in attachments) | ||
114 | { | ||
115 | uint p = (uint)attach.AttachPoint; | ||
116 | |||
117 | // m_log.DebugFormat( | ||
118 | // "[ATTACHMENTS MODULE]: Doing initial rez of attachment with itemID {0}, assetID {1}, point {2} for {3} in {4}", | ||
119 | // attach.ItemID, attach.AssetID, p, sp.Name, m_scene.RegionInfo.RegionName); | ||
120 | |||
121 | // For some reason assetIDs are being written as Zero's in the DB -- need to track tat down | ||
122 | // But they're not used anyway, the item is being looked up for now, so let's proceed. | ||
123 | //if (UUID.Zero == assetID) | ||
124 | //{ | ||
125 | // m_log.DebugFormat("[ATTACHMENT]: Cannot rez attachment in point {0} with itemID {1}", p, itemID); | ||
126 | // continue; | ||
127 | //} | ||
128 | |||
129 | try | ||
130 | { | ||
131 | // If we're an NPC then skip all the item checks and manipulations since we don't have an | ||
132 | // inventory right now. | ||
133 | if (sp.PresenceType == PresenceType.Npc) | ||
134 | RezSingleAttachmentFromInventoryInternal(sp, UUID.Zero, attach.AssetID, p); | ||
135 | else | ||
136 | RezSingleAttachmentFromInventory(sp.ControllingClient, attach.ItemID, p); | ||
137 | } | ||
138 | catch (Exception e) | ||
139 | { | ||
140 | m_log.ErrorFormat("[ATTACHMENTS MODULE]: Unable to rez attachment: {0}{1}", e.Message, e.StackTrace); | ||
141 | } | ||
142 | } | ||
143 | } | ||
144 | |||
145 | public void SaveChangedAttachments(IScenePresence sp) | ||
146 | { | ||
147 | foreach (SceneObjectGroup grp in sp.GetAttachments()) | ||
148 | { | ||
149 | if (grp.HasGroupChanged) // Resizer scripts? | ||
150 | { | ||
151 | grp.IsAttachment = false; | ||
152 | grp.AbsolutePosition = grp.RootPart.AttachedPos; | ||
153 | UpdateKnownItem(sp.ControllingClient, grp, grp.GetFromItemID(), grp.OwnerID); | ||
154 | grp.IsAttachment = true; | ||
155 | } | ||
156 | } | ||
157 | } | ||
158 | |||
159 | public void DeleteAttachmentsFromScene(IScenePresence sp, bool silent) | ||
160 | { | ||
161 | foreach (SceneObjectGroup sop in sp.GetAttachments()) | ||
162 | { | ||
163 | sop.Scene.DeleteSceneObject(sop, silent); | ||
164 | } | ||
165 | |||
166 | sp.ClearAttachments(); | ||
94 | } | 167 | } |
95 | 168 | ||
96 | /// <summary> | 169 | /// <summary> |
@@ -102,10 +175,21 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
102 | /// <param name="silent"></param> | 175 | /// <param name="silent"></param> |
103 | public void AttachObject(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, bool silent) | 176 | public void AttachObject(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, bool silent) |
104 | { | 177 | { |
105 | m_log.Debug("[ATTACHMENTS MODULE]: Invoking AttachObject"); | 178 | // m_log.DebugFormat( |
179 | // "[ATTACHMENTS MODULE]: Attaching object local id {0} to {1} point {2} from ground (silent = {3})", | ||
180 | // objectLocalID, remoteClient.Name, AttachmentPt, silent); | ||
106 | 181 | ||
107 | try | 182 | try |
108 | { | 183 | { |
184 | ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); | ||
185 | |||
186 | if (sp == null) | ||
187 | { | ||
188 | m_log.ErrorFormat( | ||
189 | "[ATTACHMENTS MODULE]: Could not find presence for client {0} {1}", remoteClient.Name, remoteClient.AgentId); | ||
190 | return; | ||
191 | } | ||
192 | |||
109 | // If we can't take it, we can't attach it! | 193 | // If we can't take it, we can't attach it! |
110 | SceneObjectPart part = m_scene.GetSceneObjectPart(objectLocalID); | 194 | SceneObjectPart part = m_scene.GetSceneObjectPart(objectLocalID); |
111 | if (part == null) | 195 | if (part == null) |
@@ -131,7 +215,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
131 | AttachmentPt &= 0x7f; | 215 | AttachmentPt &= 0x7f; |
132 | 216 | ||
133 | // Calls attach with a Zero position | 217 | // Calls attach with a Zero position |
134 | if (AttachObject(remoteClient, part.ParentGroup, AttachmentPt, false)) | 218 | if (AttachObject(sp, part.ParentGroup, AttachmentPt, false)) |
135 | { | 219 | { |
136 | m_scene.EventManager.TriggerOnAttach(objectLocalID, part.ParentGroup.GetFromItemID(), remoteClient.AgentId); | 220 | m_scene.EventManager.TriggerOnAttach(objectLocalID, part.ParentGroup.GetFromItemID(), remoteClient.AgentId); |
137 | 221 | ||
@@ -144,73 +228,94 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
144 | } | 228 | } |
145 | catch (Exception e) | 229 | catch (Exception e) |
146 | { | 230 | { |
147 | m_log.DebugFormat("[ATTACHMENTS MODULE]: exception upon Attach Object {0}", e); | 231 | m_log.ErrorFormat("[ATTACHMENTS MODULE]: exception upon Attach Object {0}{1}", e.Message, e.StackTrace); |
148 | } | 232 | } |
149 | } | 233 | } |
150 | 234 | ||
151 | public bool AttachObject(IClientAPI remoteClient, SceneObjectGroup group, uint AttachmentPt, bool silent) | 235 | public bool AttachObject(IClientAPI remoteClient, SceneObjectGroup group, uint AttachmentPt, bool silent) |
152 | { | 236 | { |
237 | ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); | ||
238 | |||
239 | if (sp == null) | ||
240 | { | ||
241 | m_log.ErrorFormat( | ||
242 | "[ATTACHMENTS MODULE]: Could not find presence for client {0} {1}", remoteClient.Name, remoteClient.AgentId); | ||
243 | return false; | ||
244 | } | ||
245 | |||
246 | return AttachObject(sp, group, AttachmentPt, silent); | ||
247 | } | ||
248 | |||
249 | private bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent) | ||
250 | { | ||
251 | // m_log.DebugFormat( | ||
252 | // "[ATTACHMENTS MODULE]: Attaching object {0} {1} to {2} point {3} from ground (silent = {4})", | ||
253 | // group.Name, group.LocalId, sp.Name, AttachmentPt, silent); | ||
254 | |||
255 | if (sp.GetAttachments(attachmentPt).Contains(group)) | ||
256 | { | ||
257 | // m_log.WarnFormat( | ||
258 | // "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since it's already attached", | ||
259 | // group.Name, group.LocalId, sp.Name, AttachmentPt); | ||
260 | |||
261 | return false; | ||
262 | } | ||
263 | |||
153 | Vector3 attachPos = group.AbsolutePosition; | 264 | Vector3 attachPos = group.AbsolutePosition; |
154 | 265 | ||
155 | // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should | 266 | // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should |
156 | // be removed when that functionality is implemented in opensim | 267 | // be removed when that functionality is implemented in opensim |
157 | AttachmentPt &= 0x7f; | 268 | attachmentPt &= 0x7f; |
158 | 269 | ||
159 | // If the attachment point isn't the same as the one previously used | 270 | // If the attachment point isn't the same as the one previously used |
160 | // set it's offset position = 0 so that it appears on the attachment point | 271 | // set it's offset position = 0 so that it appears on the attachment point |
161 | // and not in a weird location somewhere unknown. | 272 | // and not in a weird location somewhere unknown. |
162 | if (AttachmentPt != 0 && AttachmentPt != (uint)group.GetAttachmentPoint()) | 273 | if (attachmentPt != 0 && attachmentPt != group.AttachmentPoint) |
163 | { | 274 | { |
164 | attachPos = Vector3.Zero; | 275 | attachPos = Vector3.Zero; |
165 | } | 276 | } |
166 | 277 | ||
167 | // AttachmentPt 0 means the client chose to 'wear' the attachment. | 278 | // AttachmentPt 0 means the client chose to 'wear' the attachment. |
168 | if (AttachmentPt == 0) | 279 | if (attachmentPt == 0) |
169 | { | 280 | { |
170 | // Check object for stored attachment point | 281 | // Check object for stored attachment point |
171 | AttachmentPt = (uint)group.GetAttachmentPoint(); | 282 | attachmentPt = group.AttachmentPoint; |
172 | } | 283 | } |
173 | 284 | ||
174 | // if we still didn't find a suitable attachment point....... | 285 | // if we still didn't find a suitable attachment point....... |
175 | if (AttachmentPt == 0) | 286 | if (attachmentPt == 0) |
176 | { | 287 | { |
177 | // Stick it on left hand with Zero Offset from the attachment point. | 288 | // Stick it on left hand with Zero Offset from the attachment point. |
178 | AttachmentPt = (uint)AttachmentPoint.LeftHand; | 289 | attachmentPt = (uint)AttachmentPoint.LeftHand; |
179 | attachPos = Vector3.Zero; | 290 | attachPos = Vector3.Zero; |
180 | } | 291 | } |
181 | 292 | ||
182 | group.SetAttachmentPoint((byte)AttachmentPt); | 293 | group.AttachmentPoint = attachmentPt; |
183 | group.AbsolutePosition = attachPos; | 294 | group.AbsolutePosition = attachPos; |
184 | 295 | ||
185 | // Remove any previous attachments | 296 | // Remove any previous attachments |
186 | ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); | ||
187 | UUID itemID = UUID.Zero; | 297 | UUID itemID = UUID.Zero; |
188 | if (sp != null) | ||
189 | { | ||
190 | foreach (SceneObjectGroup grp in sp.Attachments) | ||
191 | { | ||
192 | if (grp.GetAttachmentPoint() == (byte)AttachmentPt) | ||
193 | { | ||
194 | itemID = grp.GetFromItemID(); | ||
195 | break; | ||
196 | } | ||
197 | } | ||
198 | if (itemID != UUID.Zero) | ||
199 | DetachSingleAttachmentToInv(itemID, remoteClient); | ||
200 | } | ||
201 | 298 | ||
202 | if (group.GetFromItemID() == UUID.Zero) | 299 | List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt); |
203 | { | 300 | |
204 | m_scene.attachObjectAssetStore(remoteClient, group, remoteClient.AgentId, out itemID); | 301 | // At the moment we can only deal with a single attachment |
205 | } | 302 | // We also don't want to do any of the inventory operations for an NPC. |
206 | else | 303 | if (sp.PresenceType != PresenceType.Npc) |
207 | { | 304 | { |
305 | if (attachments.Count != 0) | ||
306 | itemID = attachments[0].GetFromItemID(); | ||
307 | |||
308 | if (itemID != UUID.Zero) | ||
309 | DetachSingleAttachmentToInv(itemID, sp); | ||
310 | |||
208 | itemID = group.GetFromItemID(); | 311 | itemID = group.GetFromItemID(); |
312 | if (itemID == UUID.Zero) | ||
313 | itemID = AddSceneObjectAsAttachment(sp.ControllingClient, group).ID; | ||
314 | |||
315 | ShowAttachInUserInventory(sp, attachmentPt, itemID, group); | ||
209 | } | 316 | } |
210 | 317 | ||
211 | ShowAttachInUserInventory(remoteClient, AttachmentPt, itemID, group); | 318 | AttachToAgent(sp, group, attachmentPt, attachPos, silent); |
212 | |||
213 | AttachToAgent(sp, group, AttachmentPt, attachPos, silent); | ||
214 | 319 | ||
215 | return true; | 320 | return true; |
216 | } | 321 | } |
@@ -226,12 +331,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
226 | } | 331 | } |
227 | } | 332 | } |
228 | 333 | ||
229 | public UUID RezSingleAttachmentFromInventory(IClientAPI remoteClient, UUID itemID, uint AttachmentPt) | 334 | public ISceneEntity RezSingleAttachmentFromInventory( |
335 | IClientAPI remoteClient, UUID itemID, uint AttachmentPt) | ||
230 | { | 336 | { |
231 | return RezSingleAttachmentFromInventory(remoteClient, itemID, AttachmentPt, true); | 337 | return RezSingleAttachmentFromInventory(remoteClient, itemID, AttachmentPt, true); |
232 | } | 338 | } |
233 | 339 | ||
234 | public UUID RezSingleAttachmentFromInventory( | 340 | public ISceneEntity RezSingleAttachmentFromInventory( |
235 | IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus) | 341 | IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus) |
236 | { | 342 | { |
237 | return RezSingleAttachmentFromInventory(remoteClient, itemID, AttachmentPt, true, null); | 343 | return RezSingleAttachmentFromInventory(remoteClient, itemID, AttachmentPt, true, null); |
@@ -239,7 +345,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
239 | 345 | ||
240 | public UUID RezSingleAttachmentFromInventory( | 346 | public UUID RezSingleAttachmentFromInventory( |
241 | IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus, XmlDocument doc) | 347 | IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus, XmlDocument doc) |
348 | ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); | ||
349 | |||
242 | { | 350 | { |
351 | if (sp == null) { m_log.ErrorFormat( "[ATTACHMENTS MODULE]: Could not find presence for client {0} {1} in RezSingleAttachmentFromInventory()", remoteClient.Name, remoteClient.AgentId); return null; } | ||
243 | // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should | 352 | // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should |
244 | // be removed when that functionality is implemented in opensim | 353 | // be removed when that functionality is implemented in opensim |
245 | AttachmentPt &= 0x7f; | 354 | AttachmentPt &= 0x7f; |
@@ -249,15 +358,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
249 | if (updateInventoryStatus) | 358 | if (updateInventoryStatus) |
250 | { | 359 | { |
251 | if (att == null) | 360 | if (att == null) |
252 | ShowDetachInUserInventory(itemID, remoteClient); | 361 | DetachSingleAttachmentToInv(itemID, sp.ControllingClient); |
253 | else | 362 | else |
254 | ShowAttachInUserInventory(att, remoteClient, itemID, AttachmentPt); | 363 | ShowAttachInUserInventory(att, sp, itemID, AttachmentPt); |
255 | } | 364 | } |
256 | 365 | ||
257 | if (null == att) | 366 | return att; |
258 | return UUID.Zero; | ||
259 | else | ||
260 | return att.UUID; | ||
261 | } | 367 | } |
262 | 368 | ||
263 | protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal( | 369 | protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal( |
@@ -266,12 +372,19 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
266 | IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); | 372 | IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); |
267 | if (invAccess != null) | 373 | if (invAccess != null) |
268 | { | 374 | { |
269 | SceneObjectGroup objatt = invAccess.RezObject(remoteClient, | 375 | SceneObjectGroup objatt; |
270 | itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, | 376 | |
271 | false, false, remoteClient.AgentId, true); | 377 | if (itemID != UUID.Zero) |
378 | objatt = invAccess.RezObject(sp.ControllingClient, | ||
379 | itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, | ||
380 | false, false, sp.UUID, true); | ||
381 | else | ||
382 | objatt = invAccess.RezObject(sp.ControllingClient, | ||
383 | null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, | ||
384 | false, false, sp.UUID, true); | ||
272 | 385 | ||
273 | // m_log.DebugFormat( | 386 | // m_log.DebugFormat( |
274 | // "[ATTACHMENTS MODULE]: Retrieved single object {0} for attachment to {1} on point {2}", | 387 | // "[ATTACHMENTS MODULE]: Retrieved single object {0} for attachment to {1} on point {2}", |
275 | // objatt.Name, remoteClient.Name, AttachmentPt); | 388 | // objatt.Name, remoteClient.Name, AttachmentPt); |
276 | 389 | ||
277 | if (objatt != null) | 390 | if (objatt != null) |
@@ -281,17 +394,22 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
281 | // since scripts aren't running yet. So, clear it here. | 394 | // since scripts aren't running yet. So, clear it here. |
282 | objatt.HasGroupChanged = false; | 395 | objatt.HasGroupChanged = false; |
283 | bool tainted = false; | 396 | bool tainted = false; |
284 | if (AttachmentPt != 0 && AttachmentPt != objatt.GetAttachmentPoint()) | 397 | if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint) |
285 | tainted = true; | 398 | tainted = true; |
286 | 399 | ||
287 | // This will throw if the attachment fails | 400 | // This will throw if the attachment fails |
288 | try | 401 | try |
289 | { | 402 | { |
290 | AttachObject(remoteClient, objatt, AttachmentPt, false); | 403 | AttachObject(sp, objatt, attachmentPt, false); |
291 | } | 404 | } |
292 | catch | 405 | catch (Exception e) |
293 | { | 406 | { |
407 | m_log.ErrorFormat( | ||
408 | "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}", | ||
409 | objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace); | ||
410 | |||
294 | // Make sure the object doesn't stick around and bail | 411 | // Make sure the object doesn't stick around and bail |
412 | sp.RemoveAttachment(objatt); | ||
295 | m_scene.DeleteSceneObject(objatt, false); | 413 | m_scene.DeleteSceneObject(objatt, false); |
296 | return null; | 414 | return null; |
297 | } | 415 | } |
@@ -311,13 +429,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
311 | objatt.ResumeScripts(); | 429 | objatt.ResumeScripts(); |
312 | 430 | ||
313 | // Do this last so that event listeners have access to all the effects of the attachment | 431 | // Do this last so that event listeners have access to all the effects of the attachment |
314 | //m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, remoteClient.AgentId); | 432 | m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, sp.UUID); |
315 | } | 433 | } |
316 | else | 434 | else |
317 | { | 435 | { |
318 | m_log.WarnFormat( | 436 | m_log.WarnFormat( |
319 | "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}", | 437 | "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}", |
320 | itemID, remoteClient.Name, AttachmentPt); | 438 | itemID, sp.Name, attachmentPt); |
321 | } | 439 | } |
322 | 440 | ||
323 | return objatt; | 441 | return objatt; |
@@ -330,31 +448,30 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
330 | /// Update the user inventory to the attachment of an item | 448 | /// Update the user inventory to the attachment of an item |
331 | /// </summary> | 449 | /// </summary> |
332 | /// <param name="att"></param> | 450 | /// <param name="att"></param> |
333 | /// <param name="remoteClient"></param> | 451 | /// <param name="sp"></param> |
334 | /// <param name="itemID"></param> | 452 | /// <param name="itemID"></param> |
335 | /// <param name="AttachmentPt"></param> | 453 | /// <param name="attachmentPoint"></param> |
336 | /// <returns></returns> | 454 | /// <returns></returns> |
337 | protected UUID ShowAttachInUserInventory( | 455 | private UUID ShowAttachInUserInventory( |
338 | SceneObjectGroup att, IClientAPI remoteClient, UUID itemID, uint AttachmentPt) | 456 | SceneObjectGroup att, IScenePresence sp, UUID itemID, uint attachmentPoint) |
339 | { | 457 | { |
340 | // m_log.DebugFormat( | 458 | // m_log.DebugFormat( |
341 | // "[ATTACHMENTS MODULE]: Updating inventory of {0} to show attachment of {1} (item ID {2})", | 459 | // "[ATTACHMENTS MODULE]: Updating inventory of {0} to show attachment of {1} {2} (item ID {3}) at {4}", |
342 | // remoteClient.Name, att.Name, itemID); | 460 | // sp.Name, att.Name, att.LocalId, itemID, AttachmentPt); |
343 | 461 | ||
344 | if (!att.IsDeleted) | 462 | if (!att.IsDeleted) |
345 | AttachmentPt = att.RootPart.AttachmentPoint; | 463 | attachmentPoint = att.AttachmentPoint; |
346 | 464 | ||
347 | ScenePresence presence; | 465 | ScenePresence presence; |
348 | if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence)) | 466 | if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence)) |
349 | { | 467 | { |
350 | InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); | 468 | InventoryItemBase item = new InventoryItemBase(itemID, sp.UUID); |
351 | if (m_scene.InventoryService != null) | 469 | if (m_scene.InventoryService != null) |
352 | item = m_scene.InventoryService.GetItem(item); | 470 | item = m_scene.InventoryService.GetItem(item); |
353 | 471 | ||
354 | bool changed = presence.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID); | 472 | bool changed = sp.Appearance.SetAttachment((int)attachmentPoint, itemID, item.AssetID); |
355 | if (changed && m_scene.AvatarFactory != null) | 473 | if (changed && m_scene.AvatarFactory != null) |
356 | m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId); | 474 | m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); |
357 | } | ||
358 | 475 | ||
359 | return att.UUID; | 476 | return att.UUID; |
360 | } | 477 | } |
@@ -362,12 +479,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
362 | /// <summary> | 479 | /// <summary> |
363 | /// Update the user inventory to reflect an attachment | 480 | /// Update the user inventory to reflect an attachment |
364 | /// </summary> | 481 | /// </summary> |
365 | /// <param name="remoteClient"></param> | 482 | /// <param name="sp"></param> |
366 | /// <param name="AttachmentPt"></param> | 483 | /// <param name="AttachmentPt"></param> |
367 | /// <param name="itemID"></param> | 484 | /// <param name="itemID"></param> |
368 | /// <param name="att"></param> | 485 | /// <param name="att"></param> |
369 | protected void ShowAttachInUserInventory( | 486 | private void ShowAttachInUserInventory( |
370 | IClientAPI remoteClient, uint AttachmentPt, UUID itemID, SceneObjectGroup att) | 487 | IScenePresence sp, uint AttachmentPt, UUID itemID, SceneObjectGroup att) |
371 | { | 488 | { |
372 | // m_log.DebugFormat( | 489 | // m_log.DebugFormat( |
373 | // "[USER INVENTORY]: Updating attachment {0} for {1} at {2} using item ID {3}", | 490 | // "[USER INVENTORY]: Updating attachment {0} for {1} at {2} using item ID {3}", |
@@ -390,23 +507,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
390 | m_log.Error("[ATTACHMENTS MODULE]: Unable to save attachment for a prim without the rootpart!"); | 507 | m_log.Error("[ATTACHMENTS MODULE]: Unable to save attachment for a prim without the rootpart!"); |
391 | return; | 508 | return; |
392 | } | 509 | } |
510 | InventoryItemBase item = new InventoryItemBase(itemID, sp.UUID); | ||
393 | 511 | ||
394 | ScenePresence presence; | 512 | |
395 | if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence)) | 513 | |
396 | { | 514 | |
397 | // XXYY!! | 515 | |
398 | InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); | 516 | |
399 | if (item == null) | 517 | item = m_scene.InventoryService.GetItem(item); |
400 | m_log.Error("[ATTACHMENT]: item == null"); | 518 | bool changed = sp.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID); |
401 | if (m_scene == null) | 519 | if (changed && m_scene.AvatarFactory != null) |
402 | m_log.Error("[ATTACHMENT]: m_scene == null"); | 520 | m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); |
403 | if (m_scene.InventoryService == null) | ||
404 | m_log.Error("[ATTACHMENT]: m_scene.InventoryService == null"); | ||
405 | item = m_scene.InventoryService.GetItem(item); | ||
406 | bool changed = presence.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID); | ||
407 | if (changed && m_scene.AvatarFactory != null) | ||
408 | m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId); | ||
409 | } | ||
410 | } | 521 | } |
411 | 522 | ||
412 | public void DetachObject(uint objectLocalID, IClientAPI remoteClient) | 523 | public void DetachObject(uint objectLocalID, IClientAPI remoteClient) |
@@ -414,12 +525,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
414 | SceneObjectGroup group = m_scene.GetGroupByPrim(objectLocalID); | 525 | SceneObjectGroup group = m_scene.GetGroupByPrim(objectLocalID); |
415 | if (group != null) | 526 | if (group != null) |
416 | { | 527 | { |
417 | //group.DetachToGround(); | 528 | DetachSingleAttachmentToInv(group.GetFromItemID(), remoteClient); |
418 | ShowDetachInUserInventory(group.GetFromItemID(), remoteClient); | ||
419 | } | 529 | } |
420 | } | 530 | } |
421 | 531 | ||
422 | public void ShowDetachInUserInventory(UUID itemID, IClientAPI remoteClient) | 532 | public void DetachSingleAttachmentToInv(UUID itemID, IClientAPI remoteClient) |
423 | { | 533 | { |
424 | ScenePresence presence; | 534 | ScenePresence presence; |
425 | if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence)) | 535 | if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence)) |
@@ -430,34 +540,44 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
430 | bool changed = presence.Appearance.DetachAttachment(itemID); | 540 | bool changed = presence.Appearance.DetachAttachment(itemID); |
431 | if (changed && m_scene.AvatarFactory != null) | 541 | if (changed && m_scene.AvatarFactory != null) |
432 | m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId); | 542 | m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId); |
433 | } | ||
434 | 543 | ||
435 | DetachSingleAttachmentToInv(itemID, remoteClient); | 544 | DetachSingleAttachmentToInv(itemID, presence); |
545 | } | ||
436 | } | 546 | } |
437 | 547 | ||
438 | public void DetachSingleAttachmentToGround(UUID itemID, IClientAPI remoteClient) | 548 | public void DetachSingleAttachmentToGround(uint soLocalId, IClientAPI remoteClient) |
439 | { | 549 | { |
440 | SceneObjectPart part = m_scene.GetSceneObjectPart(itemID); | 550 | // m_log.DebugFormat( |
441 | if (part == null || part.ParentGroup == null) | 551 | // "[ATTACHMENTS MODULE]: DetachSingleAttachmentToGround() for {0}, object {1}", |
552 | // remoteClient.Name, sceneObjectID); | ||
553 | |||
554 | SceneObjectGroup so = m_scene.GetGroupByPrim(soLocalId); | ||
555 | |||
556 | if (so == null) | ||
442 | return; | 557 | return; |
443 | 558 | ||
444 | if (part.ParentGroup.RootPart.AttachedAvatar != remoteClient.AgentId) | 559 | if (so.AttachedAvatar != remoteClient.AgentId) |
445 | return; | 560 | return; |
446 | 561 | ||
447 | UUID inventoryID = part.ParentGroup.GetFromItemID(); | 562 | UUID inventoryID = so.GetFromItemID(); |
563 | |||
564 | // m_log.DebugFormat( | ||
565 | // "[ATTACHMENTS MODULE]: In DetachSingleAttachmentToGround(), object is {0} {1}, associated item is {2}", | ||
566 | // so.Name, so.LocalId, inventoryID); | ||
448 | 567 | ||
449 | ScenePresence presence; | 568 | ScenePresence presence; |
450 | if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence)) | 569 | if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence)) |
451 | { | 570 | { |
452 | if (!m_scene.Permissions.CanRezObject( | 571 | if (!m_scene.Permissions.CanRezObject( |
453 | part.ParentGroup.PrimCount, remoteClient.AgentId, presence.AbsolutePosition)) | 572 | so.PrimCount, remoteClient.AgentId, presence.AbsolutePosition)) |
454 | return; | 573 | return; |
455 | 574 | ||
456 | bool changed = presence.Appearance.DetachAttachment(itemID); | 575 | bool changed = presence.Appearance.DetachAttachment(inventoryID); |
457 | if (changed && m_scene.AvatarFactory != null) | 576 | if (changed && m_scene.AvatarFactory != null) |
458 | m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId); | 577 | m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId); |
459 | 578 | ||
460 | part.ParentGroup.DetachToGround(); | 579 | presence.RemoveAttachment(so); |
580 | DetachSceneObjectToGround(so, presence); | ||
461 | 581 | ||
462 | List<UUID> uuids = new List<UUID>(); | 582 | List<UUID> uuids = new List<UUID>(); |
463 | uuids.Add(inventoryID); | 583 | uuids.Add(inventoryID); |
@@ -465,12 +585,39 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
465 | remoteClient.SendRemoveInventoryItem(inventoryID); | 585 | remoteClient.SendRemoveInventoryItem(inventoryID); |
466 | } | 586 | } |
467 | 587 | ||
468 | m_scene.EventManager.TriggerOnAttach(part.ParentGroup.LocalId, itemID, UUID.Zero); | 588 | m_scene.EventManager.TriggerOnAttach(so.LocalId, so.UUID, UUID.Zero); |
589 | } | ||
590 | |||
591 | /// <summary> | ||
592 | /// Detach the given scene object to the ground. | ||
593 | /// </summary> | ||
594 | /// <remarks> | ||
595 | /// The caller has to take care of all the other work in updating avatar appearance, inventory, etc. | ||
596 | /// </remarks> | ||
597 | /// <param name="so">The scene object to detach.</param> | ||
598 | /// <param name="sp">The scene presence from which the scene object is being detached.</param> | ||
599 | private void DetachSceneObjectToGround(SceneObjectGroup so, ScenePresence sp) | ||
600 | { | ||
601 | SceneObjectPart rootPart = so.RootPart; | ||
602 | |||
603 | rootPart.FromItemID = UUID.Zero; | ||
604 | so.AbsolutePosition = sp.AbsolutePosition; | ||
605 | so.AttachedAvatar = UUID.Zero; | ||
606 | rootPart.SetParentLocalId(0); | ||
607 | so.ClearPartAttachmentData(); | ||
608 | rootPart.ApplyPhysics(rootPart.GetEffectiveObjectFlags(), rootPart.VolumeDetectActive, m_scene.m_physicalPrim); | ||
609 | so.HasGroupChanged = true; | ||
610 | rootPart.Rezzed = DateTime.Now; | ||
611 | rootPart.RemFlag(PrimFlags.TemporaryOnRez); | ||
612 | so.AttachToBackup(); | ||
613 | m_scene.EventManager.TriggerParcelPrimCountTainted(); | ||
614 | rootPart.ScheduleFullUpdate(); | ||
615 | rootPart.ClearUndoState(); | ||
469 | } | 616 | } |
470 | 617 | ||
471 | // What makes this method odd and unique is it tries to detach using an UUID.... Yay for standards. | 618 | // What makes this method odd and unique is it tries to detach using an UUID.... Yay for standards. |
472 | // To LocalId or UUID, *THAT* is the question. How now Brown UUID?? | 619 | // To LocalId or UUID, *THAT* is the question. How now Brown UUID?? |
473 | protected void DetachSingleAttachmentToInv(UUID itemID, IClientAPI remoteClient) | 620 | private void DetachSingleAttachmentToInv(UUID itemID, IScenePresence sp) |
474 | { | 621 | { |
475 | if (itemID == UUID.Zero) // If this happened, someone made a mistake.... | 622 | if (itemID == UUID.Zero) // If this happened, someone made a mistake.... |
476 | return; | 623 | return; |
@@ -493,27 +640,55 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
493 | group.DetachToInventoryPrep(); | 640 | group.DetachToInventoryPrep(); |
494 | m_log.Debug("[ATTACHMENTS MODULE]: Saving attachpoint: " + ((uint)group.GetAttachmentPoint()).ToString()); | 641 | m_log.Debug("[ATTACHMENTS MODULE]: Saving attachpoint: " + ((uint)group.GetAttachmentPoint()).ToString()); |
495 | 642 | ||
496 | // If an item contains scripts, it's always changed. | 643 | // Prepare sog for storage |
497 | // This ensures script state is saved on detach | 644 | group.AttachedAvatar = UUID.Zero; |
498 | foreach (SceneObjectPart p in group.Parts) | 645 | |
499 | if (p.Inventory.ContainsScripts()) | 646 | group.ForEachPart( |
500 | group.HasGroupChanged = true; | 647 | delegate(SceneObjectPart part) |
648 | { | ||
649 | // If there are any scripts, | ||
650 | // then always trigger a new object and state persistence in UpdateKnownItem() | ||
651 | if (part.Inventory.ContainsScripts()) | ||
652 | group.HasGroupChanged = true; | ||
653 | } | ||
654 | ); | ||
501 | 655 | ||
502 | UpdateKnownItem(remoteClient, group, group.GetFromItemID(), group.OwnerID); | 656 | group.RootPart.SetParentLocalId(0); |
657 | group.IsAttachment = false; | ||
658 | group.AbsolutePosition = group.RootPart.AttachedPos; | ||
659 | |||
660 | UpdateKnownItem(sp.ControllingClient, group, group.GetFromItemID(), group.OwnerID); | ||
503 | m_scene.DeleteSceneObject(group, false); | 661 | m_scene.DeleteSceneObject(group, false); |
662 | |||
504 | return; | 663 | return; |
505 | } | 664 | } |
506 | } | 665 | } |
507 | } | 666 | } |
508 | } | 667 | } |
509 | 668 | ||
669 | public void UpdateAttachmentPosition(SceneObjectGroup sog, Vector3 pos) | ||
670 | { | ||
671 | // First we save the | ||
672 | // attachment point information, then we update the relative | ||
673 | // positioning. Then we have to mark the object as NOT an | ||
674 | // attachment. This is necessary in order to correctly save | ||
675 | // and retrieve GroupPosition information for the attachment. | ||
676 | // Finally, we restore the object's attachment status. | ||
677 | uint attachmentPoint = sog.AttachmentPoint; | ||
678 | sog.UpdateGroupPosition(pos); | ||
679 | sog.IsAttachment = false; | ||
680 | sog.AbsolutePosition = sog.RootPart.AttachedPos; | ||
681 | sog.AttachmentPoint = attachmentPoint; | ||
682 | sog.HasGroupChanged = true; | ||
683 | } | ||
684 | |||
510 | /// <summary> | 685 | /// <summary> |
511 | /// Update the attachment asset for the new sog details if they have changed. | 686 | /// Update the attachment asset for the new sog details if they have changed. |
512 | /// </summary> | 687 | /// </summary> |
513 | /// | 688 | /// <remarks> |
514 | /// This is essential for preserving attachment attributes such as permission. Unlike normal scene objects, | 689 | /// This is essential for preserving attachment attributes such as permission. Unlike normal scene objects, |
515 | /// these details are not stored on the region. | 690 | /// these details are not stored on the region. |
516 | /// | 691 | /// </remarks> |
517 | /// <param name="remoteClient"></param> | 692 | /// <param name="remoteClient"></param> |
518 | /// <param name="grp"></param> | 693 | /// <param name="grp"></param> |
519 | /// <param name="itemID"></param> | 694 | /// <param name="itemID"></param> |
@@ -524,15 +699,19 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
524 | { | 699 | { |
525 | if (!grp.HasGroupChanged) | 700 | if (!grp.HasGroupChanged) |
526 | { | 701 | { |
527 | m_log.WarnFormat("[ATTACHMENTS MODULE]: Save request for {0} which is unchanged", grp.UUID); | 702 | m_log.DebugFormat( |
703 | "[ATTACHMENTS MODULE]: Don't need to update asset for unchanged attachment {0}, attachpoint {1}", | ||
704 | grp.UUID, grp.AttachmentPoint); | ||
705 | |||
528 | return; | 706 | return; |
529 | } | 707 | } |
530 | 708 | ||
531 | m_log.DebugFormat( | 709 | m_log.DebugFormat( |
532 | "[ATTACHMENTS MODULE]: Updating asset for attachment {0}, attachpoint {1}", | 710 | "[ATTACHMENTS MODULE]: Updating asset for attachment {0}, attachpoint {1}", |
533 | grp.UUID, grp.GetAttachmentPoint()); | 711 | grp.UUID, grp.AttachmentPoint); |
534 | 712 | ||
535 | string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp); | 713 | string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp); |
714 | |||
536 | InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); | 715 | InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); |
537 | item = m_scene.InventoryService.GetItem(item); | 716 | item = m_scene.InventoryService.GetItem(item); |
538 | 717 | ||
@@ -564,20 +743,20 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
564 | /// <summary> | 743 | /// <summary> |
565 | /// Attach this scene object to the given avatar. | 744 | /// Attach this scene object to the given avatar. |
566 | /// </summary> | 745 | /// </summary> |
567 | /// | 746 | /// <remarks> |
568 | /// This isn't publicly available since attachments should always perform the corresponding inventory | 747 | /// This isn't publicly available since attachments should always perform the corresponding inventory |
569 | /// operation (to show the attach in user inventory and update the asset with positional information). | 748 | /// operation (to show the attach in user inventory and update the asset with positional information). |
570 | /// | 749 | /// </remarks> |
571 | /// <param name="sp"></param> | 750 | /// <param name="sp"></param> |
572 | /// <param name="so"></param> | 751 | /// <param name="so"></param> |
573 | /// <param name="attachmentpoint"></param> | 752 | /// <param name="attachmentpoint"></param> |
574 | /// <param name="attachOffset"></param> | 753 | /// <param name="attachOffset"></param> |
575 | /// <param name="silent"></param> | 754 | /// <param name="silent"></param> |
576 | protected void AttachToAgent(ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent) | 755 | private void AttachToAgent( |
756 | IScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent) | ||
577 | { | 757 | { |
578 | 758 | // m_log.DebugFormat("[ATTACHMENTS MODULE]: Adding attachment {0} to avatar {1} in pt {2} pos {3} {4}", | |
579 | m_log.DebugFormat("[ATTACHMENTS MODULE]: Adding attachment {0} to avatar {1} in pt {2} pos {3} {4}", Name, avatar.Name, | 759 | // so.Name, avatar.Name, attachmentpoint, attachOffset, so.RootPart.AttachedPos); |
580 | attachmentpoint, attachOffset, so.RootPart.AttachedPos); | ||
581 | 760 | ||
582 | so.DetachFromBackup(); | 761 | so.DetachFromBackup(); |
583 | 762 | ||
@@ -585,12 +764,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
585 | m_scene.DeleteFromStorage(so.UUID); | 764 | m_scene.DeleteFromStorage(so.UUID); |
586 | m_scene.EventManager.TriggerParcelPrimCountTainted(); | 765 | m_scene.EventManager.TriggerParcelPrimCountTainted(); |
587 | 766 | ||
588 | so.RootPart.AttachedAvatar = avatar.UUID; | 767 | so.AttachedAvatar = avatar.UUID; |
589 | |||
590 | //Anakin Lohner bug #3839 | ||
591 | SceneObjectPart[] parts = so.Parts; | ||
592 | for (int i = 0; i < parts.Length; i++) | ||
593 | parts[i].AttachedAvatar = avatar.UUID; | ||
594 | 768 | ||
595 | if (so.RootPart.PhysActor != null) | 769 | if (so.RootPart.PhysActor != null) |
596 | { | 770 | { |
@@ -600,10 +774,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
600 | 774 | ||
601 | so.AbsolutePosition = attachOffset; | 775 | so.AbsolutePosition = attachOffset; |
602 | so.RootPart.AttachedPos = attachOffset; | 776 | so.RootPart.AttachedPos = attachOffset; |
603 | so.RootPart.IsAttachment = true; | 777 | so.IsAttachment = true; |
604 | |||
605 | so.RootPart.SetParentLocalId(avatar.LocalId); | 778 | so.RootPart.SetParentLocalId(avatar.LocalId); |
606 | so.SetAttachmentPoint(Convert.ToByte(attachmentpoint)); | 779 | so.AttachmentPoint = attachmentpoint; |
607 | 780 | ||
608 | avatar.AddAttachment(so); | 781 | avatar.AddAttachment(so); |
609 | 782 | ||
@@ -617,5 +790,97 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
617 | // it get cleaned up | 790 | // it get cleaned up |
618 | so.RootPart.RemFlag(PrimFlags.TemporaryOnRez); | 791 | so.RootPart.RemFlag(PrimFlags.TemporaryOnRez); |
619 | } | 792 | } |
793 | |||
794 | /// <summary> | ||
795 | /// Add a scene object that was previously free in the scene as an attachment to an avatar. | ||
796 | /// </summary> | ||
797 | /// <param name="remoteClient"></param> | ||
798 | /// <param name="grp"></param> | ||
799 | /// <returns>The user inventory item created that holds the attachment.</returns> | ||
800 | private InventoryItemBase AddSceneObjectAsAttachment(IClientAPI remoteClient, SceneObjectGroup grp) | ||
801 | { | ||
802 | // m_log.DebugFormat("[SCENE]: Called AddSceneObjectAsAttachment for object {0} {1} for {2} {3} {4}", grp.Name, grp.LocalId, remoteClient.Name, remoteClient.AgentId, AgentId); | ||
803 | |||
804 | Vector3 inventoryStoredPosition = new Vector3 | ||
805 | (((grp.AbsolutePosition.X > (int)Constants.RegionSize) | ||
806 | ? Constants.RegionSize - 6 | ||
807 | : grp.AbsolutePosition.X) | ||
808 | , | ||
809 | (grp.AbsolutePosition.Y > (int)Constants.RegionSize) | ||
810 | ? Constants.RegionSize - 6 | ||
811 | : grp.AbsolutePosition.Y, | ||
812 | grp.AbsolutePosition.Z); | ||
813 | |||
814 | Vector3 originalPosition = grp.AbsolutePosition; | ||
815 | |||
816 | grp.AbsolutePosition = inventoryStoredPosition; | ||
817 | |||
818 | // If we're being called from a script, then trying to serialize that same script's state will not complete | ||
819 | // in any reasonable time period. Therefore, we'll avoid it. The worst that can happen is that if | ||
820 | // the client/server crashes rather than logging out normally, the attachment's scripts will resume | ||
821 | // without state on relog. Arguably, this is what we want anyway. | ||
822 | string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp, false); | ||
823 | |||
824 | grp.AbsolutePosition = originalPosition; | ||
825 | |||
826 | AssetBase asset = m_scene.CreateAsset( | ||
827 | grp.GetPartName(grp.LocalId), | ||
828 | grp.GetPartDescription(grp.LocalId), | ||
829 | (sbyte)AssetType.Object, | ||
830 | Utils.StringToBytes(sceneObjectXml), | ||
831 | remoteClient.AgentId); | ||
832 | |||
833 | m_scene.AssetService.Store(asset); | ||
834 | |||
835 | InventoryItemBase item = new InventoryItemBase(); | ||
836 | item.CreatorId = grp.RootPart.CreatorID.ToString(); | ||
837 | item.CreatorData = grp.RootPart.CreatorData; | ||
838 | item.Owner = remoteClient.AgentId; | ||
839 | item.ID = UUID.Random(); | ||
840 | item.AssetID = asset.FullID; | ||
841 | item.Description = asset.Description; | ||
842 | item.Name = asset.Name; | ||
843 | item.AssetType = asset.Type; | ||
844 | item.InvType = (int)InventoryType.Object; | ||
845 | |||
846 | InventoryFolderBase folder = m_scene.InventoryService.GetFolderForType(remoteClient.AgentId, AssetType.Object); | ||
847 | if (folder != null) | ||
848 | item.Folder = folder.ID; | ||
849 | else // oopsies | ||
850 | item.Folder = UUID.Zero; | ||
851 | |||
852 | if ((remoteClient.AgentId != grp.RootPart.OwnerID) && m_scene.Permissions.PropagatePermissions()) | ||
853 | { | ||
854 | item.BasePermissions = grp.RootPart.NextOwnerMask; | ||
855 | item.CurrentPermissions = grp.RootPart.NextOwnerMask; | ||
856 | item.NextPermissions = grp.RootPart.NextOwnerMask; | ||
857 | item.EveryOnePermissions = grp.RootPart.EveryoneMask & grp.RootPart.NextOwnerMask; | ||
858 | item.GroupPermissions = grp.RootPart.GroupMask & grp.RootPart.NextOwnerMask; | ||
859 | } | ||
860 | else | ||
861 | { | ||
862 | item.BasePermissions = grp.RootPart.BaseMask; | ||
863 | item.CurrentPermissions = grp.RootPart.OwnerMask; | ||
864 | item.NextPermissions = grp.RootPart.NextOwnerMask; | ||
865 | item.EveryOnePermissions = grp.RootPart.EveryoneMask; | ||
866 | item.GroupPermissions = grp.RootPart.GroupMask; | ||
867 | } | ||
868 | item.CreationDate = Util.UnixTimeSinceEpoch(); | ||
869 | |||
870 | // sets itemID so client can show item as 'attached' in inventory | ||
871 | grp.SetFromItemID(item.ID); | ||
872 | |||
873 | if (m_scene.AddInventoryItem(item)) | ||
874 | { | ||
875 | remoteClient.SendInventoryItemCreateUpdate(item, 0); | ||
876 | } | ||
877 | else | ||
878 | { | ||
879 | if (m_dialogModule != null) | ||
880 | m_dialogModule.SendAlertToUser(remoteClient, "Operation failed"); | ||
881 | } | ||
882 | |||
883 | return item; | ||
884 | } | ||
620 | } | 885 | } |
621 | } | 886 | } |
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs new file mode 100644 index 0000000..363e258 --- /dev/null +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs | |||
@@ -0,0 +1,274 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using System.Text; | ||
32 | using System.Threading; | ||
33 | using System.Timers; | ||
34 | using Timer=System.Timers.Timer; | ||
35 | using Nini.Config; | ||
36 | using NUnit.Framework; | ||
37 | using OpenMetaverse; | ||
38 | using OpenSim.Framework; | ||
39 | using OpenSim.Framework.Communications; | ||
40 | using OpenSim.Region.CoreModules.Avatar.Attachments; | ||
41 | using OpenSim.Region.CoreModules.Framework.InventoryAccess; | ||
42 | using OpenSim.Region.CoreModules.World.Serialiser; | ||
43 | using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; | ||
44 | using OpenSim.Region.Framework.Scenes; | ||
45 | using OpenSim.Region.Framework.Interfaces; | ||
46 | using OpenSim.Tests.Common; | ||
47 | using OpenSim.Tests.Common.Mock; | ||
48 | |||
49 | namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests | ||
50 | { | ||
51 | /// <summary> | ||
52 | /// Attachment tests | ||
53 | /// </summary> | ||
54 | [TestFixture] | ||
55 | public class AttachmentsModuleTests | ||
56 | { | ||
57 | private Scene scene; | ||
58 | private AttachmentsModule m_attMod; | ||
59 | private ScenePresence m_presence; | ||
60 | |||
61 | [SetUp] | ||
62 | public void Init() | ||
63 | { | ||
64 | // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. | ||
65 | Util.FireAndForgetMethod = FireAndForgetMethod.None; | ||
66 | |||
67 | IConfigSource config = new IniConfigSource(); | ||
68 | config.AddConfig("Modules"); | ||
69 | config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule"); | ||
70 | |||
71 | scene = SceneHelpers.SetupScene(); | ||
72 | m_attMod = new AttachmentsModule(); | ||
73 | SceneHelpers.SetupSceneModules(scene, config, m_attMod, new BasicInventoryAccessModule()); | ||
74 | } | ||
75 | |||
76 | [TearDown] | ||
77 | public void TearDown() | ||
78 | { | ||
79 | // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple | ||
80 | // threads. Possibly, later tests should be rewritten not to worry about such things. | ||
81 | Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod; | ||
82 | } | ||
83 | |||
84 | /// <summary> | ||
85 | /// Add the standard presence for a test. | ||
86 | /// </summary> | ||
87 | private void AddPresence() | ||
88 | { | ||
89 | UUID userId = TestHelpers.ParseTail(0x1); | ||
90 | UserAccountHelpers.CreateUserWithInventory(scene, userId); | ||
91 | m_presence = SceneHelpers.AddScenePresence(scene, userId); | ||
92 | } | ||
93 | |||
94 | [Test] | ||
95 | public void TestAddAttachmentFromGround() | ||
96 | { | ||
97 | TestHelpers.InMethod(); | ||
98 | // log4net.Config.XmlConfigurator.Configure(); | ||
99 | |||
100 | AddPresence(); | ||
101 | string attName = "att"; | ||
102 | |||
103 | SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, attName).ParentGroup; | ||
104 | |||
105 | m_attMod.AttachObject(m_presence.ControllingClient, so, (uint)AttachmentPoint.Chest, false); | ||
106 | |||
107 | // Check status on scene presence | ||
108 | Assert.That(m_presence.HasAttachments(), Is.True); | ||
109 | List<SceneObjectGroup> attachments = m_presence.GetAttachments(); | ||
110 | Assert.That(attachments.Count, Is.EqualTo(1)); | ||
111 | SceneObjectGroup attSo = attachments[0]; | ||
112 | Assert.That(attSo.Name, Is.EqualTo(attName)); | ||
113 | Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest)); | ||
114 | Assert.That(attSo.IsAttachment); | ||
115 | Assert.That(attSo.UsesPhysics, Is.False); | ||
116 | Assert.That(attSo.IsTemporary, Is.False); | ||
117 | |||
118 | // Check item status | ||
119 | Assert.That(m_presence.Appearance.GetAttachpoint( | ||
120 | attSo.GetFromItemID()), Is.EqualTo((int)AttachmentPoint.Chest)); | ||
121 | } | ||
122 | |||
123 | [Test] | ||
124 | public void TestAddAttachmentFromInventory() | ||
125 | { | ||
126 | TestHelpers.InMethod(); | ||
127 | // log4net.Config.XmlConfigurator.Configure(); | ||
128 | |||
129 | AddPresence(); | ||
130 | |||
131 | UUID attItemId = TestHelpers.ParseTail(0x2); | ||
132 | UUID attAssetId = TestHelpers.ParseTail(0x3); | ||
133 | string attName = "att"; | ||
134 | |||
135 | UserInventoryHelpers.CreateInventoryItem( | ||
136 | scene, attName, attItemId, attAssetId, m_presence.UUID, InventoryType.Object); | ||
137 | |||
138 | m_attMod.RezSingleAttachmentFromInventory( | ||
139 | m_presence.ControllingClient, attItemId, (uint)AttachmentPoint.Chest); | ||
140 | |||
141 | // Check scene presence status | ||
142 | Assert.That(m_presence.HasAttachments(), Is.True); | ||
143 | List<SceneObjectGroup> attachments = m_presence.GetAttachments(); | ||
144 | Assert.That(attachments.Count, Is.EqualTo(1)); | ||
145 | SceneObjectGroup attSo = attachments[0]; | ||
146 | Assert.That(attSo.Name, Is.EqualTo(attName)); | ||
147 | Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest)); | ||
148 | Assert.That(attSo.IsAttachment); | ||
149 | Assert.That(attSo.UsesPhysics, Is.False); | ||
150 | Assert.That(attSo.IsTemporary, Is.False); | ||
151 | |||
152 | // Check appearance status | ||
153 | Assert.That(m_presence.Appearance.GetAttachpoint(attItemId), Is.EqualTo((int)AttachmentPoint.Chest)); | ||
154 | } | ||
155 | |||
156 | [Test] | ||
157 | public void TestDetachAttachmentToGround() | ||
158 | { | ||
159 | TestHelpers.InMethod(); | ||
160 | // log4net.Config.XmlConfigurator.Configure(); | ||
161 | |||
162 | AddPresence(); | ||
163 | |||
164 | UUID attItemId = TestHelpers.ParseTail(0x2); | ||
165 | UUID attAssetId = TestHelpers.ParseTail(0x3); | ||
166 | string attName = "att"; | ||
167 | |||
168 | UserInventoryHelpers.CreateInventoryItem( | ||
169 | scene, attName, attItemId, attAssetId, m_presence.UUID, InventoryType.Object); | ||
170 | |||
171 | ISceneEntity so = m_attMod.RezSingleAttachmentFromInventory( | ||
172 | m_presence.ControllingClient, attItemId, (uint)AttachmentPoint.Chest); | ||
173 | m_attMod.DetachSingleAttachmentToGround(so.LocalId, m_presence.ControllingClient); | ||
174 | |||
175 | // Check scene presence status | ||
176 | Assert.That(m_presence.HasAttachments(), Is.False); | ||
177 | List<SceneObjectGroup> attachments = m_presence.GetAttachments(); | ||
178 | Assert.That(attachments.Count, Is.EqualTo(0)); | ||
179 | |||
180 | // Check appearance status | ||
181 | Assert.That(m_presence.Appearance.GetAttachments().Count, Is.EqualTo(0)); | ||
182 | |||
183 | // Check item status | ||
184 | Assert.That(scene.InventoryService.GetItem(new InventoryItemBase(attItemId)), Is.Null); | ||
185 | |||
186 | // Check object in scene | ||
187 | Assert.That(scene.GetSceneObjectGroup("att"), Is.Not.Null); | ||
188 | } | ||
189 | |||
190 | [Test] | ||
191 | public void TestDetachAttachmentToInventory() | ||
192 | { | ||
193 | TestHelpers.InMethod(); | ||
194 | // log4net.Config.XmlConfigurator.Configure(); | ||
195 | |||
196 | AddPresence(); | ||
197 | |||
198 | UUID attItemId = TestHelpers.ParseTail(0x2); | ||
199 | UUID attAssetId = TestHelpers.ParseTail(0x3); | ||
200 | string attName = "att"; | ||
201 | |||
202 | UserInventoryHelpers.CreateInventoryItem( | ||
203 | scene, attName, attItemId, attAssetId, m_presence.UUID, InventoryType.Object); | ||
204 | |||
205 | m_attMod.RezSingleAttachmentFromInventory( | ||
206 | m_presence.ControllingClient, attItemId, (uint)AttachmentPoint.Chest); | ||
207 | m_attMod.DetachSingleAttachmentToInv(attItemId, m_presence.ControllingClient); | ||
208 | |||
209 | // Check status on scene presence | ||
210 | Assert.That(m_presence.HasAttachments(), Is.False); | ||
211 | List<SceneObjectGroup> attachments = m_presence.GetAttachments(); | ||
212 | Assert.That(attachments.Count, Is.EqualTo(0)); | ||
213 | |||
214 | // Check item status | ||
215 | Assert.That(m_presence.Appearance.GetAttachpoint(attItemId), Is.EqualTo(0)); | ||
216 | } | ||
217 | |||
218 | [Test] | ||
219 | public void TestRezAttachmentsOnAvatarEntrance() | ||
220 | { | ||
221 | TestHelpers.InMethod(); | ||
222 | // log4net.Config.XmlConfigurator.Configure(); | ||
223 | |||
224 | UUID userId = TestHelpers.ParseTail(0x1); | ||
225 | UUID attItemId = TestHelpers.ParseTail(0x2); | ||
226 | UUID attAssetId = TestHelpers.ParseTail(0x3); | ||
227 | string attName = "att"; | ||
228 | |||
229 | UserAccountHelpers.CreateUserWithInventory(scene, userId); | ||
230 | InventoryItemBase attItem | ||
231 | = UserInventoryHelpers.CreateInventoryItem( | ||
232 | scene, attName, attItemId, attAssetId, userId, InventoryType.Object); | ||
233 | |||
234 | AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId); | ||
235 | acd.Appearance = new AvatarAppearance(); | ||
236 | acd.Appearance.SetAttachment((int)AttachmentPoint.Chest, attItem.ID, attItem.AssetID); | ||
237 | ScenePresence presence = SceneHelpers.AddScenePresence(scene, acd); | ||
238 | |||
239 | Assert.That(presence.HasAttachments(), Is.True); | ||
240 | List<SceneObjectGroup> attachments = presence.GetAttachments(); | ||
241 | |||
242 | Assert.That(attachments.Count, Is.EqualTo(1)); | ||
243 | SceneObjectGroup attSo = attachments[0]; | ||
244 | Assert.That(attSo.Name, Is.EqualTo(attName)); | ||
245 | Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest)); | ||
246 | Assert.That(attSo.IsAttachment); | ||
247 | Assert.That(attSo.UsesPhysics, Is.False); | ||
248 | Assert.That(attSo.IsTemporary, Is.False); | ||
249 | } | ||
250 | |||
251 | // I'm commenting this test because scene setup NEEDS InventoryService to | ||
252 | // be non-null | ||
253 | //[Test] | ||
254 | // public void T032_CrossAttachments() | ||
255 | // { | ||
256 | // TestHelpers.InMethod(); | ||
257 | // | ||
258 | // ScenePresence presence = scene.GetScenePresence(agent1); | ||
259 | // ScenePresence presence2 = scene2.GetScenePresence(agent1); | ||
260 | // presence2.AddAttachment(sog1); | ||
261 | // presence2.AddAttachment(sog2); | ||
262 | // | ||
263 | // ISharedRegionModule serialiser = new SerialiserModule(); | ||
264 | // SceneHelpers.SetupSceneModules(scene, new IniConfigSource(), serialiser); | ||
265 | // SceneHelpers.SetupSceneModules(scene2, new IniConfigSource(), serialiser); | ||
266 | // | ||
267 | // Assert.That(presence.HasAttachments(), Is.False, "Presence has attachments before cross"); | ||
268 | // | ||
269 | // //Assert.That(presence2.CrossAttachmentsIntoNewRegion(region1, true), Is.True, "Cross was not successful"); | ||
270 | // Assert.That(presence2.HasAttachments(), Is.False, "Presence2 objects were not deleted"); | ||
271 | // Assert.That(presence.HasAttachments(), Is.True, "Presence has not received new objects"); | ||
272 | // } | ||
273 | } | ||
274 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs index d02a305..b6a1564 100644 --- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs | |||
@@ -104,7 +104,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
104 | public void NewClient(IClientAPI client) | 104 | public void NewClient(IClientAPI client) |
105 | { | 105 | { |
106 | client.OnRequestWearables += SendWearables; | 106 | client.OnRequestWearables += SendWearables; |
107 | client.OnSetAppearance += SetAppearance; | 107 | client.OnSetAppearance += SetAppearanceFromClient; |
108 | client.OnAvatarNowWearing += AvatarIsWearing; | 108 | client.OnAvatarNowWearing += AvatarIsWearing; |
109 | } | 109 | } |
110 | 110 | ||
@@ -116,16 +116,20 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
116 | #endregion | 116 | #endregion |
117 | 117 | ||
118 | /// <summary> | 118 | /// <summary> |
119 | /// Check for the existence of the baked texture assets. Request a rebake | 119 | /// Check for the existence of the baked texture assets. |
120 | /// unless checkonly is true. | ||
121 | /// </summary> | 120 | /// </summary> |
122 | /// <param name="client"></param> | 121 | /// <param name="client"></param> |
123 | /// <param name="checkonly"></param> | ||
124 | public bool ValidateBakedTextureCache(IClientAPI client) | 122 | public bool ValidateBakedTextureCache(IClientAPI client) |
125 | { | 123 | { |
126 | return ValidateBakedTextureCache(client, true); | 124 | return ValidateBakedTextureCache(client, true); |
127 | } | 125 | } |
128 | 126 | ||
127 | /// <summary> | ||
128 | /// Check for the existence of the baked texture assets. Request a rebake | ||
129 | /// unless checkonly is true. | ||
130 | /// </summary> | ||
131 | /// <param name="client"></param> | ||
132 | /// <param name="checkonly"></param> | ||
129 | private bool ValidateBakedTextureCache(IClientAPI client, bool checkonly) | 133 | private bool ValidateBakedTextureCache(IClientAPI client, bool checkonly) |
130 | { | 134 | { |
131 | ScenePresence sp = m_scene.GetScenePresence(client.AgentId); | 135 | ScenePresence sp = m_scene.GetScenePresence(client.AgentId); |
@@ -147,6 +151,10 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
147 | if (face == null) | 151 | if (face == null) |
148 | continue; | 152 | continue; |
149 | 153 | ||
154 | // m_log.DebugFormat( | ||
155 | // "[AVFACTORY]: Looking for texture {0}, id {1} for {2} {3}", | ||
156 | // face.TextureID, idx, client.Name, client.AgentId); | ||
157 | |||
150 | // if the texture is one of the "defaults" then skip it | 158 | // if the texture is one of the "defaults" then skip it |
151 | // this should probably be more intelligent (skirt texture doesnt matter | 159 | // this should probably be more intelligent (skirt texture doesnt matter |
152 | // if the avatar isnt wearing a skirt) but if any of the main baked | 160 | // if the avatar isnt wearing a skirt) but if any of the main baked |
@@ -156,13 +164,15 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
156 | 164 | ||
157 | defonly = false; // found a non-default texture reference | 165 | defonly = false; // found a non-default texture reference |
158 | 166 | ||
159 | if (! CheckBakedTextureAsset(client,face.TextureID,idx)) | 167 | if (!CheckBakedTextureAsset(client, face.TextureID, idx)) |
160 | { | 168 | { |
161 | // the asset didn't exist if we are only checking, then we found a bad | 169 | // the asset didn't exist if we are only checking, then we found a bad |
162 | // one and we're done otherwise, ask for a rebake | 170 | // one and we're done otherwise, ask for a rebake |
163 | if (checkonly) return false; | 171 | if (checkonly) |
172 | return false; | ||
164 | 173 | ||
165 | m_log.InfoFormat("[AVFACTORY]: missing baked texture {0}, requesting rebake", face.TextureID); | 174 | m_log.InfoFormat("[AVFACTORY]: missing baked texture {0}, requesting rebake", face.TextureID); |
175 | |||
166 | client.SendRebakeAvatarTextures(face.TextureID); | 176 | client.SendRebakeAvatarTextures(face.TextureID); |
167 | } | 177 | } |
168 | } | 178 | } |
@@ -174,16 +184,17 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
174 | } | 184 | } |
175 | 185 | ||
176 | /// <summary> | 186 | /// <summary> |
177 | /// Set appearance data (textureentry and slider settings) received from the client | 187 | /// Set appearance data (texture asset IDs and slider settings) received from the client |
178 | /// </summary> | 188 | /// </summary> |
189 | /// <param name="client"></param> | ||
179 | /// <param name="texture"></param> | 190 | /// <param name="texture"></param> |
180 | /// <param name="visualParam"></param> | 191 | /// <param name="visualParam"></param> |
181 | public void SetAppearance(IClientAPI client, Primitive.TextureEntry textureEntry, byte[] visualParams) | 192 | public void SetAppearanceFromClient(IClientAPI client, Primitive.TextureEntry textureEntry, byte[] visualParams) |
182 | { | 193 | { |
183 | ScenePresence sp = m_scene.GetScenePresence(client.AgentId); | 194 | ScenePresence sp = m_scene.GetScenePresence(client.AgentId); |
184 | if (sp == null) | 195 | if (sp == null) |
185 | { | 196 | { |
186 | m_log.WarnFormat("[AVFACTORY]: SetAppearance unable to find presence for {0}",client.AgentId); | 197 | m_log.WarnFormat("[AVFACTORY]: SetAppearance unable to find presence for {0}", client.AgentId); |
187 | return; | 198 | return; |
188 | } | 199 | } |
189 | 200 | ||
@@ -211,18 +222,18 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
211 | changed = sp.Appearance.SetTextureEntries(textureEntry) || changed; | 222 | changed = sp.Appearance.SetTextureEntries(textureEntry) || changed; |
212 | 223 | ||
213 | m_log.InfoFormat("[AVFACTORY]: received texture update for {0}", client.AgentId); | 224 | m_log.InfoFormat("[AVFACTORY]: received texture update for {0}", client.AgentId); |
214 | Util.FireAndForget(delegate(object o) { ValidateBakedTextureCache(client,false); }); | 225 | Util.FireAndForget(delegate(object o) { ValidateBakedTextureCache(client, false); }); |
215 | 226 | ||
216 | // This appears to be set only in the final stage of the appearance | 227 | // This appears to be set only in the final stage of the appearance |
217 | // update transaction. In theory, we should be able to do an immediate | 228 | // update transaction. In theory, we should be able to do an immediate |
218 | // appearance send and save here. | 229 | // appearance send and save here. |
219 | 230 | ||
220 | // save only if there were changes, send no matter what (doesn't hurt to send twice) | ||
221 | if (changed) | ||
222 | QueueAppearanceSave(client.AgentId); | ||
223 | QueueAppearanceSend(client.AgentId); | ||
224 | } | 231 | } |
232 | // save only if there were changes, send no matter what (doesn't hurt to send twice) | ||
233 | if (changed) | ||
234 | QueueAppearanceSave(client.AgentId); | ||
225 | 235 | ||
236 | QueueAppearanceSend(client.AgentId); | ||
226 | } | 237 | } |
227 | 238 | ||
228 | // m_log.WarnFormat("[AVFACTORY]: complete SetAppearance for {0}:\n{1}",client.AgentId,sp.Appearance.ToString()); | 239 | // m_log.WarnFormat("[AVFACTORY]: complete SetAppearance for {0}:\n{1}",client.AgentId,sp.Appearance.ToString()); |
@@ -246,6 +257,117 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
246 | return true; | 257 | return true; |
247 | } | 258 | } |
248 | 259 | ||
260 | public Dictionary<BakeType, Primitive.TextureEntryFace> GetBakedTextureFaces(UUID agentId) | ||
261 | { | ||
262 | ScenePresence sp = m_scene.GetScenePresence(agentId); | ||
263 | |||
264 | if (sp == null) | ||
265 | return new Dictionary<BakeType, Primitive.TextureEntryFace>(); | ||
266 | |||
267 | return GetBakedTextureFaces(sp); | ||
268 | } | ||
269 | |||
270 | private Dictionary<BakeType, Primitive.TextureEntryFace> GetBakedTextureFaces(ScenePresence sp) | ||
271 | { | ||
272 | if (sp.IsChildAgent) | ||
273 | return new Dictionary<BakeType, Primitive.TextureEntryFace>(); | ||
274 | |||
275 | Dictionary<BakeType, Primitive.TextureEntryFace> bakedTextures | ||
276 | = new Dictionary<BakeType, Primitive.TextureEntryFace>(); | ||
277 | |||
278 | AvatarAppearance appearance = sp.Appearance; | ||
279 | Primitive.TextureEntryFace[] faceTextures = appearance.Texture.FaceTextures; | ||
280 | |||
281 | foreach (int i in Enum.GetValues(typeof(BakeType))) | ||
282 | { | ||
283 | BakeType bakeType = (BakeType)i; | ||
284 | |||
285 | if (bakeType == BakeType.Unknown) | ||
286 | continue; | ||
287 | |||
288 | // m_log.DebugFormat( | ||
289 | // "[AVFACTORY]: NPC avatar {0} has texture id {1} : {2}", | ||
290 | // acd.AgentID, i, acd.Appearance.Texture.FaceTextures[i]); | ||
291 | |||
292 | int ftIndex = (int)AppearanceManager.BakeTypeToAgentTextureIndex(bakeType); | ||
293 | bakedTextures[bakeType] = faceTextures[ftIndex]; | ||
294 | } | ||
295 | |||
296 | return bakedTextures; | ||
297 | } | ||
298 | |||
299 | public bool SaveBakedTextures(UUID agentId) | ||
300 | { | ||
301 | ScenePresence sp = m_scene.GetScenePresence(agentId); | ||
302 | |||
303 | if (sp == null) | ||
304 | return false; | ||
305 | |||
306 | m_log.DebugFormat( | ||
307 | "[AV FACTORY]: Permanently saving baked textures for {0} in {1}", | ||
308 | sp.Name, m_scene.RegionInfo.RegionName); | ||
309 | |||
310 | Dictionary<BakeType, Primitive.TextureEntryFace> bakedTextures = GetBakedTextureFaces(sp); | ||
311 | |||
312 | if (bakedTextures.Count == 0) | ||
313 | return false; | ||
314 | |||
315 | foreach (BakeType bakeType in bakedTextures.Keys) | ||
316 | { | ||
317 | Primitive.TextureEntryFace bakedTextureFace = bakedTextures[bakeType]; | ||
318 | |||
319 | if (bakedTextureFace == null) | ||
320 | { | ||
321 | m_log.WarnFormat( | ||
322 | "[AV FACTORY]: No texture ID set for {0} for {1} in {2} not found when trying to save permanently", | ||
323 | bakeType, sp.Name, m_scene.RegionInfo.RegionName); | ||
324 | |||
325 | continue; | ||
326 | } | ||
327 | |||
328 | AssetBase asset = m_scene.AssetService.Get(bakedTextureFace.TextureID.ToString()); | ||
329 | |||
330 | if (asset != null) | ||
331 | { | ||
332 | asset.Temporary = false; | ||
333 | asset.Local = false; | ||
334 | m_scene.AssetService.Store(asset); | ||
335 | } | ||
336 | else | ||
337 | { | ||
338 | m_log.WarnFormat( | ||
339 | "[AV FACTORY]: Baked texture id {0} not found for bake {1} for avatar {2} in {3} when trying to save permanently", | ||
340 | bakedTextureFace.TextureID, bakeType, sp.Name, m_scene.RegionInfo.RegionName); | ||
341 | } | ||
342 | } | ||
343 | |||
344 | // for (int i = 0; i < faceTextures.Length; i++) | ||
345 | // { | ||
346 | //// m_log.DebugFormat( | ||
347 | //// "[AVFACTORY]: NPC avatar {0} has texture id {1} : {2}", | ||
348 | //// acd.AgentID, i, acd.Appearance.Texture.FaceTextures[i]); | ||
349 | // | ||
350 | // if (faceTextures[i] == null) | ||
351 | // continue; | ||
352 | // | ||
353 | // AssetBase asset = m_scene.AssetService.Get(faceTextures[i].TextureID.ToString()); | ||
354 | // | ||
355 | // if (asset != null) | ||
356 | // { | ||
357 | // asset.Temporary = false; | ||
358 | // m_scene.AssetService.Store(asset); | ||
359 | // } | ||
360 | // else | ||
361 | // { | ||
362 | // m_log.WarnFormat( | ||
363 | // "[AV FACTORY]: Baked texture {0} for {1} in {2} not found when trying to save permanently", | ||
364 | // faceTextures[i].TextureID, sp.Name, m_scene.RegionInfo.RegionName); | ||
365 | // } | ||
366 | // } | ||
367 | |||
368 | return true; | ||
369 | } | ||
370 | |||
249 | #region UpdateAppearanceTimer | 371 | #region UpdateAppearanceTimer |
250 | 372 | ||
251 | /// <summary> | 373 | /// <summary> |
@@ -278,26 +400,13 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
278 | } | 400 | } |
279 | } | 401 | } |
280 | 402 | ||
281 | private void HandleAppearanceSend(UUID agentid) | 403 | private void SaveAppearance(UUID agentid) |
282 | { | 404 | { |
283 | ScenePresence sp = m_scene.GetScenePresence(agentid); | 405 | // We must set appearance parameters in the en_US culture in order to avoid issues where values are saved |
284 | if (sp == null) | 406 | // in a culture where decimal points are commas and then reloaded in a culture which just treats them as |
285 | { | 407 | // number seperators. |
286 | m_log.WarnFormat("[AVFACTORY]: Agent {0} no longer in the scene", agentid); | 408 | Culture.SetCurrentCulture(); |
287 | return; | ||
288 | } | ||
289 | |||
290 | // m_log.WarnFormat("[AVFACTORY]: Handle appearance send for {0}", agentid); | ||
291 | 409 | ||
292 | // Send the appearance to everyone in the scene | ||
293 | sp.SendAppearanceToAllOtherAgents(); | ||
294 | |||
295 | // Send animations back to the avatar as well | ||
296 | sp.Animator.SendAnimPack(); | ||
297 | } | ||
298 | |||
299 | private void HandleAppearanceSave(UUID agentid) | ||
300 | { | ||
301 | ScenePresence sp = m_scene.GetScenePresence(agentid); | 410 | ScenePresence sp = m_scene.GetScenePresence(agentid); |
302 | if (sp == null) | 411 | if (sp == null) |
303 | { | 412 | { |
@@ -321,7 +430,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
321 | { | 430 | { |
322 | if (kvp.Value < now) | 431 | if (kvp.Value < now) |
323 | { | 432 | { |
324 | Util.FireAndForget(delegate(object o) { HandleAppearanceSend(kvp.Key); }); | 433 | Util.FireAndForget(delegate(object o) { SendAppearance(kvp.Key); }); |
325 | m_sendqueue.Remove(kvp.Key); | 434 | m_sendqueue.Remove(kvp.Key); |
326 | } | 435 | } |
327 | } | 436 | } |
@@ -334,7 +443,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
334 | { | 443 | { |
335 | if (kvp.Value < now) | 444 | if (kvp.Value < now) |
336 | { | 445 | { |
337 | Util.FireAndForget(delegate(object o) { HandleAppearanceSave(kvp.Key); }); | 446 | Util.FireAndForget(delegate(object o) { SaveAppearance(kvp.Key); }); |
338 | m_savequeue.Remove(kvp.Key); | 447 | m_savequeue.Remove(kvp.Key); |
339 | } | 448 | } |
340 | } | 449 | } |
@@ -380,11 +489,11 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
380 | // m_log.WarnFormat("[AVFACTORY]: AvatarIsWearing called for {0}", client.AgentId); | 489 | // m_log.WarnFormat("[AVFACTORY]: AvatarIsWearing called for {0}", client.AgentId); |
381 | 490 | ||
382 | // we need to clean out the existing textures | 491 | // we need to clean out the existing textures |
383 | sp.Appearance.ResetAppearance(); | 492 | sp.Appearance.ResetAppearance(); |
384 | 493 | ||
385 | // operate on a copy of the appearance so we don't have to lock anything | 494 | // operate on a copy of the appearance so we don't have to lock anything yet |
386 | AvatarAppearance avatAppearance = new AvatarAppearance(sp.Appearance, false); | 495 | AvatarAppearance avatAppearance = new AvatarAppearance(sp.Appearance, false); |
387 | 496 | ||
388 | foreach (AvatarWearingArgs.Wearable wear in e.NowWearing) | 497 | foreach (AvatarWearingArgs.Wearable wear in e.NowWearing) |
389 | { | 498 | { |
390 | if (wear.Type < AvatarWearable.MAX_WEARABLES) | 499 | if (wear.Type < AvatarWearable.MAX_WEARABLES) |
@@ -396,12 +505,37 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
396 | // This could take awhile since it needs to pull inventory | 505 | // This could take awhile since it needs to pull inventory |
397 | SetAppearanceAssets(sp.UUID, ref avatAppearance); | 506 | SetAppearanceAssets(sp.UUID, ref avatAppearance); |
398 | 507 | ||
399 | // could get fancier with the locks here, but in the spirit of "last write wins" | 508 | lock (m_setAppearanceLock) |
400 | // this should work correctly, also, we don't need to send the appearance here | 509 | { |
401 | // since the "iswearing" will trigger a new set of visual param and baked texture changes | 510 | // Update only those fields that we have changed. This is important because the viewer |
402 | // when those complete, the new appearance will be sent | 511 | // often sends AvatarIsWearing and SetAppearance packets at once, and AvatarIsWearing |
403 | sp.Appearance = avatAppearance; | 512 | // shouldn't overwrite the changes made in SetAppearance. |
404 | QueueAppearanceSave(client.AgentId); | 513 | sp.Appearance.Wearables = avatAppearance.Wearables; |
514 | sp.Appearance.Texture = avatAppearance.Texture; | ||
515 | |||
516 | // We don't need to send the appearance here since the "iswearing" will trigger a new set | ||
517 | // of visual param and baked texture changes. When those complete, the new appearance will be sent | ||
518 | |||
519 | QueueAppearanceSave(client.AgentId); | ||
520 | } | ||
521 | } | ||
522 | |||
523 | public bool SendAppearance(UUID agentId) | ||
524 | { | ||
525 | ScenePresence sp = m_scene.GetScenePresence(agentId); | ||
526 | if (sp == null) | ||
527 | { | ||
528 | m_log.WarnFormat("[AVFACTORY]: Agent {0} no longer in the scene", agentId); | ||
529 | return false; | ||
530 | } | ||
531 | |||
532 | // Send the appearance to everyone in the scene | ||
533 | sp.SendAppearanceToAllOtherAgents(); | ||
534 | |||
535 | // Send animations back to the avatar as well | ||
536 | sp.Animator.SendAnimPack(); | ||
537 | |||
538 | return true; | ||
405 | } | 539 | } |
406 | 540 | ||
407 | private void SetAppearanceAssets(UUID userID, ref AvatarAppearance appearance) | 541 | private void SetAppearanceAssets(UUID userID, ref AvatarAppearance appearance) |
diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs new file mode 100644 index 0000000..7b2f14e --- /dev/null +++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs | |||
@@ -0,0 +1,120 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using Nini.Config; | ||
31 | using NUnit.Framework; | ||
32 | using OpenMetaverse; | ||
33 | using OpenSim.Framework; | ||
34 | using OpenSim.Region.CoreModules.Asset; | ||
35 | using OpenSim.Region.Framework.Scenes; | ||
36 | using OpenSim.Tests.Common; | ||
37 | using OpenSim.Tests.Common.Mock; | ||
38 | |||
39 | namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | ||
40 | { | ||
41 | [TestFixture] | ||
42 | public class AvatarFactoryModuleTests | ||
43 | { | ||
44 | /// <summary> | ||
45 | /// Only partial right now since we don't yet test that it's ended up in the avatar appearance service. | ||
46 | /// </summary> | ||
47 | [Test] | ||
48 | public void TestSetAppearance() | ||
49 | { | ||
50 | TestHelpers.InMethod(); | ||
51 | // log4net.Config.XmlConfigurator.Configure(); | ||
52 | |||
53 | UUID userId = TestHelpers.ParseTail(0x1); | ||
54 | |||
55 | AvatarFactoryModule afm = new AvatarFactoryModule(); | ||
56 | TestScene scene = SceneHelpers.SetupScene(); | ||
57 | SceneHelpers.SetupSceneModules(scene, afm); | ||
58 | IClientAPI tc = SceneHelpers.AddScenePresence(scene, userId).ControllingClient; | ||
59 | |||
60 | byte[] visualParams = new byte[AvatarAppearance.VISUALPARAM_COUNT]; | ||
61 | for (byte i = 0; i < visualParams.Length; i++) | ||
62 | visualParams[i] = i; | ||
63 | |||
64 | afm.SetAppearanceFromClient(tc, new Primitive.TextureEntry(TestHelpers.ParseTail(0x10)), visualParams); | ||
65 | |||
66 | ScenePresence sp = scene.GetScenePresence(userId); | ||
67 | |||
68 | // TODO: Check baked texture | ||
69 | Assert.AreEqual(visualParams, sp.Appearance.VisualParams); | ||
70 | } | ||
71 | |||
72 | [Test] | ||
73 | public void TestSaveBakedTextures() | ||
74 | { | ||
75 | TestHelpers.InMethod(); | ||
76 | // log4net.Config.XmlConfigurator.Configure(); | ||
77 | |||
78 | UUID userId = TestHelpers.ParseTail(0x1); | ||
79 | UUID eyesTextureId = TestHelpers.ParseTail(0x2); | ||
80 | |||
81 | // We need an asset cache because otherwise the LocalAssetServiceConnector will short-circuit directly | ||
82 | // to the AssetService, which will then store temporary and local assets permanently | ||
83 | CoreAssetCache assetCache = new CoreAssetCache(); | ||
84 | |||
85 | AvatarFactoryModule afm = new AvatarFactoryModule(); | ||
86 | TestScene scene = SceneHelpers.SetupScene(assetCache); | ||
87 | SceneHelpers.SetupSceneModules(scene, afm); | ||
88 | IClientAPI tc = SceneHelpers.AddScenePresence(scene, userId).ControllingClient; | ||
89 | |||
90 | // TODO: Use the actual BunchOfCaps functionality once we slot in the CapabilitiesModules | ||
91 | AssetBase uploadedAsset; | ||
92 | uploadedAsset = new AssetBase(eyesTextureId, "Baked Texture", (sbyte)AssetType.Texture, userId.ToString()); | ||
93 | uploadedAsset.Data = new byte[] { 2 }; | ||
94 | uploadedAsset.Temporary = true; | ||
95 | uploadedAsset.Local = true; // Local assets aren't persisted, non-local are | ||
96 | scene.AssetService.Store(uploadedAsset); | ||
97 | |||
98 | byte[] visualParams = new byte[AvatarAppearance.VISUALPARAM_COUNT]; | ||
99 | for (byte i = 0; i < visualParams.Length; i++) | ||
100 | visualParams[i] = i; | ||
101 | |||
102 | Primitive.TextureEntry bakedTextureEntry = new Primitive.TextureEntry(TestHelpers.ParseTail(0x10)); | ||
103 | uint eyesFaceIndex = (uint)AppearanceManager.BakeTypeToAgentTextureIndex(BakeType.Eyes); | ||
104 | Primitive.TextureEntryFace eyesFace = bakedTextureEntry.CreateFace(eyesFaceIndex); | ||
105 | eyesFace.TextureID = eyesTextureId; | ||
106 | |||
107 | afm.SetAppearanceFromClient(tc, bakedTextureEntry, visualParams); | ||
108 | afm.SaveBakedTextures(userId); | ||
109 | // Dictionary<BakeType, Primitive.TextureEntryFace> bakedTextures = afm.GetBakedTextureFaces(userId); | ||
110 | |||
111 | // We should also inpsect the asset data store layer directly, but this is difficult to get at right now. | ||
112 | assetCache.Clear(); | ||
113 | |||
114 | AssetBase eyesBake = scene.AssetService.Get(eyesTextureId.ToString()); | ||
115 | Assert.That(eyesBake, Is.Not.Null); | ||
116 | Assert.That(eyesBake.Temporary, Is.False); | ||
117 | Assert.That(eyesBake.Local, Is.False); | ||
118 | } | ||
119 | } | ||
120 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs index 1a0b914..d9dcee7 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs | |||
@@ -172,11 +172,15 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
172 | private void RetrieveInstantMessages(IClientAPI client) | 172 | private void RetrieveInstantMessages(IClientAPI client) |
173 | { | 173 | { |
174 | if (m_RestURL == String.Empty) | 174 | if (m_RestURL == String.Empty) |
175 | { | ||
175 | return; | 176 | return; |
177 | } | ||
178 | else | ||
179 | { | ||
180 | m_log.DebugFormat("[OFFLINE MESSAGING]: Retrieving stored messages for {0}", client.AgentId); | ||
176 | 181 | ||
177 | m_log.DebugFormat("[OFFLINE MESSAGING] Retrieving stored messages for {0}", client.AgentId); | 182 | List<GridInstantMessage> msglist |
178 | 183 | = SynchronousRestObjectRequester.MakeRequest<UUID, List<GridInstantMessage>>( | |
179 | List<GridInstantMessage> msglist = SynchronousRestObjectPoster.BeginPostObject<UUID, List<GridInstantMessage>>( | ||
180 | "POST", m_RestURL + "/RetrieveMessages/", client.AgentId); | 184 | "POST", m_RestURL + "/RetrieveMessages/", client.AgentId); |
181 | 185 | ||
182 | if (msglist != null) | 186 | if (msglist != null) |
@@ -209,6 +213,8 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
209 | im.dialog != (byte)InstantMessageDialog.GroupInvitation && | 213 | im.dialog != (byte)InstantMessageDialog.GroupInvitation && |
210 | im.dialog != (byte)InstantMessageDialog.InventoryOffered) | 214 | im.dialog != (byte)InstantMessageDialog.InventoryOffered) |
211 | { | 215 | { |
216 | bool success = SynchronousRestObjectRequester.MakeRequest<GridInstantMessage, bool>( | ||
217 | "POST", m_RestURL+"/SaveMessage/", im); | ||
212 | return; | 218 | return; |
213 | } | 219 | } |
214 | 220 | ||
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs index aadeedb..19ef571 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs | |||
@@ -100,8 +100,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
100 | // log4net.Config.XmlConfigurator.Configure(); | 100 | // log4net.Config.XmlConfigurator.Configure(); |
101 | 101 | ||
102 | InventoryArchiverModule archiverModule = new InventoryArchiverModule(); | 102 | InventoryArchiverModule archiverModule = new InventoryArchiverModule(); |
103 | Scene scene = SceneSetupHelpers.SetupScene(); | 103 | Scene scene = SceneHelpers.SetupScene(); |
104 | SceneSetupHelpers.SetupSceneModules(scene, archiverModule); | 104 | SceneHelpers.SetupSceneModules(scene, archiverModule); |
105 | 105 | ||
106 | UserAccountHelpers.CreateUserWithInventory(scene, m_uaLL1, "hampshire"); | 106 | UserAccountHelpers.CreateUserWithInventory(scene, m_uaLL1, "hampshire"); |
107 | 107 | ||
@@ -109,7 +109,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
109 | 109 | ||
110 | // Create scene object asset | 110 | // Create scene object asset |
111 | UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040"); | 111 | UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040"); |
112 | SceneObjectGroup object1 = SceneSetupHelpers.CreateSceneObject(1, ownerId, "Ray Gun Object", 0x50); | 112 | SceneObjectGroup object1 = SceneHelpers.CreateSceneObject(1, ownerId, "Ray Gun Object", 0x50); |
113 | 113 | ||
114 | UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060"); | 114 | UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060"); |
115 | AssetBase asset1 = AssetHelpers.CreateAsset(asset1Id, object1); | 115 | AssetBase asset1 = AssetHelpers.CreateAsset(asset1Id, object1); |
@@ -127,10 +127,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
127 | scene.AddInventoryItem(item1); | 127 | scene.AddInventoryItem(item1); |
128 | 128 | ||
129 | // Create coalesced objects asset | 129 | // Create coalesced objects asset |
130 | SceneObjectGroup cobj1 = SceneSetupHelpers.CreateSceneObject(1, m_uaLL1.PrincipalID, "Object1", 0x120); | 130 | SceneObjectGroup cobj1 = SceneHelpers.CreateSceneObject(1, m_uaLL1.PrincipalID, "Object1", 0x120); |
131 | cobj1.AbsolutePosition = new Vector3(15, 30, 45); | 131 | cobj1.AbsolutePosition = new Vector3(15, 30, 45); |
132 | 132 | ||
133 | SceneObjectGroup cobj2 = SceneSetupHelpers.CreateSceneObject(1, m_uaLL1.PrincipalID, "Object2", 0x140); | 133 | SceneObjectGroup cobj2 = SceneHelpers.CreateSceneObject(1, m_uaLL1.PrincipalID, "Object2", 0x140); |
134 | cobj2.AbsolutePosition = new Vector3(25, 50, 75); | 134 | cobj2.AbsolutePosition = new Vector3(25, 50, 75); |
135 | 135 | ||
136 | CoalescedSceneObjects coa = new CoalescedSceneObjects(m_uaLL1.PrincipalID, cobj1, cobj2); | 136 | CoalescedSceneObjects coa = new CoalescedSceneObjects(m_uaLL1.PrincipalID, cobj1, cobj2); |
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs index ae3ab21..e409c8e 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs | |||
@@ -61,14 +61,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
61 | SerialiserModule serialiserModule = new SerialiserModule(); | 61 | SerialiserModule serialiserModule = new SerialiserModule(); |
62 | m_archiverModule = new InventoryArchiverModule(); | 62 | m_archiverModule = new InventoryArchiverModule(); |
63 | 63 | ||
64 | m_scene = SceneSetupHelpers.SetupScene(); | 64 | m_scene = SceneHelpers.SetupScene(); |
65 | SceneSetupHelpers.SetupSceneModules(m_scene, serialiserModule, m_archiverModule); | 65 | SceneHelpers.SetupSceneModules(m_scene, serialiserModule, m_archiverModule); |
66 | } | 66 | } |
67 | 67 | ||
68 | [Test] | 68 | [Test] |
69 | public void TestLoadCoalesecedItem() | 69 | public void TestLoadCoalesecedItem() |
70 | { | 70 | { |
71 | TestHelper.InMethod(); | 71 | TestHelpers.InMethod(); |
72 | // log4net.Config.XmlConfigurator.Configure(); | 72 | // log4net.Config.XmlConfigurator.Configure(); |
73 | 73 | ||
74 | UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL1, "password"); | 74 | UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL1, "password"); |
@@ -104,7 +104,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
104 | [Test] | 104 | [Test] |
105 | public void TestOrder() | 105 | public void TestOrder() |
106 | { | 106 | { |
107 | TestHelper.InMethod(); | 107 | TestHelpers.InMethod(); |
108 | // log4net.Config.XmlConfigurator.Configure(); | 108 | // log4net.Config.XmlConfigurator.Configure(); |
109 | 109 | ||
110 | MemoryStream archiveReadStream = new MemoryStream(m_iarStreamBytes); | 110 | MemoryStream archiveReadStream = new MemoryStream(m_iarStreamBytes); |
@@ -129,7 +129,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
129 | [Test] | 129 | [Test] |
130 | public void TestSaveItemToIar() | 130 | public void TestSaveItemToIar() |
131 | { | 131 | { |
132 | TestHelper.InMethod(); | 132 | TestHelpers.InMethod(); |
133 | // log4net.Config.XmlConfigurator.Configure(); | 133 | // log4net.Config.XmlConfigurator.Configure(); |
134 | 134 | ||
135 | // Create user | 135 | // Create user |
@@ -141,7 +141,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
141 | 141 | ||
142 | // Create asset | 142 | // Create asset |
143 | UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040"); | 143 | UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040"); |
144 | SceneObjectGroup object1 = SceneSetupHelpers.CreateSceneObject(1, ownerId, "My Little Dog Object", 0x50); | 144 | SceneObjectGroup object1 = SceneHelpers.CreateSceneObject(1, ownerId, "My Little Dog Object", 0x50); |
145 | 145 | ||
146 | UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060"); | 146 | UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060"); |
147 | AssetBase asset1 = AssetHelpers.CreateAsset(asset1Id, object1); | 147 | AssetBase asset1 = AssetHelpers.CreateAsset(asset1Id, object1); |
@@ -224,7 +224,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
224 | [Test] | 224 | [Test] |
225 | public void TestSaveItemToIarNoAssets() | 225 | public void TestSaveItemToIarNoAssets() |
226 | { | 226 | { |
227 | TestHelper.InMethod(); | 227 | TestHelpers.InMethod(); |
228 | // log4net.Config.XmlConfigurator.Configure(); | 228 | // log4net.Config.XmlConfigurator.Configure(); |
229 | 229 | ||
230 | // Create user | 230 | // Create user |
@@ -236,7 +236,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
236 | 236 | ||
237 | // Create asset | 237 | // Create asset |
238 | UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040"); | 238 | UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040"); |
239 | SceneObjectGroup object1 = SceneSetupHelpers.CreateSceneObject(1, ownerId, "My Little Dog Object", 0x50); | 239 | SceneObjectGroup object1 = SceneHelpers.CreateSceneObject(1, ownerId, "My Little Dog Object", 0x50); |
240 | 240 | ||
241 | UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060"); | 241 | UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060"); |
242 | AssetBase asset1 = AssetHelpers.CreateAsset(asset1Id, object1); | 242 | AssetBase asset1 = AssetHelpers.CreateAsset(asset1Id, object1); |
@@ -325,7 +325,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
325 | [Test] | 325 | [Test] |
326 | public void TestLoadIarCreatorAccountPresent() | 326 | public void TestLoadIarCreatorAccountPresent() |
327 | { | 327 | { |
328 | TestHelper.InMethod(); | 328 | TestHelpers.InMethod(); |
329 | // log4net.Config.XmlConfigurator.Configure(); | 329 | // log4net.Config.XmlConfigurator.Configure(); |
330 | 330 | ||
331 | UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL1, "meowfood"); | 331 | UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL1, "meowfood"); |
@@ -357,7 +357,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
357 | [Test] | 357 | [Test] |
358 | public void TestLoadIarV0_1SameNameCreator() | 358 | public void TestLoadIarV0_1SameNameCreator() |
359 | { | 359 | { |
360 | TestHelper.InMethod(); | 360 | TestHelpers.InMethod(); |
361 | // log4net.Config.XmlConfigurator.Configure(); | 361 | // log4net.Config.XmlConfigurator.Configure(); |
362 | 362 | ||
363 | UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaMT, "meowfood"); | 363 | UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaMT, "meowfood"); |
@@ -390,7 +390,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
390 | [Test] | 390 | [Test] |
391 | public void TestLoadIarV0_1AbsentCreator() | 391 | public void TestLoadIarV0_1AbsentCreator() |
392 | { | 392 | { |
393 | TestHelper.InMethod(); | 393 | TestHelpers.InMethod(); |
394 | // log4net.Config.XmlConfigurator.Configure(); | 394 | // log4net.Config.XmlConfigurator.Configure(); |
395 | 395 | ||
396 | UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaMT, "password"); | 396 | UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaMT, "password"); |
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/PathTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/PathTests.cs index 127d5f8..417c20c 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/PathTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/PathTests.cs | |||
@@ -57,13 +57,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
57 | [Test] | 57 | [Test] |
58 | public void TestSavePathToIarV0_1() | 58 | public void TestSavePathToIarV0_1() |
59 | { | 59 | { |
60 | TestHelper.InMethod(); | 60 | TestHelpers.InMethod(); |
61 | // log4net.Config.XmlConfigurator.Configure(); | 61 | // log4net.Config.XmlConfigurator.Configure(); |
62 | 62 | ||
63 | InventoryArchiverModule archiverModule = new InventoryArchiverModule(); | 63 | InventoryArchiverModule archiverModule = new InventoryArchiverModule(); |
64 | 64 | ||
65 | Scene scene = SceneSetupHelpers.SetupScene(); | 65 | Scene scene = SceneHelpers.SetupScene(); |
66 | SceneSetupHelpers.SetupSceneModules(scene, archiverModule); | 66 | SceneHelpers.SetupSceneModules(scene, archiverModule); |
67 | 67 | ||
68 | // Create user | 68 | // Create user |
69 | string userFirstName = "Jock"; | 69 | string userFirstName = "Jock"; |
@@ -172,16 +172,16 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
172 | [Test] | 172 | [Test] |
173 | public void TestLoadIarToInventoryPaths() | 173 | public void TestLoadIarToInventoryPaths() |
174 | { | 174 | { |
175 | TestHelper.InMethod(); | 175 | TestHelpers.InMethod(); |
176 | // log4net.Config.XmlConfigurator.Configure(); | 176 | // log4net.Config.XmlConfigurator.Configure(); |
177 | 177 | ||
178 | SerialiserModule serialiserModule = new SerialiserModule(); | 178 | SerialiserModule serialiserModule = new SerialiserModule(); |
179 | InventoryArchiverModule archiverModule = new InventoryArchiverModule(); | 179 | InventoryArchiverModule archiverModule = new InventoryArchiverModule(); |
180 | 180 | ||
181 | // Annoyingly, we have to set up a scene even though inventory loading has nothing to do with a scene | 181 | // Annoyingly, we have to set up a scene even though inventory loading has nothing to do with a scene |
182 | Scene scene = SceneSetupHelpers.SetupScene(); | 182 | Scene scene = SceneHelpers.SetupScene(); |
183 | 183 | ||
184 | SceneSetupHelpers.SetupSceneModules(scene, serialiserModule, archiverModule); | 184 | SceneHelpers.SetupSceneModules(scene, serialiserModule, archiverModule); |
185 | 185 | ||
186 | UserAccountHelpers.CreateUserWithInventory(scene, m_uaMT, "meowfood"); | 186 | UserAccountHelpers.CreateUserWithInventory(scene, m_uaMT, "meowfood"); |
187 | UserAccountHelpers.CreateUserWithInventory(scene, m_uaLL1, "hampshire"); | 187 | UserAccountHelpers.CreateUserWithInventory(scene, m_uaLL1, "hampshire"); |
@@ -217,13 +217,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
217 | [Test] | 217 | [Test] |
218 | public void TestLoadIarPathStartsWithSlash() | 218 | public void TestLoadIarPathStartsWithSlash() |
219 | { | 219 | { |
220 | TestHelper.InMethod(); | 220 | TestHelpers.InMethod(); |
221 | // log4net.Config.XmlConfigurator.Configure(); | 221 | // log4net.Config.XmlConfigurator.Configure(); |
222 | 222 | ||
223 | SerialiserModule serialiserModule = new SerialiserModule(); | 223 | SerialiserModule serialiserModule = new SerialiserModule(); |
224 | InventoryArchiverModule archiverModule = new InventoryArchiverModule(); | 224 | InventoryArchiverModule archiverModule = new InventoryArchiverModule(); |
225 | Scene scene = SceneSetupHelpers.SetupScene(); | 225 | Scene scene = SceneHelpers.SetupScene(); |
226 | SceneSetupHelpers.SetupSceneModules(scene, serialiserModule, archiverModule); | 226 | SceneHelpers.SetupSceneModules(scene, serialiserModule, archiverModule); |
227 | 227 | ||
228 | UserAccountHelpers.CreateUserWithInventory(scene, m_uaMT, "password"); | 228 | UserAccountHelpers.CreateUserWithInventory(scene, m_uaMT, "password"); |
229 | archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "/Objects", "password", m_iarStream); | 229 | archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "/Objects", "password", m_iarStream); |
@@ -238,7 +238,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
238 | [Test] | 238 | [Test] |
239 | public void TestLoadIarPathWithEscapedChars() | 239 | public void TestLoadIarPathWithEscapedChars() |
240 | { | 240 | { |
241 | TestHelper.InMethod(); | 241 | TestHelpers.InMethod(); |
242 | // log4net.Config.XmlConfigurator.Configure(); | 242 | // log4net.Config.XmlConfigurator.Configure(); |
243 | 243 | ||
244 | string itemName = "You & you are a mean/man/"; | 244 | string itemName = "You & you are a mean/man/"; |
@@ -247,8 +247,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
247 | 247 | ||
248 | InventoryArchiverModule archiverModule = new InventoryArchiverModule(); | 248 | InventoryArchiverModule archiverModule = new InventoryArchiverModule(); |
249 | 249 | ||
250 | Scene scene = SceneSetupHelpers.SetupScene(); | 250 | Scene scene = SceneHelpers.SetupScene(); |
251 | SceneSetupHelpers.SetupSceneModules(scene, archiverModule); | 251 | SceneHelpers.SetupSceneModules(scene, archiverModule); |
252 | 252 | ||
253 | // Create user | 253 | // Create user |
254 | string userFirstName = "Jock"; | 254 | string userFirstName = "Jock"; |
@@ -323,10 +323,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
323 | [Test] | 323 | [Test] |
324 | public void TestNewIarPath() | 324 | public void TestNewIarPath() |
325 | { | 325 | { |
326 | TestHelper.InMethod(); | 326 | TestHelpers.InMethod(); |
327 | // log4net.Config.XmlConfigurator.Configure(); | 327 | // log4net.Config.XmlConfigurator.Configure(); |
328 | 328 | ||
329 | Scene scene = SceneSetupHelpers.SetupScene(); | 329 | Scene scene = SceneHelpers.SetupScene(); |
330 | UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene); | 330 | UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene); |
331 | 331 | ||
332 | Dictionary <string, InventoryFolderBase> foldersCreated = new Dictionary<string, InventoryFolderBase>(); | 332 | Dictionary <string, InventoryFolderBase> foldersCreated = new Dictionary<string, InventoryFolderBase>(); |
@@ -390,10 +390,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
390 | [Test] | 390 | [Test] |
391 | public void TestPartExistingIarPath() | 391 | public void TestPartExistingIarPath() |
392 | { | 392 | { |
393 | TestHelper.InMethod(); | 393 | TestHelpers.InMethod(); |
394 | //log4net.Config.XmlConfigurator.Configure(); | 394 | //log4net.Config.XmlConfigurator.Configure(); |
395 | 395 | ||
396 | Scene scene = SceneSetupHelpers.SetupScene(); | 396 | Scene scene = SceneHelpers.SetupScene(); |
397 | UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene); | 397 | UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene); |
398 | 398 | ||
399 | string folder1ExistingName = "a"; | 399 | string folder1ExistingName = "a"; |
@@ -441,10 +441,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
441 | [Test] | 441 | [Test] |
442 | public void TestMergeIarPath() | 442 | public void TestMergeIarPath() |
443 | { | 443 | { |
444 | TestHelper.InMethod(); | 444 | TestHelpers.InMethod(); |
445 | // log4net.Config.XmlConfigurator.Configure(); | 445 | // log4net.Config.XmlConfigurator.Configure(); |
446 | 446 | ||
447 | Scene scene = SceneSetupHelpers.SetupScene(); | 447 | Scene scene = SceneHelpers.SetupScene(); |
448 | UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene); | 448 | UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene); |
449 | 449 | ||
450 | string folder1ExistingName = "a"; | 450 | string folder1ExistingName = "a"; |
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs index 528bc8d..120fd43 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs | |||
@@ -208,9 +208,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer | |||
208 | Array.Copy(copyIDBytes, 0, im.binaryBucket, 1, copyIDBytes.Length); | 208 | Array.Copy(copyIDBytes, 0, im.binaryBucket, 1, copyIDBytes.Length); |
209 | 209 | ||
210 | if (user != null) | 210 | if (user != null) |
211 | { | ||
212 | user.ControllingClient.SendBulkUpdateInventory(folderCopy); | 211 | user.ControllingClient.SendBulkUpdateInventory(folderCopy); |
213 | } | ||
214 | 212 | ||
215 | // HACK!! | 213 | // HACK!! |
216 | im.imSessionID = folderID.Guid; | 214 | im.imSessionID = folderID.Guid; |
@@ -240,9 +238,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer | |||
240 | Array.Copy(copyID.GetBytes(), 0, im.binaryBucket, 1, 16); | 238 | Array.Copy(copyID.GetBytes(), 0, im.binaryBucket, 1, 16); |
241 | 239 | ||
242 | if (user != null) | 240 | if (user != null) |
243 | { | ||
244 | user.ControllingClient.SendBulkUpdateInventory(itemCopy); | 241 | user.ControllingClient.SendBulkUpdateInventory(itemCopy); |
245 | } | ||
246 | 242 | ||
247 | // HACK!! | 243 | // HACK!! |
248 | im.imSessionID = itemID.Guid; | 244 | im.imSessionID = itemID.Guid; |
@@ -280,7 +276,21 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer | |||
280 | else | 276 | else |
281 | { | 277 | { |
282 | if (m_TransferModule != null) | 278 | if (m_TransferModule != null) |
283 | m_TransferModule.SendInstantMessage(im, delegate(bool success) {}); | 279 | m_TransferModule.SendInstantMessage(im, delegate(bool success) { |
280 | // Send BulkUpdateInventory | ||
281 | IInventoryService invService = scene.InventoryService; | ||
282 | UUID inventoryEntityID = new UUID(im.imSessionID); // The inventory item /folder, back from it's trip | ||
283 | |||
284 | InventoryFolderBase folder = new InventoryFolderBase(inventoryEntityID, client.AgentId); | ||
285 | folder = invService.GetFolder(folder); | ||
286 | |||
287 | ScenePresence fromUser = scene.GetScenePresence(new UUID(im.fromAgentID)); | ||
288 | |||
289 | // If the user has left the scene by the time the message comes back then we can't send | ||
290 | // them the update. | ||
291 | if (fromUser != null) | ||
292 | fromUser.ControllingClient.SendBulkUpdateInventory(folder); | ||
293 | }); | ||
284 | } | 294 | } |
285 | } | 295 | } |
286 | else if (im.dialog == (byte) InstantMessageDialog.InventoryDeclined) | 296 | else if (im.dialog == (byte) InstantMessageDialog.InventoryDeclined) |
diff --git a/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs b/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs index c82cfd2..d687e6a 100644 --- a/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs | |||
@@ -196,7 +196,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure | |||
196 | if (!(client.Scene is Scene)) | 196 | if (!(client.Scene is Scene)) |
197 | return; | 197 | return; |
198 | 198 | ||
199 | Scene scene = (Scene)(client.Scene); | 199 | // Scene scene = (Scene)(client.Scene); |
200 | 200 | ||
201 | GridInstantMessage im = null; | 201 | GridInstantMessage im = null; |
202 | if (m_PendingLures.TryGetValue(lureID, out im)) | 202 | if (m_PendingLures.TryGetValue(lureID, out im)) |
diff --git a/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs index 079e1b6..dee0ad4 100644 --- a/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs | |||
@@ -134,7 +134,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Profile | |||
134 | if (!(s is Scene)) | 134 | if (!(s is Scene)) |
135 | return; | 135 | return; |
136 | 136 | ||
137 | Scene scene = (Scene)s; | 137 | // Scene scene = (Scene)s; |
138 | 138 | ||
139 | string profileUrl = String.Empty; | 139 | string profileUrl = String.Empty; |
140 | string aboutText = String.Empty; | 140 | string aboutText = String.Empty; |
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 90f0ca2..faccab2 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs | |||
@@ -209,7 +209,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
209 | sp.TeleportFlags = (TeleportFlags)teleportFlags; | 209 | sp.TeleportFlags = (TeleportFlags)teleportFlags; |
210 | sp.Teleport(position); | 210 | sp.Teleport(position); |
211 | 211 | ||
212 | foreach (SceneObjectGroup grp in sp.Attachments) | 212 | foreach (SceneObjectGroup grp in sp.GetAttachments()) |
213 | sp.Scene.EventManager.TriggerOnScriptChangedEvent(grp.LocalId, (uint)Changed.TELEPORT); | 213 | sp.Scene.EventManager.TriggerOnScriptChangedEvent(grp.LocalId, (uint)Changed.TELEPORT); |
214 | } | 214 | } |
215 | else // Another region possibly in another simulator | 215 | else // Another region possibly in another simulator |
@@ -494,7 +494,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
494 | // Now let's make it officially a child agent | 494 | // Now let's make it officially a child agent |
495 | sp.MakeChildAgent(); | 495 | sp.MakeChildAgent(); |
496 | 496 | ||
497 | sp.Scene.CleanDroppedAttachments(); | 497 | // sp.Scene.CleanDroppedAttachments(); |
498 | 498 | ||
499 | // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone | 499 | // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone |
500 | 500 | ||
@@ -560,11 +560,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
560 | 560 | ||
561 | protected virtual void AgentHasMovedAway(ScenePresence sp, bool logout) | 561 | protected virtual void AgentHasMovedAway(ScenePresence sp, bool logout) |
562 | { | 562 | { |
563 | foreach (SceneObjectGroup sop in sp.Attachments) | 563 | sp.Scene.AttachmentsModule.DeleteAttachmentsFromScene(sp, true); |
564 | { | ||
565 | sop.Scene.DeleteSceneObject(sop, true); | ||
566 | } | ||
567 | sp.Attachments.Clear(); | ||
568 | } | 564 | } |
569 | 565 | ||
570 | protected void KillEntity(Scene scene, uint localID) | 566 | protected void KillEntity(Scene scene, uint localID) |
@@ -1088,10 +1084,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1088 | #endregion | 1084 | #endregion |
1089 | 1085 | ||
1090 | #region Enable Child Agent | 1086 | #region Enable Child Agent |
1087 | |||
1091 | /// <summary> | 1088 | /// <summary> |
1092 | /// This informs a single neighbouring region about agent "avatar". | 1089 | /// This informs a single neighbouring region about agent "avatar". |
1093 | /// Calls an asynchronous method to do so.. so it doesn't lag the sim. | 1090 | /// Calls an asynchronous method to do so.. so it doesn't lag the sim. |
1094 | /// </summary> | 1091 | /// </summary> |
1092 | /// <param name="sp"></param> | ||
1093 | /// <param name="region"></param> | ||
1095 | public void EnableChildAgent(ScenePresence sp, GridRegion region) | 1094 | public void EnableChildAgent(ScenePresence sp, GridRegion region) |
1096 | { | 1095 | { |
1097 | m_log.DebugFormat("[ENTITY TRANSFER]: Enabling child agent in new neighbour {0}", region.RegionName); | 1096 | m_log.DebugFormat("[ENTITY TRANSFER]: Enabling child agent in new neighbour {0}", region.RegionName); |
@@ -1153,6 +1152,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1153 | /// This informs all neighbouring regions about agent "avatar". | 1152 | /// This informs all neighbouring regions about agent "avatar". |
1154 | /// Calls an asynchronous method to do so.. so it doesn't lag the sim. | 1153 | /// Calls an asynchronous method to do so.. so it doesn't lag the sim. |
1155 | /// </summary> | 1154 | /// </summary> |
1155 | /// <param name="sp"></param> | ||
1156 | public void EnableChildAgents(ScenePresence sp) | 1156 | public void EnableChildAgents(ScenePresence sp) |
1157 | { | 1157 | { |
1158 | List<GridRegion> neighbours = new List<GridRegion>(); | 1158 | List<GridRegion> neighbours = new List<GridRegion>(); |
@@ -1340,7 +1340,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1340 | Utils.LongToUInts(reg.RegionHandle, out x, out y); | 1340 | Utils.LongToUInts(reg.RegionHandle, out x, out y); |
1341 | x = x / Constants.RegionSize; | 1341 | x = x / Constants.RegionSize; |
1342 | y = y / Constants.RegionSize; | 1342 | y = y / Constants.RegionSize; |
1343 | m_log.Debug("[ENTITY TRANSFER MODULE]: Starting to inform client about neighbour " + x + ", " + y + "(" + endPoint.ToString() + ")"); | 1343 | m_log.Debug("[ENTITY TRANSFER MODULE]: Starting to inform client about neighbour " + x + ", " + y + "(" + endPoint + ")"); |
1344 | 1344 | ||
1345 | string capsPath = reg.ServerURI + CapsUtil.GetCapsSeedPath(a.CapsPath); | 1345 | string capsPath = reg.ServerURI + CapsUtil.GetCapsSeedPath(a.CapsPath); |
1346 | 1346 | ||
@@ -1786,34 +1786,33 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1786 | 1786 | ||
1787 | protected bool CrossAttachmentsIntoNewRegion(GridRegion destination, ScenePresence sp, bool silent) | 1787 | protected bool CrossAttachmentsIntoNewRegion(GridRegion destination, ScenePresence sp, bool silent) |
1788 | { | 1788 | { |
1789 | List<SceneObjectGroup> m_attachments = sp.Attachments; | 1789 | List<SceneObjectGroup> m_attachments = sp.GetAttachments(); |
1790 | lock (m_attachments) | 1790 | |
1791 | // Validate | ||
1792 | foreach (SceneObjectGroup gobj in m_attachments) | ||
1791 | { | 1793 | { |
1792 | // Validate | 1794 | if (gobj == null || gobj.IsDeleted) |
1793 | foreach (SceneObjectGroup gobj in m_attachments) | 1795 | return false; |
1794 | { | 1796 | } |
1795 | if (gobj == null || gobj.IsDeleted) | ||
1796 | return false; | ||
1797 | } | ||
1798 | 1797 | ||
1799 | foreach (SceneObjectGroup gobj in m_attachments) | 1798 | foreach (SceneObjectGroup gobj in m_attachments) |
1799 | { | ||
1800 | // If the prim group is null then something must have happened to it! | ||
1801 | if (gobj != null) | ||
1800 | { | 1802 | { |
1801 | // If the prim group is null then something must have happened to it! | 1803 | // Set the parent localID to 0 so it transfers over properly. |
1802 | if (gobj != null && gobj.RootPart != null) | 1804 | gobj.RootPart.SetParentLocalId(0); |
1803 | { | 1805 | gobj.AbsolutePosition = gobj.RootPart.AttachedPos; |
1804 | // Set the parent localID to 0 so it transfers over properly. | 1806 | gobj.IsAttachment = false; |
1805 | gobj.RootPart.SetParentLocalId(0); | 1807 | //gobj.RootPart.LastOwnerID = gobj.GetFromAssetID(); |
1806 | gobj.AbsolutePosition = gobj.RootPart.AttachedPos; | 1808 | m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Sending attachment {0} to region {1}", gobj.UUID, destination.RegionName); |
1807 | gobj.RootPart.IsAttachment = false; | 1809 | CrossPrimGroupIntoNewRegion(destination, gobj, silent); |
1808 | //gobj.RootPart.LastOwnerID = gobj.GetFromAssetID(); | ||
1809 | m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Sending attachment {0} to region {1}", gobj.UUID, destination.RegionName); | ||
1810 | CrossPrimGroupIntoNewRegion(destination, gobj, silent); | ||
1811 | } | ||
1812 | } | 1810 | } |
1813 | m_attachments.Clear(); | ||
1814 | |||
1815 | return true; | ||
1816 | } | 1811 | } |
1812 | |||
1813 | sp.ClearAttachments(); | ||
1814 | |||
1815 | return true; | ||
1817 | } | 1816 | } |
1818 | 1817 | ||
1819 | #endregion | 1818 | #endregion |
@@ -1862,7 +1861,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1862 | int i = 0; | 1861 | int i = 0; |
1863 | if (sp.InTransitScriptStates.Count > 0) | 1862 | if (sp.InTransitScriptStates.Count > 0) |
1864 | { | 1863 | { |
1865 | sp.Attachments.ForEach(delegate(SceneObjectGroup sog) | 1864 | List<SceneObjectGroup> attachments = sp.GetAttachments(); |
1865 | |||
1866 | foreach (SceneObjectGroup sog in attachments) | ||
1866 | { | 1867 | { |
1867 | if (i < sp.InTransitScriptStates.Count) | 1868 | if (i < sp.InTransitScriptStates.Count) |
1868 | { | 1869 | { |
@@ -1871,8 +1872,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1871 | sog.ResumeScripts(); | 1872 | sog.ResumeScripts(); |
1872 | } | 1873 | } |
1873 | else | 1874 | else |
1874 | m_log.ErrorFormat("[ENTITY TRANSFER MODULE]: InTransitScriptStates.Count={0} smaller than Attachments.Count={1}", sp.InTransitScriptStates.Count, sp.Attachments.Count); | 1875 | m_log.ErrorFormat( |
1875 | }); | 1876 | "[ENTITY TRANSFER MODULE]: InTransitScriptStates.Count={0} smaller than Attachments.Count={1}", |
1877 | sp.InTransitScriptStates.Count, attachments.Count); | ||
1878 | } | ||
1876 | 1879 | ||
1877 | sp.InTransitScriptStates.Clear(); | 1880 | sp.InTransitScriptStates.Clear(); |
1878 | } | 1881 | } |
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index a98ce85..654e202 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs | |||
@@ -325,7 +325,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
325 | } | 325 | } |
326 | } | 326 | } |
327 | 327 | ||
328 | // This is pethod scoped and will be returned. It will be the | 328 | // This is method scoped and will be returned. It will be the |
329 | // last created asset id | 329 | // last created asset id |
330 | UUID assetID = UUID.Zero; | 330 | UUID assetID = UUID.Zero; |
331 | 331 | ||
@@ -354,9 +354,6 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
354 | CoalescedSceneObjects coa = new CoalescedSceneObjects(UUID.Zero); | 354 | CoalescedSceneObjects coa = new CoalescedSceneObjects(UUID.Zero); |
355 | Dictionary<UUID, Vector3> originalPositions = new Dictionary<UUID, Vector3>(); | 355 | Dictionary<UUID, Vector3> originalPositions = new Dictionary<UUID, Vector3>(); |
356 | 356 | ||
357 | Dictionary<UUID, string> xmlStrings = | ||
358 | new Dictionary<UUID, string>(); | ||
359 | |||
360 | foreach (SceneObjectGroup objectGroup in objlist) | 357 | foreach (SceneObjectGroup objectGroup in objlist) |
361 | { | 358 | { |
362 | Vector3 inventoryStoredPosition = new Vector3 | 359 | Vector3 inventoryStoredPosition = new Vector3 |
@@ -369,12 +366,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
369 | : objectGroup.AbsolutePosition.Y, | 366 | : objectGroup.AbsolutePosition.Y, |
370 | objectGroup.AbsolutePosition.Z); | 367 | objectGroup.AbsolutePosition.Z); |
371 | 368 | ||
372 | Vector3 originalPosition = objectGroup.AbsolutePosition; | 369 | originalPositions[objectGroup.UUID] = objectGroup.AbsolutePosition; |
373 | |||
374 | // Restore attachment data after trip through the sim | ||
375 | if (objectGroup.RootPart.AttachPoint > 0) | ||
376 | inventoryStoredPosition = objectGroup.RootPart.AttachOffset; | ||
377 | objectGroup.RootPart.Shape.State = objectGroup.RootPart.AttachPoint; | ||
378 | 370 | ||
379 | objectGroup.AbsolutePosition = inventoryStoredPosition; | 371 | objectGroup.AbsolutePosition = inventoryStoredPosition; |
380 | 372 | ||
@@ -388,60 +380,159 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
388 | (uint)PermissionMask.Modify); | 380 | (uint)PermissionMask.Modify); |
389 | objectGroup.RootPart.NextOwnerMask |= | 381 | objectGroup.RootPart.NextOwnerMask |= |
390 | (uint)PermissionMask.Move; | 382 | (uint)PermissionMask.Move; |
383 | |||
384 | coa.Add(objectGroup); | ||
385 | } | ||
391 | 386 | ||
392 | string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(objectGroup); | 387 | string itemXml; |
393 | 388 | ||
394 | objectGroup.AbsolutePosition = originalPosition; | 389 | if (objlist.Count > 1) |
390 | itemXml = CoalescedSceneObjectsSerializer.ToXml(coa); | ||
391 | else | ||
392 | itemXml = SceneObjectSerializer.ToOriginalXmlFormat(objlist[0]); | ||
393 | |||
394 | // Restore the position of each group now that it has been stored to inventory. | ||
395 | foreach (SceneObjectGroup objectGroup in objlist) | ||
396 | objectGroup.AbsolutePosition = originalPositions[objectGroup.UUID]; | ||
395 | 397 | ||
396 | xmlStrings[objectGroup.UUID] = sceneObjectXml; | 398 | InventoryItemBase item = CreateItemForObject(action, remoteClient, objlist[0], folderID); |
399 | if (item == null) | ||
400 | return UUID.Zero; | ||
401 | |||
402 | // Can't know creator is the same, so null it in inventory | ||
403 | if (objlist.Count > 1) | ||
404 | { | ||
405 | item.CreatorId = UUID.Zero.ToString(); | ||
406 | item.Flags = (uint)InventoryItemFlags.ObjectHasMultipleItems; | ||
397 | } | 407 | } |
408 | else | ||
409 | { | ||
410 | item.CreatorId = objlist[0].RootPart.CreatorID.ToString(); | ||
411 | item.SaleType = objlist[0].RootPart.ObjectSaleType; | ||
412 | item.SalePrice = objlist[0].RootPart.SalePrice; | ||
413 | } | ||
398 | 414 | ||
399 | string itemXml; | 415 | AssetBase asset = CreateAsset( |
416 | objlist[0].GetPartName(objlist[0].RootPart.LocalId), | ||
417 | objlist[0].GetPartDescription(objlist[0].RootPart.LocalId), | ||
418 | (sbyte)AssetType.Object, | ||
419 | Utils.StringToBytes(itemXml), | ||
420 | objlist[0].OwnerID.ToString()); | ||
421 | m_Scene.AssetService.Store(asset); | ||
422 | |||
423 | item.AssetID = asset.FullID; | ||
424 | assetID = asset.FullID; | ||
400 | 425 | ||
401 | if (objlist.Count > 1) | 426 | if (DeRezAction.SaveToExistingUserInventoryItem == action) |
402 | { | 427 | { |
403 | float minX, minY, minZ; | 428 | m_Scene.InventoryService.UpdateItem(item); |
404 | float maxX, maxY, maxZ; | 429 | } |
430 | else | ||
431 | { | ||
432 | AddPermissions(item, objlist[0], objlist, remoteClient); | ||
405 | 433 | ||
406 | Vector3[] offsets = Scene.GetCombinedBoundingBox(objlist, | 434 | item.CreationDate = Util.UnixTimeSinceEpoch(); |
407 | out minX, out maxX, out minY, out maxY, | 435 | item.Description = asset.Description; |
408 | out minZ, out maxZ); | 436 | item.Name = asset.Name; |
437 | item.AssetType = asset.Type; | ||
409 | 438 | ||
410 | // CreateWrapper | 439 | m_Scene.AddInventoryItem(item); |
411 | XmlDocument itemDoc = new XmlDocument(); | ||
412 | XmlElement root = itemDoc.CreateElement("", "CoalescedObject", ""); | ||
413 | itemDoc.AppendChild(root); | ||
414 | 440 | ||
415 | // Embed the offsets into the group XML | 441 | if (remoteClient != null && item.Owner == remoteClient.AgentId) |
416 | for ( int i = 0 ; i < objlist.Count ; i++ ) | ||
417 | { | 442 | { |
418 | XmlDocument doc = new XmlDocument(); | 443 | remoteClient.SendInventoryItemCreateUpdate(item, 0); |
419 | SceneObjectGroup g = objlist[i]; | 444 | } |
420 | doc.LoadXml(xmlStrings[g.UUID]); | 445 | else |
421 | XmlElement e = (XmlElement)doc.SelectSingleNode("/SceneObjectGroup"); | 446 | { |
422 | e.SetAttribute("offsetx", offsets[i].X.ToString()); | 447 | ScenePresence notifyUser = m_Scene.GetScenePresence(item.Owner); |
423 | e.SetAttribute("offsety", offsets[i].Y.ToString()); | 448 | if (notifyUser != null) |
424 | e.SetAttribute("offsetz", offsets[i].Z.ToString()); | 449 | { |
425 | 450 | notifyUser.ControllingClient.SendInventoryItemCreateUpdate(item, 0); | |
426 | XmlNode objectNode = itemDoc.ImportNode(e, true); | 451 | } |
427 | root.AppendChild(objectNode); | ||
428 | } | 452 | } |
453 | } | ||
454 | |||
455 | // This is a hook to do some per-asset post-processing for subclasses that need that | ||
456 | if (remoteClient != null) | ||
457 | ExportAsset(remoteClient.AgentId, assetID); | ||
458 | |||
459 | return assetID; | ||
460 | } | ||
429 | 461 | ||
430 | float sizeX = maxX - minX; | 462 | protected virtual void ExportAsset(UUID agentID, UUID assetID) |
431 | float sizeY = maxY - minY; | 463 | { |
432 | float sizeZ = maxZ - minZ; | 464 | // nothing to do here |
465 | } | ||
433 | 466 | ||
434 | root.SetAttribute("x", sizeX.ToString()); | 467 | /// <summary> |
435 | root.SetAttribute("y", sizeY.ToString()); | 468 | /// Add relevant permissions for an object to the item. |
436 | root.SetAttribute("z", sizeZ.ToString()); | 469 | /// </summary> |
470 | /// <param name="item"></param> | ||
471 | /// <param name="so"></param> | ||
472 | /// <param name="objsForEffectivePermissions"></param> | ||
473 | /// <param name="remoteClient"></param> | ||
474 | /// <returns></returns> | ||
475 | protected InventoryItemBase AddPermissions( | ||
476 | InventoryItemBase item, SceneObjectGroup so, List<SceneObjectGroup> objsForEffectivePermissions, | ||
477 | IClientAPI remoteClient) | ||
478 | { | ||
479 | uint effectivePerms = (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify | PermissionMask.Move) | 7; | ||
480 | foreach (SceneObjectGroup grp in objsForEffectivePermissions) | ||
481 | effectivePerms &= grp.GetEffectivePermissions(); | ||
482 | effectivePerms |= (uint)PermissionMask.Move; | ||
437 | 483 | ||
438 | itemXml = itemDoc.InnerXml; | 484 | if (remoteClient != null && (remoteClient.AgentId != so.RootPart.OwnerID) && m_Scene.Permissions.PropagatePermissions()) |
485 | { | ||
486 | uint perms = effectivePerms; | ||
487 | uint nextPerms = (perms & 7) << 13; | ||
488 | if ((nextPerms & (uint)PermissionMask.Copy) == 0) | ||
489 | perms &= ~(uint)PermissionMask.Copy; | ||
490 | if ((nextPerms & (uint)PermissionMask.Transfer) == 0) | ||
491 | perms &= ~(uint)PermissionMask.Transfer; | ||
492 | if ((nextPerms & (uint)PermissionMask.Modify) == 0) | ||
493 | perms &= ~(uint)PermissionMask.Modify; | ||
494 | |||
495 | item.BasePermissions = perms & so.RootPart.NextOwnerMask; | ||
496 | item.CurrentPermissions = item.BasePermissions; | ||
497 | item.NextPermissions = perms & so.RootPart.NextOwnerMask; | ||
498 | item.EveryOnePermissions = so.RootPart.EveryoneMask & so.RootPart.NextOwnerMask; | ||
499 | item.GroupPermissions = so.RootPart.GroupMask & so.RootPart.NextOwnerMask; | ||
500 | |||
501 | // Magic number badness. Maybe this deserves an enum. | ||
502 | // bit 4 (16) is the "Slam" bit, it means treat as passed | ||
503 | // and apply next owner perms on rez | ||
504 | item.CurrentPermissions |= 16; // Slam! | ||
439 | } | 505 | } |
440 | else | 506 | else |
441 | { | 507 | { |
442 | itemXml = xmlStrings[objlist[0].UUID]; | 508 | item.BasePermissions = effectivePerms; |
443 | } | 509 | item.CurrentPermissions = effectivePerms; |
510 | item.NextPermissions = so.RootPart.NextOwnerMask & effectivePerms; | ||
511 | item.EveryOnePermissions = so.RootPart.EveryoneMask & effectivePerms; | ||
512 | item.GroupPermissions = so.RootPart.GroupMask & effectivePerms; | ||
444 | 513 | ||
514 | item.CurrentPermissions &= | ||
515 | ((uint)PermissionMask.Copy | | ||
516 | (uint)PermissionMask.Transfer | | ||
517 | (uint)PermissionMask.Modify | | ||
518 | (uint)PermissionMask.Move | | ||
519 | 7); // Preserve folded permissions | ||
520 | } | ||
521 | |||
522 | return item; | ||
523 | } | ||
524 | |||
525 | /// <summary> | ||
526 | /// Create an item using details for the given scene object. | ||
527 | /// </summary> | ||
528 | /// <param name="action"></param> | ||
529 | /// <param name="remoteClient"></param> | ||
530 | /// <param name="so"></param> | ||
531 | /// <param name="folderID"></param> | ||
532 | /// <returns></returns> | ||
533 | protected InventoryItemBase CreateItemForObject( | ||
534 | DeRezAction action, IClientAPI remoteClient, SceneObjectGroup so, UUID folderID) | ||
535 | { | ||
445 | // Get the user info of the item destination | 536 | // Get the user info of the item destination |
446 | // | 537 | // |
447 | UUID userID = UUID.Zero; | 538 | UUID userID = UUID.Zero; |
@@ -453,7 +544,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
453 | // Saving changes requires a local user | 544 | // Saving changes requires a local user |
454 | // | 545 | // |
455 | if (remoteClient == null) | 546 | if (remoteClient == null) |
456 | return UUID.Zero; | 547 | return null; |
457 | 548 | ||
458 | userID = remoteClient.AgentId; | 549 | userID = remoteClient.AgentId; |
459 | } | 550 | } |
@@ -461,13 +552,12 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
461 | { | 552 | { |
462 | // All returns / deletes go to the object owner | 553 | // All returns / deletes go to the object owner |
463 | // | 554 | // |
464 | 555 | userID = so.RootPart.OwnerID; | |
465 | userID = objlist[0].RootPart.OwnerID; | ||
466 | } | 556 | } |
467 | 557 | ||
468 | if (userID == UUID.Zero) // Can't proceed | 558 | if (userID == UUID.Zero) // Can't proceed |
469 | { | 559 | { |
470 | return UUID.Zero; | 560 | return null; |
471 | } | 561 | } |
472 | 562 | ||
473 | // If we're returning someone's item, it goes back to the | 563 | // If we're returning someone's item, it goes back to the |
@@ -475,13 +565,13 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
475 | // Delete is treated like return in this case | 565 | // Delete is treated like return in this case |
476 | // Deleting your own items makes them go to trash | 566 | // Deleting your own items makes them go to trash |
477 | // | 567 | // |
478 | 568 | ||
479 | InventoryFolderBase folder = null; | 569 | InventoryFolderBase folder = null; |
480 | InventoryItemBase item = null; | 570 | InventoryItemBase item = null; |
481 | 571 | ||
482 | if (DeRezAction.SaveToExistingUserInventoryItem == action) | 572 | if (DeRezAction.SaveToExistingUserInventoryItem == action) |
483 | { | 573 | { |
484 | item = new InventoryItemBase(objlist[0].RootPart.FromUserInventoryItemID, userID); | 574 | item = new InventoryItemBase(so.RootPart.FromUserInventoryItemID, userID); |
485 | item = m_Scene.InventoryService.GetItem(item); | 575 | item = m_Scene.InventoryService.GetItem(item); |
486 | 576 | ||
487 | //item = userInfo.RootFolder.FindItem( | 577 | //item = userInfo.RootFolder.FindItem( |
@@ -491,8 +581,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
491 | { | 581 | { |
492 | m_log.DebugFormat( | 582 | m_log.DebugFormat( |
493 | "[AGENT INVENTORY]: Object {0} {1} scheduled for save to inventory has already been deleted.", | 583 | "[AGENT INVENTORY]: Object {0} {1} scheduled for save to inventory has already been deleted.", |
494 | objlist[0].Name, objlist[0].UUID); | 584 | so.Name, so.UUID); |
495 | return UUID.Zero; | 585 | |
586 | return null; | ||
496 | } | 587 | } |
497 | } | 588 | } |
498 | else | 589 | else |
@@ -504,19 +595,17 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
504 | // Deleting someone else's item | 595 | // Deleting someone else's item |
505 | // | 596 | // |
506 | if (remoteClient == null || | 597 | if (remoteClient == null || |
507 | objlist[0].OwnerID != remoteClient.AgentId) | 598 | so.OwnerID != remoteClient.AgentId) |
508 | { | 599 | { |
509 | |||
510 | folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder); | 600 | folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder); |
511 | } | 601 | } |
512 | else | 602 | else |
513 | { | 603 | { |
514 | folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.TrashFolder); | 604 | folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.TrashFolder); |
515 | } | 605 | } |
516 | } | 606 | } |
517 | else if (action == DeRezAction.Return) | 607 | else if (action == DeRezAction.Return) |
518 | { | 608 | { |
519 | |||
520 | // Dump to lost + found unconditionally | 609 | // Dump to lost + found unconditionally |
521 | // | 610 | // |
522 | folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder); | 611 | folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder); |
@@ -532,8 +621,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
532 | } | 621 | } |
533 | else | 622 | else |
534 | { | 623 | { |
535 | if (remoteClient == null || | 624 | if (remoteClient == null || so.OwnerID != remoteClient.AgentId) |
536 | objlist[0].OwnerID != remoteClient.AgentId) | ||
537 | { | 625 | { |
538 | // Taking copy of another person's item. Take to | 626 | // Taking copy of another person's item. Take to |
539 | // Objects folder. | 627 | // Objects folder. |
@@ -554,9 +642,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
554 | // | 642 | // |
555 | if (action == DeRezAction.Take || action == DeRezAction.TakeCopy) | 643 | if (action == DeRezAction.Take || action == DeRezAction.TakeCopy) |
556 | { | 644 | { |
557 | if (objlist[0].RootPart.FromFolderID != UUID.Zero && objlist[0].OwnerID == remoteClient.AgentId) | 645 | if (so.RootPart.FromFolderID != UUID.Zero) |
558 | { | 646 | { |
559 | InventoryFolderBase f = new InventoryFolderBase(objlist[0].RootPart.FromFolderID, userID); | 647 | InventoryFolderBase f = new InventoryFolderBase(so.RootPart.FromFolderID, userID); |
560 | folder = m_Scene.InventoryService.GetFolder(f); | 648 | folder = m_Scene.InventoryService.GetFolder(f); |
561 | } | 649 | } |
562 | } | 650 | } |
@@ -567,380 +655,375 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
567 | 655 | ||
568 | if (folder == null) // Nowhere to put it | 656 | if (folder == null) // Nowhere to put it |
569 | { | 657 | { |
570 | return UUID.Zero; | 658 | return null; |
571 | } | 659 | } |
572 | } | 660 | } |
573 | 661 | ||
574 | item = new InventoryItemBase(); | 662 | item = new InventoryItemBase(); |
575 | // Can't know creator is the same, so null it in inventory | ||
576 | if (objlist.Count > 1) | ||
577 | { | ||
578 | item.CreatorId = UUID.Zero.ToString(); | ||
579 | item.CreatorData = String.Empty; | ||
580 | } | ||
581 | else | ||
582 | { | ||
583 | item.CreatorId = objlist[0].RootPart.CreatorID.ToString(); | ||
584 | item.CreatorData = objlist[0].RootPart.CreatorData; | ||
585 | } | ||
586 | item.ID = UUID.Random(); | 663 | item.ID = UUID.Random(); |
587 | item.InvType = (int)InventoryType.Object; | 664 | item.InvType = (int)InventoryType.Object; |
588 | item.Folder = folder.ID; | 665 | item.Folder = folder.ID; |
589 | item.Owner = userID; | 666 | item.Owner = userID; |
590 | if (objlist.Count > 1) | 667 | } |
668 | |||
669 | return item; | ||
670 | } | ||
671 | |||
672 | public virtual SceneObjectGroup RezObject( | ||
673 | IClientAPI remoteClient, UUID itemID, Vector3 RayEnd, Vector3 RayStart, | ||
674 | UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, | ||
675 | bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment) | ||
676 | { | ||
677 | // m_log.DebugFormat("[INVENTORY ACCESS MODULE]: RezObject for {0}, item {1}", remoteClient.Name, itemID); | ||
678 | InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); | ||
679 | item = m_Scene.InventoryService.GetItem(item); | ||
680 | |||
681 | if (item == null) | ||
682 | { | ||
683 | |||
684 | return null; | ||
685 | } | ||
686 | |||
687 | |||
688 | |||
689 | |||
690 | |||
691 | |||
692 | |||
693 | item.Owner = remoteClient.AgentId; | ||
694 | |||
695 | return RezObject( | ||
696 | remoteClient, item, item.AssetID, | ||
697 | RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection, | ||
698 | RezSelected, RemoveItem, fromTaskID, attachment); | ||
699 | } | ||
700 | |||
701 | public virtual SceneObjectGroup RezObject( | ||
702 | IClientAPI remoteClient, InventoryItemBase item, UUID assetID, Vector3 RayEnd, Vector3 RayStart, | ||
703 | UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, | ||
704 | bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment) | ||
705 | { | ||
706 | AssetBase rezAsset = m_Scene.AssetService.Get(assetID.ToString()); | ||
707 | |||
708 | if (rezAsset == null) | ||
709 | { | ||
710 | if (item != null) | ||
591 | { | 711 | { |
592 | item.Flags = (uint)InventoryItemFlags.ObjectHasMultipleItems; | 712 | m_log.WarnFormat( |
713 | "[InventoryAccessModule]: Could not find asset {0} for item {1} {2} for {3} in RezObject()", | ||
714 | assetID, item.Name, item.ID, remoteClient.Name); | ||
593 | } | 715 | } |
594 | else | 716 | else |
595 | { | 717 | { |
596 | item.SaleType = objlist[0].RootPart.ObjectSaleType; | 718 | m_log.WarnFormat( |
597 | item.SalePrice = objlist[0].RootPart.SalePrice; | 719 | "[InventoryAccessModule]: Could not find asset {0} for {1} in RezObject()", |
720 | assetID, remoteClient.Name); | ||
598 | } | 721 | } |
722 | |||
723 | return null; | ||
599 | } | 724 | } |
600 | 725 | ||
601 | AssetBase asset = CreateAsset( | 726 | SceneObjectGroup group = null; |
602 | objlist[0].GetPartName(objlist[0].RootPart.LocalId), | ||
603 | objlist[0].GetPartDescription(objlist[0].RootPart.LocalId), | ||
604 | (sbyte)AssetType.Object, | ||
605 | Utils.StringToBytes(itemXml), | ||
606 | objlist[0].OwnerID.ToString()); | ||
607 | m_Scene.AssetService.Store(asset); | ||
608 | assetID = asset.FullID; | ||
609 | 727 | ||
610 | if (DeRezAction.SaveToExistingUserInventoryItem == action) | 728 | string xmlData = Utils.BytesToString(rezAsset.Data); |
729 | List<SceneObjectGroup> objlist = | ||
730 | new List<SceneObjectGroup>(); | ||
731 | List<Vector3> veclist = new List<Vector3>(); | ||
732 | byte bRayEndIsIntersection = (byte)(RayEndIsIntersection ? 1 : 0); | ||
733 | Vector3 pos; | ||
734 | |||
735 | XmlDocument doc = new XmlDocument(); | ||
736 | doc.LoadXml(xmlData); | ||
737 | XmlElement e = (XmlElement)doc.SelectSingleNode("/CoalescedObject"); | ||
738 | if (e == null || attachment) // Single | ||
611 | { | 739 | { |
612 | item.AssetID = asset.FullID; | 740 | SceneObjectGroup g = SceneObjectSerializer.FromOriginalXmlFormat(xmlData); |
613 | m_Scene.InventoryService.UpdateItem(item); | 741 | |
742 | objlist.Add(g); | ||
743 | veclist.Add(new Vector3(0, 0, 0)); | ||
744 | |||
745 | float offsetHeight = 0; | ||
746 | pos = m_Scene.GetNewRezLocation( | ||
747 | RayStart, RayEnd, RayTargetID, Quaternion.Identity, | ||
748 | BypassRayCast, bRayEndIsIntersection, true, g.GetAxisAlignedBoundingBox(out offsetHeight), false); | ||
749 | pos.Z += offsetHeight; | ||
614 | } | 750 | } |
615 | else | 751 | else |
616 | { | 752 | { |
617 | item.AssetID = asset.FullID; | 753 | XmlElement coll = (XmlElement)e; |
754 | float bx = Convert.ToSingle(coll.GetAttribute("x")); | ||
755 | float by = Convert.ToSingle(coll.GetAttribute("y")); | ||
756 | float bz = Convert.ToSingle(coll.GetAttribute("z")); | ||
757 | Vector3 bbox = new Vector3(bx, by, bz); | ||
618 | 758 | ||
619 | uint effectivePerms = (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify | PermissionMask.Move) | 7; | 759 | pos = m_Scene.GetNewRezLocation(RayStart, RayEnd, |
620 | foreach (SceneObjectGroup grp in objlist) | 760 | RayTargetID, Quaternion.Identity, |
621 | effectivePerms &= grp.GetEffectivePermissions(); | 761 | BypassRayCast, bRayEndIsIntersection, true, |
622 | effectivePerms |= (uint)PermissionMask.Move; | 762 | bbox, false); |
623 | 763 | ||
624 | if (remoteClient != null && (remoteClient.AgentId != objlist[0].RootPart.OwnerID) && m_Scene.Permissions.PropagatePermissions()) | 764 | pos -= bbox / 2; |
625 | { | 765 | |
626 | uint perms = effectivePerms; | 766 | XmlNodeList groups = e.SelectNodes("SceneObjectGroup"); |
627 | uint nextPerms = (perms & 7) << 13; | 767 | foreach (XmlNode n in groups) |
628 | if ((nextPerms & (uint)PermissionMask.Copy) == 0) | ||
629 | perms &= ~(uint)PermissionMask.Copy; | ||
630 | if ((nextPerms & (uint)PermissionMask.Transfer) == 0) | ||
631 | perms &= ~(uint)PermissionMask.Transfer; | ||
632 | if ((nextPerms & (uint)PermissionMask.Modify) == 0) | ||
633 | perms &= ~(uint)PermissionMask.Modify; | ||
634 | |||
635 | item.BasePermissions = perms & objlist[0].RootPart.NextOwnerMask; | ||
636 | item.CurrentPermissions = item.BasePermissions; | ||
637 | item.NextPermissions = perms & objlist[0].RootPart.NextOwnerMask; | ||
638 | item.EveryOnePermissions = objlist[0].RootPart.EveryoneMask & objlist[0].RootPart.NextOwnerMask; | ||
639 | item.GroupPermissions = objlist[0].RootPart.GroupMask & objlist[0].RootPart.NextOwnerMask; | ||
640 | |||
641 | item.Flags |= (uint)InventoryItemFlags.ObjectSlamPerm; | ||
642 | } | ||
643 | else | ||
644 | { | 768 | { |
645 | item.BasePermissions = effectivePerms; | 769 | SceneObjectGroup g = SceneObjectSerializer.FromOriginalXmlFormat(n.OuterXml); |
646 | item.CurrentPermissions = effectivePerms; | 770 | |
647 | item.NextPermissions = objlist[0].RootPart.NextOwnerMask & effectivePerms; | 771 | objlist.Add(g); |
648 | item.EveryOnePermissions = objlist[0].RootPart.EveryoneMask & effectivePerms; | 772 | XmlElement el = (XmlElement)n; |
649 | item.GroupPermissions = objlist[0].RootPart.GroupMask & effectivePerms; | 773 | |
650 | 774 | string rawX = el.GetAttribute("offsetx"); | |
651 | item.CurrentPermissions &= | 775 | string rawY = el.GetAttribute("offsety"); |
652 | ((uint)PermissionMask.Copy | | 776 | string rawZ = el.GetAttribute("offsetz"); |
653 | (uint)PermissionMask.Transfer | | 777 | // |
654 | (uint)PermissionMask.Modify | | 778 | // m_log.DebugFormat( |
655 | (uint)PermissionMask.Move | | 779 | // "[INVENTORY ACCESS MODULE]: Converting coalesced object {0} offset <{1}, {2}, {3}>", |
656 | 7); // Preserve folded permissions | 780 | // g.Name, rawX, rawY, rawZ); |
781 | |||
782 | float x = Convert.ToSingle(rawX); | ||
783 | float y = Convert.ToSingle(rawY); | ||
784 | float z = Convert.ToSingle(rawZ); | ||
785 | veclist.Add(new Vector3(x, y, z)); | ||
657 | } | 786 | } |
787 | } | ||
658 | 788 | ||
659 | item.CreationDate = Util.UnixTimeSinceEpoch(); | 789 | if (item != null && !DoPreRezWhenFromItem(remoteClient, item, objlist, pos, attachment)) |
660 | item.Description = asset.Description; | 790 | return null; |
661 | item.Name = asset.Name; | ||
662 | item.AssetType = asset.Type; | ||
663 | 791 | ||
664 | m_Scene.AddInventoryItem(item); | 792 | for (int i = 0; i < objlist.Count; i++) |
793 | { | ||
794 | group = objlist[i]; | ||
665 | 795 | ||
666 | if (remoteClient != null && item.Owner == remoteClient.AgentId) | 796 | // Vector3 storedPosition = group.AbsolutePosition; |
797 | if (group.UUID == UUID.Zero) | ||
667 | { | 798 | { |
668 | remoteClient.SendInventoryItemCreateUpdate(item, 0); | 799 | m_log.Debug("[InventoryAccessModule]: Object has UUID.Zero! Position 3"); |
669 | } | 800 | } |
670 | else | 801 | |
802 | if (!attachment) | ||
671 | { | 803 | { |
672 | ScenePresence notifyUser = m_Scene.GetScenePresence(item.Owner); | 804 | // If it's rezzed in world, select it. Much easier to |
673 | if (notifyUser != null) | 805 | // find small items. |
806 | // | ||
807 | foreach (SceneObjectPart part in group.Parts) | ||
674 | { | 808 | { |
675 | notifyUser.ControllingClient.SendInventoryItemCreateUpdate(item, 0); | 809 | part.CreateSelected = true; |
676 | } | 810 | } |
677 | } | 811 | } |
812 | |||
813 | group.ResetIDs(); | ||
814 | |||
815 | if (attachment) | ||
816 | { | ||
817 | group.RootPart.Flags |= PrimFlags.Phantom; | ||
818 | group.IsAttachment = true; | ||
819 | } | ||
820 | |||
821 | // If we're rezzing an attachment then don't ask | ||
822 | // AddNewSceneObject() to update the client since | ||
823 | // we'll be doing that later on. Scheduling more than | ||
824 | // one full update during the attachment | ||
825 | // process causes some clients to fail to display the | ||
826 | // attachment properly. | ||
827 | m_Scene.AddNewSceneObject(group, true, false); | ||
828 | |||
829 | // if attachment we set it's asset id so object updates | ||
830 | // can reflect that, if not, we set it's position in world. | ||
831 | if (!attachment) | ||
832 | { | ||
833 | group.ScheduleGroupForFullUpdate(); | ||
834 | |||
835 | group.AbsolutePosition = pos + veclist[i]; | ||
836 | } | ||
837 | |||
838 | SceneObjectPart rootPart = group.RootPart; | ||
839 | |||
840 | group.SetGroup(remoteClient.ActiveGroupId, remoteClient); | ||
841 | |||
842 | if (!attachment) | ||
843 | { | ||
844 | if (group.RootPart.Shape.PCode == (byte)PCode.Prim) | ||
845 | group.ClearPartAttachmentData(); | ||
846 | |||
847 | // Fire on_rez | ||
848 | group.CreateScriptInstances(0, true, m_Scene.DefaultScriptEngine, 1); | ||
849 | rootPart.ParentGroup.ResumeScripts(); | ||
850 | |||
851 | rootPart.ScheduleFullUpdate(); | ||
852 | } | ||
853 | |||
854 | // m_log.DebugFormat( | ||
855 | // "[InventoryAccessModule]: Rezzed {0} {1} {2} for {3}", | ||
856 | // group.Name, group.LocalId, group.UUID, remoteClient.Name); | ||
678 | } | 857 | } |
679 | 858 | ||
680 | // This is a hook to do some per-asset post-processing for subclasses that need that | 859 | group.SetGroup(remoteClient.ActiveGroupId, remoteClient); |
681 | if (remoteClient != null) | 860 | // TODO: Remove the magic number badness |
682 | ExportAsset(remoteClient.AgentId, assetID); | 861 | if (item != null) |
683 | 862 | DoPostRezWhenFromItem(item, attachment); | |
684 | return assetID; | ||
685 | } | ||
686 | 863 | ||
687 | protected virtual void ExportAsset(UUID agentID, UUID assetID) | 864 | if ((rootPart.OwnerID != item.Owner) || |
688 | { | 865 | (item.CurrentPermissions & 16) != 0 || // Magic number |
689 | // nothing to do here | 866 | (item.Flags & (uint)InventoryItemFlags.ObjectSlamPerm) != 0) |
867 | { | ||
868 | //Need to kill the for sale here | ||
869 | rootPart.ObjectSaleType = 0; | ||
870 | rootPart.SalePrice = 10; | ||
871 | |||
872 | return group; | ||
690 | } | 873 | } |
691 | 874 | ||
692 | /// <summary> | 875 | /// <summary> |
693 | /// Rez an object into the scene from the user's inventory | 876 | /// Do pre-rez processing when the object comes from an item. |
694 | /// </summary> | 877 | /// </summary> |
695 | /// FIXME: It would be really nice if inventory access modules didn't also actually do the work of rezzing | ||
696 | /// things to the scene. The caller should be doing that, I think. | ||
697 | /// <param name="remoteClient"></param> | 878 | /// <param name="remoteClient"></param> |
698 | /// <param name="itemID"></param> | 879 | /// <param name="item"></param> |
699 | /// <param name="RayEnd"></param> | 880 | /// <param name="objlist"></param> |
700 | /// <param name="RayStart"></param> | 881 | /// <param name="pos"></param> |
701 | /// <param name="RayTargetID"></param> | 882 | /// <param name="isAttachment"></param> |
702 | /// <param name="BypassRayCast"></param> | 883 | /// <returns>true if we can processed with rezzing, false if we need to abort</returns> |
703 | /// <param name="RayEndIsIntersection"></param> | 884 | private bool DoPreRezWhenFromItem( |
704 | /// <param name="RezSelected"></param> | 885 | IClientAPI remoteClient, InventoryItemBase item, List<SceneObjectGroup> objlist, Vector3 pos, bool isAttachment) |
705 | /// <param name="RemoveItem"></param> | ||
706 | /// <param name="fromTaskID"></param> | ||
707 | /// <param name="attachment"></param> | ||
708 | /// <returns>The SceneObjectGroup rezzed or null if rez was unsuccessful.</returns> | ||
709 | public virtual SceneObjectGroup RezObject(IClientAPI remoteClient, UUID itemID, Vector3 RayEnd, Vector3 RayStart, | ||
710 | UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, | ||
711 | bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment) | ||
712 | { | 886 | { |
713 | // Work out position details | 887 | UUID fromUserInventoryItemId = UUID.Zero; |
714 | byte bRayEndIsIntersection = (byte)0; | ||
715 | 888 | ||
716 | if (RayEndIsIntersection) | 889 | // If we have permission to copy then link the rezzed object back to the user inventory |
890 | // item that it came from. This allows us to enable 'save object to inventory' | ||
891 | if (!m_Scene.Permissions.BypassPermissions()) | ||
717 | { | 892 | { |
718 | bRayEndIsIntersection = (byte)1; | 893 | if ((item.CurrentPermissions & (uint)PermissionMask.Copy) |
894 | == (uint)PermissionMask.Copy && (item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0) | ||
895 | { | ||
896 | fromUserInventoryItemId = item.ID; | ||
897 | } | ||
719 | } | 898 | } |
720 | else | 899 | else |
721 | { | 900 | { |
722 | bRayEndIsIntersection = (byte)0; | 901 | if ((item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0) |
902 | { | ||
903 | // Brave new fullperm world | ||
904 | fromUserInventoryItemId = item.ID; | ||
905 | } | ||
723 | } | 906 | } |
724 | 907 | ||
725 | Vector3 scale = new Vector3(0.5f, 0.5f, 0.5f); | 908 | int primcount = 0; |
909 | foreach (SceneObjectGroup g in objlist) | ||
910 | primcount += g.PrimCount; | ||
726 | 911 | ||
912 | if (!m_Scene.Permissions.CanRezObject( | ||
913 | primcount, remoteClient.AgentId, pos) | ||
914 | && !isAttachment) | ||
915 | { | ||
916 | // The client operates in no fail mode. It will | ||
917 | // have already removed the item from the folder | ||
918 | // if it's no copy. | ||
919 | // Put it back if it's not an attachment | ||
920 | // | ||
921 | if (((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) && (!isAttachment)) | ||
922 | remoteClient.SendBulkUpdateInventory(item); | ||
727 | 923 | ||
728 | Vector3 pos = m_Scene.GetNewRezLocation( | 924 | return false; |
729 | RayStart, RayEnd, RayTargetID, Quaternion.Identity, | 925 | } |
730 | BypassRayCast, bRayEndIsIntersection, true, scale, false); | ||
731 | |||
732 | // Rez object | ||
733 | InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); | ||
734 | item = m_Scene.InventoryService.GetItem(item); | ||
735 | 926 | ||
736 | if (item != null) | 927 | for (int i = 0; i < objlist.Count; i++) |
737 | { | 928 | { |
738 | if (item.ID == UUID.Zero) | 929 | SceneObjectGroup so = objlist[i]; |
930 | SceneObjectPart rootPart = so.RootPart; | ||
931 | |||
932 | // Since renaming the item in the inventory does not | ||
933 | // affect the name stored in the serialization, transfer | ||
934 | // the correct name from the inventory to the | ||
935 | // object itself before we rez. | ||
936 | // | ||
937 | // Only do these for the first object if we are rezzing a coalescence. | ||
938 | if (i == 0) | ||
739 | { | 939 | { |
740 | m_log.Debug("[InventoryAccessModule]: Inventory object has UUID.Zero! Position 1"); | 940 | rootPart.Name = item.Name; |
941 | rootPart.Description = item.Description; | ||
942 | rootPart.ObjectSaleType = item.SaleType; | ||
943 | rootPart.SalePrice = item.SalePrice; | ||
741 | } | 944 | } |
742 | item.Owner = remoteClient.AgentId; | ||
743 | |||
744 | AssetBase rezAsset = m_Scene.AssetService.Get(item.AssetID.ToString()); | ||
745 | |||
746 | SceneObjectGroup group = null; | ||
747 | 945 | ||
748 | if (rezAsset != null) | 946 | rootPart.FromFolderID = item.Folder; |
947 | |||
948 | if ((rootPart.OwnerID != item.Owner) || | ||
949 | (item.CurrentPermissions & 16) != 0) | ||
749 | { | 950 | { |
750 | UUID itemId = UUID.Zero; | 951 | //Need to kill the for sale here |
751 | 952 | rootPart.ObjectSaleType = 0; | |
752 | // If we have permission to copy then link the rezzed object back to the user inventory | 953 | rootPart.SalePrice = 10; |
753 | // item that it came from. This allows us to enable 'save object to inventory' | 954 | |
754 | if (!m_Scene.Permissions.BypassPermissions()) | 955 | if (m_Scene.Permissions.PropagatePermissions()) |
755 | { | ||
756 | if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == (uint)PermissionMask.Copy && (item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0) | ||
757 | { | ||
758 | itemId = item.ID; | ||
759 | } | ||
760 | } | ||
761 | else | ||
762 | { | 956 | { |
763 | if ((item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0) | 957 | foreach (SceneObjectPart part in so.Parts) |
764 | { | 958 | { |
765 | // Brave new fullperm world | 959 | if ((item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0) |
766 | itemId = item.ID; | 960 | { |
961 | part.EveryoneMask = item.EveryOnePermissions; | ||
962 | part.NextOwnerMask = item.NextPermissions; | ||
963 | } | ||
964 | part.GroupMask = 0; // DO NOT propagate here | ||
767 | } | 965 | } |
966 | |||
967 | so.ApplyNextOwnerPermissions(); | ||
768 | } | 968 | } |
969 | } | ||
970 | |||
971 | foreach (SceneObjectPart part in so.Parts) | ||
972 | { | ||
973 | part.FromUserInventoryItemID = fromUserInventoryItemId; | ||
769 | 974 | ||
770 | if (item.ID == UUID.Zero) | 975 | if ((part.OwnerID != item.Owner) || |
771 | { | 976 | (item.CurrentPermissions & 16) != 0) |
772 | m_log.Debug("[InventoryAccessModule]: Inventory object has UUID.Zero! Position 2"); | ||
773 | } | ||
774 | |||
775 | string xmlData = Utils.BytesToString(rezAsset.Data); | ||
776 | List<SceneObjectGroup> objlist = | ||
777 | new List<SceneObjectGroup>(); | ||
778 | List<Vector3> veclist = new List<Vector3>(); | ||
779 | |||
780 | XmlDocument doc = new XmlDocument(); | ||
781 | doc.LoadXml(xmlData); | ||
782 | XmlElement e = (XmlElement)doc.SelectSingleNode("/CoalescedObject"); | ||
783 | if (e == null || attachment) // Single | ||
784 | { | 977 | { |
785 | SceneObjectGroup g = | 978 | part.LastOwnerID = part.OwnerID; |
786 | SceneObjectSerializer.FromOriginalXmlFormat( | 979 | part.OwnerID = item.Owner; |
787 | itemId, xmlData); | 980 | part.Inventory.ChangeInventoryOwner(item.Owner); |
788 | objlist.Add(g); | 981 | part.GroupMask = 0; // DO NOT propagate here |
789 | veclist.Add(new Vector3(0, 0, 0)); | ||
790 | |||
791 | float offsetHeight = 0; | ||
792 | pos = m_Scene.GetNewRezLocation( | ||
793 | RayStart, RayEnd, RayTargetID, Quaternion.Identity, | ||
794 | BypassRayCast, bRayEndIsIntersection, true, g.GetAxisAlignedBoundingBox(out offsetHeight), false); | ||
795 | pos.Z += offsetHeight; | ||
796 | } | 982 | } |
797 | else | 983 | part.EveryoneMask = item.EveryOnePermissions; |
798 | { | 984 | part.NextOwnerMask = item.NextPermissions; |
799 | XmlElement coll = (XmlElement)e; | 985 | } |
800 | float bx = Convert.ToSingle(coll.GetAttribute("x")); | 986 | |
801 | float by = Convert.ToSingle(coll.GetAttribute("y")); | 987 | rootPart.TrimPermissions(); |
802 | float bz = Convert.ToSingle(coll.GetAttribute("z")); | ||
803 | Vector3 bbox = new Vector3(bx, by, bz); | ||
804 | |||
805 | pos = m_Scene.GetNewRezLocation(RayStart, RayEnd, | ||
806 | RayTargetID, Quaternion.Identity, | ||
807 | BypassRayCast, bRayEndIsIntersection, true, | ||
808 | bbox, false); | ||
809 | |||
810 | pos -= bbox / 2; | ||
811 | 988 | ||
812 | XmlNodeList groups = e.SelectNodes("SceneObjectGroup"); | 989 | if (isAttachment) |
813 | foreach (XmlNode n in groups) | 990 | so.SetFromItemID(item.ID); |
814 | { | 991 | } |
815 | SceneObjectGroup g = | ||
816 | SceneObjectSerializer.FromOriginalXmlFormat( | ||
817 | itemId, n.OuterXml); | ||
818 | objlist.Add(g); | ||
819 | XmlElement el = (XmlElement)n; | ||
820 | float x = Convert.ToSingle(el.GetAttribute("offsetx")); | ||
821 | float y = Convert.ToSingle(el.GetAttribute("offsety")); | ||
822 | float z = Convert.ToSingle(el.GetAttribute("offsetz")); | ||
823 | veclist.Add(new Vector3(x, y, z)); | ||
824 | } | ||
825 | } | ||
826 | 992 | ||
827 | int primcount = 0; | 993 | return true; |
828 | foreach (SceneObjectGroup g in objlist) | 994 | } |
829 | primcount += g.PrimCount; | ||
830 | 995 | ||
831 | if (!m_Scene.Permissions.CanRezObject( | 996 | /// <summary> |
832 | primcount, remoteClient.AgentId, pos) | 997 | /// Do post-rez processing when the object comes from an item. |
833 | && !attachment) | 998 | /// </summary> |
999 | /// <param name="item"></param> | ||
1000 | /// <param name="isAttachment"></param> | ||
1001 | private void DoPostRezWhenFromItem(InventoryItemBase item, bool isAttachment) | ||
1002 | { | ||
1003 | if (!m_Scene.Permissions.BypassPermissions()) | ||
1004 | { | ||
1005 | if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) | ||
1006 | { | ||
1007 | // If this is done on attachments, no | ||
1008 | // copy ones will be lost, so avoid it | ||
1009 | // | ||
1010 | if (!isAttachment) | ||
834 | { | 1011 | { |
835 | // The client operates in no fail mode. It will | 1012 | List<UUID> uuids = new List<UUID>(); |
836 | // have already removed the item from the folder | 1013 | uuids.Add(item.ID); |
837 | // if it's no copy. | 1014 | m_Scene.InventoryService.DeleteItems(item.Owner, uuids); |
838 | // Put it back if it's not an attachment | ||
839 | // | ||
840 | if (((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) && (!attachment)) | ||
841 | remoteClient.SendBulkUpdateInventory(item); | ||
842 | return null; | ||
843 | } | 1015 | } |
844 | 1016 | } | |
845 | for (int i = 0 ; i < objlist.Count ; i++ ) | 1017 | } |
846 | { | 1018 | if ((rootPart.OwnerID != item.Owner) || |
847 | group = objlist[i]; | ||
848 | |||
849 | Vector3 storedPosition = group.AbsolutePosition; | ||
850 | if (group.UUID == UUID.Zero) | ||
851 | { | ||
852 | m_log.Debug("[InventoryAccessModule]: Inventory object has UUID.Zero! Position 3"); | ||
853 | } | ||
854 | group.RootPart.FromFolderID = item.Folder; | ||
855 | |||
856 | // If it's rezzed in world, select it. Much easier to | ||
857 | // find small items. | ||
858 | // | ||
859 | if (!attachment) | ||
860 | { | ||
861 | group.RootPart.CreateSelected = true; | ||
862 | foreach (SceneObjectPart child in group.Parts) | ||
863 | child.CreateSelected = true; | ||
864 | } | ||
865 | |||
866 | group.ResetIDs(); | ||
867 | |||
868 | if (attachment) | ||
869 | { | ||
870 | group.RootPart.Flags |= PrimFlags.Phantom; | ||
871 | group.RootPart.IsAttachment = true; | ||
872 | |||
873 | // If we're rezzing an attachment then don't ask | ||
874 | // AddNewSceneObject() to update the client since | ||
875 | // we'll be doing that later on. Scheduling more | ||
876 | // than one full update during the attachment | ||
877 | // process causes some clients to fail to display | ||
878 | // the attachment properly. | ||
879 | // Also, don't persist attachments. | ||
880 | m_Scene.AddNewSceneObject(group, false, false); | ||
881 | } | ||
882 | else | ||
883 | { | ||
884 | m_Scene.AddNewSceneObject(group, true, false); | ||
885 | } | ||
886 | |||
887 | // if attachment we set it's asset id so object updates | ||
888 | // can reflect that, if not, we set it's position in world. | ||
889 | if (!attachment) | ||
890 | { | ||
891 | group.ScheduleGroupForFullUpdate(); | ||
892 | |||
893 | group.AbsolutePosition = pos + veclist[i]; | ||
894 | } | ||
895 | else | ||
896 | { | ||
897 | group.SetFromItemID(itemID); | ||
898 | } | ||
899 | |||
900 | SceneObjectPart rootPart = null; | ||
901 | |||
902 | try | ||
903 | { | ||
904 | rootPart = group.GetChildPart(group.UUID); | ||
905 | } | ||
906 | catch (NullReferenceException) | ||
907 | { | ||
908 | string isAttachment = ""; | ||
909 | |||
910 | if (attachment) | ||
911 | isAttachment = " Object was an attachment"; | ||
912 | |||
913 | m_log.Error("[AGENT INVENTORY]: Error rezzing ItemID: " + itemID + " object has no rootpart." + isAttachment); | ||
914 | } | ||
915 | |||
916 | // Since renaming the item in the inventory does not | ||
917 | // affect the name stored in the serialization, transfer | ||
918 | // the correct name from the inventory to the | ||
919 | // object itself before we rez. | ||
920 | // On coalesced objects, do the first one | ||
921 | if (((item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0) || i == 0) | ||
922 | { | ||
923 | rootPart.Name = item.Name; | ||
924 | rootPart.Description = item.Description; | ||
925 | } | ||
926 | if ((item.Flags & (uint)InventoryItemFlags.ObjectSlamSale) != 0) | ||
927 | { | ||
928 | rootPart.ObjectSaleType = item.SaleType; | ||
929 | rootPart.SalePrice = item.SalePrice; | ||
930 | } | ||
931 | |||
932 | group.SetGroup(remoteClient.ActiveGroupId, remoteClient); | ||
933 | // TODO: Remove the magic number badness | ||
934 | |||
935 | if ((rootPart.OwnerID != item.Owner) || | ||
936 | (item.CurrentPermissions & 16) != 0 || // Magic number | 1019 | (item.CurrentPermissions & 16) != 0 || // Magic number |
937 | (item.Flags & (uint)InventoryItemFlags.ObjectSlamPerm) != 0) | 1020 | (item.Flags & (uint)InventoryItemFlags.ObjectSlamPerm) != 0) |
938 | { | 1021 | { |
939 | //Need to kill the for sale here | 1022 | //Need to kill the for sale here |
940 | rootPart.ObjectSaleType = 0; | 1023 | rootPart.ObjectSaleType = 0; |
941 | rootPart.SalePrice = 10; | 1024 | rootPart.SalePrice = 10; |
942 | 1025 | ||
943 | if (m_Scene.Permissions.PropagatePermissions()) | 1026 | if (m_Scene.Permissions.PropagatePermissions()) |
944 | { | 1027 | { |
945 | foreach (SceneObjectPart part in group.Parts) | 1028 | foreach (SceneObjectPart part in group.Parts) |
946 | { | 1029 | { |
@@ -965,58 +1048,15 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
965 | group.ApplyNextOwnerPermissions(); | 1048 | group.ApplyNextOwnerPermissions(); |
966 | } | 1049 | } |
967 | } | 1050 | } |
968 | 1051 | foreach (SceneObjectPart part in group.Parts) | |
969 | foreach (SceneObjectPart part in group.Parts) | 1052 | { |
970 | { | 1053 | if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteEveryone) != 0) |
971 | if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteEveryone) != 0) | 1054 | part.EveryoneMask = item.EveryOnePermissions; |
972 | part.EveryoneMask = item.EveryOnePermissions; | 1055 | if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteNextOwner) != 0) |
973 | if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteNextOwner) != 0) | 1056 | part.NextOwnerMask = item.NextPermissions; |
974 | part.NextOwnerMask = item.NextPermissions; | 1057 | if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteGroup) != 0) |
975 | if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteGroup) != 0) | 1058 | part.GroupMask = item.GroupPermissions; |
976 | part.GroupMask = item.GroupPermissions; | ||
977 | } | ||
978 | |||
979 | rootPart.TrimPermissions(); | ||
980 | |||
981 | if (!attachment) | ||
982 | { | ||
983 | if (group.RootPart.Shape.PCode == (byte)PCode.Prim) | ||
984 | { | ||
985 | // Save attachment data | ||
986 | group.RootPart.AttachPoint = group.RootPart.Shape.State; | ||
987 | group.RootPart.AttachOffset = storedPosition; | ||
988 | |||
989 | group.ClearPartAttachmentData(); | ||
990 | } | ||
991 | |||
992 | // Fire on_rez | ||
993 | group.CreateScriptInstances(0, true, m_Scene.DefaultScriptEngine, 1); | ||
994 | rootPart.ParentGroup.ResumeScripts(); | ||
995 | |||
996 | rootPart.ScheduleFullUpdate(); | ||
997 | } | ||
998 | } | ||
999 | |||
1000 | if (!m_Scene.Permissions.BypassPermissions()) | ||
1001 | { | ||
1002 | if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) | ||
1003 | { | ||
1004 | // If this is done on attachments, no | ||
1005 | // copy ones will be lost, so avoid it | ||
1006 | // | ||
1007 | if (!attachment) | ||
1008 | { | ||
1009 | List<UUID> uuids = new List<UUID>(); | ||
1010 | uuids.Add(item.ID); | ||
1011 | m_Scene.InventoryService.DeleteItems(item.Owner, uuids); | ||
1012 | } | ||
1013 | } | ||
1014 | } | ||
1015 | } | ||
1016 | return group; | ||
1017 | } | 1059 | } |
1018 | |||
1019 | return null; | ||
1020 | } | 1060 | } |
1021 | 1061 | ||
1022 | protected void AddUserData(SceneObjectGroup sog) | 1062 | protected void AddUserData(SceneObjectGroup sog) |
@@ -1033,11 +1073,14 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
1033 | public virtual bool CanGetAgentInventoryItem(IClientAPI remoteClient, UUID itemID, UUID requestID) | 1073 | public virtual bool CanGetAgentInventoryItem(IClientAPI remoteClient, UUID itemID, UUID requestID) |
1034 | { | 1074 | { |
1035 | InventoryItemBase assetRequestItem = GetItem(remoteClient.AgentId, itemID); | 1075 | InventoryItemBase assetRequestItem = GetItem(remoteClient.AgentId, itemID); |
1076 | |||
1036 | if (assetRequestItem == null) | 1077 | if (assetRequestItem == null) |
1037 | { | 1078 | { |
1038 | ILibraryService lib = m_Scene.RequestModuleInterface<ILibraryService>(); | 1079 | ILibraryService lib = m_Scene.RequestModuleInterface<ILibraryService>(); |
1080 | |||
1039 | if (lib != null) | 1081 | if (lib != null) |
1040 | assetRequestItem = lib.LibraryRootFolder.FindItem(itemID); | 1082 | assetRequestItem = lib.LibraryRootFolder.FindItem(itemID); |
1083 | |||
1041 | if (assetRequestItem == null) | 1084 | if (assetRequestItem == null) |
1042 | return false; | 1085 | return false; |
1043 | } | 1086 | } |
@@ -1068,6 +1111,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
1068 | m_log.WarnFormat( | 1111 | m_log.WarnFormat( |
1069 | "[CLIENT]: {0} requested asset {1} from item {2} but this does not match item's asset {3}", | 1112 | "[CLIENT]: {0} requested asset {1} from item {2} but this does not match item's asset {3}", |
1070 | Name, requestID, itemID, assetRequestItem.AssetID); | 1113 | Name, requestID, itemID, assetRequestItem.AssetID); |
1114 | |||
1071 | return false; | 1115 | return false; |
1072 | } | 1116 | } |
1073 | 1117 | ||
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs index 733ad25..e74310c 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs | |||
@@ -65,8 +65,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests | |||
65 | config.AddConfig("Modules"); | 65 | config.AddConfig("Modules"); |
66 | config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule"); | 66 | config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule"); |
67 | 67 | ||
68 | m_scene = SceneSetupHelpers.SetupScene(); | 68 | m_scene = SceneHelpers.SetupScene(); |
69 | SceneSetupHelpers.SetupSceneModules(m_scene, config, m_iam); | 69 | SceneHelpers.SetupSceneModules(m_scene, config, m_iam); |
70 | 70 | ||
71 | // Create user | 71 | // Create user |
72 | string userFirstName = "Jock"; | 72 | string userFirstName = "Jock"; |
@@ -82,14 +82,14 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests | |||
82 | [Test] | 82 | [Test] |
83 | public void TestRezCoalescedObject() | 83 | public void TestRezCoalescedObject() |
84 | { | 84 | { |
85 | TestHelper.InMethod(); | 85 | TestHelpers.InMethod(); |
86 | // log4net.Config.XmlConfigurator.Configure(); | 86 | // log4net.Config.XmlConfigurator.Configure(); |
87 | 87 | ||
88 | // Create asset | 88 | // Create asset |
89 | SceneObjectGroup object1 = SceneSetupHelpers.CreateSceneObject(1, m_userId, "Object1", 0x20); | 89 | SceneObjectGroup object1 = SceneHelpers.CreateSceneObject(1, m_userId, "Object1", 0x20); |
90 | object1.AbsolutePosition = new Vector3(15, 30, 45); | 90 | object1.AbsolutePosition = new Vector3(15, 30, 45); |
91 | 91 | ||
92 | SceneObjectGroup object2 = SceneSetupHelpers.CreateSceneObject(1, m_userId, "Object2", 0x40); | 92 | SceneObjectGroup object2 = SceneHelpers.CreateSceneObject(1, m_userId, "Object2", 0x40); |
93 | object2.AbsolutePosition = new Vector3(25, 50, 75); | 93 | object2.AbsolutePosition = new Vector3(25, 50, 75); |
94 | 94 | ||
95 | CoalescedSceneObjects coa = new CoalescedSceneObjects(m_userId, object1, object2); | 95 | CoalescedSceneObjects coa = new CoalescedSceneObjects(m_userId, object1, object2); |
@@ -138,11 +138,11 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests | |||
138 | [Test] | 138 | [Test] |
139 | public void TestRezObject() | 139 | public void TestRezObject() |
140 | { | 140 | { |
141 | TestHelper.InMethod(); | 141 | TestHelpers.InMethod(); |
142 | // log4net.Config.XmlConfigurator.Configure(); | 142 | // log4net.Config.XmlConfigurator.Configure(); |
143 | 143 | ||
144 | // Create asset | 144 | // Create asset |
145 | SceneObjectGroup object1 = SceneSetupHelpers.CreateSceneObject(1, m_userId, "My Little Dog Object", 0x40); | 145 | SceneObjectGroup object1 = SceneHelpers.CreateSceneObject(1, m_userId, "My Little Dog Object", 0x40); |
146 | 146 | ||
147 | UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060"); | 147 | UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060"); |
148 | AssetBase asset1 = AssetHelpers.CreateAsset(asset1Id, object1); | 148 | AssetBase asset1 = AssetHelpers.CreateAsset(asset1Id, object1); |
diff --git a/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs b/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs index d570608..3155ce7 100644 --- a/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs +++ b/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs | |||
@@ -185,6 +185,7 @@ namespace OpenSim.Region.CoreModules.Framework.Library | |||
185 | archread = new InventoryArchiveReadRequest(m_MockScene, uinfo, "/", iarFileName, false); | 185 | archread = new InventoryArchiveReadRequest(m_MockScene, uinfo, "/", iarFileName, false); |
186 | archread.Execute(); | 186 | archread.Execute(); |
187 | } | 187 | } |
188 | |||
188 | foreach (InventoryNodeBase node in nodes) | 189 | foreach (InventoryNodeBase node in nodes) |
189 | FixPerms(node); | 190 | FixPerms(node); |
190 | } | 191 | } |
@@ -197,18 +198,19 @@ namespace OpenSim.Region.CoreModules.Framework.Library | |||
197 | archread.Close(); | 198 | archread.Close(); |
198 | } | 199 | } |
199 | } | 200 | } |
200 | |||
201 | } | 201 | } |
202 | 202 | ||
203 | private void FixPerms(InventoryNodeBase node) | 203 | private void FixPerms(InventoryNodeBase node) |
204 | { | 204 | { |
205 | m_log.DebugFormat("[LIBRARY MODULE]: Fixing perms for {0} {1}", node.Name, node.ID); | ||
206 | |||
205 | if (node is InventoryItemBase) | 207 | if (node is InventoryItemBase) |
206 | { | 208 | { |
207 | InventoryItemBase item = (InventoryItemBase)node; | 209 | InventoryItemBase item = (InventoryItemBase)node; |
208 | item.BasePermissions = 0x7FFFFFFF; | 210 | item.BasePermissions = (uint)PermissionMask.All; |
209 | item.EveryOnePermissions = 0x7FFFFFFF; | 211 | item.EveryOnePermissions = (uint)PermissionMask.All - (uint)PermissionMask.Modify; |
210 | item.CurrentPermissions = 0x7FFFFFFF; | 212 | item.CurrentPermissions = (uint)PermissionMask.All; |
211 | item.NextPermissions = 0x7FFFFFFF; | 213 | item.NextPermissions = (uint)PermissionMask.All; |
212 | } | 214 | } |
213 | } | 215 | } |
214 | 216 | ||
diff --git a/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs b/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs index f15f8f6..b5cbcbb 100644 --- a/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs +++ b/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs | |||
@@ -68,7 +68,6 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring | |||
68 | { | 68 | { |
69 | m_scene = scene; | 69 | m_scene = scene; |
70 | 70 | ||
71 | |||
72 | m_scene.AddCommand(this, "monitor report", | 71 | m_scene.AddCommand(this, "monitor report", |
73 | "monitor report", | 72 | "monitor report", |
74 | "Returns a variety of statistics about the current region and/or simulator", | 73 | "Returns a variety of statistics about the current region and/or simulator", |
diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 27eb178..b0b35e4 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs | |||
@@ -186,7 +186,6 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
186 | } | 186 | } |
187 | } | 187 | } |
188 | 188 | ||
189 | |||
190 | private string[] GetUserNames(UUID uuid) | 189 | private string[] GetUserNames(UUID uuid) |
191 | { | 190 | { |
192 | string[] returnstring = new string[2]; | 191 | string[] returnstring = new string[2]; |
@@ -292,6 +291,25 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
292 | return userID.ToString(); | 291 | return userID.ToString(); |
293 | } | 292 | } |
294 | 293 | ||
294 | public void AddUser(UUID uuid, string first, string last) | ||
295 | { | ||
296 | if (m_UserCache.ContainsKey(uuid)) | ||
297 | return; | ||
298 | |||
299 | UserData user = new UserData(); | ||
300 | user.Id = uuid; | ||
301 | user.FirstName = first; | ||
302 | user.LastName = last; | ||
303 | // user.ProfileURL = we should initialize this to the default | ||
304 | |||
305 | AddUserInternal(user); | ||
306 | } | ||
307 | |||
308 | public void AddUser(UUID uuid, string first, string last, string profileURL) | ||
309 | { | ||
310 | AddUser(uuid, profileURL + ";" + first + " " + last); | ||
311 | } | ||
312 | |||
295 | public void AddUser(UUID id, string creatorData) | 313 | public void AddUser(UUID id, string creatorData) |
296 | { | 314 | { |
297 | if (m_UserCache.ContainsKey(id)) | 315 | if (m_UserCache.ContainsKey(id)) |
@@ -299,18 +317,17 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
299 | 317 | ||
300 | // m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, craetorData {1}", id, creatorData); | 318 | // m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, craetorData {1}", id, creatorData); |
301 | 319 | ||
302 | UserData user = new UserData(); | ||
303 | user.Id = id; | ||
304 | UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, id); | 320 | UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, id); |
305 | 321 | ||
306 | if (account != null) | 322 | if (account != null) |
307 | { | 323 | { |
308 | user.FirstName = account.FirstName; | 324 | AddUser(id, account.FirstName, account.LastName); |
309 | user.LastName = account.LastName; | ||
310 | // user.ProfileURL = we should initialize this to the default | ||
311 | } | 325 | } |
312 | else | 326 | else |
313 | { | 327 | { |
328 | UserData user = new UserData(); | ||
329 | user.Id = id; | ||
330 | |||
314 | if (creatorData != null && creatorData != string.Empty) | 331 | if (creatorData != null && creatorData != string.Empty) |
315 | { | 332 | { |
316 | //creatorData = <endpoint>;<name> | 333 | //creatorData = <endpoint>;<name> |
@@ -338,17 +355,19 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
338 | user.FirstName = "Unknown"; | 355 | user.FirstName = "Unknown"; |
339 | user.LastName = "User"; | 356 | user.LastName = "User"; |
340 | } | 357 | } |
341 | } | ||
342 | 358 | ||
343 | lock (m_UserCache) | 359 | AddUserInternal(user); |
344 | m_UserCache[id] = user; | 360 | } |
345 | |||
346 | //m_log.DebugFormat("[USER MANAGEMENT MODULE]: Added user {0} {1} {2} {3}", user.Id, user.FirstName, user.LastName, user.HomeURL); | ||
347 | } | 361 | } |
348 | 362 | ||
349 | public void AddUser(UUID uuid, string first, string last, string profileURL) | 363 | void AddUserInternal(UserData user) |
350 | { | 364 | { |
351 | AddUser(uuid, profileURL + ";" + first + " " + last); | 365 | lock (m_UserCache) |
366 | m_UserCache[user.Id] = user; | ||
367 | |||
368 | m_log.DebugFormat( | ||
369 | "[USER MANAGEMENT MODULE]: Added user {0} {1} {2} {3}", | ||
370 | user.Id, user.FirstName, user.LastName, user.HomeURL); | ||
352 | } | 371 | } |
353 | 372 | ||
354 | //public void AddUser(UUID uuid, string userData) | 373 | //public void AddUser(UUID uuid, string userData) |
diff --git a/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs b/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs index d647e71..b20a875 100644 --- a/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs | |||
@@ -282,6 +282,93 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm | |||
282 | } | 282 | } |
283 | } | 283 | } |
284 | 284 | ||
285 | /// <summary> | ||
286 | /// Delivers the message to a scene entity. | ||
287 | /// </summary> | ||
288 | /// <param name='target'> | ||
289 | /// Target. | ||
290 | /// </param> | ||
291 | /// <param name='channel'> | ||
292 | /// Channel. | ||
293 | /// </param> | ||
294 | /// <param name='name'> | ||
295 | /// Name. | ||
296 | /// </param> | ||
297 | /// <param name='id'> | ||
298 | /// Identifier. | ||
299 | /// </param> | ||
300 | /// <param name='msg'> | ||
301 | /// Message. | ||
302 | /// </param> | ||
303 | public bool DeliverMessageTo(UUID target, int channel, Vector3 pos, string name, UUID id, string msg, out string error) | ||
304 | { | ||
305 | error = null; | ||
306 | // Is id an avatar? | ||
307 | ScenePresence sp = m_scene.GetScenePresence(target); | ||
308 | |||
309 | if (sp != null) | ||
310 | { | ||
311 | // Send message to avatar | ||
312 | if (channel == 0) | ||
313 | { | ||
314 | m_scene.SimChatBroadcast(Utils.StringToBytes(msg), ChatTypeEnum.Owner, 0, pos, name, id, false); | ||
315 | } | ||
316 | |||
317 | List<SceneObjectGroup> attachments = sp.GetAttachments(); | ||
318 | |||
319 | if (attachments.Count == 0) | ||
320 | return true; | ||
321 | |||
322 | // Get uuid of attachments | ||
323 | List<UUID> targets = new List<UUID>(); | ||
324 | foreach (SceneObjectGroup sog in attachments) | ||
325 | { | ||
326 | targets.Add(sog.UUID); | ||
327 | } | ||
328 | |||
329 | // Need to check each attachment | ||
330 | foreach (ListenerInfo li in m_listenerManager.GetListeners(UUID.Zero, channel, name, id, msg)) | ||
331 | { | ||
332 | if (li.GetHostID().Equals(id)) | ||
333 | continue; | ||
334 | |||
335 | if (m_scene.GetSceneObjectPart(li.GetHostID()) == null) | ||
336 | continue; | ||
337 | |||
338 | if (targets.Contains(li.GetHostID())) | ||
339 | QueueMessage(new ListenerInfo(li, name, id, msg)); | ||
340 | } | ||
341 | |||
342 | return true; | ||
343 | } | ||
344 | |||
345 | // Need to toss an error here | ||
346 | if (channel == 0) | ||
347 | { | ||
348 | error = "Cannot use llRegionSayTo to message objects on channel 0"; | ||
349 | return false; | ||
350 | } | ||
351 | |||
352 | foreach (ListenerInfo li in m_listenerManager.GetListeners(UUID.Zero, channel, name, id, msg)) | ||
353 | { | ||
354 | // Dont process if this message is from yourself! | ||
355 | if (li.GetHostID().Equals(id)) | ||
356 | continue; | ||
357 | |||
358 | SceneObjectPart sPart = m_scene.GetSceneObjectPart(li.GetHostID()); | ||
359 | if (sPart == null) | ||
360 | continue; | ||
361 | |||
362 | if ( li.GetHostID().Equals(target)) | ||
363 | { | ||
364 | QueueMessage(new ListenerInfo(li, name, id, msg)); | ||
365 | break; | ||
366 | } | ||
367 | } | ||
368 | |||
369 | return true; | ||
370 | } | ||
371 | |||
285 | protected void QueueMessage(ListenerInfo li) | 372 | protected void QueueMessage(ListenerInfo li) |
286 | { | 373 | { |
287 | lock (m_pending.SyncRoot) | 374 | lock (m_pending.SyncRoot) |
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/MapImage/MapImageServiceInConnectorModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/MapImage/MapImageServiceInConnectorModule.cs index b570155..e5af1f4 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsIn/MapImage/MapImageServiceInConnectorModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/MapImage/MapImageServiceInConnectorModule.cs | |||
@@ -48,7 +48,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.MapImage | |||
48 | private static bool m_Enabled = false; | 48 | private static bool m_Enabled = false; |
49 | 49 | ||
50 | private IConfigSource m_Config; | 50 | private IConfigSource m_Config; |
51 | bool m_Registered = false; | ||
52 | 51 | ||
53 | #region IRegionModule interface | 52 | #region IRegionModule interface |
54 | 53 | ||
@@ -64,9 +63,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.MapImage | |||
64 | m_log.Info("[MAP SERVICE IN CONNECTOR]: MapImage Service In Connector enabled"); | 63 | m_log.Info("[MAP SERVICE IN CONNECTOR]: MapImage Service In Connector enabled"); |
65 | new MapGetServiceConnector(m_Config, MainServer.Instance, "MapImageService"); | 64 | new MapGetServiceConnector(m_Config, MainServer.Instance, "MapImageService"); |
66 | } | 65 | } |
67 | |||
68 | } | 66 | } |
69 | |||
70 | } | 67 | } |
71 | 68 | ||
72 | public void PostInitialise() | 69 | public void PostInitialise() |
@@ -106,6 +103,5 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.MapImage | |||
106 | } | 103 | } |
107 | 104 | ||
108 | #endregion | 105 | #endregion |
109 | |||
110 | } | 106 | } |
111 | } | 107 | } |
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs index 51d1d59..cc5d061 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs | |||
@@ -129,15 +129,18 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset | |||
129 | m_Cache = null; | 129 | m_Cache = null; |
130 | } | 130 | } |
131 | 131 | ||
132 | m_log.InfoFormat("[LOCAL ASSET SERVICES CONNECTOR]: Enabled local assets for region {0}", scene.RegionInfo.RegionName); | 132 | m_log.DebugFormat( |
133 | "[LOCAL ASSET SERVICES CONNECTOR]: Enabled connector for region {0}", scene.RegionInfo.RegionName); | ||
133 | 134 | ||
134 | if (m_Cache != null) | 135 | if (m_Cache != null) |
135 | { | 136 | { |
136 | m_log.InfoFormat("[LOCAL ASSET SERVICES CONNECTOR]: Enabled asset caching for region {0}", scene.RegionInfo.RegionName); | 137 | m_log.DebugFormat( |
138 | "[LOCAL ASSET SERVICES CONNECTOR]: Enabled asset caching for region {0}", | ||
139 | scene.RegionInfo.RegionName); | ||
137 | } | 140 | } |
138 | else | 141 | else |
139 | { | 142 | { |
140 | // Short-circuit directly to storage layer | 143 | // Short-circuit directly to storage layer. This ends up storing temporary and local assets. |
141 | // | 144 | // |
142 | scene.UnregisterModuleInterface<IAssetService>(this); | 145 | scene.UnregisterModuleInterface<IAssetService>(this); |
143 | scene.RegisterModuleInterface<IAssetService>(m_AssetService); | 146 | scene.RegisterModuleInterface<IAssetService>(m_AssetService); |
@@ -246,9 +249,21 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset | |||
246 | m_Cache.Cache(asset); | 249 | m_Cache.Cache(asset); |
247 | 250 | ||
248 | if (asset.Temporary || asset.Local) | 251 | if (asset.Temporary || asset.Local) |
252 | { | ||
253 | // m_log.DebugFormat( | ||
254 | // "[LOCAL ASSET SERVICE CONNECTOR]: Returning asset {0} {1} without querying database since status Temporary = {2}, Local = {3}", | ||
255 | // asset.Name, asset.ID, asset.Temporary, asset.Local); | ||
256 | |||
249 | return asset.ID; | 257 | return asset.ID; |
250 | 258 | } | |
251 | return m_AssetService.Store(asset); | 259 | else |
260 | { | ||
261 | // m_log.DebugFormat( | ||
262 | // "[LOCAL ASSET SERVICE CONNECTOR]: Passing {0} {1} on to asset service for storage, status Temporary = {2}, Local = {3}", | ||
263 | // asset.Name, asset.ID, asset.Temporary, asset.Local); | ||
264 | |||
265 | return m_AssetService.Store(asset); | ||
266 | } | ||
252 | } | 267 | } |
253 | 268 | ||
254 | public bool UpdateContent(string id, byte[] data) | 269 | public bool UpdateContent(string id, byte[] data) |
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/LocalAuthorizationServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/LocalAuthorizationServiceConnector.cs index 85a1ac3..18a7177 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/LocalAuthorizationServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/LocalAuthorizationServiceConnector.cs | |||
@@ -39,8 +39,7 @@ using OpenMetaverse; | |||
39 | 39 | ||
40 | namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Authorization | 40 | namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Authorization |
41 | { | 41 | { |
42 | public class LocalAuthorizationServicesConnector : | 42 | public class LocalAuthorizationServicesConnector : ISharedRegionModule, IAuthorizationService |
43 | ISharedRegionModule, IAuthorizationService | ||
44 | { | 43 | { |
45 | private static readonly ILog m_log = | 44 | private static readonly ILog m_log = |
46 | LogManager.GetLogger( | 45 | LogManager.GetLogger( |
@@ -127,15 +126,15 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Authorization | |||
127 | if (!m_Enabled) | 126 | if (!m_Enabled) |
128 | return; | 127 | return; |
129 | 128 | ||
130 | m_log.InfoFormat("[AUTHORIZATION CONNECTOR]: Enabled local authorization for region {0}", scene.RegionInfo.RegionName); | 129 | m_log.InfoFormat( |
131 | 130 | "[AUTHORIZATION CONNECTOR]: Enabled local authorization for region {0}", | |
132 | 131 | scene.RegionInfo.RegionName); | |
133 | } | 132 | } |
134 | 133 | ||
135 | public bool IsAuthorizedForRegion(string userID, string regionID, out string message) | 134 | public bool IsAuthorizedForRegion( |
135 | string userID, string firstName, string lastName, string regionID, out string message) | ||
136 | { | 136 | { |
137 | return m_AuthorizationService.IsAuthorizedForRegion(userID, regionID, out message); | 137 | return m_AuthorizationService.IsAuthorizedForRegion(userID, firstName, lastName, regionID, out message); |
138 | } | 138 | } |
139 | |||
140 | } | 139 | } |
141 | } | 140 | } \ No newline at end of file |
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/RemoteAuthorizationServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/RemoteAuthorizationServiceConnector.cs index 66994fa..003324f 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/RemoteAuthorizationServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/RemoteAuthorizationServiceConnector.cs | |||
@@ -117,9 +117,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Authorization | |||
117 | 117 | ||
118 | } | 118 | } |
119 | 119 | ||
120 | public bool IsAuthorizedForRegion(string userID, string regionID, out string message) | 120 | public bool IsAuthorizedForRegion( |
121 | string userID, string firstName, string lastName, string regionID, out string message) | ||
121 | { | 122 | { |
122 | m_log.InfoFormat("[REMOTE AUTHORIZATION CONNECTOR]: IsAuthorizedForRegion checking {0} for region {1}", userID, regionID); | 123 | m_log.InfoFormat( |
124 | "[REMOTE AUTHORIZATION CONNECTOR]: IsAuthorizedForRegion checking {0} for region {1}", userID, regionID); | ||
123 | 125 | ||
124 | bool isAuthorized = true; | 126 | bool isAuthorized = true; |
125 | message = String.Empty; | 127 | message = String.Empty; |
@@ -140,17 +142,19 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Authorization | |||
140 | if (scene != null) | 142 | if (scene != null) |
141 | { | 143 | { |
142 | UserAccount account = scene.UserAccountService.GetUserAccount(UUID.Zero, new UUID(userID)); | 144 | UserAccount account = scene.UserAccountService.GetUserAccount(UUID.Zero, new UUID(userID)); |
143 | isAuthorized = IsAuthorizedForRegion(userID, account.FirstName, account.LastName, | 145 | |
144 | account.Email, scene.RegionInfo.RegionName, regionID, out message); | 146 | isAuthorized |
147 | = IsAuthorizedForRegion( | ||
148 | userID, firstName, lastName, account.Email, scene.RegionInfo.RegionName, regionID, out message); | ||
145 | } | 149 | } |
146 | else | 150 | else |
147 | { | 151 | { |
148 | m_log.ErrorFormat("[REMOTE AUTHORIZATION CONNECTOR] IsAuthorizedForRegion, can't find scene to match region id of {0} ",regionID); | 152 | m_log.ErrorFormat( |
153 | "[REMOTE AUTHORIZATION CONNECTOR] IsAuthorizedForRegion, can't find scene to match region id of {0}", | ||
154 | regionID); | ||
149 | } | 155 | } |
150 | 156 | ||
151 | |||
152 | return isAuthorized; | 157 | return isAuthorized; |
153 | |||
154 | } | 158 | } |
155 | } | 159 | } |
156 | } | 160 | } \ No newline at end of file |
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs index 150a4d5..cd7d6bc 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs | |||
@@ -55,19 +55,19 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests | |||
55 | config.Configs["Modules"].Set("GridServices", "LocalGridServicesConnector"); | 55 | config.Configs["Modules"].Set("GridServices", "LocalGridServicesConnector"); |
56 | config.Configs["GridService"].Set("LocalServiceModule", "OpenSim.Services.GridService.dll:GridService"); | 56 | config.Configs["GridService"].Set("LocalServiceModule", "OpenSim.Services.GridService.dll:GridService"); |
57 | config.Configs["GridService"].Set("StorageProvider", "OpenSim.Data.Null.dll"); | 57 | config.Configs["GridService"].Set("StorageProvider", "OpenSim.Data.Null.dll"); |
58 | config.Configs["GridService"].Set("Region_Test_Region_1", "DefaultRegion"); | 58 | config.Configs["GridService"].Set("Region_Test_Region_1", "DefaultRegion"); |
59 | config.Configs["GridService"].Set("Region_Test_Region_2", "FallbackRegion"); | 59 | config.Configs["GridService"].Set("Region_Test_Region_2", "FallbackRegion"); |
60 | config.Configs["GridService"].Set("Region_Test_Region_3", "FallbackRegion"); | 60 | config.Configs["GridService"].Set("Region_Test_Region_3", "FallbackRegion"); |
61 | config.Configs["GridService"].Set("Region_Other_Region_4", "FallbackRegion"); | 61 | config.Configs["GridService"].Set("Region_Other_Region_4", "FallbackRegion"); |
62 | 62 | ||
63 | m_LocalConnector = new LocalGridServicesConnector(config); | 63 | m_LocalConnector = new LocalGridServicesConnector(config); |
64 | } | 64 | } |
65 | 65 | ||
66 | /// <summary> | 66 | /// <summary> |
67 | /// Test saving a V0.2 OpenSim Region Archive. | 67 | /// Test region registration. |
68 | /// </summary> | 68 | /// </summary> |
69 | [Test] | 69 | [Test] |
70 | public void TestRegisterRegionV0_2() | 70 | public void TestRegisterRegion() |
71 | { | 71 | { |
72 | SetUp(); | 72 | SetUp(); |
73 | 73 | ||
@@ -123,11 +123,14 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests | |||
123 | m_LocalConnector.RegisterRegion(UUID.Zero, r1); | 123 | m_LocalConnector.RegisterRegion(UUID.Zero, r1); |
124 | 124 | ||
125 | GridRegion result = m_LocalConnector.GetRegionByName(UUID.Zero, "Test"); | 125 | GridRegion result = m_LocalConnector.GetRegionByName(UUID.Zero, "Test"); |
126 | Assert.IsNull(result, "Retrieved GetRegionByName \"Test\" is not null"); | ||
127 | |||
128 | result = m_LocalConnector.GetRegionByName(UUID.Zero, "Test Region 1"); | ||
126 | Assert.IsNotNull(result, "Retrieved GetRegionByName is null"); | 129 | Assert.IsNotNull(result, "Retrieved GetRegionByName is null"); |
127 | Assert.That(result.RegionName, Is.EqualTo("Test Region 1"), "Retrieved region's name does not match"); | 130 | Assert.That(result.RegionName, Is.EqualTo("Test Region 1"), "Retrieved region's name does not match"); |
128 | 131 | ||
129 | m_LocalConnector.RegisterRegion(UUID.Zero, r2); | 132 | m_LocalConnector.RegisterRegion(UUID.Zero, r2); |
130 | m_LocalConnector.RegisterRegion(UUID.Zero, r3); | 133 | m_LocalConnector.RegisterRegion(UUID.Zero, r3); |
131 | m_LocalConnector.RegisterRegion(UUID.Zero, r4); | 134 | m_LocalConnector.RegisterRegion(UUID.Zero, r4); |
132 | 135 | ||
133 | result = m_LocalConnector.GetRegionByUUID(UUID.Zero, new UUID(1)); | 136 | result = m_LocalConnector.GetRegionByUUID(UUID.Zero, new UUID(1)); |
@@ -152,38 +155,38 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests | |||
152 | Assert.IsNotNull(results, "Retrieved GetRegionRange collection is null"); | 155 | Assert.IsNotNull(results, "Retrieved GetRegionRange collection is null"); |
153 | Assert.That(results.Count, Is.EqualTo(2), "Retrieved neighbour collection is not the number expected"); | 156 | Assert.That(results.Count, Is.EqualTo(2), "Retrieved neighbour collection is not the number expected"); |
154 | 157 | ||
155 | results = m_LocalConnector.GetDefaultRegions(UUID.Zero); | 158 | results = m_LocalConnector.GetDefaultRegions(UUID.Zero); |
156 | Assert.IsNotNull(results, "Retrieved GetDefaultRegions collection is null"); | 159 | Assert.IsNotNull(results, "Retrieved GetDefaultRegions collection is null"); |
157 | Assert.That(results.Count, Is.EqualTo(1), "Retrieved default regions collection has not the expected size"); | 160 | Assert.That(results.Count, Is.EqualTo(1), "Retrieved default regions collection has not the expected size"); |
158 | Assert.That(results[0].RegionID, Is.EqualTo(new UUID(1)), "Retrieved default region's UUID does not match"); | 161 | Assert.That(results[0].RegionID, Is.EqualTo(new UUID(1)), "Retrieved default region's UUID does not match"); |
159 | 162 | ||
160 | results = m_LocalConnector.GetFallbackRegions(UUID.Zero, r1.RegionLocX, r1.RegionLocY); | 163 | results = m_LocalConnector.GetFallbackRegions(UUID.Zero, r1.RegionLocX, r1.RegionLocY); |
161 | Assert.IsNotNull(results, "Retrieved GetFallbackRegions collection for region 1 is null"); | 164 | Assert.IsNotNull(results, "Retrieved GetFallbackRegions collection for region 1 is null"); |
162 | Assert.That(results.Count, Is.EqualTo(3), "Retrieved fallback regions collection for region 1 has not the expected size"); | 165 | Assert.That(results.Count, Is.EqualTo(3), "Retrieved fallback regions collection for region 1 has not the expected size"); |
163 | Assert.That(results[0].RegionID, Is.EqualTo(new UUID(2)), "Retrieved fallback regions for default region are not in the expected order 2-4-3"); | 166 | Assert.That(results[0].RegionID, Is.EqualTo(new UUID(2)), "Retrieved fallback regions for default region are not in the expected order 2-4-3"); |
164 | Assert.That(results[1].RegionID, Is.EqualTo(new UUID(4)), "Retrieved fallback regions for default region are not in the expected order 2-4-3"); | 167 | Assert.That(results[1].RegionID, Is.EqualTo(new UUID(4)), "Retrieved fallback regions for default region are not in the expected order 2-4-3"); |
165 | Assert.That(results[2].RegionID, Is.EqualTo(new UUID(3)), "Retrieved fallback regions for default region are not in the expected order 2-4-3"); | 168 | Assert.That(results[2].RegionID, Is.EqualTo(new UUID(3)), "Retrieved fallback regions for default region are not in the expected order 2-4-3"); |
166 | 169 | ||
167 | results = m_LocalConnector.GetFallbackRegions(UUID.Zero, r2.RegionLocX, r2.RegionLocY); | 170 | results = m_LocalConnector.GetFallbackRegions(UUID.Zero, r2.RegionLocX, r2.RegionLocY); |
168 | Assert.IsNotNull(results, "Retrieved GetFallbackRegions collection for region 2 is null"); | 171 | Assert.IsNotNull(results, "Retrieved GetFallbackRegions collection for region 2 is null"); |
169 | Assert.That(results.Count, Is.EqualTo(3), "Retrieved fallback regions collection for region 2 has not the expected size"); | 172 | Assert.That(results.Count, Is.EqualTo(3), "Retrieved fallback regions collection for region 2 has not the expected size"); |
170 | Assert.That(results[0].RegionID, Is.EqualTo(new UUID(2)), "Retrieved fallback regions are not in the expected order 2-4-3"); | 173 | Assert.That(results[0].RegionID, Is.EqualTo(new UUID(2)), "Retrieved fallback regions are not in the expected order 2-4-3"); |
171 | Assert.That(results[1].RegionID, Is.EqualTo(new UUID(4)), "Retrieved fallback regions are not in the expected order 2-4-3"); | 174 | Assert.That(results[1].RegionID, Is.EqualTo(new UUID(4)), "Retrieved fallback regions are not in the expected order 2-4-3"); |
172 | Assert.That(results[2].RegionID, Is.EqualTo(new UUID(3)), "Retrieved fallback regions are not in the expected order 2-4-3"); | 175 | Assert.That(results[2].RegionID, Is.EqualTo(new UUID(3)), "Retrieved fallback regions are not in the expected order 2-4-3"); |
173 | 176 | ||
174 | results = m_LocalConnector.GetFallbackRegions(UUID.Zero, r3.RegionLocX, r3.RegionLocY); | 177 | results = m_LocalConnector.GetFallbackRegions(UUID.Zero, r3.RegionLocX, r3.RegionLocY); |
175 | Assert.IsNotNull(results, "Retrieved GetFallbackRegions collection for region 3 is null"); | 178 | Assert.IsNotNull(results, "Retrieved GetFallbackRegions collection for region 3 is null"); |
176 | Assert.That(results.Count, Is.EqualTo(3), "Retrieved fallback regions collection for region 3 has not the expected size"); | 179 | Assert.That(results.Count, Is.EqualTo(3), "Retrieved fallback regions collection for region 3 has not the expected size"); |
177 | Assert.That(results[0].RegionID, Is.EqualTo(new UUID(3)), "Retrieved fallback regions are not in the expected order 3-4-2"); | 180 | Assert.That(results[0].RegionID, Is.EqualTo(new UUID(3)), "Retrieved fallback regions are not in the expected order 3-4-2"); |
178 | Assert.That(results[1].RegionID, Is.EqualTo(new UUID(4)), "Retrieved fallback regions are not in the expected order 3-4-2"); | 181 | Assert.That(results[1].RegionID, Is.EqualTo(new UUID(4)), "Retrieved fallback regions are not in the expected order 3-4-2"); |
179 | Assert.That(results[2].RegionID, Is.EqualTo(new UUID(2)), "Retrieved fallback regions are not in the expected order 3-4-2"); | 182 | Assert.That(results[2].RegionID, Is.EqualTo(new UUID(2)), "Retrieved fallback regions are not in the expected order 3-4-2"); |
180 | 183 | ||
181 | results = m_LocalConnector.GetFallbackRegions(UUID.Zero, r4.RegionLocX, r4.RegionLocY); | 184 | results = m_LocalConnector.GetFallbackRegions(UUID.Zero, r4.RegionLocX, r4.RegionLocY); |
182 | Assert.IsNotNull(results, "Retrieved GetFallbackRegions collection for region 4 is null"); | 185 | Assert.IsNotNull(results, "Retrieved GetFallbackRegions collection for region 4 is null"); |
183 | Assert.That(results.Count, Is.EqualTo(3), "Retrieved fallback regions collection for region 4 has not the expected size"); | 186 | Assert.That(results.Count, Is.EqualTo(3), "Retrieved fallback regions collection for region 4 has not the expected size"); |
184 | Assert.That(results[0].RegionID, Is.EqualTo(new UUID(4)), "Retrieved fallback regions are not in the expected order 4-3-2"); | 187 | Assert.That(results[0].RegionID, Is.EqualTo(new UUID(4)), "Retrieved fallback regions are not in the expected order 4-3-2"); |
185 | Assert.That(results[1].RegionID, Is.EqualTo(new UUID(3)), "Retrieved fallback regions are not in the expected order 4-3-2"); | 188 | Assert.That(results[1].RegionID, Is.EqualTo(new UUID(3)), "Retrieved fallback regions are not in the expected order 4-3-2"); |
186 | Assert.That(results[2].RegionID, Is.EqualTo(new UUID(2)), "Retrieved fallback regions are not in the expected order 4-3-2"); | 189 | Assert.That(results[2].RegionID, Is.EqualTo(new UUID(2)), "Retrieved fallback regions are not in the expected order 4-3-2"); |
187 | 190 | ||
188 | results = m_LocalConnector.GetHyperlinks(UUID.Zero); | 191 | results = m_LocalConnector.GetHyperlinks(UUID.Zero); |
189 | Assert.IsNotNull(results, "Retrieved GetHyperlinks list is null"); | 192 | Assert.IsNotNull(results, "Retrieved GetHyperlinks list is null"); |
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/ActivityDetector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/ActivityDetector.cs index 6543845..4cf62ec 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/ActivityDetector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/ActivityDetector.cs | |||
@@ -66,7 +66,10 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.GridUser | |||
66 | public void OnMakeRootAgent(ScenePresence sp) | 66 | public void OnMakeRootAgent(ScenePresence sp) |
67 | { | 67 | { |
68 | // m_log.DebugFormat("[ACTIVITY DETECTOR]: Detected root presence {0} in {1}", sp.UUID, sp.Scene.RegionInfo.RegionName); | 68 | // m_log.DebugFormat("[ACTIVITY DETECTOR]: Detected root presence {0} in {1}", sp.UUID, sp.Scene.RegionInfo.RegionName); |
69 | m_GridUserService.SetLastPosition(sp.UUID.ToString(), UUID.Zero, sp.Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat); | 69 | |
70 | if (sp.PresenceType != PresenceType.Npc) | ||
71 | m_GridUserService.SetLastPosition( | ||
72 | sp.UUID.ToString(), UUID.Zero, sp.Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat); | ||
70 | } | 73 | } |
71 | 74 | ||
72 | public void OnNewClient(IClientAPI client) | 75 | public void OnNewClient(IClientAPI client) |
@@ -93,7 +96,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.GridUser | |||
93 | lookat = ((ScenePresence)sp).Lookat; | 96 | lookat = ((ScenePresence)sp).Lookat; |
94 | } | 97 | } |
95 | } | 98 | } |
96 | m_log.DebugFormat("[ACTIVITY DETECTOR]: Detected client logout {0} in {1}", client.AgentId, client.Scene.RegionInfo.RegionName); | 99 | |
100 | // m_log.DebugFormat("[ACTIVITY DETECTOR]: Detected client logout {0} in {1}", client.AgentId, client.Scene.RegionInfo.RegionName); | ||
97 | m_GridUserService.LoggedOut(client.AgentId.ToString(), client.SessionId, client.Scene.RegionInfo.RegionID, position, lookat); | 101 | m_GridUserService.LoggedOut(client.AgentId.ToString(), client.SessionId, client.Scene.RegionInfo.RegionID, position, lookat); |
98 | } | 102 | } |
99 | 103 | ||
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs index 698fd56..72ae3363 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs | |||
@@ -211,11 +211,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory | |||
211 | return; | 211 | return; |
212 | } | 212 | } |
213 | } | 213 | } |
214 | else | 214 | // else |
215 | { | 215 | // { |
216 | m_log.DebugFormat("[HG INVENTORY CONNECTOR]: User {0} does not have InventoryServerURI. OH NOES!", userID); | 216 | // m_log.DebugFormat("[HG INVENTORY CONNECTOR]: User {0} does not have InventoryServerURI. OH NOES!", userID); |
217 | return; | 217 | // return; |
218 | } | 218 | // } |
219 | } | 219 | } |
220 | } | 220 | } |
221 | if (sp == null) | 221 | if (sp == null) |
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs index 0c57618..65e39c0 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs | |||
@@ -280,7 +280,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory | |||
280 | { | 280 | { |
281 | // m_log.DebugFormat("[LOCAL INVENTORY SERVICES CONNECTOR]: Requesting inventory item {0}", item.ID); | 281 | // m_log.DebugFormat("[LOCAL INVENTORY SERVICES CONNECTOR]: Requesting inventory item {0}", item.ID); |
282 | 282 | ||
283 | UUID requestedItemId = item.ID; | 283 | // UUID requestedItemId = item.ID; |
284 | 284 | ||
285 | item = m_InventoryService.GetItem(item); | 285 | item = m_InventoryService.GetItem(item); |
286 | 286 | ||
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs index e224670..6d3ace9 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs | |||
@@ -61,7 +61,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage | |||
61 | private bool m_enabled = false; | 61 | private bool m_enabled = false; |
62 | private IMapImageService m_MapService; | 62 | private IMapImageService m_MapService; |
63 | 63 | ||
64 | private string m_serverUrl = String.Empty; | ||
65 | private Dictionary<UUID, Scene> m_scenes = new Dictionary<UUID, Scene>(); | 64 | private Dictionary<UUID, Scene> m_scenes = new Dictionary<UUID, Scene>(); |
66 | 65 | ||
67 | private int m_refreshtime = 0; | 66 | private int m_refreshtime = 0; |
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs index fa5b873..e2e383f 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs | |||
@@ -39,7 +39,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence | |||
39 | { | 39 | { |
40 | public class PresenceDetector | 40 | public class PresenceDetector |
41 | { | 41 | { |
42 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 42 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
43 | 43 | ||
44 | private IPresenceService m_PresenceService; | 44 | private IPresenceService m_PresenceService; |
45 | private Scene m_aScene; | 45 | private Scene m_aScene; |
@@ -94,7 +94,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence | |||
94 | } | 94 | } |
95 | } | 95 | } |
96 | 96 | ||
97 | m_log.DebugFormat("[PRESENCE DETECTOR]: Detected client logout {0} in {1}", client.AgentId, client.Scene.RegionInfo.RegionName); | 97 | // m_log.DebugFormat("[PRESENCE DETECTOR]: Detected client logout {0} in {1}", client.AgentId, client.Scene.RegionInfo.RegionName); |
98 | m_PresenceService.LogoutAgent(client.SessionId); | 98 | m_PresenceService.LogoutAgent(client.SessionId); |
99 | } | 99 | } |
100 | 100 | ||
diff --git a/OpenSim/Region/CoreModules/World/Access/AccessModule.cs b/OpenSim/Region/CoreModules/World/Access/AccessModule.cs index c355b13..2399134 100644 --- a/OpenSim/Region/CoreModules/World/Access/AccessModule.cs +++ b/OpenSim/Region/CoreModules/World/Access/AccessModule.cs | |||
@@ -129,14 +129,12 @@ namespace OpenSim.Region.CoreModules.World | |||
129 | switch (cmd[1]) | 129 | switch (cmd[1]) |
130 | { | 130 | { |
131 | case "enable": | 131 | case "enable": |
132 | if (scene.LoginsDisabled) | ||
133 | MainConsole.Instance.Output(String.Format("Enabling logins for region {0}", scene.RegionInfo.RegionName)); | ||
134 | scene.LoginsDisabled = false; | 132 | scene.LoginsDisabled = false; |
133 | MainConsole.Instance.Output(String.Format("Logins are enabled for region {0}", scene.RegionInfo.RegionName)); | ||
135 | break; | 134 | break; |
136 | case "disable": | 135 | case "disable": |
137 | if (!scene.LoginsDisabled) | ||
138 | MainConsole.Instance.Output(String.Format("Disabling logins for region {0}", scene.RegionInfo.RegionName)); | ||
139 | scene.LoginsDisabled = true; | 136 | scene.LoginsDisabled = true; |
137 | MainConsole.Instance.Output(String.Format("Logins are disabled for region {0}", scene.RegionInfo.RegionName)); | ||
140 | break; | 138 | break; |
141 | case "status": | 139 | case "status": |
142 | if (scene.LoginsDisabled) | 140 | if (scene.LoginsDisabled) |
diff --git a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs index 6ba3459..b185d9b 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs | |||
@@ -68,8 +68,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
68 | SerialiserModule serialiserModule = new SerialiserModule(); | 68 | SerialiserModule serialiserModule = new SerialiserModule(); |
69 | TerrainModule terrainModule = new TerrainModule(); | 69 | TerrainModule terrainModule = new TerrainModule(); |
70 | 70 | ||
71 | m_scene = SceneSetupHelpers.SetupScene(); | 71 | m_scene = SceneHelpers.SetupScene(); |
72 | SceneSetupHelpers.SetupSceneModules(m_scene, m_archiverModule, serialiserModule, terrainModule); | 72 | SceneHelpers.SetupSceneModules(m_scene, m_archiverModule, serialiserModule, terrainModule); |
73 | } | 73 | } |
74 | 74 | ||
75 | private void LoadCompleted(Guid requestId, string errorMessage) | 75 | private void LoadCompleted(Guid requestId, string errorMessage) |
@@ -125,7 +125,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
125 | [Test] | 125 | [Test] |
126 | public void TestSaveOar() | 126 | public void TestSaveOar() |
127 | { | 127 | { |
128 | TestHelper.InMethod(); | 128 | TestHelpers.InMethod(); |
129 | // log4net.Config.XmlConfigurator.Configure(); | 129 | // log4net.Config.XmlConfigurator.Configure(); |
130 | 130 | ||
131 | SceneObjectPart part1 = CreateSceneObjectPart1(); | 131 | SceneObjectPart part1 = CreateSceneObjectPart1(); |
@@ -217,7 +217,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
217 | [Test] | 217 | [Test] |
218 | public void TestSaveOarNoAssets() | 218 | public void TestSaveOarNoAssets() |
219 | { | 219 | { |
220 | TestHelper.InMethod(); | 220 | TestHelpers.InMethod(); |
221 | // log4net.Config.XmlConfigurator.Configure(); | 221 | // log4net.Config.XmlConfigurator.Configure(); |
222 | 222 | ||
223 | SceneObjectPart part1 = CreateSceneObjectPart1(); | 223 | SceneObjectPart part1 = CreateSceneObjectPart1(); |
@@ -300,7 +300,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
300 | [Test] | 300 | [Test] |
301 | public void TestLoadOar() | 301 | public void TestLoadOar() |
302 | { | 302 | { |
303 | TestHelper.InMethod(); | 303 | TestHelpers.InMethod(); |
304 | // log4net.Config.XmlConfigurator.Configure(); | 304 | // log4net.Config.XmlConfigurator.Configure(); |
305 | 305 | ||
306 | MemoryStream archiveWriteStream = new MemoryStream(); | 306 | MemoryStream archiveWriteStream = new MemoryStream(); |
@@ -409,7 +409,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
409 | [Test] | 409 | [Test] |
410 | public void TestLoadOarRegionSettings() | 410 | public void TestLoadOarRegionSettings() |
411 | { | 411 | { |
412 | TestHelper.InMethod(); | 412 | TestHelpers.InMethod(); |
413 | //log4net.Config.XmlConfigurator.Configure(); | 413 | //log4net.Config.XmlConfigurator.Configure(); |
414 | 414 | ||
415 | MemoryStream archiveWriteStream = new MemoryStream(); | 415 | MemoryStream archiveWriteStream = new MemoryStream(); |
@@ -505,7 +505,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
505 | //[Test] | 505 | //[Test] |
506 | public void TestMergeOar() | 506 | public void TestMergeOar() |
507 | { | 507 | { |
508 | TestHelper.InMethod(); | 508 | TestHelpers.InMethod(); |
509 | //XmlConfigurator.Configure(); | 509 | //XmlConfigurator.Configure(); |
510 | 510 | ||
511 | MemoryStream archiveWriteStream = new MemoryStream(); | 511 | MemoryStream archiveWriteStream = new MemoryStream(); |
@@ -524,8 +524,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
524 | SerialiserModule serialiserModule = new SerialiserModule(); | 524 | SerialiserModule serialiserModule = new SerialiserModule(); |
525 | TerrainModule terrainModule = new TerrainModule(); | 525 | TerrainModule terrainModule = new TerrainModule(); |
526 | 526 | ||
527 | Scene scene = SceneSetupHelpers.SetupScene(); | 527 | Scene scene = SceneHelpers.SetupScene(); |
528 | SceneSetupHelpers.SetupSceneModules(scene, archiverModule, serialiserModule, terrainModule); | 528 | SceneHelpers.SetupSceneModules(scene, archiverModule, serialiserModule, terrainModule); |
529 | 529 | ||
530 | m_scene.AddNewSceneObject(new SceneObjectGroup(part2), false); | 530 | m_scene.AddNewSceneObject(new SceneObjectGroup(part2), false); |
531 | 531 | ||
diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs index b96f300..fb32288 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs | |||
@@ -875,41 +875,35 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
875 | SceneObjectPart prt = Scene.GetSceneObjectPart(obj); | 875 | SceneObjectPart prt = Scene.GetSceneObjectPart(obj); |
876 | if (prt != null) | 876 | if (prt != null) |
877 | { | 877 | { |
878 | if (prt.ParentGroup != null) | 878 | SceneObjectGroup sog = prt.ParentGroup; |
879 | LandStatReportItem lsri = new LandStatReportItem(); | ||
880 | lsri.LocationX = sog.AbsolutePosition.X; | ||
881 | lsri.LocationY = sog.AbsolutePosition.Y; | ||
882 | lsri.LocationZ = sog.AbsolutePosition.Z; | ||
883 | lsri.Score = SceneData[obj]; | ||
884 | lsri.TaskID = sog.UUID; | ||
885 | lsri.TaskLocalID = sog.LocalId; | ||
886 | lsri.TaskName = sog.GetPartName(obj); | ||
887 | lsri.OwnerName = "waiting"; | ||
888 | lock (uuidNameLookupList) | ||
889 | uuidNameLookupList.Add(sog.OwnerID); | ||
890 | |||
891 | if (filter.Length != 0) | ||
879 | { | 892 | { |
880 | SceneObjectGroup sog = prt.ParentGroup; | 893 | if ((lsri.OwnerName.Contains(filter) || lsri.TaskName.Contains(filter))) |
881 | if (sog != null) | ||
882 | { | 894 | { |
883 | LandStatReportItem lsri = new LandStatReportItem(); | 895 | } |
884 | lsri.LocationX = sog.AbsolutePosition.X; | 896 | else |
885 | lsri.LocationY = sog.AbsolutePosition.Y; | 897 | { |
886 | lsri.LocationZ = sog.AbsolutePosition.Z; | 898 | continue; |
887 | lsri.Score = SceneData[obj]; | ||
888 | lsri.TaskID = sog.UUID; | ||
889 | lsri.TaskLocalID = sog.LocalId; | ||
890 | lsri.TaskName = sog.GetPartName(obj); | ||
891 | lsri.OwnerName = "waiting"; | ||
892 | lock (uuidNameLookupList) | ||
893 | uuidNameLookupList.Add(sog.OwnerID); | ||
894 | |||
895 | if (filter.Length != 0) | ||
896 | { | ||
897 | if ((lsri.OwnerName.Contains(filter) || lsri.TaskName.Contains(filter))) | ||
898 | { | ||
899 | } | ||
900 | else | ||
901 | { | ||
902 | continue; | ||
903 | } | ||
904 | } | ||
905 | |||
906 | SceneReport.Add(lsri); | ||
907 | } | 899 | } |
908 | } | 900 | } |
909 | } | ||
910 | 901 | ||
902 | SceneReport.Add(lsri); | ||
903 | } | ||
911 | } | 904 | } |
912 | } | 905 | } |
906 | |||
913 | remoteClient.SendLandStatReply(reportType, requestFlags, (uint)SceneReport.Count,SceneReport.ToArray()); | 907 | remoteClient.SendLandStatReply(reportType, requestFlags, (uint)SceneReport.Count,SceneReport.ToArray()); |
914 | 908 | ||
915 | if (uuidNameLookupList.Count > 0) | 909 | if (uuidNameLookupList.Count > 0) |
diff --git a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs index 4e7c76f..a3066e7 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs | |||
@@ -423,17 +423,49 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
423 | SendLandUpdate(avatar, false); | 423 | SendLandUpdate(avatar, false); |
424 | } | 424 | } |
425 | 425 | ||
426 | public void EventManagerOnSignificantClientMovement(IClientAPI remote_client) | 426 | public void EventManagerOnSignificantClientMovement(ScenePresence clientAvatar) |
427 | { | 427 | { |
428 | ScenePresence clientAvatar = m_scene.GetScenePresence(remote_client.AgentId); | 428 | SendLandUpdate(clientAvatar); |
429 | 429 | SendOutNearestBanLine(clientAvatar.ControllingClient); | |
430 | if (clientAvatar != null) | 430 | ILandObject parcel = GetLandObject(clientAvatar.AbsolutePosition.X, clientAvatar.AbsolutePosition.Y); |
431 | if (parcel != null) | ||
431 | { | 432 | { |
432 | SendLandUpdate(clientAvatar); | 433 | if (clientAvatar.AbsolutePosition.Z < LandChannel.BAN_LINE_SAFETY_HIEGHT && |
433 | SendOutNearestBanLine(remote_client); | 434 | clientAvatar.sentMessageAboutRestrictedParcelFlyingDown) |
434 | ILandObject parcel = GetLandObject(clientAvatar.AbsolutePosition.X, clientAvatar.AbsolutePosition.Y); | 435 | { |
435 | if (parcel != null) | 436 | EventManagerOnAvatarEnteringNewParcel(clientAvatar, parcel.LandData.LocalID, |
436 | EnforceBans(parcel, clientAvatar); | 437 | m_scene.RegionInfo.RegionID); |
438 | //They are going under the safety line! | ||
439 | if (!parcel.IsBannedFromLand(clientAvatar.UUID)) | ||
440 | { | ||
441 | clientAvatar.sentMessageAboutRestrictedParcelFlyingDown = false; | ||
442 | } | ||
443 | } | ||
444 | else if (clientAvatar.AbsolutePosition.Z < LandChannel.BAN_LINE_SAFETY_HIEGHT && | ||
445 | parcel.IsBannedFromLand(clientAvatar.UUID)) | ||
446 | { | ||
447 | //once we've sent the message once, keep going toward the target until we are done | ||
448 | if (forcedPosition.ContainsKey(clientAvatar.ControllingClient.AgentId)) | ||
449 | { | ||
450 | SendYouAreBannedNotice(clientAvatar); | ||
451 | ForceAvatarToPosition(clientAvatar, m_scene.GetNearestAllowedPosition(clientAvatar)); | ||
452 | } | ||
453 | } | ||
454 | else if (parcel.IsRestrictedFromLand(clientAvatar.UUID)) | ||
455 | { | ||
456 | //once we've sent the message once, keep going toward the target until we are done | ||
457 | if (forcedPosition.ContainsKey(clientAvatar.ControllingClient.AgentId)) | ||
458 | { | ||
459 | SendYouAreRestrictedNotice(clientAvatar); | ||
460 | ForceAvatarToPosition(clientAvatar, m_scene.GetNearestAllowedPosition(clientAvatar)); | ||
461 | } | ||
462 | } | ||
463 | else | ||
464 | { | ||
465 | //when we are finally in a safe place, lets release the forced position lock | ||
466 | forcedPosition.Remove(clientAvatar.ControllingClient.AgentId); | ||
467 | } | ||
468 | EnforceBans(parcel, clientAvatar); | ||
437 | } | 469 | } |
438 | } | 470 | } |
439 | 471 | ||
@@ -665,7 +697,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
665 | // Corner case. If an autoreturn happens during sim startup | 697 | // Corner case. If an autoreturn happens during sim startup |
666 | // we will come here with the list uninitialized | 698 | // we will come here with the list uninitialized |
667 | // | 699 | // |
668 | int landId = m_landIDList[x, y]; | 700 | // int landId = m_landIDList[x, y]; |
669 | 701 | ||
670 | // if (landId == 0) | 702 | // if (landId == 0) |
671 | // m_log.DebugFormat( | 703 | // m_log.DebugFormat( |
diff --git a/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs b/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs index f466194..5122734 100644 --- a/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs +++ b/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs | |||
@@ -51,7 +51,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
51 | 51 | ||
52 | public class PrimCountModule : IPrimCountModule, INonSharedRegionModule | 52 | public class PrimCountModule : IPrimCountModule, INonSharedRegionModule |
53 | { | 53 | { |
54 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 54 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
55 | 55 | ||
56 | private Scene m_Scene; | 56 | private Scene m_Scene; |
57 | private Dictionary<UUID, PrimCounts> m_PrimCounts = | 57 | private Dictionary<UUID, PrimCounts> m_PrimCounts = |
diff --git a/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs b/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs index a3aa38d..e553ffa 100644 --- a/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs +++ b/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs | |||
@@ -64,8 +64,8 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests | |||
64 | { | 64 | { |
65 | m_pcm = new PrimCountModule(); | 65 | m_pcm = new PrimCountModule(); |
66 | LandManagementModule lmm = new LandManagementModule(); | 66 | LandManagementModule lmm = new LandManagementModule(); |
67 | m_scene = SceneSetupHelpers.SetupScene(); | 67 | m_scene = SceneHelpers.SetupScene(); |
68 | SceneSetupHelpers.SetupSceneModules(m_scene, lmm, m_pcm); | 68 | SceneHelpers.SetupSceneModules(m_scene, lmm, m_pcm); |
69 | 69 | ||
70 | int xParcelDivider = (int)Constants.RegionSize - 1; | 70 | int xParcelDivider = (int)Constants.RegionSize - 1; |
71 | 71 | ||
@@ -106,12 +106,12 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests | |||
106 | [Test] | 106 | [Test] |
107 | public void TestAddOwnerObject() | 107 | public void TestAddOwnerObject() |
108 | { | 108 | { |
109 | TestHelper.InMethod(); | 109 | TestHelpers.InMethod(); |
110 | // log4net.Config.XmlConfigurator.Configure(); | 110 | // log4net.Config.XmlConfigurator.Configure(); |
111 | 111 | ||
112 | IPrimCounts pc = m_lo.PrimCounts; | 112 | IPrimCounts pc = m_lo.PrimCounts; |
113 | 113 | ||
114 | SceneObjectGroup sog = SceneSetupHelpers.CreateSceneObject(3, m_userId, "a", 0x01); | 114 | SceneObjectGroup sog = SceneHelpers.CreateSceneObject(3, m_userId, "a", 0x01); |
115 | m_scene.AddNewSceneObject(sog, false); | 115 | m_scene.AddNewSceneObject(sog, false); |
116 | 116 | ||
117 | Assert.That(pc.Owner, Is.EqualTo(3)); | 117 | Assert.That(pc.Owner, Is.EqualTo(3)); |
@@ -124,7 +124,7 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests | |||
124 | Assert.That(pc.Simulator, Is.EqualTo(3)); | 124 | Assert.That(pc.Simulator, Is.EqualTo(3)); |
125 | 125 | ||
126 | // Add a second object and retest | 126 | // Add a second object and retest |
127 | SceneObjectGroup sog2 = SceneSetupHelpers.CreateSceneObject(2, m_userId, "b", 0x10); | 127 | SceneObjectGroup sog2 = SceneHelpers.CreateSceneObject(2, m_userId, "b", 0x10); |
128 | m_scene.AddNewSceneObject(sog2, false); | 128 | m_scene.AddNewSceneObject(sog2, false); |
129 | 129 | ||
130 | Assert.That(pc.Owner, Is.EqualTo(5)); | 130 | Assert.That(pc.Owner, Is.EqualTo(5)); |
@@ -143,12 +143,12 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests | |||
143 | [Test] | 143 | [Test] |
144 | public void TestCopyOwnerObject() | 144 | public void TestCopyOwnerObject() |
145 | { | 145 | { |
146 | TestHelper.InMethod(); | 146 | TestHelpers.InMethod(); |
147 | // log4net.Config.XmlConfigurator.Configure(); | 147 | // log4net.Config.XmlConfigurator.Configure(); |
148 | 148 | ||
149 | IPrimCounts pc = m_lo.PrimCounts; | 149 | IPrimCounts pc = m_lo.PrimCounts; |
150 | 150 | ||
151 | SceneObjectGroup sog = SceneSetupHelpers.CreateSceneObject(3, m_userId, "a", 0x01); | 151 | SceneObjectGroup sog = SceneHelpers.CreateSceneObject(3, m_userId, "a", 0x01); |
152 | m_scene.AddNewSceneObject(sog, false); | 152 | m_scene.AddNewSceneObject(sog, false); |
153 | m_scene.SceneGraph.DuplicateObject(sog.LocalId, Vector3.Zero, 0, m_userId, UUID.Zero, Quaternion.Identity); | 153 | m_scene.SceneGraph.DuplicateObject(sog.LocalId, Vector3.Zero, 0, m_userId, UUID.Zero, Quaternion.Identity); |
154 | 154 | ||
@@ -169,12 +169,12 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests | |||
169 | [Test] | 169 | [Test] |
170 | public void TestMoveOwnerObject() | 170 | public void TestMoveOwnerObject() |
171 | { | 171 | { |
172 | TestHelper.InMethod(); | 172 | TestHelpers.InMethod(); |
173 | // log4net.Config.XmlConfigurator.Configure(); | 173 | // log4net.Config.XmlConfigurator.Configure(); |
174 | 174 | ||
175 | SceneObjectGroup sog = SceneSetupHelpers.CreateSceneObject(3, m_userId, "a", 0x01); | 175 | SceneObjectGroup sog = SceneHelpers.CreateSceneObject(3, m_userId, "a", 0x01); |
176 | m_scene.AddNewSceneObject(sog, false); | 176 | m_scene.AddNewSceneObject(sog, false); |
177 | SceneObjectGroup sog2 = SceneSetupHelpers.CreateSceneObject(2, m_userId, "b", 0x10); | 177 | SceneObjectGroup sog2 = SceneHelpers.CreateSceneObject(2, m_userId, "b", 0x10); |
178 | m_scene.AddNewSceneObject(sog2, false); | 178 | m_scene.AddNewSceneObject(sog2, false); |
179 | 179 | ||
180 | // Move the first scene object to the eastern strip parcel | 180 | // Move the first scene object to the eastern strip parcel |
@@ -230,13 +230,13 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests | |||
230 | [Test] | 230 | [Test] |
231 | public void TestRemoveOwnerObject() | 231 | public void TestRemoveOwnerObject() |
232 | { | 232 | { |
233 | TestHelper.InMethod(); | 233 | TestHelpers.InMethod(); |
234 | // log4net.Config.XmlConfigurator.Configure(); | 234 | // log4net.Config.XmlConfigurator.Configure(); |
235 | 235 | ||
236 | IPrimCounts pc = m_lo.PrimCounts; | 236 | IPrimCounts pc = m_lo.PrimCounts; |
237 | 237 | ||
238 | m_scene.AddNewSceneObject(SceneSetupHelpers.CreateSceneObject(1, m_userId, "a", 0x1), false); | 238 | m_scene.AddNewSceneObject(SceneHelpers.CreateSceneObject(1, m_userId, "a", 0x1), false); |
239 | SceneObjectGroup sogToDelete = SceneSetupHelpers.CreateSceneObject(3, m_userId, "b", 0x10); | 239 | SceneObjectGroup sogToDelete = SceneHelpers.CreateSceneObject(3, m_userId, "b", 0x10); |
240 | m_scene.AddNewSceneObject(sogToDelete, false); | 240 | m_scene.AddNewSceneObject(sogToDelete, false); |
241 | m_scene.DeleteSceneObject(sogToDelete, false); | 241 | m_scene.DeleteSceneObject(sogToDelete, false); |
242 | 242 | ||
@@ -253,14 +253,14 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests | |||
253 | [Test] | 253 | [Test] |
254 | public void TestAddGroupObject() | 254 | public void TestAddGroupObject() |
255 | { | 255 | { |
256 | TestHelper.InMethod(); | 256 | TestHelpers.InMethod(); |
257 | // log4net.Config.XmlConfigurator.Configure(); | 257 | // log4net.Config.XmlConfigurator.Configure(); |
258 | 258 | ||
259 | m_lo.DeedToGroup(m_groupId); | 259 | m_lo.DeedToGroup(m_groupId); |
260 | 260 | ||
261 | IPrimCounts pc = m_lo.PrimCounts; | 261 | IPrimCounts pc = m_lo.PrimCounts; |
262 | 262 | ||
263 | SceneObjectGroup sog = SceneSetupHelpers.CreateSceneObject(3, m_otherUserId, "a", 0x01); | 263 | SceneObjectGroup sog = SceneHelpers.CreateSceneObject(3, m_otherUserId, "a", 0x01); |
264 | sog.GroupID = m_groupId; | 264 | sog.GroupID = m_groupId; |
265 | m_scene.AddNewSceneObject(sog, false); | 265 | m_scene.AddNewSceneObject(sog, false); |
266 | 266 | ||
@@ -284,18 +284,18 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests | |||
284 | [Test] | 284 | [Test] |
285 | public void TestRemoveGroupObject() | 285 | public void TestRemoveGroupObject() |
286 | { | 286 | { |
287 | TestHelper.InMethod(); | 287 | TestHelpers.InMethod(); |
288 | // log4net.Config.XmlConfigurator.Configure(); | 288 | // log4net.Config.XmlConfigurator.Configure(); |
289 | 289 | ||
290 | m_lo.DeedToGroup(m_groupId); | 290 | m_lo.DeedToGroup(m_groupId); |
291 | 291 | ||
292 | IPrimCounts pc = m_lo.PrimCounts; | 292 | IPrimCounts pc = m_lo.PrimCounts; |
293 | 293 | ||
294 | SceneObjectGroup sogToKeep = SceneSetupHelpers.CreateSceneObject(1, m_userId, "a", 0x1); | 294 | SceneObjectGroup sogToKeep = SceneHelpers.CreateSceneObject(1, m_userId, "a", 0x1); |
295 | sogToKeep.GroupID = m_groupId; | 295 | sogToKeep.GroupID = m_groupId; |
296 | m_scene.AddNewSceneObject(sogToKeep, false); | 296 | m_scene.AddNewSceneObject(sogToKeep, false); |
297 | 297 | ||
298 | SceneObjectGroup sogToDelete = SceneSetupHelpers.CreateSceneObject(3, m_userId, "b", 0x10); | 298 | SceneObjectGroup sogToDelete = SceneHelpers.CreateSceneObject(3, m_userId, "b", 0x10); |
299 | m_scene.AddNewSceneObject(sogToDelete, false); | 299 | m_scene.AddNewSceneObject(sogToDelete, false); |
300 | m_scene.DeleteSceneObject(sogToDelete, false); | 300 | m_scene.DeleteSceneObject(sogToDelete, false); |
301 | 301 | ||
@@ -313,12 +313,12 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests | |||
313 | [Test] | 313 | [Test] |
314 | public void TestAddOthersObject() | 314 | public void TestAddOthersObject() |
315 | { | 315 | { |
316 | TestHelper.InMethod(); | 316 | TestHelpers.InMethod(); |
317 | // log4net.Config.XmlConfigurator.Configure(); | 317 | // log4net.Config.XmlConfigurator.Configure(); |
318 | 318 | ||
319 | IPrimCounts pc = m_lo.PrimCounts; | 319 | IPrimCounts pc = m_lo.PrimCounts; |
320 | 320 | ||
321 | SceneObjectGroup sog = SceneSetupHelpers.CreateSceneObject(3, m_otherUserId, "a", 0x01); | 321 | SceneObjectGroup sog = SceneHelpers.CreateSceneObject(3, m_otherUserId, "a", 0x01); |
322 | m_scene.AddNewSceneObject(sog, false); | 322 | m_scene.AddNewSceneObject(sog, false); |
323 | 323 | ||
324 | Assert.That(pc.Owner, Is.EqualTo(0)); | 324 | Assert.That(pc.Owner, Is.EqualTo(0)); |
@@ -334,13 +334,13 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests | |||
334 | [Test] | 334 | [Test] |
335 | public void TestRemoveOthersObject() | 335 | public void TestRemoveOthersObject() |
336 | { | 336 | { |
337 | TestHelper.InMethod(); | 337 | TestHelpers.InMethod(); |
338 | // log4net.Config.XmlConfigurator.Configure(); | 338 | // log4net.Config.XmlConfigurator.Configure(); |
339 | 339 | ||
340 | IPrimCounts pc = m_lo.PrimCounts; | 340 | IPrimCounts pc = m_lo.PrimCounts; |
341 | 341 | ||
342 | m_scene.AddNewSceneObject(SceneSetupHelpers.CreateSceneObject(1, m_otherUserId, "a", 0x1), false); | 342 | m_scene.AddNewSceneObject(SceneHelpers.CreateSceneObject(1, m_otherUserId, "a", 0x1), false); |
343 | SceneObjectGroup sogToDelete = SceneSetupHelpers.CreateSceneObject(3, m_otherUserId, "b", 0x10); | 343 | SceneObjectGroup sogToDelete = SceneHelpers.CreateSceneObject(3, m_otherUserId, "b", 0x10); |
344 | m_scene.AddNewSceneObject(sogToDelete, false); | 344 | m_scene.AddNewSceneObject(sogToDelete, false); |
345 | m_scene.DeleteSceneObject(sogToDelete, false); | 345 | m_scene.DeleteSceneObject(sogToDelete, false); |
346 | 346 | ||
@@ -360,10 +360,10 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests | |||
360 | [Test] | 360 | [Test] |
361 | public void TestTaint() | 361 | public void TestTaint() |
362 | { | 362 | { |
363 | TestHelper.InMethod(); | 363 | TestHelpers.InMethod(); |
364 | IPrimCounts pc = m_lo.PrimCounts; | 364 | IPrimCounts pc = m_lo.PrimCounts; |
365 | 365 | ||
366 | SceneObjectGroup sog = SceneSetupHelpers.CreateSceneObject(3, m_userId, "a", 0x01); | 366 | SceneObjectGroup sog = SceneHelpers.CreateSceneObject(3, m_userId, "a", 0x01); |
367 | m_scene.AddNewSceneObject(sog, false); | 367 | m_scene.AddNewSceneObject(sog, false); |
368 | 368 | ||
369 | m_pcm.TaintPrimCount(); | 369 | m_pcm.TaintPrimCount(); |
diff --git a/OpenSim/Region/CoreModules/World/LegacyMap/TexturedMapTileRenderer.cs b/OpenSim/Region/CoreModules/World/LegacyMap/TexturedMapTileRenderer.cs index aa14054..1d2141e 100644 --- a/OpenSim/Region/CoreModules/World/LegacyMap/TexturedMapTileRenderer.cs +++ b/OpenSim/Region/CoreModules/World/LegacyMap/TexturedMapTileRenderer.cs | |||
@@ -173,7 +173,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
173 | private Bitmap fetchTexture(UUID id) | 173 | private Bitmap fetchTexture(UUID id) |
174 | { | 174 | { |
175 | AssetBase asset = m_scene.AssetService.Get(id.ToString()); | 175 | AssetBase asset = m_scene.AssetService.Get(id.ToString()); |
176 | m_log.DebugFormat("Fetched texture {0}, found: {1}", id, asset != null); | 176 | m_log.DebugFormat("[TexturedMapTileRenderer]: Fetched texture {0}, found: {1}", id, asset != null); |
177 | if (asset == null) return null; | 177 | if (asset == null) return null; |
178 | 178 | ||
179 | ManagedImage managedImage; | 179 | ManagedImage managedImage; |
diff --git a/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs b/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs index d5b7082..4326606 100644 --- a/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs +++ b/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs | |||
@@ -53,17 +53,17 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap.Tests | |||
53 | public void SetUp() | 53 | public void SetUp() |
54 | { | 54 | { |
55 | m_module = new MoapModule(); | 55 | m_module = new MoapModule(); |
56 | m_scene = SceneSetupHelpers.SetupScene(); | 56 | m_scene = SceneHelpers.SetupScene(); |
57 | SceneSetupHelpers.SetupSceneModules(m_scene, m_module); | 57 | SceneHelpers.SetupSceneModules(m_scene, m_module); |
58 | } | 58 | } |
59 | 59 | ||
60 | [Test] | 60 | [Test] |
61 | public void TestClearMediaUrl() | 61 | public void TestClearMediaUrl() |
62 | { | 62 | { |
63 | TestHelper.InMethod(); | 63 | TestHelpers.InMethod(); |
64 | // log4net.Config.XmlConfigurator.Configure(); | 64 | // log4net.Config.XmlConfigurator.Configure(); |
65 | 65 | ||
66 | SceneObjectPart part = SceneSetupHelpers.AddSceneObject(m_scene); | 66 | SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene); |
67 | MediaEntry me = new MediaEntry(); | 67 | MediaEntry me = new MediaEntry(); |
68 | 68 | ||
69 | m_module.SetMediaEntry(part, 1, me); | 69 | m_module.SetMediaEntry(part, 1, me); |
@@ -84,11 +84,11 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap.Tests | |||
84 | [Test] | 84 | [Test] |
85 | public void TestSetMediaUrl() | 85 | public void TestSetMediaUrl() |
86 | { | 86 | { |
87 | TestHelper.InMethod(); | 87 | TestHelpers.InMethod(); |
88 | 88 | ||
89 | string homeUrl = "opensimulator.org"; | 89 | string homeUrl = "opensimulator.org"; |
90 | 90 | ||
91 | SceneObjectPart part = SceneSetupHelpers.AddSceneObject(m_scene); | 91 | SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene); |
92 | MediaEntry me = new MediaEntry() { HomeURL = homeUrl }; | 92 | MediaEntry me = new MediaEntry() { HomeURL = homeUrl }; |
93 | 93 | ||
94 | m_module.SetMediaEntry(part, 1, me); | 94 | m_module.SetMediaEntry(part, 1, me); |
diff --git a/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs b/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs index 516189f..49e3236 100644 --- a/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs +++ b/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs | |||
@@ -85,7 +85,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.BuySell | |||
85 | IClientAPI client, UUID agentID, UUID sessionID, uint localID, byte saleType, int salePrice) | 85 | IClientAPI client, UUID agentID, UUID sessionID, uint localID, byte saleType, int salePrice) |
86 | { | 86 | { |
87 | SceneObjectPart part = m_scene.GetSceneObjectPart(localID); | 87 | SceneObjectPart part = m_scene.GetSceneObjectPart(localID); |
88 | if (part == null || part.ParentGroup == null) | 88 | if (part == null) |
89 | return; | 89 | return; |
90 | 90 | ||
91 | if (part.ParentGroup.IsDeleted) | 91 | if (part.ParentGroup.IsDeleted) |
@@ -111,9 +111,6 @@ namespace OpenSim.Region.CoreModules.World.Objects.BuySell | |||
111 | if (part == null) | 111 | if (part == null) |
112 | return false; | 112 | return false; |
113 | 113 | ||
114 | if (part.ParentGroup == null) | ||
115 | return false; | ||
116 | |||
117 | SceneObjectGroup group = part.ParentGroup; | 114 | SceneObjectGroup group = part.ParentGroup; |
118 | 115 | ||
119 | switch (saleType) | 116 | switch (saleType) |
diff --git a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs index 2c7843f..afb641f 100644 --- a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs +++ b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs | |||
@@ -146,7 +146,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions | |||
146 | = ParseUserSetConfigSetting(myConfig, "allowed_script_editors", m_allowedScriptEditors); | 146 | = ParseUserSetConfigSetting(myConfig, "allowed_script_editors", m_allowedScriptEditors); |
147 | 147 | ||
148 | if (m_bypassPermissions) | 148 | if (m_bypassPermissions) |
149 | m_log.Info("[PERMISSIONS]: serviceside_object_permissions = false in ini file so disabling all region service permission checks"); | 149 | m_log.Info("[PERMISSIONS]: serverside_object_permissions = false in ini file so disabling all region service permission checks"); |
150 | else | 150 | else |
151 | m_log.Debug("[PERMISSIONS]: Enabling all region service permission checks"); | 151 | m_log.Debug("[PERMISSIONS]: Enabling all region service permission checks"); |
152 | 152 | ||
@@ -1131,7 +1131,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions | |||
1131 | SceneObjectPart part = scene.GetSceneObjectPart(objectID); | 1131 | SceneObjectPart part = scene.GetSceneObjectPart(objectID); |
1132 | if (part.OwnerID != moverID) | 1132 | if (part.OwnerID != moverID) |
1133 | { | 1133 | { |
1134 | if (part.ParentGroup != null && !part.ParentGroup.IsDeleted) | 1134 | if (!part.ParentGroup.IsDeleted) |
1135 | { | 1135 | { |
1136 | if (part.ParentGroup.IsAttachment) | 1136 | if (part.ParentGroup.IsAttachment) |
1137 | return false; | 1137 | return false; |
diff --git a/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs b/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs index 4f752ab..d5b585a 100644 --- a/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs +++ b/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs | |||
@@ -236,14 +236,14 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests | |||
236 | public void Init() | 236 | public void Init() |
237 | { | 237 | { |
238 | m_serialiserModule = new SerialiserModule(); | 238 | m_serialiserModule = new SerialiserModule(); |
239 | m_scene = SceneSetupHelpers.SetupScene(); | 239 | m_scene = SceneHelpers.SetupScene(); |
240 | SceneSetupHelpers.SetupSceneModules(m_scene, m_serialiserModule); | 240 | SceneHelpers.SetupSceneModules(m_scene, m_serialiserModule); |
241 | } | 241 | } |
242 | 242 | ||
243 | [Test] | 243 | [Test] |
244 | public void TestDeserializeXml() | 244 | public void TestDeserializeXml() |
245 | { | 245 | { |
246 | TestHelper.InMethod(); | 246 | TestHelpers.InMethod(); |
247 | //log4net.Config.XmlConfigurator.Configure(); | 247 | //log4net.Config.XmlConfigurator.Configure(); |
248 | 248 | ||
249 | SceneObjectGroup so = SceneObjectSerializer.FromOriginalXmlFormat(xml); | 249 | SceneObjectGroup so = SceneObjectSerializer.FromOriginalXmlFormat(xml); |
@@ -259,7 +259,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests | |||
259 | [Test] | 259 | [Test] |
260 | public void TestSerializeXml() | 260 | public void TestSerializeXml() |
261 | { | 261 | { |
262 | TestHelper.InMethod(); | 262 | TestHelpers.InMethod(); |
263 | //log4net.Config.XmlConfigurator.Configure(); | 263 | //log4net.Config.XmlConfigurator.Configure(); |
264 | 264 | ||
265 | string rpName = "My Little Donkey"; | 265 | string rpName = "My Little Donkey"; |
@@ -334,7 +334,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests | |||
334 | [Test] | 334 | [Test] |
335 | public void TestDeserializeXml2() | 335 | public void TestDeserializeXml2() |
336 | { | 336 | { |
337 | TestHelper.InMethod(); | 337 | TestHelpers.InMethod(); |
338 | //log4net.Config.XmlConfigurator.Configure(); | 338 | //log4net.Config.XmlConfigurator.Configure(); |
339 | 339 | ||
340 | SceneObjectGroup so = m_serialiserModule.DeserializeGroupFromXml2(xml2); | 340 | SceneObjectGroup so = m_serialiserModule.DeserializeGroupFromXml2(xml2); |
@@ -350,7 +350,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests | |||
350 | [Test] | 350 | [Test] |
351 | public void TestSerializeXml2() | 351 | public void TestSerializeXml2() |
352 | { | 352 | { |
353 | TestHelper.InMethod(); | 353 | TestHelpers.InMethod(); |
354 | //log4net.Config.XmlConfigurator.Configure(); | 354 | //log4net.Config.XmlConfigurator.Configure(); |
355 | 355 | ||
356 | string rpName = "My Little Pony"; | 356 | string rpName = "My Little Pony"; |
diff --git a/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs b/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs index 09c0ebb..22ffcd6 100644 --- a/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs +++ b/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs | |||
@@ -81,7 +81,7 @@ namespace OpenSim.Region.CoreModules.World.Sound | |||
81 | 81 | ||
82 | if (grp.IsAttachment) | 82 | if (grp.IsAttachment) |
83 | { | 83 | { |
84 | if (grp.GetAttachmentPoint() > 30) // HUD | 84 | if (grp.AttachmentPoint > 30) // HUD |
85 | { | 85 | { |
86 | if (sp.ControllingClient.AgentId != grp.OwnerID) | 86 | if (sp.ControllingClient.AgentId != grp.OwnerID) |
87 | return; | 87 | return; |
@@ -115,7 +115,7 @@ namespace OpenSim.Region.CoreModules.World.Sound | |||
115 | { | 115 | { |
116 | SceneObjectGroup grp = part.ParentGroup; | 116 | SceneObjectGroup grp = part.ParentGroup; |
117 | 117 | ||
118 | if (grp.IsAttachment && grp.GetAttachmentPoint() > 30) | 118 | if (grp.IsAttachment && grp.AttachmentPoint > 30) |
119 | { | 119 | { |
120 | objectID = ownerID; | 120 | objectID = ownerID; |
121 | parentID = ownerID; | 121 | parentID = ownerID; |
diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs index 2da6458..a93ffaa 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs | |||
@@ -84,7 +84,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
84 | private ITerrainChannel m_revert; | 84 | private ITerrainChannel m_revert; |
85 | private Scene m_scene; | 85 | private Scene m_scene; |
86 | private volatile bool m_tainted; | 86 | private volatile bool m_tainted; |
87 | private readonly UndoStack<LandUndoState> m_undo = new UndoStack<LandUndoState>(5); | 87 | private readonly Stack<LandUndoState> m_undo = new Stack<LandUndoState>(5); |
88 | 88 | ||
89 | #region ICommandableModule Members | 89 | #region ICommandableModule Members |
90 | 90 | ||
diff --git a/OpenSim/Region/CoreModules/World/Vegetation/VegetationModule.cs b/OpenSim/Region/CoreModules/World/Vegetation/VegetationModule.cs index c2ad7b8..ab8e1bf 100644 --- a/OpenSim/Region/CoreModules/World/Vegetation/VegetationModule.cs +++ b/OpenSim/Region/CoreModules/World/Vegetation/VegetationModule.cs | |||
@@ -100,15 +100,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Vegetation | |||
100 | { | 100 | { |
101 | case Tree.Cypress1: | 101 | case Tree.Cypress1: |
102 | case Tree.Cypress2: | 102 | case Tree.Cypress2: |
103 | tree.Scale = new Vector3(4, 4, 10); | 103 | tree.Scale *= new Vector3(8, 8, 20); |
104 | break; | 104 | break; |
105 | 105 | ||
106 | // case... other tree types | 106 | // case... other tree types |
107 | // tree.Scale = new Vector3(?, ?, ?); | 107 | // tree.Scale *= new Vector3(?, ?, ?); |
108 | // break; | 108 | // break; |
109 | 109 | ||
110 | default: | 110 | default: |
111 | tree.Scale = new Vector3(4, 4, 4); | 111 | tree.Scale *= new Vector3(8, 8, 8); |
112 | break; | 112 | break; |
113 | } | 113 | } |
114 | } | 114 | } |
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs index ced2773..c13e9c6 100644 --- a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs +++ b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs | |||
@@ -96,16 +96,7 @@ m_log.DebugFormat("MAP NAME=({0})", mapName); | |||
96 | 96 | ||
97 | // try to fetch from GridServer | 97 | // try to fetch from GridServer |
98 | List<GridRegion> regionInfos = m_scene.GridService.GetRegionsByName(m_scene.RegionInfo.ScopeID, mapName, 20); | 98 | List<GridRegion> regionInfos = m_scene.GridService.GetRegionsByName(m_scene.RegionInfo.ScopeID, mapName, 20); |
99 | if (regionInfos == null) | 99 | if (regionInfos.Count == 0) |
100 | { | ||
101 | m_log.Warn("[MAPSEARCHMODULE]: RequestNamedRegions returned null. Old gridserver?"); | ||
102 | // service wasn't available; maybe still an old GridServer. Try the old API, though it will return only one region | ||
103 | regionInfos = new List<GridRegion>(); | ||
104 | GridRegion info = m_scene.GridService.GetRegionByName(m_scene.RegionInfo.ScopeID, mapName); | ||
105 | if (info != null) | ||
106 | regionInfos.Add(info); | ||
107 | } | ||
108 | else if (regionInfos.Count == 0) | ||
109 | remoteClient.SendAlertMessage("Hyperlink could not be established."); | 100 | remoteClient.SendAlertMessage("Hyperlink could not be established."); |
110 | 101 | ||
111 | //m_log.DebugFormat("[MAPSEARCHMODULE]: search {0} returned {1} regions", mapName, regionInfos.Count); | 102 | //m_log.DebugFormat("[MAPSEARCHMODULE]: search {0} returned {1} regions", mapName, regionInfos.Count); |
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs index ca5529d9..21e3ecb 100644 --- a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs +++ b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs | |||
@@ -46,6 +46,7 @@ using OpenSim.Framework.Servers; | |||
46 | using OpenSim.Framework.Servers.HttpServer; | 46 | using OpenSim.Framework.Servers.HttpServer; |
47 | using OpenSim.Region.Framework.Interfaces; | 47 | using OpenSim.Region.Framework.Interfaces; |
48 | using OpenSim.Region.Framework.Scenes; | 48 | using OpenSim.Region.Framework.Scenes; |
49 | using OpenSim.Region.CoreModules.World.Land; | ||
49 | using Caps=OpenSim.Framework.Capabilities.Caps; | 50 | using Caps=OpenSim.Framework.Capabilities.Caps; |
50 | using OSDArray=OpenMetaverse.StructuredData.OSDArray; | 51 | using OSDArray=OpenMetaverse.StructuredData.OSDArray; |
51 | using OSDMap=OpenMetaverse.StructuredData.OSDMap; | 52 | using OSDMap=OpenMetaverse.StructuredData.OSDMap; |
@@ -68,6 +69,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
68 | protected Scene m_scene; | 69 | protected Scene m_scene; |
69 | private List<MapBlockData> cachedMapBlocks = new List<MapBlockData>(); | 70 | private List<MapBlockData> cachedMapBlocks = new List<MapBlockData>(); |
70 | private int cachedTime = 0; | 71 | private int cachedTime = 0; |
72 | private int blacklistTimeout = 10*60*1000; // 10 minutes | ||
71 | private byte[] myMapImageJPEG; | 73 | private byte[] myMapImageJPEG; |
72 | protected volatile bool m_Enabled = false; | 74 | protected volatile bool m_Enabled = false; |
73 | private Dictionary<UUID, MapRequestState> m_openRequests = new Dictionary<UUID, MapRequestState>(); | 75 | private Dictionary<UUID, MapRequestState> m_openRequests = new Dictionary<UUID, MapRequestState>(); |
@@ -85,6 +87,8 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
85 | IConfig startupConfig = config.Configs["Startup"]; | 87 | IConfig startupConfig = config.Configs["Startup"]; |
86 | if (startupConfig.GetString("WorldMapModule", "WorldMap") == "WorldMap") | 88 | if (startupConfig.GetString("WorldMapModule", "WorldMap") == "WorldMap") |
87 | m_Enabled = true; | 89 | m_Enabled = true; |
90 | |||
91 | blacklistTimeout = startupConfig.GetInt("BlacklistTimeout", 10*60) * 1000; | ||
88 | } | 92 | } |
89 | 93 | ||
90 | public virtual void AddRegion (Scene scene) | 94 | public virtual void AddRegion (Scene scene) |
@@ -159,11 +163,17 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
159 | m_scene.EventManager.OnClientClosed += ClientLoggedOut; | 163 | m_scene.EventManager.OnClientClosed += ClientLoggedOut; |
160 | m_scene.EventManager.OnMakeChildAgent += MakeChildAgent; | 164 | m_scene.EventManager.OnMakeChildAgent += MakeChildAgent; |
161 | m_scene.EventManager.OnMakeRootAgent += MakeRootAgent; | 165 | m_scene.EventManager.OnMakeRootAgent += MakeRootAgent; |
166 | m_scene.EventManager.OnRegionUp += OnRegionUp; | ||
167 | |||
168 | StartThread(new object()); | ||
162 | } | 169 | } |
163 | 170 | ||
164 | // this has to be called with a lock on m_scene | 171 | // this has to be called with a lock on m_scene |
165 | protected virtual void RemoveHandlers() | 172 | protected virtual void RemoveHandlers() |
166 | { | 173 | { |
174 | StopThread(); | ||
175 | |||
176 | m_scene.EventManager.OnRegionUp -= OnRegionUp; | ||
167 | m_scene.EventManager.OnMakeRootAgent -= MakeRootAgent; | 177 | m_scene.EventManager.OnMakeRootAgent -= MakeRootAgent; |
168 | m_scene.EventManager.OnMakeChildAgent -= MakeChildAgent; | 178 | m_scene.EventManager.OnMakeChildAgent -= MakeChildAgent; |
169 | m_scene.EventManager.OnClientClosed -= ClientLoggedOut; | 179 | m_scene.EventManager.OnClientClosed -= ClientLoggedOut; |
@@ -279,7 +289,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
279 | /// <returns></returns> | 289 | /// <returns></returns> |
280 | public LLSDMapLayerResponse GetMapLayer(LLSDMapRequest mapReq) | 290 | public LLSDMapLayerResponse GetMapLayer(LLSDMapRequest mapReq) |
281 | { | 291 | { |
282 | m_log.Debug("[WORLD MAP]: MapLayer Request in region: " + m_scene.RegionInfo.RegionName); | 292 | m_log.DebugFormat("[WORLD MAP]: MapLayer Request in region: {0}", m_scene.RegionInfo.RegionName); |
283 | LLSDMapLayerResponse mapResponse = new LLSDMapLayerResponse(); | 293 | LLSDMapLayerResponse mapResponse = new LLSDMapLayerResponse(); |
284 | mapResponse.LayerData.Array.Add(GetOSDMapLayerResponse()); | 294 | mapResponse.LayerData.Array.Add(GetOSDMapLayerResponse()); |
285 | return mapResponse; | 295 | return mapResponse; |
@@ -321,8 +331,6 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
321 | lock (m_rootAgents) | 331 | lock (m_rootAgents) |
322 | { | 332 | { |
323 | m_rootAgents.Remove(AgentId); | 333 | m_rootAgents.Remove(AgentId); |
324 | if (m_rootAgents.Count == 0) | ||
325 | StopThread(); | ||
326 | } | 334 | } |
327 | } | 335 | } |
328 | #endregion | 336 | #endregion |
@@ -362,6 +370,8 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
362 | public virtual void HandleMapItemRequest(IClientAPI remoteClient, uint flags, | 370 | public virtual void HandleMapItemRequest(IClientAPI remoteClient, uint flags, |
363 | uint EstateID, bool godlike, uint itemtype, ulong regionhandle) | 371 | uint EstateID, bool godlike, uint itemtype, ulong regionhandle) |
364 | { | 372 | { |
373 | // m_log.DebugFormat("[WORLD MAP]: Handle MapItem request {0} {1}", regionhandle, itemtype); | ||
374 | |||
365 | lock (m_rootAgents) | 375 | lock (m_rootAgents) |
366 | { | 376 | { |
367 | if (!m_rootAgents.Contains(remoteClient.AgentId)) | 377 | if (!m_rootAgents.Contains(remoteClient.AgentId)) |
@@ -370,7 +380,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
370 | uint xstart = 0; | 380 | uint xstart = 0; |
371 | uint ystart = 0; | 381 | uint ystart = 0; |
372 | Utils.LongToUInts(m_scene.RegionInfo.RegionHandle, out xstart, out ystart); | 382 | Utils.LongToUInts(m_scene.RegionInfo.RegionHandle, out xstart, out ystart); |
373 | if (itemtype == 6) // we only sevice 6 right now (avatar green dots) | 383 | if (itemtype == 6) // Service 6 right now (MAP_ITEM_AGENTS_LOCATION; green dots) |
374 | { | 384 | { |
375 | if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle) | 385 | if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle) |
376 | { | 386 | { |
@@ -414,14 +424,57 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
414 | // Remote Map Item Request | 424 | // Remote Map Item Request |
415 | 425 | ||
416 | // ensures that the blockingqueue doesn't get borked if the GetAgents() timing changes. | 426 | // ensures that the blockingqueue doesn't get borked if the GetAgents() timing changes. |
417 | // Note that we only start up a remote mapItem Request thread if there's users who could | 427 | RequestMapItems("",remoteClient.AgentId,flags,EstateID,godlike,itemtype,regionhandle); |
418 | // be making requests | 428 | } |
419 | if (!threadrunning) | 429 | } else if (itemtype == 7) // Service 7 (MAP_ITEM_LAND_FOR_SALE) |
430 | { | ||
431 | if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle) | ||
432 | { | ||
433 | // Parcels | ||
434 | ILandChannel landChannel = m_scene.LandChannel; | ||
435 | List<ILandObject> parcels = landChannel.AllParcels(); | ||
436 | |||
437 | // Local Map Item Request | ||
438 | List<mapItemReply> mapitems = new List<mapItemReply>(); | ||
439 | mapItemReply mapitem = new mapItemReply(); | ||
440 | if ((parcels != null) && (parcels.Count >= 1)) | ||
420 | { | 441 | { |
421 | m_log.Warn("[WORLD MAP]: Starting new remote request thread manually. This means that AvatarEnteringParcel never fired! This needs to be fixed! Don't Mantis this, as the developers can see it in this message"); | 442 | foreach (ILandObject parcel_interface in parcels) |
422 | StartThread(new object()); | 443 | { |
444 | // Play it safe | ||
445 | if (!(parcel_interface is LandObject)) | ||
446 | continue; | ||
447 | |||
448 | LandObject land = (LandObject)parcel_interface; | ||
449 | LandData parcel = land.LandData; | ||
450 | |||
451 | // Show land for sale | ||
452 | if ((parcel.Flags & (uint)ParcelFlags.ForSale) == (uint)ParcelFlags.ForSale) | ||
453 | { | ||
454 | Vector3 min = parcel.AABBMin; | ||
455 | Vector3 max = parcel.AABBMax; | ||
456 | float x = (min.X+max.X)/2; | ||
457 | float y = (min.Y+max.Y)/2; | ||
458 | |||
459 | mapitem = new mapItemReply(); | ||
460 | mapitem.x = (uint)(xstart + x); | ||
461 | mapitem.y = (uint)(ystart + y); | ||
462 | // mapitem.z = (uint)m_scene.GetGroundHeight(x,y); | ||
463 | mapitem.id = UUID.Zero; | ||
464 | mapitem.name = parcel.Name; | ||
465 | mapitem.Extra = parcel.Area; | ||
466 | mapitem.Extra2 = parcel.SalePrice; | ||
467 | mapitems.Add(mapitem); | ||
468 | } | ||
469 | } | ||
423 | } | 470 | } |
471 | remoteClient.SendMapItemReply(mapitems.ToArray(), itemtype, flags); | ||
472 | } | ||
473 | else | ||
474 | { | ||
475 | // Remote Map Item Request | ||
424 | 476 | ||
477 | // ensures that the blockingqueue doesn't get borked if the GetAgents() timing changes. | ||
425 | RequestMapItems("",remoteClient.AgentId,flags,EstateID,godlike,itemtype,regionhandle); | 478 | RequestMapItems("",remoteClient.AgentId,flags,EstateID,godlike,itemtype,regionhandle); |
426 | } | 479 | } |
427 | } | 480 | } |
@@ -542,6 +595,28 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
542 | } | 595 | } |
543 | av.ControllingClient.SendMapItemReply(returnitems.ToArray(), mrs.itemtype, mrs.flags); | 596 | av.ControllingClient.SendMapItemReply(returnitems.ToArray(), mrs.itemtype, mrs.flags); |
544 | } | 597 | } |
598 | |||
599 | // Service 7 (MAP_ITEM_LAND_FOR_SALE) | ||
600 | uint itemtype = 7; | ||
601 | |||
602 | if (response.ContainsKey(itemtype.ToString())) | ||
603 | { | ||
604 | List<mapItemReply> returnitems = new List<mapItemReply>(); | ||
605 | OSDArray itemarray = (OSDArray)response[itemtype.ToString()]; | ||
606 | for (int i = 0; i < itemarray.Count; i++) | ||
607 | { | ||
608 | OSDMap mapitem = (OSDMap)itemarray[i]; | ||
609 | mapItemReply mi = new mapItemReply(); | ||
610 | mi.x = (uint)mapitem["X"].AsInteger(); | ||
611 | mi.y = (uint)mapitem["Y"].AsInteger(); | ||
612 | mi.id = mapitem["ID"].AsUUID(); | ||
613 | mi.Extra = mapitem["Extra"].AsInteger(); | ||
614 | mi.Extra2 = mapitem["Extra2"].AsInteger(); | ||
615 | mi.name = mapitem["Name"].AsString(); | ||
616 | returnitems.Add(mi); | ||
617 | } | ||
618 | av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, mrs.flags); | ||
619 | } | ||
545 | } | 620 | } |
546 | } | 621 | } |
547 | } | 622 | } |
@@ -589,12 +664,23 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
589 | private OSDMap RequestMapItemsAsync(UUID id, uint flags, | 664 | private OSDMap RequestMapItemsAsync(UUID id, uint flags, |
590 | uint EstateID, bool godlike, uint itemtype, ulong regionhandle) | 665 | uint EstateID, bool godlike, uint itemtype, ulong regionhandle) |
591 | { | 666 | { |
667 | // m_log.DebugFormat("[WORLDMAP]: RequestMapItemsAsync; region handle: {0} {1}", regionhandle, itemtype); | ||
668 | |||
592 | string httpserver = ""; | 669 | string httpserver = ""; |
593 | bool blacklisted = false; | 670 | bool blacklisted = false; |
594 | lock (m_blacklistedregions) | 671 | lock (m_blacklistedregions) |
595 | { | 672 | { |
596 | if (m_blacklistedregions.ContainsKey(regionhandle)) | 673 | if (m_blacklistedregions.ContainsKey(regionhandle)) |
597 | blacklisted = true; | 674 | { |
675 | if (Environment.TickCount > (m_blacklistedregions[regionhandle] + blacklistTimeout)) | ||
676 | { | ||
677 | m_log.DebugFormat("[WORLDMAP]: Unblock blacklisted region {0}", regionhandle); | ||
678 | |||
679 | m_blacklistedregions.Remove(regionhandle); | ||
680 | } | ||
681 | else | ||
682 | blacklisted = true; | ||
683 | } | ||
598 | } | 684 | } |
599 | 685 | ||
600 | if (blacklisted) | 686 | if (blacklisted) |
@@ -636,7 +722,16 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
636 | lock (m_blacklistedurls) | 722 | lock (m_blacklistedurls) |
637 | { | 723 | { |
638 | if (m_blacklistedurls.ContainsKey(httpserver)) | 724 | if (m_blacklistedurls.ContainsKey(httpserver)) |
639 | blacklisted = true; | 725 | { |
726 | if (Environment.TickCount > (m_blacklistedurls[httpserver] + blacklistTimeout)) | ||
727 | { | ||
728 | m_log.DebugFormat("[WORLDMAP]: Unblock blacklisted URL {0}", httpserver); | ||
729 | |||
730 | m_blacklistedurls.Remove(httpserver); | ||
731 | } | ||
732 | else | ||
733 | blacklisted = true; | ||
734 | } | ||
640 | } | 735 | } |
641 | 736 | ||
642 | // Can't find the http server | 737 | // Can't find the http server |
@@ -682,7 +777,6 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
682 | mapitemsrequest.ContentLength = buffer.Length; //Count bytes to send | 777 | mapitemsrequest.ContentLength = buffer.Length; //Count bytes to send |
683 | os = mapitemsrequest.GetRequestStream(); | 778 | os = mapitemsrequest.GetRequestStream(); |
684 | os.Write(buffer, 0, buffer.Length); //Send it | 779 | os.Write(buffer, 0, buffer.Length); //Send it |
685 | os.Close(); | ||
686 | //m_log.DebugFormat("[WORLD MAP]: Getting MapItems from {0}", httpserver); | 780 | //m_log.DebugFormat("[WORLD MAP]: Getting MapItems from {0}", httpserver); |
687 | } | 781 | } |
688 | catch (WebException ex) | 782 | catch (WebException ex) |
@@ -705,6 +799,11 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
705 | responseMap["connect"] = OSD.FromBoolean(false); | 799 | responseMap["connect"] = OSD.FromBoolean(false); |
706 | return responseMap; | 800 | return responseMap; |
707 | } | 801 | } |
802 | finally | ||
803 | { | ||
804 | if (os != null) | ||
805 | os.Close(); | ||
806 | } | ||
708 | 807 | ||
709 | string response_mapItems_reply = null; | 808 | string response_mapItems_reply = null; |
710 | { // get the response | 809 | { // get the response |
@@ -1060,6 +1159,8 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
1060 | 1159 | ||
1061 | Utils.LongToUInts(m_scene.RegionInfo.RegionHandle,out xstart,out ystart); | 1160 | Utils.LongToUInts(m_scene.RegionInfo.RegionHandle,out xstart,out ystart); |
1062 | 1161 | ||
1162 | // Service 6 (MAP_ITEM_AGENTS_LOCATION; green dots) | ||
1163 | |||
1063 | OSDMap responsemap = new OSDMap(); | 1164 | OSDMap responsemap = new OSDMap(); |
1064 | int tc = Environment.TickCount; | 1165 | int tc = Environment.TickCount; |
1065 | if (m_scene.GetRootAgentCount() == 0) | 1166 | if (m_scene.GetRootAgentCount() == 0) |
@@ -1092,6 +1193,60 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
1092 | }); | 1193 | }); |
1093 | responsemap["6"] = responsearr; | 1194 | responsemap["6"] = responsearr; |
1094 | } | 1195 | } |
1196 | |||
1197 | // Service 7 (MAP_ITEM_LAND_FOR_SALE) | ||
1198 | |||
1199 | ILandChannel landChannel = m_scene.LandChannel; | ||
1200 | List<ILandObject> parcels = landChannel.AllParcels(); | ||
1201 | |||
1202 | if ((parcels == null) || (parcels.Count == 0)) | ||
1203 | { | ||
1204 | OSDMap responsemapdata = new OSDMap(); | ||
1205 | responsemapdata["X"] = OSD.FromInteger((int)(xstart + 1)); | ||
1206 | responsemapdata["Y"] = OSD.FromInteger((int)(ystart + 1)); | ||
1207 | responsemapdata["ID"] = OSD.FromUUID(UUID.Zero); | ||
1208 | responsemapdata["Name"] = OSD.FromString(""); | ||
1209 | responsemapdata["Extra"] = OSD.FromInteger(0); | ||
1210 | responsemapdata["Extra2"] = OSD.FromInteger(0); | ||
1211 | OSDArray responsearr = new OSDArray(); | ||
1212 | responsearr.Add(responsemapdata); | ||
1213 | |||
1214 | responsemap["7"] = responsearr; | ||
1215 | } | ||
1216 | else | ||
1217 | { | ||
1218 | OSDArray responsearr = new OSDArray(m_scene.GetRootAgentCount()); | ||
1219 | foreach (ILandObject parcel_interface in parcels) | ||
1220 | { | ||
1221 | // Play it safe | ||
1222 | if (!(parcel_interface is LandObject)) | ||
1223 | continue; | ||
1224 | |||
1225 | LandObject land = (LandObject)parcel_interface; | ||
1226 | LandData parcel = land.LandData; | ||
1227 | |||
1228 | // Show land for sale | ||
1229 | if ((parcel.Flags & (uint)ParcelFlags.ForSale) == (uint)ParcelFlags.ForSale) | ||
1230 | { | ||
1231 | Vector3 min = parcel.AABBMin; | ||
1232 | Vector3 max = parcel.AABBMax; | ||
1233 | float x = (min.X+max.X)/2; | ||
1234 | float y = (min.Y+max.Y)/2; | ||
1235 | |||
1236 | OSDMap responsemapdata = new OSDMap(); | ||
1237 | responsemapdata["X"] = OSD.FromInteger((int)(xstart + x)); | ||
1238 | responsemapdata["Y"] = OSD.FromInteger((int)(ystart + y)); | ||
1239 | // responsemapdata["Z"] = OSD.FromInteger((int)m_scene.GetGroundHeight(x,y)); | ||
1240 | responsemapdata["ID"] = OSD.FromUUID(UUID.Zero); | ||
1241 | responsemapdata["Name"] = OSD.FromString(parcel.Name); | ||
1242 | responsemapdata["Extra"] = OSD.FromInteger(parcel.Area); | ||
1243 | responsemapdata["Extra2"] = OSD.FromInteger(parcel.SalePrice); | ||
1244 | responsearr.Add(responsemapdata); | ||
1245 | } | ||
1246 | } | ||
1247 | responsemap["7"] = responsearr; | ||
1248 | } | ||
1249 | |||
1095 | return responsemap; | 1250 | return responsemap; |
1096 | } | 1251 | } |
1097 | 1252 | ||
@@ -1110,14 +1265,12 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
1110 | if (data == null) | 1265 | if (data == null) |
1111 | return; | 1266 | return; |
1112 | 1267 | ||
1113 | UUID lastMapRegionUUID = m_scene.RegionInfo.RegionSettings.TerrainImageID; | ||
1114 | |||
1115 | m_log.Debug("[WORLDMAP]: STORING MAPTILE IMAGE"); | 1268 | m_log.Debug("[WORLDMAP]: STORING MAPTILE IMAGE"); |
1116 | 1269 | ||
1117 | m_scene.RegionInfo.RegionSettings.TerrainImageID = UUID.Random(); | 1270 | UUID terrainImageID = UUID.Random(); |
1118 | 1271 | ||
1119 | AssetBase asset = new AssetBase( | 1272 | AssetBase asset = new AssetBase( |
1120 | m_scene.RegionInfo.RegionSettings.TerrainImageID, | 1273 | terrainImageID, |
1121 | "terrainImage_" + m_scene.RegionInfo.RegionID.ToString(), | 1274 | "terrainImage_" + m_scene.RegionInfo.RegionID.ToString(), |
1122 | (sbyte)AssetType.Texture, | 1275 | (sbyte)AssetType.Texture, |
1123 | m_scene.RegionInfo.RegionID.ToString()); | 1276 | m_scene.RegionInfo.RegionID.ToString()); |
@@ -1129,6 +1282,10 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
1129 | // Store the new one | 1282 | // Store the new one |
1130 | m_log.DebugFormat("[WORLDMAP]: Storing map tile {0}", asset.ID); | 1283 | m_log.DebugFormat("[WORLDMAP]: Storing map tile {0}", asset.ID); |
1131 | m_scene.AssetService.Store(asset); | 1284 | m_scene.AssetService.Store(asset); |
1285 | |||
1286 | // Switch to the new one | ||
1287 | UUID lastMapRegionUUID = m_scene.RegionInfo.RegionSettings.TerrainImageID; | ||
1288 | m_scene.RegionInfo.RegionSettings.TerrainImageID = terrainImageID; | ||
1132 | m_scene.RegionInfo.RegionSettings.Save(); | 1289 | m_scene.RegionInfo.RegionSettings.Save(); |
1133 | 1290 | ||
1134 | // Delete the old one | 1291 | // Delete the old one |
@@ -1138,12 +1295,6 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
1138 | 1295 | ||
1139 | private void MakeRootAgent(ScenePresence avatar) | 1296 | private void MakeRootAgent(ScenePresence avatar) |
1140 | { | 1297 | { |
1141 | // You may ask, why this is in a threadpool to start with.. | ||
1142 | // The reason is so we don't cause the thread to freeze waiting | ||
1143 | // for the 1 second it costs to start a thread manually. | ||
1144 | if (!threadrunning) | ||
1145 | Util.FireAndForget(this.StartThread); | ||
1146 | |||
1147 | lock (m_rootAgents) | 1298 | lock (m_rootAgents) |
1148 | { | 1299 | { |
1149 | if (!m_rootAgents.Contains(avatar.UUID)) | 1300 | if (!m_rootAgents.Contains(avatar.UUID)) |
@@ -1158,8 +1309,30 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
1158 | lock (m_rootAgents) | 1309 | lock (m_rootAgents) |
1159 | { | 1310 | { |
1160 | m_rootAgents.Remove(avatar.UUID); | 1311 | m_rootAgents.Remove(avatar.UUID); |
1161 | if (m_rootAgents.Count == 0) | 1312 | } |
1162 | StopThread(); | 1313 | } |
1314 | |||
1315 | public void OnRegionUp(GridRegion otherRegion) | ||
1316 | { | ||
1317 | ulong regionhandle = otherRegion.RegionHandle; | ||
1318 | string httpserver = otherRegion.ServerURI + "MAP/MapItems/" + regionhandle.ToString(); | ||
1319 | |||
1320 | lock (m_blacklistedregions) | ||
1321 | { | ||
1322 | if (!m_blacklistedregions.ContainsKey(regionhandle)) | ||
1323 | m_blacklistedregions.Remove(regionhandle); | ||
1324 | } | ||
1325 | |||
1326 | lock (m_blacklistedurls) | ||
1327 | { | ||
1328 | if (m_blacklistedurls.ContainsKey(httpserver)) | ||
1329 | m_blacklistedurls.Remove(httpserver); | ||
1330 | } | ||
1331 | |||
1332 | lock (m_cachedRegionMapItemsAddress) | ||
1333 | { | ||
1334 | if (!m_cachedRegionMapItemsAddress.ContainsKey(regionhandle)) | ||
1335 | m_cachedRegionMapItemsAddress.Remove(regionhandle); | ||
1163 | } | 1336 | } |
1164 | } | 1337 | } |
1165 | 1338 | ||
diff --git a/OpenSim/Region/DataSnapshot/ObjectSnapshot.cs b/OpenSim/Region/DataSnapshot/ObjectSnapshot.cs index 5e75cae..0bb4044 100644 --- a/OpenSim/Region/DataSnapshot/ObjectSnapshot.cs +++ b/OpenSim/Region/DataSnapshot/ObjectSnapshot.cs | |||
@@ -118,59 +118,56 @@ namespace OpenSim.Region.DataSnapshot.Providers | |||
118 | { | 118 | { |
119 | SceneObjectPart m_rootPart = obj.RootPart; | 119 | SceneObjectPart m_rootPart = obj.RootPart; |
120 | 120 | ||
121 | if (m_rootPart != null) | 121 | ILandObject land = m_scene.LandChannel.GetLandObject(m_rootPart.AbsolutePosition.X, m_rootPart.AbsolutePosition.Y); |
122 | { | ||
123 | ILandObject land = m_scene.LandChannel.GetLandObject(m_rootPart.AbsolutePosition.X, m_rootPart.AbsolutePosition.Y); | ||
124 | 122 | ||
125 | XmlNode xmlobject = nodeFactory.CreateNode(XmlNodeType.Element, "object", ""); | 123 | XmlNode xmlobject = nodeFactory.CreateNode(XmlNodeType.Element, "object", ""); |
126 | node = nodeFactory.CreateNode(XmlNodeType.Element, "uuid", ""); | 124 | node = nodeFactory.CreateNode(XmlNodeType.Element, "uuid", ""); |
127 | node.InnerText = obj.UUID.ToString(); | 125 | node.InnerText = obj.UUID.ToString(); |
128 | xmlobject.AppendChild(node); | 126 | xmlobject.AppendChild(node); |
129 | 127 | ||
130 | node = nodeFactory.CreateNode(XmlNodeType.Element, "title", ""); | 128 | node = nodeFactory.CreateNode(XmlNodeType.Element, "title", ""); |
131 | node.InnerText = m_rootPart.Name; | 129 | node.InnerText = m_rootPart.Name; |
132 | xmlobject.AppendChild(node); | 130 | xmlobject.AppendChild(node); |
133 | |||
134 | node = nodeFactory.CreateNode(XmlNodeType.Element, "description", ""); | ||
135 | node.InnerText = m_rootPart.Description; | ||
136 | xmlobject.AppendChild(node); | ||
137 | 131 | ||
138 | node = nodeFactory.CreateNode(XmlNodeType.Element, "flags", ""); | 132 | node = nodeFactory.CreateNode(XmlNodeType.Element, "description", ""); |
139 | node.InnerText = String.Format("{0:x}", (uint)m_rootPart.Flags); | 133 | node.InnerText = m_rootPart.Description; |
140 | xmlobject.AppendChild(node); | 134 | xmlobject.AppendChild(node); |
141 | 135 | ||
142 | node = nodeFactory.CreateNode(XmlNodeType.Element, "regionuuid", ""); | 136 | node = nodeFactory.CreateNode(XmlNodeType.Element, "flags", ""); |
143 | node.InnerText = m_scene.RegionInfo.RegionSettings.RegionUUID.ToString(); | 137 | node.InnerText = String.Format("{0:x}", (uint)m_rootPart.Flags); |
144 | xmlobject.AppendChild(node); | 138 | xmlobject.AppendChild(node); |
145 | 139 | ||
146 | if (land != null && land.LandData != null) | 140 | node = nodeFactory.CreateNode(XmlNodeType.Element, "regionuuid", ""); |
147 | { | 141 | node.InnerText = m_scene.RegionInfo.RegionSettings.RegionUUID.ToString(); |
148 | node = nodeFactory.CreateNode(XmlNodeType.Element, "parceluuid", ""); | 142 | xmlobject.AppendChild(node); |
149 | node.InnerText = land.LandData.GlobalID.ToString(); | ||
150 | xmlobject.AppendChild(node); | ||
151 | } | ||
152 | else | ||
153 | { | ||
154 | // Something is wrong with this object. Let's not list it. | ||
155 | m_log.WarnFormat("[DATASNAPSHOT]: Bad data for object {0} ({1}) in region {2}", obj.Name, obj.UUID, m_scene.RegionInfo.RegionName); | ||
156 | continue; | ||
157 | } | ||
158 | 143 | ||
159 | node = nodeFactory.CreateNode(XmlNodeType.Element, "location", ""); | 144 | if (land != null && land.LandData != null) |
160 | Vector3 loc = obj.AbsolutePosition; | 145 | { |
161 | node.InnerText = loc.X.ToString() + "/" + loc.Y.ToString() + "/" + loc.Z.ToString(); | 146 | node = nodeFactory.CreateNode(XmlNodeType.Element, "parceluuid", ""); |
147 | node.InnerText = land.LandData.GlobalID.ToString(); | ||
162 | xmlobject.AppendChild(node); | 148 | xmlobject.AppendChild(node); |
149 | } | ||
150 | else | ||
151 | { | ||
152 | // Something is wrong with this object. Let's not list it. | ||
153 | m_log.WarnFormat("[DATASNAPSHOT]: Bad data for object {0} ({1}) in region {2}", obj.Name, obj.UUID, m_scene.RegionInfo.RegionName); | ||
154 | continue; | ||
155 | } | ||
163 | 156 | ||
164 | string bestImage = GuessImage(obj); | 157 | node = nodeFactory.CreateNode(XmlNodeType.Element, "location", ""); |
165 | if (bestImage != string.Empty) | 158 | Vector3 loc = obj.AbsolutePosition; |
166 | { | 159 | node.InnerText = loc.X.ToString() + "/" + loc.Y.ToString() + "/" + loc.Z.ToString(); |
167 | node = nodeFactory.CreateNode(XmlNodeType.Element, "image", ""); | 160 | xmlobject.AppendChild(node); |
168 | node.InnerText = bestImage; | ||
169 | xmlobject.AppendChild(node); | ||
170 | } | ||
171 | 161 | ||
172 | parent.AppendChild(xmlobject); | 162 | string bestImage = GuessImage(obj); |
163 | if (bestImage != string.Empty) | ||
164 | { | ||
165 | node = nodeFactory.CreateNode(XmlNodeType.Element, "image", ""); | ||
166 | node.InnerText = bestImage; | ||
167 | xmlobject.AppendChild(node); | ||
173 | } | 168 | } |
169 | |||
170 | parent.AppendChild(xmlobject); | ||
174 | } | 171 | } |
175 | #pragma warning disable 0612 | 172 | #pragma warning disable 0612 |
176 | } | 173 | } |
diff --git a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs index 7e4fa71..3b740e2 100644 --- a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs +++ b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs | |||
@@ -83,7 +83,7 @@ namespace OpenSim.Region.Examples.SimpleModule | |||
83 | public event DeRezObject OnDeRezObject; | 83 | public event DeRezObject OnDeRezObject; |
84 | public event Action<IClientAPI> OnRegionHandShakeReply; | 84 | public event Action<IClientAPI> OnRegionHandShakeReply; |
85 | public event GenericCall1 OnRequestWearables; | 85 | public event GenericCall1 OnRequestWearables; |
86 | public event GenericCall1 OnCompleteMovementToRegion; | 86 | public event Action<IClientAPI, bool> OnCompleteMovementToRegion; |
87 | public event UpdateAgent OnPreAgentUpdate; | 87 | public event UpdateAgent OnPreAgentUpdate; |
88 | public event UpdateAgent OnAgentUpdate; | 88 | public event UpdateAgent OnAgentUpdate; |
89 | public event AgentRequestSit OnAgentRequestSit; | 89 | public event AgentRequestSit OnAgentRequestSit; |
@@ -222,7 +222,7 @@ namespace OpenSim.Region.Examples.SimpleModule | |||
222 | public event ScriptReset OnScriptReset; | 222 | public event ScriptReset OnScriptReset; |
223 | public event GetScriptRunning OnGetScriptRunning; | 223 | public event GetScriptRunning OnGetScriptRunning; |
224 | public event SetScriptRunning OnSetScriptRunning; | 224 | public event SetScriptRunning OnSetScriptRunning; |
225 | public event UpdateVector OnAutoPilotGo; | 225 | public event Action<Vector3, bool> OnAutoPilotGo; |
226 | 226 | ||
227 | public event TerrainUnacked OnUnackedTerrain; | 227 | public event TerrainUnacked OnUnackedTerrain; |
228 | 228 | ||
@@ -663,7 +663,7 @@ namespace OpenSim.Region.Examples.SimpleModule | |||
663 | 663 | ||
664 | if (OnCompleteMovementToRegion != null) | 664 | if (OnCompleteMovementToRegion != null) |
665 | { | 665 | { |
666 | OnCompleteMovementToRegion(this); | 666 | OnCompleteMovementToRegion(this, true); |
667 | } | 667 | } |
668 | } | 668 | } |
669 | public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID) | 669 | public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID) |
diff --git a/OpenSim/Region/Examples/SimpleModule/RegionModule.cs b/OpenSim/Region/Examples/SimpleModule/RegionModule.cs index 088b818..3b8ce37 100644 --- a/OpenSim/Region/Examples/SimpleModule/RegionModule.cs +++ b/OpenSim/Region/Examples/SimpleModule/RegionModule.cs | |||
@@ -95,7 +95,7 @@ namespace OpenSim.Region.Examples.SimpleModule | |||
95 | for (int i = 0; i < 1; i++) | 95 | for (int i = 0; i < 1; i++) |
96 | { | 96 | { |
97 | MyNpcCharacter m_character = new MyNpcCharacter(m_scene); | 97 | MyNpcCharacter m_character = new MyNpcCharacter(m_scene); |
98 | m_scene.AddNewClient(m_character); | 98 | m_scene.AddNewClient(m_character, PresenceType.Npc); |
99 | m_scene.AgentCrossing(m_character.AgentId, Vector3.Zero, false); | 99 | m_scene.AgentCrossing(m_character.AgentId, Vector3.Zero, false); |
100 | } | 100 | } |
101 | 101 | ||
diff --git a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs index 788f42b..6bbdd7d 100644 --- a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs | |||
@@ -37,6 +37,27 @@ namespace OpenSim.Region.Framework.Interfaces | |||
37 | public interface IAttachmentsModule | 37 | public interface IAttachmentsModule |
38 | { | 38 | { |
39 | /// <summary> | 39 | /// <summary> |
40 | /// RezAttachments. This should only be called upon login on the first region. | ||
41 | /// Attachment rezzings on crossings and TPs are done in a different way. | ||
42 | /// </summary> | ||
43 | void RezAttachments(IScenePresence sp); | ||
44 | |||
45 | /// <summary> | ||
46 | /// Save the attachments that have change on this presence. | ||
47 | /// </summary> | ||
48 | /// <param name="sp"></param> | ||
49 | void SaveChangedAttachments(IScenePresence sp); | ||
50 | |||
51 | /// <summary> | ||
52 | /// Delete all the presence's attachments from the scene | ||
53 | /// </summary> | ||
54 | /// <param name="sp"> | ||
55 | /// This is done when a root agent leaves/is demoted to child (for instance, on logout, teleport or region cross). | ||
56 | /// </param> | ||
57 | /// <param name="silent"></param> | ||
58 | void DeleteAttachmentsFromScene(IScenePresence sp, bool silent); | ||
59 | |||
60 | /// <summary> | ||
40 | /// Attach an object to an avatar from the world. | 61 | /// Attach an object to an avatar from the world. |
41 | /// </summary> | 62 | /// </summary> |
42 | /// <param name="controllingClient"></param> | 63 | /// <param name="controllingClient"></param> |
@@ -48,13 +69,11 @@ namespace OpenSim.Region.Framework.Interfaces | |||
48 | IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, bool silent); | 69 | IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, bool silent); |
49 | 70 | ||
50 | /// <summary> | 71 | /// <summary> |
51 | /// Attach an object to an avatar. | 72 | /// Attach an object to an avatar |
52 | /// </summary> | 73 | /// </summary> |
53 | /// <param name="controllingClient"></param> | 74 | /// <param name="remoteClient"></param> |
54 | /// <param name="localID"></param> | 75 | /// <param name="grp"></param> |
55 | /// <param name="attachPoint"></param> | 76 | /// <param name="AttachmentPt"></param> |
56 | /// <param name="rot"></param> | ||
57 | /// <param name="attachPos"></param> | ||
58 | /// <param name="silent"></param> | 77 | /// <param name="silent"></param> |
59 | /// <returns>true if the object was successfully attached, false otherwise</returns> | 78 | /// <returns>true if the object was successfully attached, false otherwise</returns> |
60 | bool AttachObject( | 79 | bool AttachObject( |
@@ -67,7 +86,7 @@ namespace OpenSim.Region.Framework.Interfaces | |||
67 | /// <param name="itemID"></param> | 86 | /// <param name="itemID"></param> |
68 | /// <param name="AttachmentPt"></param> | 87 | /// <param name="AttachmentPt"></param> |
69 | /// <returns>The scene object that was attached. Null if the scene object could not be found</returns> | 88 | /// <returns>The scene object that was attached. Null if the scene object could not be found</returns> |
70 | UUID RezSingleAttachmentFromInventory(IClientAPI remoteClient, UUID itemID, uint AttachmentPt); | 89 | ISceneEntity RezSingleAttachmentFromInventory(IClientAPI remoteClient, UUID itemID, uint AttachmentPt); |
71 | 90 | ||
72 | /// <summary> | 91 | /// <summary> |
73 | /// Rez an attachment from user inventory | 92 | /// Rez an attachment from user inventory |
@@ -80,7 +99,7 @@ namespace OpenSim.Region.Framework.Interfaces | |||
80 | /// False is required so that we don't attempt to update information when a user enters a scene with the | 99 | /// False is required so that we don't attempt to update information when a user enters a scene with the |
81 | /// attachment already correctly set up in inventory. | 100 | /// attachment already correctly set up in inventory. |
82 | /// <returns>The uuid of the scene object that was attached. Null if the scene object could not be found</returns> | 101 | /// <returns>The uuid of the scene object that was attached. Null if the scene object could not be found</returns> |
83 | UUID RezSingleAttachmentFromInventory( | 102 | ISceneEntity RezSingleAttachmentFromInventory( |
84 | IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus); | 103 | IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus); |
85 | 104 | ||
86 | // Same as above, but also load script states from a separate doc | 105 | // Same as above, but also load script states from a separate doc |
@@ -101,9 +120,10 @@ namespace OpenSim.Region.Framework.Interfaces | |||
101 | /// <summary> | 120 | /// <summary> |
102 | /// Detach an object from the avatar. | 121 | /// Detach an object from the avatar. |
103 | /// </summary> | 122 | /// </summary> |
104 | /// | 123 | /// <remarks> |
105 | /// This method is called in response to a client's detach request, so we only update the information in | 124 | /// This method is called in response to a client's detach request, so we only update the information in |
106 | /// inventory | 125 | /// inventory |
126 | /// </remarks> | ||
107 | /// <param name="objectLocalID"></param> | 127 | /// <param name="objectLocalID"></param> |
108 | /// <param name="remoteClient"></param> | 128 | /// <param name="remoteClient"></param> |
109 | void DetachObject(uint objectLocalID, IClientAPI remoteClient); | 129 | void DetachObject(uint objectLocalID, IClientAPI remoteClient); |
@@ -111,12 +131,12 @@ namespace OpenSim.Region.Framework.Interfaces | |||
111 | /// <summary> | 131 | /// <summary> |
112 | /// Detach the given item to the ground. | 132 | /// Detach the given item to the ground. |
113 | /// </summary> | 133 | /// </summary> |
114 | /// <param name="itemID"></param> | 134 | /// <param name="objectLocalID"></param> |
115 | /// <param name="remoteClient"></param> | 135 | /// <param name="remoteClient"></param> |
116 | void DetachSingleAttachmentToGround(UUID itemID, IClientAPI remoteClient); | 136 | void DetachSingleAttachmentToGround(uint objectLocalID, IClientAPI remoteClient); |
117 | 137 | ||
118 | /// <summary> | 138 | /// <summary> |
119 | /// Update the user inventory to show a detach. | 139 | /// Detach the given item so that it remains in the user's inventory. |
120 | /// </summary> | 140 | /// </summary> |
121 | /// <param name="itemID"> | 141 | /// <param name="itemID"> |
122 | /// A <see cref="UUID"/> | 142 | /// A <see cref="UUID"/> |
@@ -124,23 +144,15 @@ namespace OpenSim.Region.Framework.Interfaces | |||
124 | /// <param name="remoteClient"> | 144 | /// <param name="remoteClient"> |
125 | /// A <see cref="IClientAPI"/> | 145 | /// A <see cref="IClientAPI"/> |
126 | /// </param> | 146 | /// </param> |
127 | void ShowDetachInUserInventory(UUID itemID, IClientAPI remoteClient); | 147 | void DetachSingleAttachmentToInv(UUID itemID, IClientAPI remoteClient); |
128 | 148 | ||
129 | /// <summary> | 149 | /// <summary> |
130 | /// Update the user inventory with a changed attachment | 150 | /// Update the user inventory with a changed attachment |
131 | /// </summary> | 151 | /// </summary> |
132 | /// <param name="remoteClient"> | 152 | /// <param name="remoteClient"></param> |
133 | /// A <see cref="IClientAPI"/> | 153 | /// <param name="grp"></param> |
134 | /// </param> | 154 | /// <param name="itemID"></param> |
135 | /// <param name="grp"> | 155 | /// <param name="agentID"></param> |
136 | /// A <see cref="SceneObjectGroup"/> | ||
137 | /// </param> | ||
138 | /// <param name="itemID"> | ||
139 | /// A <see cref="UUID"/> | ||
140 | /// </param> | ||
141 | /// <param name="agentID"> | ||
142 | /// A <see cref="UUID"/> | ||
143 | /// </param> | ||
144 | void UpdateKnownItem(IClientAPI remoteClient, SceneObjectGroup grp, UUID itemID, UUID agentID); | 156 | void UpdateKnownItem(IClientAPI remoteClient, SceneObjectGroup grp, UUID itemID, UUID agentID); |
145 | } | 157 | } |
146 | } | 158 | } |
diff --git a/OpenSim/Region/Framework/Interfaces/IAvatarFactory.cs b/OpenSim/Region/Framework/Interfaces/IAvatarFactory.cs index d0e5609..4dbddf4 100644 --- a/OpenSim/Region/Framework/Interfaces/IAvatarFactory.cs +++ b/OpenSim/Region/Framework/Interfaces/IAvatarFactory.cs | |||
@@ -25,6 +25,7 @@ | |||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System.Collections.Generic; | ||
28 | using OpenMetaverse; | 29 | using OpenMetaverse; |
29 | using OpenSim.Framework; | 30 | using OpenSim.Framework; |
30 | 31 | ||
@@ -32,6 +33,30 @@ namespace OpenSim.Region.Framework.Interfaces | |||
32 | { | 33 | { |
33 | public interface IAvatarFactory | 34 | public interface IAvatarFactory |
34 | { | 35 | { |
36 | /// <summary> | ||
37 | /// Send the appearance of an avatar to others in the scene. | ||
38 | /// </summary> | ||
39 | /// <param name="agentId"></param> | ||
40 | /// <returns></returns> | ||
41 | bool SendAppearance(UUID agentId); | ||
42 | |||
43 | /// <summary> | ||
44 | /// Return the baked texture ids of the given agent. | ||
45 | /// </summary> | ||
46 | /// <param name="agentId"></param> | ||
47 | /// <returns>An empty list if this agent has no baked textures (e.g. because it's a child agent)</returns> | ||
48 | Dictionary<BakeType, Primitive.TextureEntryFace> GetBakedTextureFaces(UUID agentId); | ||
49 | |||
50 | /// <summary> | ||
51 | /// Save the baked textures for the given agent permanently in the asset database. | ||
52 | /// </summary> | ||
53 | /// <remarks> | ||
54 | /// This is used to preserve apperance textures for NPCs | ||
55 | /// </remarks> | ||
56 | /// <param name="agentId"></param> | ||
57 | /// <returns>true if a valid agent was found, false otherwise</returns> | ||
58 | bool SaveBakedTextures(UUID agentId); | ||
59 | |||
35 | bool ValidateBakedTextureCache(IClientAPI client); | 60 | bool ValidateBakedTextureCache(IClientAPI client); |
36 | void QueueAppearanceSend(UUID agentid); | 61 | void QueueAppearanceSend(UUID agentid); |
37 | void QueueAppearanceSave(UUID agentid); | 62 | void QueueAppearanceSave(UUID agentid); |
diff --git a/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs b/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs index da11e61..1904011 100644 --- a/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs | |||
@@ -54,10 +54,58 @@ namespace OpenSim.Region.Framework.Interfaces | |||
54 | /// FIXME: This is not very useful. It would be far more useful to return a list of items instead. | 54 | /// FIXME: This is not very useful. It would be far more useful to return a list of items instead. |
55 | /// </returns> | 55 | /// </returns> |
56 | UUID CopyToInventory(DeRezAction action, UUID folderID, List<SceneObjectGroup> objectGroups, IClientAPI remoteClient); | 56 | UUID CopyToInventory(DeRezAction action, UUID folderID, List<SceneObjectGroup> objectGroups, IClientAPI remoteClient); |
57 | 57 | ||
58 | SceneObjectGroup RezObject(IClientAPI remoteClient, UUID itemID, Vector3 RayEnd, Vector3 RayStart, | 58 | /// <summary> |
59 | UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, | 59 | /// Rez an object into the scene from the user's inventory |
60 | bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment); | 60 | /// </summary> |
61 | /// <remarks> | ||
62 | /// FIXME: It would be really nice if inventory access modules didn't also actually do the work of rezzing | ||
63 | /// things to the scene. The caller should be doing that, I think. | ||
64 | /// </remarks> | ||
65 | /// <param name="remoteClient"></param> | ||
66 | /// <param name="itemID"></param> | ||
67 | /// <param name="RayEnd"></param> | ||
68 | /// <param name="RayStart"></param> | ||
69 | /// <param name="RayTargetID"></param> | ||
70 | /// <param name="BypassRayCast"></param> | ||
71 | /// <param name="RayEndIsIntersection"></param> | ||
72 | /// <param name="RezSelected"></param> | ||
73 | /// <param name="RemoveItem"></param> | ||
74 | /// <param name="fromTaskID"></param> | ||
75 | /// <param name="attachment"></param> | ||
76 | /// <returns>The SceneObjectGroup rezzed or null if rez was unsuccessful.</returns> | ||
77 | SceneObjectGroup RezObject( | ||
78 | IClientAPI remoteClient, UUID itemID, Vector3 RayEnd, Vector3 RayStart, | ||
79 | UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, | ||
80 | bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment); | ||
81 | |||
82 | /// <summary> | ||
83 | /// Rez an object into the scene from the user's inventory | ||
84 | /// </summary> | ||
85 | /// <remarks> | ||
86 | /// FIXME: It would be really nice if inventory access modules didn't also actually do the work of rezzing | ||
87 | /// things to the scene. The caller should be doing that, I think. | ||
88 | /// </remarks> | ||
89 | /// <param name="remoteClient"></param> | ||
90 | /// <param name="item"> | ||
91 | /// The item from which the object asset came. Can be null, in which case pre and post rez item adjustment and checks are not performed. | ||
92 | /// </param> | ||
93 | /// <param name="assetID">The asset id for the object to rez.</param> | ||
94 | /// <param name="RayEnd"></param> | ||
95 | /// <param name="RayStart"></param> | ||
96 | /// <param name="RayTargetID"></param> | ||
97 | /// <param name="BypassRayCast"></param> | ||
98 | /// <param name="RayEndIsIntersection"></param> | ||
99 | /// <param name="RezSelected"></param> | ||
100 | /// <param name="RemoveItem"></param> | ||
101 | /// <param name="fromTaskID"></param> | ||
102 | /// <param name="attachment"></param> | ||
103 | /// <returns>The SceneObjectGroup rezzed or null if rez was unsuccessful.</returns> | ||
104 | SceneObjectGroup RezObject( | ||
105 | IClientAPI remoteClient, InventoryItemBase item, UUID assetID, Vector3 RayEnd, Vector3 RayStart, | ||
106 | UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, | ||
107 | bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment); | ||
108 | |||
61 | void TransferInventoryAssets(InventoryItemBase item, UUID sender, UUID receiver); | 109 | void TransferInventoryAssets(InventoryItemBase item, UUID sender, UUID receiver); |
62 | 110 | ||
63 | /// <summary> | 111 | /// <summary> |
diff --git a/OpenSim/Region/Framework/Interfaces/INPCModule.cs b/OpenSim/Region/Framework/Interfaces/INPCModule.cs index 21a755f..5e5c4a1 100644 --- a/OpenSim/Region/Framework/Interfaces/INPCModule.cs +++ b/OpenSim/Region/Framework/Interfaces/INPCModule.cs | |||
@@ -26,15 +26,80 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using OpenMetaverse; | 28 | using OpenMetaverse; |
29 | using OpenSim.Framework; | ||
29 | using OpenSim.Region.Framework.Scenes; | 30 | using OpenSim.Region.Framework.Scenes; |
30 | 31 | ||
31 | namespace OpenSim.Region.Framework.Interfaces | 32 | namespace OpenSim.Region.Framework.Interfaces |
32 | { | 33 | { |
33 | public interface INPCModule | 34 | public interface INPCModule |
34 | { | 35 | { |
35 | UUID CreateNPC(string firstname, string lastname, Vector3 position, Scene scene, UUID cloneAppearanceFrom); | 36 | /// <summary> |
36 | void Autopilot(UUID agentID, Scene scene, Vector3 pos); | 37 | /// Create an NPC |
37 | void Say(UUID agentID, Scene scene, string text); | 38 | /// </summary> |
38 | void DeleteNPC(UUID agentID, Scene scene); | 39 | /// <param name="firstname"></param> |
40 | /// <param name="lastname"></param> | ||
41 | /// <param name="position"></param> | ||
42 | /// <param name="scene"></param> | ||
43 | /// <param name="appearance">The avatar appearance to use for the new NPC.</param> | ||
44 | /// <returns>The UUID of the ScenePresence created.</returns> | ||
45 | UUID CreateNPC(string firstname, string lastname, Vector3 position, Scene scene, AvatarAppearance appearance); | ||
46 | |||
47 | /// <summary> | ||
48 | /// Check if the agent is an NPC. | ||
49 | /// </summary> | ||
50 | /// <param name="agentID"></param> | ||
51 | /// <param name="scene"></param> | ||
52 | /// <returns>True if the agent is an NPC in the given scene. False otherwise.</returns> | ||
53 | bool IsNPC(UUID agentID, Scene scene); | ||
54 | |||
55 | /// <summary> | ||
56 | /// Set the appearance for an NPC. | ||
57 | /// </summary> | ||
58 | /// <param name="agentID"></param> | ||
59 | /// <param name="appearance"></param> | ||
60 | /// <param name="scene"></param> | ||
61 | /// <returns>True if the operation succeeded, false if there was no such agent or the agent was not an NPC</returns> | ||
62 | bool SetNPCAppearance(UUID agentID, AvatarAppearance appearance, Scene scene); | ||
63 | |||
64 | /// <summary> | ||
65 | /// Move an NPC to a target over time. | ||
66 | /// </summary> | ||
67 | /// <param name="agentID">The UUID of the NPC</param> | ||
68 | /// <param name="scene"></param> | ||
69 | /// <param name="pos"></param> | ||
70 | /// <param name="noFly"> | ||
71 | /// If true, then the avatar will attempt to walk to the location even if it's up in the air. | ||
72 | /// This is to allow walking on prims. | ||
73 | /// </param> | ||
74 | /// <param name="landAtTarget"> | ||
75 | /// If true and the avatar is flying when it reaches the target, land. | ||
76 | /// </param> | ||
77 | /// <returns>True if the operation succeeded, false if there was no such agent or the agent was not an NPC</returns> | ||
78 | bool MoveToTarget(UUID agentID, Scene scene, Vector3 pos, bool noFly, bool landAtTarget); | ||
79 | |||
80 | /// <summary> | ||
81 | /// Stop the NPC's current movement. | ||
82 | /// </summary> | ||
83 | /// <param name="agentID">The UUID of the NPC</param> | ||
84 | /// <param name="scene"></param> | ||
85 | /// <returns>True if the operation succeeded, false if there was no such agent or the agent was not an NPC</returns> | ||
86 | bool StopMoveToTarget(UUID agentID, Scene scene); | ||
87 | |||
88 | /// <summary> | ||
89 | /// Get the NPC to say something. | ||
90 | /// </summary> | ||
91 | /// <param name="agentID">The UUID of the NPC</param> | ||
92 | /// <param name="scene"></param> | ||
93 | /// <param name="text"></param> | ||
94 | /// <returns>True if the operation succeeded, false if there was no such agent or the agent was not an NPC</returns> | ||
95 | bool Say(UUID agentID, Scene scene, string text); | ||
96 | |||
97 | /// <summary> | ||
98 | /// Delete an NPC. | ||
99 | /// </summary> | ||
100 | /// <param name="agentID">The UUID of the NPC</param> | ||
101 | /// <param name="scene"></param> | ||
102 | /// <returns>True if the operation succeeded, false if there was no such agent or the agent was not an NPC</returns> | ||
103 | bool DeleteNPC(UUID agentID, Scene scene); | ||
39 | } | 104 | } |
40 | } \ No newline at end of file | 105 | } \ No newline at end of file |
diff --git a/OpenSim/Region/Framework/Interfaces/IScenePresence.cs b/OpenSim/Region/Framework/Interfaces/IScenePresence.cs new file mode 100644 index 0000000..8913133 --- /dev/null +++ b/OpenSim/Region/Framework/Interfaces/IScenePresence.cs | |||
@@ -0,0 +1,88 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using OpenSim.Framework; | ||
31 | using OpenSim.Region.Framework.Scenes; | ||
32 | |||
33 | namespace OpenSim.Region.Framework.Interfaces | ||
34 | { | ||
35 | /// <summary> | ||
36 | /// An agent in the scene. | ||
37 | /// </summary> | ||
38 | /// <remarks> | ||
39 | /// Interface is a work in progress. Please feel free to add other required properties and methods. | ||
40 | /// </remarks> | ||
41 | public interface IScenePresence : ISceneEntity | ||
42 | { | ||
43 | /// <value> | ||
44 | /// The client controlling this presence | ||
45 | /// </value> | ||
46 | IClientAPI ControllingClient { get; } | ||
47 | |||
48 | /// <summary> | ||
49 | /// What type of presence is this? User, NPC, etc. | ||
50 | /// </summary> | ||
51 | PresenceType PresenceType { get; } | ||
52 | |||
53 | /// <summary> | ||
54 | /// Avatar appearance data. | ||
55 | /// </summary> | ||
56 | /// <remarks> | ||
57 | // Because appearance setting is in a module, we actually need | ||
58 | // to give it access to our appearance directly, otherwise we | ||
59 | // get a synchronization issue. | ||
60 | /// </remarks> | ||
61 | AvatarAppearance Appearance { get; set; } | ||
62 | |||
63 | /// <summary> | ||
64 | /// The scene objects attached to this avatar. | ||
65 | /// </summary> | ||
66 | /// <returns> | ||
67 | /// A copy of the list. | ||
68 | /// </returns> | ||
69 | /// <remarks> | ||
70 | /// Do not change this list directly - use the attachments module. | ||
71 | /// </remarks> | ||
72 | List<SceneObjectGroup> GetAttachments(); | ||
73 | |||
74 | /// <summary> | ||
75 | /// The scene objects attached to this avatar at a specific attachment point. | ||
76 | /// </summary> | ||
77 | /// <param name="attachmentPoint"></param> | ||
78 | /// <returns></returns> | ||
79 | List<SceneObjectGroup> GetAttachments(uint attachmentPoint); | ||
80 | |||
81 | bool HasAttachments(); | ||
82 | |||
83 | // Don't use these methods directly. Instead, use the AttachmentsModule | ||
84 | void AddAttachment(SceneObjectGroup gobj); | ||
85 | void RemoveAttachment(SceneObjectGroup gobj); | ||
86 | void ClearAttachments(); | ||
87 | } | ||
88 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/Framework/Interfaces/ISimulatorFeaturesModule.cs b/OpenSim/Region/Framework/Interfaces/ISimulatorFeaturesModule.cs new file mode 100644 index 0000000..8cef14e --- /dev/null +++ b/OpenSim/Region/Framework/Interfaces/ISimulatorFeaturesModule.cs | |||
@@ -0,0 +1,43 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using OpenMetaverse.StructuredData; | ||
30 | |||
31 | namespace OpenSim.Region.Framework.Interfaces | ||
32 | { | ||
33 | /// <summary> | ||
34 | /// Add remove or retrieve Simulator Features that will be given to a viewer via the SimulatorFeatures capability. | ||
35 | /// </summary> | ||
36 | public interface ISimulatorFeaturesModule | ||
37 | { | ||
38 | void AddFeature(string name, OSD value); | ||
39 | bool RemoveFeature(string name); | ||
40 | bool TryGetFeature(string name, out OSD value); | ||
41 | OSDMap GetFeatures(); | ||
42 | } | ||
43 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/Framework/Interfaces/IUserManagement.cs b/OpenSim/Region/Framework/Interfaces/IUserManagement.cs index 5d30aa8..c66e053 100644 --- a/OpenSim/Region/Framework/Interfaces/IUserManagement.cs +++ b/OpenSim/Region/Framework/Interfaces/IUserManagement.cs | |||
@@ -5,13 +5,48 @@ using OpenMetaverse; | |||
5 | 5 | ||
6 | namespace OpenSim.Region.Framework.Interfaces | 6 | namespace OpenSim.Region.Framework.Interfaces |
7 | { | 7 | { |
8 | /// <summary> | ||
9 | /// This maintains the relationship between a UUID and a user name. | ||
10 | /// </summary> | ||
8 | public interface IUserManagement | 11 | public interface IUserManagement |
9 | { | 12 | { |
10 | string GetUserName(UUID uuid); | 13 | string GetUserName(UUID uuid); |
11 | string GetUserHomeURL(UUID uuid); | 14 | string GetUserHomeURL(UUID uuid); |
12 | string GetUserUUI(UUID uuid); | 15 | string GetUserUUI(UUID uuid); |
13 | string GetUserServerURL(UUID uuid, string serverType); | 16 | string GetUserServerURL(UUID uuid, string serverType); |
14 | void AddUser(UUID uuid, string userData); | 17 | |
18 | /// <summary> | ||
19 | /// Add a user. | ||
20 | /// </summary> | ||
21 | /// <remarks> | ||
22 | /// If an account is found for the UUID, then the names in this will be used rather than any information | ||
23 | /// extracted from creatorData. | ||
24 | /// </remarks> | ||
25 | /// <param name="uuid"></param> | ||
26 | /// <param name="creatorData">The creator data for this user.</param> | ||
27 | void AddUser(UUID uuid, string creatorData); | ||
28 | |||
29 | /// <summary> | ||
30 | /// Add a user. | ||
31 | /// </summary> | ||
32 | /// <remarks> | ||
33 | /// The UUID is related to the name without any other checks being performed, such as user account presence. | ||
34 | /// </remarks> | ||
35 | /// <param name="uuid"></param> | ||
36 | /// <param name="firstName"></param> | ||
37 | /// <param name="lastName"></param> | ||
38 | void AddUser(UUID uuid, string firstName, string lastName); | ||
39 | |||
40 | /// <summary> | ||
41 | /// Add a user. | ||
42 | /// </summary> | ||
43 | /// <remarks> | ||
44 | /// The arguments apart from uuid are formed into a creatorData string and processing proceeds as for the | ||
45 | /// AddUser(UUID uuid, string creatorData) method. | ||
46 | /// </remarks> | ||
47 | /// <param name="uuid"></param> | ||
48 | /// <param name="firstName"></param> | ||
49 | /// <param name="profileURL"></param> | ||
15 | void AddUser(UUID uuid, string firstName, string lastName, string profileURL); | 50 | void AddUser(UUID uuid, string firstName, string lastName, string profileURL); |
16 | } | 51 | } |
17 | } | 52 | } |
diff --git a/OpenSim/Region/Framework/Interfaces/IWorldComm.cs b/OpenSim/Region/Framework/Interfaces/IWorldComm.cs index 8da99a0..dafbf30 100644 --- a/OpenSim/Region/Framework/Interfaces/IWorldComm.cs +++ b/OpenSim/Region/Framework/Interfaces/IWorldComm.cs | |||
@@ -81,6 +81,26 @@ namespace OpenSim.Region.Framework.Interfaces | |||
81 | void DeliverMessage(ChatTypeEnum type, int channel, string name, UUID id, string msg); | 81 | void DeliverMessage(ChatTypeEnum type, int channel, string name, UUID id, string msg); |
82 | 82 | ||
83 | /// <summary> | 83 | /// <summary> |
84 | /// Delivers the message to a specified object in the region. | ||
85 | /// </summary> | ||
86 | /// <param name='target'> | ||
87 | /// Target. | ||
88 | /// </param> | ||
89 | /// <param name='channel'> | ||
90 | /// Channel. | ||
91 | /// </param> | ||
92 | /// <param name='name'> | ||
93 | /// Name. | ||
94 | /// </param> | ||
95 | /// <param name='id'> | ||
96 | /// Identifier. | ||
97 | /// </param> | ||
98 | /// <param name='msg'> | ||
99 | /// Message. | ||
100 | /// </param> | ||
101 | bool DeliverMessageTo(UUID target, int channel, Vector3 pos, string name, UUID id, string msg, out string error); | ||
102 | |||
103 | /// <summary> | ||
84 | /// Are there any listen events ready to be dispatched? | 104 | /// Are there any listen events ready to be dispatched? |
85 | /// </summary> | 105 | /// </summary> |
86 | /// <returns>boolean indication</returns> | 106 | /// <returns>boolean indication</returns> |
diff --git a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs index 9c103cb..4925175 100644 --- a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs +++ b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs | |||
@@ -27,6 +27,8 @@ | |||
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Reflection; | ||
31 | using log4net; | ||
30 | using OpenMetaverse; | 32 | using OpenMetaverse; |
31 | using OpenSim.Framework; | 33 | using OpenSim.Framework; |
32 | using OpenSim.Region.Framework.Interfaces; | 34 | using OpenSim.Region.Framework.Interfaces; |
@@ -40,6 +42,8 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
40 | /// </summary> | 42 | /// </summary> |
41 | public class ScenePresenceAnimator | 43 | public class ScenePresenceAnimator |
42 | { | 44 | { |
45 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
46 | |||
43 | public AnimationSet Animations | 47 | public AnimationSet Animations |
44 | { | 48 | { |
45 | get { return m_animations; } | 49 | get { return m_animations; } |
@@ -79,6 +83,8 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
79 | if (m_scenePresence.IsChildAgent) | 83 | if (m_scenePresence.IsChildAgent) |
80 | return; | 84 | return; |
81 | 85 | ||
86 | // m_log.DebugFormat("[SCENE PRESENCE ANIMATOR]: Adding animation {0} for {1}", animID, m_scenePresence.Name); | ||
87 | |||
82 | if (m_animations.Add(animID, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, objectID)) | 88 | if (m_animations.Add(animID, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, objectID)) |
83 | SendAnimPack(); | 89 | SendAnimPack(); |
84 | } | 90 | } |
@@ -93,6 +99,8 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
93 | if (animID == UUID.Zero) | 99 | if (animID == UUID.Zero) |
94 | return; | 100 | return; |
95 | 101 | ||
102 | // m_log.DebugFormat("[SCENE PRESENCE ANIMATOR]: Adding animation {0} {1} for {2}", animID, name, m_scenePresence.Name); | ||
103 | |||
96 | AddAnimation(animID, objectID); | 104 | AddAnimation(animID, objectID); |
97 | } | 105 | } |
98 | 106 | ||
@@ -136,6 +144,10 @@ TrySetMovementAnimation("STAND"); | |||
136 | if (m_animations.TrySetDefaultAnimation( | 144 | if (m_animations.TrySetDefaultAnimation( |
137 | anim, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, m_scenePresence.UUID)) | 145 | anim, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, m_scenePresence.UUID)) |
138 | { | 146 | { |
147 | // m_log.DebugFormat( | ||
148 | // "[SCENE PRESENCE ANIMATOR]: Updating movement animation to {0} for {1}", | ||
149 | // anim, m_scenePresence.Name); | ||
150 | |||
139 | // 16384 is CHANGED_ANIMATION | 151 | // 16384 is CHANGED_ANIMATION |
140 | m_scenePresence.SendScriptEventToAttachments("changed", new Object[] { (int)Changed.ANIMATION}); | 152 | m_scenePresence.SendScriptEventToAttachments("changed", new Object[] { (int)Changed.ANIMATION}); |
141 | SendAnimPack(); | 153 | SendAnimPack(); |
@@ -353,7 +365,7 @@ TrySetMovementAnimation("STAND"); | |||
353 | /* This section removed, replaced by jumping section | 365 | /* This section removed, replaced by jumping section |
354 | m_animTickFall = 0; | 366 | m_animTickFall = 0; |
355 | 367 | ||
356 | if (move.Z > 0f) | 368 | if (move.Z > 0.2f) |
357 | { | 369 | { |
358 | // Jumping | 370 | // Jumping |
359 | if (!jumping) | 371 | if (!jumping) |
diff --git a/OpenSim/Region/Framework/Scenes/AsyncInventorySender.cs b/OpenSim/Region/Framework/Scenes/AsyncInventorySender.cs index 06cd14b..9cb5674 100644 --- a/OpenSim/Region/Framework/Scenes/AsyncInventorySender.cs +++ b/OpenSim/Region/Framework/Scenes/AsyncInventorySender.cs | |||
@@ -70,7 +70,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
70 | /// </remarks> | 70 | /// </remarks> |
71 | public class AsyncInventorySender | 71 | public class AsyncInventorySender |
72 | { | 72 | { |
73 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 73 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
74 | 74 | ||
75 | protected Scene m_scene; | 75 | protected Scene m_scene; |
76 | 76 | ||
diff --git a/OpenSim/Region/Framework/Scenes/EntityBase.cs b/OpenSim/Region/Framework/Scenes/EntityBase.cs index 6fd38e5..213431a 100644 --- a/OpenSim/Region/Framework/Scenes/EntityBase.cs +++ b/OpenSim/Region/Framework/Scenes/EntityBase.cs | |||
@@ -66,12 +66,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
66 | /// <summary> | 66 | /// <summary> |
67 | /// Signals whether this entity was in a scene but has since been removed from it. | 67 | /// Signals whether this entity was in a scene but has since been removed from it. |
68 | /// </summary> | 68 | /// </summary> |
69 | public bool IsDeleted | 69 | public bool IsDeleted { get; protected internal set; } |
70 | { | ||
71 | get { return m_isDeleted; } | ||
72 | set { m_isDeleted = value; } | ||
73 | } | ||
74 | protected bool m_isDeleted; | ||
75 | 70 | ||
76 | protected Vector3 m_pos; | 71 | protected Vector3 m_pos; |
77 | 72 | ||
diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs index 3ec4e59..65c6a29 100644 --- a/OpenSim/Region/Framework/Scenes/EventManager.cs +++ b/OpenSim/Region/Framework/Scenes/EventManager.cs | |||
@@ -169,8 +169,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
169 | public delegate void AvatarEnteringNewParcel(ScenePresence avatar, int localLandID, UUID regionID); | 169 | public delegate void AvatarEnteringNewParcel(ScenePresence avatar, int localLandID, UUID regionID); |
170 | public event AvatarEnteringNewParcel OnAvatarEnteringNewParcel; | 170 | public event AvatarEnteringNewParcel OnAvatarEnteringNewParcel; |
171 | 171 | ||
172 | public delegate void SignificantClientMovement(IClientAPI remote_client); | 172 | public event Action<ScenePresence> OnSignificantClientMovement; |
173 | public event SignificantClientMovement OnSignificantClientMovement; | ||
174 | 173 | ||
175 | public delegate void IncomingInstantMessage(GridInstantMessage message); | 174 | public delegate void IncomingInstantMessage(GridInstantMessage message); |
176 | public event IncomingInstantMessage OnIncomingInstantMessage; | 175 | public event IncomingInstantMessage OnIncomingInstantMessage; |
@@ -1616,16 +1615,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
1616 | } | 1615 | } |
1617 | } | 1616 | } |
1618 | 1617 | ||
1619 | public void TriggerSignificantClientMovement(IClientAPI client) | 1618 | public void TriggerSignificantClientMovement(ScenePresence presence) |
1620 | { | 1619 | { |
1621 | SignificantClientMovement handlerSignificantClientMovement = OnSignificantClientMovement; | 1620 | Action<ScenePresence> handlerSignificantClientMovement = OnSignificantClientMovement; |
1622 | if (handlerSignificantClientMovement != null) | 1621 | if (handlerSignificantClientMovement != null) |
1623 | { | 1622 | { |
1624 | foreach (SignificantClientMovement d in handlerSignificantClientMovement.GetInvocationList()) | 1623 | foreach (Action<ScenePresence> d in handlerSignificantClientMovement.GetInvocationList()) |
1625 | { | 1624 | { |
1626 | try | 1625 | try |
1627 | { | 1626 | { |
1628 | d(client); | 1627 | d(presence); |
1629 | } | 1628 | } |
1630 | catch (Exception e) | 1629 | catch (Exception e) |
1631 | { | 1630 | { |
diff --git a/OpenSim/Region/Framework/Scenes/Prioritizer.cs b/OpenSim/Region/Framework/Scenes/Prioritizer.cs index 657df15..0a34a4c 100644 --- a/OpenSim/Region/Framework/Scenes/Prioritizer.cs +++ b/OpenSim/Region/Framework/Scenes/Prioritizer.cs | |||
@@ -116,14 +116,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
116 | return priority; | 116 | return priority; |
117 | } | 117 | } |
118 | 118 | ||
119 | |||
120 | private uint GetPriorityByTime(IClientAPI client, ISceneEntity entity) | 119 | private uint GetPriorityByTime(IClientAPI client, ISceneEntity entity) |
121 | { | 120 | { |
122 | // And anything attached to this avatar gets top priority as well | 121 | // And anything attached to this avatar gets top priority as well |
123 | if (entity is SceneObjectPart) | 122 | if (entity is SceneObjectPart) |
124 | { | 123 | { |
125 | SceneObjectPart sop = (SceneObjectPart)entity; | 124 | SceneObjectPart sop = (SceneObjectPart)entity; |
126 | if (sop.ParentGroup.RootPart.IsAttachment && client.AgentId == sop.ParentGroup.RootPart.AttachedAvatar) | 125 | if (sop.ParentGroup.IsAttachment && client.AgentId == sop.ParentGroup.AttachedAvatar) |
127 | return 1; | 126 | return 1; |
128 | } | 127 | } |
129 | 128 | ||
@@ -136,7 +135,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
136 | if (entity is SceneObjectPart) | 135 | if (entity is SceneObjectPart) |
137 | { | 136 | { |
138 | SceneObjectPart sop = (SceneObjectPart)entity; | 137 | SceneObjectPart sop = (SceneObjectPart)entity; |
139 | if (sop.ParentGroup.RootPart.IsAttachment && client.AgentId == sop.ParentGroup.RootPart.AttachedAvatar) | 138 | if (sop.ParentGroup.IsAttachment && client.AgentId == sop.ParentGroup.AttachedAvatar) |
140 | return 1; | 139 | return 1; |
141 | } | 140 | } |
142 | 141 | ||
@@ -149,7 +148,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
149 | if (entity is SceneObjectPart) | 148 | if (entity is SceneObjectPart) |
150 | { | 149 | { |
151 | SceneObjectPart sop = (SceneObjectPart)entity; | 150 | SceneObjectPart sop = (SceneObjectPart)entity; |
152 | if (sop.ParentGroup.RootPart.IsAttachment && client.AgentId == sop.ParentGroup.RootPart.AttachedAvatar) | 151 | if (sop.ParentGroup.IsAttachment && client.AgentId == sop.ParentGroup.AttachedAvatar) |
153 | return 1; | 152 | return 1; |
154 | } | 153 | } |
155 | 154 | ||
@@ -172,7 +171,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
172 | if (entity is SceneObjectPart) | 171 | if (entity is SceneObjectPart) |
173 | { | 172 | { |
174 | // Attachments are high priority, | 173 | // Attachments are high priority, |
175 | if (((SceneObjectPart)entity).ParentGroup.RootPart.IsAttachment) | 174 | if (((SceneObjectPart)entity).ParentGroup.IsAttachment) |
176 | return 1; | 175 | return 1; |
177 | 176 | ||
178 | // Non physical prims are lower priority than physical prims | 177 | // Non physical prims are lower priority than physical prims |
@@ -209,8 +208,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
209 | if (entity is SceneObjectPart) | 208 | if (entity is SceneObjectPart) |
210 | { | 209 | { |
211 | SceneObjectGroup group = (entity as SceneObjectPart).ParentGroup; | 210 | SceneObjectGroup group = (entity as SceneObjectPart).ParentGroup; |
212 | if (group != null) | 211 | entityPos = group.AbsolutePosition; |
213 | entityPos = group.AbsolutePosition; | ||
214 | } | 212 | } |
215 | 213 | ||
216 | // Use the camera position for local agents and avatar position for remote agents | 214 | // Use the camera position for local agents and avatar position for remote agents |
diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index dbefb4a..89f3683 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs | |||
@@ -211,16 +211,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
211 | 211 | ||
212 | // Retrieve group | 212 | // Retrieve group |
213 | SceneObjectPart part = GetSceneObjectPart(primId); | 213 | SceneObjectPart part = GetSceneObjectPart(primId); |
214 | SceneObjectGroup group = part.ParentGroup; | 214 | if (part == null) |
215 | if (null == group) | ||
216 | { | ||
217 | m_log.ErrorFormat( | ||
218 | "[PRIM INVENTORY]: " + | ||
219 | "Prim inventory update requested for item ID {0} in prim ID {1} but this prim does not exist", | ||
220 | itemId, primId); | ||
221 | |||
222 | return new ArrayList(); | 215 | return new ArrayList(); |
223 | } | 216 | |
217 | SceneObjectGroup group = part.ParentGroup; | ||
224 | 218 | ||
225 | // Retrieve item | 219 | // Retrieve item |
226 | TaskInventoryItem item = group.GetInventoryItem(part.LocalId, itemId); | 220 | TaskInventoryItem item = group.GetInventoryItem(part.LocalId, itemId); |
@@ -709,7 +703,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
709 | newName = item.Name; | 703 | newName = item.Name; |
710 | } | 704 | } |
711 | 705 | ||
712 | if (remoteClient.AgentId == oldAgentID || (LibraryService != null && LibraryService.LibraryRootFolder != null && oldAgentID == LibraryService.LibraryRootFolder.Owner)) | 706 | if (remoteClient.AgentId == oldAgentID |
707 | || (LibraryService != null | ||
708 | && LibraryService.LibraryRootFolder != null | ||
709 | && oldAgentID == LibraryService.LibraryRootFolder.Owner)) | ||
713 | { | 710 | { |
714 | CreateNewInventoryItem( | 711 | CreateNewInventoryItem( |
715 | remoteClient, item.CreatorId, item.CreatorData, newFolderID, newName, item.Flags, callbackID, asset, (sbyte)item.InvType, | 712 | remoteClient, item.CreatorId, item.CreatorData, newFolderID, newName, item.Flags, callbackID, asset, (sbyte)item.InvType, |
@@ -981,23 +978,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
981 | if (item == null) | 978 | if (item == null) |
982 | return; | 979 | return; |
983 | 980 | ||
984 | if (item.Type == 10) | 981 | if (item.Type == 10) |
985 | { | ||
986 | part.RemoveScriptEvents(itemID); | ||
987 | EventManager.TriggerRemoveScript(localID, itemID); | ||
988 | } | ||
989 | |||
990 | group.RemoveInventoryItem(localID, itemID); | ||
991 | part.GetProperties(remoteClient); | ||
992 | } | ||
993 | else | ||
994 | { | 982 | { |
995 | m_log.ErrorFormat( | 983 | part.RemoveScriptEvents(itemID); |
996 | "[PRIM INVENTORY]: " + | 984 | EventManager.TriggerRemoveScript(localID, itemID); |
997 | "Removal of item {0} requested of prim {1} but this prim does not exist", | ||
998 | itemID, | ||
999 | localID); | ||
1000 | } | 985 | } |
986 | |||
987 | group.RemoveInventoryItem(localID, itemID); | ||
988 | part.GetProperties(remoteClient); | ||
1001 | } | 989 | } |
1002 | 990 | ||
1003 | private InventoryItemBase CreateAgentInventoryItemFromTask(UUID destAgent, SceneObjectPart part, UUID itemId) | 991 | private InventoryItemBase CreateAgentInventoryItemFromTask(UUID destAgent, SceneObjectPart part, UUID itemId) |
@@ -1780,7 +1768,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1780 | } | 1768 | } |
1781 | 1769 | ||
1782 | // Already deleted by someone else | 1770 | // Already deleted by someone else |
1783 | if (part.ParentGroup == null || part.ParentGroup.IsDeleted) | 1771 | if (part.ParentGroup.IsDeleted) |
1784 | { | 1772 | { |
1785 | //Client still thinks the object exists, kill it | 1773 | //Client still thinks the object exists, kill it |
1786 | deleteIDs.Add(localID); | 1774 | deleteIDs.Add(localID); |
@@ -2158,6 +2146,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
2158 | foreach (uint localID in localIDs) | 2146 | foreach (uint localID in localIDs) |
2159 | { | 2147 | { |
2160 | SceneObjectPart part = GetSceneObjectPart(localID); | 2148 | SceneObjectPart part = GetSceneObjectPart(localID); |
2149 | if (part == null) | ||
2150 | continue; | ||
2151 | |||
2161 | if (!groups.Contains(part.ParentGroup)) | 2152 | if (!groups.Contains(part.ParentGroup)) |
2162 | groups.Add(part.ParentGroup); | 2153 | groups.Add(part.ParentGroup); |
2163 | } | 2154 | } |
@@ -2203,6 +2194,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
2203 | foreach (uint localID in localIDs) | 2194 | foreach (uint localID in localIDs) |
2204 | { | 2195 | { |
2205 | SceneObjectPart part = GetSceneObjectPart(localID); | 2196 | SceneObjectPart part = GetSceneObjectPart(localID); |
2197 | if (part == null) | ||
2198 | continue; | ||
2206 | part.GetProperties(remoteClient); | 2199 | part.GetProperties(remoteClient); |
2207 | } | 2200 | } |
2208 | } | 2201 | } |
diff --git a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs index 9bef443..9da57a8 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs | |||
@@ -191,10 +191,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
191 | if (part == null) | 191 | if (part == null) |
192 | return; | 192 | return; |
193 | 193 | ||
194 | // The prim is in the process of being deleted. | ||
195 | if (null == part.ParentGroup.RootPart) | ||
196 | return; | ||
197 | |||
198 | // A deselect packet contains all the local prims being deselected. However, since selection is still | 194 | // A deselect packet contains all the local prims being deselected. However, since selection is still |
199 | // group based we only want the root prim to trigger a full update - otherwise on objects with many prims | 195 | // group based we only want the root prim to trigger a full update - otherwise on objects with many prims |
200 | // we end up sending many duplicate ObjectUpdates | 196 | // we end up sending many duplicate ObjectUpdates |
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index ec82cc3..26fe61d 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs | |||
@@ -635,6 +635,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
635 | "delete object name <name>", | 635 | "delete object name <name>", |
636 | "Delete object by name", HandleDeleteObject); | 636 | "Delete object by name", HandleDeleteObject); |
637 | 637 | ||
638 | MainConsole.Instance.Commands.AddCommand("region", false, "delete object outside", | ||
639 | "delete object outside", | ||
640 | "Delete all objects outside boundaries", HandleDeleteObject); | ||
641 | |||
638 | //Bind Storage Manager functions to some land manager functions for this scene | 642 | //Bind Storage Manager functions to some land manager functions for this scene |
639 | EventManager.OnLandObjectAdded += | 643 | EventManager.OnLandObjectAdded += |
640 | new EventManager.LandObjectAdded(simDataService.StoreLandObject); | 644 | new EventManager.LandObjectAdded(simDataService.StoreLandObject); |
@@ -1703,20 +1707,20 @@ namespace OpenSim.Region.Framework.Scenes | |||
1703 | 1707 | ||
1704 | m_sceneGridService.SetScene(this); | 1708 | m_sceneGridService.SetScene(this); |
1705 | 1709 | ||
1706 | // If we generate maptiles internally at all, the maptile generator | 1710 | GridRegion region = new GridRegion(RegionInfo); |
1707 | // will register the region. If not, do it here | 1711 | string error = GridService.RegisterRegion(RegionInfo.ScopeID, region); |
1708 | if (m_generateMaptiles) | 1712 | if (error != String.Empty) |
1709 | { | 1713 | { |
1710 | RegenerateMaptile(null, null); | 1714 | throw new Exception(error); |
1711 | } | 1715 | } |
1712 | else | 1716 | |
1717 | // Generate the maptile asynchronously, because sometimes it can be very slow and we | ||
1718 | // don't want this to delay starting the region. | ||
1719 | if (m_generateMaptiles) | ||
1713 | { | 1720 | { |
1714 | GridRegion region = new GridRegion(RegionInfo); | 1721 | Util.FireAndForget(delegate { |
1715 | string error = GridService.RegisterRegion(RegionInfo.ScopeID, region); | 1722 | RegenerateMaptile(null, null); |
1716 | if (error != String.Empty) | 1723 | }); |
1717 | { | ||
1718 | throw new Exception(error); | ||
1719 | } | ||
1720 | } | 1724 | } |
1721 | } | 1725 | } |
1722 | 1726 | ||
@@ -1757,6 +1761,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1757 | /// <summary> | 1761 | /// <summary> |
1758 | /// Loads the World's objects | 1762 | /// Loads the World's objects |
1759 | /// </summary> | 1763 | /// </summary> |
1764 | /// <param name="regionID"></param> | ||
1760 | public virtual void LoadPrimsFromStorage(UUID regionID) | 1765 | public virtual void LoadPrimsFromStorage(UUID regionID) |
1761 | { | 1766 | { |
1762 | LoadingPrims = true; | 1767 | LoadingPrims = true; |
@@ -1769,20 +1774,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
1769 | foreach (SceneObjectGroup group in PrimsFromDB) | 1774 | foreach (SceneObjectGroup group in PrimsFromDB) |
1770 | { | 1775 | { |
1771 | EventManager.TriggerOnSceneObjectLoaded(group); | 1776 | EventManager.TriggerOnSceneObjectLoaded(group); |
1772 | |||
1773 | if (group.RootPart == null) | ||
1774 | { | ||
1775 | m_log.ErrorFormat( | ||
1776 | "[SCENE]: Found a SceneObjectGroup with m_rootPart == null and {0} children", | ||
1777 | group.Parts == null ? 0 : group.PrimCount); | ||
1778 | } | ||
1779 | |||
1780 | AddRestoredSceneObject(group, true, true); | 1777 | AddRestoredSceneObject(group, true, true); |
1781 | SceneObjectPart rootPart = group.GetChildPart(group.UUID); | 1778 | SceneObjectPart rootPart = group.GetChildPart(group.UUID); |
1782 | rootPart.Flags &= ~PrimFlags.Scripted; | 1779 | rootPart.Flags &= ~PrimFlags.Scripted; |
1783 | rootPart.TrimPermissions(); | 1780 | rootPart.TrimPermissions(); |
1784 | group.CheckSculptAndLoad(); | 1781 | |
1785 | //rootPart.DoPhysicsPropertyUpdate(UsePhysics, true); | 1782 | // Don't do this here - it will get done later on when sculpt data is loaded. |
1783 | // group.CheckSculptAndLoad(); | ||
1786 | } | 1784 | } |
1787 | 1785 | ||
1788 | m_log.Info("[SCENE]: Loaded " + PrimsFromDB.Count.ToString() + " SceneObject(s)"); | 1786 | m_log.Info("[SCENE]: Loaded " + PrimsFromDB.Count.ToString() + " SceneObject(s)"); |
@@ -2643,10 +2641,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
2643 | #region Add/Remove Avatar Methods | 2641 | #region Add/Remove Avatar Methods |
2644 | 2642 | ||
2645 | /// <summary> | 2643 | /// <summary> |
2646 | /// Adding a New Client and Create a Presence for it. | 2644 | /// Add a new client and create a child agent for it. |
2647 | /// </summary> | 2645 | /// </summary> |
2648 | /// <param name="client"></param> | 2646 | /// <param name="client"></param> |
2649 | public override void AddNewClient(IClientAPI client) | 2647 | /// <param name="type">The type of agent to add.</param> |
2648 | public override void AddNewClient(IClientAPI client, PresenceType type) | ||
2650 | { | 2649 | { |
2651 | AgentCircuitData aCircuit = m_authenticateHandler.GetAgentCircuitData(client.CircuitCode); | 2650 | AgentCircuitData aCircuit = m_authenticateHandler.GetAgentCircuitData(client.CircuitCode); |
2652 | bool vialogin = false; | 2651 | bool vialogin = false; |
@@ -2667,7 +2666,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2667 | m_clientManager.Add(client); | 2666 | m_clientManager.Add(client); |
2668 | SubscribeToClientEvents(client); | 2667 | SubscribeToClientEvents(client); |
2669 | 2668 | ||
2670 | ScenePresence sp = m_sceneGraph.CreateAndAddChildScenePresence(client, aCircuit.Appearance); | 2669 | ScenePresence sp = m_sceneGraph.CreateAndAddChildScenePresence(client, aCircuit.Appearance, type); |
2671 | m_eventManager.TriggerOnNewPresence(sp); | 2670 | m_eventManager.TriggerOnNewPresence(sp); |
2672 | 2671 | ||
2673 | sp.TeleportFlags = (TeleportFlags)aCircuit.teleportFlags; | 2672 | sp.TeleportFlags = (TeleportFlags)aCircuit.teleportFlags; |
@@ -2678,16 +2677,17 @@ namespace OpenSim.Region.Framework.Scenes | |||
2678 | if (aCircuit.child == false) | 2677 | if (aCircuit.child == false) |
2679 | { | 2678 | { |
2680 | sp.IsChildAgent = false; | 2679 | sp.IsChildAgent = false; |
2681 | Util.FireAndForget(delegate(object o) { sp.RezAttachments(); }); | 2680 | Util.FireAndForget(delegate(object o) { AttachmentsModule.RezAttachments(sp); }); |
2682 | } | 2681 | } |
2683 | } | 2682 | } |
2684 | 2683 | ||
2685 | if (TryGetScenePresence(client.AgentId, out presence)) | 2684 | ScenePresence createdSp = GetScenePresence(client.AgentId); |
2685 | if (createdSp != null) | ||
2686 | { | 2686 | { |
2687 | m_LastLogin = Util.EnvironmentTickCount(); | 2687 | m_LastLogin = Util.EnvironmentTickCount(); |
2688 | 2688 | ||
2689 | // Cache the user's name | 2689 | // Cache the user's name |
2690 | CacheUserName(aCircuit); | 2690 | CacheUserName(createdSp, aCircuit); |
2691 | 2691 | ||
2692 | EventManager.TriggerOnNewClient(client); | 2692 | EventManager.TriggerOnNewClient(client); |
2693 | if (vialogin) | 2693 | if (vialogin) |
@@ -2702,28 +2702,41 @@ namespace OpenSim.Region.Framework.Scenes | |||
2702 | } | 2702 | } |
2703 | } | 2703 | } |
2704 | 2704 | ||
2705 | private void CacheUserName(AgentCircuitData aCircuit) | 2705 | /// <summary> |
2706 | /// Cache the user name for later use. | ||
2707 | /// </summary> | ||
2708 | /// <param name="sp"></param> | ||
2709 | /// <param name="aCircuit"></param> | ||
2710 | private void CacheUserName(ScenePresence sp, AgentCircuitData aCircuit) | ||
2706 | { | 2711 | { |
2707 | IUserManagement uMan = RequestModuleInterface<IUserManagement>(); | 2712 | IUserManagement uMan = RequestModuleInterface<IUserManagement>(); |
2708 | if (uMan != null) | 2713 | if (uMan != null) |
2709 | { | 2714 | { |
2710 | string homeURL = string.Empty; | ||
2711 | string first = aCircuit.firstname, last = aCircuit.lastname; | 2715 | string first = aCircuit.firstname, last = aCircuit.lastname; |
2712 | 2716 | ||
2713 | if (aCircuit.ServiceURLs.ContainsKey("HomeURI")) | 2717 | if (sp.PresenceType == PresenceType.Npc) |
2714 | homeURL = aCircuit.ServiceURLs["HomeURI"].ToString(); | 2718 | { |
2715 | 2719 | uMan.AddUser(aCircuit.AgentID, first, last); | |
2716 | if (aCircuit.lastname.StartsWith("@")) | 2720 | } |
2721 | else | ||
2717 | { | 2722 | { |
2718 | string[] parts = aCircuit.firstname.Split('.'); | 2723 | string homeURL = string.Empty; |
2719 | if (parts.Length >= 2) | 2724 | |
2725 | if (aCircuit.ServiceURLs.ContainsKey("HomeURI")) | ||
2726 | homeURL = aCircuit.ServiceURLs["HomeURI"].ToString(); | ||
2727 | |||
2728 | if (aCircuit.lastname.StartsWith("@")) | ||
2720 | { | 2729 | { |
2721 | first = parts[0]; | 2730 | string[] parts = aCircuit.firstname.Split('.'); |
2722 | last = parts[1]; | 2731 | if (parts.Length >= 2) |
2732 | { | ||
2733 | first = parts[0]; | ||
2734 | last = parts[1]; | ||
2735 | } | ||
2723 | } | 2736 | } |
2724 | } | ||
2725 | 2737 | ||
2726 | uMan.AddUser(aCircuit.AgentID, first, last, homeURL); | 2738 | uMan.AddUser(aCircuit.AgentID, first, last, homeURL); |
2739 | } | ||
2727 | } | 2740 | } |
2728 | } | 2741 | } |
2729 | 2742 | ||
@@ -2821,12 +2834,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
2821 | 2834 | ||
2822 | public virtual void SubscribeToClientPrimEvents(IClientAPI client) | 2835 | public virtual void SubscribeToClientPrimEvents(IClientAPI client) |
2823 | { | 2836 | { |
2824 | client.OnUpdatePrimGroupPosition += m_sceneGraph.UpdatePrimPosition; | 2837 | client.OnUpdatePrimGroupPosition += m_sceneGraph.UpdatePrimGroupPosition; |
2825 | client.OnUpdatePrimSinglePosition += m_sceneGraph.UpdatePrimSinglePosition; | 2838 | client.OnUpdatePrimSinglePosition += m_sceneGraph.UpdatePrimSinglePosition; |
2826 | client.OnUpdatePrimGroupRotation += m_sceneGraph.UpdatePrimRotation; | 2839 | |
2827 | client.OnUpdatePrimGroupMouseRotation += m_sceneGraph.UpdatePrimRotation; | 2840 | client.OnUpdatePrimGroupRotation += m_sceneGraph.UpdatePrimGroupRotation; |
2841 | client.OnUpdatePrimGroupMouseRotation += m_sceneGraph.UpdatePrimGroupRotation; | ||
2828 | client.OnUpdatePrimSingleRotation += m_sceneGraph.UpdatePrimSingleRotation; | 2842 | client.OnUpdatePrimSingleRotation += m_sceneGraph.UpdatePrimSingleRotation; |
2829 | client.OnUpdatePrimSingleRotationPosition += m_sceneGraph.UpdatePrimSingleRotationPosition; | 2843 | client.OnUpdatePrimSingleRotationPosition += m_sceneGraph.UpdatePrimSingleRotationPosition; |
2844 | |||
2830 | client.OnUpdatePrimScale += m_sceneGraph.UpdatePrimScale; | 2845 | client.OnUpdatePrimScale += m_sceneGraph.UpdatePrimScale; |
2831 | client.OnUpdatePrimGroupScale += m_sceneGraph.UpdatePrimGroupScale; | 2846 | client.OnUpdatePrimGroupScale += m_sceneGraph.UpdatePrimGroupScale; |
2832 | client.OnUpdateExtraParams += m_sceneGraph.UpdateExtraParam; | 2847 | client.OnUpdateExtraParams += m_sceneGraph.UpdateExtraParam; |
@@ -2856,7 +2871,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
2856 | client.OnUndo += m_sceneGraph.HandleUndo; | 2871 | client.OnUndo += m_sceneGraph.HandleUndo; |
2857 | client.OnRedo += m_sceneGraph.HandleRedo; | 2872 | client.OnRedo += m_sceneGraph.HandleRedo; |
2858 | client.OnObjectDescription += m_sceneGraph.PrimDescription; | 2873 | client.OnObjectDescription += m_sceneGraph.PrimDescription; |
2859 | client.OnObjectDrop += m_sceneGraph.DropObject; | ||
2860 | client.OnObjectIncludeInSearch += m_sceneGraph.MakeObjectSearchable; | 2874 | client.OnObjectIncludeInSearch += m_sceneGraph.MakeObjectSearchable; |
2861 | client.OnObjectOwner += ObjectOwner; | 2875 | client.OnObjectOwner += ObjectOwner; |
2862 | } | 2876 | } |
@@ -2949,12 +2963,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
2949 | 2963 | ||
2950 | public virtual void UnSubscribeToClientPrimEvents(IClientAPI client) | 2964 | public virtual void UnSubscribeToClientPrimEvents(IClientAPI client) |
2951 | { | 2965 | { |
2952 | client.OnUpdatePrimGroupPosition -= m_sceneGraph.UpdatePrimPosition; | 2966 | client.OnUpdatePrimGroupPosition -= m_sceneGraph.UpdatePrimGroupPosition; |
2953 | client.OnUpdatePrimSinglePosition -= m_sceneGraph.UpdatePrimSinglePosition; | 2967 | client.OnUpdatePrimSinglePosition -= m_sceneGraph.UpdatePrimSinglePosition; |
2954 | client.OnUpdatePrimGroupRotation -= m_sceneGraph.UpdatePrimRotation; | 2968 | |
2955 | client.OnUpdatePrimGroupMouseRotation -= m_sceneGraph.UpdatePrimRotation; | 2969 | client.OnUpdatePrimGroupRotation -= m_sceneGraph.UpdatePrimGroupRotation; |
2970 | client.OnUpdatePrimGroupMouseRotation -= m_sceneGraph.UpdatePrimGroupRotation; | ||
2956 | client.OnUpdatePrimSingleRotation -= m_sceneGraph.UpdatePrimSingleRotation; | 2971 | client.OnUpdatePrimSingleRotation -= m_sceneGraph.UpdatePrimSingleRotation; |
2957 | client.OnUpdatePrimSingleRotationPosition -= m_sceneGraph.UpdatePrimSingleRotationPosition; | 2972 | client.OnUpdatePrimSingleRotationPosition -= m_sceneGraph.UpdatePrimSingleRotationPosition; |
2973 | |||
2958 | client.OnUpdatePrimScale -= m_sceneGraph.UpdatePrimScale; | 2974 | client.OnUpdatePrimScale -= m_sceneGraph.UpdatePrimScale; |
2959 | client.OnUpdatePrimGroupScale -= m_sceneGraph.UpdatePrimGroupScale; | 2975 | client.OnUpdatePrimGroupScale -= m_sceneGraph.UpdatePrimGroupScale; |
2960 | client.OnUpdateExtraParams -= m_sceneGraph.UpdateExtraParam; | 2976 | client.OnUpdateExtraParams -= m_sceneGraph.UpdateExtraParam; |
@@ -2982,7 +2998,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
2982 | client.OnUndo -= m_sceneGraph.HandleUndo; | 2998 | client.OnUndo -= m_sceneGraph.HandleUndo; |
2983 | client.OnRedo -= m_sceneGraph.HandleRedo; | 2999 | client.OnRedo -= m_sceneGraph.HandleRedo; |
2984 | client.OnObjectDescription -= m_sceneGraph.PrimDescription; | 3000 | client.OnObjectDescription -= m_sceneGraph.PrimDescription; |
2985 | client.OnObjectDrop -= m_sceneGraph.DropObject; | ||
2986 | client.OnObjectIncludeInSearch -= m_sceneGraph.MakeObjectSearchable; | 3001 | client.OnObjectIncludeInSearch -= m_sceneGraph.MakeObjectSearchable; |
2987 | client.OnObjectOwner -= ObjectOwner; | 3002 | client.OnObjectOwner -= ObjectOwner; |
2988 | } | 3003 | } |
@@ -3098,58 +3113,51 @@ namespace OpenSim.Region.Framework.Scenes | |||
3098 | Vector3 AXOrigin = new Vector3(RayStart.X, RayStart.Y, RayStart.Z); | 3113 | Vector3 AXOrigin = new Vector3(RayStart.X, RayStart.Y, RayStart.Z); |
3099 | Vector3 AXdirection = new Vector3(direction.X, direction.Y, direction.Z); | 3114 | Vector3 AXdirection = new Vector3(direction.X, direction.Y, direction.Z); |
3100 | 3115 | ||
3101 | if (target2.ParentGroup != null) | 3116 | pos = target2.AbsolutePosition; |
3102 | { | 3117 | //m_log.Info("[OBJECT_REZ]: TargetPos: " + pos.ToString() + ", RayStart: " + RayStart.ToString() + ", RayEnd: " + RayEnd.ToString() + ", Volume: " + Util.GetDistanceTo(RayStart,RayEnd).ToString() + ", mag1: " + Util.GetMagnitude(RayStart).ToString() + ", mag2: " + Util.GetMagnitude(RayEnd).ToString()); |
3103 | pos = target2.AbsolutePosition; | ||
3104 | //m_log.Info("[OBJECT_REZ]: TargetPos: " + pos.ToString() + ", RayStart: " + RayStart.ToString() + ", RayEnd: " + RayEnd.ToString() + ", Volume: " + Util.GetDistanceTo(RayStart,RayEnd).ToString() + ", mag1: " + Util.GetMagnitude(RayStart).ToString() + ", mag2: " + Util.GetMagnitude(RayEnd).ToString()); | ||
3105 | 3118 | ||
3106 | // TODO: Raytrace better here | 3119 | // TODO: Raytrace better here |
3107 | 3120 | ||
3108 | //EntityIntersection ei = m_sceneGraph.GetClosestIntersectingPrim(new Ray(AXOrigin, AXdirection)); | 3121 | //EntityIntersection ei = m_sceneGraph.GetClosestIntersectingPrim(new Ray(AXOrigin, AXdirection)); |
3109 | Ray NewRay = new Ray(AXOrigin, AXdirection); | 3122 | Ray NewRay = new Ray(AXOrigin, AXdirection); |
3110 | 3123 | ||
3111 | // Ray Trace against target here | 3124 | // Ray Trace against target here |
3112 | EntityIntersection ei = target2.TestIntersectionOBB(NewRay, Quaternion.Identity, frontFacesOnly, CopyCenters); | 3125 | EntityIntersection ei = target2.TestIntersectionOBB(NewRay, Quaternion.Identity, frontFacesOnly, CopyCenters); |
3113 | 3126 | ||
3114 | // Un-comment out the following line to Get Raytrace results printed to the console. | 3127 | // Un-comment out the following line to Get Raytrace results printed to the console. |
3115 | //m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString()); | 3128 | //m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString()); |
3116 | float ScaleOffset = 0.5f; | 3129 | float ScaleOffset = 0.5f; |
3117 | 3130 | ||
3118 | // If we hit something | 3131 | // If we hit something |
3119 | if (ei.HitTF) | 3132 | if (ei.HitTF) |
3120 | { | 3133 | { |
3121 | Vector3 scale = target.Scale; | 3134 | Vector3 scale = target.Scale; |
3122 | Vector3 scaleComponent = new Vector3(ei.AAfaceNormal.X, ei.AAfaceNormal.Y, ei.AAfaceNormal.Z); | 3135 | Vector3 scaleComponent = new Vector3(ei.AAfaceNormal.X, ei.AAfaceNormal.Y, ei.AAfaceNormal.Z); |
3123 | if (scaleComponent.X != 0) ScaleOffset = scale.X; | 3136 | if (scaleComponent.X != 0) ScaleOffset = scale.X; |
3124 | if (scaleComponent.Y != 0) ScaleOffset = scale.Y; | 3137 | if (scaleComponent.Y != 0) ScaleOffset = scale.Y; |
3125 | if (scaleComponent.Z != 0) ScaleOffset = scale.Z; | 3138 | if (scaleComponent.Z != 0) ScaleOffset = scale.Z; |
3126 | ScaleOffset = Math.Abs(ScaleOffset); | 3139 | ScaleOffset = Math.Abs(ScaleOffset); |
3127 | Vector3 intersectionpoint = new Vector3(ei.ipoint.X, ei.ipoint.Y, ei.ipoint.Z); | 3140 | Vector3 intersectionpoint = new Vector3(ei.ipoint.X, ei.ipoint.Y, ei.ipoint.Z); |
3128 | Vector3 normal = new Vector3(ei.normal.X, ei.normal.Y, ei.normal.Z); | 3141 | Vector3 normal = new Vector3(ei.normal.X, ei.normal.Y, ei.normal.Z); |
3129 | Vector3 offset = normal * (ScaleOffset / 2f); | 3142 | Vector3 offset = normal * (ScaleOffset / 2f); |
3130 | pos = intersectionpoint + offset; | 3143 | pos = intersectionpoint + offset; |
3131 | 3144 | ||
3132 | // stick in offset format from the original prim | 3145 | // stick in offset format from the original prim |
3133 | pos = pos - target.ParentGroup.AbsolutePosition; | 3146 | pos = pos - target.ParentGroup.AbsolutePosition; |
3134 | if (CopyRotates) | 3147 | if (CopyRotates) |
3135 | { | 3148 | { |
3136 | Quaternion worldRot = target2.GetWorldRotation(); | 3149 | Quaternion worldRot = target2.GetWorldRotation(); |
3137 | 3150 | ||
3138 | // SceneObjectGroup obj = m_sceneGraph.DuplicateObject(localID, pos, target.GetEffectiveObjectFlags(), AgentID, GroupID, worldRot); | 3151 | // SceneObjectGroup obj = m_sceneGraph.DuplicateObject(localID, pos, target.GetEffectiveObjectFlags(), AgentID, GroupID, worldRot); |
3139 | m_sceneGraph.DuplicateObject(localID, pos, target.GetEffectiveObjectFlags(), AgentID, GroupID, worldRot); | 3152 | m_sceneGraph.DuplicateObject(localID, pos, target.GetEffectiveObjectFlags(), AgentID, GroupID, worldRot); |
3140 | //obj.Rotation = worldRot; | 3153 | //obj.Rotation = worldRot; |
3141 | //obj.UpdateGroupRotationR(worldRot); | 3154 | //obj.UpdateGroupRotationR(worldRot); |
3142 | } | 3155 | } |
3143 | else | 3156 | else |
3144 | { | 3157 | { |
3145 | m_sceneGraph.DuplicateObject(localID, pos, target.GetEffectiveObjectFlags(), AgentID, GroupID); | 3158 | m_sceneGraph.DuplicateObject(localID, pos, target.GetEffectiveObjectFlags(), AgentID, GroupID); |
3146 | } | ||
3147 | } | 3159 | } |
3148 | |||
3149 | return; | ||
3150 | } | 3160 | } |
3151 | |||
3152 | return; | ||
3153 | } | 3161 | } |
3154 | } | 3162 | } |
3155 | 3163 | ||
@@ -3192,7 +3200,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3192 | if (aCircuit == null) | 3200 | if (aCircuit == null) |
3193 | { | 3201 | { |
3194 | m_log.DebugFormat("[APPEARANCE] Client did not supply a circuit. Non-Linden? Creating default appearance."); | 3202 | m_log.DebugFormat("[APPEARANCE] Client did not supply a circuit. Non-Linden? Creating default appearance."); |
3195 | appearance = new AvatarAppearance(client.AgentId); | 3203 | appearance = new AvatarAppearance(); |
3196 | return; | 3204 | return; |
3197 | } | 3205 | } |
3198 | 3206 | ||
@@ -3200,15 +3208,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
3200 | if (appearance == null) | 3208 | if (appearance == null) |
3201 | { | 3209 | { |
3202 | m_log.DebugFormat("[APPEARANCE]: Appearance not found in {0}, returning default", RegionInfo.RegionName); | 3210 | m_log.DebugFormat("[APPEARANCE]: Appearance not found in {0}, returning default", RegionInfo.RegionName); |
3203 | appearance = new AvatarAppearance(client.AgentId); | 3211 | appearance = new AvatarAppearance(); |
3204 | } | 3212 | } |
3205 | } | 3213 | } |
3206 | 3214 | ||
3207 | /// <summary> | 3215 | public override void RemoveClient(UUID agentID, bool closeChildAgents) |
3208 | /// Remove the given client from the scene. | ||
3209 | /// </summary> | ||
3210 | /// <param name="agentID"></param> | ||
3211 | public override void RemoveClient(UUID agentID) | ||
3212 | { | 3216 | { |
3213 | CheckHeartbeat(); | 3217 | CheckHeartbeat(); |
3214 | bool childagentYN = false; | 3218 | bool childagentYN = false; |
@@ -3229,15 +3233,17 @@ namespace OpenSim.Region.Framework.Scenes | |||
3229 | (childagentYN ? "child" : "root"), agentID, RegionInfo.RegionName); | 3233 | (childagentYN ? "child" : "root"), agentID, RegionInfo.RegionName); |
3230 | 3234 | ||
3231 | m_sceneGraph.removeUserCount(!childagentYN); | 3235 | m_sceneGraph.removeUserCount(!childagentYN); |
3232 | 3236 | ||
3233 | if (CapsModule != null) | 3237 | // TODO: We shouldn't use closeChildAgents here - it's being used by the NPC module to stop |
3238 | // unnecessary operations. This should go away once NPCs have no accompanying IClientAPI | ||
3239 | if (closeChildAgents && CapsModule != null) | ||
3234 | CapsModule.RemoveCaps(agentID); | 3240 | CapsModule.RemoveCaps(agentID); |
3235 | 3241 | ||
3236 | // REFACTORING PROBLEM -- well not really a problem, but just to point out that whatever | 3242 | // REFACTORING PROBLEM -- well not really a problem, but just to point out that whatever |
3237 | // this method is doing is HORRIBLE!!! | 3243 | // this method is doing is HORRIBLE!!! |
3238 | avatar.Scene.NeedSceneCacheClear(avatar.UUID); | 3244 | avatar.Scene.NeedSceneCacheClear(avatar.UUID); |
3239 | 3245 | ||
3240 | if (!avatar.IsChildAgent) | 3246 | if (closeChildAgents && !avatar.IsChildAgent) |
3241 | { | 3247 | { |
3242 | //List<ulong> childknownRegions = new List<ulong>(); | 3248 | //List<ulong> childknownRegions = new List<ulong>(); |
3243 | //List<ulong> ckn = avatar.KnownChildRegionHandles; | 3249 | //List<ulong> ckn = avatar.KnownChildRegionHandles; |
@@ -3263,8 +3269,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
3263 | m_eventManager.TriggerOnRemovePresence(agentID); | 3269 | m_eventManager.TriggerOnRemovePresence(agentID); |
3264 | m_log.Debug("[Scene] Finished OnRemovePresence"); | 3270 | m_log.Debug("[Scene] Finished OnRemovePresence"); |
3265 | 3271 | ||
3266 | if (avatar != null && (!avatar.IsChildAgent)) | 3272 | if (AttachmentsModule != null && !avatar.IsChildAgent && avatar.PresenceType != PresenceType.Npc) |
3267 | avatar.SaveChangedAttachments(); | 3273 | AttachmentsModule.SaveChangedAttachments(avatar); |
3268 | 3274 | ||
3269 | if (avatar != null && (!avatar.IsChildAgent)) | 3275 | if (avatar != null && (!avatar.IsChildAgent)) |
3270 | avatar.SaveChangedAttachments(); | 3276 | avatar.SaveChangedAttachments(); |
@@ -3304,7 +3310,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3304 | } | 3310 | } |
3305 | m_log.Debug("[Scene] Done. Firing RemoveCircuit"); | 3311 | m_log.Debug("[Scene] Done. Firing RemoveCircuit"); |
3306 | m_authenticateHandler.RemoveCircuit(avatar.ControllingClient.CircuitCode); | 3312 | m_authenticateHandler.RemoveCircuit(avatar.ControllingClient.CircuitCode); |
3307 | CleanDroppedAttachments(); | 3313 | // CleanDroppedAttachments(); |
3308 | m_log.Debug("[Scene] The avatar has left the building"); | 3314 | m_log.Debug("[Scene] The avatar has left the building"); |
3309 | //m_log.InfoFormat("[SCENE] Memory pre GC {0}", System.GC.GetTotalMemory(false)); | 3315 | //m_log.InfoFormat("[SCENE] Memory pre GC {0}", System.GC.GetTotalMemory(false)); |
3310 | //m_log.InfoFormat("[SCENE] Memory post GC {0}", System.GC.GetTotalMemory(true)); | 3316 | //m_log.InfoFormat("[SCENE] Memory post GC {0}", System.GC.GetTotalMemory(true)); |
@@ -3540,7 +3546,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3540 | 3546 | ||
3541 | if (vialogin) | 3547 | if (vialogin) |
3542 | { | 3548 | { |
3543 | CleanDroppedAttachments(); | 3549 | // CleanDroppedAttachments(); |
3544 | 3550 | ||
3545 | if (TestBorderCross(agent.startpos, Cardinals.E)) | 3551 | if (TestBorderCross(agent.startpos, Cardinals.E)) |
3546 | { | 3552 | { |
@@ -3699,11 +3705,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
3699 | 3705 | ||
3700 | if (AuthorizationService != null) | 3706 | if (AuthorizationService != null) |
3701 | { | 3707 | { |
3702 | if (!AuthorizationService.IsAuthorizedForRegion(agentID.ToString(), RegionInfo.RegionID.ToString(),out reason)) | 3708 | if (!AuthorizationService.IsAuthorizedForRegion( |
3709 | agent.AgentID.ToString(), agent.firstname, agent.lastname, RegionInfo.RegionID.ToString(), out reason)) | ||
3703 | { | 3710 | { |
3704 | m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} at {1} because the user does not have access to the region", | 3711 | m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} at {1} because the user does not have access to the region", |
3705 | agentID, RegionInfo.RegionName); | 3712 | agentID, RegionInfo.RegionName); |
3706 | //reason = String.Format("You are not currently on the access list for {0}",RegionInfo.RegionName); | 3713 | |
3707 | return false; | 3714 | return false; |
3708 | } | 3715 | } |
3709 | } | 3716 | } |
@@ -4033,8 +4040,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
4033 | } | 4040 | } |
4034 | 4041 | ||
4035 | /// <summary> | 4042 | /// <summary> |
4036 | /// Tries to teleport agent to other region. | 4043 | /// Tries to teleport agent to another region. |
4037 | /// </summary> | 4044 | /// </summary> |
4045 | /// <remarks> | ||
4046 | /// The region name must exactly match that given. | ||
4047 | /// </remarks> | ||
4038 | /// <param name="remoteClient"></param> | 4048 | /// <param name="remoteClient"></param> |
4039 | /// <param name="regionName"></param> | 4049 | /// <param name="regionName"></param> |
4040 | /// <param name="position"></param> | 4050 | /// <param name="position"></param> |
@@ -4043,15 +4053,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
4043 | public void RequestTeleportLocation(IClientAPI remoteClient, string regionName, Vector3 position, | 4053 | public void RequestTeleportLocation(IClientAPI remoteClient, string regionName, Vector3 position, |
4044 | Vector3 lookat, uint teleportFlags) | 4054 | Vector3 lookat, uint teleportFlags) |
4045 | { | 4055 | { |
4046 | List<GridRegion> regions = GridService.GetRegionsByName(RegionInfo.ScopeID, regionName, 1); | 4056 | GridRegion region = GridService.GetRegionByName(RegionInfo.ScopeID, regionName); |
4047 | if (regions == null || regions.Count == 0) | 4057 | |
4058 | if (region == null) | ||
4048 | { | 4059 | { |
4049 | // can't find the region: Tell viewer and abort | 4060 | // can't find the region: Tell viewer and abort |
4050 | remoteClient.SendTeleportFailed("The region '" + regionName + "' could not be found."); | 4061 | remoteClient.SendTeleportFailed("The region '" + regionName + "' could not be found."); |
4051 | return; | 4062 | return; |
4052 | } | 4063 | } |
4053 | 4064 | ||
4054 | RequestTeleportLocation(remoteClient, regions[0].RegionHandle, position, lookat, teleportFlags); | 4065 | RequestTeleportLocation(remoteClient, region.RegionHandle, position, lookat, teleportFlags); |
4055 | } | 4066 | } |
4056 | 4067 | ||
4057 | /// <summary> | 4068 | /// <summary> |
@@ -4353,7 +4364,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
4353 | // their scripts will actually run. | 4364 | // their scripts will actually run. |
4354 | // -- Leaf, Tue Aug 12 14:17:05 EDT 2008 | 4365 | // -- Leaf, Tue Aug 12 14:17:05 EDT 2008 |
4355 | SceneObjectPart parent = part.ParentGroup.RootPart; | 4366 | SceneObjectPart parent = part.ParentGroup.RootPart; |
4356 | if (parent != null && parent.IsAttachment) | 4367 | if (part.ParentGroup.IsAttachment) |
4357 | return ScriptDanger(parent, parent.GetWorldPosition()); | 4368 | return ScriptDanger(parent, parent.GetWorldPosition()); |
4358 | else | 4369 | else |
4359 | return ScriptDanger(part, part.GetWorldPosition()); | 4370 | return ScriptDanger(part, part.GetWorldPosition()); |
@@ -5122,11 +5133,19 @@ namespace OpenSim.Region.Framework.Scenes | |||
5122 | 5133 | ||
5123 | private void HandleDeleteObject(string module, string[] cmd) | 5134 | private void HandleDeleteObject(string module, string[] cmd) |
5124 | { | 5135 | { |
5125 | if (cmd.Length < 4) | 5136 | if (cmd.Length < 3) |
5126 | return; | 5137 | return; |
5127 | 5138 | ||
5128 | string mode = cmd[2]; | 5139 | string mode = cmd[2]; |
5129 | string o = cmd[3]; | 5140 | string o = ""; |
5141 | |||
5142 | if (mode != "outside") | ||
5143 | { | ||
5144 | if (cmd.Length < 4) | ||
5145 | return; | ||
5146 | |||
5147 | o = cmd[3]; | ||
5148 | } | ||
5130 | 5149 | ||
5131 | List<SceneObjectGroup> deletes = new List<SceneObjectGroup>(); | 5150 | List<SceneObjectGroup> deletes = new List<SceneObjectGroup>(); |
5132 | 5151 | ||
@@ -5168,10 +5187,35 @@ namespace OpenSim.Region.Framework.Scenes | |||
5168 | deletes.Add(g); | 5187 | deletes.Add(g); |
5169 | }); | 5188 | }); |
5170 | break; | 5189 | break; |
5190 | case "outside": | ||
5191 | ForEachSOG(delegate (SceneObjectGroup g) | ||
5192 | { | ||
5193 | SceneObjectPart rootPart = g.RootPart; | ||
5194 | bool delete = false; | ||
5195 | |||
5196 | if (rootPart.GroupPosition.Z < 0.0 || rootPart.GroupPosition.Z > 10000.0) | ||
5197 | { | ||
5198 | delete = true; | ||
5199 | } | ||
5200 | else | ||
5201 | { | ||
5202 | ILandObject parcel = LandChannel.GetLandObject(rootPart.GroupPosition.X, rootPart.GroupPosition.Y); | ||
5203 | |||
5204 | if (parcel == null || parcel.LandData.Name == "NO LAND") | ||
5205 | delete = true; | ||
5206 | } | ||
5207 | |||
5208 | if (delete && !g.IsAttachment && !deletes.Contains(g)) | ||
5209 | deletes.Add(g); | ||
5210 | }); | ||
5211 | break; | ||
5171 | } | 5212 | } |
5172 | 5213 | ||
5173 | foreach (SceneObjectGroup g in deletes) | 5214 | foreach (SceneObjectGroup g in deletes) |
5215 | { | ||
5216 | m_log.InfoFormat("[SCENE]: Deleting object {0}", g.UUID); | ||
5174 | DeleteSceneObject(g, false); | 5217 | DeleteSceneObject(g, false); |
5218 | } | ||
5175 | } | 5219 | } |
5176 | 5220 | ||
5177 | private void HandleReloadEstate(string module, string[] cmd) | 5221 | private void HandleReloadEstate(string module, string[] cmd) |
@@ -5268,10 +5312,40 @@ namespace OpenSim.Region.Framework.Scenes | |||
5268 | } | 5312 | } |
5269 | } | 5313 | } |
5270 | 5314 | ||
5271 | public void CleanDroppedAttachments() | 5315 | // public void CleanDroppedAttachments() |
5272 | { | 5316 | // { |
5273 | List<SceneObjectGroup> objectsToDelete = | 5317 | // List<SceneObjectGroup> objectsToDelete = |
5274 | new List<SceneObjectGroup>(); | 5318 | // new List<SceneObjectGroup>(); |
5319 | // | ||
5320 | // lock (m_cleaningAttachments) | ||
5321 | // { | ||
5322 | // ForEachSOG(delegate (SceneObjectGroup grp) | ||
5323 | // { | ||
5324 | // if (grp.RootPart.Shape.PCode == 0 && grp.RootPart.Shape.State != 0 && (!objectsToDelete.Contains(grp))) | ||
5325 | // { | ||
5326 | // UUID agentID = grp.OwnerID; | ||
5327 | // if (agentID == UUID.Zero) | ||
5328 | // { | ||
5329 | // objectsToDelete.Add(grp); | ||
5330 | // return; | ||
5331 | // } | ||
5332 | // | ||
5333 | // ScenePresence sp = GetScenePresence(agentID); | ||
5334 | // if (sp == null) | ||
5335 | // { | ||
5336 | // objectsToDelete.Add(grp); | ||
5337 | // return; | ||
5338 | // } | ||
5339 | // } | ||
5340 | // }); | ||
5341 | // } | ||
5342 | // | ||
5343 | // foreach (SceneObjectGroup grp in objectsToDelete) | ||
5344 | // { | ||
5345 | // m_log.InfoFormat("[SCENE]: Deleting dropped attachment {0} of user {1}", grp.UUID, grp.OwnerID); | ||
5346 | // DeleteSceneObject(grp, true); | ||
5347 | // } | ||
5348 | // } | ||
5275 | 5349 | ||
5276 | lock (m_cleaningAttachments) | 5350 | lock (m_cleaningAttachments) |
5277 | { | 5351 | { |
diff --git a/OpenSim/Region/Framework/Scenes/SceneBase.cs b/OpenSim/Region/Framework/Scenes/SceneBase.cs index f343bc8..bf861b8 100644 --- a/OpenSim/Region/Framework/Scenes/SceneBase.cs +++ b/OpenSim/Region/Framework/Scenes/SceneBase.cs | |||
@@ -177,18 +177,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
177 | 177 | ||
178 | #region Add/Remove Agent/Avatar | 178 | #region Add/Remove Agent/Avatar |
179 | 179 | ||
180 | /// <summary> | 180 | public abstract void AddNewClient(IClientAPI client, PresenceType type); |
181 | /// Register the new client with the scene. The client starts off as a child agent - the later agent crossing | 181 | public abstract void RemoveClient(UUID agentID, bool closeChildAgents); |
182 | /// will promote it to a root agent during login. | ||
183 | /// </summary> | ||
184 | /// <param name="client"></param | ||
185 | public abstract void AddNewClient(IClientAPI client); | ||
186 | |||
187 | /// <summary> | ||
188 | /// Remove a client from the scene | ||
189 | /// </summary> | ||
190 | /// <param name="agentID"></param> | ||
191 | public abstract void RemoveClient(UUID agentID); | ||
192 | 182 | ||
193 | public bool TryGetScenePresence(UUID agentID, out object scenePresence) | 183 | public bool TryGetScenePresence(UUID agentID, out object scenePresence) |
194 | { | 184 | { |
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index 39d4a29..29edf13 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs | |||
@@ -403,7 +403,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
403 | /// </returns> | 403 | /// </returns> |
404 | protected bool AddSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates) | 404 | protected bool AddSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates) |
405 | { | 405 | { |
406 | if (sceneObject == null || sceneObject.RootPart == null || sceneObject.RootPart.UUID == UUID.Zero) | 406 | if (sceneObject == null || sceneObject.RootPart.UUID == UUID.Zero) |
407 | return false; | 407 | return false; |
408 | 408 | ||
409 | if (Entities.ContainsKey(sceneObject.UUID)) | 409 | if (Entities.ContainsKey(sceneObject.UUID)) |
@@ -613,13 +613,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
613 | m_activeScripts += number; | 613 | m_activeScripts += number; |
614 | } | 614 | } |
615 | 615 | ||
616 | public void DropObject(uint objectLocalID, IClientAPI remoteClient) | ||
617 | { | ||
618 | SceneObjectGroup group = GetGroupByPrim(objectLocalID); | ||
619 | if (group != null) | ||
620 | m_parentScene.AttachmentsModule.DetachSingleAttachmentToGround(group.UUID, remoteClient); | ||
621 | } | ||
622 | |||
623 | protected internal void HandleUndo(IClientAPI remoteClient, UUID primId) | 616 | protected internal void HandleUndo(IClientAPI remoteClient, UUID primId) |
624 | { | 617 | { |
625 | if (primId != UUID.Zero) | 618 | if (primId != UUID.Zero) |
@@ -629,11 +622,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
629 | part.Undo(); | 622 | part.Undo(); |
630 | } | 623 | } |
631 | } | 624 | } |
625 | |||
632 | protected internal void HandleRedo(IClientAPI remoteClient, UUID primId) | 626 | protected internal void HandleRedo(IClientAPI remoteClient, UUID primId) |
633 | { | 627 | { |
634 | if (primId != UUID.Zero) | 628 | if (primId != UUID.Zero) |
635 | { | 629 | { |
636 | SceneObjectPart part = m_parentScene.GetSceneObjectPart(primId); | 630 | SceneObjectPart part = m_parentScene.GetSceneObjectPart(primId); |
631 | |||
637 | if (part != null) | 632 | if (part != null) |
638 | part.Redo(); | 633 | part.Redo(); |
639 | } | 634 | } |
@@ -653,12 +648,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
653 | } | 648 | } |
654 | } | 649 | } |
655 | 650 | ||
656 | protected internal ScenePresence CreateAndAddChildScenePresence(IClientAPI client, AvatarAppearance appearance) | 651 | protected internal ScenePresence CreateAndAddChildScenePresence( |
652 | IClientAPI client, AvatarAppearance appearance, PresenceType type) | ||
657 | { | 653 | { |
658 | ScenePresence newAvatar = null; | 654 | ScenePresence newAvatar = null; |
659 | 655 | ||
660 | // ScenePresence always defaults to child agent | 656 | // ScenePresence always defaults to child agent |
661 | newAvatar = new ScenePresence(client, m_parentScene, m_regInfo, appearance); | 657 | newAvatar = new ScenePresence(client, m_parentScene, m_regInfo, appearance, type); |
662 | 658 | ||
663 | AddScenePresence(newAvatar); | 659 | AddScenePresence(newAvatar); |
664 | 660 | ||
@@ -1285,19 +1281,20 @@ namespace OpenSim.Region.Framework.Scenes | |||
1285 | #region Client Event handlers | 1281 | #region Client Event handlers |
1286 | 1282 | ||
1287 | /// <summary> | 1283 | /// <summary> |
1288 | /// | 1284 | /// Update the scale of an individual prim. |
1289 | /// </summary> | 1285 | /// </summary> |
1290 | /// <param name="localID"></param> | 1286 | /// <param name="localID"></param> |
1291 | /// <param name="scale"></param> | 1287 | /// <param name="scale"></param> |
1292 | /// <param name="remoteClient"></param> | 1288 | /// <param name="remoteClient"></param> |
1293 | protected internal void UpdatePrimScale(uint localID, Vector3 scale, IClientAPI remoteClient) | 1289 | protected internal void UpdatePrimScale(uint localID, Vector3 scale, IClientAPI remoteClient) |
1294 | { | 1290 | { |
1295 | SceneObjectGroup group = GetGroupByPrim(localID); | 1291 | SceneObjectPart part = GetSceneObjectPart(localID); |
1296 | if (group != null) | 1292 | |
1293 | if (part != null) | ||
1297 | { | 1294 | { |
1298 | if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId)) | 1295 | if (m_parentScene.Permissions.CanEditObject(part.ParentGroup.UUID, remoteClient.AgentId)) |
1299 | { | 1296 | { |
1300 | group.Resize(scale, localID); | 1297 | part.Resize(scale); |
1301 | } | 1298 | } |
1302 | } | 1299 | } |
1303 | } | 1300 | } |
@@ -1309,7 +1306,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1309 | { | 1306 | { |
1310 | if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId)) | 1307 | if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId)) |
1311 | { | 1308 | { |
1312 | group.GroupResize(scale, localID); | 1309 | group.GroupResize(scale); |
1313 | } | 1310 | } |
1314 | } | 1311 | } |
1315 | } | 1312 | } |
@@ -1363,19 +1360,18 @@ namespace OpenSim.Region.Framework.Scenes | |||
1363 | { | 1360 | { |
1364 | if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId)) | 1361 | if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId)) |
1365 | { | 1362 | { |
1366 | group.UpdateSingleRotation(rot,pos, localID); | 1363 | group.UpdateSingleRotation(rot, pos, localID); |
1367 | } | 1364 | } |
1368 | } | 1365 | } |
1369 | } | 1366 | } |
1370 | 1367 | ||
1371 | |||
1372 | /// <summary> | 1368 | /// <summary> |
1373 | /// | 1369 | /// Update the rotation of a whole group. |
1374 | /// </summary> | 1370 | /// </summary> |
1375 | /// <param name="localID"></param> | 1371 | /// <param name="localID"></param> |
1376 | /// <param name="rot"></param> | 1372 | /// <param name="rot"></param> |
1377 | /// <param name="remoteClient"></param> | 1373 | /// <param name="remoteClient"></param> |
1378 | protected internal void UpdatePrimRotation(uint localID, Quaternion rot, IClientAPI remoteClient) | 1374 | protected internal void UpdatePrimGroupRotation(uint localID, Quaternion rot, IClientAPI remoteClient) |
1379 | { | 1375 | { |
1380 | SceneObjectGroup group = GetGroupByPrim(localID); | 1376 | SceneObjectGroup group = GetGroupByPrim(localID); |
1381 | if (group != null) | 1377 | if (group != null) |
@@ -1394,7 +1390,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1394 | /// <param name="pos"></param> | 1390 | /// <param name="pos"></param> |
1395 | /// <param name="rot"></param> | 1391 | /// <param name="rot"></param> |
1396 | /// <param name="remoteClient"></param> | 1392 | /// <param name="remoteClient"></param> |
1397 | protected internal void UpdatePrimRotation(uint localID, Vector3 pos, Quaternion rot, IClientAPI remoteClient) | 1393 | protected internal void UpdatePrimGroupRotation(uint localID, Vector3 pos, Quaternion rot, IClientAPI remoteClient) |
1398 | { | 1394 | { |
1399 | SceneObjectGroup group = GetGroupByPrim(localID); | 1395 | SceneObjectGroup group = GetGroupByPrim(localID); |
1400 | if (group != null) | 1396 | if (group != null) |
@@ -1425,12 +1421,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
1425 | } | 1421 | } |
1426 | 1422 | ||
1427 | /// <summary> | 1423 | /// <summary> |
1428 | /// Update the position of the given part | 1424 | /// Update the position of the given group. |
1429 | /// </summary> | 1425 | /// </summary> |
1430 | /// <param name="localID"></param> | 1426 | /// <param name="localID"></param> |
1431 | /// <param name="pos"></param> | 1427 | /// <param name="pos"></param> |
1432 | /// <param name="remoteClient"></param> | 1428 | /// <param name="remoteClient"></param> |
1433 | public void UpdatePrimPosition(uint localID, Vector3 pos, IClientAPI remoteClient) | 1429 | public void UpdatePrimGroupPosition(uint localID, Vector3 pos, IClientAPI remoteClient) |
1434 | { | 1430 | { |
1435 | SceneObjectGroup group = GetGroupByPrim(localID); | 1431 | SceneObjectGroup group = GetGroupByPrim(localID); |
1436 | 1432 | ||
@@ -1481,21 +1477,26 @@ namespace OpenSim.Region.Framework.Scenes | |||
1481 | } | 1477 | } |
1482 | 1478 | ||
1483 | /// <summary> | 1479 | /// <summary> |
1484 | /// | 1480 | /// Update the flags on a scene object. This covers properties such as phantom, physics and temporary. |
1485 | /// </summary> | 1481 | /// </summary> |
1482 | /// <remarks> | ||
1483 | /// This is currently handling the incoming call from the client stack (e.g. LLClientView). | ||
1484 | /// </remarks> | ||
1486 | /// <param name="localID"></param> | 1485 | /// <param name="localID"></param> |
1487 | /// <param name="packet"></param> | 1486 | /// <param name="UsePhysics"></param> |
1487 | /// <param name="SetTemporary"></param> | ||
1488 | /// <param name="SetPhantom"></param> | ||
1488 | /// <param name="remoteClient"></param> | 1489 | /// <param name="remoteClient"></param> |
1489 | /// This routine seems to get called when a user changes object settings in the viewer. | 1490 | protected internal void UpdatePrimFlags( |
1490 | /// If some one can confirm that, please change the comment according. | 1491 | uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, IClientAPI remoteClient) |
1491 | protected internal void UpdatePrimFlags(uint localID, bool UsePhysics, bool IsTemporary, bool IsPhantom, IClientAPI remoteClient) | ||
1492 | { | 1492 | { |
1493 | SceneObjectGroup group = GetGroupByPrim(localID); | 1493 | SceneObjectGroup group = GetGroupByPrim(localID); |
1494 | if (group != null) | 1494 | if (group != null) |
1495 | { | 1495 | { |
1496 | if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId)) | 1496 | if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId)) |
1497 | { | 1497 | { |
1498 | group.UpdatePrimFlags(localID, UsePhysics, IsTemporary, IsPhantom, false); // VolumeDetect can't be set via UI and will always be off when a change is made there | 1498 | // VolumeDetect can't be set via UI and will always be off when a change is made there |
1499 | group.UpdatePrimFlags(localID, UsePhysics, SetTemporary, SetPhantom, false); | ||
1499 | } | 1500 | } |
1500 | } | 1501 | } |
1501 | } | 1502 | } |
@@ -1618,8 +1619,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
1618 | if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId)) | 1619 | if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId)) |
1619 | { | 1620 | { |
1620 | SceneObjectPart part = m_parentScene.GetSceneObjectPart(primLocalID); | 1621 | SceneObjectPart part = m_parentScene.GetSceneObjectPart(primLocalID); |
1621 | part.ClickAction = Convert.ToByte(clickAction); | 1622 | if (part != null) |
1622 | group.HasGroupChanged = true; | 1623 | { |
1624 | part.ClickAction = Convert.ToByte(clickAction); | ||
1625 | group.HasGroupChanged = true; | ||
1626 | } | ||
1623 | } | 1627 | } |
1624 | } | 1628 | } |
1625 | } | 1629 | } |
@@ -1632,8 +1636,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
1632 | if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId)) | 1636 | if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId)) |
1633 | { | 1637 | { |
1634 | SceneObjectPart part = m_parentScene.GetSceneObjectPart(primLocalID); | 1638 | SceneObjectPart part = m_parentScene.GetSceneObjectPart(primLocalID); |
1635 | part.Material = Convert.ToByte(material); | 1639 | if (part != null) |
1636 | group.HasGroupChanged = true; | 1640 | { |
1641 | part.Material = Convert.ToByte(material); | ||
1642 | group.HasGroupChanged = true; | ||
1643 | } | ||
1637 | } | 1644 | } |
1638 | } | 1645 | } |
1639 | } | 1646 | } |
@@ -1706,23 +1713,24 @@ namespace OpenSim.Region.Framework.Scenes | |||
1706 | parentGroup.areUpdatesSuspended = true; | 1713 | parentGroup.areUpdatesSuspended = true; |
1707 | 1714 | ||
1708 | List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>(); | 1715 | List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>(); |
1709 | if (parentGroup != null) | 1716 | |
1717 | // We do this in reverse to get the link order of the prims correct | ||
1718 | for (int i = children.Count - 1; i >= 0; i--) | ||
1710 | { | 1719 | { |
1711 | // We do this in reverse to get the link order of the prims correct | 1720 | SceneObjectGroup child = children[i].ParentGroup; |
1712 | for (int i = children.Count - 1; i >= 0; i--) | ||
1713 | { | ||
1714 | SceneObjectGroup child = children[i].ParentGroup; | ||
1715 | 1721 | ||
1722 | // Make sure no child prim is set for sale | ||
1723 | // So that, on delink, no prims are unwittingly | ||
1724 | // left for sale and sold off | ||
1725 | |||
1716 | if (child != null) | 1726 | if (child != null) |
1717 | { | 1727 | { |
1728 | child.RootPart.ObjectSaleType = 0; | ||
1729 | child.RootPart.SalePrice = 10; | ||
1718 | childGroups.Add(child); | 1730 | childGroups.Add(child); |
1719 | } | 1731 | } |
1720 | } | 1732 | } |
1721 | } | 1733 | } |
1722 | else | ||
1723 | { | ||
1724 | return; // parent is null so not in this region | ||
1725 | } | ||
1726 | 1734 | ||
1727 | foreach (SceneObjectGroup child in childGroups) | 1735 | foreach (SceneObjectGroup child in childGroups) |
1728 | { | 1736 | { |
diff --git a/OpenSim/Region/Framework/Scenes/SceneManager.cs b/OpenSim/Region/Framework/Scenes/SceneManager.cs index 86ba2aa..7fada4b 100644 --- a/OpenSim/Region/Framework/Scenes/SceneManager.cs +++ b/OpenSim/Region/Framework/Scenes/SceneManager.cs | |||
@@ -47,12 +47,18 @@ namespace OpenSim.Region.Framework.Scenes | |||
47 | 47 | ||
48 | public event RestartSim OnRestartSim; | 48 | public event RestartSim OnRestartSim; |
49 | 49 | ||
50 | private readonly List<Scene> m_localScenes; | 50 | private static SceneManager m_instance = null; |
51 | public static SceneManager Instance | ||
52 | { | ||
53 | get { return m_instance; } | ||
54 | } | ||
55 | |||
56 | private readonly List<Scene> m_localScenes = new List<Scene>(); | ||
51 | private Scene m_currentScene = null; | 57 | private Scene m_currentScene = null; |
52 | 58 | ||
53 | public List<Scene> Scenes | 59 | public List<Scene> Scenes |
54 | { | 60 | { |
55 | get { return m_localScenes; } | 61 | get { return new List<Scene>(m_localScenes); } |
56 | } | 62 | } |
57 | 63 | ||
58 | public Scene CurrentScene | 64 | public Scene CurrentScene |
@@ -66,13 +72,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
66 | { | 72 | { |
67 | if (m_currentScene == null) | 73 | if (m_currentScene == null) |
68 | { | 74 | { |
69 | if (m_localScenes.Count > 0) | 75 | lock (m_localScenes) |
70 | { | 76 | { |
71 | return m_localScenes[0]; | 77 | if (m_localScenes.Count > 0) |
72 | } | 78 | return m_localScenes[0]; |
73 | else | 79 | else |
74 | { | 80 | return null; |
75 | return null; | ||
76 | } | 81 | } |
77 | } | 82 | } |
78 | else | 83 | else |
@@ -84,6 +89,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
84 | 89 | ||
85 | public SceneManager() | 90 | public SceneManager() |
86 | { | 91 | { |
92 | m_instance = this; | ||
87 | m_localScenes = new List<Scene>(); | 93 | m_localScenes = new List<Scene>(); |
88 | } | 94 | } |
89 | 95 | ||
@@ -91,17 +97,21 @@ namespace OpenSim.Region.Framework.Scenes | |||
91 | { | 97 | { |
92 | // collect known shared modules in sharedModules | 98 | // collect known shared modules in sharedModules |
93 | Dictionary<string, IRegionModule> sharedModules = new Dictionary<string, IRegionModule>(); | 99 | Dictionary<string, IRegionModule> sharedModules = new Dictionary<string, IRegionModule>(); |
94 | for (int i = 0; i < m_localScenes.Count; i++) | 100 | |
101 | lock (m_localScenes) | ||
95 | { | 102 | { |
96 | // extract known shared modules from scene | 103 | for (int i = 0; i < m_localScenes.Count; i++) |
97 | foreach (string k in m_localScenes[i].Modules.Keys) | ||
98 | { | 104 | { |
99 | if (m_localScenes[i].Modules[k].IsSharedModule && | 105 | // extract known shared modules from scene |
100 | !sharedModules.ContainsKey(k)) | 106 | foreach (string k in m_localScenes[i].Modules.Keys) |
101 | sharedModules[k] = m_localScenes[i].Modules[k]; | 107 | { |
108 | if (m_localScenes[i].Modules[k].IsSharedModule && | ||
109 | !sharedModules.ContainsKey(k)) | ||
110 | sharedModules[k] = m_localScenes[i].Modules[k]; | ||
111 | } | ||
112 | // close scene/region | ||
113 | m_localScenes[i].Close(); | ||
102 | } | 114 | } |
103 | // close scene/region | ||
104 | m_localScenes[i].Close(); | ||
105 | } | 115 | } |
106 | 116 | ||
107 | // all regions/scenes are now closed, we can now safely | 117 | // all regions/scenes are now closed, we can now safely |
@@ -114,13 +124,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
114 | 124 | ||
115 | public void Close(Scene cscene) | 125 | public void Close(Scene cscene) |
116 | { | 126 | { |
117 | if (m_localScenes.Contains(cscene)) | 127 | lock (m_localScenes) |
118 | { | 128 | { |
119 | for (int i = 0; i < m_localScenes.Count; i++) | 129 | if (m_localScenes.Contains(cscene)) |
120 | { | 130 | { |
121 | if (m_localScenes[i].Equals(cscene)) | 131 | for (int i = 0; i < m_localScenes.Count; i++) |
122 | { | 132 | { |
123 | m_localScenes[i].Close(); | 133 | if (m_localScenes[i].Equals(cscene)) |
134 | { | ||
135 | m_localScenes[i].Close(); | ||
136 | } | ||
124 | } | 137 | } |
125 | } | 138 | } |
126 | } | 139 | } |
@@ -129,27 +142,33 @@ namespace OpenSim.Region.Framework.Scenes | |||
129 | public void Add(Scene scene) | 142 | public void Add(Scene scene) |
130 | { | 143 | { |
131 | scene.OnRestart += HandleRestart; | 144 | scene.OnRestart += HandleRestart; |
132 | m_localScenes.Add(scene); | 145 | |
146 | lock (m_localScenes) | ||
147 | m_localScenes.Add(scene); | ||
133 | } | 148 | } |
134 | 149 | ||
135 | public void HandleRestart(RegionInfo rdata) | 150 | public void HandleRestart(RegionInfo rdata) |
136 | { | 151 | { |
137 | m_log.Error("[SCENEMANAGER]: Got Restart message for region:" + rdata.RegionName + " Sending up to main"); | 152 | m_log.Error("[SCENEMANAGER]: Got Restart message for region:" + rdata.RegionName + " Sending up to main"); |
138 | int RegionSceneElement = -1; | 153 | int RegionSceneElement = -1; |
139 | for (int i = 0; i < m_localScenes.Count; i++) | 154 | |
155 | lock (m_localScenes) | ||
140 | { | 156 | { |
141 | if (rdata.RegionName == m_localScenes[i].RegionInfo.RegionName) | 157 | for (int i = 0; i < m_localScenes.Count; i++) |
142 | { | 158 | { |
143 | RegionSceneElement = i; | 159 | if (rdata.RegionName == m_localScenes[i].RegionInfo.RegionName) |
160 | { | ||
161 | RegionSceneElement = i; | ||
162 | } | ||
144 | } | 163 | } |
145 | } | ||
146 | 164 | ||
147 | // Now we make sure the region is no longer known about by the SceneManager | 165 | // Now we make sure the region is no longer known about by the SceneManager |
148 | // Prevents duplicates. | 166 | // Prevents duplicates. |
149 | 167 | ||
150 | if (RegionSceneElement >= 0) | 168 | if (RegionSceneElement >= 0) |
151 | { | 169 | { |
152 | m_localScenes.RemoveAt(RegionSceneElement); | 170 | m_localScenes.RemoveAt(RegionSceneElement); |
171 | } | ||
153 | } | 172 | } |
154 | 173 | ||
155 | // Send signal to main that we're restarting this sim. | 174 | // Send signal to main that we're restarting this sim. |
@@ -160,28 +179,32 @@ namespace OpenSim.Region.Framework.Scenes | |||
160 | { | 179 | { |
161 | RegionInfo Result = null; | 180 | RegionInfo Result = null; |
162 | 181 | ||
163 | for (int i = 0; i < m_localScenes.Count; i++) | 182 | lock (m_localScenes) |
164 | { | ||
165 | if (m_localScenes[i].RegionInfo.RegionHandle == regionHandle) | ||
166 | { | ||
167 | // Inform other regions to tell their avatar about me | ||
168 | Result = m_localScenes[i].RegionInfo; | ||
169 | } | ||
170 | } | ||
171 | if (Result != null) | ||
172 | { | 183 | { |
173 | for (int i = 0; i < m_localScenes.Count; i++) | 184 | for (int i = 0; i < m_localScenes.Count; i++) |
174 | { | 185 | { |
175 | if (m_localScenes[i].RegionInfo.RegionHandle != regionHandle) | 186 | if (m_localScenes[i].RegionInfo.RegionHandle == regionHandle) |
176 | { | 187 | { |
177 | // Inform other regions to tell their avatar about me | 188 | // Inform other regions to tell their avatar about me |
178 | //m_localScenes[i].OtherRegionUp(Result); | 189 | Result = m_localScenes[i].RegionInfo; |
179 | } | 190 | } |
180 | } | 191 | } |
181 | } | 192 | |
182 | else | 193 | if (Result != null) |
183 | { | 194 | { |
184 | m_log.Error("[REGION]: Unable to notify Other regions of this Region coming up"); | 195 | for (int i = 0; i < m_localScenes.Count; i++) |
196 | { | ||
197 | if (m_localScenes[i].RegionInfo.RegionHandle != regionHandle) | ||
198 | { | ||
199 | // Inform other regions to tell their avatar about me | ||
200 | //m_localScenes[i].OtherRegionUp(Result); | ||
201 | } | ||
202 | } | ||
203 | } | ||
204 | else | ||
205 | { | ||
206 | m_log.Error("[REGION]: Unable to notify Other regions of this Region coming up"); | ||
207 | } | ||
185 | } | 208 | } |
186 | } | 209 | } |
187 | 210 | ||
@@ -285,7 +308,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
285 | { | 308 | { |
286 | if (m_currentScene == null) | 309 | if (m_currentScene == null) |
287 | { | 310 | { |
288 | m_localScenes.ForEach(func); | 311 | lock (m_localScenes) |
312 | m_localScenes.ForEach(func); | ||
289 | } | 313 | } |
290 | else | 314 | else |
291 | { | 315 | { |
@@ -314,12 +338,15 @@ namespace OpenSim.Region.Framework.Scenes | |||
314 | } | 338 | } |
315 | else | 339 | else |
316 | { | 340 | { |
317 | foreach (Scene scene in m_localScenes) | 341 | lock (m_localScenes) |
318 | { | 342 | { |
319 | if (String.Compare(scene.RegionInfo.RegionName, regionName, true) == 0) | 343 | foreach (Scene scene in m_localScenes) |
320 | { | 344 | { |
321 | m_currentScene = scene; | 345 | if (String.Compare(scene.RegionInfo.RegionName, regionName, true) == 0) |
322 | return true; | 346 | { |
347 | m_currentScene = scene; | ||
348 | return true; | ||
349 | } | ||
323 | } | 350 | } |
324 | } | 351 | } |
325 | 352 | ||
@@ -331,12 +358,15 @@ namespace OpenSim.Region.Framework.Scenes | |||
331 | { | 358 | { |
332 | m_log.Debug("Searching for Region: '" + regionID + "'"); | 359 | m_log.Debug("Searching for Region: '" + regionID + "'"); |
333 | 360 | ||
334 | foreach (Scene scene in m_localScenes) | 361 | lock (m_localScenes) |
335 | { | 362 | { |
336 | if (scene.RegionInfo.RegionID == regionID) | 363 | foreach (Scene scene in m_localScenes) |
337 | { | 364 | { |
338 | m_currentScene = scene; | 365 | if (scene.RegionInfo.RegionID == regionID) |
339 | return true; | 366 | { |
367 | m_currentScene = scene; | ||
368 | return true; | ||
369 | } | ||
340 | } | 370 | } |
341 | } | 371 | } |
342 | 372 | ||
@@ -345,26 +375,33 @@ namespace OpenSim.Region.Framework.Scenes | |||
345 | 375 | ||
346 | public bool TryGetScene(string regionName, out Scene scene) | 376 | public bool TryGetScene(string regionName, out Scene scene) |
347 | { | 377 | { |
348 | foreach (Scene mscene in m_localScenes) | 378 | lock (m_localScenes) |
349 | { | 379 | { |
350 | if (String.Compare(mscene.RegionInfo.RegionName, regionName, true) == 0) | 380 | foreach (Scene mscene in m_localScenes) |
351 | { | 381 | { |
352 | scene = mscene; | 382 | if (String.Compare(mscene.RegionInfo.RegionName, regionName, true) == 0) |
353 | return true; | 383 | { |
384 | scene = mscene; | ||
385 | return true; | ||
386 | } | ||
354 | } | 387 | } |
355 | } | 388 | } |
389 | |||
356 | scene = null; | 390 | scene = null; |
357 | return false; | 391 | return false; |
358 | } | 392 | } |
359 | 393 | ||
360 | public bool TryGetScene(UUID regionID, out Scene scene) | 394 | public bool TryGetScene(UUID regionID, out Scene scene) |
361 | { | 395 | { |
362 | foreach (Scene mscene in m_localScenes) | 396 | lock (m_localScenes) |
363 | { | 397 | { |
364 | if (mscene.RegionInfo.RegionID == regionID) | 398 | foreach (Scene mscene in m_localScenes) |
365 | { | 399 | { |
366 | scene = mscene; | 400 | if (mscene.RegionInfo.RegionID == regionID) |
367 | return true; | 401 | { |
402 | scene = mscene; | ||
403 | return true; | ||
404 | } | ||
368 | } | 405 | } |
369 | } | 406 | } |
370 | 407 | ||
@@ -374,13 +411,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
374 | 411 | ||
375 | public bool TryGetScene(uint locX, uint locY, out Scene scene) | 412 | public bool TryGetScene(uint locX, uint locY, out Scene scene) |
376 | { | 413 | { |
377 | foreach (Scene mscene in m_localScenes) | 414 | lock (m_localScenes) |
378 | { | 415 | { |
379 | if (mscene.RegionInfo.RegionLocX == locX && | 416 | foreach (Scene mscene in m_localScenes) |
380 | mscene.RegionInfo.RegionLocY == locY) | ||
381 | { | 417 | { |
382 | scene = mscene; | 418 | if (mscene.RegionInfo.RegionLocX == locX && |
383 | return true; | 419 | mscene.RegionInfo.RegionLocY == locY) |
420 | { | ||
421 | scene = mscene; | ||
422 | return true; | ||
423 | } | ||
384 | } | 424 | } |
385 | } | 425 | } |
386 | 426 | ||
@@ -390,13 +430,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
390 | 430 | ||
391 | public bool TryGetScene(IPEndPoint ipEndPoint, out Scene scene) | 431 | public bool TryGetScene(IPEndPoint ipEndPoint, out Scene scene) |
392 | { | 432 | { |
393 | foreach (Scene mscene in m_localScenes) | 433 | lock (m_localScenes) |
394 | { | 434 | { |
395 | if ((mscene.RegionInfo.InternalEndPoint.Equals(ipEndPoint.Address)) && | 435 | foreach (Scene mscene in m_localScenes) |
396 | (mscene.RegionInfo.InternalEndPoint.Port == ipEndPoint.Port)) | ||
397 | { | 436 | { |
398 | scene = mscene; | 437 | if ((mscene.RegionInfo.InternalEndPoint.Equals(ipEndPoint.Address)) && |
399 | return true; | 438 | (mscene.RegionInfo.InternalEndPoint.Port == ipEndPoint.Port)) |
439 | { | ||
440 | scene = mscene; | ||
441 | return true; | ||
442 | } | ||
400 | } | 443 | } |
401 | } | 444 | } |
402 | 445 | ||
@@ -465,11 +508,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
465 | 508 | ||
466 | public RegionInfo GetRegionInfo(UUID regionID) | 509 | public RegionInfo GetRegionInfo(UUID regionID) |
467 | { | 510 | { |
468 | foreach (Scene scene in m_localScenes) | 511 | lock (m_localScenes) |
469 | { | 512 | { |
470 | if (scene.RegionInfo.RegionID == regionID) | 513 | foreach (Scene scene in m_localScenes) |
471 | { | 514 | { |
472 | return scene.RegionInfo; | 515 | if (scene.RegionInfo.RegionID == regionID) |
516 | { | ||
517 | return scene.RegionInfo; | ||
518 | } | ||
473 | } | 519 | } |
474 | } | 520 | } |
475 | 521 | ||
@@ -488,11 +534,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
488 | 534 | ||
489 | public bool TryGetScenePresence(UUID avatarId, out ScenePresence avatar) | 535 | public bool TryGetScenePresence(UUID avatarId, out ScenePresence avatar) |
490 | { | 536 | { |
491 | foreach (Scene scene in m_localScenes) | 537 | lock (m_localScenes) |
492 | { | 538 | { |
493 | if (scene.TryGetScenePresence(avatarId, out avatar)) | 539 | foreach (Scene scene in m_localScenes) |
494 | { | 540 | { |
495 | return true; | 541 | if (scene.TryGetScenePresence(avatarId, out avatar)) |
542 | { | ||
543 | return true; | ||
544 | } | ||
496 | } | 545 | } |
497 | } | 546 | } |
498 | 547 | ||
@@ -503,12 +552,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
503 | public bool TryGetAvatarsScene(UUID avatarId, out Scene scene) | 552 | public bool TryGetAvatarsScene(UUID avatarId, out Scene scene) |
504 | { | 553 | { |
505 | ScenePresence avatar = null; | 554 | ScenePresence avatar = null; |
506 | foreach (Scene mScene in m_localScenes) | 555 | |
556 | lock (m_localScenes) | ||
507 | { | 557 | { |
508 | if (mScene.TryGetScenePresence(avatarId, out avatar)) | 558 | foreach (Scene mScene in m_localScenes) |
509 | { | 559 | { |
510 | scene = mScene; | 560 | if (mScene.TryGetScenePresence(avatarId, out avatar)) |
511 | return true; | 561 | { |
562 | scene = mScene; | ||
563 | return true; | ||
564 | } | ||
512 | } | 565 | } |
513 | } | 566 | } |
514 | 567 | ||
@@ -518,17 +571,22 @@ namespace OpenSim.Region.Framework.Scenes | |||
518 | 571 | ||
519 | public void CloseScene(Scene scene) | 572 | public void CloseScene(Scene scene) |
520 | { | 573 | { |
521 | m_localScenes.Remove(scene); | 574 | lock (m_localScenes) |
575 | m_localScenes.Remove(scene); | ||
576 | |||
522 | scene.Close(); | 577 | scene.Close(); |
523 | } | 578 | } |
524 | 579 | ||
525 | public bool TryGetAvatarByName(string avatarName, out ScenePresence avatar) | 580 | public bool TryGetAvatarByName(string avatarName, out ScenePresence avatar) |
526 | { | 581 | { |
527 | foreach (Scene scene in m_localScenes) | 582 | lock (m_localScenes) |
528 | { | 583 | { |
529 | if (scene.TryGetAvatarByName(avatarName, out avatar)) | 584 | foreach (Scene scene in m_localScenes) |
530 | { | 585 | { |
531 | return true; | 586 | if (scene.TryGetAvatarByName(avatarName, out avatar)) |
587 | { | ||
588 | return true; | ||
589 | } | ||
532 | } | 590 | } |
533 | } | 591 | } |
534 | 592 | ||
@@ -538,7 +596,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
538 | 596 | ||
539 | public void ForEachScene(Action<Scene> action) | 597 | public void ForEachScene(Action<Scene> action) |
540 | { | 598 | { |
541 | m_localScenes.ForEach(action); | 599 | lock (m_localScenes) |
600 | m_localScenes.ForEach(action); | ||
542 | } | 601 | } |
543 | } | 602 | } |
544 | } | 603 | } |
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 6c47645..b1b76dd 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | |||
@@ -209,25 +209,87 @@ namespace OpenSim.Region.Framework.Scenes | |||
209 | return true; | 209 | return true; |
210 | return false; | 210 | return false; |
211 | } | 211 | } |
212 | 212 | ||
213 | /// <value> | 213 | /// <summary> |
214 | /// Is this scene object acting as an attachment? | 214 | /// Is this scene object acting as an attachment? |
215 | /// | 215 | /// </summary> |
216 | /// We return false if the group has already been deleted. | 216 | public bool IsAttachment { get; set; } |
217 | /// | 217 | |
218 | /// TODO: At the moment set must be done on the part itself. There may be a case for doing it here since I | 218 | /// <summary> |
219 | /// presume either all or no parts in a linkset can be part of an attachment (in which | 219 | /// The avatar to which this scene object is attached. |
220 | /// case the value would get proprogated down into all the descendent parts). | 220 | /// </summary> |
221 | /// </value> | 221 | /// <remarks> |
222 | public bool IsAttachment | 222 | /// If we're not attached to an avatar then this is UUID.Zero |
223 | /// </remarks> | ||
224 | public UUID AttachedAvatar { get; set; } | ||
225 | |||
226 | /// <summary> | ||
227 | /// Attachment point of this scene object to an avatar. | ||
228 | /// </summary> | ||
229 | /// <remarks> | ||
230 | /// 0 if we're not attached to anything | ||
231 | /// </remarks> | ||
232 | public uint AttachmentPoint | ||
223 | { | 233 | { |
224 | get | 234 | get |
225 | { | 235 | { |
226 | if (!IsDeleted) | 236 | return m_rootPart.Shape.State; |
227 | return m_rootPart.IsAttachment; | ||
228 | |||
229 | return false; | ||
230 | } | 237 | } |
238 | |||
239 | set | ||
240 | { | ||
241 | IsAttachment = value != 0; | ||
242 | m_rootPart.Shape.State = (byte)value; | ||
243 | } | ||
244 | } | ||
245 | |||
246 | public void ClearPartAttachmentData() | ||
247 | { | ||
248 | AttachmentPoint = 0; | ||
249 | |||
250 | // Even though we don't use child part state parameters for attachments any more, we still need to set | ||
251 | // these to zero since having them non-zero in rezzed scene objects will crash some clients. Even if | ||
252 | // we store them correctly, scene objects that we receive from elsewhere might not. | ||
253 | foreach (SceneObjectPart part in Parts) | ||
254 | part.Shape.State = 0; | ||
255 | } | ||
256 | |||
257 | /// <summary> | ||
258 | /// Is this scene object phantom? | ||
259 | /// </summary> | ||
260 | /// <remarks> | ||
261 | /// Updating must currently take place through UpdatePrimFlags() | ||
262 | /// </remarks> | ||
263 | public bool IsPhantom | ||
264 | { | ||
265 | get { return (RootPart.Flags & PrimFlags.Phantom) != 0; } | ||
266 | } | ||
267 | |||
268 | /// <summary> | ||
269 | /// Does this scene object use physics? | ||
270 | /// </summary> | ||
271 | /// <remarks> | ||
272 | /// Updating must currently take place through UpdatePrimFlags() | ||
273 | /// </remarks> | ||
274 | public bool UsesPhysics | ||
275 | { | ||
276 | get { return (RootPart.Flags & PrimFlags.TemporaryOnRez) != 0; } | ||
277 | } | ||
278 | |||
279 | /// <summary> | ||
280 | /// Is this scene object temporary? | ||
281 | /// </summary> | ||
282 | /// <remarks> | ||
283 | /// Updating must currently take place through UpdatePrimFlags() | ||
284 | /// </remarks> | ||
285 | public bool IsTemporary | ||
286 | { | ||
287 | get { return (RootPart.Flags & PrimFlags.TemporaryOnRez) != 0; } | ||
288 | } | ||
289 | |||
290 | public bool IsVolumeDetect | ||
291 | { | ||
292 | get { return RootPart.VolumeDetectActive; } | ||
231 | } | 293 | } |
232 | 294 | ||
233 | public float scriptScore; | 295 | public float scriptScore; |
@@ -261,11 +323,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
261 | /// </summary> | 323 | /// </summary> |
262 | public override string Name | 324 | public override string Name |
263 | { | 325 | { |
264 | get { | 326 | get { return RootPart.Name; } |
265 | if (RootPart == null) | ||
266 | return String.Empty; | ||
267 | return RootPart.Name; | ||
268 | } | ||
269 | set { RootPart.Name = value; } | 327 | set { RootPart.Name = value; } |
270 | } | 328 | } |
271 | 329 | ||
@@ -305,6 +363,38 @@ namespace OpenSim.Region.Framework.Scenes | |||
305 | get { return m_rootPart.RotationOffset; } | 363 | get { return m_rootPart.RotationOffset; } |
306 | } | 364 | } |
307 | 365 | ||
366 | public Vector3 GroupScale | ||
367 | { | ||
368 | get | ||
369 | { | ||
370 | Vector3 minScale = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionSize); | ||
371 | Vector3 maxScale = Vector3.Zero; | ||
372 | Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f); | ||
373 | |||
374 | SceneObjectPart[] parts = m_parts.GetArray(); | ||
375 | for (int i = 0; i < parts.Length; i++) | ||
376 | { | ||
377 | SceneObjectPart part = parts[i]; | ||
378 | Vector3 partscale = part.Scale; | ||
379 | Vector3 partoffset = part.OffsetPosition; | ||
380 | |||
381 | minScale.X = (partscale.X + partoffset.X < minScale.X) ? partscale.X + partoffset.X : minScale.X; | ||
382 | minScale.Y = (partscale.Y + partoffset.Y < minScale.Y) ? partscale.Y + partoffset.Y : minScale.Y; | ||
383 | minScale.Z = (partscale.Z + partoffset.Z < minScale.Z) ? partscale.Z + partoffset.Z : minScale.Z; | ||
384 | |||
385 | maxScale.X = (partscale.X + partoffset.X > maxScale.X) ? partscale.X + partoffset.X : maxScale.X; | ||
386 | maxScale.Y = (partscale.Y + partoffset.Y > maxScale.Y) ? partscale.Y + partoffset.Y : maxScale.Y; | ||
387 | maxScale.Z = (partscale.Z + partoffset.Z > maxScale.Z) ? partscale.Z + partoffset.Z : maxScale.Z; | ||
388 | } | ||
389 | |||
390 | finalScale.X = (minScale.X > maxScale.X) ? minScale.X : maxScale.X; | ||
391 | finalScale.Y = (minScale.Y > maxScale.Y) ? minScale.Y : maxScale.Y; | ||
392 | finalScale.Z = (minScale.Z > maxScale.Z) ? minScale.Z : maxScale.Z; | ||
393 | |||
394 | return finalScale; | ||
395 | } | ||
396 | } | ||
397 | |||
308 | public UUID GroupID | 398 | public UUID GroupID |
309 | { | 399 | { |
310 | get { return m_rootPart.GroupID; } | 400 | get { return m_rootPart.GroupID; } |
@@ -344,11 +434,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
344 | /// <summary> | 434 | /// <summary> |
345 | /// Check both the attachment property and the relevant properties of the underlying root part. | 435 | /// Check both the attachment property and the relevant properties of the underlying root part. |
346 | /// </summary> | 436 | /// </summary> |
437 | /// <remarks> | ||
347 | /// This is necessary in some cases, particularly when a scene object has just crossed into a region and doesn't | 438 | /// This is necessary in some cases, particularly when a scene object has just crossed into a region and doesn't |
348 | /// have the IsAttachment property yet checked. | 439 | /// have the IsAttachment property yet checked. |
349 | /// | 440 | /// |
350 | /// FIXME: However, this should be fixed so that this property | 441 | /// FIXME: However, this should be fixed so that this property |
351 | /// propertly reflects the underlying status. | 442 | /// propertly reflects the underlying status. |
443 | /// </remarks> | ||
352 | /// <returns></returns> | 444 | /// <returns></returns> |
353 | public bool IsAttachmentCheckFull() | 445 | public bool IsAttachmentCheckFull() |
354 | { | 446 | { |
@@ -682,7 +774,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
682 | part.ParentID = m_rootPart.LocalId; | 774 | part.ParentID = m_rootPart.LocalId; |
683 | //m_log.DebugFormat("[SCENE]: Given local id {0} to part {1}, linknum {2}, parent {3} {4}", part.LocalId, part.UUID, part.LinkNum, part.ParentID, part.ParentUUID); | 775 | //m_log.DebugFormat("[SCENE]: Given local id {0} to part {1}, linknum {2}, parent {3} {4}", part.LocalId, part.UUID, part.LinkNum, part.ParentID, part.ParentUUID); |
684 | } | 776 | } |
685 | 777 | ||
686 | ApplyPhysics(m_scene.m_physicalPrim); | 778 | ApplyPhysics(m_scene.m_physicalPrim); |
687 | 779 | ||
688 | if (RootPart.PhysActor != null) | 780 | if (RootPart.PhysActor != null) |
@@ -693,34 +785,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
693 | //ScheduleGroupForFullUpdate(); | 785 | //ScheduleGroupForFullUpdate(); |
694 | } | 786 | } |
695 | 787 | ||
696 | public Vector3 GroupScale() | ||
697 | { | ||
698 | Vector3 minScale = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionSize); | ||
699 | Vector3 maxScale = Vector3.Zero; | ||
700 | Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f); | ||
701 | |||
702 | SceneObjectPart[] parts = m_parts.GetArray(); | ||
703 | for (int i = 0; i < parts.Length; i++) | ||
704 | { | ||
705 | SceneObjectPart part = parts[i]; | ||
706 | Vector3 partscale = part.Scale; | ||
707 | Vector3 partoffset = part.OffsetPosition; | ||
708 | |||
709 | minScale.X = (partscale.X + partoffset.X < minScale.X) ? partscale.X + partoffset.X : minScale.X; | ||
710 | minScale.Y = (partscale.Y + partoffset.Y < minScale.Y) ? partscale.Y + partoffset.Y : minScale.Y; | ||
711 | minScale.Z = (partscale.Z + partoffset.Z < minScale.Z) ? partscale.Z + partoffset.Z : minScale.Z; | ||
712 | |||
713 | maxScale.X = (partscale.X + partoffset.X > maxScale.X) ? partscale.X + partoffset.X : maxScale.X; | ||
714 | maxScale.Y = (partscale.Y + partoffset.Y > maxScale.Y) ? partscale.Y + partoffset.Y : maxScale.Y; | ||
715 | maxScale.Z = (partscale.Z + partoffset.Z > maxScale.Z) ? partscale.Z + partoffset.Z : maxScale.Z; | ||
716 | } | ||
717 | |||
718 | finalScale.X = (minScale.X > maxScale.X) ? minScale.X : maxScale.X; | ||
719 | finalScale.Y = (minScale.Y > maxScale.Y) ? minScale.Y : maxScale.Y; | ||
720 | finalScale.Z = (minScale.Z > maxScale.Z) ? minScale.Z : maxScale.Z; | ||
721 | return finalScale; | ||
722 | |||
723 | } | ||
724 | public EntityIntersection TestIntersection(Ray hRay, bool frontFacesOnly, bool faceCenters) | 788 | public EntityIntersection TestIntersection(Ray hRay, bool frontFacesOnly, bool faceCenters) |
725 | { | 789 | { |
726 | // We got a request from the inner_scene to raytrace along the Ray hRay | 790 | // We got a request from the inner_scene to raytrace along the Ray hRay |
@@ -1082,6 +1146,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1082 | } | 1146 | } |
1083 | } | 1147 | } |
1084 | 1148 | ||
1149 | <<<<<<< HEAD | ||
1085 | /// <summary> | 1150 | /// <summary> |
1086 | /// Add the avatar to this linkset (avatar is sat). | 1151 | /// Add the avatar to this linkset (avatar is sat). |
1087 | /// </summary> | 1152 | /// </summary> |
@@ -1263,6 +1328,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
1263 | //m_rootPart.ScheduleFullUpdate(); | 1328 | //m_rootPart.ScheduleFullUpdate(); |
1264 | } | 1329 | } |
1265 | 1330 | ||
1331 | ======= | ||
1332 | >>>>>>> 9f75eaf50e42ef6409fc272ba33a817241907ed8 | ||
1266 | /// <summary> | 1333 | /// <summary> |
1267 | /// | 1334 | /// |
1268 | /// </summary> | 1335 | /// </summary> |
@@ -1320,11 +1387,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
1320 | public void AddPart(SceneObjectPart part) | 1387 | public void AddPart(SceneObjectPart part) |
1321 | { | 1388 | { |
1322 | part.SetParent(this); | 1389 | part.SetParent(this); |
1390 | <<<<<<< HEAD | ||
1323 | m_parts.Add(part.UUID, part); | 1391 | m_parts.Add(part.UUID, part); |
1324 | 1392 | ||
1325 | part.LinkNum = m_parts.Count; | 1393 | part.LinkNum = m_parts.Count; |
1326 | 1394 | ||
1327 | if (part.LinkNum == 2 && RootPart != null) | 1395 | if (part.LinkNum == 2 && RootPart != null) |
1396 | ======= | ||
1397 | part.LinkNum = m_parts.Add(part.UUID, part); | ||
1398 | if (part.LinkNum == 2) | ||
1399 | >>>>>>> 9f75eaf50e42ef6409fc272ba33a817241907ed8 | ||
1328 | RootPart.LinkNum = 1; | 1400 | RootPart.LinkNum = 1; |
1329 | } | 1401 | } |
1330 | 1402 | ||
@@ -1407,7 +1479,15 @@ namespace OpenSim.Region.Framework.Scenes | |||
1407 | 1479 | ||
1408 | public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient) | 1480 | public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient) |
1409 | { | 1481 | { |
1482 | <<<<<<< HEAD | ||
1410 | part.StoreUndoState(UndoType.STATE_PRIM_ALL); | 1483 | part.StoreUndoState(UndoType.STATE_PRIM_ALL); |
1484 | ======= | ||
1485 | // m_log.DebugFormat( | ||
1486 | // "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}", | ||
1487 | // remoteClient.Name, part.Name, part.LocalId, offsetPos); | ||
1488 | |||
1489 | part.StoreUndoState(); | ||
1490 | >>>>>>> 9f75eaf50e42ef6409fc272ba33a817241907ed8 | ||
1411 | part.OnGrab(offsetPos, remoteClient); | 1491 | part.OnGrab(offsetPos, remoteClient); |
1412 | } | 1492 | } |
1413 | 1493 | ||
@@ -1711,16 +1791,30 @@ namespace OpenSim.Region.Framework.Scenes | |||
1711 | dupe.m_isBackedUp = false; | 1791 | dupe.m_isBackedUp = false; |
1712 | dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); | 1792 | dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); |
1713 | 1793 | ||
1794 | <<<<<<< HEAD | ||
1714 | // Warning, The following code related to previousAttachmentStatus is needed so that clones of | 1795 | // Warning, The following code related to previousAttachmentStatus is needed so that clones of |
1715 | // attachments do not bordercross while they're being duplicated. This is hacktastic! | 1796 | // attachments do not bordercross while they're being duplicated. This is hacktastic! |
1716 | // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! | 1797 | // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! |
1717 | // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state | 1798 | // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state |
1718 | // (which should be false anyway) set it as an Attachment and then set it's Absolute Position, | 1799 | // (which should be false anyway) set it as an Attachment and then set it's Absolute Position, |
1719 | // then restore it's attachment state | 1800 | // then restore it's attachment state |
1801 | ======= | ||
1802 | bool previousAttachmentStatus = dupe.IsAttachment; | ||
1803 | |||
1804 | if (!userExposed) | ||
1805 | dupe.IsAttachment = true; | ||
1806 | >>>>>>> 9f75eaf50e42ef6409fc272ba33a817241907ed8 | ||
1720 | 1807 | ||
1721 | // This is only necessary when userExposed is false! | 1808 | // This is only necessary when userExposed is false! |
1722 | 1809 | ||
1810 | <<<<<<< HEAD | ||
1723 | bool previousAttachmentStatus = dupe.RootPart.IsAttachment; | 1811 | bool previousAttachmentStatus = dupe.RootPart.IsAttachment; |
1812 | ======= | ||
1813 | if (!userExposed) | ||
1814 | { | ||
1815 | dupe.IsAttachment = previousAttachmentStatus; | ||
1816 | } | ||
1817 | >>>>>>> 9f75eaf50e42ef6409fc272ba33a817241907ed8 | ||
1724 | 1818 | ||
1725 | if (!userExposed) | 1819 | if (!userExposed) |
1726 | dupe.RootPart.IsAttachment = true; | 1820 | dupe.RootPart.IsAttachment = true; |
@@ -1781,7 +1875,26 @@ namespace OpenSim.Region.Framework.Scenes | |||
1781 | dupe.HasGroupChanged = true; | 1875 | dupe.HasGroupChanged = true; |
1782 | dupe.AttachToBackup(); | 1876 | dupe.AttachToBackup(); |
1783 | 1877 | ||
1878 | <<<<<<< HEAD | ||
1784 | ScheduleGroupForFullUpdate(); | 1879 | ScheduleGroupForFullUpdate(); |
1880 | ======= | ||
1881 | // Need to duplicate the physics actor as well | ||
1882 | if (part.PhysActor != null && userExposed) | ||
1883 | { | ||
1884 | PrimitiveBaseShape pbs = newPart.Shape; | ||
1885 | |||
1886 | newPart.PhysActor | ||
1887 | = m_scene.PhysicsScene.AddPrimShape( | ||
1888 | string.Format("{0}/{1}", newPart.Name, newPart.UUID), | ||
1889 | pbs, | ||
1890 | newPart.AbsolutePosition, | ||
1891 | newPart.Scale, | ||
1892 | newPart.RotationOffset, | ||
1893 | part.PhysActor.IsPhysical, | ||
1894 | newPart.LocalId); | ||
1895 | |||
1896 | newPart.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true); | ||
1897 | >>>>>>> 9f75eaf50e42ef6409fc272ba33a817241907ed8 | ||
1785 | } | 1898 | } |
1786 | } | 1899 | } |
1787 | finally | 1900 | finally |
@@ -1802,36 +1915,24 @@ namespace OpenSim.Region.Framework.Scenes | |||
1802 | SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); | 1915 | SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); |
1803 | } | 1916 | } |
1804 | 1917 | ||
1805 | public void ScriptSetPhysicsStatus(bool UsePhysics) | 1918 | public void ScriptSetPhysicsStatus(bool usePhysics) |
1806 | { | 1919 | { |
1807 | bool IsTemporary = ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0); | 1920 | UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect); |
1808 | bool IsPhantom = ((RootPart.Flags & PrimFlags.Phantom) != 0); | ||
1809 | bool IsVolumeDetect = RootPart.VolumeDetectActive; | ||
1810 | UpdatePrimFlags(RootPart.LocalId, UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect); | ||
1811 | } | 1921 | } |
1812 | 1922 | ||
1813 | public void ScriptSetTemporaryStatus(bool TemporaryStatus) | 1923 | public void ScriptSetTemporaryStatus(bool makeTemporary) |
1814 | { | 1924 | { |
1815 | bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0); | 1925 | UpdatePrimFlags(RootPart.LocalId, UsesPhysics, makeTemporary, IsPhantom, IsVolumeDetect); |
1816 | bool IsPhantom = ((RootPart.Flags & PrimFlags.Phantom) != 0); | ||
1817 | bool IsVolumeDetect = RootPart.VolumeDetectActive; | ||
1818 | UpdatePrimFlags(RootPart.LocalId, UsePhysics, TemporaryStatus, IsPhantom, IsVolumeDetect); | ||
1819 | } | 1926 | } |
1820 | 1927 | ||
1821 | public void ScriptSetPhantomStatus(bool PhantomStatus) | 1928 | public void ScriptSetPhantomStatus(bool makePhantom) |
1822 | { | 1929 | { |
1823 | bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0); | 1930 | UpdatePrimFlags(RootPart.LocalId, UsesPhysics, IsTemporary, makePhantom, IsVolumeDetect); |
1824 | bool IsTemporary = ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0); | ||
1825 | bool IsVolumeDetect = RootPart.VolumeDetectActive; | ||
1826 | UpdatePrimFlags(RootPart.LocalId, UsePhysics, IsTemporary, PhantomStatus, IsVolumeDetect); | ||
1827 | } | 1931 | } |
1828 | 1932 | ||
1829 | public void ScriptSetVolumeDetect(bool VDStatus) | 1933 | public void ScriptSetVolumeDetect(bool makeVolumeDetect) |
1830 | { | 1934 | { |
1831 | bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0); | 1935 | UpdatePrimFlags(RootPart.LocalId, UsesPhysics, IsTemporary, IsPhantom, makeVolumeDetect); |
1832 | bool IsTemporary = ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0); | ||
1833 | bool IsPhantom = ((RootPart.Flags & PrimFlags.Phantom) != 0); | ||
1834 | UpdatePrimFlags(RootPart.LocalId, UsePhysics, IsTemporary, IsPhantom, VDStatus); | ||
1835 | 1936 | ||
1836 | /* | 1937 | /* |
1837 | ScriptSetPhantomStatus(false); // What ever it was before, now it's not phantom anymore | 1938 | ScriptSetPhantomStatus(false); // What ever it was before, now it's not phantom anymore |
@@ -1849,126 +1950,87 @@ namespace OpenSim.Region.Framework.Scenes | |||
1849 | 1950 | ||
1850 | public void applyImpulse(Vector3 impulse) | 1951 | public void applyImpulse(Vector3 impulse) |
1851 | { | 1952 | { |
1852 | // We check if rootpart is null here because scripts don't delete if you delete the host. | 1953 | if (IsAttachment) |
1853 | // This means that unfortunately, we can pass a null physics actor to Simulate! | ||
1854 | // Make sure we don't do that! | ||
1855 | SceneObjectPart rootpart = m_rootPart; | ||
1856 | if (rootpart != null) | ||
1857 | { | 1954 | { |
1858 | if (IsAttachment) | 1955 | ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar); |
1956 | if (avatar != null) | ||
1859 | { | 1957 | { |
1860 | ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar); | 1958 | avatar.PushForce(impulse); |
1861 | if (avatar != null) | ||
1862 | { | ||
1863 | avatar.PushForce(impulse); | ||
1864 | } | ||
1865 | } | 1959 | } |
1866 | else | 1960 | } |
1961 | else | ||
1962 | { | ||
1963 | if (RootPart.PhysActor != null) | ||
1867 | { | 1964 | { |
1868 | if (rootpart.PhysActor != null) | 1965 | RootPart.PhysActor.AddForce(impulse, true); |
1869 | { | 1966 | m_scene.PhysicsScene.AddPhysicsActorTaint(RootPart.PhysActor); |
1870 | rootpart.PhysActor.AddForce(impulse, true); | ||
1871 | m_scene.PhysicsScene.AddPhysicsActorTaint(rootpart.PhysActor); | ||
1872 | } | ||
1873 | } | 1967 | } |
1874 | } | 1968 | } |
1875 | } | 1969 | } |
1876 | 1970 | ||
1877 | public void applyAngularImpulse(Vector3 impulse) | 1971 | public void applyAngularImpulse(Vector3 impulse) |
1878 | { | 1972 | { |
1879 | // We check if rootpart is null here because scripts don't delete if you delete the host. | 1973 | if (RootPart.PhysActor != null) |
1880 | // This means that unfortunately, we can pass a null physics actor to Simulate! | ||
1881 | // Make sure we don't do that! | ||
1882 | SceneObjectPart rootpart = m_rootPart; | ||
1883 | if (rootpart != null) | ||
1884 | { | 1974 | { |
1885 | if (rootpart.PhysActor != null) | 1975 | if (!IsAttachment) |
1886 | { | 1976 | { |
1887 | if (!IsAttachment) | 1977 | RootPart.PhysActor.AddAngularForce(impulse, true); |
1888 | { | 1978 | m_scene.PhysicsScene.AddPhysicsActorTaint(RootPart.PhysActor); |
1889 | rootpart.PhysActor.AddAngularForce(impulse, true); | ||
1890 | m_scene.PhysicsScene.AddPhysicsActorTaint(rootpart.PhysActor); | ||
1891 | } | ||
1892 | } | 1979 | } |
1893 | } | 1980 | } |
1894 | } | 1981 | } |
1895 | 1982 | ||
1896 | public void setAngularImpulse(Vector3 impulse) | 1983 | public void setAngularImpulse(Vector3 impulse) |
1897 | { | 1984 | { |
1898 | // We check if rootpart is null here because scripts don't delete if you delete the host. | 1985 | if (RootPart.PhysActor != null) |
1899 | // This means that unfortunately, we can pass a null physics actor to Simulate! | ||
1900 | // Make sure we don't do that! | ||
1901 | SceneObjectPart rootpart = m_rootPart; | ||
1902 | if (rootpart != null) | ||
1903 | { | 1986 | { |
1904 | if (rootpart.PhysActor != null) | 1987 | if (!IsAttachment) |
1905 | { | 1988 | { |
1906 | if (!IsAttachment) | 1989 | RootPart.PhysActor.Torque = impulse; |
1907 | { | 1990 | m_scene.PhysicsScene.AddPhysicsActorTaint(RootPart.PhysActor); |
1908 | rootpart.PhysActor.Torque = impulse; | ||
1909 | m_scene.PhysicsScene.AddPhysicsActorTaint(rootpart.PhysActor); | ||
1910 | } | ||
1911 | } | 1991 | } |
1912 | } | 1992 | } |
1913 | } | 1993 | } |
1914 | 1994 | ||
1915 | public Vector3 GetTorque() | 1995 | public Vector3 GetTorque() |
1916 | { | 1996 | { |
1917 | // We check if rootpart is null here because scripts don't delete if you delete the host. | 1997 | if (RootPart.PhysActor != null) |
1918 | // This means that unfortunately, we can pass a null physics actor to Simulate! | ||
1919 | // Make sure we don't do that! | ||
1920 | SceneObjectPart rootpart = m_rootPart; | ||
1921 | if (rootpart != null) | ||
1922 | { | 1998 | { |
1923 | if (rootpart.PhysActor != null) | 1999 | if (!IsAttachment) |
1924 | { | 2000 | { |
1925 | if (!IsAttachment) | 2001 | Vector3 torque = RootPart.PhysActor.Torque; |
1926 | { | 2002 | return torque; |
1927 | Vector3 torque = rootpart.PhysActor.Torque; | ||
1928 | return torque; | ||
1929 | } | ||
1930 | } | 2003 | } |
1931 | } | 2004 | } |
2005 | |||
1932 | return Vector3.Zero; | 2006 | return Vector3.Zero; |
1933 | } | 2007 | } |
1934 | 2008 | ||
1935 | // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object | 2009 | // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object |
1936 | public void moveToTarget(Vector3 target, float tau) | 2010 | public void moveToTarget(Vector3 target, float tau) |
1937 | { | 2011 | { |
1938 | SceneObjectPart rootpart = m_rootPart; | 2012 | if (IsAttachment) |
1939 | if (rootpart != null) | ||
1940 | { | 2013 | { |
1941 | if (IsAttachment) | 2014 | ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar); |
2015 | if (avatar != null) | ||
1942 | { | 2016 | { |
1943 | ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar); | 2017 | avatar.MoveToTarget(target, false); |
1944 | if (avatar != null) | ||
1945 | { | ||
1946 | List<string> coords = new List<string>(); | ||
1947 | uint regionX = 0; | ||
1948 | uint regionY = 0; | ||
1949 | Utils.LongToUInts(Scene.RegionInfo.RegionHandle, out regionX, out regionY); | ||
1950 | target.X += regionX; | ||
1951 | target.Y += regionY; | ||
1952 | coords.Add(target.X.ToString()); | ||
1953 | coords.Add(target.Y.ToString()); | ||
1954 | coords.Add(target.Z.ToString()); | ||
1955 | avatar.DoMoveToPosition(avatar, "", coords); | ||
1956 | } | ||
1957 | } | 2018 | } |
1958 | else | 2019 | } |
2020 | else | ||
2021 | { | ||
2022 | if (RootPart.PhysActor != null) | ||
1959 | { | 2023 | { |
1960 | if (rootpart.PhysActor != null) | 2024 | RootPart.PhysActor.PIDTarget = target; |
1961 | { | 2025 | RootPart.PhysActor.PIDTau = tau; |
1962 | rootpart.PhysActor.PIDTarget = target; | 2026 | RootPart.PhysActor.PIDActive = true; |
1963 | rootpart.PhysActor.PIDTau = tau; | ||
1964 | rootpart.PhysActor.PIDActive = true; | ||
1965 | } | ||
1966 | } | 2027 | } |
1967 | } | 2028 | } |
1968 | } | 2029 | } |
1969 | 2030 | ||
1970 | public void stopMoveToTarget() | 2031 | public void stopMoveToTarget() |
1971 | { | 2032 | { |
2033 | <<<<<<< HEAD | ||
1972 | SceneObjectPart rootpart = m_rootPart; | 2034 | SceneObjectPart rootpart = m_rootPart; |
1973 | if (rootpart != null) | 2035 | if (rootpart != null) |
1974 | { | 2036 | { |
@@ -1985,6 +2047,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
1985 | } | 2047 | } |
1986 | } | 2048 | } |
1987 | } | 2049 | } |
2050 | ======= | ||
2051 | if (RootPart.PhysActor != null) | ||
2052 | RootPart.PhysActor.PIDActive = false; | ||
2053 | >>>>>>> 9f75eaf50e42ef6409fc272ba33a817241907ed8 | ||
1988 | } | 2054 | } |
1989 | 2055 | ||
1990 | public void rotLookAt(Quaternion target, float strength, float damping) | 2056 | public void rotLookAt(Quaternion target, float strength, float damping) |
@@ -2016,6 +2082,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2016 | 2082 | ||
2017 | public void stopLookAt() | 2083 | public void stopLookAt() |
2018 | { | 2084 | { |
2085 | <<<<<<< HEAD | ||
2019 | SceneObjectPart rootpart = m_rootPart; | 2086 | SceneObjectPart rootpart = m_rootPart; |
2020 | if (rootpart != null) | 2087 | if (rootpart != null) |
2021 | { | 2088 | { |
@@ -2025,6 +2092,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
2025 | } | 2092 | } |
2026 | } | 2093 | } |
2027 | 2094 | ||
2095 | ======= | ||
2096 | if (RootPart.PhysActor != null) | ||
2097 | RootPart.PhysActor.APIDActive = false; | ||
2098 | >>>>>>> 9f75eaf50e42ef6409fc272ba33a817241907ed8 | ||
2028 | } | 2099 | } |
2029 | 2100 | ||
2030 | /// <summary> | 2101 | /// <summary> |
@@ -2035,22 +2106,18 @@ namespace OpenSim.Region.Framework.Scenes | |||
2035 | /// <param name="tau">Number of seconds over which to reach target</param> | 2106 | /// <param name="tau">Number of seconds over which to reach target</param> |
2036 | public void SetHoverHeight(float height, PIDHoverType hoverType, float tau) | 2107 | public void SetHoverHeight(float height, PIDHoverType hoverType, float tau) |
2037 | { | 2108 | { |
2038 | SceneObjectPart rootpart = m_rootPart; | 2109 | if (RootPart.PhysActor != null) |
2039 | if (rootpart != null) | ||
2040 | { | 2110 | { |
2041 | if (rootpart.PhysActor != null) | 2111 | if (height != 0f) |
2042 | { | 2112 | { |
2043 | if (height != 0f) | 2113 | RootPart.PhysActor.PIDHoverHeight = height; |
2044 | { | 2114 | RootPart.PhysActor.PIDHoverType = hoverType; |
2045 | rootpart.PhysActor.PIDHoverHeight = height; | 2115 | RootPart.PhysActor.PIDTau = tau; |
2046 | rootpart.PhysActor.PIDHoverType = hoverType; | 2116 | RootPart.PhysActor.PIDHoverActive = true; |
2047 | rootpart.PhysActor.PIDTau = tau; | 2117 | } |
2048 | rootpart.PhysActor.PIDHoverActive = true; | 2118 | else |
2049 | } | 2119 | { |
2050 | else | 2120 | RootPart.PhysActor.PIDHoverActive = false; |
2051 | { | ||
2052 | rootpart.PhysActor.PIDHoverActive = false; | ||
2053 | } | ||
2054 | } | 2121 | } |
2055 | } | 2122 | } |
2056 | } | 2123 | } |
@@ -2145,7 +2212,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2145 | // an object has been deleted from a scene before update was processed. | 2212 | // an object has been deleted from a scene before update was processed. |
2146 | // A more fundamental overhaul of the update mechanism is required to eliminate all | 2213 | // A more fundamental overhaul of the update mechanism is required to eliminate all |
2147 | // the race conditions. | 2214 | // the race conditions. |
2148 | if (m_isDeleted) | 2215 | if (IsDeleted) |
2149 | return; | 2216 | return; |
2150 | 2217 | ||
2151 | // Even temporary objects take part in physics (e.g. temp-on-rez bullets) | 2218 | // Even temporary objects take part in physics (e.g. temp-on-rez bullets) |
@@ -2458,7 +2525,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2458 | } | 2525 | } |
2459 | 2526 | ||
2460 | m_scene.UnlinkSceneObject(objectGroup, true); | 2527 | m_scene.UnlinkSceneObject(objectGroup, true); |
2461 | objectGroup.m_isDeleted = true; | 2528 | objectGroup.IsDeleted = true; |
2462 | 2529 | ||
2463 | objectGroup.m_parts.Clear(); | 2530 | objectGroup.m_parts.Clear(); |
2464 | 2531 | ||
@@ -2595,9 +2662,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
2595 | /// <param name="objectGroup"></param> | 2662 | /// <param name="objectGroup"></param> |
2596 | public virtual void DetachFromBackup() | 2663 | public virtual void DetachFromBackup() |
2597 | { | 2664 | { |
2665 | <<<<<<< HEAD | ||
2598 | m_scene.SceneGraph.FireDetachFromBackup(this); | 2666 | m_scene.SceneGraph.FireDetachFromBackup(this); |
2599 | 2667 | ||
2600 | if (m_isBackedUp) | 2668 | if (m_isBackedUp) |
2669 | ======= | ||
2670 | if (m_isBackedUp && Scene != null) | ||
2671 | >>>>>>> 9f75eaf50e42ef6409fc272ba33a817241907ed8 | ||
2601 | m_scene.EventManager.OnBackup -= ProcessBackup; | 2672 | m_scene.EventManager.OnBackup -= ProcessBackup; |
2602 | 2673 | ||
2603 | m_isBackedUp = false; | 2674 | m_isBackedUp = false; |
@@ -2857,14 +2928,15 @@ namespace OpenSim.Region.Framework.Scenes | |||
2857 | /// Update prim flags for this group. | 2928 | /// Update prim flags for this group. |
2858 | /// </summary> | 2929 | /// </summary> |
2859 | /// <param name="localID"></param> | 2930 | /// <param name="localID"></param> |
2860 | /// <param name="type"></param> | 2931 | /// <param name="UsePhysics"></param> |
2861 | /// <param name="inUse"></param> | 2932 | /// <param name="SetTemporary"></param> |
2862 | /// <param name="data"></param> | 2933 | /// <param name="SetPhantom"></param> |
2863 | public void UpdatePrimFlags(uint localID, bool UsePhysics, bool IsTemporary, bool IsPhantom, bool IsVolumeDetect) | 2934 | /// <param name="SetVolumeDetect"></param> |
2935 | public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect) | ||
2864 | { | 2936 | { |
2865 | SceneObjectPart selectionPart = GetChildPart(localID); | 2937 | SceneObjectPart selectionPart = GetChildPart(localID); |
2866 | 2938 | ||
2867 | if (IsTemporary) | 2939 | if (SetTemporary && Scene != null) |
2868 | { | 2940 | { |
2869 | DetachFromBackup(); | 2941 | DetachFromBackup(); |
2870 | // Remove from database and parcel prim count | 2942 | // Remove from database and parcel prim count |
@@ -2876,24 +2948,32 @@ namespace OpenSim.Region.Framework.Scenes | |||
2876 | if (selectionPart != null) | 2948 | if (selectionPart != null) |
2877 | { | 2949 | { |
2878 | SceneObjectPart[] parts = m_parts.GetArray(); | 2950 | SceneObjectPart[] parts = m_parts.GetArray(); |
2879 | for (int i = 0; i < parts.Length; i++) | 2951 | |
2952 | if (Scene != null) | ||
2880 | { | 2953 | { |
2881 | SceneObjectPart part = parts[i]; | 2954 | for (int i = 0; i < parts.Length; i++) |
2882 | if (part.Scale.X > m_scene.RegionInfo.PhysPrimMax || | ||
2883 | part.Scale.Y > m_scene.RegionInfo.PhysPrimMax || | ||
2884 | part.Scale.Z > m_scene.RegionInfo.PhysPrimMax) | ||
2885 | { | 2955 | { |
2886 | UsePhysics = false; // Reset physics | 2956 | SceneObjectPart part = parts[i]; |
2887 | break; | 2957 | if (part.Scale.X > m_scene.RegionInfo.PhysPrimMax || |
2958 | part.Scale.Y > m_scene.RegionInfo.PhysPrimMax || | ||
2959 | part.Scale.Z > m_scene.RegionInfo.PhysPrimMax) | ||
2960 | { | ||
2961 | UsePhysics = false; // Reset physics | ||
2962 | break; | ||
2963 | } | ||
2888 | } | 2964 | } |
2889 | } | 2965 | } |
2890 | 2966 | ||
2891 | RootPart.UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect); | 2967 | RootPart.UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect); |
2892 | for (int i = 0; i < parts.Length; i++) | 2968 | for (int i = 0; i < parts.Length; i++) |
2969 | <<<<<<< HEAD | ||
2893 | { | 2970 | { |
2894 | if (parts[i] != RootPart) | 2971 | if (parts[i] != RootPart) |
2895 | parts[i].UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect); | 2972 | parts[i].UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect); |
2896 | } | 2973 | } |
2974 | ======= | ||
2975 | parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); | ||
2976 | >>>>>>> 9f75eaf50e42ef6409fc272ba33a817241907ed8 | ||
2897 | } | 2977 | } |
2898 | } | 2978 | } |
2899 | 2979 | ||
@@ -2966,12 +3046,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
2966 | #region Resize | 3046 | #region Resize |
2967 | 3047 | ||
2968 | /// <summary> | 3048 | /// <summary> |
2969 | /// Resize the given part | 3049 | /// Resize the entire group of prims. |
2970 | /// </summary> | 3050 | /// </summary> |
2971 | /// <param name="scale"></param> | 3051 | /// <param name="scale"></param> |
2972 | /// <param name="localID"></param> | 3052 | public void GroupResize(Vector3 scale) |
2973 | public void Resize(Vector3 scale, uint localID) | ||
2974 | { | 3053 | { |
3054 | <<<<<<< HEAD | ||
2975 | if (scale.X > m_scene.m_maxNonphys) | 3055 | if (scale.X > m_scene.m_maxNonphys) |
2976 | scale.X = m_scene.m_maxNonphys; | 3056 | scale.X = m_scene.m_maxNonphys; |
2977 | if (scale.Y > m_scene.m_maxNonphys) | 3057 | if (scale.Y > m_scene.m_maxNonphys) |
@@ -2996,23 +3076,25 @@ namespace OpenSim.Region.Framework.Scenes | |||
2996 | m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor); | 3076 | m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor); |
2997 | } | 3077 | } |
2998 | part.Resize(scale); | 3078 | part.Resize(scale); |
3079 | ======= | ||
3080 | // m_log.DebugFormat( | ||
3081 | // "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale); | ||
2999 | 3082 | ||
3000 | HasGroupChanged = true; | 3083 | RootPart.StoreUndoState(true); |
3001 | part.TriggerScriptChangedEvent(Changed.SCALE); | 3084 | >>>>>>> 9f75eaf50e42ef6409fc272ba33a817241907ed8 |
3002 | ScheduleGroupForFullUpdate(); | ||
3003 | 3085 | ||
3004 | //if (part.UUID == m_rootPart.UUID) | 3086 | scale.X = Math.Min(scale.X, Scene.m_maxNonphys); |
3005 | //{ | 3087 | scale.Y = Math.Min(scale.Y, Scene.m_maxNonphys); |
3006 | //if (m_rootPart.PhysActor != null) | 3088 | scale.Z = Math.Min(scale.Z, Scene.m_maxNonphys); |
3007 | //{ | 3089 | |
3008 | //m_rootPart.PhysActor.Size = | 3090 | if (RootPart.PhysActor != null && RootPart.PhysActor.IsPhysical) |
3009 | //new PhysicsVector(m_rootPart.Scale.X, m_rootPart.Scale.Y, m_rootPart.Scale.Z); | 3091 | { |
3010 | //m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor); | 3092 | scale.X = Math.Min(scale.X, Scene.m_maxPhys); |
3011 | //} | 3093 | scale.Y = Math.Min(scale.Y, Scene.m_maxPhys); |
3012 | //} | 3094 | scale.Z = Math.Min(scale.Z, Scene.m_maxPhys); |
3013 | } | 3095 | } |
3014 | } | ||
3015 | 3096 | ||
3097 | <<<<<<< HEAD | ||
3016 | public void GroupResize(Vector3 scale, uint localID) | 3098 | public void GroupResize(Vector3 scale, uint localID) |
3017 | { | 3099 | { |
3018 | SceneObjectPart part = GetChildPart(localID); | 3100 | SceneObjectPart part = GetChildPart(localID); |
@@ -3036,24 +3118,50 @@ namespace OpenSim.Region.Framework.Scenes | |||
3036 | float x = (scale.X / part.Scale.X); | 3118 | float x = (scale.X / part.Scale.X); |
3037 | float y = (scale.Y / part.Scale.Y); | 3119 | float y = (scale.Y / part.Scale.Y); |
3038 | float z = (scale.Z / part.Scale.Z); | 3120 | float z = (scale.Z / part.Scale.Z); |
3121 | ======= | ||
3122 | float x = (scale.X / RootPart.Scale.X); | ||
3123 | float y = (scale.Y / RootPart.Scale.Y); | ||
3124 | float z = (scale.Z / RootPart.Scale.Z); | ||
3125 | >>>>>>> 9f75eaf50e42ef6409fc272ba33a817241907ed8 | ||
3039 | 3126 | ||
3040 | SceneObjectPart[] parts; | 3127 | SceneObjectPart[] parts; |
3041 | if (x > 1.0f || y > 1.0f || z > 1.0f) | 3128 | if (x > 1.0f || y > 1.0f || z > 1.0f) |
3129 | { | ||
3130 | parts = m_parts.GetArray(); | ||
3131 | for (int i = 0; i < parts.Length; i++) | ||
3042 | { | 3132 | { |
3043 | parts = m_parts.GetArray(); | 3133 | SceneObjectPart obPart = parts[i]; |
3044 | for (int i = 0; i < parts.Length; i++) | 3134 | if (obPart.UUID != m_rootPart.UUID) |
3045 | { | 3135 | { |
3046 | SceneObjectPart obPart = parts[i]; | 3136 | // obPart.IgnoreUndoUpdate = true; |
3047 | if (obPart.UUID != m_rootPart.UUID) | 3137 | Vector3 oldSize = new Vector3(obPart.Scale); |
3138 | |||
3139 | float f = 1.0f; | ||
3140 | float a = 1.0f; | ||
3141 | |||
3142 | if (RootPart.PhysActor != null && RootPart.PhysActor.IsPhysical) | ||
3048 | { | 3143 | { |
3049 | obPart.IgnoreUndoUpdate = true; | 3144 | if (oldSize.X * x > m_scene.m_maxPhys) |
3050 | Vector3 oldSize = new Vector3(obPart.Scale); | 3145 | { |
3146 | f = m_scene.m_maxPhys / oldSize.X; | ||
3147 | a = f / x; | ||
3148 | x *= a; | ||
3149 | y *= a; | ||
3150 | z *= a; | ||
3151 | } | ||
3051 | 3152 | ||
3052 | float f = 1.0f; | 3153 | if (oldSize.Y * y > m_scene.m_maxPhys) |
3053 | float a = 1.0f; | 3154 | { |
3155 | f = m_scene.m_maxPhys / oldSize.Y; | ||
3156 | a = f / y; | ||
3157 | x *= a; | ||
3158 | y *= a; | ||
3159 | z *= a; | ||
3160 | } | ||
3054 | 3161 | ||
3055 | if (part.PhysActor != null && part.PhysActor.IsPhysical) | 3162 | if (oldSize.Z * z > m_scene.m_maxPhys) |
3056 | { | 3163 | { |
3164 | <<<<<<< HEAD | ||
3057 | if (oldSize.X*x > m_scene.m_maxPhys) | 3165 | if (oldSize.X*x > m_scene.m_maxPhys) |
3058 | { | 3166 | { |
3059 | f = m_scene.m_maxPhys / oldSize.X; | 3167 | f = m_scene.m_maxPhys / oldSize.X; |
@@ -3078,9 +3186,20 @@ namespace OpenSim.Region.Framework.Scenes | |||
3078 | y *= a; | 3186 | y *= a; |
3079 | z *= a; | 3187 | z *= a; |
3080 | } | 3188 | } |
3189 | ======= | ||
3190 | f = m_scene.m_maxPhys / oldSize.Z; | ||
3191 | a = f / z; | ||
3192 | x *= a; | ||
3193 | y *= a; | ||
3194 | z *= a; | ||
3195 | >>>>>>> 9f75eaf50e42ef6409fc272ba33a817241907ed8 | ||
3081 | } | 3196 | } |
3082 | else | 3197 | } |
3198 | else | ||
3199 | { | ||
3200 | if (oldSize.X * x > m_scene.m_maxNonphys) | ||
3083 | { | 3201 | { |
3202 | <<<<<<< HEAD | ||
3084 | if (oldSize.X*x > m_scene.m_maxNonphys) | 3203 | if (oldSize.X*x > m_scene.m_maxNonphys) |
3085 | { | 3204 | { |
3086 | f = m_scene.m_maxNonphys / oldSize.X; | 3205 | f = m_scene.m_maxNonphys / oldSize.X; |
@@ -3107,10 +3226,40 @@ namespace OpenSim.Region.Framework.Scenes | |||
3107 | } | 3226 | } |
3108 | } | 3227 | } |
3109 | obPart.IgnoreUndoUpdate = false; | 3228 | obPart.IgnoreUndoUpdate = false; |
3229 | ======= | ||
3230 | f = m_scene.m_maxNonphys / oldSize.X; | ||
3231 | a = f / x; | ||
3232 | x *= a; | ||
3233 | y *= a; | ||
3234 | z *= a; | ||
3235 | } | ||
3236 | |||
3237 | if (oldSize.Y * y > m_scene.m_maxNonphys) | ||
3238 | { | ||
3239 | f = m_scene.m_maxNonphys / oldSize.Y; | ||
3240 | a = f / y; | ||
3241 | x *= a; | ||
3242 | y *= a; | ||
3243 | z *= a; | ||
3244 | } | ||
3245 | |||
3246 | if (oldSize.Z * z > m_scene.m_maxNonphys) | ||
3247 | { | ||
3248 | f = m_scene.m_maxNonphys / oldSize.Z; | ||
3249 | a = f / z; | ||
3250 | x *= a; | ||
3251 | y *= a; | ||
3252 | z *= a; | ||
3253 | } | ||
3254 | >>>>>>> 9f75eaf50e42ef6409fc272ba33a817241907ed8 | ||
3110 | } | 3255 | } |
3256 | |||
3257 | // obPart.IgnoreUndoUpdate = false; | ||
3111 | } | 3258 | } |
3112 | } | 3259 | } |
3260 | } | ||
3113 | 3261 | ||
3262 | <<<<<<< HEAD | ||
3114 | Vector3 prevScale = part.Scale; | 3263 | Vector3 prevScale = part.Scale; |
3115 | prevScale.X *= x; | 3264 | prevScale.X *= x; |
3116 | prevScale.Y *= y; | 3265 | prevScale.Y *= y; |
@@ -3121,12 +3270,26 @@ namespace OpenSim.Region.Framework.Scenes | |||
3121 | part.IgnoreUndoUpdate = true; | 3270 | part.IgnoreUndoUpdate = true; |
3122 | part.Resize(prevScale); | 3271 | part.Resize(prevScale); |
3123 | part.IgnoreUndoUpdate = false; | 3272 | part.IgnoreUndoUpdate = false; |
3273 | ======= | ||
3274 | Vector3 prevScale = RootPart.Scale; | ||
3275 | prevScale.X *= x; | ||
3276 | prevScale.Y *= y; | ||
3277 | prevScale.Z *= z; | ||
3278 | >>>>>>> 9f75eaf50e42ef6409fc272ba33a817241907ed8 | ||
3124 | 3279 | ||
3125 | parts = m_parts.GetArray(); | 3280 | // RootPart.IgnoreUndoUpdate = true; |
3126 | for (int i = 0; i < parts.Length; i++) | 3281 | RootPart.Resize(prevScale); |
3282 | // RootPart.IgnoreUndoUpdate = false; | ||
3283 | |||
3284 | parts = m_parts.GetArray(); | ||
3285 | for (int i = 0; i < parts.Length; i++) | ||
3286 | { | ||
3287 | SceneObjectPart obPart = parts[i]; | ||
3288 | |||
3289 | if (obPart.UUID != m_rootPart.UUID) | ||
3127 | { | 3290 | { |
3128 | SceneObjectPart obPart = parts[i]; | ||
3129 | obPart.IgnoreUndoUpdate = true; | 3291 | obPart.IgnoreUndoUpdate = true; |
3292 | <<<<<<< HEAD | ||
3130 | if (obPart.UUID != m_rootPart.UUID) | 3293 | if (obPart.UUID != m_rootPart.UUID) |
3131 | { | 3294 | { |
3132 | if (obPart.UUID != m_rootPart.UUID) | 3295 | if (obPart.UUID != m_rootPart.UUID) |
@@ -3150,18 +3313,38 @@ namespace OpenSim.Region.Framework.Scenes | |||
3150 | } | 3313 | } |
3151 | obPart.IgnoreUndoUpdate = false; | 3314 | obPart.IgnoreUndoUpdate = false; |
3152 | } | 3315 | } |
3316 | ======= | ||
3317 | >>>>>>> 9f75eaf50e42ef6409fc272ba33a817241907ed8 | ||
3153 | 3318 | ||
3154 | if (part.PhysActor != null) | 3319 | Vector3 currentpos = new Vector3(obPart.OffsetPosition); |
3155 | { | 3320 | currentpos.X *= x; |
3156 | part.PhysActor.Size = prevScale; | 3321 | currentpos.Y *= y; |
3157 | m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor); | 3322 | currentpos.Z *= z; |
3323 | |||
3324 | Vector3 newSize = new Vector3(obPart.Scale); | ||
3325 | newSize.X *= x; | ||
3326 | newSize.Y *= y; | ||
3327 | newSize.Z *= z; | ||
3328 | |||
3329 | obPart.Resize(newSize); | ||
3330 | obPart.UpdateOffSet(currentpos); | ||
3331 | |||
3332 | obPart.IgnoreUndoUpdate = false; | ||
3158 | } | 3333 | } |
3159 | 3334 | ||
3335 | <<<<<<< HEAD | ||
3160 | part.IgnoreUndoUpdate = false; | 3336 | part.IgnoreUndoUpdate = false; |
3161 | HasGroupChanged = true; | 3337 | HasGroupChanged = true; |
3162 | m_rootPart.TriggerScriptChangedEvent(Changed.SCALE); | 3338 | m_rootPart.TriggerScriptChangedEvent(Changed.SCALE); |
3163 | ScheduleGroupForTerseUpdate(); | 3339 | ScheduleGroupForTerseUpdate(); |
3340 | ======= | ||
3341 | // obPart.IgnoreUndoUpdate = false; | ||
3342 | // obPart.StoreUndoState(); | ||
3343 | >>>>>>> 9f75eaf50e42ef6409fc272ba33a817241907ed8 | ||
3164 | } | 3344 | } |
3345 | |||
3346 | // m_log.DebugFormat( | ||
3347 | // "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale); | ||
3165 | } | 3348 | } |
3166 | 3349 | ||
3167 | #endregion | 3350 | #endregion |
@@ -3174,6 +3357,17 @@ namespace OpenSim.Region.Framework.Scenes | |||
3174 | /// <param name="pos"></param> | 3357 | /// <param name="pos"></param> |
3175 | public void UpdateGroupPosition(Vector3 pos) | 3358 | public void UpdateGroupPosition(Vector3 pos) |
3176 | { | 3359 | { |
3360 | <<<<<<< HEAD | ||
3361 | ======= | ||
3362 | // m_log.DebugFormat("[SCENE OBJECT GROUP]: Updating group position on {0} {1} to {2}", Name, LocalId, pos); | ||
3363 | |||
3364 | RootPart.StoreUndoState(true); | ||
3365 | |||
3366 | // SceneObjectPart[] parts = m_parts.GetArray(); | ||
3367 | // for (int i = 0; i < parts.Length; i++) | ||
3368 | // parts[i].StoreUndoState(); | ||
3369 | |||
3370 | >>>>>>> 9f75eaf50e42ef6409fc272ba33a817241907ed8 | ||
3177 | if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) | 3371 | if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) |
3178 | { | 3372 | { |
3179 | if (IsAttachment) | 3373 | if (IsAttachment) |
@@ -3210,12 +3404,24 @@ namespace OpenSim.Region.Framework.Scenes | |||
3210 | { | 3404 | { |
3211 | SceneObjectPart part = GetChildPart(localID); | 3405 | SceneObjectPart part = GetChildPart(localID); |
3212 | 3406 | ||
3407 | <<<<<<< HEAD | ||
3213 | SceneObjectPart[] parts = m_parts.GetArray(); | 3408 | SceneObjectPart[] parts = m_parts.GetArray(); |
3214 | for (int i = 0; i < parts.Length; i++) | 3409 | for (int i = 0; i < parts.Length; i++) |
3215 | parts[i].StoreUndoState(UndoType.STATE_PRIM_POSITION); | 3410 | parts[i].StoreUndoState(UndoType.STATE_PRIM_POSITION); |
3411 | ======= | ||
3412 | // SceneObjectPart[] parts = m_parts.GetArray(); | ||
3413 | // for (int i = 0; i < parts.Length; i++) | ||
3414 | // parts[i].StoreUndoState(); | ||
3415 | >>>>>>> 9f75eaf50e42ef6409fc272ba33a817241907ed8 | ||
3216 | 3416 | ||
3217 | if (part != null) | 3417 | if (part != null) |
3218 | { | 3418 | { |
3419 | // m_log.DebugFormat( | ||
3420 | // "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); | ||
3421 | |||
3422 | part.StoreUndoState(false); | ||
3423 | part.IgnoreUndoUpdate = true; | ||
3424 | |||
3219 | if (part.UUID == m_rootPart.UUID) | 3425 | if (part.UUID == m_rootPart.UUID) |
3220 | { | 3426 | { |
3221 | UpdateRootPosition(pos); | 3427 | UpdateRootPosition(pos); |
@@ -3226,18 +3432,28 @@ namespace OpenSim.Region.Framework.Scenes | |||
3226 | } | 3432 | } |
3227 | 3433 | ||
3228 | HasGroupChanged = true; | 3434 | HasGroupChanged = true; |
3435 | part.IgnoreUndoUpdate = false; | ||
3229 | } | 3436 | } |
3230 | } | 3437 | } |
3231 | 3438 | ||
3232 | /// <summary> | 3439 | /// <summary> |
3233 | /// | 3440 | /// Update just the root prim position in a linkset |
3234 | /// </summary> | 3441 | /// </summary> |
3235 | /// <param name="pos"></param> | 3442 | /// <param name="pos"></param> |
3236 | private void UpdateRootPosition(Vector3 pos) | 3443 | public void UpdateRootPosition(Vector3 pos) |
3237 | { | 3444 | { |
3445 | <<<<<<< HEAD | ||
3238 | SceneObjectPart[] parts = m_parts.GetArray(); | 3446 | SceneObjectPart[] parts = m_parts.GetArray(); |
3239 | for (int i = 0; i < parts.Length; i++) | 3447 | for (int i = 0; i < parts.Length; i++) |
3240 | parts[i].StoreUndoState(UndoType.STATE_PRIM_POSITION); | 3448 | parts[i].StoreUndoState(UndoType.STATE_PRIM_POSITION); |
3449 | ======= | ||
3450 | // m_log.DebugFormat( | ||
3451 | // "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos); | ||
3452 | |||
3453 | // SceneObjectPart[] parts = m_parts.GetArray(); | ||
3454 | // for (int i = 0; i < parts.Length; i++) | ||
3455 | // parts[i].StoreUndoState(); | ||
3456 | >>>>>>> 9f75eaf50e42ef6409fc272ba33a817241907ed8 | ||
3241 | 3457 | ||
3242 | Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); | 3458 | Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); |
3243 | Vector3 oldPos = | 3459 | Vector3 oldPos = |
@@ -3250,7 +3466,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3250 | axDiff *= Quaternion.Inverse(partRotation); | 3466 | axDiff *= Quaternion.Inverse(partRotation); |
3251 | diff = axDiff; | 3467 | diff = axDiff; |
3252 | 3468 | ||
3253 | parts = m_parts.GetArray(); | 3469 | SceneObjectPart[] parts = m_parts.GetArray(); |
3254 | for (int i = 0; i < parts.Length; i++) | 3470 | for (int i = 0; i < parts.Length; i++) |
3255 | { | 3471 | { |
3256 | SceneObjectPart obPart = parts[i]; | 3472 | SceneObjectPart obPart = parts[i]; |
@@ -3296,9 +3512,20 @@ namespace OpenSim.Region.Framework.Scenes | |||
3296 | /// <param name="rot"></param> | 3512 | /// <param name="rot"></param> |
3297 | public void UpdateGroupRotationR(Quaternion rot) | 3513 | public void UpdateGroupRotationR(Quaternion rot) |
3298 | { | 3514 | { |
3515 | <<<<<<< HEAD | ||
3299 | SceneObjectPart[] parts = m_parts.GetArray(); | 3516 | SceneObjectPart[] parts = m_parts.GetArray(); |
3300 | for (int i = 0; i < parts.Length; i++) | 3517 | for (int i = 0; i < parts.Length; i++) |
3301 | parts[i].StoreUndoState(UndoType.STATE_GROUP_ROTATION); | 3518 | parts[i].StoreUndoState(UndoType.STATE_GROUP_ROTATION); |
3519 | ======= | ||
3520 | // m_log.DebugFormat( | ||
3521 | // "[SCENE OBJECT GROUP]: Updating group rotation R of {0} {1} to {2}", Name, LocalId, rot); | ||
3522 | |||
3523 | // SceneObjectPart[] parts = m_parts.GetArray(); | ||
3524 | // for (int i = 0; i < parts.Length; i++) | ||
3525 | // parts[i].StoreUndoState(); | ||
3526 | |||
3527 | m_rootPart.StoreUndoState(true); | ||
3528 | >>>>>>> 9f75eaf50e42ef6409fc272ba33a817241907ed8 | ||
3302 | 3529 | ||
3303 | m_rootPart.UpdateRotation(rot); | 3530 | m_rootPart.UpdateRotation(rot); |
3304 | 3531 | ||
@@ -3320,9 +3547,21 @@ namespace OpenSim.Region.Framework.Scenes | |||
3320 | /// <param name="rot"></param> | 3547 | /// <param name="rot"></param> |
3321 | public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) | 3548 | public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) |
3322 | { | 3549 | { |
3550 | <<<<<<< HEAD | ||
3323 | SceneObjectPart[] parts = m_parts.GetArray(); | 3551 | SceneObjectPart[] parts = m_parts.GetArray(); |
3324 | for (int i = 0; i < parts.Length; i++) | 3552 | for (int i = 0; i < parts.Length; i++) |
3325 | parts[i].StoreUndoState(UndoType.STATE_GROUP_ROTATION); | 3553 | parts[i].StoreUndoState(UndoType.STATE_GROUP_ROTATION); |
3554 | ======= | ||
3555 | // m_log.DebugFormat( | ||
3556 | // "[SCENE OBJECT GROUP]: Updating group rotation PR of {0} {1} to {2}", Name, LocalId, rot); | ||
3557 | |||
3558 | // SceneObjectPart[] parts = m_parts.GetArray(); | ||
3559 | // for (int i = 0; i < parts.Length; i++) | ||
3560 | // parts[i].StoreUndoState(); | ||
3561 | |||
3562 | RootPart.StoreUndoState(true); | ||
3563 | RootPart.IgnoreUndoUpdate = true; | ||
3564 | >>>>>>> 9f75eaf50e42ef6409fc272ba33a817241907ed8 | ||
3326 | 3565 | ||
3327 | m_rootPart.UpdateRotation(rot); | 3566 | m_rootPart.UpdateRotation(rot); |
3328 | 3567 | ||
@@ -3337,6 +3576,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
3337 | 3576 | ||
3338 | HasGroupChanged = true; | 3577 | HasGroupChanged = true; |
3339 | ScheduleGroupForTerseUpdate(); | 3578 | ScheduleGroupForTerseUpdate(); |
3579 | |||
3580 | RootPart.IgnoreUndoUpdate = false; | ||
3340 | } | 3581 | } |
3341 | 3582 | ||
3342 | /// <summary> | 3583 | /// <summary> |
@@ -3353,6 +3594,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
3353 | 3594 | ||
3354 | if (part != null) | 3595 | if (part != null) |
3355 | { | 3596 | { |
3597 | // m_log.DebugFormat( | ||
3598 | // "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); | ||
3599 | |||
3356 | if (part.UUID == m_rootPart.UUID) | 3600 | if (part.UUID == m_rootPart.UUID) |
3357 | { | 3601 | { |
3358 | UpdateRootRotation(rot); | 3602 | UpdateRootRotation(rot); |
@@ -3374,6 +3618,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
3374 | SceneObjectPart part = GetChildPart(localID); | 3618 | SceneObjectPart part = GetChildPart(localID); |
3375 | if (part != null) | 3619 | if (part != null) |
3376 | { | 3620 | { |
3621 | // m_log.DebugFormat( | ||
3622 | // "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", | ||
3623 | // part.Name, part.LocalId, rot); | ||
3624 | |||
3625 | part.StoreUndoState(); | ||
3626 | part.IgnoreUndoUpdate = true; | ||
3627 | |||
3377 | if (part.UUID == m_rootPart.UUID) | 3628 | if (part.UUID == m_rootPart.UUID) |
3378 | { | 3629 | { |
3379 | UpdateRootRotation(rot); | 3630 | UpdateRootRotation(rot); |
@@ -3390,12 +3641,19 @@ namespace OpenSim.Region.Framework.Scenes | |||
3390 | } | 3641 | } |
3391 | else | 3642 | else |
3392 | { | 3643 | { |
3644 | <<<<<<< HEAD | ||
3393 | part.StoreUndoState(UndoType.STATE_PRIM_ROTATION); | 3645 | part.StoreUndoState(UndoType.STATE_PRIM_ROTATION); |
3394 | part.IgnoreUndoUpdate = true; | 3646 | part.IgnoreUndoUpdate = true; |
3395 | part.UpdateRotation(rot); | 3647 | part.UpdateRotation(rot); |
3396 | part.OffsetPosition = pos; | 3648 | part.OffsetPosition = pos; |
3397 | part.IgnoreUndoUpdate = false; | 3649 | part.IgnoreUndoUpdate = false; |
3650 | ======= | ||
3651 | part.UpdateRotation(rot); | ||
3652 | part.OffsetPosition = pos; | ||
3653 | >>>>>>> 9f75eaf50e42ef6409fc272ba33a817241907ed8 | ||
3398 | } | 3654 | } |
3655 | |||
3656 | part.IgnoreUndoUpdate = false; | ||
3399 | } | 3657 | } |
3400 | } | 3658 | } |
3401 | 3659 | ||
@@ -3403,8 +3661,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
3403 | /// | 3661 | /// |
3404 | /// </summary> | 3662 | /// </summary> |
3405 | /// <param name="rot"></param> | 3663 | /// <param name="rot"></param> |
3406 | private void UpdateRootRotation(Quaternion rot) | 3664 | public void UpdateRootRotation(Quaternion rot) |
3407 | { | 3665 | { |
3666 | // m_log.DebugFormat( | ||
3667 | // "[SCENE OBJECT GROUP]: Updating root rotation of {0} {1} to {2}", | ||
3668 | // Name, LocalId, rot); | ||
3669 | |||
3408 | Quaternion axRot = rot; | 3670 | Quaternion axRot = rot; |
3409 | Quaternion oldParentRot = m_rootPart.RotationOffset; | 3671 | Quaternion oldParentRot = m_rootPart.RotationOffset; |
3410 | 3672 | ||
@@ -3436,6 +3698,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3436 | axPos *= oldParentRot; | 3698 | axPos *= oldParentRot; |
3437 | axPos *= Quaternion.Inverse(axRot); | 3699 | axPos *= Quaternion.Inverse(axRot); |
3438 | prim.OffsetPosition = axPos; | 3700 | prim.OffsetPosition = axPos; |
3701 | <<<<<<< HEAD | ||
3439 | 3702 | ||
3440 | prim.RotationOffset *= Quaternion.Inverse(prim.GetWorldRotation()) * (oldParentRot * prim.RotationOffset); | 3703 | prim.RotationOffset *= Quaternion.Inverse(prim.GetWorldRotation()) * (oldParentRot * prim.RotationOffset); |
3441 | 3704 | ||
@@ -3448,6 +3711,32 @@ namespace OpenSim.Region.Framework.Scenes | |||
3448 | } | 3711 | } |
3449 | HasGroupChanged = true; | 3712 | HasGroupChanged = true; |
3450 | ScheduleGroupForFullUpdate(); | 3713 | ScheduleGroupForFullUpdate(); |
3714 | ======= | ||
3715 | Quaternion primsRot = prim.RotationOffset; | ||
3716 | Quaternion newRot = primsRot * oldParentRot; | ||
3717 | newRot *= Quaternion.Inverse(axRot); | ||
3718 | prim.RotationOffset = newRot; | ||
3719 | prim.ScheduleTerseUpdate(); | ||
3720 | prim.IgnoreUndoUpdate = false; | ||
3721 | } | ||
3722 | } | ||
3723 | |||
3724 | // for (int i = 0; i < parts.Length; i++) | ||
3725 | // { | ||
3726 | // SceneObjectPart childpart = parts[i]; | ||
3727 | // if (childpart != m_rootPart) | ||
3728 | // { | ||
3729 | //// childpart.IgnoreUndoUpdate = false; | ||
3730 | //// childpart.StoreUndoState(); | ||
3731 | // } | ||
3732 | // } | ||
3733 | |||
3734 | m_rootPart.ScheduleTerseUpdate(); | ||
3735 | |||
3736 | // m_log.DebugFormat( | ||
3737 | // "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", | ||
3738 | // Name, LocalId, rot); | ||
3739 | >>>>>>> 9f75eaf50e42ef6409fc272ba33a817241907ed8 | ||
3451 | } | 3740 | } |
3452 | 3741 | ||
3453 | #endregion | 3742 | #endregion |
@@ -3462,28 +3751,23 @@ namespace OpenSim.Region.Framework.Scenes | |||
3462 | int yaxis = 4; | 3751 | int yaxis = 4; |
3463 | int zaxis = 8; | 3752 | int zaxis = 8; |
3464 | 3753 | ||
3465 | if (m_rootPart != null) | 3754 | setX = ((axis & xaxis) != 0) ? true : false; |
3466 | { | 3755 | setY = ((axis & yaxis) != 0) ? true : false; |
3467 | setX = ((axis & xaxis) != 0) ? true : false; | 3756 | setZ = ((axis & zaxis) != 0) ? true : false; |
3468 | setY = ((axis & yaxis) != 0) ? true : false; | ||
3469 | setZ = ((axis & zaxis) != 0) ? true : false; | ||
3470 | 3757 | ||
3471 | float setval = (rotate10 > 0) ? 1f : 0f; | 3758 | float setval = (rotate10 > 0) ? 1f : 0f; |
3472 | 3759 | ||
3473 | if (setX) | 3760 | if (setX) |
3474 | m_rootPart.RotationAxis.X = setval; | 3761 | RootPart.RotationAxis.X = setval; |
3475 | if (setY) | 3762 | if (setY) |
3476 | m_rootPart.RotationAxis.Y = setval; | 3763 | RootPart.RotationAxis.Y = setval; |
3477 | if (setZ) | 3764 | if (setZ) |
3478 | m_rootPart.RotationAxis.Z = setval; | 3765 | RootPart.RotationAxis.Z = setval; |
3479 | 3766 | ||
3480 | if (setX || setY || setZ) | 3767 | if (setX || setY || setZ) |
3481 | { | 3768 | RootPart.SetPhysicsAxisRotation(); |
3482 | m_rootPart.SetPhysicsAxisRotation(); | ||
3483 | } | ||
3484 | |||
3485 | } | ||
3486 | } | 3769 | } |
3770 | |||
3487 | public int registerRotTargetWaypoint(Quaternion target, float tolerance) | 3771 | public int registerRotTargetWaypoint(Quaternion target, float tolerance) |
3488 | { | 3772 | { |
3489 | scriptRotTarget waypoint = new scriptRotTarget(); | 3773 | scriptRotTarget waypoint = new scriptRotTarget(); |
@@ -3611,7 +3895,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
3611 | foreach (uint idx in m_rotTargets.Keys) | 3895 | foreach (uint idx in m_rotTargets.Keys) |
3612 | { | 3896 | { |
3613 | scriptRotTarget target = m_rotTargets[idx]; | 3897 | scriptRotTarget target = m_rotTargets[idx]; |
3614 | double angle = Math.Acos(target.targetRot.X * m_rootPart.RotationOffset.X + target.targetRot.Y * m_rootPart.RotationOffset.Y + target.targetRot.Z * m_rootPart.RotationOffset.Z + target.targetRot.W * m_rootPart.RotationOffset.W) * 2; | 3898 | double angle |
3899 | = Math.Acos( | ||
3900 | target.targetRot.X * m_rootPart.RotationOffset.X | ||
3901 | + target.targetRot.Y * m_rootPart.RotationOffset.Y | ||
3902 | + target.targetRot.Z * m_rootPart.RotationOffset.Z | ||
3903 | + target.targetRot.W * m_rootPart.RotationOffset.W) | ||
3904 | * 2; | ||
3615 | if (angle < 0) angle = -angle; | 3905 | if (angle < 0) angle = -angle; |
3616 | if (angle > Math.PI) angle = (Math.PI * 2 - angle); | 3906 | if (angle > Math.PI) angle = (Math.PI * 2 - angle); |
3617 | if (angle <= target.tolerance) | 3907 | if (angle <= target.tolerance) |
@@ -3676,43 +3966,28 @@ namespace OpenSim.Region.Framework.Scenes | |||
3676 | 3966 | ||
3677 | return retmass; | 3967 | return retmass; |
3678 | } | 3968 | } |
3679 | 3969 | ||
3970 | /// <summary> | ||
3971 | /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that | ||
3972 | /// the physics engine can use it. | ||
3973 | /// </summary> | ||
3974 | /// <remarks> | ||
3975 | /// When the physics engine has finished with it, the sculpt data is discarded to save memory. | ||
3976 | /// </remarks> | ||
3680 | public void CheckSculptAndLoad() | 3977 | public void CheckSculptAndLoad() |
3681 | { | 3978 | { |
3682 | if (IsDeleted) | 3979 | if (IsDeleted) |
3683 | return; | 3980 | return; |
3981 | |||
3684 | if ((RootPart.GetEffectiveObjectFlags() & (uint)PrimFlags.Phantom) != 0) | 3982 | if ((RootPart.GetEffectiveObjectFlags() & (uint)PrimFlags.Phantom) != 0) |
3685 | return; | 3983 | return; |
3686 | 3984 | ||
3687 | SceneObjectPart[] parts = m_parts.GetArray(); | 3985 | // m_log.Debug("Processing CheckSculptAndLoad for {0} {1}", Name, LocalId); |
3688 | for (int i = 0; i < parts.Length; i++) | ||
3689 | { | ||
3690 | SceneObjectPart part = parts[i]; | ||
3691 | if (part.Shape.SculptEntry && part.Shape.SculptTexture != UUID.Zero) | ||
3692 | { | ||
3693 | // check if a previously decoded sculpt map has been cached | ||
3694 | if (File.Exists(System.IO.Path.Combine("j2kDecodeCache", "smap_" + part.Shape.SculptTexture.ToString()))) | ||
3695 | { | ||
3696 | part.SculptTextureCallback(part.Shape.SculptTexture, null); | ||
3697 | } | ||
3698 | else | ||
3699 | { | ||
3700 | m_scene.AssetService.Get( | ||
3701 | part.Shape.SculptTexture.ToString(), part, AssetReceived); | ||
3702 | } | ||
3703 | } | ||
3704 | } | ||
3705 | } | ||
3706 | 3986 | ||
3707 | protected void AssetReceived(string id, Object sender, AssetBase asset) | 3987 | SceneObjectPart[] parts = m_parts.GetArray(); |
3708 | { | ||
3709 | SceneObjectPart sop = (SceneObjectPart)sender; | ||
3710 | 3988 | ||
3711 | if (sop != null) | 3989 | for (int i = 0; i < parts.Length; i++) |
3712 | { | 3990 | parts[i].CheckSculptAndLoad(); |
3713 | if (asset != null) | ||
3714 | sop.SculptTextureCallback(asset.FullID, asset); | ||
3715 | } | ||
3716 | } | 3991 | } |
3717 | 3992 | ||
3718 | /// <summary> | 3993 | /// <summary> |
@@ -3747,19 +4022,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
3747 | return String.Format("{0} {1} ({2})", Name, UUID, AbsolutePosition); | 4022 | return String.Format("{0} {1} ({2})", Name, UUID, AbsolutePosition); |
3748 | } | 4023 | } |
3749 | 4024 | ||
3750 | public void SetAttachmentPoint(byte point) | ||
3751 | { | ||
3752 | SceneObjectPart[] parts = m_parts.GetArray(); | ||
3753 | for (int i = 0; i < parts.Length; i++) | ||
3754 | parts[i].SetAttachmentPoint(point); | ||
3755 | } | ||
3756 | |||
3757 | #region ISceneObject | 4025 | #region ISceneObject |
3758 | 4026 | ||
3759 | public virtual ISceneObject CloneForNewScene() | 4027 | public virtual ISceneObject CloneForNewScene() |
3760 | { | 4028 | { |
3761 | SceneObjectGroup sog = Copy(false); | 4029 | SceneObjectGroup sog = Copy(false); |
3762 | sog.m_isDeleted = false; | 4030 | sog.IsDeleted = false; |
3763 | return sog; | 4031 | return sog; |
3764 | } | 4032 | } |
3765 | 4033 | ||
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 037f384..893faf8 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | |||
@@ -28,6 +28,7 @@ | |||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Drawing; | 30 | using System.Drawing; |
31 | using System.IO; | ||
31 | using System.Reflection; | 32 | using System.Reflection; |
32 | using System.Runtime.Serialization; | 33 | using System.Runtime.Serialization; |
33 | using System.Security.Permissions; | 34 | using System.Security.Permissions; |
@@ -216,28 +217,18 @@ namespace OpenSim.Region.Framework.Scenes | |||
216 | /// </value> | 217 | /// </value> |
217 | private UUID m_fromUserInventoryItemID; | 218 | private UUID m_fromUserInventoryItemID; |
218 | 219 | ||
219 | |||
220 | public UUID FromUserInventoryItemID | 220 | public UUID FromUserInventoryItemID |
221 | { | 221 | { |
222 | get { return m_fromUserInventoryItemID; } | 222 | get { return m_fromUserInventoryItemID; } |
223 | set { m_fromUserInventoryItemID = value; } | ||
223 | } | 224 | } |
224 | 225 | ||
225 | |||
226 | public bool IsAttachment; | ||
227 | |||
228 | |||
229 | public scriptEvents AggregateScriptEvents; | 226 | public scriptEvents AggregateScriptEvents; |
230 | 227 | ||
231 | 228 | ||
232 | public UUID AttachedAvatar; | ||
233 | |||
234 | |||
235 | public Vector3 AttachedPos; | 229 | public Vector3 AttachedPos; |
236 | 230 | ||
237 | 231 | ||
238 | public uint AttachmentPoint; | ||
239 | |||
240 | |||
241 | public Vector3 RotationAxis = Vector3.One; | 232 | public Vector3 RotationAxis = Vector3.One; |
242 | 233 | ||
243 | 234 | ||
@@ -269,12 +260,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
269 | } | 260 | } |
270 | protected SceneObjectPartInventory m_inventory; | 261 | protected SceneObjectPartInventory m_inventory; |
271 | 262 | ||
272 | |||
273 | public bool Undoing; | 263 | public bool Undoing; |
274 | |||
275 | 264 | ||
276 | public bool IgnoreUndoUpdate = false; | 265 | public bool IgnoreUndoUpdate = false; |
277 | |||
278 | 266 | ||
279 | private PrimFlags LocalFlags; | 267 | private PrimFlags LocalFlags; |
280 | 268 | ||
@@ -296,8 +284,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
296 | private bool m_occupied; // KF if any av is sitting on this prim | 284 | private bool m_occupied; // KF if any av is sitting on this prim |
297 | private string m_text = String.Empty; | 285 | private string m_text = String.Empty; |
298 | private string m_touchName = String.Empty; | 286 | private string m_touchName = String.Empty; |
299 | private readonly UndoStack<UndoState> m_undo = new UndoStack<UndoState>(5); | 287 | private readonly Stack<UndoState> m_undo = new Stack<UndoState>(5); |
300 | private readonly UndoStack<UndoState> m_redo = new UndoStack<UndoState>(5); | 288 | private readonly Stack<UndoState> m_redo = new Stack<UndoState>(5); |
301 | private UUID _creatorID; | 289 | private UUID _creatorID; |
302 | 290 | ||
303 | private bool m_passTouches; | 291 | private bool m_passTouches; |
@@ -323,7 +311,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
323 | protected string m_name; | 311 | protected string m_name; |
324 | protected Vector3 m_offsetPosition; | 312 | protected Vector3 m_offsetPosition; |
325 | 313 | ||
326 | // FIXME, TODO, ERROR: 'ParentGroup' can't be in here, move it out. | ||
327 | protected SceneObjectGroup m_parentGroup; | 314 | protected SceneObjectGroup m_parentGroup; |
328 | protected byte[] m_particleSystem = Utils.EmptyBytes; | 315 | protected byte[] m_particleSystem = Utils.EmptyBytes; |
329 | protected ulong m_regionHandle; | 316 | protected ulong m_regionHandle; |
@@ -424,7 +411,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
424 | CreateSelected = true; | 411 | CreateSelected = true; |
425 | 412 | ||
426 | TrimPermissions(); | 413 | TrimPermissions(); |
427 | //m_undo = new UndoStack<UndoState>(ParentGroup.GetSceneMaxUndo()); | ||
428 | 414 | ||
429 | m_inventory = new SceneObjectPartInventory(this); | 415 | m_inventory = new SceneObjectPartInventory(this); |
430 | } | 416 | } |
@@ -619,6 +605,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
619 | set | 605 | set |
620 | { | 606 | { |
621 | m_passTouches = value; | 607 | m_passTouches = value; |
608 | |||
622 | if (ParentGroup != null) | 609 | if (ParentGroup != null) |
623 | ParentGroup.HasGroupChanged = true; | 610 | ParentGroup.HasGroupChanged = true; |
624 | } | 611 | } |
@@ -744,9 +731,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
744 | return m_groupPosition; | 731 | return m_groupPosition; |
745 | } | 732 | } |
746 | 733 | ||
747 | if (IsAttachment) | 734 | if (m_parentGroup.IsAttachment) |
748 | { | 735 | { |
749 | ScenePresence sp = m_parentGroup.Scene.GetScenePresence(AttachedAvatar); | 736 | ScenePresence sp = m_parentGroup.Scene.GetScenePresence(ParentGroup.AttachedAvatar); |
750 | if (sp != null) | 737 | if (sp != null) |
751 | return sp.AbsolutePosition; | 738 | return sp.AbsolutePosition; |
752 | } | 739 | } |
@@ -794,7 +781,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
794 | set | 781 | set |
795 | { | 782 | { |
796 | Vector3 oldpos = m_offsetPosition; | 783 | Vector3 oldpos = m_offsetPosition; |
797 | StoreUndoState(UndoType.STATE_PRIM_POSITION); | ||
798 | m_offsetPosition = value; | 784 | m_offsetPosition = value; |
799 | 785 | ||
800 | if (ParentGroup != null && !ParentGroup.IsDeleted) | 786 | if (ParentGroup != null && !ParentGroup.IsDeleted) |
@@ -834,7 +820,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
834 | { | 820 | { |
835 | if (IsRoot) | 821 | if (IsRoot) |
836 | { | 822 | { |
837 | if (IsAttachment) | 823 | if (m_parentGroup.IsAttachment) |
838 | return AttachedPos; | 824 | return AttachedPos; |
839 | else | 825 | else |
840 | return AbsolutePosition; | 826 | return AbsolutePosition; |
@@ -887,7 +873,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
887 | actor.Orientation = resultingrotation; | 873 | actor.Orientation = resultingrotation; |
888 | //m_log.Info("[PART]: RO2:" + actor.Orientation.ToString()); | 874 | //m_log.Info("[PART]: RO2:" + actor.Orientation.ToString()); |
889 | } | 875 | } |
890 | m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor); | 876 | |
877 | if (m_parentGroup != null) | ||
878 | m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor); | ||
891 | //} | 879 | //} |
892 | } | 880 | } |
893 | catch (Exception ex) | 881 | catch (Exception ex) |
@@ -895,7 +883,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
895 | m_log.Error("[SCENEOBJECTPART]: ROTATIONOFFSET" + ex.Message); | 883 | m_log.Error("[SCENEOBJECTPART]: ROTATIONOFFSET" + ex.Message); |
896 | } | 884 | } |
897 | } | 885 | } |
898 | |||
899 | } | 886 | } |
900 | } | 887 | } |
901 | 888 | ||
@@ -1044,30 +1031,39 @@ namespace OpenSim.Region.Framework.Scenes | |||
1044 | get { return m_shape; } | 1031 | get { return m_shape; } |
1045 | set { m_shape = value; } | 1032 | set { m_shape = value; } |
1046 | } | 1033 | } |
1047 | 1034 | ||
1035 | /// <summary> | ||
1036 | /// Change the scale of this part. | ||
1037 | /// </summary> | ||
1048 | public Vector3 Scale | 1038 | public Vector3 Scale |
1049 | { | 1039 | { |
1050 | get { return m_shape.Scale; } | 1040 | get { return m_shape.Scale; } |
1051 | set | 1041 | set |
1052 | { | 1042 | { |
1053 | StoreUndoState(UndoType.STATE_PRIM_SCALE); | ||
1054 | if (m_shape != null) | 1043 | if (m_shape != null) |
1055 | { | 1044 | { |
1045 | StoreUndoState(); | ||
1046 | |||
1056 | m_shape.Scale = value; | 1047 | m_shape.Scale = value; |
1057 | 1048 | ||
1058 | PhysicsActor actor = PhysActor; | 1049 | PhysicsActor actor = PhysActor; |
1059 | if (actor != null && m_parentGroup != null) | 1050 | if (actor != null) |
1060 | { | 1051 | { |
1061 | if (m_parentGroup.Scene != null) | 1052 | if (m_parentGroup.Scene != null) |
1062 | { | 1053 | { |
1063 | if (m_parentGroup.Scene.PhysicsScene != null) | 1054 | if (m_parentGroup.Scene.PhysicsScene != null) |
1064 | { | 1055 | { |
1065 | actor.Size = m_shape.Scale; | 1056 | actor.Size = m_shape.Scale; |
1066 | m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor); | 1057 | |
1058 | if (Shape.SculptEntry) | ||
1059 | CheckSculptAndLoad(); | ||
1060 | else | ||
1061 | ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor); | ||
1067 | } | 1062 | } |
1068 | } | 1063 | } |
1069 | } | 1064 | } |
1070 | } | 1065 | } |
1066 | |||
1071 | TriggerScriptChangedEvent(Changed.SCALE); | 1067 | TriggerScriptChangedEvent(Changed.SCALE); |
1072 | } | 1068 | } |
1073 | } | 1069 | } |
@@ -1092,13 +1088,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
1092 | set | 1088 | set |
1093 | { | 1089 | { |
1094 | m_mediaUrl = value; | 1090 | m_mediaUrl = value; |
1095 | 1091 | ||
1096 | if (ParentGroup != null) | 1092 | if (ParentGroup != null) |
1097 | ParentGroup.HasGroupChanged = true; | 1093 | ParentGroup.HasGroupChanged = true; |
1098 | } | 1094 | } |
1099 | } | 1095 | } |
1100 | 1096 | ||
1101 | |||
1102 | public bool CreateSelected | 1097 | public bool CreateSelected |
1103 | { | 1098 | { |
1104 | get { return m_createSelected; } | 1099 | get { return m_createSelected; } |
@@ -1118,7 +1113,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
1118 | { | 1113 | { |
1119 | get | 1114 | get |
1120 | { | 1115 | { |
1121 | return GroupPosition + (m_offsetPosition * ParentGroup.RootPart.RotationOffset); | 1116 | if (m_parentGroup.IsAttachment) |
1117 | return GroupPosition; | ||
1118 | |||
1119 | return m_offsetPosition + m_groupPosition; | ||
1122 | } | 1120 | } |
1123 | } | 1121 | } |
1124 | 1122 | ||
@@ -1138,7 +1136,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
1138 | set { m_sitTargetOrientation = value; } | 1136 | set { m_sitTargetOrientation = value; } |
1139 | } | 1137 | } |
1140 | 1138 | ||
1141 | |||
1142 | public Vector3 SitTargetPosition | 1139 | public Vector3 SitTargetPosition |
1143 | { | 1140 | { |
1144 | get { return m_sitTargetPosition; } | 1141 | get { return m_sitTargetPosition; } |
@@ -1268,7 +1265,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
1268 | /// <summary> | 1265 | /// <summary> |
1269 | /// Property flags. See OpenMetaverse.PrimFlags | 1266 | /// Property flags. See OpenMetaverse.PrimFlags |
1270 | /// </summary> | 1267 | /// </summary> |
1268 | /// <remarks> | ||
1271 | /// Example properties are PrimFlags.Phantom and PrimFlags.DieAtEdge | 1269 | /// Example properties are PrimFlags.Phantom and PrimFlags.DieAtEdge |
1270 | /// </remarks> | ||
1272 | public PrimFlags Flags | 1271 | public PrimFlags Flags |
1273 | { | 1272 | { |
1274 | get { return _flags; } | 1273 | get { return _flags; } |
@@ -1298,7 +1297,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1298 | { | 1297 | { |
1299 | get | 1298 | get |
1300 | { | 1299 | { |
1301 | if (ParentGroup != null && ParentGroup.Scene != null) | 1300 | if (ParentGroup.Scene != null) |
1302 | return ParentGroup.Scene.RegionInfo.RegionID; | 1301 | return ParentGroup.Scene.RegionInfo.RegionID; |
1303 | else | 1302 | else |
1304 | return UUID.Zero; | 1303 | return UUID.Zero; |
@@ -1313,14 +1312,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
1313 | get | 1312 | get |
1314 | { | 1313 | { |
1315 | if (ParentGroup != null) | 1314 | if (ParentGroup != null) |
1316 | { | ||
1317 | _parentUUID = ParentGroup.UUID; | 1315 | _parentUUID = ParentGroup.UUID; |
1318 | } | 1316 | |
1319 | return _parentUUID; | 1317 | return _parentUUID; |
1320 | } | 1318 | } |
1319 | |||
1321 | set { _parentUUID = value; } | 1320 | set { _parentUUID = value; } |
1322 | } | 1321 | } |
1323 | |||
1324 | 1322 | ||
1325 | public string SitAnimation | 1323 | public string SitAnimation |
1326 | { | 1324 | { |
@@ -1555,10 +1553,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1555 | impulse = newimpulse; | 1553 | impulse = newimpulse; |
1556 | } | 1554 | } |
1557 | 1555 | ||
1558 | if (m_parentGroup != null) | 1556 | m_parentGroup.applyAngularImpulse(impulse); |
1559 | { | ||
1560 | m_parentGroup.applyAngularImpulse(impulse); | ||
1561 | } | ||
1562 | } | 1557 | } |
1563 | 1558 | ||
1564 | /// <summary> | 1559 | /// <summary> |
@@ -1581,19 +1576,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1581 | impulse = newimpulse; | 1576 | impulse = newimpulse; |
1582 | } | 1577 | } |
1583 | 1578 | ||
1584 | if (m_parentGroup != null) | 1579 | m_parentGroup.setAngularImpulse(impulse); |
1585 | { | ||
1586 | m_parentGroup.setAngularImpulse(impulse); | ||
1587 | } | ||
1588 | } | ||
1589 | |||
1590 | public Vector3 GetTorque() | ||
1591 | { | ||
1592 | if (m_parentGroup != null) | ||
1593 | { | ||
1594 | m_parentGroup.GetTorque(); | ||
1595 | } | ||
1596 | return Vector3.Zero; | ||
1597 | } | 1580 | } |
1598 | 1581 | ||
1599 | /// <summary> | 1582 | /// <summary> |
@@ -1623,7 +1606,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1623 | 1606 | ||
1624 | // The only time the physics scene shouldn't know about the prim is if it's phantom or an attachment, which is phantom by definition | 1607 | // The only time the physics scene shouldn't know about the prim is if it's phantom or an attachment, which is phantom by definition |
1625 | // or flexible | 1608 | // or flexible |
1626 | if (!isPhantom && !IsAttachment && !(Shape.PathCurve == (byte) Extrusion.Flexible)) | 1609 | if (!isPhantom && !m_parentGroup.IsAttachment && !(Shape.PathCurve == (byte) Extrusion.Flexible)) |
1627 | { | 1610 | { |
1628 | try | 1611 | try |
1629 | { | 1612 | { |
@@ -1635,7 +1618,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
1635 | RotationOffset, | 1618 | RotationOffset, |
1636 | RigidBody, | 1619 | RigidBody, |
1637 | m_localId); | 1620 | m_localId); |
1638 | PhysActor.SetMaterial(Material); | ||
1639 | } | 1621 | } |
1640 | catch | 1622 | catch |
1641 | { | 1623 | { |
@@ -1647,6 +1629,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1647 | { | 1629 | { |
1648 | PhysActor.SOPName = this.Name; // save object name and desc into the PhysActor so ODE internals know the joint/body info | 1630 | PhysActor.SOPName = this.Name; // save object name and desc into the PhysActor so ODE internals know the joint/body info |
1649 | PhysActor.SOPDescription = this.Description; | 1631 | PhysActor.SOPDescription = this.Description; |
1632 | PhysActor.SetMaterial(Material); | ||
1650 | DoPhysicsPropertyUpdate(RigidBody, true); | 1633 | DoPhysicsPropertyUpdate(RigidBody, true); |
1651 | PhysActor.SetVolumeDetect(VolumeDetectActive ? 1 : 0); | 1634 | PhysActor.SetVolumeDetect(VolumeDetectActive ? 1 : 0); |
1652 | } | 1635 | } |
@@ -1658,19 +1641,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
1658 | } | 1641 | } |
1659 | } | 1642 | } |
1660 | 1643 | ||
1661 | public void ClearUndoState() | ||
1662 | { | ||
1663 | lock (m_undo) | ||
1664 | { | ||
1665 | m_undo.Clear(); | ||
1666 | } | ||
1667 | lock (m_redo) | ||
1668 | { | ||
1669 | m_redo.Clear(); | ||
1670 | } | ||
1671 | StoreUndoState(UndoType.STATE_ALL); | ||
1672 | } | ||
1673 | |||
1674 | public byte ConvertScriptUintToByte(uint indata) | 1644 | public byte ConvertScriptUintToByte(uint indata) |
1675 | { | 1645 | { |
1676 | byte outdata = (byte)TextureAnimFlags.NONE; | 1646 | byte outdata = (byte)TextureAnimFlags.NONE; |
@@ -1751,7 +1721,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
1751 | { | 1721 | { |
1752 | if (dupe.m_shape.SculptEntry && dupe.m_shape.SculptTexture != UUID.Zero) | 1722 | if (dupe.m_shape.SculptEntry && dupe.m_shape.SculptTexture != UUID.Zero) |
1753 | { | 1723 | { |
1754 | m_parentGroup.Scene.AssetService.Get(dupe.m_shape.SculptTexture.ToString(), dupe, AssetReceived); | 1724 | ParentGroup.Scene.AssetService.Get( |
1725 | dupe.m_shape.SculptTexture.ToString(), dupe, dupe.AssetReceived); | ||
1755 | } | 1726 | } |
1756 | 1727 | ||
1757 | bool UsePhysics = ((dupe.Flags & PrimFlags.Physics) != 0); | 1728 | bool UsePhysics = ((dupe.Flags & PrimFlags.Physics) != 0); |
@@ -1765,14 +1736,20 @@ namespace OpenSim.Region.Framework.Scenes | |||
1765 | return dupe; | 1736 | return dupe; |
1766 | } | 1737 | } |
1767 | 1738 | ||
1739 | /// <summary> | ||
1740 | /// Called back by asynchronous asset fetch. | ||
1741 | /// </summary> | ||
1742 | /// <param name="id">ID of asset received</param> | ||
1743 | /// <param name="sender">Register</param> | ||
1744 | /// <param name="asset"></param> | ||
1768 | protected void AssetReceived(string id, Object sender, AssetBase asset) | 1745 | protected void AssetReceived(string id, Object sender, AssetBase asset) |
1769 | { | 1746 | { |
1770 | if (asset != null) | 1747 | if (asset != null) |
1771 | { | 1748 | SculptTextureCallback(asset); |
1772 | SceneObjectPart sop = (SceneObjectPart)sender; | 1749 | else |
1773 | if (sop != null) | 1750 | m_log.WarnFormat( |
1774 | sop.SculptTextureCallback(asset.FullID, asset); | 1751 | "[SCENE OBJECT PART]: Part {0} {1} requested mesh/sculpt data for asset id {2} from asset service but received no data", |
1775 | } | 1752 | Name, LocalId, id); |
1776 | } | 1753 | } |
1777 | 1754 | ||
1778 | public static SceneObjectPart Create() | 1755 | public static SceneObjectPart Create() |
@@ -1789,97 +1766,111 @@ namespace OpenSim.Region.Framework.Scenes | |||
1789 | return part; | 1766 | return part; |
1790 | } | 1767 | } |
1791 | 1768 | ||
1792 | public void DoPhysicsPropertyUpdate(bool UsePhysics, bool isNew) | 1769 | /// <summary> |
1770 | /// Do a physics property update for a NINJA joint. | ||
1771 | /// </summary> | ||
1772 | /// <param name="UsePhysics"></param> | ||
1773 | /// <param name="isNew"></param> | ||
1774 | protected void DoPhysicsPropertyUpdateForNinjaJoint(bool UsePhysics, bool isNew) | ||
1793 | { | 1775 | { |
1794 | if (IsJoint()) | 1776 | if (UsePhysics) |
1795 | { | 1777 | { |
1796 | if (UsePhysics) | 1778 | // by turning a joint proxy object physical, we cause creation of a joint in the ODE scene. |
1797 | { | 1779 | // note that, as a special case, joints have no bodies or geoms in the physics scene, even though they are physical. |
1798 | // by turning a joint proxy object physical, we cause creation of a joint in the ODE scene. | ||
1799 | // note that, as a special case, joints have no bodies or geoms in the physics scene, even though they are physical. | ||
1800 | 1780 | ||
1801 | PhysicsJointType jointType; | 1781 | PhysicsJointType jointType; |
1802 | if (IsHingeJoint()) | 1782 | if (IsHingeJoint()) |
1803 | { | 1783 | { |
1804 | jointType = PhysicsJointType.Hinge; | 1784 | jointType = PhysicsJointType.Hinge; |
1805 | } | 1785 | } |
1806 | else if (IsBallJoint()) | 1786 | else if (IsBallJoint()) |
1807 | { | 1787 | { |
1808 | jointType = PhysicsJointType.Ball; | 1788 | jointType = PhysicsJointType.Ball; |
1809 | } | 1789 | } |
1810 | else | 1790 | else |
1811 | { | 1791 | { |
1812 | jointType = PhysicsJointType.Ball; | 1792 | jointType = PhysicsJointType.Ball; |
1813 | } | 1793 | } |
1814 | 1794 | ||
1815 | List<string> bodyNames = new List<string>(); | 1795 | List<string> bodyNames = new List<string>(); |
1816 | string RawParams = Description; | 1796 | string RawParams = Description; |
1817 | string[] jointParams = RawParams.Split(" ".ToCharArray(), System.StringSplitOptions.RemoveEmptyEntries); | 1797 | string[] jointParams = RawParams.Split(" ".ToCharArray(), System.StringSplitOptions.RemoveEmptyEntries); |
1818 | string trackedBodyName = null; | 1798 | string trackedBodyName = null; |
1819 | if (jointParams.Length >= 2) | 1799 | if (jointParams.Length >= 2) |
1800 | { | ||
1801 | for (int iBodyName = 0; iBodyName < 2; iBodyName++) | ||
1820 | { | 1802 | { |
1821 | for (int iBodyName = 0; iBodyName < 2; iBodyName++) | 1803 | string bodyName = jointParams[iBodyName]; |
1804 | bodyNames.Add(bodyName); | ||
1805 | if (bodyName != "NULL") | ||
1822 | { | 1806 | { |
1823 | string bodyName = jointParams[iBodyName]; | 1807 | if (trackedBodyName == null) |
1824 | bodyNames.Add(bodyName); | ||
1825 | if (bodyName != "NULL") | ||
1826 | { | 1808 | { |
1827 | if (trackedBodyName == null) | 1809 | trackedBodyName = bodyName; |
1828 | { | ||
1829 | trackedBodyName = bodyName; | ||
1830 | } | ||
1831 | } | 1810 | } |
1832 | } | 1811 | } |
1833 | } | 1812 | } |
1813 | } | ||
1834 | 1814 | ||
1835 | SceneObjectPart trackedBody = m_parentGroup.Scene.GetSceneObjectPart(trackedBodyName); // FIXME: causes a sequential lookup | 1815 | SceneObjectPart trackedBody = m_parentGroup.Scene.GetSceneObjectPart(trackedBodyName); // FIXME: causes a sequential lookup |
1836 | Quaternion localRotation = Quaternion.Identity; | 1816 | Quaternion localRotation = Quaternion.Identity; |
1837 | if (trackedBody != null) | 1817 | if (trackedBody != null) |
1838 | { | 1818 | { |
1839 | localRotation = Quaternion.Inverse(trackedBody.RotationOffset) * this.RotationOffset; | 1819 | localRotation = Quaternion.Inverse(trackedBody.RotationOffset) * this.RotationOffset; |
1840 | } | 1820 | } |
1841 | else | 1821 | else |
1842 | { | 1822 | { |
1843 | // error, output it below | 1823 | // error, output it below |
1844 | } | 1824 | } |
1845 | |||
1846 | PhysicsJoint joint; | ||
1847 | 1825 | ||
1848 | joint = m_parentGroup.Scene.PhysicsScene.RequestJointCreation(Name, jointType, | 1826 | PhysicsJoint joint; |
1849 | AbsolutePosition, | ||
1850 | this.RotationOffset, | ||
1851 | Description, | ||
1852 | bodyNames, | ||
1853 | trackedBodyName, | ||
1854 | localRotation); | ||
1855 | 1827 | ||
1856 | if (trackedBody == null) | 1828 | joint = m_parentGroup.Scene.PhysicsScene.RequestJointCreation(Name, jointType, |
1857 | { | 1829 | AbsolutePosition, |
1858 | ParentGroup.Scene.jointErrorMessage(joint, "warning: tracked body name not found! joint location will not be updated properly. joint: " + Name); | 1830 | this.RotationOffset, |
1859 | } | 1831 | Description, |
1832 | bodyNames, | ||
1833 | trackedBodyName, | ||
1834 | localRotation); | ||
1860 | 1835 | ||
1836 | if (trackedBody == null) | ||
1837 | { | ||
1838 | ParentGroup.Scene.jointErrorMessage(joint, "warning: tracked body name not found! joint location will not be updated properly. joint: " + Name); | ||
1839 | } | ||
1840 | } | ||
1841 | else | ||
1842 | { | ||
1843 | if (isNew) | ||
1844 | { | ||
1845 | // if the joint proxy is new, and it is not physical, do nothing. There is no joint in ODE to | ||
1846 | // delete, and if we try to delete it, due to asynchronous processing, the deletion request | ||
1847 | // will get processed later at an indeterminate time, which could cancel a later-arriving | ||
1848 | // joint creation request. | ||
1861 | } | 1849 | } |
1862 | else | 1850 | else |
1863 | { | 1851 | { |
1864 | if (isNew) | 1852 | // here we turn off the joint object, so remove the joint from the physics scene |
1865 | { | 1853 | m_parentGroup.Scene.PhysicsScene.RequestJointDeletion(Name); // FIXME: what if the name changed? |
1866 | // if the joint proxy is new, and it is not physical, do nothing. There is no joint in ODE to | ||
1867 | // delete, and if we try to delete it, due to asynchronous processing, the deletion request | ||
1868 | // will get processed later at an indeterminate time, which could cancel a later-arriving | ||
1869 | // joint creation request. | ||
1870 | } | ||
1871 | else | ||
1872 | { | ||
1873 | // here we turn off the joint object, so remove the joint from the physics scene | ||
1874 | m_parentGroup.Scene.PhysicsScene.RequestJointDeletion(Name); // FIXME: what if the name changed? | ||
1875 | 1854 | ||
1876 | // make sure client isn't interpolating the joint proxy object | 1855 | // make sure client isn't interpolating the joint proxy object |
1877 | Velocity = Vector3.Zero; | 1856 | Velocity = Vector3.Zero; |
1878 | AngularVelocity = Vector3.Zero; | 1857 | AngularVelocity = Vector3.Zero; |
1879 | Acceleration = Vector3.Zero; | 1858 | Acceleration = Vector3.Zero; |
1880 | } | ||
1881 | } | 1859 | } |
1882 | } | 1860 | } |
1861 | } | ||
1862 | |||
1863 | /// <summary> | ||
1864 | /// Do a physics propery update for this part. | ||
1865 | /// </summary> | ||
1866 | /// <param name="UsePhysics"></param> | ||
1867 | /// <param name="isNew"></param> | ||
1868 | public void DoPhysicsPropertyUpdate(bool UsePhysics, bool isNew) | ||
1869 | { | ||
1870 | if (IsJoint()) | ||
1871 | { | ||
1872 | DoPhysicsPropertyUpdateForNinjaJoint(UsePhysics, isNew); | ||
1873 | } | ||
1883 | else | 1874 | else |
1884 | { | 1875 | { |
1885 | if (PhysActor != null) | 1876 | if (PhysActor != null) |
@@ -1919,7 +1910,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
1919 | 1910 | ||
1920 | PhysActor.IsPhysical = UsePhysics; | 1911 | PhysActor.IsPhysical = UsePhysics; |
1921 | 1912 | ||
1922 | |||
1923 | // If we're not what we're supposed to be in the physics scene, recreate ourselves. | 1913 | // If we're not what we're supposed to be in the physics scene, recreate ourselves. |
1924 | //m_parentGroup.Scene.PhysicsScene.RemovePrim(PhysActor); | 1914 | //m_parentGroup.Scene.PhysicsScene.RemovePrim(PhysActor); |
1925 | /// that's not wholesome. Had to make Scene public | 1915 | /// that's not wholesome. Had to make Scene public |
@@ -1943,7 +1933,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
1943 | } | 1933 | } |
1944 | } | 1934 | } |
1945 | } | 1935 | } |
1946 | m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor); | 1936 | |
1937 | // If this part is a sculpt then delay the physics update until we've asynchronously loaded the | ||
1938 | // mesh data. | ||
1939 | if (Shape.SculptEntry) | ||
1940 | CheckSculptAndLoad(); | ||
1941 | else | ||
1942 | m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor); | ||
1947 | } | 1943 | } |
1948 | } | 1944 | } |
1949 | } | 1945 | } |
@@ -1955,22 +1951,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
1955 | /// <returns></returns> | 1951 | /// <returns></returns> |
1956 | public static SceneObjectPart FromXml(XmlTextReader xmlReader) | 1952 | public static SceneObjectPart FromXml(XmlTextReader xmlReader) |
1957 | { | 1953 | { |
1958 | return FromXml(UUID.Zero, xmlReader); | ||
1959 | } | ||
1960 | |||
1961 | /// <summary> | ||
1962 | /// Restore this part from the serialized xml representation. | ||
1963 | /// </summary> | ||
1964 | /// <param name="fromUserInventoryItemId">The inventory id from which this part came, if applicable</param> | ||
1965 | /// <param name="xmlReader"></param> | ||
1966 | /// <returns></returns> | ||
1967 | public static SceneObjectPart FromXml(UUID fromUserInventoryItemId, XmlTextReader xmlReader) | ||
1968 | { | ||
1969 | SceneObjectPart part = SceneObjectSerializer.Xml2ToSOP(xmlReader); | 1954 | SceneObjectPart part = SceneObjectSerializer.Xml2ToSOP(xmlReader); |
1970 | part.m_fromUserInventoryItemID = fromUserInventoryItemId; | ||
1971 | 1955 | ||
1972 | // for tempOnRez objects, we have to fix the Expire date. | 1956 | // for tempOnRez objects, we have to fix the Expire date. |
1973 | if ((part.Flags & PrimFlags.TemporaryOnRez) != 0) part.ResetExpire(); | 1957 | if ((part.Flags & PrimFlags.TemporaryOnRez) != 0) |
1958 | part.ResetExpire(); | ||
1974 | 1959 | ||
1975 | return part; | 1960 | return part; |
1976 | } | 1961 | } |
@@ -1982,8 +1967,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
1982 | 1967 | ||
1983 | public bool GetDieAtEdge() | 1968 | public bool GetDieAtEdge() |
1984 | { | 1969 | { |
1985 | if (m_parentGroup == null) | ||
1986 | return false; | ||
1987 | if (m_parentGroup.IsDeleted) | 1970 | if (m_parentGroup.IsDeleted) |
1988 | return false; | 1971 | return false; |
1989 | 1972 | ||
@@ -1992,8 +1975,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
1992 | 1975 | ||
1993 | public bool GetReturnAtEdge() | 1976 | public bool GetReturnAtEdge() |
1994 | { | 1977 | { |
1995 | if (m_parentGroup == null) | ||
1996 | return false; | ||
1997 | if (m_parentGroup.IsDeleted) | 1978 | if (m_parentGroup.IsDeleted) |
1998 | return false; | 1979 | return false; |
1999 | 1980 | ||
@@ -2002,8 +1983,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
2002 | 1983 | ||
2003 | public void SetReturnAtEdge(bool p) | 1984 | public void SetReturnAtEdge(bool p) |
2004 | { | 1985 | { |
2005 | if (m_parentGroup == null) | ||
2006 | return; | ||
2007 | if (m_parentGroup.IsDeleted) | 1986 | if (m_parentGroup.IsDeleted) |
2008 | return; | 1987 | return; |
2009 | 1988 | ||
@@ -2012,8 +1991,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
2012 | 1991 | ||
2013 | public bool GetBlockGrab() | 1992 | public bool GetBlockGrab() |
2014 | { | 1993 | { |
2015 | if (m_parentGroup == null) | ||
2016 | return false; | ||
2017 | if (m_parentGroup.IsDeleted) | 1994 | if (m_parentGroup.IsDeleted) |
2018 | return false; | 1995 | return false; |
2019 | 1996 | ||
@@ -2022,8 +1999,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
2022 | 1999 | ||
2023 | public void SetBlockGrab(bool p) | 2000 | public void SetBlockGrab(bool p) |
2024 | { | 2001 | { |
2025 | if (m_parentGroup == null) | ||
2026 | return; | ||
2027 | if (m_parentGroup.IsDeleted) | 2002 | if (m_parentGroup.IsDeleted) |
2028 | return; | 2003 | return; |
2029 | 2004 | ||
@@ -2032,8 +2007,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
2032 | 2007 | ||
2033 | public void SetStatusSandbox(bool p) | 2008 | public void SetStatusSandbox(bool p) |
2034 | { | 2009 | { |
2035 | if (m_parentGroup == null) | ||
2036 | return; | ||
2037 | if (m_parentGroup.IsDeleted) | 2010 | if (m_parentGroup.IsDeleted) |
2038 | return; | 2011 | return; |
2039 | StatusSandboxPos = m_parentGroup.RootPart.AbsolutePosition; | 2012 | StatusSandboxPos = m_parentGroup.RootPart.AbsolutePosition; |
@@ -2042,8 +2015,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
2042 | 2015 | ||
2043 | public bool GetStatusSandbox() | 2016 | public bool GetStatusSandbox() |
2044 | { | 2017 | { |
2045 | if (m_parentGroup == null) | ||
2046 | return false; | ||
2047 | if (m_parentGroup.IsDeleted) | 2018 | if (m_parentGroup.IsDeleted) |
2048 | return false; | 2019 | return false; |
2049 | 2020 | ||
@@ -2085,25 +2056,17 @@ namespace OpenSim.Region.Framework.Scenes | |||
2085 | public Vector3 GetGeometricCenter() | 2056 | public Vector3 GetGeometricCenter() |
2086 | { | 2057 | { |
2087 | if (PhysActor != null) | 2058 | if (PhysActor != null) |
2088 | { | ||
2089 | return new Vector3(PhysActor.CenterOfMass.X, PhysActor.CenterOfMass.Y, PhysActor.CenterOfMass.Z); | 2059 | return new Vector3(PhysActor.CenterOfMass.X, PhysActor.CenterOfMass.Y, PhysActor.CenterOfMass.Z); |
2090 | } | ||
2091 | else | 2060 | else |
2092 | { | ||
2093 | return new Vector3(0, 0, 0); | 2061 | return new Vector3(0, 0, 0); |
2094 | } | ||
2095 | } | 2062 | } |
2096 | 2063 | ||
2097 | public float GetMass() | 2064 | public float GetMass() |
2098 | { | 2065 | { |
2099 | if (PhysActor != null) | 2066 | if (PhysActor != null) |
2100 | { | ||
2101 | return PhysActor.Mass; | 2067 | return PhysActor.Mass; |
2102 | } | ||
2103 | else | 2068 | else |
2104 | { | ||
2105 | return 0; | 2069 | return 0; |
2106 | } | ||
2107 | } | 2070 | } |
2108 | 2071 | ||
2109 | public Vector3 GetForce() | 2072 | public Vector3 GetForce() |
@@ -2119,19 +2082,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
2119 | client.SendObjectPropertiesReply(this); | 2082 | client.SendObjectPropertiesReply(this); |
2120 | } | 2083 | } |
2121 | 2084 | ||
2122 | public UUID GetRootPartUUID() | ||
2123 | { | ||
2124 | if (m_parentGroup != null) | ||
2125 | { | ||
2126 | return m_parentGroup.UUID; | ||
2127 | } | ||
2128 | return UUID.Zero; | ||
2129 | } | ||
2130 | |||
2131 | /// <summary> | 2085 | /// <summary> |
2132 | /// Method for a prim to get it's world position from the group. | 2086 | /// Method for a prim to get it's world position from the group. |
2133 | /// Remember, the Group Position simply gives the position of the group itself | ||
2134 | /// </summary> | 2087 | /// </summary> |
2088 | /// <remarks> | ||
2089 | /// Remember, the Group Position simply gives the position of the group itself | ||
2090 | /// </remarks> | ||
2135 | /// <returns>A Linked Child Prim objects position in world</returns> | 2091 | /// <returns>A Linked Child Prim objects position in world</returns> |
2136 | public Vector3 GetWorldPosition() | 2092 | public Vector3 GetWorldPosition() |
2137 | { | 2093 | { |
@@ -2249,8 +2205,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
2249 | m_lastColliders.Remove(localID); | 2205 | m_lastColliders.Remove(localID); |
2250 | } | 2206 | } |
2251 | 2207 | ||
2252 | if (m_parentGroup == null) | ||
2253 | return; | ||
2254 | if (m_parentGroup.IsDeleted) | 2208 | if (m_parentGroup.IsDeleted) |
2255 | return; | 2209 | return; |
2256 | 2210 | ||
@@ -2271,9 +2225,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
2271 | { | 2225 | { |
2272 | if (localId == 0) | 2226 | if (localId == 0) |
2273 | continue; | 2227 | continue; |
2274 | // always running this check because if the user deletes the object it would return a null reference. | ||
2275 | if (m_parentGroup == null) | ||
2276 | return; | ||
2277 | 2228 | ||
2278 | if (m_parentGroup.Scene == null) | 2229 | if (m_parentGroup.Scene == null) |
2279 | return; | 2230 | return; |
@@ -2282,7 +2233,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
2282 | string data = ""; | 2233 | string data = ""; |
2283 | if (obj != null) | 2234 | if (obj != null) |
2284 | { | 2235 | { |
2285 | if (m_parentGroup.RootPart.CollisionFilter.ContainsValue(obj.UUID.ToString()) || m_parentGroup.RootPart.CollisionFilter.ContainsValue(obj.Name)) | 2236 | if (m_parentGroup.RootPart.CollisionFilter.ContainsValue(obj.UUID.ToString()) |
2237 | || m_parentGroup.RootPart.CollisionFilter.ContainsValue(obj.Name)) | ||
2286 | { | 2238 | { |
2287 | bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1,out data); | 2239 | bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1,out data); |
2288 | //If it is 1, it is to accept ONLY collisions from this object | 2240 | //If it is 1, it is to accept ONLY collisions from this object |
@@ -2329,7 +2281,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
2329 | { | 2281 | { |
2330 | if (av.LocalId == localId) | 2282 | if (av.LocalId == localId) |
2331 | { | 2283 | { |
2332 | if (m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.UUID.ToString()) || m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.Name)) | 2284 | if (m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.UUID.ToString()) |
2285 | || m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.Name)) | ||
2333 | { | 2286 | { |
2334 | bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1, out data); | 2287 | bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1, out data); |
2335 | //If it is 1, it is to accept ONLY collisions from this avatar | 2288 | //If it is 1, it is to accept ONLY collisions from this avatar |
@@ -2377,12 +2330,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
2377 | if (colliding.Count > 0) | 2330 | if (colliding.Count > 0) |
2378 | { | 2331 | { |
2379 | StartCollidingMessage.Colliders = colliding; | 2332 | StartCollidingMessage.Colliders = colliding; |
2380 | // always running this check because if the user deletes the object it would return a null reference. | ||
2381 | if (m_parentGroup == null) | ||
2382 | return; | ||
2383 | 2333 | ||
2384 | if (m_parentGroup.Scene == null) | 2334 | if (m_parentGroup.Scene == null) |
2385 | return; | 2335 | return; |
2336 | |||
2386 | if (m_parentGroup.PassCollision == true) | 2337 | if (m_parentGroup.PassCollision == true) |
2387 | { | 2338 | { |
2388 | //TODO: Add pass to root prim! | 2339 | //TODO: Add pass to root prim! |
@@ -2403,9 +2354,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
2403 | // always running this check because if the user deletes the object it would return a null reference. | 2354 | // always running this check because if the user deletes the object it would return a null reference. |
2404 | if (localId == 0) | 2355 | if (localId == 0) |
2405 | continue; | 2356 | continue; |
2406 | |||
2407 | if (m_parentGroup == null) | ||
2408 | return; | ||
2409 | 2357 | ||
2410 | if (m_parentGroup.Scene == null) | 2358 | if (m_parentGroup.Scene == null) |
2411 | return; | 2359 | return; |
@@ -2414,7 +2362,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
2414 | string data = ""; | 2362 | string data = ""; |
2415 | if (obj != null) | 2363 | if (obj != null) |
2416 | { | 2364 | { |
2417 | if (m_parentGroup.RootPart.CollisionFilter.ContainsValue(obj.UUID.ToString()) || m_parentGroup.RootPart.CollisionFilter.ContainsValue(obj.Name)) | 2365 | if (m_parentGroup.RootPart.CollisionFilter.ContainsValue(obj.UUID.ToString()) |
2366 | || m_parentGroup.RootPart.CollisionFilter.ContainsValue(obj.Name)) | ||
2418 | { | 2367 | { |
2419 | bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1,out data); | 2368 | bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1,out data); |
2420 | //If it is 1, it is to accept ONLY collisions from this object | 2369 | //If it is 1, it is to accept ONLY collisions from this object |
@@ -2461,7 +2410,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
2461 | { | 2410 | { |
2462 | if (av.LocalId == localId) | 2411 | if (av.LocalId == localId) |
2463 | { | 2412 | { |
2464 | if (m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.UUID.ToString()) || m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.Name)) | 2413 | if (m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.UUID.ToString()) |
2414 | || m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.Name)) | ||
2465 | { | 2415 | { |
2466 | bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1, out data); | 2416 | bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1, out data); |
2467 | //If it is 1, it is to accept ONLY collisions from this avatar | 2417 | //If it is 1, it is to accept ONLY collisions from this avatar |
@@ -2509,9 +2459,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
2509 | if (colliding.Count > 0) | 2459 | if (colliding.Count > 0) |
2510 | { | 2460 | { |
2511 | CollidingMessage.Colliders = colliding; | 2461 | CollidingMessage.Colliders = colliding; |
2512 | // always running this check because if the user deletes the object it would return a null reference. | ||
2513 | if (m_parentGroup == null) | ||
2514 | return; | ||
2515 | 2462 | ||
2516 | if (m_parentGroup.Scene == null) | 2463 | if (m_parentGroup.Scene == null) |
2517 | return; | 2464 | return; |
@@ -2532,11 +2479,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
2532 | if (localId == 0) | 2479 | if (localId == 0) |
2533 | continue; | 2480 | continue; |
2534 | 2481 | ||
2535 | // always running this check because if the user deletes the object it would return a null reference. | ||
2536 | if (m_parentGroup == null) | ||
2537 | return; | ||
2538 | if (m_parentGroup.Scene == null) | 2482 | if (m_parentGroup.Scene == null) |
2539 | return; | 2483 | return; |
2484 | |||
2540 | SceneObjectPart obj = m_parentGroup.Scene.GetSceneObjectPart(localId); | 2485 | SceneObjectPart obj = m_parentGroup.Scene.GetSceneObjectPart(localId); |
2541 | string data = ""; | 2486 | string data = ""; |
2542 | if (obj != null) | 2487 | if (obj != null) |
@@ -2588,7 +2533,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
2588 | { | 2533 | { |
2589 | if (av.LocalId == localId) | 2534 | if (av.LocalId == localId) |
2590 | { | 2535 | { |
2591 | if (m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.UUID.ToString()) || m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.Name)) | 2536 | if (m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.UUID.ToString()) |
2537 | || m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.Name)) | ||
2592 | { | 2538 | { |
2593 | bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1, out data); | 2539 | bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1, out data); |
2594 | //If it is 1, it is to accept ONLY collisions from this avatar | 2540 | //If it is 1, it is to accept ONLY collisions from this avatar |
@@ -2637,9 +2583,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
2637 | if (colliding.Count > 0) | 2583 | if (colliding.Count > 0) |
2638 | { | 2584 | { |
2639 | EndCollidingMessage.Colliders = colliding; | 2585 | EndCollidingMessage.Colliders = colliding; |
2640 | // always running this check because if the user deletes the object it would return a null reference. | ||
2641 | if (m_parentGroup == null) | ||
2642 | return; | ||
2643 | 2586 | ||
2644 | if (m_parentGroup.Scene == null) | 2587 | if (m_parentGroup.Scene == null) |
2645 | return; | 2588 | return; |
@@ -2648,6 +2591,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2648 | } | 2591 | } |
2649 | } | 2592 | } |
2650 | } | 2593 | } |
2594 | |||
2651 | if ((m_parentGroup.RootPart.ScriptEvents & scriptEvents.land_collision_start) != 0) | 2595 | if ((m_parentGroup.RootPart.ScriptEvents & scriptEvents.land_collision_start) != 0) |
2652 | { | 2596 | { |
2653 | if (startedColliders.Count > 0) | 2597 | if (startedColliders.Count > 0) |
@@ -2675,9 +2619,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
2675 | if (colliding.Count > 0) | 2619 | if (colliding.Count > 0) |
2676 | { | 2620 | { |
2677 | LandStartCollidingMessage.Colliders = colliding; | 2621 | LandStartCollidingMessage.Colliders = colliding; |
2678 | // always running this check because if the user deletes the object it would return a null reference. | ||
2679 | if (m_parentGroup == null) | ||
2680 | return; | ||
2681 | 2622 | ||
2682 | if (m_parentGroup.Scene == null) | 2623 | if (m_parentGroup.Scene == null) |
2683 | return; | 2624 | return; |
@@ -2686,6 +2627,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2686 | } | 2627 | } |
2687 | } | 2628 | } |
2688 | } | 2629 | } |
2630 | |||
2689 | if ((m_parentGroup.RootPart.ScriptEvents & scriptEvents.land_collision) != 0) | 2631 | if ((m_parentGroup.RootPart.ScriptEvents & scriptEvents.land_collision) != 0) |
2690 | { | 2632 | { |
2691 | if (m_lastColliders.Count > 0) | 2633 | if (m_lastColliders.Count > 0) |
@@ -2713,9 +2655,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
2713 | if (colliding.Count > 0) | 2655 | if (colliding.Count > 0) |
2714 | { | 2656 | { |
2715 | LandCollidingMessage.Colliders = colliding; | 2657 | LandCollidingMessage.Colliders = colliding; |
2716 | // always running this check because if the user deletes the object it would return a null reference. | ||
2717 | if (m_parentGroup == null) | ||
2718 | return; | ||
2719 | 2658 | ||
2720 | if (m_parentGroup.Scene == null) | 2659 | if (m_parentGroup.Scene == null) |
2721 | return; | 2660 | return; |
@@ -2724,6 +2663,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2724 | } | 2663 | } |
2725 | } | 2664 | } |
2726 | } | 2665 | } |
2666 | |||
2727 | if ((m_parentGroup.RootPart.ScriptEvents & scriptEvents.land_collision_end) != 0) | 2667 | if ((m_parentGroup.RootPart.ScriptEvents & scriptEvents.land_collision_end) != 0) |
2728 | { | 2668 | { |
2729 | if (endedColliders.Count > 0) | 2669 | if (endedColliders.Count > 0) |
@@ -2751,9 +2691,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
2751 | if (colliding.Count > 0) | 2691 | if (colliding.Count > 0) |
2752 | { | 2692 | { |
2753 | LandEndCollidingMessage.Colliders = colliding; | 2693 | LandEndCollidingMessage.Colliders = colliding; |
2754 | // always running this check because if the user deletes the object it would return a null reference. | ||
2755 | if (m_parentGroup == null) | ||
2756 | return; | ||
2757 | 2694 | ||
2758 | if (m_parentGroup.Scene == null) | 2695 | if (m_parentGroup.Scene == null) |
2759 | return; | 2696 | return; |
@@ -2777,10 +2714,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
2777 | { | 2714 | { |
2778 | if (PhysActor != null) | 2715 | if (PhysActor != null) |
2779 | { | 2716 | { |
2780 | |||
2781 | Vector3 newpos = new Vector3(PhysActor.Position.GetBytes(), 0); | 2717 | Vector3 newpos = new Vector3(PhysActor.Position.GetBytes(), 0); |
2782 | 2718 | ||
2783 | if (m_parentGroup.Scene.TestBorderCross(newpos, Cardinals.N) | m_parentGroup.Scene.TestBorderCross(newpos, Cardinals.S) | m_parentGroup.Scene.TestBorderCross(newpos, Cardinals.E) | m_parentGroup.Scene.TestBorderCross(newpos, Cardinals.W)) | 2719 | if (m_parentGroup.Scene.TestBorderCross(newpos, Cardinals.N) |
2720 | | m_parentGroup.Scene.TestBorderCross(newpos, Cardinals.S) | ||
2721 | | m_parentGroup.Scene.TestBorderCross(newpos, Cardinals.E) | ||
2722 | | m_parentGroup.Scene.TestBorderCross(newpos, Cardinals.W)) | ||
2784 | { | 2723 | { |
2785 | m_parentGroup.AbsolutePosition = newpos; | 2724 | m_parentGroup.AbsolutePosition = newpos; |
2786 | return; | 2725 | return; |
@@ -2869,13 +2808,29 @@ namespace OpenSim.Region.Framework.Scenes | |||
2869 | } | 2808 | } |
2870 | 2809 | ||
2871 | /// <summary> | 2810 | /// <summary> |
2872 | /// Resize this part. | 2811 | /// Set the scale of this part. |
2873 | /// </summary> | 2812 | /// </summary> |
2813 | /// <remarks> | ||
2814 | /// Unlike the scale property, this checks the new size against scene limits and schedules a full property | ||
2815 | /// update to viewers. | ||
2816 | /// </remarks> | ||
2874 | /// <param name="scale"></param> | 2817 | /// <param name="scale"></param> |
2875 | public void Resize(Vector3 scale) | 2818 | public void Resize(Vector3 scale) |
2876 | { | 2819 | { |
2877 | StoreUndoState(UndoType.STATE_PRIM_SCALE); | 2820 | scale.X = Math.Min(scale.X, ParentGroup.Scene.m_maxNonphys); |
2878 | m_shape.Scale = scale; | 2821 | scale.Y = Math.Min(scale.Y, ParentGroup.Scene.m_maxNonphys); |
2822 | scale.Z = Math.Min(scale.Z, ParentGroup.Scene.m_maxNonphys); | ||
2823 | |||
2824 | if (PhysActor != null && PhysActor.IsPhysical) | ||
2825 | { | ||
2826 | scale.X = Math.Min(scale.X, ParentGroup.Scene.m_maxPhys); | ||
2827 | scale.Y = Math.Min(scale.Y, ParentGroup.Scene.m_maxPhys); | ||
2828 | scale.Z = Math.Min(scale.Z, ParentGroup.Scene.m_maxPhys); | ||
2829 | } | ||
2830 | |||
2831 | // m_log.DebugFormat("[SCENE OBJECT PART]: Resizing {0} {1} to {2}", Name, LocalId, scale); | ||
2832 | |||
2833 | Scale = scale; | ||
2879 | 2834 | ||
2880 | ParentGroup.HasGroupChanged = true; | 2835 | ParentGroup.HasGroupChanged = true; |
2881 | ScheduleFullUpdate(); | 2836 | ScheduleFullUpdate(); |
@@ -2886,20 +2841,48 @@ namespace OpenSim.Region.Framework.Scenes | |||
2886 | m_parentGroup.rotLookAt(target, strength, damping); // This calls method in SceneObjectGroup. | 2841 | m_parentGroup.rotLookAt(target, strength, damping); // This calls method in SceneObjectGroup. |
2887 | } | 2842 | } |
2888 | 2843 | ||
2844 | public void rotLookAt(Quaternion target, float strength, float damping) | ||
2845 | { | ||
2846 | if (m_parentGroup.IsAttachment) | ||
2847 | { | ||
2848 | /* | ||
2849 | ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar); | ||
2850 | if (avatar != null) | ||
2851 | { | ||
2852 | Rotate the Av? | ||
2853 | } */ | ||
2854 | } | ||
2855 | else | ||
2856 | { | ||
2857 | APIDDamp = damping; | ||
2858 | APIDStrength = strength; | ||
2859 | APIDTarget = target; | ||
2860 | } | ||
2861 | } | ||
2862 | |||
2863 | public void startLookAt(Quaternion rot, float damp, float strength) | ||
2864 | { | ||
2865 | APIDDamp = damp; | ||
2866 | APIDStrength = strength; | ||
2867 | APIDTarget = rot; | ||
2868 | } | ||
2869 | |||
2870 | public void stopLookAt() | ||
2871 | { | ||
2872 | APIDTarget = Quaternion.Identity; | ||
2873 | } | ||
2874 | |||
2889 | /// <summary> | 2875 | /// <summary> |
2890 | /// Schedules this prim for a full update | 2876 | /// Schedules this prim for a full update |
2891 | /// </summary> | 2877 | /// </summary> |
2892 | public void ScheduleFullUpdate() | 2878 | public void ScheduleFullUpdate() |
2893 | { | 2879 | { |
2894 | // m_log.DebugFormat("[SCENE OBJECT PART]: Scheduling full update for {0} {1}", Name, LocalId); | 2880 | // m_log.DebugFormat("[SCENE OBJECT PART]: Scheduling full update for {0} {1}", Name, LocalId); |
2895 | 2881 | ||
2896 | if (m_parentGroup != null) | 2882 | if (m_parentGroup == null) |
2897 | { | 2883 | return; |
2898 | if (!m_parentGroup.areUpdatesSuspended) | 2884 | |
2899 | { | 2885 | m_parentGroup.QueueForUpdateCheck(); |
2900 | m_parentGroup.QueueForUpdateCheck(); | ||
2901 | } | ||
2902 | } | ||
2903 | 2886 | ||
2904 | int timeNow = Util.UnixTimeSinceEpoch(); | 2887 | int timeNow = Util.UnixTimeSinceEpoch(); |
2905 | 2888 | ||
@@ -2928,13 +2911,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
2928 | /// </summary> | 2911 | /// </summary> |
2929 | public void ScheduleTerseUpdate() | 2912 | public void ScheduleTerseUpdate() |
2930 | { | 2913 | { |
2914 | if (m_parentGroup == null) | ||
2915 | return; | ||
2916 | |||
2931 | if (m_updateFlag < 1) | 2917 | if (m_updateFlag < 1) |
2932 | { | 2918 | { |
2933 | if (m_parentGroup != null) | 2919 | m_parentGroup.HasGroupChanged = true; |
2934 | { | 2920 | m_parentGroup.QueueForUpdateCheck(); |
2935 | m_parentGroup.HasGroupChanged = true; | 2921 | |
2936 | m_parentGroup.QueueForUpdateCheck(); | ||
2937 | } | ||
2938 | TimeStampTerse = (uint) Util.UnixTimeSinceEpoch(); | 2922 | TimeStampTerse = (uint) Util.UnixTimeSinceEpoch(); |
2939 | m_updateFlag = 1; | 2923 | m_updateFlag = 1; |
2940 | 2924 | ||
@@ -2944,40 +2928,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
2944 | } | 2928 | } |
2945 | } | 2929 | } |
2946 | 2930 | ||
2947 | public void ScriptSetPhantomStatus(bool Phantom) | ||
2948 | { | ||
2949 | if (m_parentGroup != null) | ||
2950 | { | ||
2951 | m_parentGroup.ScriptSetPhantomStatus(Phantom); | ||
2952 | } | ||
2953 | } | ||
2954 | |||
2955 | public void ScriptSetTemporaryStatus(bool Temporary) | ||
2956 | { | ||
2957 | if (m_parentGroup != null) | ||
2958 | { | ||
2959 | m_parentGroup.ScriptSetTemporaryStatus(Temporary); | ||
2960 | } | ||
2961 | } | ||
2962 | |||
2963 | public void ScriptSetPhysicsStatus(bool UsePhysics) | 2931 | public void ScriptSetPhysicsStatus(bool UsePhysics) |
2964 | { | 2932 | { |
2965 | if (m_parentGroup == null) | 2933 | m_parentGroup.ScriptSetPhysicsStatus(UsePhysics); |
2966 | DoPhysicsPropertyUpdate(UsePhysics, false); | ||
2967 | else | ||
2968 | m_parentGroup.ScriptSetPhysicsStatus(UsePhysics); | ||
2969 | } | 2934 | } |
2970 | 2935 | ||
2971 | public void ScriptSetVolumeDetect(bool SetVD) | 2936 | /// <summary> |
2972 | { | 2937 | /// Set sculpt and mesh data, and tell the physics engine to process the change. |
2973 | 2938 | /// </summary> | |
2974 | if (m_parentGroup != null) | 2939 | /// <param name="texture">The mesh itself.</param> |
2975 | { | 2940 | public void SculptTextureCallback(AssetBase texture) |
2976 | m_parentGroup.ScriptSetVolumeDetect(SetVD); | ||
2977 | } | ||
2978 | } | ||
2979 | |||
2980 | public void SculptTextureCallback(UUID textureID, AssetBase texture) | ||
2981 | { | 2941 | { |
2982 | if (m_shape.SculptEntry) | 2942 | if (m_shape.SculptEntry) |
2983 | { | 2943 | { |
@@ -2985,14 +2945,17 @@ namespace OpenSim.Region.Framework.Scenes | |||
2985 | //if (texture != null) | 2945 | //if (texture != null) |
2986 | { | 2946 | { |
2987 | if (texture != null) | 2947 | if (texture != null) |
2948 | { | ||
2949 | // m_log.DebugFormat( | ||
2950 | // "[SCENE OBJECT PART]: Setting sculpt data for {0} on SculptTextureCallback()", Name); | ||
2951 | |||
2988 | m_shape.SculptData = texture.Data; | 2952 | m_shape.SculptData = texture.Data; |
2953 | } | ||
2989 | 2954 | ||
2990 | if (PhysActor != null) | 2955 | if (PhysActor != null) |
2991 | { | 2956 | { |
2992 | // Tricks physics engine into thinking we've changed the part shape. | 2957 | // Update the physics actor with the new loaded sculpt data and set the taint signal. |
2993 | PrimitiveBaseShape m_newshape = m_shape.Copy(); | 2958 | PhysActor.Shape = m_shape; |
2994 | PhysActor.Shape = m_newshape; | ||
2995 | m_shape = m_newshape; | ||
2996 | 2959 | ||
2997 | m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor); | 2960 | m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor); |
2998 | } | 2961 | } |
@@ -3000,16 +2963,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
3000 | } | 2963 | } |
3001 | } | 2964 | } |
3002 | 2965 | ||
3003 | // /// <summary> | ||
3004 | // /// | ||
3005 | // /// </summary> | ||
3006 | // /// <param name="remoteClient"></param> | ||
3007 | // public void SendFullUpdate(IClientAPI remoteClient, uint clientFlags) | ||
3008 | // { | ||
3009 | // m_parentGroup.SendPartFullUpdate(remoteClient, this, clientFlags); | ||
3010 | // } | ||
3011 | |||
3012 | |||
3013 | /// <summary> | 2966 | /// <summary> |
3014 | /// Send a full update to the client for the given part | 2967 | /// Send a full update to the client for the given part |
3015 | /// </summary> | 2968 | /// </summary> |
@@ -3017,12 +2970,15 @@ namespace OpenSim.Region.Framework.Scenes | |||
3017 | /// <param name="clientFlags"></param> | 2970 | /// <param name="clientFlags"></param> |
3018 | protected internal void SendFullUpdate(IClientAPI remoteClient, uint clientFlags) | 2971 | protected internal void SendFullUpdate(IClientAPI remoteClient, uint clientFlags) |
3019 | { | 2972 | { |
2973 | if (m_parentGroup == null) | ||
2974 | return; | ||
2975 | |||
3020 | // m_log.DebugFormat( | 2976 | // m_log.DebugFormat( |
3021 | // "[SOG]: Sendinging part full update to {0} for {1} {2}", remoteClient.Name, part.Name, part.LocalId); | 2977 | // "[SOG]: Sendinging part full update to {0} for {1} {2}", remoteClient.Name, part.Name, part.LocalId); |
3022 | 2978 | ||
3023 | if (IsRoot) | 2979 | if (IsRoot) |
3024 | { | 2980 | { |
3025 | if (IsAttachment) | 2981 | if (m_parentGroup.IsAttachment) |
3026 | { | 2982 | { |
3027 | SendFullUpdateToClient(remoteClient, AttachedPos, clientFlags); | 2983 | SendFullUpdateToClient(remoteClient, AttachedPos, clientFlags); |
3028 | } | 2984 | } |
@@ -3042,6 +2998,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
3042 | /// </summary> | 2998 | /// </summary> |
3043 | public void SendFullUpdateToAllClients() | 2999 | public void SendFullUpdateToAllClients() |
3044 | { | 3000 | { |
3001 | if (m_parentGroup == null) | ||
3002 | return; | ||
3003 | |||
3045 | m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence avatar) | 3004 | m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence avatar) |
3046 | { | 3005 | { |
3047 | SendFullUpdate(avatar.ControllingClient, avatar.GenerateClientFlags(UUID)); | 3006 | SendFullUpdate(avatar.ControllingClient, avatar.GenerateClientFlags(UUID)); |
@@ -3054,6 +3013,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
3054 | /// <param name="agentID"></param> | 3013 | /// <param name="agentID"></param> |
3055 | public void SendFullUpdateToAllClientsExcept(UUID agentID) | 3014 | public void SendFullUpdateToAllClientsExcept(UUID agentID) |
3056 | { | 3015 | { |
3016 | if (m_parentGroup == null) | ||
3017 | return; | ||
3018 | |||
3057 | m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence avatar) | 3019 | m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence avatar) |
3058 | { | 3020 | { |
3059 | // Ugly reference :( | 3021 | // Ugly reference :( |
@@ -3082,9 +3044,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
3082 | /// <param name="clientFlags"></param> | 3044 | /// <param name="clientFlags"></param> |
3083 | public void SendFullUpdateToClient(IClientAPI remoteClient, Vector3 lPos, uint clientFlags) | 3045 | public void SendFullUpdateToClient(IClientAPI remoteClient, Vector3 lPos, uint clientFlags) |
3084 | { | 3046 | { |
3047 | if (ParentGroup == null) | ||
3048 | return; | ||
3049 | |||
3085 | // Suppress full updates during attachment editing | 3050 | // Suppress full updates during attachment editing |
3086 | // | 3051 | // |
3087 | if (ParentGroup.IsSelected && IsAttachment) | 3052 | if (ParentGroup.IsSelected && ParentGroup.IsAttachment) |
3088 | return; | 3053 | return; |
3089 | 3054 | ||
3090 | if (ParentGroup.IsDeleted) | 3055 | if (ParentGroup.IsDeleted) |
@@ -3177,7 +3142,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3177 | 3142 | ||
3178 | UUID ownerID = _ownerID; | 3143 | UUID ownerID = _ownerID; |
3179 | UUID objectID = ParentGroup.RootPart.UUID; | 3144 | UUID objectID = ParentGroup.RootPart.UUID; |
3180 | UUID parentID = GetRootPartUUID(); | 3145 | UUID parentID = ParentGroup.UUID; |
3181 | 3146 | ||
3182 | UUID soundID = UUID.Zero; | 3147 | UUID soundID = UUID.Zero; |
3183 | Vector3 position = AbsolutePosition; // region local | 3148 | Vector3 position = AbsolutePosition; // region local |
@@ -3215,7 +3180,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3215 | ParentGroup.PlaySoundMasterPrim = this; | 3180 | ParentGroup.PlaySoundMasterPrim = this; |
3216 | ownerID = _ownerID; | 3181 | ownerID = _ownerID; |
3217 | objectID = ParentGroup.RootPart.UUID; | 3182 | objectID = ParentGroup.RootPart.UUID; |
3218 | parentID = GetRootPartUUID(); | 3183 | parentID = ParentGroup.UUID; |
3219 | position = AbsolutePosition; // region local | 3184 | position = AbsolutePosition; // region local |
3220 | regionHandle = ParentGroup.Scene.RegionInfo.RegionHandle; | 3185 | regionHandle = ParentGroup.Scene.RegionInfo.RegionHandle; |
3221 | if (triggered) | 3186 | if (triggered) |
@@ -3226,7 +3191,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3226 | { | 3191 | { |
3227 | ownerID = prim._ownerID; | 3192 | ownerID = prim._ownerID; |
3228 | objectID = prim.ParentGroup.RootPart.UUID; | 3193 | objectID = prim.ParentGroup.RootPart.UUID; |
3229 | parentID = prim.GetRootPartUUID(); | 3194 | parentID = prim.ParentGroup.UUID; |
3230 | position = prim.AbsolutePosition; // region local | 3195 | position = prim.AbsolutePosition; // region local |
3231 | regionHandle = prim.ParentGroup.Scene.RegionInfo.RegionHandle; | 3196 | regionHandle = prim.ParentGroup.Scene.RegionInfo.RegionHandle; |
3232 | if (triggered) | 3197 | if (triggered) |
@@ -3263,45 +3228,23 @@ namespace OpenSim.Region.Framework.Scenes | |||
3263 | }); | 3228 | }); |
3264 | } | 3229 | } |
3265 | 3230 | ||
3266 | public void SetAttachmentPoint(uint AttachmentPoint) | ||
3267 | { | ||
3268 | this.AttachmentPoint = AttachmentPoint; | ||
3269 | |||
3270 | if (AttachmentPoint != 0) | ||
3271 | { | ||
3272 | IsAttachment = true; | ||
3273 | } | ||
3274 | else | ||
3275 | { | ||
3276 | IsAttachment = false; | ||
3277 | } | ||
3278 | |||
3279 | // save the attachment point. | ||
3280 | //if (AttachmentPoint != 0) | ||
3281 | //{ | ||
3282 | m_shape.State = (byte)AttachmentPoint; | ||
3283 | //} | ||
3284 | } | ||
3285 | |||
3286 | public void SetAxisRotation(int axis, int rotate) | 3231 | public void SetAxisRotation(int axis, int rotate) |
3287 | { | 3232 | { |
3288 | if (m_parentGroup != null) | 3233 | m_parentGroup.SetAxisRotation(axis, rotate); |
3289 | { | 3234 | |
3290 | m_parentGroup.SetAxisRotation(axis, rotate); | ||
3291 | } | ||
3292 | //Cannot use ScriptBaseClass constants as no referance to it currently. | 3235 | //Cannot use ScriptBaseClass constants as no referance to it currently. |
3293 | if (axis == 2)//STATUS_ROTATE_X | 3236 | if (axis == 2)//STATUS_ROTATE_X |
3294 | STATUS_ROTATE_X = rotate; | 3237 | STATUS_ROTATE_X = rotate; |
3238 | |||
3295 | if (axis == 4)//STATUS_ROTATE_Y | 3239 | if (axis == 4)//STATUS_ROTATE_Y |
3296 | STATUS_ROTATE_Y = rotate; | 3240 | STATUS_ROTATE_Y = rotate; |
3241 | |||
3297 | if (axis == 8)//STATUS_ROTATE_Z | 3242 | if (axis == 8)//STATUS_ROTATE_Z |
3298 | STATUS_ROTATE_Z = rotate; | 3243 | STATUS_ROTATE_Z = rotate; |
3299 | } | 3244 | } |
3300 | 3245 | ||
3301 | public void SetDieAtEdge(bool p) | 3246 | public void SetDieAtEdge(bool p) |
3302 | { | 3247 | { |
3303 | if (m_parentGroup == null) | ||
3304 | return; | ||
3305 | if (m_parentGroup.IsDeleted) | 3248 | if (m_parentGroup.IsDeleted) |
3306 | return; | 3249 | return; |
3307 | 3250 | ||
@@ -3554,7 +3497,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3554 | } | 3497 | } |
3555 | 3498 | ||
3556 | /// <summary> | 3499 | /// <summary> |
3557 | /// | 3500 | /// Set the parent group of this prim. |
3558 | /// </summary> | 3501 | /// </summary> |
3559 | public void SetParent(SceneObjectGroup parent) | 3502 | public void SetParent(SceneObjectGroup parent) |
3560 | { | 3503 | { |
@@ -3611,8 +3554,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
3611 | { | 3554 | { |
3612 | Text = text; | 3555 | Text = text; |
3613 | 3556 | ||
3614 | ParentGroup.HasGroupChanged = true; | 3557 | if (ParentGroup != null) |
3615 | ScheduleFullUpdate(); | 3558 | { |
3559 | ParentGroup.HasGroupChanged = true; | ||
3560 | ScheduleFullUpdate(); | ||
3561 | } | ||
3616 | } | 3562 | } |
3617 | 3563 | ||
3618 | public void StopLookAt() | 3564 | public void StopLookAt() |
@@ -3646,24 +3592,44 @@ namespace OpenSim.Region.Framework.Scenes | |||
3646 | } | 3592 | } |
3647 | public void StoreUndoState(UndoType type) | 3593 | public void StoreUndoState(UndoType type) |
3648 | { | 3594 | { |
3649 | if (!Undoing && (m_parentGroup == null || m_parentGroup.RootPart == null || !m_parentGroup.RootPart.Undoing)) | 3595 | StoreUndoState(false); |
3596 | } | ||
3597 | |||
3598 | public void StoreUndoState(bool forGroup) | ||
3599 | { | ||
3600 | if (!Undoing) | ||
3650 | { | 3601 | { |
3651 | if (!IgnoreUndoUpdate) | 3602 | if (!IgnoreUndoUpdate) |
3652 | { | 3603 | { |
3653 | if (m_parentGroup != null) | 3604 | if (ParentGroup != null) |
3654 | { | 3605 | { |
3655 | lock (m_undo) | 3606 | lock (m_undo) |
3656 | { | 3607 | { |
3657 | if (m_undo.Count > 0) | 3608 | if (m_undo.Count > 0) |
3658 | { | 3609 | { |
3659 | UndoState last = m_undo.Peek(); | 3610 | UndoState last = m_undo.Peek(); |
3660 | 3611 | if (last != null) | |
3612 | { | ||
3613 | // TODO: May need to fix for group comparison | ||
3614 | if (last.Compare(this)) | ||
3615 | { | ||
3616 | // m_log.DebugFormat( | ||
3617 | // "[SCENE OBJECT PART]: Not storing undo for {0} {1} since current state is same as last undo state, initial stack size {2}", | ||
3618 | // Name, LocalId, m_undo.Count); | ||
3619 | |||
3620 | return; | ||
3621 | } | ||
3622 | } | ||
3661 | } | 3623 | } |
3662 | 3624 | ||
3625 | // m_log.DebugFormat( | ||
3626 | // "[SCENE OBJECT PART]: Storing undo state for {0} {1}, forGroup {2}, initial stack size {3}", | ||
3627 | // Name, LocalId, forGroup, m_undo.Count); | ||
3628 | |||
3663 | if (m_parentGroup.GetSceneMaxUndo() > 0) | 3629 | if (m_parentGroup.GetSceneMaxUndo() > 0) |
3664 | { | 3630 | { |
3665 | UndoState lastUndo = m_undo.Peek(); | 3631 | UndoState nUndo = new UndoState(this, forGroup); |
3666 | 3632 | ||
3667 | UndoState nUndo = new UndoState(this, type); | 3633 | UndoState nUndo = new UndoState(this, type); |
3668 | 3634 | ||
3669 | if (lastUndo != null) | 3635 | if (lastUndo != null) |
@@ -3677,11 +3643,114 @@ namespace OpenSim.Region.Framework.Scenes | |||
3677 | } | 3643 | } |
3678 | } | 3644 | } |
3679 | m_undo.Push(nUndo); | 3645 | m_undo.Push(nUndo); |
3646 | |||
3647 | if (m_redo.Count > 0) | ||
3648 | m_redo.Clear(); | ||
3649 | |||
3650 | // m_log.DebugFormat( | ||
3651 | // "[SCENE OBJECT PART]: Stored undo state for {0} {1}, forGroup {2}, stack size now {3}", | ||
3652 | // Name, LocalId, forGroup, m_undo.Count); | ||
3680 | } | 3653 | } |
3654 | } | ||
3655 | } | ||
3656 | } | ||
3657 | // else | ||
3658 | // { | ||
3659 | // m_log.DebugFormat("[SCENE OBJECT PART]: Ignoring undo store for {0} {1}", Name, LocalId); | ||
3660 | // } | ||
3661 | } | ||
3662 | // else | ||
3663 | // { | ||
3664 | // m_log.DebugFormat( | ||
3665 | // "[SCENE OBJECT PART]: Ignoring undo store for {0} {1} since already undoing", Name, LocalId); | ||
3666 | // } | ||
3667 | } | ||
3668 | |||
3669 | /// <summary> | ||
3670 | /// Return number of undos on the stack. Here temporarily pending a refactor. | ||
3671 | /// </summary> | ||
3672 | public int UndoCount | ||
3673 | { | ||
3674 | get | ||
3675 | { | ||
3676 | lock (m_undo) | ||
3677 | return m_undo.Count; | ||
3678 | } | ||
3679 | } | ||
3680 | |||
3681 | public void Undo() | ||
3682 | { | ||
3683 | lock (m_undo) | ||
3684 | { | ||
3685 | // m_log.DebugFormat( | ||
3686 | // "[SCENE OBJECT PART]: Handling undo request for {0} {1}, stack size {2}", | ||
3687 | // Name, LocalId, m_undo.Count); | ||
3688 | |||
3689 | if (m_undo.Count > 0) | ||
3690 | { | ||
3691 | UndoState goback = m_undo.Pop(); | ||
3681 | 3692 | ||
3693 | if (goback != null) | ||
3694 | { | ||
3695 | UndoState nUndo = null; | ||
3696 | |||
3697 | if (m_parentGroup.GetSceneMaxUndo() > 0) | ||
3698 | { | ||
3699 | nUndo = new UndoState(this, goback.ForGroup); | ||
3682 | } | 3700 | } |
3701 | |||
3702 | goback.PlaybackState(this); | ||
3703 | |||
3704 | if (nUndo != null) | ||
3705 | m_redo.Push(nUndo); | ||
3683 | } | 3706 | } |
3684 | } | 3707 | } |
3708 | |||
3709 | // m_log.DebugFormat( | ||
3710 | // "[SCENE OBJECT PART]: Handled undo request for {0} {1}, stack size now {2}", | ||
3711 | // Name, LocalId, m_undo.Count); | ||
3712 | } | ||
3713 | } | ||
3714 | |||
3715 | public void Redo() | ||
3716 | { | ||
3717 | lock (m_undo) | ||
3718 | { | ||
3719 | // m_log.DebugFormat( | ||
3720 | // "[SCENE OBJECT PART]: Handling redo request for {0} {1}, stack size {2}", | ||
3721 | // Name, LocalId, m_redo.Count); | ||
3722 | |||
3723 | if (m_redo.Count > 0) | ||
3724 | { | ||
3725 | UndoState gofwd = m_redo.Pop(); | ||
3726 | |||
3727 | if (gofwd != null) | ||
3728 | { | ||
3729 | if (m_parentGroup.GetSceneMaxUndo() > 0) | ||
3730 | { | ||
3731 | UndoState nUndo = new UndoState(this, gofwd.ForGroup); | ||
3732 | |||
3733 | m_undo.Push(nUndo); | ||
3734 | } | ||
3735 | |||
3736 | gofwd.PlayfwdState(this); | ||
3737 | } | ||
3738 | |||
3739 | // m_log.DebugFormat( | ||
3740 | // "[SCENE OBJECT PART]: Handled redo request for {0} {1}, stack size now {2}", | ||
3741 | // Name, LocalId, m_redo.Count); | ||
3742 | } | ||
3743 | } | ||
3744 | } | ||
3745 | |||
3746 | public void ClearUndoState() | ||
3747 | { | ||
3748 | // m_log.DebugFormat("[SCENE OBJECT PART]: Clearing undo and redo stacks in {0} {1}", Name, LocalId); | ||
3749 | |||
3750 | lock (m_undo) | ||
3751 | { | ||
3752 | m_undo.Clear(); | ||
3753 | m_redo.Clear(); | ||
3685 | } | 3754 | } |
3686 | } | 3755 | } |
3687 | 3756 | ||
@@ -4145,46 +4214,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
4145 | _nextOwnerMask &= (uint)PermissionMask.All; | 4214 | _nextOwnerMask &= (uint)PermissionMask.All; |
4146 | } | 4215 | } |
4147 | 4216 | ||
4148 | public void Undo() | ||
4149 | { | ||
4150 | lock (m_undo) | ||
4151 | { | ||
4152 | if (m_undo.Count > 0) | ||
4153 | { | ||
4154 | UndoState nUndo = null; | ||
4155 | UndoState goback = m_undo.Pop(); | ||
4156 | if (m_parentGroup.GetSceneMaxUndo() > 0) | ||
4157 | { | ||
4158 | nUndo = new UndoState(this, goback.Type); | ||
4159 | } | ||
4160 | |||
4161 | |||
4162 | if (goback != null) | ||
4163 | { | ||
4164 | goback.PlaybackState(this); | ||
4165 | if (nUndo != null) | ||
4166 | m_redo.Push(nUndo); | ||
4167 | } | ||
4168 | } | ||
4169 | } | ||
4170 | } | ||
4171 | |||
4172 | public void Redo() | ||
4173 | { | ||
4174 | lock (m_redo) | ||
4175 | { | ||
4176 | UndoState gofwd = m_redo.Pop(); | ||
4177 | if (m_parentGroup.GetSceneMaxUndo() > 0) | ||
4178 | { | ||
4179 | UndoState nUndo = new UndoState(this, gofwd.Type); | ||
4180 | |||
4181 | m_undo.Push(nUndo); | ||
4182 | } | ||
4183 | if (gofwd != null) | ||
4184 | gofwd.PlayfwdState(this); | ||
4185 | } | ||
4186 | } | ||
4187 | |||
4188 | public void UpdateExtraParam(ushort type, bool inUse, byte[] data) | 4217 | public void UpdateExtraParam(ushort type, bool inUse, byte[] data) |
4189 | { | 4218 | { |
4190 | m_shape.ReadInUpdateExtraParam(type, inUse, data); | 4219 | m_shape.ReadInUpdateExtraParam(type, inUse, data); |
@@ -4197,8 +4226,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
4197 | } | 4226 | } |
4198 | } | 4227 | } |
4199 | 4228 | ||
4200 | ParentGroup.HasGroupChanged = true; | 4229 | if (ParentGroup != null) |
4201 | ScheduleFullUpdate(); | 4230 | { |
4231 | ParentGroup.HasGroupChanged = true; | ||
4232 | ScheduleFullUpdate(); | ||
4233 | } | ||
4202 | } | 4234 | } |
4203 | 4235 | ||
4204 | public void UpdateGroupPosition(Vector3 pos) | 4236 | public void UpdateGroupPosition(Vector3 pos) |
@@ -4345,14 +4377,21 @@ namespace OpenSim.Region.Framework.Scenes | |||
4345 | } | 4377 | } |
4346 | } | 4378 | } |
4347 | 4379 | ||
4348 | public void UpdatePrimFlags(bool UsePhysics, bool IsTemporary, bool IsPhantom, bool IsVD) | 4380 | /// <summary> |
4381 | /// Update the flags on this prim. This covers properties such as phantom, physics and temporary. | ||
4382 | /// </summary> | ||
4383 | /// <param name="UsePhysics"></param> | ||
4384 | /// <param name="SetTemporary"></param> | ||
4385 | /// <param name="SetPhantom"></param> | ||
4386 | /// <param name="SetVD"></param> | ||
4387 | public void UpdatePrimFlags(bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVD) | ||
4349 | { | 4388 | { |
4350 | bool wasUsingPhysics = ((Flags & PrimFlags.Physics) != 0); | 4389 | bool wasUsingPhysics = ((Flags & PrimFlags.Physics) != 0); |
4351 | bool wasTemporary = ((Flags & PrimFlags.TemporaryOnRez) != 0); | 4390 | bool wasTemporary = ((Flags & PrimFlags.TemporaryOnRez) != 0); |
4352 | bool wasPhantom = ((Flags & PrimFlags.Phantom) != 0); | 4391 | bool wasPhantom = ((Flags & PrimFlags.Phantom) != 0); |
4353 | bool wasVD = VolumeDetectActive; | 4392 | bool wasVD = VolumeDetectActive; |
4354 | 4393 | ||
4355 | if ((UsePhysics == wasUsingPhysics) && (wasTemporary == IsTemporary) && (wasPhantom == IsPhantom) && (IsVD==wasVD)) | 4394 | if ((UsePhysics == wasUsingPhysics) && (wasTemporary == SetTemporary) && (wasPhantom == SetPhantom) && (SetVD == wasVD)) |
4356 | { | 4395 | { |
4357 | return; | 4396 | return; |
4358 | } | 4397 | } |
@@ -4362,32 +4401,31 @@ namespace OpenSim.Region.Framework.Scenes | |||
4362 | // that... | 4401 | // that... |
4363 | // ... if VD is changed, all others are not. | 4402 | // ... if VD is changed, all others are not. |
4364 | // ... if one of the others is changed, VD is not. | 4403 | // ... if one of the others is changed, VD is not. |
4365 | if (IsVD) // VD is active, special logic applies | 4404 | if (SetVD) // VD is active, special logic applies |
4366 | { | 4405 | { |
4367 | // State machine logic for VolumeDetect | 4406 | // State machine logic for VolumeDetect |
4368 | // More logic below | 4407 | // More logic below |
4369 | bool phanReset = (IsPhantom != wasPhantom) && !IsPhantom; | 4408 | bool phanReset = (SetPhantom != wasPhantom) && !SetPhantom; |
4370 | 4409 | ||
4371 | if (phanReset) // Phantom changes from on to off switch VD off too | 4410 | if (phanReset) // Phantom changes from on to off switch VD off too |
4372 | { | 4411 | { |
4373 | IsVD = false; // Switch it of for the course of this routine | 4412 | SetVD = false; // Switch it of for the course of this routine |
4374 | VolumeDetectActive = false; // and also permanently | 4413 | VolumeDetectActive = false; // and also permanently |
4375 | if (PhysActor != null) | 4414 | if (PhysActor != null) |
4376 | PhysActor.SetVolumeDetect(0); // Let physics know about it too | 4415 | PhysActor.SetVolumeDetect(0); // Let physics know about it too |
4377 | } | 4416 | } |
4378 | else | 4417 | else |
4379 | { | 4418 | { |
4380 | IsPhantom = false; | ||
4381 | // If volumedetect is active we don't want phantom to be applied. | 4419 | // If volumedetect is active we don't want phantom to be applied. |
4382 | // If this is a new call to VD out of the state "phantom" | 4420 | // If this is a new call to VD out of the state "phantom" |
4383 | // this will also cause the prim to be visible to physics | 4421 | // this will also cause the prim to be visible to physics |
4422 | SetPhantom = false; | ||
4384 | } | 4423 | } |
4385 | |||
4386 | } | 4424 | } |
4387 | 4425 | ||
4388 | if (UsePhysics && IsJoint()) | 4426 | if (UsePhysics && IsJoint()) |
4389 | { | 4427 | { |
4390 | IsPhantom = true; | 4428 | SetPhantom = true; |
4391 | } | 4429 | } |
4392 | 4430 | ||
4393 | if (UsePhysics) | 4431 | if (UsePhysics) |
@@ -4396,14 +4434,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
4396 | if (!wasUsingPhysics) | 4434 | if (!wasUsingPhysics) |
4397 | { | 4435 | { |
4398 | DoPhysicsPropertyUpdate(UsePhysics, false); | 4436 | DoPhysicsPropertyUpdate(UsePhysics, false); |
4399 | if (m_parentGroup != null) | 4437 | |
4438 | if (!m_parentGroup.IsDeleted) | ||
4400 | { | 4439 | { |
4401 | if (!m_parentGroup.IsDeleted) | 4440 | if (LocalId == m_parentGroup.RootPart.LocalId) |
4402 | { | 4441 | { |
4403 | if (LocalId == m_parentGroup.RootPart.LocalId) | 4442 | m_parentGroup.CheckSculptAndLoad(); |
4404 | { | ||
4405 | m_parentGroup.CheckSculptAndLoad(); | ||
4406 | } | ||
4407 | } | 4443 | } |
4408 | } | 4444 | } |
4409 | } | 4445 | } |
@@ -4417,8 +4453,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
4417 | } | 4453 | } |
4418 | } | 4454 | } |
4419 | 4455 | ||
4420 | 4456 | if (SetPhantom | |
4421 | if (IsPhantom || IsAttachment || (Shape.PathCurve == (byte)Extrusion.Flexible)) // note: this may have been changed above in the case of joints | 4457 | || ParentGroup.IsAttachment |
4458 | || (Shape.PathCurve == (byte)Extrusion.Flexible)) // note: this may have been changed above in the case of joints | ||
4422 | { | 4459 | { |
4423 | AddFlag(PrimFlags.Phantom); | 4460 | AddFlag(PrimFlags.Phantom); |
4424 | if (PhysActor != null) | 4461 | if (PhysActor != null) |
@@ -4432,7 +4469,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
4432 | { | 4469 | { |
4433 | RemFlag(PrimFlags.Phantom); | 4470 | RemFlag(PrimFlags.Phantom); |
4434 | 4471 | ||
4472 | if (ParentGroup.Scene == null) | ||
4473 | return; | ||
4474 | |||
4435 | PhysicsActor pa = PhysActor; | 4475 | PhysicsActor pa = PhysActor; |
4476 | |||
4436 | if (pa == null) | 4477 | if (pa == null) |
4437 | { | 4478 | { |
4438 | // It's not phantom anymore. So make sure the physics engine get's knowledge of it | 4479 | // It's not phantom anymore. So make sure the physics engine get's knowledge of it |
@@ -4444,22 +4485,21 @@ namespace OpenSim.Region.Framework.Scenes | |||
4444 | RotationOffset, | 4485 | RotationOffset, |
4445 | UsePhysics, | 4486 | UsePhysics, |
4446 | m_localId); | 4487 | m_localId); |
4447 | PhysActor.SetMaterial(Material); | ||
4448 | 4488 | ||
4449 | pa = PhysActor; | 4489 | pa = PhysActor; |
4450 | if (pa != null) | 4490 | if (pa != null) |
4451 | { | 4491 | { |
4492 | PhysActor.SetMaterial(Material); | ||
4452 | DoPhysicsPropertyUpdate(UsePhysics, true); | 4493 | DoPhysicsPropertyUpdate(UsePhysics, true); |
4453 | if (m_parentGroup != null) | 4494 | |
4495 | if (!m_parentGroup.IsDeleted) | ||
4454 | { | 4496 | { |
4455 | if (!m_parentGroup.IsDeleted) | 4497 | if (LocalId == m_parentGroup.RootPart.LocalId) |
4456 | { | 4498 | { |
4457 | if (LocalId == m_parentGroup.RootPart.LocalId) | 4499 | m_parentGroup.CheckSculptAndLoad(); |
4458 | { | ||
4459 | m_parentGroup.CheckSculptAndLoad(); | ||
4460 | } | ||
4461 | } | 4500 | } |
4462 | } | 4501 | } |
4502 | |||
4463 | if ( | 4503 | if ( |
4464 | ((AggregateScriptEvents & scriptEvents.collision) != 0) || | 4504 | ((AggregateScriptEvents & scriptEvents.collision) != 0) || |
4465 | ((AggregateScriptEvents & scriptEvents.collision_end) != 0) || | 4505 | ((AggregateScriptEvents & scriptEvents.collision_end) != 0) || |
@@ -4470,8 +4510,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
4470 | (CollisionSound != UUID.Zero) | 4510 | (CollisionSound != UUID.Zero) |
4471 | ) | 4511 | ) |
4472 | { | 4512 | { |
4473 | PhysActor.OnCollisionUpdate += PhysicsCollision; | 4513 | PhysActor.OnCollisionUpdate += PhysicsCollision; |
4474 | PhysActor.SubscribeEvents(1000); | 4514 | PhysActor.SubscribeEvents(1000); |
4475 | } | 4515 | } |
4476 | } | 4516 | } |
4477 | } | 4517 | } |
@@ -4480,20 +4520,18 @@ namespace OpenSim.Region.Framework.Scenes | |||
4480 | pa.IsPhysical = UsePhysics; | 4520 | pa.IsPhysical = UsePhysics; |
4481 | 4521 | ||
4482 | DoPhysicsPropertyUpdate(UsePhysics, false); // Update physical status. If it's phantom this will remove the prim | 4522 | DoPhysicsPropertyUpdate(UsePhysics, false); // Update physical status. If it's phantom this will remove the prim |
4483 | if (m_parentGroup != null) | 4523 | |
4524 | if (!m_parentGroup.IsDeleted) | ||
4484 | { | 4525 | { |
4485 | if (!m_parentGroup.IsDeleted) | 4526 | if (LocalId == m_parentGroup.RootPart.LocalId) |
4486 | { | 4527 | { |
4487 | if (LocalId == m_parentGroup.RootPart.LocalId) | 4528 | m_parentGroup.CheckSculptAndLoad(); |
4488 | { | ||
4489 | m_parentGroup.CheckSculptAndLoad(); | ||
4490 | } | ||
4491 | } | 4529 | } |
4492 | } | 4530 | } |
4493 | } | 4531 | } |
4494 | } | 4532 | } |
4495 | 4533 | ||
4496 | if (IsVD) | 4534 | if (SetVD) |
4497 | { | 4535 | { |
4498 | // If the above logic worked (this is urgent candidate to unit tests!) | 4536 | // If the above logic worked (this is urgent candidate to unit tests!) |
4499 | // we now have a physicsactor. | 4537 | // we now have a physicsactor. |
@@ -4508,18 +4546,19 @@ namespace OpenSim.Region.Framework.Scenes | |||
4508 | } | 4546 | } |
4509 | } | 4547 | } |
4510 | else | 4548 | else |
4511 | { // Remove VolumeDetect in any case. Note, it's safe to call SetVolumeDetect as often as you like | 4549 | { |
4550 | // Remove VolumeDetect in any case. Note, it's safe to call SetVolumeDetect as often as you like | ||
4512 | // (mumbles, well, at least if you have infinte CPU powers :-)) | 4551 | // (mumbles, well, at least if you have infinte CPU powers :-)) |
4513 | PhysicsActor pa = this.PhysActor; | 4552 | PhysicsActor pa = this.PhysActor; |
4514 | if (pa != null) | 4553 | if (pa != null) |
4515 | { | 4554 | { |
4516 | PhysActor.SetVolumeDetect(0); | 4555 | PhysActor.SetVolumeDetect(0); |
4517 | } | 4556 | } |
4557 | |||
4518 | this.VolumeDetectActive = false; | 4558 | this.VolumeDetectActive = false; |
4519 | } | 4559 | } |
4520 | 4560 | ||
4521 | 4561 | if (SetTemporary) | |
4522 | if (IsTemporary) | ||
4523 | { | 4562 | { |
4524 | AddFlag(PrimFlags.TemporaryOnRez); | 4563 | AddFlag(PrimFlags.TemporaryOnRez); |
4525 | } | 4564 | } |
@@ -4529,8 +4568,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
4529 | } | 4568 | } |
4530 | // m_log.Debug("Update: PHY:" + UsePhysics.ToString() + ", T:" + IsTemporary.ToString() + ", PHA:" + IsPhantom.ToString() + " S:" + CastsShadows.ToString()); | 4569 | // m_log.Debug("Update: PHY:" + UsePhysics.ToString() + ", T:" + IsTemporary.ToString() + ", PHA:" + IsPhantom.ToString() + " S:" + CastsShadows.ToString()); |
4531 | 4570 | ||
4532 | ParentGroup.HasGroupChanged = true; | 4571 | if (ParentGroup != null) |
4533 | ScheduleFullUpdate(); | 4572 | { |
4573 | ParentGroup.HasGroupChanged = true; | ||
4574 | ScheduleFullUpdate(); | ||
4575 | } | ||
4576 | |||
4577 | // m_log.DebugFormat("[SCENE OBJECT PART]: Updated PrimFlags on {0} {1} to {2}", Name, LocalId, Flags); | ||
4534 | } | 4578 | } |
4535 | 4579 | ||
4536 | public void UpdateRotation(Quaternion rot) | 4580 | public void UpdateRotation(Quaternion rot) |
@@ -4541,8 +4585,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
4541 | (rot.W != RotationOffset.W)) | 4585 | (rot.W != RotationOffset.W)) |
4542 | { | 4586 | { |
4543 | RotationOffset = rot; | 4587 | RotationOffset = rot; |
4544 | ParentGroup.HasGroupChanged = true; | 4588 | |
4545 | ScheduleTerseUpdate(); | 4589 | if (ParentGroup != null) |
4590 | { | ||
4591 | ParentGroup.HasGroupChanged = true; | ||
4592 | ScheduleTerseUpdate(); | ||
4593 | } | ||
4546 | } | 4594 | } |
4547 | } | 4595 | } |
4548 | 4596 | ||
@@ -4570,6 +4618,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
4570 | m_shape.PathTaperY = shapeBlock.PathTaperY; | 4618 | m_shape.PathTaperY = shapeBlock.PathTaperY; |
4571 | m_shape.PathTwist = shapeBlock.PathTwist; | 4619 | m_shape.PathTwist = shapeBlock.PathTwist; |
4572 | m_shape.PathTwistBegin = shapeBlock.PathTwistBegin; | 4620 | m_shape.PathTwistBegin = shapeBlock.PathTwistBegin; |
4621 | |||
4573 | if (PhysActor != null) | 4622 | if (PhysActor != null) |
4574 | { | 4623 | { |
4575 | PhysActor.Shape = m_shape; | 4624 | PhysActor.Shape = m_shape; |
@@ -4591,11 +4640,46 @@ namespace OpenSim.Region.Framework.Scenes | |||
4591 | } | 4640 | } |
4592 | 4641 | ||
4593 | /// <summary> | 4642 | /// <summary> |
4643 | /// If the part is a sculpt/mesh, retrieve the mesh data and reinsert it into the shape so that the physics | ||
4644 | /// engine can use it. | ||
4645 | /// </summary> | ||
4646 | /// <remarks> | ||
4647 | /// When the physics engine has finished with it, the sculpt data is discarded to save memory. | ||
4648 | /// </remarks> | ||
4649 | public void CheckSculptAndLoad() | ||
4650 | { | ||
4651 | // m_log.DebugFormat("Processing CheckSculptAndLoad for {0} {1}", Name, LocalId); | ||
4652 | |||
4653 | if (ParentGroup.IsDeleted) | ||
4654 | return; | ||
4655 | |||
4656 | if ((ParentGroup.RootPart.GetEffectiveObjectFlags() & (uint)PrimFlags.Phantom) != 0) | ||
4657 | return; | ||
4658 | |||
4659 | if (Shape.SculptEntry && Shape.SculptTexture != UUID.Zero) | ||
4660 | { | ||
4661 | // check if a previously decoded sculpt map has been cached | ||
4662 | // We don't read the file here - the meshmerizer will do that later. | ||
4663 | // TODO: Could we simplify the meshmerizer code by reading and setting the data here? | ||
4664 | if (File.Exists(System.IO.Path.Combine("j2kDecodeCache", "smap_" + Shape.SculptTexture.ToString()))) | ||
4665 | { | ||
4666 | SculptTextureCallback(null); | ||
4667 | } | ||
4668 | else | ||
4669 | { | ||
4670 | ParentGroup.Scene.AssetService.Get(Shape.SculptTexture.ToString(), this, AssetReceived); | ||
4671 | } | ||
4672 | } | ||
4673 | } | ||
4674 | |||
4675 | /// <summary> | ||
4594 | /// Update the textures on the part. | 4676 | /// Update the textures on the part. |
4595 | /// </summary> | 4677 | /// </summary> |
4678 | /// <remarks> | ||
4596 | /// Added to handle bug in libsecondlife's TextureEntry.ToBytes() | 4679 | /// Added to handle bug in libsecondlife's TextureEntry.ToBytes() |
4597 | /// not handling RGBA properly. Cycles through, and "fixes" the color | 4680 | /// not handling RGBA properly. Cycles through, and "fixes" the color |
4598 | /// info | 4681 | /// info |
4682 | /// </remarks> | ||
4599 | /// <param name="tex"></param> | 4683 | /// <param name="tex"></param> |
4600 | public void UpdateTexture(Primitive.TextureEntry tex) | 4684 | public void UpdateTexture(Primitive.TextureEntry tex) |
4601 | { | 4685 | { |
@@ -4687,7 +4771,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
4687 | { | 4771 | { |
4688 | PhysActor.OnCollisionUpdate += PhysicsCollision; | 4772 | PhysActor.OnCollisionUpdate += PhysicsCollision; |
4689 | PhysActor.SubscribeEvents(1000); | 4773 | PhysActor.SubscribeEvents(1000); |
4690 | |||
4691 | } | 4774 | } |
4692 | } | 4775 | } |
4693 | else | 4776 | else |
@@ -4699,14 +4782,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
4699 | } | 4782 | } |
4700 | } | 4783 | } |
4701 | 4784 | ||
4702 | if (m_parentGroup == null) | ||
4703 | { | ||
4704 | // m_log.DebugFormat( | ||
4705 | // "[SCENE OBJECT PART]: Scheduling part {0} {1} for full update in aggregateScriptEvents() since m_parentGroup == null", Name, LocalId); | ||
4706 | ScheduleFullUpdate(); | ||
4707 | return; | ||
4708 | } | ||
4709 | |||
4710 | //if ((GetEffectiveObjectFlags() & (uint)PrimFlags.Scripted) != 0) | 4785 | //if ((GetEffectiveObjectFlags() & (uint)PrimFlags.Scripted) != 0) |
4711 | //{ | 4786 | //{ |
4712 | // m_parentGroup.Scene.EventManager.OnScriptTimerEvent += handleTimerAccounting; | 4787 | // m_parentGroup.Scene.EventManager.OnScriptTimerEvent += handleTimerAccounting; |
@@ -4716,7 +4791,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
4716 | // m_parentGroup.Scene.EventManager.OnScriptTimerEvent -= handleTimerAccounting; | 4791 | // m_parentGroup.Scene.EventManager.OnScriptTimerEvent -= handleTimerAccounting; |
4717 | //} | 4792 | //} |
4718 | 4793 | ||
4719 | LocalFlags=(PrimFlags)objectflagupdate; | 4794 | LocalFlags = (PrimFlags)objectflagupdate; |
4720 | 4795 | ||
4721 | if (m_parentGroup != null && m_parentGroup.RootPart == this) | 4796 | if (m_parentGroup != null && m_parentGroup.RootPart == this) |
4722 | { | 4797 | { |
@@ -4730,40 +4805,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
4730 | } | 4805 | } |
4731 | } | 4806 | } |
4732 | 4807 | ||
4733 | public int registerTargetWaypoint(Vector3 target, float tolerance) | ||
4734 | { | ||
4735 | if (m_parentGroup != null) | ||
4736 | { | ||
4737 | return m_parentGroup.registerTargetWaypoint(target, tolerance); | ||
4738 | } | ||
4739 | return 0; | ||
4740 | } | ||
4741 | |||
4742 | public void unregisterTargetWaypoint(int handle) | ||
4743 | { | ||
4744 | if (m_parentGroup != null) | ||
4745 | { | ||
4746 | m_parentGroup.unregisterTargetWaypoint(handle); | ||
4747 | } | ||
4748 | } | ||
4749 | |||
4750 | public int registerRotTargetWaypoint(Quaternion target, float tolerance) | ||
4751 | { | ||
4752 | if (m_parentGroup != null) | ||
4753 | { | ||
4754 | return m_parentGroup.registerRotTargetWaypoint(target, tolerance); | ||
4755 | } | ||
4756 | return 0; | ||
4757 | } | ||
4758 | |||
4759 | public void unregisterRotTargetWaypoint(int handle) | ||
4760 | { | ||
4761 | if (m_parentGroup != null) | ||
4762 | { | ||
4763 | m_parentGroup.unregisterRotTargetWaypoint(handle); | ||
4764 | } | ||
4765 | } | ||
4766 | |||
4767 | public void SetCameraAtOffset(Vector3 v) | 4808 | public void SetCameraAtOffset(Vector3 v) |
4768 | { | 4809 | { |
4769 | m_cameraAtOffset = v; | 4810 | m_cameraAtOffset = v; |
@@ -4803,10 +4844,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
4803 | 4844 | ||
4804 | public void SendTerseUpdateToClient(IClientAPI remoteClient) | 4845 | public void SendTerseUpdateToClient(IClientAPI remoteClient) |
4805 | { | 4846 | { |
4806 | if (ParentGroup == null || ParentGroup.IsDeleted) | 4847 | if (ParentGroup.IsDeleted) |
4807 | return; | 4848 | return; |
4808 | 4849 | ||
4809 | if (IsAttachment && ParentGroup.RootPart != this) | 4850 | if (ParentGroup.IsAttachment && ParentGroup.RootPart != this) |
4810 | return; | 4851 | return; |
4811 | 4852 | ||
4812 | // Causes this thread to dig into the Client Thread Data. | 4853 | // Causes this thread to dig into the Client Thread Data. |
@@ -4827,6 +4868,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
4827 | 4868 | ||
4828 | Inventory.ApplyNextOwnerPermissions(); | 4869 | Inventory.ApplyNextOwnerPermissions(); |
4829 | } | 4870 | } |
4871 | |||
4830 | public void UpdateLookAt() | 4872 | public void UpdateLookAt() |
4831 | { | 4873 | { |
4832 | try | 4874 | try |
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs index 56680df..1f0840d 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs | |||
@@ -118,14 +118,17 @@ namespace OpenSim.Region.Framework.Scenes | |||
118 | } | 118 | } |
119 | 119 | ||
120 | /// <summary> | 120 | /// <summary> |
121 | /// Reset UUIDs for all the items in the prim's inventory. This involves either generating | 121 | /// Reset UUIDs for all the items in the prim's inventory. |
122 | /// </summary> | ||
123 | /// <remarks> | ||
124 | /// This involves either generating | ||
122 | /// new ones or setting existing UUIDs to the correct parent UUIDs. | 125 | /// new ones or setting existing UUIDs to the correct parent UUIDs. |
123 | /// | 126 | /// |
124 | /// If this method is called and there are inventory items, then we regard the inventory as having changed. | 127 | /// If this method is called and there are inventory items, then we regard the inventory as having changed. |
125 | /// </summary> | 128 | /// </remarks> |
126 | /// <param name="linkNum">Link number for the part</param> | ||
127 | public void ResetInventoryIDs() | 129 | public void ResetInventoryIDs() |
128 | { | 130 | { |
131 | if (null == m_part) | ||
129 | m_items.LockItemsForWrite(true); | 132 | m_items.LockItemsForWrite(true); |
130 | 133 | ||
131 | if (Items.Count == 0) | 134 | if (Items.Count == 0) |
@@ -212,7 +215,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
212 | // Don't let this set the HasGroupChanged flag for attachments | 215 | // Don't let this set the HasGroupChanged flag for attachments |
213 | // as this happens during rez and we don't want a new asset | 216 | // as this happens during rez and we don't want a new asset |
214 | // for each attachment each time | 217 | // for each attachment each time |
215 | if (!m_part.ParentGroup.RootPart.IsAttachment) | 218 | if (!m_part.ParentGroup.IsAttachment) |
216 | { | 219 | { |
217 | HasInventoryChanged = true; | 220 | HasInventoryChanged = true; |
218 | m_part.ParentGroup.HasGroupChanged = true; | 221 | m_part.ParentGroup.HasGroupChanged = true; |
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index d2f84e3..de9b1f3 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs | |||
@@ -67,7 +67,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
67 | 67 | ||
68 | public delegate void SendCourseLocationsMethod(UUID scene, ScenePresence presence, List<Vector3> coarseLocations, List<UUID> avatarUUIDs); | 68 | public delegate void SendCourseLocationsMethod(UUID scene, ScenePresence presence, List<Vector3> coarseLocations, List<UUID> avatarUUIDs); |
69 | 69 | ||
70 | public class ScenePresence : EntityBase, ISceneEntity | 70 | public class ScenePresence : EntityBase, IScenePresence |
71 | { | 71 | { |
72 | // ~ScenePresence() | 72 | // ~ScenePresence() |
73 | // { | 73 | // { |
@@ -76,6 +76,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
76 | 76 | ||
77 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 77 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
78 | 78 | ||
79 | public PresenceType PresenceType { get; private set; } | ||
80 | |||
79 | // private static readonly byte[] DEFAULT_TEXTURE = AvatarAppearance.GetDefaultTexture().GetBytes(); | 81 | // private static readonly byte[] DEFAULT_TEXTURE = AvatarAppearance.GetDefaultTexture().GetBytes(); |
80 | private static readonly Array DIR_CONTROL_FLAGS = Enum.GetValues(typeof(Dir_ControlFlags)); | 82 | private static readonly Array DIR_CONTROL_FLAGS = Enum.GetValues(typeof(Dir_ControlFlags)); |
81 | private static readonly Vector3 HEAD_ADJUSTMENT = new Vector3(0f, 0f, 0.3f); | 83 | private static readonly Vector3 HEAD_ADJUSTMENT = new Vector3(0f, 0f, 0.3f); |
@@ -92,6 +94,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
92 | // Value revised by KF 091121 by comparison with SL. | 94 | // Value revised by KF 091121 by comparison with SL. |
93 | private static readonly Vector3 SIT_TARGET_ADJUSTMENT = new Vector3(0.0f, 0.0f, 0.418f); | 95 | private static readonly Vector3 SIT_TARGET_ADJUSTMENT = new Vector3(0.0f, 0.0f, 0.418f); |
94 | 96 | ||
97 | /// <summary> | ||
98 | /// Movement updates for agents in neighboring regions are sent directly to clients. | ||
99 | /// This value only affects how often agent positions are sent to neighbor regions | ||
100 | /// for things such as distance-based update prioritization | ||
101 | /// </summary> | ||
102 | public static readonly float SIGNIFICANT_MOVEMENT = 2.0f; | ||
103 | |||
95 | public UUID currentParcelUUID = UUID.Zero; | 104 | public UUID currentParcelUUID = UUID.Zero; |
96 | 105 | ||
97 | private ISceneViewer m_sceneViewer; | 106 | private ISceneViewer m_sceneViewer; |
@@ -105,14 +114,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
105 | } | 114 | } |
106 | protected ScenePresenceAnimator m_animator; | 115 | protected ScenePresenceAnimator m_animator; |
107 | 116 | ||
108 | /// <value> | 117 | /// <summary> |
109 | /// The scene objects attached to this avatar. Do not change this list directly - use methods such as | 118 | /// Attachments recorded on this avatar. |
110 | /// AddAttachment() and RemoveAttachment(). Lock this list when performing any read operations upon it. | 119 | /// </summary> |
111 | /// </value> | 120 | /// <remarks> |
112 | public List<SceneObjectGroup> Attachments | 121 | /// TODO: For some reason, we effectively have a list both here and in Appearance. Need to work out if this is |
113 | { | 122 | /// necessary. |
114 | get { return m_attachments; } | 123 | /// </remarks> |
115 | } | ||
116 | 124 | ||
117 | protected List<SceneObjectGroup> m_attachments = new List<SceneObjectGroup>(); | 125 | protected List<SceneObjectGroup> m_attachments = new List<SceneObjectGroup>(); |
118 | 126 | ||
@@ -120,7 +128,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
120 | private ScriptControlled IgnoredControls = ScriptControlled.CONTROL_ZERO; | 128 | private ScriptControlled IgnoredControls = ScriptControlled.CONTROL_ZERO; |
121 | private ScriptControlled LastCommands = ScriptControlled.CONTROL_ZERO; | 129 | private ScriptControlled LastCommands = ScriptControlled.CONTROL_ZERO; |
122 | private bool MouseDown = false; | 130 | private bool MouseDown = false; |
123 | private SceneObjectGroup proxyObjectGroup; | 131 | // private SceneObjectGroup proxyObjectGroup; |
124 | //private SceneObjectPart proxyObjectPart = null; | 132 | //private SceneObjectPart proxyObjectPart = null; |
125 | public Vector3 lastKnownAllowedPosition; | 133 | public Vector3 lastKnownAllowedPosition; |
126 | public Vector4 CollisionPlane = Vector4.UnitW; | 134 | public Vector4 CollisionPlane = Vector4.UnitW; |
@@ -178,7 +186,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
178 | 186 | ||
179 | private float m_speedModifier = 1.0f; | 187 | private float m_speedModifier = 1.0f; |
180 | 188 | ||
181 | private Quaternion m_bodyRot= Quaternion.Identity; | 189 | private Quaternion m_bodyRot = Quaternion.Identity; |
182 | 190 | ||
183 | private Quaternion m_bodyRotPrevious = Quaternion.Identity; | 191 | private Quaternion m_bodyRotPrevious = Quaternion.Identity; |
184 | 192 | ||
@@ -224,8 +232,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
224 | private string m_nextSitAnimation = String.Empty; | 232 | private string m_nextSitAnimation = String.Empty; |
225 | 233 | ||
226 | //PauPaw:Proper PID Controler for autopilot************ | 234 | //PauPaw:Proper PID Controler for autopilot************ |
227 | private bool m_moveToPositionInProgress; | 235 | public bool MovingToTarget { get; private set; } |
228 | private Vector3 m_moveToPositionTarget; | 236 | public Vector3 MoveToPositionTarget { get; private set; } |
229 | private Quaternion m_offsetRotation = new Quaternion(0.0f, 0.0f, 0.0f, 1.0f); | 237 | private Quaternion m_offsetRotation = new Quaternion(0.0f, 0.0f, 0.0f, 1.0f); |
230 | 238 | ||
231 | private bool m_followCamAuto; | 239 | private bool m_followCamAuto; |
@@ -455,9 +463,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
455 | 463 | ||
456 | protected PhysicsActor m_physicsActor; | 464 | protected PhysicsActor m_physicsActor; |
457 | 465 | ||
458 | /// <value> | ||
459 | /// The client controlling this presence | ||
460 | /// </value> | ||
461 | public IClientAPI ControllingClient | 466 | public IClientAPI ControllingClient |
462 | { | 467 | { |
463 | get { return m_controllingClient; } | 468 | get { return m_controllingClient; } |
@@ -765,15 +770,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
765 | 770 | ||
766 | #region Constructor(s) | 771 | #region Constructor(s) |
767 | 772 | ||
768 | public ScenePresence() | 773 | public ScenePresence( |
774 | IClientAPI client, Scene world, RegionInfo reginfo, AvatarAppearance appearance, PresenceType type) | ||
769 | { | 775 | { |
770 | m_sendCourseLocationsMethod = SendCoarseLocationsDefault; | 776 | m_sendCourseLocationsMethod = SendCoarseLocationsDefault; |
771 | CreateSceneViewer(); | 777 | m_sceneViewer = new SceneViewer(this); |
772 | m_animator = new ScenePresenceAnimator(this); | 778 | m_animator = new ScenePresenceAnimator(this); |
773 | } | 779 | PresenceType = type; |
774 | |||
775 | private ScenePresence(IClientAPI client, Scene world, RegionInfo reginfo) : this() | ||
776 | { | ||
777 | m_DrawDistance = world.DefaultDrawDistance; | 780 | m_DrawDistance = world.DefaultDrawDistance; |
778 | m_rootRegionHandle = reginfo.RegionHandle; | 781 | m_rootRegionHandle = reginfo.RegionHandle; |
779 | m_controllingClient = client; | 782 | m_controllingClient = client; |
@@ -817,19 +820,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
817 | 820 | ||
818 | RegisterToEvents(); | 821 | RegisterToEvents(); |
819 | SetDirectionVectors(); | 822 | SetDirectionVectors(); |
820 | } | ||
821 | 823 | ||
822 | public ScenePresence(IClientAPI client, Scene world, RegionInfo reginfo, AvatarAppearance appearance) | ||
823 | : this(client, world, reginfo) | ||
824 | { | ||
825 | m_appearance = appearance; | 824 | m_appearance = appearance; |
826 | } | 825 | } |
827 | 826 | ||
828 | private void CreateSceneViewer() | ||
829 | { | ||
830 | m_sceneViewer = new SceneViewer(this); | ||
831 | } | ||
832 | |||
833 | public void RegisterToEvents() | 827 | public void RegisterToEvents() |
834 | { | 828 | { |
835 | m_controllingClient.OnCompleteMovementToRegion += CompleteMovement; | 829 | m_controllingClient.OnCompleteMovementToRegion += CompleteMovement; |
@@ -841,8 +835,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
841 | m_controllingClient.OnStartAnim += HandleStartAnim; | 835 | m_controllingClient.OnStartAnim += HandleStartAnim; |
842 | m_controllingClient.OnStopAnim += HandleStopAnim; | 836 | m_controllingClient.OnStopAnim += HandleStopAnim; |
843 | m_controllingClient.OnForceReleaseControls += HandleForceReleaseControls; | 837 | m_controllingClient.OnForceReleaseControls += HandleForceReleaseControls; |
844 | m_controllingClient.OnAutoPilotGo += DoAutoPilot; | 838 | m_controllingClient.OnAutoPilotGo += MoveToTarget; |
845 | m_controllingClient.AddGenericPacketHandler("autopilot", DoMoveToPosition); | ||
846 | 839 | ||
847 | // ControllingClient.OnChildAgentStatus += new StatusChange(this.ChildStatusChange); | 840 | // ControllingClient.OnChildAgentStatus += new StatusChange(this.ChildStatusChange); |
848 | // ControllingClient.OnStopMovement += new GenericCall2(this.StopMovement); | 841 | // ControllingClient.OnStopMovement += new GenericCall2(this.StopMovement); |
@@ -1029,11 +1022,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
1029 | } | 1022 | } |
1030 | 1023 | ||
1031 | float localAVHeight = 1.56f; | 1024 | float localAVHeight = 1.56f; |
1032 | if (m_appearance != null) | 1025 | if (m_appearance.AvatarHeight > 0) |
1033 | { | 1026 | localAVHeight = m_appearance.AvatarHeight; |
1034 | if (m_appearance.AvatarHeight > 0) | ||
1035 | localAVHeight = m_appearance.AvatarHeight; | ||
1036 | } | ||
1037 | 1027 | ||
1038 | float posZLimit = 0; | 1028 | float posZLimit = 0; |
1039 | 1029 | ||
@@ -1047,26 +1037,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
1047 | } | 1037 | } |
1048 | AbsolutePosition = pos; | 1038 | AbsolutePosition = pos; |
1049 | 1039 | ||
1050 | if (m_appearance != null) | ||
1051 | { | ||
1052 | if (m_appearance.AvatarHeight > 0) | ||
1053 | SetHeight(m_appearance.AvatarHeight); | ||
1054 | } | ||
1055 | else | ||
1056 | { | ||
1057 | m_log.ErrorFormat("[SCENE PRESENCE]: null appearance in MakeRoot in {0}", Scene.RegionInfo.RegionName); | ||
1058 | // emergency; this really shouldn't happen | ||
1059 | m_appearance = new AvatarAppearance(UUID); | ||
1060 | } | ||
1061 | |||
1062 | AddToPhysicalScene(isFlying); | 1040 | AddToPhysicalScene(isFlying); |
1063 | 1041 | ||
1064 | if (m_appearance != null) | ||
1065 | { | ||
1066 | if (m_appearance.AvatarHeight > 0) | ||
1067 | SetHeight(m_appearance.AvatarHeight); | ||
1068 | } | ||
1069 | |||
1070 | if (m_forceFly) | 1042 | if (m_forceFly) |
1071 | { | 1043 | { |
1072 | m_physicsActor.Flying = true; | 1044 | m_physicsActor.Flying = true; |
@@ -1087,15 +1059,18 @@ namespace OpenSim.Region.Framework.Scenes | |||
1087 | // and it has already rezzed the attachments and started their scripts. | 1059 | // and it has already rezzed the attachments and started their scripts. |
1088 | // We do the following only for non-login agents, because their scripts | 1060 | // We do the following only for non-login agents, because their scripts |
1089 | // haven't started yet. | 1061 | // haven't started yet. |
1090 | if (wasChild && Attachments != null && Attachments.Count > 0) | 1062 | lock (m_attachments) |
1091 | { | 1063 | { |
1092 | m_log.DebugFormat("[SCENE PRESENCE]: Restarting scripts in attachments..."); | 1064 | if (wasChild && HasAttachments()) |
1093 | // Resume scripts | ||
1094 | Attachments.ForEach(delegate(SceneObjectGroup sog) | ||
1095 | { | 1065 | { |
1096 | sog.RootPart.ParentGroup.CreateScriptInstances(0, false, m_scene.DefaultScriptEngine, GetStateSource()); | 1066 | m_log.DebugFormat("[SCENE PRESENCE]: Restarting scripts in attachments..."); |
1097 | sog.ResumeScripts(); | 1067 | // Resume scripts |
1098 | }); | 1068 | foreach (SceneObjectGroup sog in m_attachments) |
1069 | { | ||
1070 | sog.RootPart.ParentGroup.CreateScriptInstances(0, false, m_scene.DefaultScriptEngine, GetStateSource()); | ||
1071 | sog.ResumeScripts(); | ||
1072 | } | ||
1073 | } | ||
1099 | } | 1074 | } |
1100 | 1075 | ||
1101 | // send the animations of the other presences to me | 1076 | // send the animations of the other presences to me |
@@ -1105,6 +1080,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
1105 | presence.Animator.SendAnimPackToClient(ControllingClient); | 1080 | presence.Animator.SendAnimPackToClient(ControllingClient); |
1106 | }); | 1081 | }); |
1107 | 1082 | ||
1083 | // If we don't reset the movement flag here, an avatar that crosses to a neighbouring sim and returns will | ||
1084 | // stall on the border crossing since the existing child agent will still have the last movement | ||
1085 | // recorded, which stops the input from being processed. | ||
1086 | m_movementflag = 0; | ||
1087 | |||
1108 | m_scene.EventManager.TriggerOnMakeRootAgent(this); | 1088 | m_scene.EventManager.TriggerOnMakeRootAgent(this); |
1109 | } | 1089 | } |
1110 | 1090 | ||
@@ -1196,11 +1176,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
1196 | CheckLandingPoint(ref pos); | 1176 | CheckLandingPoint(ref pos); |
1197 | AbsolutePosition = pos; | 1177 | AbsolutePosition = pos; |
1198 | AddToPhysicalScene(isFlying); | 1178 | AddToPhysicalScene(isFlying); |
1199 | if (m_appearance != null) | ||
1200 | { | ||
1201 | if (m_appearance.AvatarHeight > 0) | ||
1202 | SetHeight(m_appearance.AvatarHeight); | ||
1203 | } | ||
1204 | 1179 | ||
1205 | SendTerseUpdateToAllClients(); | 1180 | SendTerseUpdateToAllClients(); |
1206 | 1181 | ||
@@ -1216,22 +1191,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
1216 | CheckLandingPoint(ref pos); | 1191 | CheckLandingPoint(ref pos); |
1217 | AbsolutePosition = pos; | 1192 | AbsolutePosition = pos; |
1218 | AddToPhysicalScene(isFlying); | 1193 | AddToPhysicalScene(isFlying); |
1219 | if (m_appearance != null) | ||
1220 | { | ||
1221 | if (m_appearance.AvatarHeight > 0) | ||
1222 | SetHeight(m_appearance.AvatarHeight); | ||
1223 | } | ||
1224 | 1194 | ||
1225 | SendTerseUpdateToAllClients(); | 1195 | SendTerseUpdateToAllClients(); |
1226 | } | 1196 | } |
1227 | 1197 | ||
1228 | /// <summary> | ||
1229 | /// | ||
1230 | /// </summary> | ||
1231 | public void StopMovement() | ||
1232 | { | ||
1233 | } | ||
1234 | |||
1235 | public void StopFlying() | 1198 | public void StopFlying() |
1236 | { | 1199 | { |
1237 | ControllingClient.StopFlying(this); | 1200 | ControllingClient.StopFlying(this); |
@@ -1281,7 +1244,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1281 | #region Event Handlers | 1244 | #region Event Handlers |
1282 | 1245 | ||
1283 | /// <summary> | 1246 | /// <summary> |
1284 | /// Sets avatar height in the phyiscs plugin | 1247 | /// Sets avatar height in the physics plugin |
1285 | /// </summary> | 1248 | /// </summary> |
1286 | public void SetHeight(float height) | 1249 | public void SetHeight(float height) |
1287 | { | 1250 | { |
@@ -1294,10 +1257,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
1294 | 1257 | ||
1295 | /// <summary> | 1258 | /// <summary> |
1296 | /// Complete Avatar's movement into the region. | 1259 | /// Complete Avatar's movement into the region. |
1297 | /// This is called upon a very important packet sent from the client, | ||
1298 | /// so it's client-controlled. Never call this method directly. | ||
1299 | /// </summary> | 1260 | /// </summary> |
1300 | public void CompleteMovement(IClientAPI client) | 1261 | /// <param name="client"></param> |
1262 | /// <param name="openChildAgents"> | ||
1263 | /// If true, send notification to neighbour regions to expect | ||
1264 | /// a child agent from the client. These neighbours can be some distance away, depending right now on the | ||
1265 | /// configuration of DefaultDrawDistance in the [Startup] section of config | ||
1266 | /// </param> | ||
1267 | public void CompleteMovement(IClientAPI client, bool openChildAgents) | ||
1301 | { | 1268 | { |
1302 | // DateTime startTime = DateTime.Now; | 1269 | // DateTime startTime = DateTime.Now; |
1303 | 1270 | ||
@@ -1338,15 +1305,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
1338 | SendInitialData(); | 1305 | SendInitialData(); |
1339 | 1306 | ||
1340 | // Create child agents in neighbouring regions | 1307 | // Create child agents in neighbouring regions |
1341 | if (!m_isChildAgent) | 1308 | if (openChildAgents && !m_isChildAgent) |
1342 | { | 1309 | { |
1343 | IEntityTransferModule m_agentTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>(); | 1310 | IEntityTransferModule m_agentTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>(); |
1344 | if (m_agentTransfer != null) | 1311 | if (m_agentTransfer != null) |
1345 | m_agentTransfer.EnableChildAgents(this); | 1312 | m_agentTransfer.EnableChildAgents(this); |
1346 | else | ||
1347 | m_log.DebugFormat( | ||
1348 | "[SCENE PRESENCE]: Unable to create child agents in neighbours, because AgentTransferModule is not active for region {0}", | ||
1349 | m_scene.RegionInfo.RegionName); | ||
1350 | 1313 | ||
1351 | IFriendsModule friendsModule = m_scene.RequestModuleInterface<IFriendsModule>(); | 1314 | IFriendsModule friendsModule = m_scene.RequestModuleInterface<IFriendsModule>(); |
1352 | if (friendsModule != null) | 1315 | if (friendsModule != null) |
@@ -1403,6 +1366,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
1403 | /// </summary> | 1366 | /// </summary> |
1404 | public void HandleAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData) | 1367 | public void HandleAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData) |
1405 | { | 1368 | { |
1369 | // m_log.DebugFormat("[SCENE PRESENCE]: Received agent update from {0}", remoteClient.Name); | ||
1370 | |||
1406 | //if (m_isChildAgent) | 1371 | //if (m_isChildAgent) |
1407 | //{ | 1372 | //{ |
1408 | // // m_log.Debug("DEBUG: HandleAgentUpdate: child agent"); | 1373 | // // m_log.Debug("DEBUG: HandleAgentUpdate: child agent"); |
@@ -1445,7 +1410,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
1445 | #region Inputs | 1410 | #region Inputs |
1446 | 1411 | ||
1447 | AgentManager.ControlFlags flags = (AgentManager.ControlFlags)agentData.ControlFlags; | 1412 | AgentManager.ControlFlags flags = (AgentManager.ControlFlags)agentData.ControlFlags; |
1448 | Quaternion bodyRotation = agentData.BodyRotation; | ||
1449 | 1413 | ||
1450 | // Camera location in world. We'll need to raytrace | 1414 | // Camera location in world. We'll need to raytrace |
1451 | // from this location from time to time. | 1415 | // from this location from time to time. |
@@ -1530,23 +1494,29 @@ namespace OpenSim.Region.Framework.Scenes | |||
1530 | { | 1494 | { |
1531 | return; | 1495 | return; |
1532 | } | 1496 | } |
1533 | |||
1534 | bool update_movementflag = false; | ||
1535 | 1497 | ||
1536 | if (m_allowMovement && !SitGround) | 1498 | if (m_allowMovement && !SitGround) |
1537 | { | 1499 | { |
1500 | Quaternion bodyRotation = agentData.BodyRotation; | ||
1501 | bool update_rotation = false; | ||
1502 | |||
1503 | if (bodyRotation != m_bodyRot) | ||
1504 | { | ||
1505 | Rotation = bodyRotation; | ||
1506 | update_rotation = true; | ||
1507 | } | ||
1508 | |||
1509 | bool update_movementflag = false; | ||
1510 | |||
1538 | if (agentData.UseClientAgentPosition) | 1511 | if (agentData.UseClientAgentPosition) |
1539 | { | 1512 | { |
1540 | m_moveToPositionInProgress = (agentData.ClientAgentPosition - AbsolutePosition).Length() > 0.2f; | 1513 | MovingToTarget = (agentData.ClientAgentPosition - AbsolutePosition).Length() > 0.2f; |
1541 | m_moveToPositionTarget = agentData.ClientAgentPosition; | 1514 | MoveToPositionTarget = agentData.ClientAgentPosition; |
1542 | } | 1515 | } |
1543 | 1516 | ||
1544 | int i = 0; | 1517 | int i = 0; |
1545 | |||
1546 | bool update_rotation = false; | ||
1547 | bool DCFlagKeyPressed = false; | 1518 | bool DCFlagKeyPressed = false; |
1548 | Vector3 agent_control_v3 = Vector3.Zero; | 1519 | Vector3 agent_control_v3 = Vector3.Zero; |
1549 | Quaternion q = bodyRotation; | ||
1550 | 1520 | ||
1551 | bool oldflying = PhysicsActor.Flying; | 1521 | bool oldflying = PhysicsActor.Flying; |
1552 | 1522 | ||
@@ -1577,7 +1547,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
1577 | if (m_parentID == 0) | 1547 | if (m_parentID == 0) |
1578 | { | 1548 | { |
1579 | bool bAllowUpdateMoveToPosition = false; | 1549 | bool bAllowUpdateMoveToPosition = false; |
1580 | bool bResetMoveToPosition = false; | ||
1581 | 1550 | ||
1582 | Vector3[] dirVectors; | 1551 | Vector3[] dirVectors; |
1583 | 1552 | ||
@@ -1598,8 +1567,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
1598 | { | 1567 | { |
1599 | if (((uint)flags & (uint)DCF) != 0) | 1568 | if (((uint)flags & (uint)DCF) != 0) |
1600 | { | 1569 | { |
1601 | bResetMoveToPosition = true; | ||
1602 | DCFlagKeyPressed = true; | 1570 | DCFlagKeyPressed = true; |
1571 | |||
1603 | try | 1572 | try |
1604 | { | 1573 | { |
1605 | agent_control_v3 += dirVectors[i]; | 1574 | agent_control_v3 += dirVectors[i]; |
@@ -1615,6 +1584,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
1615 | 1584 | ||
1616 | if ((m_movementflag & (uint)DCF) == 0) | 1585 | if ((m_movementflag & (uint)DCF) == 0) |
1617 | { | 1586 | { |
1587 | |||
1588 | // m_log.DebugFormat("[SCENE PRESENCE]: Updating m_movementflag for {0} with {1}", Name, DCF); | ||
1618 | m_movementflag += (byte)(uint)DCF; | 1589 | m_movementflag += (byte)(uint)DCF; |
1619 | update_movementflag = true; | 1590 | update_movementflag = true; |
1620 | } | 1591 | } |
@@ -1631,10 +1602,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
1631 | bAllowUpdateMoveToPosition = true; | 1602 | bAllowUpdateMoveToPosition = true; |
1632 | } | 1603 | } |
1633 | } | 1604 | } |
1605 | |||
1634 | i++; | 1606 | i++; |
1635 | } | 1607 | } |
1636 | //Paupaw:Do Proper PID for Autopilot here | 1608 | if (MovingToTarget) |
1637 | if (bResetMoveToPosition) | ||
1638 | { | 1609 | { |
1639 | m_moveToPositionTarget = Vector3.Zero; | 1610 | m_moveToPositionTarget = Vector3.Zero; |
1640 | m_moveToPositionInProgress = false; | 1611 | m_moveToPositionInProgress = false; |
@@ -1680,12 +1651,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
1680 | // if (there) | 1651 | // if (there) |
1681 | if (Util.GetDistanceTo(abspos, tgt) <= 0.5f) | 1652 | if (Util.GetDistanceTo(abspos, tgt) <= 0.5f) |
1682 | { | 1653 | { |
1683 | // we are close enough to the target | 1654 | ResetMoveToTarget(); |
1684 | m_moveToPositionTarget = Vector3.Zero; | ||
1685 | m_moveToPositionInProgress = false; | ||
1686 | update_movementflag = true; | 1655 | update_movementflag = true; |
1687 | } | 1656 | } |
1688 | else | 1657 | else if (bAllowUpdateMoveToPosition) |
1689 | { | 1658 | { |
1690 | try | 1659 | try |
1691 | { | 1660 | { |
@@ -1790,14 +1759,26 @@ namespace OpenSim.Region.Framework.Scenes | |||
1790 | // which occurs later in the main scene loop | 1759 | // which occurs later in the main scene loop |
1791 | if (update_movementflag || (update_rotation && DCFlagKeyPressed)) | 1760 | if (update_movementflag || (update_rotation && DCFlagKeyPressed)) |
1792 | { | 1761 | { |
1793 | // m_log.DebugFormat("{0} {1}", update_movementflag, (update_rotation && DCFlagKeyPressed)); | 1762 | // m_log.DebugFormat( |
1794 | // m_log.DebugFormat( | 1763 | // "[SCENE PRESENCE]: In {0} adding velocity of {1} to {2}, umf = {3}, ur = {4}", |
1795 | // "In {0} adding velocity to {1} of {2}", m_scene.RegionInfo.RegionName, Name, agent_control_v3); | 1764 | // m_scene.RegionInfo.RegionName, agent_control_v3, Name, update_movementflag, update_rotation); |
1796 | 1765 | ||
1797 | AddNewMovement(agent_control_v3, q, Nudging); | 1766 | AddNewMovement(agent_control_v3, q, Nudging); |
1798 | 1767 | ||
1799 | 1768 | ||
1800 | } | 1769 | } |
1770 | // else | ||
1771 | // { | ||
1772 | // if (!update_movementflag) | ||
1773 | // { | ||
1774 | // m_log.DebugFormat( | ||
1775 | // "[SCENE PRESENCE]: In {0} ignoring requested update of {1} for {2} as update_movementflag = false", | ||
1776 | // m_scene.RegionInfo.RegionName, agent_control_v3, Name); | ||
1777 | // } | ||
1778 | // } | ||
1779 | |||
1780 | if (update_movementflag && m_parentID == 0) | ||
1781 | Animator.UpdateMovementAnimations(); | ||
1801 | } | 1782 | } |
1802 | 1783 | ||
1803 | if (update_movementflag && !SitGround) | 1784 | if (update_movementflag && !SitGround) |
@@ -1808,30 +1789,18 @@ namespace OpenSim.Region.Framework.Scenes | |||
1808 | m_scene.StatsReporter.AddAgentTime(Util.EnvironmentTickCountSubtract(m_perfMonMS)); | 1789 | m_scene.StatsReporter.AddAgentTime(Util.EnvironmentTickCountSubtract(m_perfMonMS)); |
1809 | } | 1790 | } |
1810 | 1791 | ||
1811 | public void DoAutoPilot(uint not_used, Vector3 Pos, IClientAPI remote_client) | 1792 | /// <summary> |
1793 | /// Calculate an update to move the presence to the set target. | ||
1794 | /// </summary> | ||
1795 | /// <remarks> | ||
1796 | /// This doesn't actually perform the movement. Instead, it adds its vector to agent_control_v3. | ||
1797 | /// </remarks> | ||
1798 | /// <param value="agent_control_v3">Cumulative agent movement that this method will update.</param> | ||
1799 | /// <returns>True if movement has been updated in some way. False otherwise.</returns> | ||
1800 | public bool HandleMoveToTargetUpdate(ref Vector3 agent_control_v3) | ||
1812 | { | 1801 | { |
1813 | m_autopilotMoving = true; | 1802 | // m_log.DebugFormat("[SCENE PRESENCE]: Called HandleMoveToTargetUpdate() for {0}", Name); |
1814 | m_autoPilotTarget = Pos; | 1803 | bool updated = false; |
1815 | m_sitAtAutoTarget = false; | ||
1816 | PrimitiveBaseShape proxy = PrimitiveBaseShape.Default; | ||
1817 | //proxy.PCode = (byte)PCode.ParticleSystem; | ||
1818 | proxyObjectGroup = new SceneObjectGroup(UUID, Pos, Rotation, proxy); | ||
1819 | proxyObjectGroup.AttachToScene(m_scene); | ||
1820 | |||
1821 | // Commented out this code since it could never have executed, but might still be informative. | ||
1822 | // if (proxyObjectGroup != null) | ||
1823 | // { | ||
1824 | proxyObjectGroup.SendGroupFullUpdate(); | ||
1825 | remote_client.SendSitResponse(proxyObjectGroup.UUID, Vector3.Zero, Quaternion.Identity, true, Vector3.Zero, Vector3.Zero, false); | ||
1826 | m_scene.DeleteSceneObject(proxyObjectGroup, false); | ||
1827 | // } | ||
1828 | // else | ||
1829 | // { | ||
1830 | // m_autopilotMoving = false; | ||
1831 | // m_autoPilotTarget = Vector3.Zero; | ||
1832 | // ControllingClient.SendAlertMessage("Autopilot cancelled"); | ||
1833 | // } | ||
1834 | } | ||
1835 | 1804 | ||
1836 | public void StopMoveToPosition() | 1805 | public void StopMoveToPosition() |
1837 | { | 1806 | { |
@@ -1844,31 +1813,186 @@ namespace OpenSim.Region.Framework.Scenes | |||
1844 | //Console.WriteLine("SP:DoMoveToPosition"); | 1813 | //Console.WriteLine("SP:DoMoveToPosition"); |
1845 | try | 1814 | try |
1846 | { | 1815 | { |
1847 | float locx = 0f; | 1816 | double distanceToTarget = Util.GetDistanceTo(AbsolutePosition, MoveToPositionTarget); |
1848 | float locy = 0f; | 1817 | // m_log.DebugFormat( |
1849 | float locz = 0f; | 1818 | // "[SCENE PRESENCE]: Abs pos of {0} is {1}, target {2}, distance {3}", |
1850 | uint regionX = 0; | 1819 | // Name, AbsolutePosition, MoveToPositionTarget, distanceToTarget); |
1851 | uint regionY = 0; | 1820 | |
1852 | try | 1821 | // Check the error term of the current position in relation to the target position |
1822 | if (distanceToTarget <= 1) | ||
1853 | { | 1823 | { |
1854 | Utils.LongToUInts(Scene.RegionInfo.RegionHandle, out regionX, out regionY); | 1824 | // We are close enough to the target |
1855 | locx = Convert.ToSingle(args[0]) - (float)regionX; | 1825 | AbsolutePosition = MoveToPositionTarget; |
1856 | locy = Convert.ToSingle(args[1]) - (float)regionY; | 1826 | ResetMoveToTarget(); |
1857 | locz = Convert.ToSingle(args[2]); | 1827 | updated = true; |
1858 | } | 1828 | } |
1859 | catch (InvalidCastException) | 1829 | else |
1860 | { | 1830 | { |
1861 | m_log.Error("[CLIENT]: Invalid autopilot request"); | 1831 | try |
1862 | return; | 1832 | { |
1833 | // move avatar in 3D at one meter/second towards target, in avatar coordinate frame. | ||
1834 | // This movement vector gets added to the velocity through AddNewMovement(). | ||
1835 | // Theoretically we might need a more complex PID approach here if other | ||
1836 | // unknown forces are acting on the avatar and we need to adaptively respond | ||
1837 | // to such forces, but the following simple approach seems to works fine. | ||
1838 | Vector3 LocalVectorToTarget3D = | ||
1839 | (MoveToPositionTarget - AbsolutePosition) // vector from cur. pos to target in global coords | ||
1840 | * Matrix4.CreateFromQuaternion(Quaternion.Inverse(Rotation)); // change to avatar coords | ||
1841 | // Ignore z component of vector | ||
1842 | // Vector3 LocalVectorToTarget2D = new Vector3((float)(LocalVectorToTarget3D.X), (float)(LocalVectorToTarget3D.Y), 0f); | ||
1843 | LocalVectorToTarget3D.Normalize(); | ||
1844 | |||
1845 | // update avatar movement flags. the avatar coordinate system is as follows: | ||
1846 | // | ||
1847 | // +X (forward) | ||
1848 | // | ||
1849 | // ^ | ||
1850 | // | | ||
1851 | // | | ||
1852 | // | | ||
1853 | // | | ||
1854 | // (left) +Y <--------o--------> -Y | ||
1855 | // avatar | ||
1856 | // | | ||
1857 | // | | ||
1858 | // | | ||
1859 | // | | ||
1860 | // v | ||
1861 | // -X | ||
1862 | // | ||
1863 | |||
1864 | // based on the above avatar coordinate system, classify the movement into | ||
1865 | // one of left/right/back/forward. | ||
1866 | if (LocalVectorToTarget3D.X < 0) //MoveBack | ||
1867 | { | ||
1868 | m_movementflag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_BACK; | ||
1869 | AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_BACK; | ||
1870 | updated = true; | ||
1871 | } | ||
1872 | else if (LocalVectorToTarget3D.X > 0) //Move Forward | ||
1873 | { | ||
1874 | m_movementflag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD; | ||
1875 | AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD; | ||
1876 | updated = true; | ||
1877 | } | ||
1878 | |||
1879 | if (LocalVectorToTarget3D.Y > 0) //MoveLeft | ||
1880 | { | ||
1881 | m_movementflag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT; | ||
1882 | AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT; | ||
1883 | updated = true; | ||
1884 | } | ||
1885 | else if (LocalVectorToTarget3D.Y < 0) //MoveRight | ||
1886 | { | ||
1887 | m_movementflag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT; | ||
1888 | AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT; | ||
1889 | updated = true; | ||
1890 | } | ||
1891 | |||
1892 | if (LocalVectorToTarget3D.Z > 0) //Up | ||
1893 | { | ||
1894 | // Don't set these flags for up or down - doing so will make the avatar crouch or | ||
1895 | // keep trying to jump even if walking along level ground | ||
1896 | //m_movementflag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_UP; | ||
1897 | //AgentControlFlags | ||
1898 | //AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_UP; | ||
1899 | updated = true; | ||
1900 | } | ||
1901 | else if (LocalVectorToTarget3D.Z < 0) //Down | ||
1902 | { | ||
1903 | //m_movementflag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_DOWN; | ||
1904 | //AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_DOWN; | ||
1905 | updated = true; | ||
1906 | } | ||
1907 | |||
1908 | // m_log.DebugFormat( | ||
1909 | // "[SCENE PRESENCE]: HandleMoveToTargetUpdate adding {0} to move vector {1} for {2}", | ||
1910 | // LocalVectorToTarget3D, agent_control_v3, Name); | ||
1911 | |||
1912 | agent_control_v3 += LocalVectorToTarget3D; | ||
1913 | } | ||
1914 | catch (Exception e) | ||
1915 | { | ||
1916 | //Avoid system crash, can be slower but... | ||
1917 | m_log.DebugFormat("Crash! {0}", e.ToString()); | ||
1918 | } | ||
1863 | } | 1919 | } |
1864 | m_moveToPositionInProgress = true; | ||
1865 | m_moveToPositionTarget = new Vector3(locx, locy, locz); | ||
1866 | } | 1920 | } |
1867 | catch (Exception ex) | 1921 | |
1868 | { | 1922 | return updated; |
1869 | //Why did I get this error? | 1923 | } |
1870 | m_log.Error("[SCENEPRESENCE]: DoMoveToPosition" + ex); | 1924 | |
1871 | } | 1925 | /// <summary> |
1926 | /// Move to the given target over time. | ||
1927 | /// </summary> | ||
1928 | /// <param name="pos"></param> | ||
1929 | /// <param name="noFly"> | ||
1930 | /// If true, then don't allow the avatar to fly to the target, even if it's up in the air. | ||
1931 | /// This is to allow movement to targets that are known to be on an elevated platform with a continuous path | ||
1932 | /// from start to finish. | ||
1933 | /// </param> | ||
1934 | public void MoveToTarget(Vector3 pos, bool noFly) | ||
1935 | { | ||
1936 | m_log.DebugFormat( | ||
1937 | "[SCENE PRESENCE]: Avatar {0} received request to move to position {1} in {2}", | ||
1938 | Name, pos, m_scene.RegionInfo.RegionName); | ||
1939 | |||
1940 | if (pos.X < 0 || pos.X >= Constants.RegionSize | ||
1941 | || pos.Y < 0 || pos.Y >= Constants.RegionSize | ||
1942 | || pos.Z < 0) | ||
1943 | return; | ||
1944 | |||
1945 | // Vector3 heightAdjust = new Vector3(0, 0, Appearance.AvatarHeight / 2); | ||
1946 | // pos += heightAdjust; | ||
1947 | // | ||
1948 | // // Anti duck-walking measure | ||
1949 | // if (Math.Abs(pos.Z - AbsolutePosition.Z) < 0.2f) | ||
1950 | // { | ||
1951 | //// m_log.DebugFormat("[SCENE PRESENCE]: Adjusting MoveToPosition from {0} to {1}", pos, AbsolutePosition); | ||
1952 | // pos.Z = AbsolutePosition.Z; | ||
1953 | // } | ||
1954 | |||
1955 | float terrainHeight = (float)m_scene.Heightmap[(int)pos.X, (int)pos.Y]; | ||
1956 | pos.Z = Math.Max(terrainHeight, pos.Z); | ||
1957 | |||
1958 | // Fudge factor. It appears that if one clicks "go here" on a piece of ground, the go here request is | ||
1959 | // always slightly higher than the actual terrain height. | ||
1960 | // FIXME: This constrains NOC movements as well, so should be somewhere else. | ||
1961 | if (pos.Z - terrainHeight < 0.2) | ||
1962 | pos.Z = terrainHeight; | ||
1963 | |||
1964 | m_log.DebugFormat( | ||
1965 | "[SCENE PRESENCE]: Avatar {0} set move to target {1} (terrain height {2}) in {3}", | ||
1966 | Name, pos, terrainHeight, m_scene.RegionInfo.RegionName); | ||
1967 | |||
1968 | if (noFly) | ||
1969 | PhysicsActor.Flying = false; | ||
1970 | else if (pos.Z > terrainHeight) | ||
1971 | PhysicsActor.Flying = true; | ||
1972 | |||
1973 | MovingToTarget = true; | ||
1974 | MoveToPositionTarget = pos; | ||
1975 | |||
1976 | Vector3 agent_control_v3 = new Vector3(); | ||
1977 | HandleMoveToTargetUpdate(ref agent_control_v3); | ||
1978 | AddNewMovement(agent_control_v3); | ||
1979 | } | ||
1980 | |||
1981 | /// <summary> | ||
1982 | /// Reset the move to target. | ||
1983 | /// </summary> | ||
1984 | public void ResetMoveToTarget() | ||
1985 | { | ||
1986 | m_log.DebugFormat("[SCENE PRESENCE]: Resetting move to target for {0}", Name); | ||
1987 | |||
1988 | MovingToTarget = false; | ||
1989 | MoveToPositionTarget = Vector3.Zero; | ||
1990 | |||
1991 | // We need to reset the control flag as the ScenePresenceAnimator uses this to determine the correct | ||
1992 | // resting animation (e.g. hover or stand). NPCs don't have a client that will quickly reset this flag. | ||
1993 | // However, the line is here rather than in the NPC module since it also appears necessary to stop a | ||
1994 | // viewer that uses "go here" from juddering on all subsequent avatar movements. | ||
1995 | AgentControlFlags = (uint)AgentManager.ControlFlags.NONE; | ||
1872 | } | 1996 | } |
1873 | 1997 | ||
1874 | private void CheckAtSitTarget() | 1998 | private void CheckAtSitTarget() |
@@ -1997,11 +2121,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
1997 | m_offsetRotation = new Quaternion(0.0f, 0.0f, 0.0f, 1.0f); | 2121 | m_offsetRotation = new Quaternion(0.0f, 0.0f, 0.0f, 1.0f); |
1998 | SendAvatarDataToAllAgents(); | 2122 | SendAvatarDataToAllAgents(); |
1999 | m_requestedSitTargetID = 0; | 2123 | m_requestedSitTargetID = 0; |
2000 | if (m_physicsActor != null && m_appearance != null) | ||
2001 | { | ||
2002 | if (m_appearance.AvatarHeight > 0) | ||
2003 | SetHeight(m_appearance.AvatarHeight); | ||
2004 | } | ||
2005 | } | 2124 | } |
2006 | Animator.TrySetMovementAnimation("STAND"); | 2125 | Animator.TrySetMovementAnimation("STAND"); |
2007 | } | 2126 | } |
@@ -2057,7 +2176,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2057 | bool forceMouselook = false; | 2176 | bool forceMouselook = false; |
2058 | 2177 | ||
2059 | //SceneObjectPart part = m_scene.GetSceneObjectPart(targetID); | 2178 | //SceneObjectPart part = m_scene.GetSceneObjectPart(targetID); |
2060 | SceneObjectPart part = FindNextAvailableSitTarget(targetID); | 2179 | SceneObjectPart part = FindNextAvailableSitTarget(targetID); |
2061 | if (part == null) return; | 2180 | if (part == null) return; |
2062 | 2181 | ||
2063 | // TODO: determine position to sit at based on scene geometry; don't trust offset from client | 2182 | // TODO: determine position to sit at based on scene geometry; don't trust offset from client |
@@ -2215,14 +2334,23 @@ namespace OpenSim.Region.Framework.Scenes | |||
2215 | HandleAgentSit(remoteClient, UUID); | 2334 | HandleAgentSit(remoteClient, UUID); |
2216 | } | 2335 | } |
2217 | 2336 | ||
2337 | // public void HandleAgentRequestSit(IClientAPI remoteClient, UUID agentID, UUID targetID, Vector3 offset, string sitAnimation) | ||
2218 | public void HandleAgentRequestSit(IClientAPI remoteClient, UUID agentID, UUID targetID, Vector3 offset) | 2338 | public void HandleAgentRequestSit(IClientAPI remoteClient, UUID agentID, UUID targetID, Vector3 offset) |
2219 | { | 2339 | { |
2220 | if (m_parentID != 0) | 2340 | if (m_parentID != 0) |
2221 | { | 2341 | { |
2222 | StandUp(); | 2342 | StandUp(); |
2223 | } | 2343 | } |
2344 | |||
2345 | // if (!String.IsNullOrEmpty(sitAnimation)) | ||
2346 | // { | ||
2347 | // m_nextSitAnimation = sitAnimation; | ||
2348 | // } | ||
2349 | // else | ||
2350 | // { | ||
2224 | m_nextSitAnimation = "SIT"; | 2351 | m_nextSitAnimation = "SIT"; |
2225 | 2352 | // } | |
2353 | |||
2226 | //SceneObjectPart part = m_scene.GetSceneObjectPart(targetID); | 2354 | //SceneObjectPart part = m_scene.GetSceneObjectPart(targetID); |
2227 | SceneObjectPart part = FindNextAvailableSitTarget(targetID); | 2355 | SceneObjectPart part = FindNextAvailableSitTarget(targetID); |
2228 | 2356 | ||
@@ -2247,7 +2375,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
2247 | } | 2375 | } |
2248 | else | 2376 | else |
2249 | { | 2377 | { |
2250 | |||
2251 | m_log.Warn("Sit requested on unknown object: " + targetID.ToString()); | 2378 | m_log.Warn("Sit requested on unknown object: " + targetID.ToString()); |
2252 | } | 2379 | } |
2253 | 2380 | ||
@@ -2445,44 +2572,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2445 | SendSitResponse(ControllingClient, m_requestedSitTargetUUID, collisionPoint - m_requestedSitOffset, Quaternion.Identity); | 2572 | SendSitResponse(ControllingClient, m_requestedSitTargetUUID, collisionPoint - m_requestedSitOffset, Quaternion.Identity); |
2446 | } | 2573 | } |
2447 | */ | 2574 | */ |
2448 | public void HandleAgentRequestSit(IClientAPI remoteClient, UUID agentID, UUID targetID, Vector3 offset, string sitAnimation) | ||
2449 | { | ||
2450 | if (m_parentID != 0) | ||
2451 | { | ||
2452 | StandUp(); | ||
2453 | } | ||
2454 | if (!String.IsNullOrEmpty(sitAnimation)) | ||
2455 | { | ||
2456 | m_nextSitAnimation = sitAnimation; | ||
2457 | } | ||
2458 | else | ||
2459 | { | ||
2460 | m_nextSitAnimation = "SIT"; | ||
2461 | } | ||
2462 | |||
2463 | //SceneObjectPart part = m_scene.GetSceneObjectPart(targetID); | ||
2464 | SceneObjectPart part = FindNextAvailableSitTarget(targetID); | ||
2465 | if (part != null) | ||
2466 | { | ||
2467 | m_requestedSitTargetID = part.LocalId; | ||
2468 | //m_requestedSitOffset = offset; | ||
2469 | m_requestedSitTargetUUID = targetID; | ||
2470 | 2575 | ||
2471 | m_log.DebugFormat("[SIT]: Client requested Sit Position: {0}", offset); | ||
2472 | |||
2473 | if (m_scene.PhysicsScene.SupportsRayCast()) | ||
2474 | { | ||
2475 | //SitRayCastAvatarPosition(part); | ||
2476 | //return; | ||
2477 | } | ||
2478 | } | ||
2479 | else | ||
2480 | { | ||
2481 | m_log.Warn("Sit requested on unknown object: " + targetID); | ||
2482 | } | ||
2483 | |||
2484 | SendSitResponse(remoteClient, targetID, offset, Quaternion.Identity); | ||
2485 | } | ||
2486 | 2576 | ||
2487 | public void HandleAgentSit(IClientAPI remoteClient, UUID agentID) | 2577 | public void HandleAgentSit(IClientAPI remoteClient, UUID agentID) |
2488 | { | 2578 | { |
@@ -2669,8 +2759,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2669 | 2759 | ||
2670 | m_perfMonMS = Util.EnvironmentTickCount(); | 2760 | m_perfMonMS = Util.EnvironmentTickCount(); |
2671 | 2761 | ||
2672 | Rotation = rotation; | 2762 | Vector3 direc = vec * Rotation; |
2673 | Vector3 direc = vec * rotation; | ||
2674 | direc.Normalize(); | 2763 | direc.Normalize(); |
2675 | PhysicsActor actor = m_physicsActor; | 2764 | PhysicsActor actor = m_physicsActor; |
2676 | 2765 | ||
@@ -2901,13 +2990,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2901 | // We have an appearance but we may not have the baked textures. Check the asset cache | 2990 | // We have an appearance but we may not have the baked textures. Check the asset cache |
2902 | // to see if all the baked textures are already here. | 2991 | // to see if all the baked textures are already here. |
2903 | if (m_scene.AvatarFactory != null) | 2992 | if (m_scene.AvatarFactory != null) |
2904 | { | ||
2905 | cachedappearance = m_scene.AvatarFactory.ValidateBakedTextureCache(m_controllingClient); | 2993 | cachedappearance = m_scene.AvatarFactory.ValidateBakedTextureCache(m_controllingClient); |
2906 | } | ||
2907 | else | ||
2908 | { | ||
2909 | m_log.WarnFormat("[SCENEPRESENCE]: AvatarFactory not set for {0}", Name); | ||
2910 | } | ||
2911 | 2994 | ||
2912 | // If we aren't using a cached appearance, then clear out the baked textures | 2995 | // If we aren't using a cached appearance, then clear out the baked textures |
2913 | if (!cachedappearance) | 2996 | if (!cachedappearance) |
@@ -3064,19 +3147,21 @@ namespace OpenSim.Region.Framework.Scenes | |||
3064 | /// <param name="avatar"></param> | 3147 | /// <param name="avatar"></param> |
3065 | public void SendAppearanceToAgent(ScenePresence avatar) | 3148 | public void SendAppearanceToAgent(ScenePresence avatar) |
3066 | { | 3149 | { |
3067 | // m_log.WarnFormat("[SP] Send appearance from {0} to {1}",m_uuid,avatar.ControllingClient.AgentId); | 3150 | // m_log.DebugFormat( |
3151 | // "[SCENE PRESENCE] Send appearance from {0} {1} to {2} {3}", Name, m_uuid, avatar.Name, avatar.UUID); | ||
3068 | 3152 | ||
3069 | avatar.ControllingClient.SendAppearance( | 3153 | avatar.ControllingClient.SendAppearance( |
3070 | m_appearance.Owner, m_appearance.VisualParams, m_appearance.Texture.GetBytes()); | 3154 | UUID, m_appearance.VisualParams, m_appearance.Texture.GetBytes()); |
3071 | } | 3155 | } |
3072 | 3156 | ||
3073 | // Because appearance setting is in a module, we actually need | ||
3074 | // to give it access to our appearance directly, otherwise we | ||
3075 | // get a synchronization issue. | ||
3076 | public AvatarAppearance Appearance | 3157 | public AvatarAppearance Appearance |
3077 | { | 3158 | { |
3078 | get { return m_appearance; } | 3159 | get { return m_appearance; } |
3079 | set { m_appearance = value; } | 3160 | set |
3161 | { | ||
3162 | m_appearance = value; | ||
3163 | // m_log.DebugFormat("[SCENE PRESENCE]: Set appearance for {0} to {1}", Name, value); | ||
3164 | } | ||
3080 | } | 3165 | } |
3081 | 3166 | ||
3082 | #endregion | 3167 | #endregion |
@@ -3088,15 +3173,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
3088 | /// </summary> | 3173 | /// </summary> |
3089 | protected void CheckForSignificantMovement() | 3174 | protected void CheckForSignificantMovement() |
3090 | { | 3175 | { |
3091 | // Movement updates for agents in neighboring regions are sent directly to clients. | ||
3092 | // This value only affects how often agent positions are sent to neighbor regions | ||
3093 | // for things such as distance-based update prioritization | ||
3094 | const float SIGNIFICANT_MOVEMENT = 2.0f; | ||
3095 | |||
3096 | if (Util.GetDistanceTo(AbsolutePosition, posLastSignificantMove) > SIGNIFICANT_MOVEMENT) | 3176 | if (Util.GetDistanceTo(AbsolutePosition, posLastSignificantMove) > SIGNIFICANT_MOVEMENT) |
3097 | { | 3177 | { |
3098 | posLastSignificantMove = AbsolutePosition; | 3178 | posLastSignificantMove = AbsolutePosition; |
3099 | m_scene.EventManager.TriggerSignificantClientMovement(m_controllingClient); | 3179 | m_scene.EventManager.TriggerSignificantClientMovement(this); |
3100 | } | 3180 | } |
3101 | 3181 | ||
3102 | // Minimum Draw distance is 64 meters, the Radius of the draw distance sphere is 32m | 3182 | // Minimum Draw distance is 64 meters, the Radius of the draw distance sphere is 32m |
@@ -3579,7 +3659,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3579 | ISceneObject clone = sog.CloneForNewScene(); | 3659 | ISceneObject clone = sog.CloneForNewScene(); |
3580 | // Attachment module assumes that GroupPosition holds the offsets...! | 3660 | // Attachment module assumes that GroupPosition holds the offsets...! |
3581 | ((SceneObjectGroup)clone).RootPart.GroupPosition = sog.RootPart.AttachedPos; | 3661 | ((SceneObjectGroup)clone).RootPart.GroupPosition = sog.RootPart.AttachedPos; |
3582 | ((SceneObjectGroup)clone).RootPart.IsAttachment = false; | 3662 | ((SceneObjectGroup)clone).IsAttachment = false; |
3583 | cAgent.AttachmentObjects.Add(clone); | 3663 | cAgent.AttachmentObjects.Add(clone); |
3584 | string state = sog.GetStateSnapshot(); | 3664 | string state = sog.GetStateSnapshot(); |
3585 | cAgent.AttachmentObjectStates.Add(state); | 3665 | cAgent.AttachmentObjectStates.Add(state); |
@@ -3746,6 +3826,8 @@ if (m_animator.m_jumping) force.Z = m_animator.m_jumpVelocity; // add for ju | |||
3746 | m_physicsActor.OnOutOfBounds += OutOfBoundsCall; // Called for PhysicsActors when there's something wrong | 3826 | m_physicsActor.OnOutOfBounds += OutOfBoundsCall; // Called for PhysicsActors when there's something wrong |
3747 | m_physicsActor.SubscribeEvents(500); | 3827 | m_physicsActor.SubscribeEvents(500); |
3748 | m_physicsActor.LocalID = LocalId; | 3828 | m_physicsActor.LocalID = LocalId; |
3829 | |||
3830 | SetHeight(m_appearance.AvatarHeight); | ||
3749 | } | 3831 | } |
3750 | 3832 | ||
3751 | private void OutOfBoundsCall(Vector3 pos) | 3833 | private void OutOfBoundsCall(Vector3 pos) |
@@ -4001,19 +4083,7 @@ if (m_animator.m_jumping) force.Z = m_animator.m_jumpVelocity; // add for ju | |||
4001 | 4083 | ||
4002 | public void Close() | 4084 | public void Close() |
4003 | { | 4085 | { |
4004 | lock (m_attachments) | 4086 | m_scene.AttachmentsModule.DeleteAttachmentsFromScene(this, false); |
4005 | { | ||
4006 | // Delete attachments from scene | ||
4007 | // Don't try to save, as this thread won't live long | ||
4008 | // enough to complete the save. This would cause no copy | ||
4009 | // attachments to poof! | ||
4010 | // | ||
4011 | foreach (SceneObjectGroup grp in m_attachments) | ||
4012 | { | ||
4013 | m_scene.DeleteSceneObject(grp, false); | ||
4014 | } | ||
4015 | m_attachments.Clear(); | ||
4016 | } | ||
4017 | 4087 | ||
4018 | lock (m_knownChildRegions) | 4088 | lock (m_knownChildRegions) |
4019 | { | 4089 | { |
@@ -4048,9 +4118,19 @@ if (m_animator.m_jumping) force.Z = m_animator.m_jumpVelocity; // add for ju | |||
4048 | m_attachments.Add(gobj); | 4118 | m_attachments.Add(gobj); |
4049 | } | 4119 | } |
4050 | } | 4120 | } |
4051 | 4121 | ||
4122 | /// <summary> | ||
4123 | /// Get all the presence's attachments. | ||
4124 | /// </summary> | ||
4125 | /// <returns>A copy of the list which contains the attachments.</returns> | ||
4126 | public List<SceneObjectGroup> GetAttachments() | ||
4127 | { | ||
4128 | lock (m_attachments) | ||
4129 | return new List<SceneObjectGroup>(m_attachments); | ||
4130 | } | ||
4131 | |||
4052 | /// <summary> | 4132 | /// <summary> |
4053 | /// Get the scene object attached to the given point. | 4133 | /// Get the scene objects attached to the given point. |
4054 | /// </summary> | 4134 | /// </summary> |
4055 | /// <param name="attachmentPoint"></param> | 4135 | /// <param name="attachmentPoint"></param> |
4056 | /// <returns>Returns an empty list if there were no attachments at the point.</returns> | 4136 | /// <returns>Returns an empty list if there were no attachments at the point.</returns> |
@@ -4062,7 +4142,7 @@ if (m_animator.m_jumping) force.Z = m_animator.m_jumpVelocity; // add for ju | |||
4062 | { | 4142 | { |
4063 | foreach (SceneObjectGroup so in m_attachments) | 4143 | foreach (SceneObjectGroup so in m_attachments) |
4064 | { | 4144 | { |
4065 | if (attachmentPoint == so.RootPart.AttachmentPoint) | 4145 | if (attachmentPoint == so.AttachmentPoint) |
4066 | attachments.Add(so); | 4146 | attachments.Add(so); |
4067 | } | 4147 | } |
4068 | } | 4148 | } |
@@ -4072,7 +4152,8 @@ if (m_animator.m_jumping) force.Z = m_animator.m_jumpVelocity; // add for ju | |||
4072 | 4152 | ||
4073 | public bool HasAttachments() | 4153 | public bool HasAttachments() |
4074 | { | 4154 | { |
4075 | return m_attachments.Count > 0; | 4155 | lock (m_attachments) |
4156 | return m_attachments.Count > 0; | ||
4076 | } | 4157 | } |
4077 | 4158 | ||
4078 | public bool HasScriptedAttachments() | 4159 | public bool HasScriptedAttachments() |
@@ -4094,12 +4175,16 @@ if (m_animator.m_jumping) force.Z = m_animator.m_jumpVelocity; // add for ju | |||
4094 | public void RemoveAttachment(SceneObjectGroup gobj) | 4175 | public void RemoveAttachment(SceneObjectGroup gobj) |
4095 | { | 4176 | { |
4096 | lock (m_attachments) | 4177 | lock (m_attachments) |
4097 | { | 4178 | m_attachments.Remove(gobj); |
4098 | if (m_attachments.Contains(gobj)) | 4179 | } |
4099 | { | 4180 | |
4100 | m_attachments.Remove(gobj); | 4181 | /// <summary> |
4101 | } | 4182 | /// Clear all attachments |
4102 | } | 4183 | /// </summary> |
4184 | public void ClearAttachments() | ||
4185 | { | ||
4186 | lock (m_attachments) | ||
4187 | m_attachments.Clear(); | ||
4103 | } | 4188 | } |
4104 | 4189 | ||
4105 | public bool ValidateAttachments() | 4190 | public bool ValidateAttachments() |
@@ -4110,12 +4195,22 @@ if (m_animator.m_jumping) force.Z = m_animator.m_jumpVelocity; // add for ju | |||
4110 | foreach (SceneObjectGroup gobj in m_attachments) | 4195 | foreach (SceneObjectGroup gobj in m_attachments) |
4111 | { | 4196 | { |
4112 | if (gobj == null) | 4197 | if (gobj == null) |
4198 | { | ||
4199 | m_log.WarnFormat( | ||
4200 | "[SCENE PRESENCE]: Failed to validate an attachment for {0} since it was null", Name); | ||
4113 | return false; | 4201 | return false; |
4202 | } | ||
4114 | 4203 | ||
4115 | if (gobj.IsDeleted) | 4204 | if (gobj.IsDeleted) |
4205 | { | ||
4206 | m_log.WarnFormat( | ||
4207 | "[SCENE PRESENCE]: Failed to validate attachment {0} {1} for {2} since it had been deleted", | ||
4208 | gobj.Name, gobj.UUID, Name); | ||
4116 | return false; | 4209 | return false; |
4210 | } | ||
4117 | } | 4211 | } |
4118 | } | 4212 | } |
4213 | |||
4119 | return true; | 4214 | return true; |
4120 | } | 4215 | } |
4121 | 4216 | ||
@@ -4553,4 +4648,4 @@ if (m_animator.m_jumping) force.Z = m_animator.m_jumpVelocity; // add for ju | |||
4553 | } | 4648 | } |
4554 | } | 4649 | } |
4555 | } | 4650 | } |
4556 | } | 4651 | } \ No newline at end of file |
diff --git a/OpenSim/Region/Framework/Scenes/SceneViewer.cs b/OpenSim/Region/Framework/Scenes/SceneViewer.cs index f04ed4d..501487a 100644 --- a/OpenSim/Region/Framework/Scenes/SceneViewer.cs +++ b/OpenSim/Region/Framework/Scenes/SceneViewer.cs | |||
@@ -110,7 +110,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
110 | { | 110 | { |
111 | SceneObjectPart part = m_partsUpdateQueue.Dequeue(); | 111 | SceneObjectPart part = m_partsUpdateQueue.Dequeue(); |
112 | 112 | ||
113 | if (part.ParentGroup == null || part.ParentGroup.IsDeleted) | 113 | if (part.ParentGroup.IsDeleted) |
114 | continue; | 114 | continue; |
115 | 115 | ||
116 | if (m_updateTimes.ContainsKey(part.UUID)) | 116 | if (m_updateTimes.ContainsKey(part.UUID)) |
@@ -120,8 +120,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
120 | // We deal with the possibility that two updates occur at | 120 | // We deal with the possibility that two updates occur at |
121 | // the same unix time at the update point itself. | 121 | // the same unix time at the update point itself. |
122 | 122 | ||
123 | if ((update.LastFullUpdateTime < part.TimeStampFull) || | 123 | if ((update.LastFullUpdateTime < part.TimeStampFull) || part.ParentGroup.IsAttachment) |
124 | part.IsAttachment) | ||
125 | { | 124 | { |
126 | // m_log.DebugFormat( | 125 | // m_log.DebugFormat( |
127 | // "[SCENE PRESENCE]: Fully updating prim {0}, {1} - part timestamp {2}", | 126 | // "[SCENE PRESENCE]: Fully updating prim {0}, {1} - part timestamp {2}", |
diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs index d6e8223..11dad6c 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs | |||
@@ -53,19 +53,9 @@ namespace OpenSim.Region.Framework.Scenes.Serialization | |||
53 | /// <summary> | 53 | /// <summary> |
54 | /// Deserialize a scene object from the original xml format | 54 | /// Deserialize a scene object from the original xml format |
55 | /// </summary> | 55 | /// </summary> |
56 | /// <param name="serialization"></param> | 56 | /// <param name="xmlData"></param> |
57 | /// <returns></returns> | 57 | /// <returns></returns> |
58 | public static SceneObjectGroup FromOriginalXmlFormat(string serialization) | 58 | public static SceneObjectGroup FromOriginalXmlFormat(string xmlData) |
59 | { | ||
60 | return FromOriginalXmlFormat(UUID.Zero, serialization); | ||
61 | } | ||
62 | |||
63 | /// <summary> | ||
64 | /// Deserialize a scene object from the original xml format | ||
65 | /// </summary> | ||
66 | /// <param name="serialization"></param> | ||
67 | /// <returns></returns> | ||
68 | public static SceneObjectGroup FromOriginalXmlFormat(UUID fromUserInventoryItemID, string xmlData) | ||
69 | { | 59 | { |
70 | //m_log.DebugFormat("[SOG]: Starting deserialization of SOG"); | 60 | //m_log.DebugFormat("[SOG]: Starting deserialization of SOG"); |
71 | //int time = System.Environment.TickCount; | 61 | //int time = System.Environment.TickCount; |
@@ -87,7 +77,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization | |||
87 | 77 | ||
88 | sr = new StringReader(parts[0].InnerXml); | 78 | sr = new StringReader(parts[0].InnerXml); |
89 | reader = new XmlTextReader(sr); | 79 | reader = new XmlTextReader(sr); |
90 | SceneObjectGroup sceneObject = new SceneObjectGroup(SceneObjectPart.FromXml(fromUserInventoryItemID, reader)); | 80 | SceneObjectGroup sceneObject = new SceneObjectGroup(SceneObjectPart.FromXml(reader)); |
91 | reader.Close(); | 81 | reader.Close(); |
92 | sr.Close(); | 82 | sr.Close(); |
93 | 83 | ||
@@ -102,7 +92,6 @@ namespace OpenSim.Region.Framework.Scenes.Serialization | |||
102 | sceneObject.AddPart(part); | 92 | sceneObject.AddPart(part); |
103 | part.LinkNum = linkNum; | 93 | part.LinkNum = linkNum; |
104 | part.TrimPermissions(); | 94 | part.TrimPermissions(); |
105 | part.StoreUndoState(UndoType.STATE_ALL); | ||
106 | reader.Close(); | 95 | reader.Close(); |
107 | sr.Close(); | 96 | sr.Close(); |
108 | } | 97 | } |
@@ -128,26 +117,36 @@ namespace OpenSim.Region.Framework.Scenes.Serialization | |||
128 | /// <returns></returns> | 117 | /// <returns></returns> |
129 | public static string ToOriginalXmlFormat(SceneObjectGroup sceneObject) | 118 | public static string ToOriginalXmlFormat(SceneObjectGroup sceneObject) |
130 | { | 119 | { |
120 | return ToOriginalXmlFormat(sceneObject, true); | ||
121 | } | ||
122 | |||
123 | /// <summary> | ||
124 | /// Serialize a scene object to the original xml format | ||
125 | /// </summary> | ||
126 | /// <param name="sceneObject"></param> | ||
127 | /// <param name="doScriptStates">Control whether script states are also serialized.</para> | ||
128 | /// <returns></returns> | ||
129 | public static string ToOriginalXmlFormat(SceneObjectGroup sceneObject, bool doScriptStates) | ||
130 | { | ||
131 | using (StringWriter sw = new StringWriter()) | 131 | using (StringWriter sw = new StringWriter()) |
132 | { | 132 | { |
133 | using (XmlTextWriter writer = new XmlTextWriter(sw)) | 133 | using (XmlTextWriter writer = new XmlTextWriter(sw)) |
134 | { | 134 | { |
135 | ToOriginalXmlFormat(sceneObject, writer); | 135 | ToOriginalXmlFormat(sceneObject, writer, doScriptStates); |
136 | } | 136 | } |
137 | 137 | ||
138 | return sw.ToString(); | 138 | return sw.ToString(); |
139 | } | 139 | } |
140 | } | 140 | } |
141 | |||
142 | 141 | ||
143 | /// <summary> | 142 | /// <summary> |
144 | /// Serialize a scene object to the original xml format | 143 | /// Serialize a scene object to the original xml format |
145 | /// </summary> | 144 | /// </summary> |
146 | /// <param name="sceneObject"></param> | 145 | /// <param name="sceneObject"></param> |
147 | /// <returns></returns> | 146 | /// <returns></returns> |
148 | public static void ToOriginalXmlFormat(SceneObjectGroup sceneObject, XmlTextWriter writer) | 147 | public static void ToOriginalXmlFormat(SceneObjectGroup sceneObject, XmlTextWriter writer, bool doScriptStates) |
149 | { | 148 | { |
150 | ToOriginalXmlFormat(sceneObject, writer, false); | 149 | ToOriginalXmlFormat(sceneObject, writer, doScriptStates, false); |
151 | } | 150 | } |
152 | 151 | ||
153 | /// <summary> | 152 | /// <summary> |
@@ -157,10 +156,11 @@ namespace OpenSim.Region.Framework.Scenes.Serialization | |||
157 | /// <param name="writer"></param> | 156 | /// <param name="writer"></param> |
158 | /// <param name="noRootElement">If false, don't write the enclosing SceneObjectGroup element</param> | 157 | /// <param name="noRootElement">If false, don't write the enclosing SceneObjectGroup element</param> |
159 | /// <returns></returns> | 158 | /// <returns></returns> |
160 | public static void ToOriginalXmlFormat(SceneObjectGroup sceneObject, XmlTextWriter writer, bool noRootElement) | 159 | public static void ToOriginalXmlFormat( |
160 | SceneObjectGroup sceneObject, XmlTextWriter writer, bool doScriptStates, bool noRootElement) | ||
161 | { | 161 | { |
162 | //m_log.DebugFormat("[SERIALIZER]: Starting serialization of {0}", Name); | 162 | // m_log.DebugFormat("[SERIALIZER]: Starting serialization of {0}", sceneObject.Name); |
163 | //int time = System.Environment.TickCount; | 163 | // int time = System.Environment.TickCount; |
164 | 164 | ||
165 | if (!noRootElement) | 165 | if (!noRootElement) |
166 | writer.WriteStartElement(String.Empty, "SceneObjectGroup", String.Empty); | 166 | writer.WriteStartElement(String.Empty, "SceneObjectGroup", String.Empty); |
@@ -183,12 +183,14 @@ namespace OpenSim.Region.Framework.Scenes.Serialization | |||
183 | } | 183 | } |
184 | 184 | ||
185 | writer.WriteEndElement(); // OtherParts | 185 | writer.WriteEndElement(); // OtherParts |
186 | sceneObject.SaveScriptedState(writer); | 186 | |
187 | if (doScriptStates) | ||
188 | sceneObject.SaveScriptedState(writer); | ||
187 | 189 | ||
188 | if (!noRootElement) | 190 | if (!noRootElement) |
189 | writer.WriteEndElement(); // SceneObjectGroup | 191 | writer.WriteEndElement(); // SceneObjectGroup |
190 | 192 | ||
191 | //m_log.DebugFormat("[SERIALIZER]: Finished serialization of SOG {0}, {1}ms", Name, System.Environment.TickCount - time); | 193 | // m_log.DebugFormat("[SERIALIZER]: Finished serialization of SOG {0}, {1}ms", sceneObject.Name, System.Environment.TickCount - time); |
192 | } | 194 | } |
193 | 195 | ||
194 | protected static void ToXmlFormat(SceneObjectPart part, XmlTextWriter writer) | 196 | protected static void ToXmlFormat(SceneObjectPart part, XmlTextWriter writer) |
@@ -236,15 +238,14 @@ namespace OpenSim.Region.Framework.Scenes.Serialization | |||
236 | if (originalLinkNum != 0) | 238 | if (originalLinkNum != 0) |
237 | part.LinkNum = originalLinkNum; | 239 | part.LinkNum = originalLinkNum; |
238 | 240 | ||
239 | part.StoreUndoState(UndoType.STATE_ALL); | ||
240 | reader.Close(); | 241 | reader.Close(); |
241 | sr.Close(); | 242 | sr.Close(); |
242 | } | 243 | } |
243 | 244 | ||
244 | // Script state may, or may not, exist. Not having any, is NOT | 245 | // Script state may, or may not, exist. Not having any, is NOT |
245 | // ever a problem. | 246 | // ever a problem. |
246 | |||
247 | sceneObject.LoadScriptState(doc); | 247 | sceneObject.LoadScriptState(doc); |
248 | |||
248 | return sceneObject; | 249 | return sceneObject; |
249 | } | 250 | } |
250 | catch (Exception e) | 251 | catch (Exception e) |
@@ -1592,4 +1593,4 @@ namespace OpenSim.Region.Framework.Scenes.Serialization | |||
1592 | 1593 | ||
1593 | #endregion | 1594 | #endregion |
1594 | } | 1595 | } |
1595 | } | 1596 | } \ No newline at end of file |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/AttachmentTests.cs b/OpenSim/Region/Framework/Scenes/Tests/AttachmentTests.cs deleted file mode 100644 index cff649b..0000000 --- a/OpenSim/Region/Framework/Scenes/Tests/AttachmentTests.cs +++ /dev/null | |||
@@ -1,172 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using System.Text; | ||
32 | using System.Threading; | ||
33 | using System.Timers; | ||
34 | using Timer=System.Timers.Timer; | ||
35 | using Nini.Config; | ||
36 | using NUnit.Framework; | ||
37 | using OpenMetaverse; | ||
38 | using OpenSim.Framework; | ||
39 | using OpenSim.Framework.Communications; | ||
40 | using OpenSim.Region.Framework.Scenes; | ||
41 | using OpenSim.Region.Framework.Interfaces; | ||
42 | using OpenSim.Region.CoreModules.World.Serialiser; | ||
43 | using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; | ||
44 | using OpenSim.Tests.Common; | ||
45 | using OpenSim.Tests.Common.Mock; | ||
46 | |||
47 | namespace OpenSim.Region.Framework.Scenes.Tests | ||
48 | { | ||
49 | /// <summary> | ||
50 | /// Attachment tests | ||
51 | /// </summary> | ||
52 | [TestFixture] | ||
53 | public class AttachmentTests | ||
54 | { | ||
55 | public Scene scene, scene2; | ||
56 | public UUID agent1; | ||
57 | public static Random random; | ||
58 | public ulong region1, region2; | ||
59 | public AgentCircuitData acd1; | ||
60 | public SceneObjectGroup sog1, sog2, sog3; | ||
61 | |||
62 | [TestFixtureSetUp] | ||
63 | public void Init() | ||
64 | { | ||
65 | TestHelper.InMethod(); | ||
66 | |||
67 | scene = SceneSetupHelpers.SetupScene("Neighbour x", UUID.Random(), 1000, 1000); | ||
68 | scene2 = SceneSetupHelpers.SetupScene("Neighbour x+1", UUID.Random(), 1001, 1000); | ||
69 | |||
70 | ISharedRegionModule interregionComms = new LocalSimulationConnectorModule(); | ||
71 | interregionComms.Initialise(new IniConfigSource()); | ||
72 | interregionComms.PostInitialise(); | ||
73 | SceneSetupHelpers.SetupSceneModules(scene, new IniConfigSource(), interregionComms); | ||
74 | SceneSetupHelpers.SetupSceneModules(scene2, new IniConfigSource(), interregionComms); | ||
75 | |||
76 | agent1 = UUID.Random(); | ||
77 | random = new Random(); | ||
78 | sog1 = NewSOG(UUID.Random(), scene, agent1); | ||
79 | sog2 = NewSOG(UUID.Random(), scene, agent1); | ||
80 | sog3 = NewSOG(UUID.Random(), scene, agent1); | ||
81 | |||
82 | //ulong neighbourHandle = Utils.UIntsToLong((uint)(neighbourx * Constants.RegionSize), (uint)(neighboury * Constants.RegionSize)); | ||
83 | region1 = scene.RegionInfo.RegionHandle; | ||
84 | region2 = scene2.RegionInfo.RegionHandle; | ||
85 | |||
86 | SceneSetupHelpers.AddRootAgent(scene, agent1); | ||
87 | } | ||
88 | |||
89 | [Test] | ||
90 | public void T030_TestAddAttachments() | ||
91 | { | ||
92 | TestHelper.InMethod(); | ||
93 | |||
94 | ScenePresence presence = scene.GetScenePresence(agent1); | ||
95 | |||
96 | presence.AddAttachment(sog1); | ||
97 | presence.AddAttachment(sog2); | ||
98 | presence.AddAttachment(sog3); | ||
99 | |||
100 | Assert.That(presence.HasAttachments(), Is.True); | ||
101 | Assert.That(presence.ValidateAttachments(), Is.True); | ||
102 | } | ||
103 | |||
104 | [Test] | ||
105 | public void T031_RemoveAttachments() | ||
106 | { | ||
107 | TestHelper.InMethod(); | ||
108 | |||
109 | ScenePresence presence = scene.GetScenePresence(agent1); | ||
110 | presence.RemoveAttachment(sog1); | ||
111 | presence.RemoveAttachment(sog2); | ||
112 | presence.RemoveAttachment(sog3); | ||
113 | Assert.That(presence.HasAttachments(), Is.False); | ||
114 | } | ||
115 | |||
116 | // I'm commenting this test because scene setup NEEDS InventoryService to | ||
117 | // be non-null | ||
118 | //[Test] | ||
119 | public void T032_CrossAttachments() | ||
120 | { | ||
121 | TestHelper.InMethod(); | ||
122 | |||
123 | ScenePresence presence = scene.GetScenePresence(agent1); | ||
124 | ScenePresence presence2 = scene2.GetScenePresence(agent1); | ||
125 | presence2.AddAttachment(sog1); | ||
126 | presence2.AddAttachment(sog2); | ||
127 | |||
128 | ISharedRegionModule serialiser = new SerialiserModule(); | ||
129 | SceneSetupHelpers.SetupSceneModules(scene, new IniConfigSource(), serialiser); | ||
130 | SceneSetupHelpers.SetupSceneModules(scene2, new IniConfigSource(), serialiser); | ||
131 | |||
132 | Assert.That(presence.HasAttachments(), Is.False, "Presence has attachments before cross"); | ||
133 | |||
134 | //Assert.That(presence2.CrossAttachmentsIntoNewRegion(region1, true), Is.True, "Cross was not successful"); | ||
135 | Assert.That(presence2.HasAttachments(), Is.False, "Presence2 objects were not deleted"); | ||
136 | Assert.That(presence.HasAttachments(), Is.True, "Presence has not received new objects"); | ||
137 | } | ||
138 | |||
139 | private SceneObjectGroup NewSOG(UUID uuid, Scene scene, UUID agent) | ||
140 | { | ||
141 | SceneObjectPart sop = new SceneObjectPart(); | ||
142 | sop.Name = RandomName(); | ||
143 | sop.Description = RandomName(); | ||
144 | sop.Text = RandomName(); | ||
145 | sop.SitName = RandomName(); | ||
146 | sop.TouchName = RandomName(); | ||
147 | sop.UUID = uuid; | ||
148 | sop.Shape = PrimitiveBaseShape.Default; | ||
149 | sop.Shape.State = 1; | ||
150 | sop.OwnerID = agent; | ||
151 | |||
152 | SceneObjectGroup sog = new SceneObjectGroup(sop); | ||
153 | sog.SetScene(scene); | ||
154 | |||
155 | return sog; | ||
156 | } | ||
157 | |||
158 | private static string RandomName() | ||
159 | { | ||
160 | StringBuilder name = new StringBuilder(); | ||
161 | int size = random.Next(5,12); | ||
162 | char ch; | ||
163 | for (int i = 0; i < size; i++) | ||
164 | { | ||
165 | ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65))) ; | ||
166 | name.Append(ch); | ||
167 | } | ||
168 | |||
169 | return name.ToString(); | ||
170 | } | ||
171 | } | ||
172 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/Framework/Scenes/Tests/BorderTests.cs b/OpenSim/Region/Framework/Scenes/Tests/BorderTests.cs index 3a0dd00..ab6311b 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/BorderTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/BorderTests.cs | |||
@@ -41,7 +41,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
41 | [Test] | 41 | [Test] |
42 | public void TestCross() | 42 | public void TestCross() |
43 | { | 43 | { |
44 | TestHelper.InMethod(); | 44 | TestHelpers.InMethod(); |
45 | 45 | ||
46 | List<Border> testborders = new List<Border>(); | 46 | List<Border> testborders = new List<Border>(); |
47 | 47 | ||
@@ -99,7 +99,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
99 | [Test] | 99 | [Test] |
100 | public void TestCrossSquare512() | 100 | public void TestCrossSquare512() |
101 | { | 101 | { |
102 | TestHelper.InMethod(); | 102 | TestHelpers.InMethod(); |
103 | 103 | ||
104 | List<Border> testborders = new List<Border>(); | 104 | List<Border> testborders = new List<Border>(); |
105 | 105 | ||
@@ -179,7 +179,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
179 | [Test] | 179 | [Test] |
180 | public void TestCrossRectangle512x256() | 180 | public void TestCrossRectangle512x256() |
181 | { | 181 | { |
182 | TestHelper.InMethod(); | 182 | TestHelpers.InMethod(); |
183 | 183 | ||
184 | List<Border> testborders = new List<Border>(); | 184 | List<Border> testborders = new List<Border>(); |
185 | 185 | ||
@@ -259,7 +259,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
259 | [Test] | 259 | [Test] |
260 | public void TestCrossOdd512x512w256hole() | 260 | public void TestCrossOdd512x512w256hole() |
261 | { | 261 | { |
262 | TestHelper.InMethod(); | 262 | TestHelpers.InMethod(); |
263 | 263 | ||
264 | List<Border> testborders = new List<Border>(); | 264 | List<Border> testborders = new List<Border>(); |
265 | // 512____ | 265 | // 512____ |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/EntityManagerTests.cs b/OpenSim/Region/Framework/Scenes/Tests/EntityManagerTests.cs index f69a4b4..a5d2b23 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/EntityManagerTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/EntityManagerTests.cs | |||
@@ -45,12 +45,12 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
45 | { | 45 | { |
46 | static public Random random; | 46 | static public Random random; |
47 | SceneObjectGroup found; | 47 | SceneObjectGroup found; |
48 | Scene scene = SceneSetupHelpers.SetupScene(); | 48 | Scene scene = SceneHelpers.SetupScene(); |
49 | 49 | ||
50 | [Test] | 50 | [Test] |
51 | public void T010_AddObjects() | 51 | public void T010_AddObjects() |
52 | { | 52 | { |
53 | TestHelper.InMethod(); | 53 | TestHelpers.InMethod(); |
54 | 54 | ||
55 | random = new Random(); | 55 | random = new Random(); |
56 | SceneObjectGroup found; | 56 | SceneObjectGroup found; |
@@ -85,7 +85,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
85 | [Test] | 85 | [Test] |
86 | public void T011_ThreadAddRemoveTest() | 86 | public void T011_ThreadAddRemoveTest() |
87 | { | 87 | { |
88 | TestHelper.InMethod(); | 88 | TestHelpers.InMethod(); |
89 | 89 | ||
90 | // This test adds and removes with mutiple threads, attempting to break the | 90 | // This test adds and removes with mutiple threads, attempting to break the |
91 | // uuid and localid dictionary coherence. | 91 | // uuid and localid dictionary coherence. |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneGraphTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneGraphTests.cs index 895f2bb..9a60e50 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneGraphTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneGraphTests.cs | |||
@@ -43,8 +43,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
43 | [Test] | 43 | [Test] |
44 | public void TestDuplicateObject() | 44 | public void TestDuplicateObject() |
45 | { | 45 | { |
46 | TestHelper.InMethod(); | 46 | TestHelpers.InMethod(); |
47 | Scene scene = SceneSetupHelpers.SetupScene(); | 47 | Scene scene = SceneHelpers.SetupScene(); |
48 | 48 | ||
49 | UUID ownerId = new UUID("00000000-0000-0000-0000-000000000010"); | 49 | UUID ownerId = new UUID("00000000-0000-0000-0000-000000000010"); |
50 | string part1Name = "part1"; | 50 | string part1Name = "part1"; |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs index 0a82c4f..1ea2329 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs | |||
@@ -49,9 +49,9 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
49 | [Test] | 49 | [Test] |
50 | public void TestAddSceneObject() | 50 | public void TestAddSceneObject() |
51 | { | 51 | { |
52 | TestHelper.InMethod(); | 52 | TestHelpers.InMethod(); |
53 | 53 | ||
54 | Scene scene = SceneSetupHelpers.SetupScene(); | 54 | Scene scene = SceneHelpers.SetupScene(); |
55 | 55 | ||
56 | string objName = "obj1"; | 56 | string objName = "obj1"; |
57 | UUID objUuid = new UUID("00000000-0000-0000-0000-000000000001"); | 57 | UUID objUuid = new UUID("00000000-0000-0000-0000-000000000001"); |
@@ -76,9 +76,9 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
76 | /// </summary> | 76 | /// </summary> |
77 | public void TestAddExistingSceneObjectUuid() | 77 | public void TestAddExistingSceneObjectUuid() |
78 | { | 78 | { |
79 | TestHelper.InMethod(); | 79 | TestHelpers.InMethod(); |
80 | 80 | ||
81 | Scene scene = SceneSetupHelpers.SetupScene(); | 81 | Scene scene = SceneHelpers.SetupScene(); |
82 | 82 | ||
83 | string obj1Name = "Alfred"; | 83 | string obj1Name = "Alfred"; |
84 | string obj2Name = "Betty"; | 84 | string obj2Name = "Betty"; |
@@ -110,10 +110,10 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
110 | [Test] | 110 | [Test] |
111 | public void TestDeleteSceneObject() | 111 | public void TestDeleteSceneObject() |
112 | { | 112 | { |
113 | TestHelper.InMethod(); | 113 | TestHelpers.InMethod(); |
114 | 114 | ||
115 | TestScene scene = SceneSetupHelpers.SetupScene(); | 115 | TestScene scene = SceneHelpers.SetupScene(); |
116 | SceneObjectPart part = SceneSetupHelpers.AddSceneObject(scene); | 116 | SceneObjectPart part = SceneHelpers.AddSceneObject(scene); |
117 | scene.DeleteSceneObject(part.ParentGroup, false); | 117 | scene.DeleteSceneObject(part.ParentGroup, false); |
118 | 118 | ||
119 | SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId); | 119 | SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId); |
@@ -126,20 +126,20 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
126 | [Test] | 126 | [Test] |
127 | public void TestDeleteSceneObjectAsync() | 127 | public void TestDeleteSceneObjectAsync() |
128 | { | 128 | { |
129 | TestHelper.InMethod(); | 129 | TestHelpers.InMethod(); |
130 | //log4net.Config.XmlConfigurator.Configure(); | 130 | //log4net.Config.XmlConfigurator.Configure(); |
131 | 131 | ||
132 | UUID agentId = UUID.Parse("00000000-0000-0000-0000-000000000001"); | 132 | UUID agentId = UUID.Parse("00000000-0000-0000-0000-000000000001"); |
133 | 133 | ||
134 | TestScene scene = SceneSetupHelpers.SetupScene(); | 134 | TestScene scene = SceneHelpers.SetupScene(); |
135 | 135 | ||
136 | // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. | 136 | // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. |
137 | AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter; | 137 | AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter; |
138 | sogd.Enabled = false; | 138 | sogd.Enabled = false; |
139 | 139 | ||
140 | SceneObjectPart part = SceneSetupHelpers.AddSceneObject(scene); | 140 | SceneObjectPart part = SceneHelpers.AddSceneObject(scene); |
141 | 141 | ||
142 | IClientAPI client = SceneSetupHelpers.AddRootAgent(scene, agentId); | 142 | IClientAPI client = SceneHelpers.AddScenePresence(scene, agentId).ControllingClient; |
143 | scene.DeRezObjects(client, new System.Collections.Generic.List<uint>() { part.LocalId }, UUID.Zero, DeRezAction.Delete, UUID.Zero); | 143 | scene.DeRezObjects(client, new System.Collections.Generic.List<uint>() { part.LocalId }, UUID.Zero, DeRezAction.Delete, UUID.Zero); |
144 | 144 | ||
145 | SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId); | 145 | SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId); |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs index 5357a06..654b1a2 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs | |||
@@ -56,17 +56,17 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
56 | [Test] | 56 | [Test] |
57 | public void TestDeRezSceneObject() | 57 | public void TestDeRezSceneObject() |
58 | { | 58 | { |
59 | TestHelper.InMethod(); | 59 | TestHelpers.InMethod(); |
60 | // log4net.Config.XmlConfigurator.Configure(); | 60 | // log4net.Config.XmlConfigurator.Configure(); |
61 | 61 | ||
62 | UUID userId = UUID.Parse("10000000-0000-0000-0000-000000000001"); | 62 | UUID userId = UUID.Parse("10000000-0000-0000-0000-000000000001"); |
63 | 63 | ||
64 | TestScene scene = SceneSetupHelpers.SetupScene(); | 64 | TestScene scene = SceneHelpers.SetupScene(); |
65 | IConfigSource configSource = new IniConfigSource(); | 65 | IConfigSource configSource = new IniConfigSource(); |
66 | IConfig config = configSource.AddConfig("Startup"); | 66 | IConfig config = configSource.AddConfig("Startup"); |
67 | config.Set("serverside_object_permissions", true); | 67 | config.Set("serverside_object_permissions", true); |
68 | SceneSetupHelpers.SetupSceneModules(scene, configSource, new object[] { new PermissionsModule() }); | 68 | SceneHelpers.SetupSceneModules(scene, configSource, new object[] { new PermissionsModule() }); |
69 | TestClient client = SceneSetupHelpers.AddRootAgent(scene, userId); | 69 | IClientAPI client = SceneHelpers.AddScenePresence(scene, userId).ControllingClient; |
70 | 70 | ||
71 | // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. | 71 | // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. |
72 | AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter; | 72 | AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter; |
@@ -94,18 +94,18 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
94 | [Test] | 94 | [Test] |
95 | public void TestDeRezSceneObjectNotOwner() | 95 | public void TestDeRezSceneObjectNotOwner() |
96 | { | 96 | { |
97 | TestHelper.InMethod(); | 97 | TestHelpers.InMethod(); |
98 | // log4net.Config.XmlConfigurator.Configure(); | 98 | // log4net.Config.XmlConfigurator.Configure(); |
99 | 99 | ||
100 | UUID userId = UUID.Parse("10000000-0000-0000-0000-000000000001"); | 100 | UUID userId = UUID.Parse("10000000-0000-0000-0000-000000000001"); |
101 | UUID objectOwnerId = UUID.Parse("20000000-0000-0000-0000-000000000001"); | 101 | UUID objectOwnerId = UUID.Parse("20000000-0000-0000-0000-000000000001"); |
102 | 102 | ||
103 | TestScene scene = SceneSetupHelpers.SetupScene(); | 103 | TestScene scene = SceneHelpers.SetupScene(); |
104 | IConfigSource configSource = new IniConfigSource(); | 104 | IConfigSource configSource = new IniConfigSource(); |
105 | IConfig config = configSource.AddConfig("Startup"); | 105 | IConfig config = configSource.AddConfig("Startup"); |
106 | config.Set("serverside_object_permissions", true); | 106 | config.Set("serverside_object_permissions", true); |
107 | SceneSetupHelpers.SetupSceneModules(scene, configSource, new object[] { new PermissionsModule() }); | 107 | SceneHelpers.SetupSceneModules(scene, configSource, new object[] { new PermissionsModule() }); |
108 | TestClient client = SceneSetupHelpers.AddRootAgent(scene, userId); | 108 | IClientAPI client = SceneHelpers.AddScenePresence(scene, userId).ControllingClient; |
109 | 109 | ||
110 | // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. | 110 | // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. |
111 | AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter; | 111 | AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter; |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs index cb1d531..2912a46 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs | |||
@@ -50,14 +50,14 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
50 | [Test] | 50 | [Test] |
51 | public void TestLinkDelink2SceneObjects() | 51 | public void TestLinkDelink2SceneObjects() |
52 | { | 52 | { |
53 | TestHelper.InMethod(); | 53 | TestHelpers.InMethod(); |
54 | 54 | ||
55 | bool debugtest = false; | 55 | bool debugtest = false; |
56 | 56 | ||
57 | Scene scene = SceneSetupHelpers.SetupScene(); | 57 | Scene scene = SceneHelpers.SetupScene(); |
58 | SceneObjectPart part1 = SceneSetupHelpers.AddSceneObject(scene); | 58 | SceneObjectPart part1 = SceneHelpers.AddSceneObject(scene); |
59 | SceneObjectGroup grp1 = part1.ParentGroup; | 59 | SceneObjectGroup grp1 = part1.ParentGroup; |
60 | SceneObjectPart part2 = SceneSetupHelpers.AddSceneObject(scene); | 60 | SceneObjectPart part2 = SceneHelpers.AddSceneObject(scene); |
61 | SceneObjectGroup grp2 = part2.ParentGroup; | 61 | SceneObjectGroup grp2 = part2.ParentGroup; |
62 | 62 | ||
63 | grp1.AbsolutePosition = new Vector3(10, 10, 10); | 63 | grp1.AbsolutePosition = new Vector3(10, 10, 10); |
@@ -132,18 +132,18 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
132 | [Test] | 132 | [Test] |
133 | public void TestLinkDelink2groups4SceneObjects() | 133 | public void TestLinkDelink2groups4SceneObjects() |
134 | { | 134 | { |
135 | TestHelper.InMethod(); | 135 | TestHelpers.InMethod(); |
136 | 136 | ||
137 | bool debugtest = false; | 137 | bool debugtest = false; |
138 | 138 | ||
139 | Scene scene = SceneSetupHelpers.SetupScene(); | 139 | Scene scene = SceneHelpers.SetupScene(); |
140 | SceneObjectPart part1 = SceneSetupHelpers.AddSceneObject(scene); | 140 | SceneObjectPart part1 = SceneHelpers.AddSceneObject(scene); |
141 | SceneObjectGroup grp1 = part1.ParentGroup; | 141 | SceneObjectGroup grp1 = part1.ParentGroup; |
142 | SceneObjectPart part2 = SceneSetupHelpers.AddSceneObject(scene); | 142 | SceneObjectPart part2 = SceneHelpers.AddSceneObject(scene); |
143 | SceneObjectGroup grp2 = part2.ParentGroup; | 143 | SceneObjectGroup grp2 = part2.ParentGroup; |
144 | SceneObjectPart part3 = SceneSetupHelpers.AddSceneObject(scene); | 144 | SceneObjectPart part3 = SceneHelpers.AddSceneObject(scene); |
145 | SceneObjectGroup grp3 = part3.ParentGroup; | 145 | SceneObjectGroup grp3 = part3.ParentGroup; |
146 | SceneObjectPart part4 = SceneSetupHelpers.AddSceneObject(scene); | 146 | SceneObjectPart part4 = SceneHelpers.AddSceneObject(scene); |
147 | SceneObjectGroup grp4 = part4.ParentGroup; | 147 | SceneObjectGroup grp4 = part4.ParentGroup; |
148 | 148 | ||
149 | grp1.AbsolutePosition = new Vector3(10, 10, 10); | 149 | grp1.AbsolutePosition = new Vector3(10, 10, 10); |
@@ -266,10 +266,10 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
266 | [Test] | 266 | [Test] |
267 | public void TestNewSceneObjectLinkPersistence() | 267 | public void TestNewSceneObjectLinkPersistence() |
268 | { | 268 | { |
269 | TestHelper.InMethod(); | 269 | TestHelpers.InMethod(); |
270 | //log4net.Config.XmlConfigurator.Configure(); | 270 | //log4net.Config.XmlConfigurator.Configure(); |
271 | 271 | ||
272 | TestScene scene = SceneSetupHelpers.SetupScene(); | 272 | TestScene scene = SceneHelpers.SetupScene(); |
273 | 273 | ||
274 | string rootPartName = "rootpart"; | 274 | string rootPartName = "rootpart"; |
275 | UUID rootPartUuid = new UUID("00000000-0000-0000-0000-000000000001"); | 275 | UUID rootPartUuid = new UUID("00000000-0000-0000-0000-000000000001"); |
@@ -305,10 +305,10 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
305 | [Test] | 305 | [Test] |
306 | public void TestDelinkPersistence() | 306 | public void TestDelinkPersistence() |
307 | { | 307 | { |
308 | TestHelper.InMethod(); | 308 | TestHelpers.InMethod(); |
309 | //log4net.Config.XmlConfigurator.Configure(); | 309 | //log4net.Config.XmlConfigurator.Configure(); |
310 | 310 | ||
311 | TestScene scene = SceneSetupHelpers.SetupScene(); | 311 | TestScene scene = SceneHelpers.SetupScene(); |
312 | 312 | ||
313 | string rootPartName = "rootpart"; | 313 | string rootPartName = "rootpart"; |
314 | UUID rootPartUuid = new UUID("00000000-0000-0000-0000-000000000001"); | 314 | UUID rootPartUuid = new UUID("00000000-0000-0000-0000-000000000001"); |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectResizeTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectResizeTests.cs new file mode 100644 index 0000000..b49c6e7 --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectResizeTests.cs | |||
@@ -0,0 +1,104 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Reflection; | ||
30 | using NUnit.Framework; | ||
31 | using OpenMetaverse; | ||
32 | using OpenSim.Framework; | ||
33 | using OpenSim.Framework.Communications; | ||
34 | using OpenSim.Region.Framework.Scenes; | ||
35 | using OpenSim.Tests.Common; | ||
36 | using OpenSim.Tests.Common.Mock; | ||
37 | |||
38 | namespace OpenSim.Region.Framework.Scenes.Tests | ||
39 | { | ||
40 | /// <summary> | ||
41 | /// Basic scene object resize tests | ||
42 | /// </summary> | ||
43 | [TestFixture] | ||
44 | public class SceneObjectResizeTests | ||
45 | { | ||
46 | /// <summary> | ||
47 | /// Test resizing an object | ||
48 | /// </summary> | ||
49 | [Test] | ||
50 | public void TestResizeSceneObject() | ||
51 | { | ||
52 | TestHelpers.InMethod(); | ||
53 | // log4net.Config.XmlConfigurator.Configure(); | ||
54 | |||
55 | Scene scene = SceneHelpers.SetupScene(); | ||
56 | SceneObjectGroup g1 = SceneHelpers.AddSceneObject(scene).ParentGroup; | ||
57 | |||
58 | g1.GroupResize(new Vector3(2, 3, 4)); | ||
59 | |||
60 | SceneObjectGroup g1Post = scene.GetSceneObjectGroup(g1.UUID); | ||
61 | |||
62 | Assert.That(g1Post.RootPart.Scale.X, Is.EqualTo(2)); | ||
63 | Assert.That(g1Post.RootPart.Scale.Y, Is.EqualTo(3)); | ||
64 | Assert.That(g1Post.RootPart.Scale.Z, Is.EqualTo(4)); | ||
65 | |||
66 | Assert.That(g1Post.RootPart.UndoCount, Is.EqualTo(1)); | ||
67 | } | ||
68 | |||
69 | /// <summary> | ||
70 | /// Test resizing an individual part in a scene object. | ||
71 | /// </summary> | ||
72 | [Test] | ||
73 | public void TestResizeSceneObjectPart() | ||
74 | { | ||
75 | TestHelpers.InMethod(); | ||
76 | //log4net.Config.XmlConfigurator.Configure(); | ||
77 | |||
78 | Scene scene = SceneHelpers.SetupScene(); | ||
79 | |||
80 | SceneObjectGroup g1 = SceneHelpers.CreateSceneObject(2, UUID.Zero); | ||
81 | g1.RootPart.Scale = new Vector3(2, 3, 4); | ||
82 | g1.Parts[1].Scale = new Vector3(5, 6, 7); | ||
83 | |||
84 | scene.AddSceneObject(g1); | ||
85 | |||
86 | SceneObjectGroup g1Post = scene.GetSceneObjectGroup(g1.UUID); | ||
87 | |||
88 | g1Post.Parts[1].Resize(new Vector3(8, 9, 10)); | ||
89 | |||
90 | SceneObjectGroup g1PostPost = scene.GetSceneObjectGroup(g1.UUID); | ||
91 | |||
92 | SceneObjectPart g1RootPart = g1PostPost.RootPart; | ||
93 | SceneObjectPart g1ChildPart = g1PostPost.Parts[1]; | ||
94 | |||
95 | Assert.That(g1RootPart.Scale.X, Is.EqualTo(2)); | ||
96 | Assert.That(g1RootPart.Scale.Y, Is.EqualTo(3)); | ||
97 | Assert.That(g1RootPart.Scale.Z, Is.EqualTo(4)); | ||
98 | |||
99 | Assert.That(g1ChildPart.Scale.X, Is.EqualTo(8)); | ||
100 | Assert.That(g1ChildPart.Scale.Y, Is.EqualTo(9)); | ||
101 | Assert.That(g1ChildPart.Scale.Z, Is.EqualTo(10)); | ||
102 | } | ||
103 | } | ||
104 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs new file mode 100644 index 0000000..2a342d5 --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs | |||
@@ -0,0 +1,66 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Reflection; | ||
30 | using NUnit.Framework; | ||
31 | using OpenMetaverse; | ||
32 | using OpenSim.Framework; | ||
33 | using OpenSim.Framework.Communications; | ||
34 | using OpenSim.Region.Framework.Scenes; | ||
35 | using OpenSim.Tests.Common; | ||
36 | using OpenSim.Tests.Common.Mock; | ||
37 | |||
38 | namespace OpenSim.Region.Framework.Scenes.Tests | ||
39 | { | ||
40 | /// <summary> | ||
41 | /// Basic scene object status tests | ||
42 | /// </summary> | ||
43 | [TestFixture] | ||
44 | public class SceneObjectStatusTests | ||
45 | { | ||
46 | [Test] | ||
47 | public void TestSetPhantom() | ||
48 | { | ||
49 | TestHelpers.InMethod(); | ||
50 | |||
51 | // Scene scene = SceneSetupHelpers.SetupScene(); | ||
52 | SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, UUID.Zero); | ||
53 | SceneObjectPart rootPart = so.RootPart; | ||
54 | Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); | ||
55 | |||
56 | so.ScriptSetPhantomStatus(true); | ||
57 | |||
58 | // Console.WriteLine("so.RootPart.Flags [{0}]", so.RootPart.Flags); | ||
59 | Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Phantom)); | ||
60 | |||
61 | so.ScriptSetPhantomStatus(false); | ||
62 | |||
63 | Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); | ||
64 | } | ||
65 | } | ||
66 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectUserGroupTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectUserGroupTests.cs index 77bd4c2..c13d82e 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectUserGroupTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectUserGroupTests.cs | |||
@@ -53,12 +53,12 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
53 | [Test] | 53 | [Test] |
54 | public void TestShareWithGroup() | 54 | public void TestShareWithGroup() |
55 | { | 55 | { |
56 | TestHelper.InMethod(); | 56 | TestHelpers.InMethod(); |
57 | // log4net.Config.XmlConfigurator.Configure(); | 57 | // log4net.Config.XmlConfigurator.Configure(); |
58 | 58 | ||
59 | UUID userId = UUID.Parse("10000000-0000-0000-0000-000000000001"); | 59 | UUID userId = UUID.Parse("10000000-0000-0000-0000-000000000001"); |
60 | 60 | ||
61 | TestScene scene = SceneSetupHelpers.SetupScene(); | 61 | TestScene scene = SceneHelpers.SetupScene(); |
62 | IConfigSource configSource = new IniConfigSource(); | 62 | IConfigSource configSource = new IniConfigSource(); |
63 | 63 | ||
64 | IConfig startupConfig = configSource.AddConfig("Startup"); | 64 | IConfig startupConfig = configSource.AddConfig("Startup"); |
@@ -69,13 +69,13 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
69 | groupsConfig.Set("Module", "GroupsModule"); | 69 | groupsConfig.Set("Module", "GroupsModule"); |
70 | groupsConfig.Set("DebugEnabled", true); | 70 | groupsConfig.Set("DebugEnabled", true); |
71 | 71 | ||
72 | SceneSetupHelpers.SetupSceneModules( | 72 | SceneHelpers.SetupSceneModules( |
73 | scene, configSource, new object[] | 73 | scene, configSource, new object[] |
74 | { new PermissionsModule(), | 74 | { new PermissionsModule(), |
75 | new GroupsModule(), | 75 | new GroupsModule(), |
76 | new MockGroupsServicesConnector() }); | 76 | new MockGroupsServicesConnector() }); |
77 | 77 | ||
78 | TestClient client = SceneSetupHelpers.AddRootAgent(scene, userId); | 78 | IClientAPI client = SceneHelpers.AddScenePresence(scene, userId).ControllingClient; |
79 | 79 | ||
80 | IGroupsModule groupsModule = scene.RequestModuleInterface<IGroupsModule>(); | 80 | IGroupsModule groupsModule = scene.RequestModuleInterface<IGroupsModule>(); |
81 | 81 | ||
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs index 03ac252..ce9d418 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs | |||
@@ -51,7 +51,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
51 | /// Scene presence tests | 51 | /// Scene presence tests |
52 | /// </summary> | 52 | /// </summary> |
53 | [TestFixture] | 53 | [TestFixture] |
54 | public class ScenePresenceTests | 54 | public class ScenePresenceAgentTests |
55 | { | 55 | { |
56 | public Scene scene, scene2, scene3; | 56 | public Scene scene, scene2, scene3; |
57 | public UUID agent1, agent2, agent3; | 57 | public UUID agent1, agent2, agent3; |
@@ -64,90 +64,140 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
64 | [TestFixtureSetUp] | 64 | [TestFixtureSetUp] |
65 | public void Init() | 65 | public void Init() |
66 | { | 66 | { |
67 | TestHelper.InMethod(); | 67 | TestHelpers.InMethod(); |
68 | 68 | ||
69 | scene = SceneSetupHelpers.SetupScene("Neighbour x", UUID.Random(), 1000, 1000); | 69 | scene = SceneHelpers.SetupScene("Neighbour x", UUID.Random(), 1000, 1000); |
70 | scene2 = SceneSetupHelpers.SetupScene("Neighbour x+1", UUID.Random(), 1001, 1000); | 70 | scene2 = SceneHelpers.SetupScene("Neighbour x+1", UUID.Random(), 1001, 1000); |
71 | scene3 = SceneSetupHelpers.SetupScene("Neighbour x-1", UUID.Random(), 999, 1000); | 71 | scene3 = SceneHelpers.SetupScene("Neighbour x-1", UUID.Random(), 999, 1000); |
72 | 72 | ||
73 | ISharedRegionModule interregionComms = new LocalSimulationConnectorModule(); | 73 | ISharedRegionModule interregionComms = new LocalSimulationConnectorModule(); |
74 | interregionComms.Initialise(new IniConfigSource()); | 74 | interregionComms.Initialise(new IniConfigSource()); |
75 | interregionComms.PostInitialise(); | 75 | interregionComms.PostInitialise(); |
76 | SceneSetupHelpers.SetupSceneModules(scene, new IniConfigSource(), interregionComms); | 76 | SceneHelpers.SetupSceneModules(scene, new IniConfigSource(), interregionComms); |
77 | SceneSetupHelpers.SetupSceneModules(scene2, new IniConfigSource(), interregionComms); | 77 | SceneHelpers.SetupSceneModules(scene2, new IniConfigSource(), interregionComms); |
78 | SceneSetupHelpers.SetupSceneModules(scene3, new IniConfigSource(), interregionComms); | 78 | SceneHelpers.SetupSceneModules(scene3, new IniConfigSource(), interregionComms); |
79 | 79 | ||
80 | agent1 = UUID.Random(); | 80 | agent1 = UUID.Random(); |
81 | agent2 = UUID.Random(); | 81 | agent2 = UUID.Random(); |
82 | agent3 = UUID.Random(); | 82 | agent3 = UUID.Random(); |
83 | random = new Random(); | 83 | random = new Random(); |
84 | sog1 = NewSOG(UUID.Random(), scene, agent1); | 84 | sog1 = SceneHelpers.CreateSceneObject(1, agent1); |
85 | sog2 = NewSOG(UUID.Random(), scene, agent1); | 85 | scene.AddSceneObject(sog1); |
86 | sog3 = NewSOG(UUID.Random(), scene, agent1); | 86 | sog2 = SceneHelpers.CreateSceneObject(1, agent1); |
87 | scene.AddSceneObject(sog2); | ||
88 | sog3 = SceneHelpers.CreateSceneObject(1, agent1); | ||
89 | scene.AddSceneObject(sog3); | ||
87 | 90 | ||
88 | //ulong neighbourHandle = Utils.UIntsToLong((uint)(neighbourx * Constants.RegionSize), (uint)(neighboury * Constants.RegionSize)); | ||
89 | region1 = scene.RegionInfo.RegionHandle; | 91 | region1 = scene.RegionInfo.RegionHandle; |
90 | region2 = scene2.RegionInfo.RegionHandle; | 92 | region2 = scene2.RegionInfo.RegionHandle; |
91 | region3 = scene3.RegionInfo.RegionHandle; | 93 | region3 = scene3.RegionInfo.RegionHandle; |
92 | } | 94 | } |
93 | 95 | ||
94 | /// <summary> | ||
95 | /// Test adding a root agent to a scene. Doesn't yet actually complete crossing the agent into the scene. | ||
96 | /// </summary> | ||
97 | [Test] | 96 | [Test] |
98 | public void T010_TestAddRootAgent() | 97 | public void TestCloseAgent() |
99 | { | 98 | { |
100 | TestHelper.InMethod(); | 99 | TestHelpers.InMethod(); |
101 | 100 | // log4net.Config.XmlConfigurator.Configure(); | |
102 | string firstName = "testfirstname"; | ||
103 | |||
104 | AgentCircuitData agent = new AgentCircuitData(); | ||
105 | agent.AgentID = agent1; | ||
106 | agent.firstname = firstName; | ||
107 | agent.lastname = "testlastname"; | ||
108 | agent.SessionID = UUID.Random(); | ||
109 | agent.SecureSessionID = UUID.Random(); | ||
110 | agent.circuitcode = 123; | ||
111 | agent.BaseFolder = UUID.Zero; | ||
112 | agent.InventoryFolder = UUID.Zero; | ||
113 | agent.startpos = Vector3.Zero; | ||
114 | agent.CapsPath = GetRandomCapsObjectPath(); | ||
115 | agent.ChildrenCapSeeds = new Dictionary<ulong, string>(); | ||
116 | agent.child = true; | ||
117 | 101 | ||
118 | scene.PresenceService.LoginAgent(agent.AgentID.ToString(), agent.SessionID, agent.SecureSessionID); | 102 | TestScene scene = SceneHelpers.SetupScene(); |
103 | ScenePresence sp = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x1)); | ||
119 | 104 | ||
120 | string reason; | 105 | Assert.That(scene.AuthenticateHandler.GetAgentCircuitData(sp.UUID), Is.Not.Null); |
121 | scene.NewUserConnection(agent, (uint)TeleportFlags.ViaLogin, out reason); | ||
122 | testclient = new TestClient(agent, scene); | ||
123 | scene.AddNewClient(testclient); | ||
124 | 106 | ||
125 | ScenePresence presence = scene.GetScenePresence(agent1); | 107 | scene.IncomingCloseAgent(sp.UUID); |
126 | 108 | ||
127 | Assert.That(presence, Is.Not.Null, "presence is null"); | 109 | Assert.That(scene.GetScenePresence(sp.UUID), Is.Null); |
128 | Assert.That(presence.Firstname, Is.EqualTo(firstName), "First name not same"); | 110 | Assert.That(scene.AuthenticateHandler.GetAgentCircuitData(sp.UUID), Is.Null); |
129 | acd1 = agent; | ||
130 | } | 111 | } |
131 | 112 | ||
132 | /// <summary> | 113 | /// <summary> |
133 | /// Test removing an uncrossed root agent from a scene. | 114 | /// Test that if a root agent logs into a region, a child agent is also established in the neighbouring region |
134 | /// </summary> | 115 | /// </summary> |
116 | /// <remarks> | ||
117 | /// Please note that unlike the other tests here, this doesn't rely on structures | ||
118 | /// </remarks> | ||
135 | [Test] | 119 | [Test] |
136 | public void T011_TestRemoveRootAgent() | 120 | public void TestChildAgentEstablished() |
137 | { | 121 | { |
138 | TestHelper.InMethod(); | 122 | TestHelpers.InMethod(); |
139 | 123 | // log4net.Config.XmlConfigurator.Configure(); | |
140 | scene.RemoveClient(agent1); | 124 | |
141 | 125 | UUID agent1Id = UUID.Parse("00000000-0000-0000-0000-000000000001"); | |
142 | ScenePresence presence = scene.GetScenePresence(agent1); | 126 | |
127 | TestScene myScene1 = SceneHelpers.SetupScene("Neighbour y", UUID.Random(), 1000, 1000); | ||
128 | // TestScene myScene2 = SceneHelpers.SetupScene("Neighbour y + 1", UUID.Random(), 1001, 1000); | ||
129 | |||
130 | IConfigSource configSource = new IniConfigSource(); | ||
131 | configSource.AddConfig("Modules").Set("EntityTransferModule", "BasicEntityTransferModule"); | ||
132 | EntityTransferModule etm = new EntityTransferModule(); | ||
133 | |||
134 | SceneHelpers.SetupSceneModules(myScene1, configSource, etm); | ||
135 | |||
136 | SceneHelpers.AddScenePresence(myScene1, agent1Id); | ||
137 | // ScenePresence childPresence = myScene2.GetScenePresence(agent1); | ||
143 | 138 | ||
144 | Assert.That(presence, Is.Null, "presence is not null"); | 139 | // TODO: Need to do a fair amount of work to allow synchronous establishment of child agents |
140 | // Assert.That(childPresence, Is.Not.Null); | ||
141 | // Assert.That(childPresence.IsChildAgent, Is.True); | ||
145 | } | 142 | } |
146 | 143 | ||
144 | // /// <summary> | ||
145 | // /// Test adding a root agent to a scene. Doesn't yet actually complete crossing the agent into the scene. | ||
146 | // /// </summary> | ||
147 | // [Test] | ||
148 | // public void T010_TestAddRootAgent() | ||
149 | // { | ||
150 | // TestHelpers.InMethod(); | ||
151 | // | ||
152 | // string firstName = "testfirstname"; | ||
153 | // | ||
154 | // AgentCircuitData agent = new AgentCircuitData(); | ||
155 | // agent.AgentID = agent1; | ||
156 | // agent.firstname = firstName; | ||
157 | // agent.lastname = "testlastname"; | ||
158 | // agent.SessionID = UUID.Random(); | ||
159 | // agent.SecureSessionID = UUID.Random(); | ||
160 | // agent.circuitcode = 123; | ||
161 | // agent.BaseFolder = UUID.Zero; | ||
162 | // agent.InventoryFolder = UUID.Zero; | ||
163 | // agent.startpos = Vector3.Zero; | ||
164 | // agent.CapsPath = GetRandomCapsObjectPath(); | ||
165 | // agent.ChildrenCapSeeds = new Dictionary<ulong, string>(); | ||
166 | // agent.child = true; | ||
167 | // | ||
168 | // scene.PresenceService.LoginAgent(agent.AgentID.ToString(), agent.SessionID, agent.SecureSessionID); | ||
169 | // | ||
170 | // string reason; | ||
171 | // scene.NewUserConnection(agent, (uint)TeleportFlags.ViaLogin, out reason); | ||
172 | // testclient = new TestClient(agent, scene); | ||
173 | // scene.AddNewClient(testclient); | ||
174 | // | ||
175 | // ScenePresence presence = scene.GetScenePresence(agent1); | ||
176 | // | ||
177 | // Assert.That(presence, Is.Not.Null, "presence is null"); | ||
178 | // Assert.That(presence.Firstname, Is.EqualTo(firstName), "First name not same"); | ||
179 | // acd1 = agent; | ||
180 | // } | ||
181 | // | ||
182 | // /// <summary> | ||
183 | // /// Test removing an uncrossed root agent from a scene. | ||
184 | // /// </summary> | ||
185 | // [Test] | ||
186 | // public void T011_TestRemoveRootAgent() | ||
187 | // { | ||
188 | // TestHelpers.InMethod(); | ||
189 | // | ||
190 | // scene.RemoveClient(agent1); | ||
191 | // | ||
192 | // ScenePresence presence = scene.GetScenePresence(agent1); | ||
193 | // | ||
194 | // Assert.That(presence, Is.Null, "presence is not null"); | ||
195 | // } | ||
196 | |||
147 | [Test] | 197 | [Test] |
148 | public void T012_TestAddNeighbourRegion() | 198 | public void T012_TestAddNeighbourRegion() |
149 | { | 199 | { |
150 | TestHelper.InMethod(); | 200 | TestHelpers.InMethod(); |
151 | 201 | ||
152 | string reason; | 202 | string reason; |
153 | 203 | ||
@@ -157,7 +207,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
157 | scene.NewUserConnection(acd1, 0, out reason); | 207 | scene.NewUserConnection(acd1, 0, out reason); |
158 | if (testclient == null) | 208 | if (testclient == null) |
159 | testclient = new TestClient(acd1, scene); | 209 | testclient = new TestClient(acd1, scene); |
160 | scene.AddNewClient(testclient); | 210 | scene.AddNewClient(testclient, PresenceType.User); |
161 | 211 | ||
162 | ScenePresence presence = scene.GetScenePresence(agent1); | 212 | ScenePresence presence = scene.GetScenePresence(agent1); |
163 | presence.MakeRootAgent(new Vector3(90,90,90),false); | 213 | presence.MakeRootAgent(new Vector3(90,90,90),false); |
@@ -175,7 +225,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
175 | [Test] | 225 | [Test] |
176 | public void T013_TestRemoveNeighbourRegion() | 226 | public void T013_TestRemoveNeighbourRegion() |
177 | { | 227 | { |
178 | TestHelper.InMethod(); | 228 | TestHelpers.InMethod(); |
179 | 229 | ||
180 | ScenePresence presence = scene.GetScenePresence(agent1); | 230 | ScenePresence presence = scene.GetScenePresence(agent1); |
181 | presence.RemoveNeighbourRegion(region3); | 231 | presence.RemoveNeighbourRegion(region3); |
@@ -188,37 +238,6 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
188 | CompleteAvatarMovement | 238 | CompleteAvatarMovement |
189 | */ | 239 | */ |
190 | } | 240 | } |
191 | |||
192 | /// <summary> | ||
193 | /// Test that if a root agent logs into a region, a child agent is also established in the neighbouring region | ||
194 | /// </summary> | ||
195 | /// <remarks> | ||
196 | /// Please note that unlike the other tests here, this doesn't rely on structures | ||
197 | /// </remarks> | ||
198 | [Test] | ||
199 | public void TestChildAgentEstablished() | ||
200 | { | ||
201 | TestHelper.InMethod(); | ||
202 | // log4net.Config.XmlConfigurator.Configure(); | ||
203 | |||
204 | UUID agent1Id = UUID.Parse("00000000-0000-0000-0000-000000000001"); | ||
205 | |||
206 | TestScene myScene1 = SceneSetupHelpers.SetupScene("Neighbour y", UUID.Random(), 1000, 1000); | ||
207 | TestScene myScene2 = SceneSetupHelpers.SetupScene("Neighbour y + 1", UUID.Random(), 1001, 1000); | ||
208 | |||
209 | IConfigSource configSource = new IniConfigSource(); | ||
210 | configSource.AddConfig("Modules").Set("EntityTransferModule", "BasicEntityTransferModule"); | ||
211 | EntityTransferModule etm = new EntityTransferModule(); | ||
212 | |||
213 | SceneSetupHelpers.SetupSceneModules(myScene1, configSource, etm); | ||
214 | |||
215 | SceneSetupHelpers.AddRootAgent(myScene1, agent1Id); | ||
216 | ScenePresence childPresence = myScene2.GetScenePresence(agent1); | ||
217 | |||
218 | // TODO: Need to do a fair amount of work to allow synchronous establishment of child agents | ||
219 | // Assert.That(childPresence, Is.Not.Null); | ||
220 | // Assert.That(childPresence.IsChildAgent, Is.True); | ||
221 | } | ||
222 | 241 | ||
223 | // I'm commenting this test because it does not represent | 242 | // I'm commenting this test because it does not represent |
224 | // crossings. The Thread.Sleep's in here are not meaningful mocks, | 243 | // crossings. The Thread.Sleep's in here are not meaningful mocks, |
@@ -230,7 +249,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
230 | //[Test] | 249 | //[Test] |
231 | public void T021_TestCrossToNewRegion() | 250 | public void T021_TestCrossToNewRegion() |
232 | { | 251 | { |
233 | TestHelper.InMethod(); | 252 | TestHelpers.InMethod(); |
234 | 253 | ||
235 | scene.RegisterRegionWithGrid(); | 254 | scene.RegisterRegionWithGrid(); |
236 | scene2.RegisterRegionWithGrid(); | 255 | scene2.RegisterRegionWithGrid(); |
@@ -238,7 +257,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
238 | // Adding child agent to region 1001 | 257 | // Adding child agent to region 1001 |
239 | string reason; | 258 | string reason; |
240 | scene2.NewUserConnection(acd1,0, out reason); | 259 | scene2.NewUserConnection(acd1,0, out reason); |
241 | scene2.AddNewClient(testclient); | 260 | scene2.AddNewClient(testclient, PresenceType.User); |
242 | 261 | ||
243 | ScenePresence presence = scene.GetScenePresence(agent1); | 262 | ScenePresence presence = scene.GetScenePresence(agent1); |
244 | presence.MakeRootAgent(new Vector3(0,unchecked(Constants.RegionSize-1),0), true); | 263 | presence.MakeRootAgent(new Vector3(0,unchecked(Constants.RegionSize-1),0), true); |
@@ -338,6 +357,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
338 | agent.InventoryFolder = UUID.Zero; | 357 | agent.InventoryFolder = UUID.Zero; |
339 | agent.startpos = Vector3.Zero; | 358 | agent.startpos = Vector3.Zero; |
340 | agent.CapsPath = GetRandomCapsObjectPath(); | 359 | agent.CapsPath = GetRandomCapsObjectPath(); |
360 | agent.Appearance = new AvatarAppearance(); | ||
341 | 361 | ||
342 | acd1 = agent; | 362 | acd1 = agent; |
343 | } | 363 | } |
@@ -349,37 +369,5 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
349 | capsPath = capsPath.Remove(capsPath.Length - 4, 4); | 369 | capsPath = capsPath.Remove(capsPath.Length - 4, 4); |
350 | return capsPath; | 370 | return capsPath; |
351 | } | 371 | } |
352 | |||
353 | private SceneObjectGroup NewSOG(UUID uuid, Scene scene, UUID agent) | ||
354 | { | ||
355 | SceneObjectPart sop = new SceneObjectPart(); | ||
356 | sop.Name = RandomName(); | ||
357 | sop.Description = RandomName(); | ||
358 | sop.Text = RandomName(); | ||
359 | sop.SitName = RandomName(); | ||
360 | sop.TouchName = RandomName(); | ||
361 | sop.UUID = uuid; | ||
362 | sop.Shape = PrimitiveBaseShape.Default; | ||
363 | sop.Shape.State = 1; | ||
364 | sop.OwnerID = agent; | ||
365 | |||
366 | SceneObjectGroup sog = new SceneObjectGroup(sop); | ||
367 | sog.SetScene(scene); | ||
368 | |||
369 | return sog; | ||
370 | } | ||
371 | |||
372 | private static string RandomName() | ||
373 | { | ||
374 | StringBuilder name = new StringBuilder(); | ||
375 | int size = random.Next(5,12); | ||
376 | char ch ; | ||
377 | for (int i=0; i<size; i++) | ||
378 | { | ||
379 | ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65))) ; | ||
380 | name.Append(ch); | ||
381 | } | ||
382 | return name.ToString(); | ||
383 | } | ||
384 | } | 372 | } |
385 | } \ No newline at end of file | 373 | } \ No newline at end of file |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/StandaloneTeleportTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs index 1b5a54e..39bb43a 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/StandaloneTeleportTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs | |||
@@ -44,7 +44,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
44 | /// Teleport tests in a standalone OpenSim | 44 | /// Teleport tests in a standalone OpenSim |
45 | /// </summary> | 45 | /// </summary> |
46 | [TestFixture] | 46 | [TestFixture] |
47 | public class StandaloneTeleportTests | 47 | public class ScenePresenceTeleportTests |
48 | { | 48 | { |
49 | /// <summary> | 49 | /// <summary> |
50 | /// Test a teleport between two regions that are not neighbours and do not share any neighbours in common. | 50 | /// Test a teleport between two regions that are not neighbours and do not share any neighbours in common. |
@@ -54,7 +54,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
54 | //[Test, LongRunning] | 54 | //[Test, LongRunning] |
55 | public void TestSimpleNotNeighboursTeleport() | 55 | public void TestSimpleNotNeighboursTeleport() |
56 | { | 56 | { |
57 | TestHelper.InMethod(); | 57 | TestHelpers.InMethod(); |
58 | ThreadRunResults results = new ThreadRunResults(); | 58 | ThreadRunResults results = new ThreadRunResults(); |
59 | results.Result = false; | 59 | results.Result = false; |
60 | results.Message = "Test did not run"; | 60 | results.Message = "Test did not run"; |
@@ -116,16 +116,16 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
116 | ISharedRegionModule interregionComms = new LocalSimulationConnectorModule(); | 116 | ISharedRegionModule interregionComms = new LocalSimulationConnectorModule(); |
117 | 117 | ||
118 | 118 | ||
119 | Scene sceneB = SceneSetupHelpers.SetupScene("sceneB", sceneBId, 1010, 1010); | 119 | Scene sceneB = SceneHelpers.SetupScene("sceneB", sceneBId, 1010, 1010); |
120 | SceneSetupHelpers.SetupSceneModules(sceneB, new IniConfigSource(), interregionComms); | 120 | SceneHelpers.SetupSceneModules(sceneB, new IniConfigSource(), interregionComms); |
121 | sceneB.RegisterRegionWithGrid(); | 121 | sceneB.RegisterRegionWithGrid(); |
122 | 122 | ||
123 | Scene sceneA = SceneSetupHelpers.SetupScene("sceneA", sceneAId, 1000, 1000); | 123 | Scene sceneA = SceneHelpers.SetupScene("sceneA", sceneAId, 1000, 1000); |
124 | SceneSetupHelpers.SetupSceneModules(sceneA, new IniConfigSource(), interregionComms); | 124 | SceneHelpers.SetupSceneModules(sceneA, new IniConfigSource(), interregionComms); |
125 | sceneA.RegisterRegionWithGrid(); | 125 | sceneA.RegisterRegionWithGrid(); |
126 | 126 | ||
127 | UUID agentId = UUID.Parse("00000000-0000-0000-0000-000000000041"); | 127 | UUID agentId = UUID.Parse("00000000-0000-0000-0000-000000000041"); |
128 | TestClient client = SceneSetupHelpers.AddRootAgent(sceneA, agentId); | 128 | TestClient client = (TestClient)SceneHelpers.AddScenePresence(sceneA, agentId).ControllingClient; |
129 | 129 | ||
130 | ICapabilitiesModule sceneACapsModule = sceneA.RequestModuleInterface<ICapabilitiesModule>(); | 130 | ICapabilitiesModule sceneACapsModule = sceneA.RequestModuleInterface<ICapabilitiesModule>(); |
131 | 131 | ||
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs index 13d93f9..8b8aea5 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs | |||
@@ -58,9 +58,9 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
58 | [Test] | 58 | [Test] |
59 | public void TestUpdateScene() | 59 | public void TestUpdateScene() |
60 | { | 60 | { |
61 | TestHelper.InMethod(); | 61 | TestHelpers.InMethod(); |
62 | 62 | ||
63 | Scene scene = SceneSetupHelpers.SetupScene(); | 63 | Scene scene = SceneHelpers.SetupScene(); |
64 | scene.Update(); | 64 | scene.Update(); |
65 | 65 | ||
66 | Assert.That(scene.Frame, Is.EqualTo(1)); | 66 | Assert.That(scene.Frame, Is.EqualTo(1)); |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs b/OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs index f4e14d4..1abef8d 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs | |||
@@ -55,12 +55,12 @@ namespace OpenSim.Region.Framework.Tests | |||
55 | [Test] | 55 | [Test] |
56 | public void TestRezObjectFromInventoryItem() | 56 | public void TestRezObjectFromInventoryItem() |
57 | { | 57 | { |
58 | TestHelper.InMethod(); | 58 | TestHelpers.InMethod(); |
59 | // log4net.Config.XmlConfigurator.Configure(); | 59 | // log4net.Config.XmlConfigurator.Configure(); |
60 | 60 | ||
61 | Scene scene = SceneSetupHelpers.SetupScene(); | 61 | Scene scene = SceneHelpers.SetupScene(); |
62 | UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene); | 62 | UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene); |
63 | SceneObjectGroup sog1 = SceneSetupHelpers.CreateSceneObject(1, user1.PrincipalID); | 63 | SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, user1.PrincipalID); |
64 | SceneObjectPart sop1 = sog1.RootPart; | 64 | SceneObjectPart sop1 = sog1.RootPart; |
65 | 65 | ||
66 | // Create an object embedded inside the first | 66 | // Create an object embedded inside the first |
@@ -98,12 +98,12 @@ namespace OpenSim.Region.Framework.Tests | |||
98 | [Test] | 98 | [Test] |
99 | public void TestMoveTaskInventoryItem() | 99 | public void TestMoveTaskInventoryItem() |
100 | { | 100 | { |
101 | TestHelper.InMethod(); | 101 | TestHelpers.InMethod(); |
102 | // log4net.Config.XmlConfigurator.Configure(); | 102 | // log4net.Config.XmlConfigurator.Configure(); |
103 | 103 | ||
104 | Scene scene = SceneSetupHelpers.SetupScene(); | 104 | Scene scene = SceneHelpers.SetupScene(); |
105 | UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene); | 105 | UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene); |
106 | SceneObjectGroup sog1 = SceneSetupHelpers.CreateSceneObject(1, user1.PrincipalID); | 106 | SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, user1.PrincipalID); |
107 | SceneObjectPart sop1 = sog1.RootPart; | 107 | SceneObjectPart sop1 = sog1.RootPart; |
108 | TaskInventoryItem sopItem1 = TaskInventoryHelpers.AddNotecard(scene, sop1); | 108 | TaskInventoryItem sopItem1 = TaskInventoryHelpers.AddNotecard(scene, sop1); |
109 | 109 | ||
@@ -125,12 +125,12 @@ namespace OpenSim.Region.Framework.Tests | |||
125 | [Test] | 125 | [Test] |
126 | public void TestMoveTaskInventoryItemNoParent() | 126 | public void TestMoveTaskInventoryItemNoParent() |
127 | { | 127 | { |
128 | TestHelper.InMethod(); | 128 | TestHelpers.InMethod(); |
129 | // log4net.Config.XmlConfigurator.Configure(); | 129 | // log4net.Config.XmlConfigurator.Configure(); |
130 | 130 | ||
131 | Scene scene = SceneSetupHelpers.SetupScene(); | 131 | Scene scene = SceneHelpers.SetupScene(); |
132 | UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene); | 132 | UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene); |
133 | SceneObjectGroup sog1 = SceneSetupHelpers.CreateSceneObject(1, user1.PrincipalID); | 133 | SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, user1.PrincipalID); |
134 | SceneObjectPart sop1 = sog1.RootPart; | 134 | SceneObjectPart sop1 = sog1.RootPart; |
135 | TaskInventoryItem sopItem1 = TaskInventoryHelpers.AddNotecard(scene, sop1); | 135 | TaskInventoryItem sopItem1 = TaskInventoryHelpers.AddNotecard(scene, sop1); |
136 | 136 | ||
diff --git a/OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs b/OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs index abca792..55fc1e7 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs | |||
@@ -55,12 +55,12 @@ namespace OpenSim.Region.Framework.Tests | |||
55 | [Test] | 55 | [Test] |
56 | public void TestGiveInventoryItem() | 56 | public void TestGiveInventoryItem() |
57 | { | 57 | { |
58 | TestHelper.InMethod(); | 58 | TestHelpers.InMethod(); |
59 | // log4net.Config.XmlConfigurator.Configure(); | 59 | // log4net.Config.XmlConfigurator.Configure(); |
60 | 60 | ||
61 | Scene scene = SceneSetupHelpers.SetupScene(); | 61 | Scene scene = SceneHelpers.SetupScene(); |
62 | UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene, 1001); | 62 | UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1001)); |
63 | UserAccount user2 = UserAccountHelpers.CreateUserWithInventory(scene, 1002); | 63 | UserAccount user2 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1002)); |
64 | InventoryItemBase item1 = UserInventoryHelpers.CreateInventoryItem(scene, "item1", user1.PrincipalID); | 64 | InventoryItemBase item1 = UserInventoryHelpers.CreateInventoryItem(scene, "item1", user1.PrincipalID); |
65 | 65 | ||
66 | scene.GiveInventoryItem(user2.PrincipalID, user1.PrincipalID, item1.ID); | 66 | scene.GiveInventoryItem(user2.PrincipalID, user1.PrincipalID, item1.ID); |
@@ -82,12 +82,12 @@ namespace OpenSim.Region.Framework.Tests | |||
82 | [Test] | 82 | [Test] |
83 | public void TestGiveInventoryFolder() | 83 | public void TestGiveInventoryFolder() |
84 | { | 84 | { |
85 | TestHelper.InMethod(); | 85 | TestHelpers.InMethod(); |
86 | // log4net.Config.XmlConfigurator.Configure(); | 86 | // log4net.Config.XmlConfigurator.Configure(); |
87 | 87 | ||
88 | Scene scene = SceneSetupHelpers.SetupScene(); | 88 | Scene scene = SceneHelpers.SetupScene(); |
89 | UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene, 1001); | 89 | UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1001)); |
90 | UserAccount user2 = UserAccountHelpers.CreateUserWithInventory(scene, 1002); | 90 | UserAccount user2 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1002)); |
91 | InventoryFolderBase folder1 | 91 | InventoryFolderBase folder1 |
92 | = UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, user1.PrincipalID, "folder1"); | 92 | = UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, user1.PrincipalID, "folder1"); |
93 | 93 | ||
diff --git a/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs b/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs index 4da8df1..24de56e 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs | |||
@@ -47,7 +47,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
47 | public void Init() | 47 | public void Init() |
48 | { | 48 | { |
49 | // FIXME: We don't need a full scene here - it would be enough to set up the asset service. | 49 | // FIXME: We don't need a full scene here - it would be enough to set up the asset service. |
50 | Scene scene = SceneSetupHelpers.SetupScene(); | 50 | Scene scene = SceneHelpers.SetupScene(); |
51 | m_assetService = scene.AssetService; | 51 | m_assetService = scene.AssetService; |
52 | m_uuidGatherer = new UuidGatherer(m_assetService); | 52 | m_uuidGatherer = new UuidGatherer(m_assetService); |
53 | } | 53 | } |
@@ -55,7 +55,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
55 | [Test] | 55 | [Test] |
56 | public void TestCorruptAsset() | 56 | public void TestCorruptAsset() |
57 | { | 57 | { |
58 | TestHelper.InMethod(); | 58 | TestHelpers.InMethod(); |
59 | 59 | ||
60 | UUID corruptAssetUuid = UUID.Parse("00000000-0000-0000-0000-000000000666"); | 60 | UUID corruptAssetUuid = UUID.Parse("00000000-0000-0000-0000-000000000666"); |
61 | AssetBase corruptAsset | 61 | AssetBase corruptAsset |
@@ -75,7 +75,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
75 | [Test] | 75 | [Test] |
76 | public void TestMissingAsset() | 76 | public void TestMissingAsset() |
77 | { | 77 | { |
78 | TestHelper.InMethod(); | 78 | TestHelpers.InMethod(); |
79 | 79 | ||
80 | UUID missingAssetUuid = UUID.Parse("00000000-0000-0000-0000-000000000666"); | 80 | UUID missingAssetUuid = UUID.Parse("00000000-0000-0000-0000-000000000666"); |
81 | IDictionary<UUID, AssetType> foundAssetUuids = new Dictionary<UUID, AssetType>(); | 81 | IDictionary<UUID, AssetType> foundAssetUuids = new Dictionary<UUID, AssetType>(); |
diff --git a/OpenSim/Region/Framework/Scenes/UndoState.cs b/OpenSim/Region/Framework/Scenes/UndoState.cs index f71b507..81f41db 100644 --- a/OpenSim/Region/Framework/Scenes/UndoState.cs +++ b/OpenSim/Region/Framework/Scenes/UndoState.cs | |||
@@ -25,6 +25,9 @@ | |||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | ||
29 | using System.Reflection; | ||
30 | using log4net; | ||
28 | using OpenMetaverse; | 31 | using OpenMetaverse; |
29 | using OpenSim.Region.Framework.Interfaces; | 32 | using OpenSim.Region.Framework.Interfaces; |
30 | using System; | 33 | using System; |
@@ -47,6 +50,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
47 | 50 | ||
48 | public class UndoState | 51 | public class UndoState |
49 | { | 52 | { |
53 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
54 | |||
50 | public Vector3 Position = Vector3.Zero; | 55 | public Vector3 Position = Vector3.Zero; |
51 | public Vector3 Scale = Vector3.Zero; | 56 | public Vector3 Scale = Vector3.Zero; |
52 | public Quaternion Rotation = Quaternion.Identity; | 57 | public Quaternion Rotation = Quaternion.Identity; |
@@ -56,13 +61,23 @@ namespace OpenSim.Region.Framework.Scenes | |||
56 | public DateTime LastUpdated = DateTime.Now; | 61 | public DateTime LastUpdated = DateTime.Now; |
57 | public UndoType Type; | 62 | public UndoType Type; |
58 | 63 | ||
59 | public UndoState(SceneObjectPart part, UndoType type) | 64 | /// <summary> |
65 | /// Is this undo state for an entire group? | ||
66 | /// </summary> | ||
67 | public bool ForGroup; | ||
68 | |||
69 | /// <summary> | ||
70 | /// Constructor. | ||
71 | /// </summary> | ||
72 | /// <param name="part"></param> | ||
73 | /// <param name="forGroup">True if the undo is for an entire group</param> | ||
74 | public UndoState(SceneObjectPart part, bool forGroup) | ||
60 | { | 75 | { |
61 | Type = type; | 76 | if (part.ParentID == 0) |
62 | if (part != null) | ||
63 | { | 77 | { |
64 | if (part.ParentID == 0) | 78 | ForGroup = forGroup; |
65 | { | 79 | |
80 | // if (ForGroup) | ||
66 | GroupScale = part.ParentGroup.RootPart.Shape.Scale; | 81 | GroupScale = part.ParentGroup.RootPart.Shape.Scale; |
67 | 82 | ||
68 | //FUBAR WARNING: Do NOT get the group's absoluteposition here | 83 | //FUBAR WARNING: Do NOT get the group's absoluteposition here |
@@ -70,23 +85,35 @@ namespace OpenSim.Region.Framework.Scenes | |||
70 | GroupPosition = part.ParentGroup.RootPart.AbsolutePosition; | 85 | GroupPosition = part.ParentGroup.RootPart.AbsolutePosition; |
71 | GroupRotation = part.ParentGroup.GroupRotation; | 86 | GroupRotation = part.ParentGroup.GroupRotation; |
72 | Position = part.ParentGroup.RootPart.AbsolutePosition; | 87 | Position = part.ParentGroup.RootPart.AbsolutePosition; |
73 | Rotation = part.RotationOffset; | 88 | // else |
74 | Scale = part.Shape.Scale; | 89 | // Position = part.OffsetPosition; |
75 | LastUpdated = DateTime.Now; | ||
76 | } | ||
77 | else | ||
78 | { | ||
79 | GroupScale = part.Shape.Scale; | ||
80 | 90 | ||
81 | //FUBAR WARNING: Do NOT get the group's absoluteposition here | 91 | // m_log.DebugFormat( |
82 | //or you'll experience a loop and/or a stack issue | 92 | // "[UNDO STATE]: Storing undo position {0} for root part", Position); |
83 | GroupPosition = part.ParentGroup.RootPart.AbsolutePosition; | 93 | |
84 | GroupRotation = part.ParentGroup.Rotation; | 94 | Rotation = part.RotationOffset; |
85 | Position = part.OffsetPosition; | 95 | |
86 | Rotation = part.RotationOffset; | 96 | // m_log.DebugFormat( |
87 | Scale = part.Shape.Scale; | 97 | // "[UNDO STATE]: Storing undo rotation {0} for root part", Rotation); |
88 | LastUpdated = DateTime.Now; | 98 | |
89 | } | 99 | Scale = part.Shape.Scale; |
100 | |||
101 | // m_log.DebugFormat( | ||
102 | // "[UNDO STATE]: Storing undo scale {0} for root part", Scale); | ||
103 | } | ||
104 | else | ||
105 | { | ||
106 | Position = part.OffsetPosition; | ||
107 | // m_log.DebugFormat( | ||
108 | // "[UNDO STATE]: Storing undo position {0} for child part", Position); | ||
109 | |||
110 | Rotation = part.RotationOffset; | ||
111 | // m_log.DebugFormat( | ||
112 | // "[UNDO STATE]: Storing undo rotation {0} for child part", Rotation); | ||
113 | |||
114 | Scale = part.Shape.Scale; | ||
115 | // m_log.DebugFormat( | ||
116 | // "[UNDO STATE]: Storing undo scale {0} for child part", Scale); | ||
90 | } | 117 | } |
91 | } | 118 | } |
92 | public void Merge(UndoState last) | 119 | public void Merge(UndoState last) |
@@ -132,95 +159,143 @@ namespace OpenSim.Region.Framework.Scenes | |||
132 | return false; | 159 | return false; |
133 | } | 160 | } |
134 | } | 161 | } |
162 | /// <summary> | ||
163 | /// Compare the relevant state in the given part to this state. | ||
164 | /// </summary> | ||
165 | /// <param name="part"></param> | ||
166 | /// <returns>true if both the part's position, rotation and scale match those in this undo state. False otherwise.</returns> | ||
135 | public bool Compare(SceneObjectPart part) | 167 | public bool Compare(SceneObjectPart part) |
136 | { | 168 | { |
137 | if (part != null) | 169 | if (part != null) |
138 | { | 170 | { |
139 | if (part.ParentID == 0) | 171 | if (part.ParentID == 0) |
140 | { | 172 | return |
141 | if (Position == part.ParentGroup.RootPart.AbsolutePosition && Rotation == part.ParentGroup.Rotation && GroupPosition == part.ParentGroup.RootPart.AbsolutePosition && part.ParentGroup.Rotation == GroupRotation && part.Shape.Scale == GroupScale) | 173 | Position == part.ParentGroup.AbsolutePosition |
142 | return true; | 174 | && Rotation == part.RotationOffset |
143 | else | 175 | && Scale == part.Shape.Scale; |
144 | return false; | ||
145 | } | ||
146 | else | 176 | else |
147 | { | 177 | return |
148 | if (Position == part.OffsetPosition && Rotation == part.RotationOffset && Scale == part.Shape.Scale && GroupPosition == part.ParentGroup.RootPart.AbsolutePosition && part.ParentGroup.Rotation == GroupRotation && part.Shape.Scale == GroupScale) | 178 | Position == part.OffsetPosition |
149 | return true; | 179 | && Rotation == part.RotationOffset |
150 | else | 180 | && Scale == part.Shape.Scale; |
151 | return false; | ||
152 | |||
153 | } | ||
154 | } | 181 | } |
182 | |||
155 | return false; | 183 | return false; |
156 | } | 184 | } |
157 | 185 | ||
158 | private void RestoreState(SceneObjectPart part) | 186 | private void RestoreState(SceneObjectPart part) |
159 | { | 187 | { |
160 | bool GroupChange = false; | 188 | part.Undoing = true; |
161 | if ((Type & UndoType.STATE_GROUP_POSITION) != 0 | ||
162 | || (Type & UndoType.STATE_GROUP_ROTATION) != 0 | ||
163 | || (Type & UndoType.STATE_GROUP_SCALE) != 0) | ||
164 | { | ||
165 | GroupChange = true; | ||
166 | } | ||
167 | 189 | ||
168 | if (part != null) | 190 | if (part.ParentID == 0) |
169 | { | 191 | { |
170 | part.Undoing = true; | 192 | // m_log.DebugFormat( |
193 | // "[UNDO STATE]: Undoing position to {0} for root part {1} {2}", | ||
194 | // Position, part.Name, part.LocalId); | ||
171 | 195 | ||
172 | if (part.ParentID == 0 && GroupChange == false) | 196 | if (Position != Vector3.Zero) |
173 | { | 197 | { |
174 | if (Position != Vector3.Zero) | 198 | if (ForGroup) |
175 | 199 | part.ParentGroup.AbsolutePosition = Position; | |
176 | part.ParentGroup.UpdateSinglePosition(Position, part.LocalId); | 200 | else |
177 | part.ParentGroup.UpdateSingleRotation(Rotation, part.LocalId); | 201 | part.ParentGroup.UpdateRootPosition(Position); |
178 | if (Scale != Vector3.Zero) | ||
179 | part.Resize(Scale); | ||
180 | part.ParentGroup.ScheduleGroupForTerseUpdate(); | ||
181 | } | 202 | } |
203 | |||
204 | // m_log.DebugFormat( | ||
205 | // "[UNDO STATE]: Undoing rotation {0} to {1} for root part {2} {3}", | ||
206 | // part.RotationOffset, Rotation, part.Name, part.LocalId); | ||
207 | |||
208 | if (ForGroup) | ||
209 | part.UpdateRotation(Rotation); | ||
182 | else | 210 | else |
211 | part.ParentGroup.UpdateRootRotation(Rotation); | ||
212 | |||
213 | if (Scale != Vector3.Zero) | ||
183 | { | 214 | { |
184 | if (GroupChange) | 215 | // m_log.DebugFormat( |
185 | { | 216 | // "[UNDO STATE]: Undoing scale {0} to {1} for root part {2} {3}", |
186 | part.ParentGroup.RootPart.Undoing = true; | 217 | // part.Shape.Scale, Scale, part.Name, part.LocalId); |
187 | if (GroupPosition != Vector3.Zero) | 218 | |
188 | { | 219 | if (ForGroup) |
189 | //Calculate the scale... | 220 | part.ParentGroup.GroupResize(Scale); |
190 | Vector3 gs = part.Shape.Scale; | ||
191 | float scale = GroupScale.Z / gs.Z; | ||
192 | |||
193 | //Scale first since it can affect our position | ||
194 | part.ParentGroup.GroupResize(gs * scale, part.LocalId); | ||
195 | part.ParentGroup.AbsolutePosition = GroupPosition; | ||
196 | part.ParentGroup.UpdateGroupRotationR(GroupRotation); | ||
197 | |||
198 | } | ||
199 | part.ParentGroup.RootPart.Undoing = false; | ||
200 | } | ||
201 | else | 221 | else |
202 | { | 222 | part.Resize(Scale); |
203 | if (Position != Vector3.Zero) //We can use this for all the updates since all are set | ||
204 | { | ||
205 | part.OffsetPosition = Position; | ||
206 | part.UpdateRotation(Rotation); | ||
207 | part.Resize(Scale); part.ScheduleTerseUpdate(); | ||
208 | } | ||
209 | } | ||
210 | } | 223 | } |
211 | part.Undoing = false; | ||
212 | 224 | ||
225 | part.ParentGroup.ScheduleGroupForTerseUpdate(); | ||
213 | } | 226 | } |
227 | else | ||
228 | { | ||
229 | if (Position != Vector3.Zero) | ||
230 | { | ||
231 | // m_log.DebugFormat( | ||
232 | // "[UNDO STATE]: Undoing position {0} to {1} for child part {2} {3}", | ||
233 | // part.OffsetPosition, Position, part.Name, part.LocalId); | ||
234 | |||
235 | part.OffsetPosition = Position; | ||
236 | } | ||
237 | |||
238 | // m_log.DebugFormat( | ||
239 | // "[UNDO STATE]: Undoing rotation {0} to {1} for child part {2} {3}", | ||
240 | // part.RotationOffset, Rotation, part.Name, part.LocalId); | ||
241 | |||
242 | part.UpdateRotation(Rotation); | ||
243 | |||
244 | if (Scale != Vector3.Zero) | ||
245 | { | ||
246 | // m_log.DebugFormat( | ||
247 | // "[UNDO STATE]: Undoing scale {0} to {1} for child part {2} {3}", | ||
248 | // part.Shape.Scale, Scale, part.Name, part.LocalId); | ||
249 | |||
250 | part.Resize(Scale); | ||
251 | } | ||
252 | |||
253 | part.ScheduleTerseUpdate(); | ||
254 | } | ||
255 | |||
256 | part.Undoing = false; | ||
214 | } | 257 | } |
215 | public void PlaybackState(SceneObjectPart part) | 258 | |
216 | { | ||
217 | RestoreState(part); | ||
218 | } | ||
219 | public void PlayfwdState(SceneObjectPart part) | 259 | public void PlayfwdState(SceneObjectPart part) |
220 | { | 260 | { |
221 | RestoreState(part); | 261 | part.Undoing = true; |
262 | |||
263 | if (part.ParentID == 0) | ||
264 | { | ||
265 | if (Position != Vector3.Zero) | ||
266 | part.ParentGroup.AbsolutePosition = Position; | ||
267 | |||
268 | if (Rotation != Quaternion.Identity) | ||
269 | part.UpdateRotation(Rotation); | ||
270 | |||
271 | if (Scale != Vector3.Zero) | ||
272 | { | ||
273 | if (ForGroup) | ||
274 | part.ParentGroup.GroupResize(Scale); | ||
275 | else | ||
276 | part.Resize(Scale); | ||
277 | } | ||
278 | |||
279 | part.ParentGroup.ScheduleGroupForTerseUpdate(); | ||
280 | } | ||
281 | else | ||
282 | { | ||
283 | if (Position != Vector3.Zero) | ||
284 | part.OffsetPosition = Position; | ||
285 | |||
286 | if (Rotation != Quaternion.Identity) | ||
287 | part.UpdateRotation(Rotation); | ||
288 | |||
289 | if (Scale != Vector3.Zero) | ||
290 | part.Resize(Scale); | ||
291 | |||
292 | part.ScheduleTerseUpdate(); | ||
293 | } | ||
294 | |||
295 | part.Undoing = false; | ||
222 | } | 296 | } |
223 | } | 297 | } |
298 | |||
224 | public class LandUndoState | 299 | public class LandUndoState |
225 | { | 300 | { |
226 | public ITerrainModule m_terrainModule; | 301 | public ITerrainModule m_terrainModule; |
@@ -234,10 +309,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
234 | 309 | ||
235 | public bool Compare(ITerrainChannel terrainChannel) | 310 | public bool Compare(ITerrainChannel terrainChannel) |
236 | { | 311 | { |
237 | if (m_terrainChannel != terrainChannel) | 312 | return m_terrainChannel == terrainChannel; |
238 | return false; | ||
239 | else | ||
240 | return false; | ||
241 | } | 313 | } |
242 | 314 | ||
243 | public void PlaybackState() | 315 | public void PlaybackState() |
@@ -246,4 +318,3 @@ namespace OpenSim.Region.Framework.Scenes | |||
246 | } | 318 | } |
247 | } | 319 | } |
248 | } | 320 | } |
249 | |||
diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs index 26934e8..00b1c1e 100644 --- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs +++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs | |||
@@ -677,7 +677,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server | |||
677 | public event DeRezObject OnDeRezObject; | 677 | public event DeRezObject OnDeRezObject; |
678 | public event Action<IClientAPI> OnRegionHandShakeReply; | 678 | public event Action<IClientAPI> OnRegionHandShakeReply; |
679 | public event GenericCall1 OnRequestWearables; | 679 | public event GenericCall1 OnRequestWearables; |
680 | public event GenericCall1 OnCompleteMovementToRegion; | 680 | public event Action<IClientAPI, bool> OnCompleteMovementToRegion; |
681 | public event UpdateAgent OnPreAgentUpdate; | 681 | public event UpdateAgent OnPreAgentUpdate; |
682 | public event UpdateAgent OnAgentUpdate; | 682 | public event UpdateAgent OnAgentUpdate; |
683 | public event AgentRequestSit OnAgentRequestSit; | 683 | public event AgentRequestSit OnAgentRequestSit; |
@@ -806,7 +806,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server | |||
806 | public event ScriptReset OnScriptReset; | 806 | public event ScriptReset OnScriptReset; |
807 | public event GetScriptRunning OnGetScriptRunning; | 807 | public event GetScriptRunning OnGetScriptRunning; |
808 | public event SetScriptRunning OnSetScriptRunning; | 808 | public event SetScriptRunning OnSetScriptRunning; |
809 | public event UpdateVector OnAutoPilotGo; | 809 | public event Action<Vector3, bool> OnAutoPilotGo; |
810 | public event TerrainUnacked OnUnackedTerrain; | 810 | public event TerrainUnacked OnUnackedTerrain; |
811 | public event ActivateGesture OnActivateGesture; | 811 | public event ActivateGesture OnActivateGesture; |
812 | public event DeactivateGesture OnDeactivateGesture; | 812 | public event DeactivateGesture OnDeactivateGesture; |
@@ -899,7 +899,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server | |||
899 | 899 | ||
900 | public void Start() | 900 | public void Start() |
901 | { | 901 | { |
902 | Scene.AddNewClient(this); | 902 | Scene.AddNewClient(this, PresenceType.User); |
903 | 903 | ||
904 | // Mimicking LLClientView which gets always set appearance from client. | 904 | // Mimicking LLClientView which gets always set appearance from client. |
905 | Scene scene = (Scene)Scene; | 905 | Scene scene = (Scene)Scene; |
@@ -919,7 +919,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server | |||
919 | 919 | ||
920 | if (OnCompleteMovementToRegion != null) | 920 | if (OnCompleteMovementToRegion != null) |
921 | { | 921 | { |
922 | OnCompleteMovementToRegion(this); | 922 | OnCompleteMovementToRegion(this, true); |
923 | } | 923 | } |
924 | } | 924 | } |
925 | 925 | ||
diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs index ee52a39..d2f6327 100644 --- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs +++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs | |||
@@ -47,16 +47,16 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups.Tests | |||
47 | [Test] | 47 | [Test] |
48 | public void TestBasic() | 48 | public void TestBasic() |
49 | { | 49 | { |
50 | TestHelper.InMethod(); | 50 | TestHelpers.InMethod(); |
51 | // log4net.Config.XmlConfigurator.Configure(); | 51 | // log4net.Config.XmlConfigurator.Configure(); |
52 | 52 | ||
53 | TestScene scene = SceneSetupHelpers.SetupScene(); | 53 | TestScene scene = SceneHelpers.SetupScene(); |
54 | IConfigSource configSource = new IniConfigSource(); | 54 | IConfigSource configSource = new IniConfigSource(); |
55 | IConfig config = configSource.AddConfig("Groups"); | 55 | IConfig config = configSource.AddConfig("Groups"); |
56 | config.Set("Enabled", true); | 56 | config.Set("Enabled", true); |
57 | config.Set("Module", "GroupsModule"); | 57 | config.Set("Module", "GroupsModule"); |
58 | config.Set("DebugEnabled", true); | 58 | config.Set("DebugEnabled", true); |
59 | SceneSetupHelpers.SetupSceneModules( | 59 | SceneHelpers.SetupSceneModules( |
60 | scene, configSource, new object[] { new MockGroupsServicesConnector() }); | 60 | scene, configSource, new object[] { new MockGroupsServicesConnector() }); |
61 | } | 61 | } |
62 | } | 62 | } |
diff --git a/OpenSim/Region/OptionalModules/Framework/Monitoring/MonitorServicesModule.cs b/OpenSim/Region/OptionalModules/Framework/Monitoring/MonitorServicesModule.cs new file mode 100644 index 0000000..a25e034 --- /dev/null +++ b/OpenSim/Region/OptionalModules/Framework/Monitoring/MonitorServicesModule.cs | |||
@@ -0,0 +1,119 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Reflection; | ||
30 | using System.Text; | ||
31 | using log4net; | ||
32 | using Mono.Addins; | ||
33 | using Nini.Config; | ||
34 | using OpenMetaverse; | ||
35 | using OpenSim.Framework; | ||
36 | using OpenSim.Framework.Console; | ||
37 | using OpenSim.Region.Framework.Interfaces; | ||
38 | using OpenSim.Region.Framework.Scenes; | ||
39 | |||
40 | namespace OpenSim.Region.OptionalModules.Framework.Monitoring | ||
41 | { | ||
42 | /// <summary> | ||
43 | /// An experimental module to return data on services used by the simulator. | ||
44 | /// </summary> | ||
45 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "MonitorServicesModule")] | ||
46 | public class MonitorServicesModule : ISharedRegionModule | ||
47 | { | ||
48 | protected Scene m_scene; | ||
49 | |||
50 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
51 | |||
52 | public string Name { get { return "Services Health Monitoring Module"; } } | ||
53 | |||
54 | public Type ReplaceableInterface { get { return null; } } | ||
55 | |||
56 | public void Initialise(IConfigSource source) | ||
57 | { | ||
58 | } | ||
59 | |||
60 | public void PostInitialise() | ||
61 | { | ||
62 | } | ||
63 | |||
64 | public void Close() | ||
65 | { | ||
66 | } | ||
67 | |||
68 | public void AddRegion(Scene scene) | ||
69 | { | ||
70 | if (m_scene == null) | ||
71 | { | ||
72 | m_scene = scene; | ||
73 | |||
74 | // m_scene.AddCommand(this, "monitor services", | ||
75 | // "monitor services", | ||
76 | // "Returns the status of services used by the simulator. Experimental.", | ||
77 | // HandleMonitorServices); | ||
78 | } | ||
79 | } | ||
80 | |||
81 | public void RemoveRegion(Scene scene) | ||
82 | { | ||
83 | } | ||
84 | |||
85 | public void RegionLoaded(Scene scene) | ||
86 | { | ||
87 | } | ||
88 | |||
89 | protected void HandleMonitorServices(string module, string[] args) | ||
90 | { | ||
91 | MainConsole.Instance.Output(GenerateServicesReport()); | ||
92 | } | ||
93 | |||
94 | protected string GenerateServicesReport() | ||
95 | { | ||
96 | StringBuilder sb = new StringBuilder(); | ||
97 | sb.Append("This is an experimental module. Please don't rely on these results\n"); | ||
98 | sb.Append("Asset service: "); | ||
99 | |||
100 | try | ||
101 | { | ||
102 | CheckAssetService(); | ||
103 | sb.Append("OK"); | ||
104 | } | ||
105 | catch (Exception e) | ||
106 | { | ||
107 | sb.AppendFormat("FAIL ({0})", e.Message); | ||
108 | } | ||
109 | |||
110 | return sb.ToString(); | ||
111 | } | ||
112 | |||
113 | protected void CheckAssetService() | ||
114 | { | ||
115 | // Try to fetch an asset that will not exist (and hence avoid hitting cache) | ||
116 | m_scene.AssetService.Get(UUID.Random().ToString()); | ||
117 | } | ||
118 | } | ||
119 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs b/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs new file mode 100755 index 0000000..2a44360 --- /dev/null +++ b/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs | |||
@@ -0,0 +1,277 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Reflection; | ||
30 | using System.Collections.Generic; | ||
31 | using log4net; | ||
32 | using Mono.Addins; | ||
33 | using Nini.Config; | ||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Framework.Console; | ||
36 | using OpenSim.Region.CoreModules.Framework.InterfaceCommander; | ||
37 | using OpenSim.Region.Framework.Interfaces; | ||
38 | using OpenSim.Region.Framework.Scenes; | ||
39 | using OpenSim.Region.Physics.Manager; | ||
40 | |||
41 | namespace OpenSim.Region.OptionalModules.PhysicsParameters | ||
42 | { | ||
43 | /// <summary> | ||
44 | /// </summary> | ||
45 | /// <remarks> | ||
46 | /// </remarks> | ||
47 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "PhysicsParameters")] | ||
48 | public class PhysicsParameters : ISharedRegionModule | ||
49 | { | ||
50 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
51 | private static string LogHeader = "[PHYSICS PARAMETERS]"; | ||
52 | |||
53 | private List<Scene> m_scenes = new List<Scene>(); | ||
54 | private static bool m_commandsLoaded = false; | ||
55 | |||
56 | #region ISharedRegionModule | ||
57 | public string Name { get { return "Runtime Physics Parameter Module"; } } | ||
58 | |||
59 | public Type ReplaceableInterface { get { return null; } } | ||
60 | |||
61 | public void Initialise(IConfigSource source) | ||
62 | { | ||
63 | // m_log.DebugFormat("{0}: INITIALIZED MODULE", LogHeader); | ||
64 | } | ||
65 | |||
66 | public void PostInitialise() | ||
67 | { | ||
68 | // m_log.DebugFormat("[{0}: POST INITIALIZED MODULE", LogHeader); | ||
69 | InstallInterfaces(); | ||
70 | } | ||
71 | |||
72 | public void Close() | ||
73 | { | ||
74 | // m_log.DebugFormat("{0}: CLOSED MODULE", LogHeader); | ||
75 | } | ||
76 | |||
77 | public void AddRegion(Scene scene) | ||
78 | { | ||
79 | // m_log.DebugFormat("{0}: REGION {1} ADDED", LogHeader, scene.RegionInfo.RegionName); | ||
80 | m_scenes.Add(scene); | ||
81 | } | ||
82 | |||
83 | public void RemoveRegion(Scene scene) | ||
84 | { | ||
85 | // m_log.DebugFormat("{0}: REGION {1} REMOVED", LogHeader, scene.RegionInfo.RegionName); | ||
86 | if (m_scenes.Contains(scene)) | ||
87 | m_scenes.Remove(scene); | ||
88 | } | ||
89 | |||
90 | public void RegionLoaded(Scene scene) | ||
91 | { | ||
92 | // m_log.DebugFormat("{0}: REGION {1} LOADED", LogHeader, scene.RegionInfo.RegionName); | ||
93 | } | ||
94 | #endregion INonSharedRegionModule | ||
95 | |||
96 | private const string getInvocation = "physics get [<param>|ALL]"; | ||
97 | private const string setInvocation = "physics set <param> [<value>|TRUE|FALSE] [localID|ALL]"; | ||
98 | private const string listInvocation = "physics list"; | ||
99 | private void InstallInterfaces() | ||
100 | { | ||
101 | if (!m_commandsLoaded) | ||
102 | { | ||
103 | MainConsole.Instance.Commands.AddCommand("Physics", false, "physics set", | ||
104 | "physics set", | ||
105 | "Set physics parameter from currently selected region" + Environment.NewLine | ||
106 | + "Invocation: " + setInvocation, | ||
107 | ProcessPhysicsSet); | ||
108 | |||
109 | MainConsole.Instance.Commands.AddCommand("Physics", false, "physics get", | ||
110 | "physics get", | ||
111 | "Get physics parameter from currently selected region" + Environment.NewLine | ||
112 | + "Invocation: " + getInvocation, | ||
113 | ProcessPhysicsGet); | ||
114 | |||
115 | MainConsole.Instance.Commands.AddCommand("Physics", false, "physics list", | ||
116 | "physics list", | ||
117 | "List settable physics parameters" + Environment.NewLine | ||
118 | + "Invocation: " + listInvocation, | ||
119 | ProcessPhysicsList); | ||
120 | |||
121 | m_commandsLoaded = true; | ||
122 | } | ||
123 | } | ||
124 | |||
125 | // TODO: extend get so you can get a value from an individual localID | ||
126 | private void ProcessPhysicsGet(string module, string[] cmdparms) | ||
127 | { | ||
128 | if (cmdparms.Length != 3) | ||
129 | { | ||
130 | WriteError("Parameter count error. Invocation: " + getInvocation); | ||
131 | return; | ||
132 | } | ||
133 | string parm = cmdparms[2]; | ||
134 | |||
135 | if (SceneManager.Instance == null || SceneManager.Instance.CurrentScene == null) | ||
136 | { | ||
137 | WriteError("Error: no region selected. Use 'change region' to select a region."); | ||
138 | return; | ||
139 | } | ||
140 | |||
141 | Scene scene = SceneManager.Instance.CurrentScene; | ||
142 | IPhysicsParameters physScene = scene.PhysicsScene as IPhysicsParameters; | ||
143 | if (physScene != null) | ||
144 | { | ||
145 | if (parm.ToLower() == "all") | ||
146 | { | ||
147 | foreach (PhysParameterEntry ppe in physScene.GetParameterList()) | ||
148 | { | ||
149 | float val = 0.0f; | ||
150 | if (physScene.GetPhysicsParameter(ppe.name, out val)) | ||
151 | { | ||
152 | WriteOut(" {0}/{1} = {2}", scene.RegionInfo.RegionName, ppe.name, val); | ||
153 | } | ||
154 | else | ||
155 | { | ||
156 | WriteOut(" {0}/{1} = {2}", scene.RegionInfo.RegionName, ppe.name, "unknown"); | ||
157 | } | ||
158 | } | ||
159 | } | ||
160 | else | ||
161 | { | ||
162 | float val = 0.0f; | ||
163 | if (physScene.GetPhysicsParameter(parm, out val)) | ||
164 | { | ||
165 | WriteOut(" {0}/{1} = {2}", scene.RegionInfo.RegionName, parm, val); | ||
166 | } | ||
167 | else | ||
168 | { | ||
169 | WriteError("Failed fetch of parameter '{0}' from region '{1}'", parm, scene.RegionInfo.RegionName); | ||
170 | } | ||
171 | } | ||
172 | } | ||
173 | else | ||
174 | { | ||
175 | WriteError("Region '{0}' physics engine has no gettable physics parameters", scene.RegionInfo.RegionName); | ||
176 | } | ||
177 | return; | ||
178 | } | ||
179 | |||
180 | private void ProcessPhysicsSet(string module, string[] cmdparms) | ||
181 | { | ||
182 | if (cmdparms.Length < 4 || cmdparms.Length > 5) | ||
183 | { | ||
184 | WriteError("Parameter count error. Invocation: " + getInvocation); | ||
185 | return; | ||
186 | } | ||
187 | string parm = "xxx"; | ||
188 | float val = 0f; | ||
189 | uint localID = (uint)PhysParameterEntry.APPLY_TO_NONE; // set default value | ||
190 | try | ||
191 | { | ||
192 | parm = cmdparms[2]; | ||
193 | string valparm = cmdparms[3].ToLower(); | ||
194 | if (valparm == "true") | ||
195 | val = PhysParameterEntry.NUMERIC_TRUE; | ||
196 | else | ||
197 | { | ||
198 | if (valparm == "false") | ||
199 | val = PhysParameterEntry.NUMERIC_FALSE; | ||
200 | else | ||
201 | val = float.Parse(valparm, Culture.NumberFormatInfo); | ||
202 | } | ||
203 | if (cmdparms.Length > 4) | ||
204 | { | ||
205 | if (cmdparms[4].ToLower() == "all") | ||
206 | localID = (uint)PhysParameterEntry.APPLY_TO_ALL; | ||
207 | else | ||
208 | localID = uint.Parse(cmdparms[2], Culture.NumberFormatInfo); | ||
209 | } | ||
210 | } | ||
211 | catch | ||
212 | { | ||
213 | WriteError(" Error parsing parameters. Invocation: " + setInvocation); | ||
214 | return; | ||
215 | } | ||
216 | |||
217 | if (SceneManager.Instance == null || SceneManager.Instance.CurrentScene == null) | ||
218 | { | ||
219 | WriteError("Error: no region selected. Use 'change region' to select a region."); | ||
220 | return; | ||
221 | } | ||
222 | |||
223 | Scene scene = SceneManager.Instance.CurrentScene; | ||
224 | IPhysicsParameters physScene = scene.PhysicsScene as IPhysicsParameters; | ||
225 | if (physScene != null) | ||
226 | { | ||
227 | if (!physScene.SetPhysicsParameter(parm, val, localID)) | ||
228 | { | ||
229 | WriteError("Failed set of parameter '{0}' for region '{1}'", parm, scene.RegionInfo.RegionName); | ||
230 | } | ||
231 | } | ||
232 | else | ||
233 | { | ||
234 | WriteOut("Region '{0}'s physics engine has no settable physics parameters", scene.RegionInfo.RegionName); | ||
235 | } | ||
236 | return; | ||
237 | } | ||
238 | |||
239 | private void ProcessPhysicsList(string module, string[] cmdparms) | ||
240 | { | ||
241 | if (SceneManager.Instance == null || SceneManager.Instance.CurrentScene == null) | ||
242 | { | ||
243 | WriteError("Error: no region selected. Use 'change region' to select a region."); | ||
244 | return; | ||
245 | } | ||
246 | Scene scene = SceneManager.Instance.CurrentScene; | ||
247 | |||
248 | IPhysicsParameters physScene = scene.PhysicsScene as IPhysicsParameters; | ||
249 | if (physScene != null) | ||
250 | { | ||
251 | WriteOut("Available physics parameters:"); | ||
252 | PhysParameterEntry[] parms = physScene.GetParameterList(); | ||
253 | foreach (PhysParameterEntry ent in parms) | ||
254 | { | ||
255 | WriteOut(" {0}: {1}", ent.name, ent.desc); | ||
256 | } | ||
257 | } | ||
258 | else | ||
259 | { | ||
260 | WriteError("Current regions's physics engine has no settable physics parameters"); | ||
261 | } | ||
262 | return; | ||
263 | } | ||
264 | |||
265 | private void WriteOut(string msg, params object[] args) | ||
266 | { | ||
267 | m_log.InfoFormat(msg, args); | ||
268 | // MainConsole.Instance.OutputFormat(msg, args); | ||
269 | } | ||
270 | |||
271 | private void WriteError(string msg, params object[] args) | ||
272 | { | ||
273 | m_log.ErrorFormat(msg, args); | ||
274 | // MainConsole.Instance.OutputFormat(msg, args); | ||
275 | } | ||
276 | } | ||
277 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs b/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs index 05c729a..963d1e2 100644 --- a/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs +++ b/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs | |||
@@ -126,6 +126,11 @@ namespace OpenSim.Region.OptionalModules.Scripting.RegionReady | |||
126 | m_scene.EventManager.OnEmptyScriptCompileQueue -= OnEmptyScriptCompileQueue; | 126 | m_scene.EventManager.OnEmptyScriptCompileQueue -= OnEmptyScriptCompileQueue; |
127 | m_scene.EventManager.OnOarFileLoaded -= OnOarFileLoaded; | 127 | m_scene.EventManager.OnOarFileLoaded -= OnOarFileLoaded; |
128 | 128 | ||
129 | if(m_uri != string.Empty) | ||
130 | { | ||
131 | RRAlert("shutdown"); | ||
132 | } | ||
133 | |||
129 | m_scene = null; | 134 | m_scene = null; |
130 | } | 135 | } |
131 | 136 | ||
diff --git a/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcGridRouterModule.cs b/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcGridRouterModule.cs index d18ac0a..2187449 100644 --- a/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcGridRouterModule.cs +++ b/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcGridRouterModule.cs | |||
@@ -106,7 +106,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcGridRouterModule | |||
106 | info.channel = channel; | 106 | info.channel = channel; |
107 | info.uri = uri; | 107 | info.uri = uri; |
108 | 108 | ||
109 | bool success = SynchronousRestObjectPoster.BeginPostObject<XmlRpcInfo, bool>( | 109 | bool success = SynchronousRestObjectRequester.MakeRequest<XmlRpcInfo, bool>( |
110 | "POST", m_ServerURI+"/RegisterChannel/", info); | 110 | "POST", m_ServerURI+"/RegisterChannel/", info); |
111 | 111 | ||
112 | if (!success) | 112 | if (!success) |
@@ -125,7 +125,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcGridRouterModule | |||
125 | 125 | ||
126 | if (m_Channels.ContainsKey(itemID)) | 126 | if (m_Channels.ContainsKey(itemID)) |
127 | { | 127 | { |
128 | bool success = SynchronousRestObjectPoster.BeginPostObject<UUID, bool>( | 128 | bool success = SynchronousRestObjectRequester.MakeRequest<UUID, bool>( |
129 | "POST", m_ServerURI+"/RemoveChannel/", m_Channels[itemID]); | 129 | "POST", m_ServerURI+"/RemoveChannel/", m_Channels[itemID]); |
130 | 130 | ||
131 | if (!success) | 131 | if (!success) |
diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs index 69d6261..4f831a4 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs | |||
@@ -37,6 +37,11 @@ namespace OpenSim.Region.OptionalModules.World.NPC | |||
37 | { | 37 | { |
38 | public class NPCAvatar : IClientAPI | 38 | public class NPCAvatar : IClientAPI |
39 | { | 39 | { |
40 | /// <summary> | ||
41 | /// Signal whether the avatar should land when it reaches a move target | ||
42 | /// </summary> | ||
43 | public bool LandAtTarget { get; set; } | ||
44 | |||
40 | private readonly string m_firstname; | 45 | private readonly string m_firstname; |
41 | private readonly string m_lastname; | 46 | private readonly string m_lastname; |
42 | private readonly Vector3 m_startPos; | 47 | private readonly Vector3 m_startPos; |
@@ -99,6 +104,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC | |||
99 | { | 104 | { |
100 | 105 | ||
101 | } | 106 | } |
107 | |||
102 | public void SendSitResponse(UUID TargetID, Vector3 OffsetPos, Quaternion SitOrientation, bool autopilot, | 108 | public void SendSitResponse(UUID TargetID, Vector3 OffsetPos, Quaternion SitOrientation, bool autopilot, |
103 | Vector3 CameraAtOffset, Vector3 CameraEyeOffset, bool ForceMouseLook) | 109 | Vector3 CameraAtOffset, Vector3 CameraEyeOffset, bool ForceMouseLook) |
104 | { | 110 | { |
@@ -189,7 +195,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC | |||
189 | public event DeRezObject OnDeRezObject; | 195 | public event DeRezObject OnDeRezObject; |
190 | public event Action<IClientAPI> OnRegionHandShakeReply; | 196 | public event Action<IClientAPI> OnRegionHandShakeReply; |
191 | public event GenericCall1 OnRequestWearables; | 197 | public event GenericCall1 OnRequestWearables; |
192 | public event GenericCall1 OnCompleteMovementToRegion; | 198 | public event Action<IClientAPI, bool> OnCompleteMovementToRegion; |
193 | public event UpdateAgent OnPreAgentUpdate; | 199 | public event UpdateAgent OnPreAgentUpdate; |
194 | public event UpdateAgent OnAgentUpdate; | 200 | public event UpdateAgent OnAgentUpdate; |
195 | public event AgentRequestSit OnAgentRequestSit; | 201 | public event AgentRequestSit OnAgentRequestSit; |
@@ -327,7 +333,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC | |||
327 | public event ScriptReset OnScriptReset; | 333 | public event ScriptReset OnScriptReset; |
328 | public event GetScriptRunning OnGetScriptRunning; | 334 | public event GetScriptRunning OnGetScriptRunning; |
329 | public event SetScriptRunning OnSetScriptRunning; | 335 | public event SetScriptRunning OnSetScriptRunning; |
330 | public event UpdateVector OnAutoPilotGo; | 336 | public event Action<Vector3, bool> OnAutoPilotGo; |
331 | 337 | ||
332 | public event TerrainUnacked OnUnackedTerrain; | 338 | public event TerrainUnacked OnUnackedTerrain; |
333 | 339 | ||
@@ -744,12 +750,8 @@ namespace OpenSim.Region.OptionalModules.World.NPC | |||
744 | { | 750 | { |
745 | OnRegionHandShakeReply(this); | 751 | OnRegionHandShakeReply(this); |
746 | } | 752 | } |
747 | |||
748 | if (OnCompleteMovementToRegion != null) | ||
749 | { | ||
750 | OnCompleteMovementToRegion(this); | ||
751 | } | ||
752 | } | 753 | } |
754 | |||
753 | public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID) | 755 | public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID) |
754 | { | 756 | { |
755 | } | 757 | } |
diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs index 3cdd06d..2fdeeab 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs | |||
@@ -44,32 +44,119 @@ namespace OpenSim.Region.OptionalModules.World.NPC | |||
44 | { | 44 | { |
45 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 45 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
46 | 46 | ||
47 | // private const bool m_enabled = false; | 47 | private Dictionary<UUID, NPCAvatar> m_avatars = new Dictionary<UUID, NPCAvatar>(); |
48 | |||
49 | private Dictionary<UUID,NPCAvatar> m_avatars = new Dictionary<UUID, NPCAvatar>(); | ||
50 | private Dictionary<UUID,AvatarAppearance> m_appearanceCache = new Dictionary<UUID, AvatarAppearance>(); | ||
51 | 48 | ||
52 | public void Initialise(Scene scene, IConfigSource source) | 49 | public void Initialise(Scene scene, IConfigSource source) |
53 | { | 50 | { |
54 | scene.RegisterModuleInterface<INPCModule>(this); | 51 | IConfig config = source.Configs["NPC"]; |
52 | |||
53 | if (config != null && config.GetBoolean("Enabled", false)) | ||
54 | { | ||
55 | scene.RegisterModuleInterface<INPCModule>(this); | ||
56 | scene.EventManager.OnSignificantClientMovement += HandleOnSignificantClientMovement; | ||
57 | } | ||
55 | } | 58 | } |
56 | 59 | ||
57 | private AvatarAppearance GetAppearance(UUID target, Scene scene) | 60 | public void HandleOnSignificantClientMovement(ScenePresence presence) |
58 | { | 61 | { |
59 | if (m_appearanceCache.ContainsKey(target)) | 62 | lock (m_avatars) |
60 | return m_appearanceCache[target]; | ||
61 | |||
62 | AvatarAppearance appearance = scene.AvatarService.GetAppearance(target); | ||
63 | if (appearance != null) | ||
64 | { | 63 | { |
65 | m_appearanceCache.Add(target, appearance); | 64 | if (m_avatars.ContainsKey(presence.UUID) && presence.MovingToTarget) |
66 | return appearance; | 65 | { |
66 | double distanceToTarget = Util.GetDistanceTo(presence.AbsolutePosition, presence.MoveToPositionTarget); | ||
67 | // m_log.DebugFormat( | ||
68 | // "[NPC MODULE]: Abs pos of {0} is {1}, target {2}, distance {3}", | ||
69 | // presence.Name, presence.AbsolutePosition, presence.MoveToPositionTarget, distanceToTarget); | ||
70 | |||
71 | // Check the error term of the current position in relation to the target position | ||
72 | if (distanceToTarget <= ScenePresence.SIGNIFICANT_MOVEMENT) | ||
73 | { | ||
74 | // We are close enough to the target | ||
75 | m_log.DebugFormat("[NPC MODULE]: Stopping movement of npc {0}", presence.Name); | ||
76 | |||
77 | presence.Velocity = Vector3.Zero; | ||
78 | presence.AbsolutePosition = presence.MoveToPositionTarget; | ||
79 | presence.ResetMoveToTarget(); | ||
80 | |||
81 | if (presence.PhysicsActor.Flying) | ||
82 | { | ||
83 | // A horrible hack to stop the NPC dead in its tracks rather than having them overshoot | ||
84 | // the target if flying. | ||
85 | // We really need to be more subtle (slow the avatar as it approaches the target) or at | ||
86 | // least be able to set collision status once, rather than 5 times to give it enough | ||
87 | // weighting so that that PhysicsActor thinks it really is colliding. | ||
88 | for (int i = 0; i < 5; i++) | ||
89 | presence.PhysicsActor.IsColliding = true; | ||
90 | |||
91 | // Vector3 targetPos = presence.MoveToPositionTarget; | ||
92 | if (m_avatars[presence.UUID].LandAtTarget) | ||
93 | presence.PhysicsActor.Flying = false; | ||
94 | |||
95 | // float terrainHeight = (float)presence.Scene.Heightmap[(int)targetPos.X, (int)targetPos.Y]; | ||
96 | // if (targetPos.Z - terrainHeight < 0.2) | ||
97 | // { | ||
98 | // presence.PhysicsActor.Flying = false; | ||
99 | // } | ||
100 | } | ||
101 | |||
102 | // m_log.DebugFormat( | ||
103 | // "[NPC MODULE]: AgentControlFlags {0}, MovementFlag {1} for {2}", | ||
104 | // presence.AgentControlFlags, presence.MovementFlag, presence.Name); | ||
105 | } | ||
106 | else | ||
107 | { | ||
108 | // m_log.DebugFormat( | ||
109 | // "[NPC MODULE]: Updating npc {0} at {1} for next movement to {2}", | ||
110 | // presence.Name, presence.AbsolutePosition, presence.MoveToPositionTarget); | ||
111 | |||
112 | Vector3 agent_control_v3 = new Vector3(); | ||
113 | presence.HandleMoveToTargetUpdate(ref agent_control_v3); | ||
114 | presence.AddNewMovement(agent_control_v3); | ||
115 | } | ||
116 | // | ||
117 | //// presence.DoMoveToPositionUpdate((0, presence.MoveToPositionTarget, null); | ||
118 | |||
119 | // | ||
120 | // | ||
121 | |||
122 | } | ||
67 | } | 123 | } |
124 | } | ||
125 | |||
126 | public bool IsNPC(UUID agentId, Scene scene) | ||
127 | { | ||
128 | ScenePresence sp = scene.GetScenePresence(agentId); | ||
129 | if (sp == null || sp.IsChildAgent) | ||
130 | return false; | ||
68 | 131 | ||
69 | return new AvatarAppearance(); | 132 | lock (m_avatars) |
133 | return m_avatars.ContainsKey(agentId); | ||
70 | } | 134 | } |
71 | 135 | ||
72 | public UUID CreateNPC(string firstname, string lastname, Vector3 position, Scene scene, UUID cloneAppearanceFrom) | 136 | public bool SetNPCAppearance(UUID agentId, AvatarAppearance appearance, Scene scene) |
137 | { | ||
138 | ScenePresence sp = scene.GetScenePresence(agentId); | ||
139 | if (sp == null || sp.IsChildAgent) | ||
140 | return false; | ||
141 | |||
142 | lock (m_avatars) | ||
143 | if (!m_avatars.ContainsKey(agentId)) | ||
144 | return false; | ||
145 | |||
146 | scene.AttachmentsModule.DeleteAttachmentsFromScene(sp, false); | ||
147 | |||
148 | AvatarAppearance npcAppearance = new AvatarAppearance(appearance, true); | ||
149 | sp.Appearance = npcAppearance; | ||
150 | scene.AttachmentsModule.RezAttachments(sp); | ||
151 | |||
152 | IAvatarFactory module = scene.RequestModuleInterface<IAvatarFactory>(); | ||
153 | module.SendAppearance(sp.UUID); | ||
154 | |||
155 | return true; | ||
156 | } | ||
157 | |||
158 | public UUID CreateNPC( | ||
159 | string firstname, string lastname, Vector3 position, Scene scene, AvatarAppearance appearance) | ||
73 | { | 160 | { |
74 | NPCAvatar npcAvatar = new NPCAvatar(firstname, lastname, position, scene); | 161 | NPCAvatar npcAvatar = new NPCAvatar(firstname, lastname, position, scene); |
75 | npcAvatar.CircuitCode = (uint)Util.RandomClass.Next(0, int.MaxValue); | 162 | npcAvatar.CircuitCode = (uint)Util.RandomClass.Next(0, int.MaxValue); |
@@ -84,12 +171,18 @@ namespace OpenSim.Region.OptionalModules.World.NPC | |||
84 | acd.lastname = lastname; | 171 | acd.lastname = lastname; |
85 | acd.ServiceURLs = new Dictionary<string, object>(); | 172 | acd.ServiceURLs = new Dictionary<string, object>(); |
86 | 173 | ||
87 | AvatarAppearance originalAppearance = GetAppearance(cloneAppearanceFrom, scene); | 174 | AvatarAppearance npcAppearance = new AvatarAppearance(appearance, true); |
88 | AvatarAppearance npcAppearance = new AvatarAppearance(originalAppearance, true); | ||
89 | acd.Appearance = npcAppearance; | 175 | acd.Appearance = npcAppearance; |
90 | 176 | ||
177 | // for (int i = 0; i < acd.Appearance.Texture.FaceTextures.Length; i++) | ||
178 | // { | ||
179 | // m_log.DebugFormat( | ||
180 | // "[NPC MODULE]: NPC avatar {0} has texture id {1} : {2}", | ||
181 | // acd.AgentID, i, acd.Appearance.Texture.FaceTextures[i]); | ||
182 | // } | ||
183 | |||
91 | scene.AuthenticateHandler.AddNewCircuit(npcAvatar.CircuitCode, acd); | 184 | scene.AuthenticateHandler.AddNewCircuit(npcAvatar.CircuitCode, acd); |
92 | scene.AddNewClient(npcAvatar); | 185 | scene.AddNewClient(npcAvatar, PresenceType.Npc); |
93 | 186 | ||
94 | ScenePresence sp; | 187 | ScenePresence sp; |
95 | if (scene.TryGetScenePresence(npcAvatar.AgentId, out sp)) | 188 | if (scene.TryGetScenePresence(npcAvatar.AgentId, out sp)) |
@@ -97,13 +190,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC | |||
97 | m_log.DebugFormat( | 190 | m_log.DebugFormat( |
98 | "[NPC MODULE]: Successfully retrieved scene presence for NPC {0} {1}", sp.Name, sp.UUID); | 191 | "[NPC MODULE]: Successfully retrieved scene presence for NPC {0} {1}", sp.Name, sp.UUID); |
99 | 192 | ||
100 | // Shouldn't call this - temporary. | 193 | sp.CompleteMovement(npcAvatar, false); |
101 | sp.CompleteMovement(npcAvatar); | ||
102 | |||
103 | // sp.SendAppearanceToAllOtherAgents(); | ||
104 | // | ||
105 | // // Send animations back to the avatar as well | ||
106 | // sp.Animator.SendAnimPack(); | ||
107 | } | 194 | } |
108 | else | 195 | else |
109 | { | 196 | { |
@@ -118,7 +205,30 @@ namespace OpenSim.Region.OptionalModules.World.NPC | |||
118 | return npcAvatar.AgentId; | 205 | return npcAvatar.AgentId; |
119 | } | 206 | } |
120 | 207 | ||
121 | public void Autopilot(UUID agentID, Scene scene, Vector3 pos) | 208 | public bool MoveToTarget(UUID agentID, Scene scene, Vector3 pos, bool noFly, bool landAtTarget) |
209 | { | ||
210 | lock (m_avatars) | ||
211 | { | ||
212 | if (m_avatars.ContainsKey(agentID)) | ||
213 | { | ||
214 | ScenePresence sp; | ||
215 | scene.TryGetScenePresence(agentID, out sp); | ||
216 | |||
217 | m_log.DebugFormat( | ||
218 | "[NPC MODULE]: Moving {0} to {1} in {2}, noFly {3}, landAtTarget {4}", | ||
219 | sp.Name, pos, scene.RegionInfo.RegionName, noFly, landAtTarget); | ||
220 | |||
221 | m_avatars[agentID].LandAtTarget = landAtTarget; | ||
222 | sp.MoveToTarget(pos, noFly); | ||
223 | |||
224 | return true; | ||
225 | } | ||
226 | } | ||
227 | |||
228 | return false; | ||
229 | } | ||
230 | |||
231 | public bool StopMoveToTarget(UUID agentID, Scene scene) | ||
122 | { | 232 | { |
123 | lock (m_avatars) | 233 | lock (m_avatars) |
124 | { | 234 | { |
@@ -126,32 +236,49 @@ namespace OpenSim.Region.OptionalModules.World.NPC | |||
126 | { | 236 | { |
127 | ScenePresence sp; | 237 | ScenePresence sp; |
128 | scene.TryGetScenePresence(agentID, out sp); | 238 | scene.TryGetScenePresence(agentID, out sp); |
129 | sp.DoAutoPilot(0, pos, m_avatars[agentID]); | 239 | |
240 | sp.Velocity = Vector3.Zero; | ||
241 | sp.ResetMoveToTarget(); | ||
242 | |||
243 | return true; | ||
130 | } | 244 | } |
131 | } | 245 | } |
246 | |||
247 | return false; | ||
132 | } | 248 | } |
133 | 249 | ||
134 | public void Say(UUID agentID, Scene scene, string text) | 250 | public bool Say(UUID agentID, Scene scene, string text) |
135 | { | 251 | { |
136 | lock (m_avatars) | 252 | lock (m_avatars) |
137 | { | 253 | { |
138 | if (m_avatars.ContainsKey(agentID)) | 254 | if (m_avatars.ContainsKey(agentID)) |
139 | { | 255 | { |
256 | ScenePresence sp; | ||
257 | scene.TryGetScenePresence(agentID, out sp); | ||
258 | |||
140 | m_avatars[agentID].Say(text); | 259 | m_avatars[agentID].Say(text); |
260 | |||
261 | return true; | ||
141 | } | 262 | } |
142 | } | 263 | } |
264 | |||
265 | return false; | ||
143 | } | 266 | } |
144 | 267 | ||
145 | public void DeleteNPC(UUID agentID, Scene scene) | 268 | public bool DeleteNPC(UUID agentID, Scene scene) |
146 | { | 269 | { |
147 | lock (m_avatars) | 270 | lock (m_avatars) |
148 | { | 271 | { |
149 | if (m_avatars.ContainsKey(agentID)) | 272 | if (m_avatars.ContainsKey(agentID)) |
150 | { | 273 | { |
151 | scene.RemoveClient(agentID); | 274 | scene.RemoveClient(agentID, false); |
152 | m_avatars.Remove(agentID); | 275 | m_avatars.Remove(agentID); |
276 | |||
277 | return true; | ||
153 | } | 278 | } |
154 | } | 279 | } |
280 | |||
281 | return false; | ||
155 | } | 282 | } |
156 | 283 | ||
157 | public void PostInitialise() | 284 | public void PostInitialise() |
diff --git a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs index 899e721..78296a4 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs | |||
@@ -27,11 +27,14 @@ | |||
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Reflection; | 29 | using System.Reflection; |
30 | using log4net; | ||
30 | using Nini.Config; | 31 | using Nini.Config; |
31 | using NUnit.Framework; | 32 | using NUnit.Framework; |
32 | using OpenMetaverse; | 33 | using OpenMetaverse; |
33 | using OpenSim.Framework; | 34 | using OpenSim.Framework; |
34 | using OpenSim.Framework.Communications; | 35 | using OpenSim.Framework.Communications; |
36 | using OpenSim.Region.CoreModules.Avatar.AvatarFactory; | ||
37 | using OpenSim.Region.CoreModules.Framework.UserManagement; | ||
35 | using OpenSim.Region.CoreModules.ServiceConnectorsOut.Avatar; | 38 | using OpenSim.Region.CoreModules.ServiceConnectorsOut.Avatar; |
36 | using OpenSim.Region.Framework.Interfaces; | 39 | using OpenSim.Region.Framework.Interfaces; |
37 | using OpenSim.Region.Framework.Scenes; | 40 | using OpenSim.Region.Framework.Scenes; |
@@ -47,25 +50,112 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests | |||
47 | [Test] | 50 | [Test] |
48 | public void TestCreate() | 51 | public void TestCreate() |
49 | { | 52 | { |
50 | TestHelper.InMethod(); | 53 | TestHelpers.InMethod(); |
51 | // log4net.Config.XmlConfigurator.Configure(); | 54 | // log4net.Config.XmlConfigurator.Configure(); |
52 | 55 | ||
53 | IConfigSource config = new IniConfigSource(); | 56 | IConfigSource config = new IniConfigSource(); |
57 | config.AddConfig("NPC"); | ||
58 | config.Configs["NPC"].Set("Enabled", "true"); | ||
54 | 59 | ||
55 | config.AddConfig("Modules"); | 60 | AvatarFactoryModule afm = new AvatarFactoryModule(); |
56 | config.Configs["Modules"].Set("AvatarServices", "LocalAvatarServicesConnector"); | 61 | UserManagementModule umm = new UserManagementModule(); |
57 | config.AddConfig("AvatarService"); | ||
58 | config.Configs["AvatarService"].Set("LocalServiceModule", "OpenSim.Services.AvatarService.dll:AvatarService"); | ||
59 | config.Configs["AvatarService"].Set("StorageProvider", "OpenSim.Data.Null.dll"); | ||
60 | 62 | ||
61 | TestScene scene = SceneSetupHelpers.SetupScene(); | 63 | TestScene scene = SceneHelpers.SetupScene(); |
62 | SceneSetupHelpers.SetupSceneModules(scene, config, new NPCModule(), new LocalAvatarServicesConnector()); | 64 | SceneHelpers.SetupSceneModules(scene, config, afm, umm, new NPCModule()); |
65 | ScenePresence sp = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x1)); | ||
66 | // ScenePresence originalAvatar = scene.GetScenePresence(originalClient.AgentId); | ||
67 | |||
68 | // 8 is the index of the first baked texture in AvatarAppearance | ||
69 | UUID originalFace8TextureId = TestHelpers.ParseTail(0x10); | ||
70 | Primitive.TextureEntry originalTe = new Primitive.TextureEntry(UUID.Zero); | ||
71 | Primitive.TextureEntryFace originalTef = originalTe.CreateFace(8); | ||
72 | originalTef.TextureID = originalFace8TextureId; | ||
73 | |||
74 | // We also need to add the texture to the asset service, otherwise the AvatarFactoryModule will tell | ||
75 | // ScenePresence.SendInitialData() to reset our entire appearance. | ||
76 | scene.AssetService.Store(AssetHelpers.CreateAsset(originalFace8TextureId)); | ||
77 | |||
78 | afm.SetAppearanceFromClient(sp.ControllingClient, originalTe, null); | ||
63 | 79 | ||
64 | INPCModule npcModule = scene.RequestModuleInterface<INPCModule>(); | 80 | INPCModule npcModule = scene.RequestModuleInterface<INPCModule>(); |
65 | UUID npcId = npcModule.CreateNPC("John", "Smith", new Vector3(128, 128, 30), scene, UUID.Zero); | 81 | UUID npcId = npcModule.CreateNPC("John", "Smith", new Vector3(128, 128, 30), scene, sp.Appearance); |
66 | 82 | ||
67 | ScenePresence npc = scene.GetScenePresence(npcId); | 83 | ScenePresence npc = scene.GetScenePresence(npcId); |
84 | |||
68 | Assert.That(npc, Is.Not.Null); | 85 | Assert.That(npc, Is.Not.Null); |
86 | Assert.That(npc.Appearance.Texture.FaceTextures[8].TextureID, Is.EqualTo(originalFace8TextureId)); | ||
87 | Assert.That(umm.GetUserName(npc.UUID), Is.EqualTo(string.Format("{0} {1}", npc.Firstname, npc.Lastname))); | ||
88 | } | ||
89 | |||
90 | [Test] | ||
91 | public void TestMove() | ||
92 | { | ||
93 | TestHelpers.InMethod(); | ||
94 | // log4net.Config.XmlConfigurator.Configure(); | ||
95 | |||
96 | IConfigSource config = new IniConfigSource(); | ||
97 | |||
98 | config.AddConfig("NPC"); | ||
99 | config.Configs["NPC"].Set("Enabled", "true"); | ||
100 | |||
101 | TestScene scene = SceneHelpers.SetupScene(); | ||
102 | SceneHelpers.SetupSceneModules(scene, config, new NPCModule()); | ||
103 | ScenePresence sp = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x1)); | ||
104 | // ScenePresence originalAvatar = scene.GetScenePresence(originalClient.AgentId); | ||
105 | |||
106 | Vector3 startPos = new Vector3(128, 128, 30); | ||
107 | INPCModule npcModule = scene.RequestModuleInterface<INPCModule>(); | ||
108 | UUID npcId = npcModule.CreateNPC("John", "Smith", startPos, scene, sp.Appearance); | ||
109 | |||
110 | ScenePresence npc = scene.GetScenePresence(npcId); | ||
111 | Assert.That(npc.AbsolutePosition, Is.EqualTo(startPos)); | ||
112 | |||
113 | // For now, we'll make the scene presence fly to simplify this test, but this needs to change. | ||
114 | npc.PhysicsActor.Flying = true; | ||
115 | |||
116 | scene.Update(); | ||
117 | Assert.That(npc.AbsolutePosition, Is.EqualTo(startPos)); | ||
118 | |||
119 | Vector3 targetPos = startPos + new Vector3(0, 0, 10); | ||
120 | npcModule.MoveToTarget(npc.UUID, scene, targetPos, false, false); | ||
121 | |||
122 | Assert.That(npc.AbsolutePosition, Is.EqualTo(startPos)); | ||
123 | |||
124 | scene.Update(); | ||
125 | |||
126 | // We should really check the exact figure. | ||
127 | Assert.That(npc.AbsolutePosition.X, Is.EqualTo(startPos.X)); | ||
128 | Assert.That(npc.AbsolutePosition.Y, Is.EqualTo(startPos.Y)); | ||
129 | Assert.That(npc.AbsolutePosition.Z, Is.GreaterThan(startPos.Z)); | ||
130 | Assert.That(npc.AbsolutePosition.Z, Is.LessThan(targetPos.Z)); | ||
131 | |||
132 | for (int i = 0; i < 10; i++) | ||
133 | scene.Update(); | ||
134 | |||
135 | double distanceToTarget = Util.GetDistanceTo(npc.AbsolutePosition, targetPos); | ||
136 | Assert.That(distanceToTarget, Is.LessThan(1), "NPC not within 1 unit of target position on first move"); | ||
137 | Assert.That(npc.AbsolutePosition, Is.EqualTo(targetPos)); | ||
138 | Assert.That(npc.AgentControlFlags, Is.EqualTo((uint)AgentManager.ControlFlags.NONE)); | ||
139 | |||
140 | // Try a second movement | ||
141 | startPos = npc.AbsolutePosition; | ||
142 | targetPos = startPos + new Vector3(10, 0, 0); | ||
143 | npcModule.MoveToTarget(npc.UUID, scene, targetPos, false, false); | ||
144 | |||
145 | scene.Update(); | ||
146 | |||
147 | // We should really check the exact figure. | ||
148 | Assert.That(npc.AbsolutePosition.X, Is.GreaterThan(startPos.X)); | ||
149 | Assert.That(npc.AbsolutePosition.X, Is.LessThan(targetPos.X)); | ||
150 | Assert.That(npc.AbsolutePosition.Y, Is.EqualTo(startPos.Y)); | ||
151 | Assert.That(npc.AbsolutePosition.Z, Is.EqualTo(startPos.Z)); | ||
152 | |||
153 | for (int i = 0; i < 10; i++) | ||
154 | scene.Update(); | ||
155 | |||
156 | distanceToTarget = Util.GetDistanceTo(npc.AbsolutePosition, targetPos); | ||
157 | Assert.That(distanceToTarget, Is.LessThan(1), "NPC not within 1 unit of target position on second move"); | ||
158 | Assert.That(npc.AbsolutePosition, Is.EqualTo(targetPos)); | ||
69 | } | 159 | } |
70 | } | 160 | } |
71 | } \ No newline at end of file | 161 | } \ No newline at end of file |
diff --git a/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs b/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs index 2563361..38c2f7b 100644 --- a/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs +++ b/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs | |||
@@ -381,7 +381,6 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator | |||
381 | { | 381 | { |
382 | SceneObjectPart selectedTree = ((SceneObjectGroup)m_scene.Entities[tree]).RootPart; | 382 | SceneObjectPart selectedTree = ((SceneObjectGroup)m_scene.Entities[tree]).RootPart; |
383 | 383 | ||
384 | |||
385 | m_scene.DeleteSceneObject(selectedTree.ParentGroup, false); | 384 | m_scene.DeleteSceneObject(selectedTree.ParentGroup, false); |
386 | m_scene.ForEachClient(delegate(IClientAPI controller) | 385 | m_scene.ForEachClient(delegate(IClientAPI controller) |
387 | { | 386 | { |
diff --git a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs index 6c9d9ab..1ceed1a 100644 --- a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs +++ b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs | |||
@@ -123,11 +123,15 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin | |||
123 | actorPosition.X = ((int)Constants.RegionSize - 0.1f); | 123 | actorPosition.X = ((int)Constants.RegionSize - 0.1f); |
124 | } | 124 | } |
125 | 125 | ||
126 | float height = _heightMap[(int)actor.Position.Y * Constants.RegionSize + (int)actor.Position.X] + actor.Size.Z; | 126 | float terrainHeight = 0; |
127 | if (_heightMap != null) | ||
128 | terrainHeight = _heightMap[(int)actor.Position.Y * Constants.RegionSize + (int)actor.Position.X]; | ||
129 | |||
130 | float height = terrainHeight + actor.Size.Z; | ||
131 | |||
127 | if (actor.Flying) | 132 | if (actor.Flying) |
128 | { | 133 | { |
129 | if (actor.Position.Z + (actor.Velocity.Z*timeStep) < | 134 | if (actor.Position.Z + (actor.Velocity.Z * timeStep) < terrainHeight + 2) |
130 | _heightMap[(int)actor.Position.Y * Constants.RegionSize + (int)actor.Position.X] + 2) | ||
131 | { | 135 | { |
132 | actorPosition.Z = height; | 136 | actorPosition.Z = height; |
133 | actorVelocity.Z = 0; | 137 | actorVelocity.Z = 0; |
@@ -135,7 +139,7 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin | |||
135 | } | 139 | } |
136 | else | 140 | else |
137 | { | 141 | { |
138 | actorPosition.Z += actor.Velocity.Z*timeStep; | 142 | actorPosition.Z += actor.Velocity.Z * timeStep; |
139 | actor.IsColliding = false; | 143 | actor.IsColliding = false; |
140 | } | 144 | } |
141 | } | 145 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs new file mode 100644 index 0000000..682eb80 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs | |||
@@ -0,0 +1,451 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyrightD | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Reflection; | ||
30 | using log4net; | ||
31 | using OpenMetaverse; | ||
32 | using OpenSim.Framework; | ||
33 | using OpenSim.Region.Physics.Manager; | ||
34 | |||
35 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
36 | { | ||
37 | public class BSCharacter : PhysicsActor | ||
38 | { | ||
39 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
40 | private static readonly string LogHeader = "[BULLETS CHAR]"; | ||
41 | |||
42 | private BSScene _scene; | ||
43 | private String _avName; | ||
44 | private bool _stopped; | ||
45 | private Vector3 _size; | ||
46 | private Vector3 _scale; | ||
47 | private PrimitiveBaseShape _pbs; | ||
48 | private uint _localID = 0; | ||
49 | private bool _grabbed; | ||
50 | private bool _selected; | ||
51 | private Vector3 _position; | ||
52 | private float _mass; | ||
53 | public float _density; | ||
54 | public float _avatarVolume; | ||
55 | private Vector3 _force; | ||
56 | private Vector3 _velocity; | ||
57 | private Vector3 _torque; | ||
58 | private float _collisionScore; | ||
59 | private Vector3 _acceleration; | ||
60 | private Quaternion _orientation; | ||
61 | private int _physicsActorType; | ||
62 | private bool _isPhysical; | ||
63 | private bool _flying; | ||
64 | private bool _setAlwaysRun; | ||
65 | private bool _throttleUpdates; | ||
66 | private bool _isColliding; | ||
67 | private long _collidingStep; | ||
68 | private bool _collidingGround; | ||
69 | private long _collidingGroundStep; | ||
70 | private bool _collidingObj; | ||
71 | private bool _floatOnWater; | ||
72 | private Vector3 _rotationalVelocity; | ||
73 | private bool _kinematic; | ||
74 | private float _buoyancy; | ||
75 | |||
76 | private int _subscribedEventsMs = 0; | ||
77 | private int _lastCollisionTime = 0; | ||
78 | |||
79 | private Vector3 _PIDTarget; | ||
80 | private bool _usePID; | ||
81 | private float _PIDTau; | ||
82 | private bool _useHoverPID; | ||
83 | private float _PIDHoverHeight; | ||
84 | private PIDHoverType _PIDHoverType; | ||
85 | private float _PIDHoverTao; | ||
86 | |||
87 | public BSCharacter(uint localID, String avName, BSScene parent_scene, Vector3 pos, Vector3 size, bool isFlying) | ||
88 | { | ||
89 | _localID = localID; | ||
90 | _avName = avName; | ||
91 | _scene = parent_scene; | ||
92 | _position = pos; | ||
93 | _size = size; | ||
94 | _flying = isFlying; | ||
95 | _orientation = Quaternion.Identity; | ||
96 | _velocity = Vector3.Zero; | ||
97 | _buoyancy = isFlying ? 1f : 0f; | ||
98 | _scale = new Vector3(1f, 1f, 1f); | ||
99 | _density = _scene.Params.avatarDensity; | ||
100 | ComputeAvatarVolumeAndMass(); // set _avatarVolume and _mass based on capsule size, _density and _scale | ||
101 | |||
102 | ShapeData shapeData = new ShapeData(); | ||
103 | shapeData.ID = _localID; | ||
104 | shapeData.Type = ShapeData.PhysicsShapeType.SHAPE_AVATAR; | ||
105 | shapeData.Position = _position; | ||
106 | shapeData.Rotation = _orientation; | ||
107 | shapeData.Velocity = _velocity; | ||
108 | shapeData.Scale = _scale; | ||
109 | shapeData.Mass = _mass; | ||
110 | shapeData.Buoyancy = _buoyancy; | ||
111 | shapeData.Static = ShapeData.numericFalse; | ||
112 | shapeData.Friction = _scene.Params.avatarFriction; | ||
113 | shapeData.Restitution = _scene.Params.defaultRestitution; | ||
114 | |||
115 | // do actual create at taint time | ||
116 | _scene.TaintedObject(delegate() | ||
117 | { | ||
118 | BulletSimAPI.CreateObject(parent_scene.WorldID, shapeData); | ||
119 | }); | ||
120 | |||
121 | return; | ||
122 | } | ||
123 | |||
124 | // called when this character is being destroyed and the resources should be released | ||
125 | public void Destroy() | ||
126 | { | ||
127 | _scene.TaintedObject(delegate() | ||
128 | { | ||
129 | BulletSimAPI.DestroyObject(_scene.WorldID, _localID); | ||
130 | }); | ||
131 | } | ||
132 | |||
133 | public override void RequestPhysicsterseUpdate() | ||
134 | { | ||
135 | base.RequestPhysicsterseUpdate(); | ||
136 | } | ||
137 | |||
138 | public override bool Stopped { | ||
139 | get { return _stopped; } | ||
140 | } | ||
141 | public override Vector3 Size { | ||
142 | get { return _size; } | ||
143 | set { _size = value; | ||
144 | } | ||
145 | } | ||
146 | public override PrimitiveBaseShape Shape { | ||
147 | set { _pbs = value; | ||
148 | } | ||
149 | } | ||
150 | public override uint LocalID { | ||
151 | set { _localID = value; | ||
152 | } | ||
153 | get { return _localID; } | ||
154 | } | ||
155 | public override bool Grabbed { | ||
156 | set { _grabbed = value; | ||
157 | } | ||
158 | } | ||
159 | public override bool Selected { | ||
160 | set { _selected = value; | ||
161 | } | ||
162 | } | ||
163 | public override void CrossingFailure() { return; } | ||
164 | public override void link(PhysicsActor obj) { return; } | ||
165 | public override void delink() { return; } | ||
166 | public override void LockAngularMotion(Vector3 axis) { return; } | ||
167 | |||
168 | public override Vector3 Position { | ||
169 | get { | ||
170 | // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); | ||
171 | return _position; | ||
172 | } | ||
173 | set { | ||
174 | _position = value; | ||
175 | _scene.TaintedObject(delegate() | ||
176 | { | ||
177 | BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); | ||
178 | }); | ||
179 | } | ||
180 | } | ||
181 | public override float Mass { | ||
182 | get { | ||
183 | return _mass; | ||
184 | } | ||
185 | } | ||
186 | public override Vector3 Force { | ||
187 | get { return _force; } | ||
188 | set { | ||
189 | _force = value; | ||
190 | // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); | ||
191 | _scene.TaintedObject(delegate() | ||
192 | { | ||
193 | BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force); | ||
194 | }); | ||
195 | } | ||
196 | } | ||
197 | |||
198 | public override int VehicleType { | ||
199 | get { return 0; } | ||
200 | set { return; } | ||
201 | } | ||
202 | public override void VehicleFloatParam(int param, float value) { } | ||
203 | public override void VehicleVectorParam(int param, Vector3 value) {} | ||
204 | public override void VehicleRotationParam(int param, Quaternion rotation) { } | ||
205 | public override void VehicleFlags(int param, bool remove) { } | ||
206 | |||
207 | // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more | ||
208 | public override void SetVolumeDetect(int param) { return; } | ||
209 | |||
210 | public override Vector3 GeometricCenter { get { return Vector3.Zero; } } | ||
211 | public override Vector3 CenterOfMass { get { return Vector3.Zero; } } | ||
212 | public override Vector3 Velocity { | ||
213 | get { return _velocity; } | ||
214 | set { | ||
215 | _velocity = value; | ||
216 | // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); | ||
217 | _scene.TaintedObject(delegate() | ||
218 | { | ||
219 | BulletSimAPI.SetObjectVelocity(_scene.WorldID, _localID, _velocity); | ||
220 | }); | ||
221 | } | ||
222 | } | ||
223 | public override Vector3 Torque { | ||
224 | get { return _torque; } | ||
225 | set { _torque = value; | ||
226 | } | ||
227 | } | ||
228 | public override float CollisionScore { | ||
229 | get { return _collisionScore; } | ||
230 | set { _collisionScore = value; | ||
231 | } | ||
232 | } | ||
233 | public override Vector3 Acceleration { | ||
234 | get { return _acceleration; } | ||
235 | } | ||
236 | public override Quaternion Orientation { | ||
237 | get { return _orientation; } | ||
238 | set { | ||
239 | _orientation = value; | ||
240 | // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation); | ||
241 | _scene.TaintedObject(delegate() | ||
242 | { | ||
243 | // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); | ||
244 | BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); | ||
245 | }); | ||
246 | } | ||
247 | } | ||
248 | public override int PhysicsActorType { | ||
249 | get { return _physicsActorType; } | ||
250 | set { _physicsActorType = value; | ||
251 | } | ||
252 | } | ||
253 | public override bool IsPhysical { | ||
254 | get { return _isPhysical; } | ||
255 | set { _isPhysical = value; | ||
256 | } | ||
257 | } | ||
258 | public override bool Flying { | ||
259 | get { return _flying; } | ||
260 | set { | ||
261 | _flying = value; | ||
262 | _scene.TaintedObject(delegate() | ||
263 | { | ||
264 | // simulate flying by changing the effect of gravity | ||
265 | BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, LocalID, _flying ? 1f : 0f); | ||
266 | }); | ||
267 | } | ||
268 | } | ||
269 | public override bool | ||
270 | SetAlwaysRun { | ||
271 | get { return _setAlwaysRun; } | ||
272 | set { _setAlwaysRun = value; } | ||
273 | } | ||
274 | public override bool ThrottleUpdates { | ||
275 | get { return _throttleUpdates; } | ||
276 | set { _throttleUpdates = value; } | ||
277 | } | ||
278 | public override bool IsColliding { | ||
279 | get { return (_collidingStep == _scene.SimulationStep); } | ||
280 | set { _isColliding = value; } | ||
281 | } | ||
282 | public override bool CollidingGround { | ||
283 | get { return (_collidingGroundStep == _scene.SimulationStep); } | ||
284 | set { _collidingGround = value; } | ||
285 | } | ||
286 | public override bool CollidingObj { | ||
287 | get { return _collidingObj; } | ||
288 | set { _collidingObj = value; } | ||
289 | } | ||
290 | public override bool FloatOnWater { | ||
291 | set { _floatOnWater = value; } | ||
292 | } | ||
293 | public override Vector3 RotationalVelocity { | ||
294 | get { return _rotationalVelocity; } | ||
295 | set { _rotationalVelocity = value; } | ||
296 | } | ||
297 | public override bool Kinematic { | ||
298 | get { return _kinematic; } | ||
299 | set { _kinematic = value; } | ||
300 | } | ||
301 | public override float Buoyancy { | ||
302 | get { return _buoyancy; } | ||
303 | set { _buoyancy = value; | ||
304 | _scene.TaintedObject(delegate() | ||
305 | { | ||
306 | BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, LocalID, _buoyancy); | ||
307 | }); | ||
308 | } | ||
309 | } | ||
310 | |||
311 | // Used for MoveTo | ||
312 | public override Vector3 PIDTarget { | ||
313 | set { _PIDTarget = value; } | ||
314 | } | ||
315 | public override bool PIDActive { | ||
316 | set { _usePID = value; } | ||
317 | } | ||
318 | public override float PIDTau { | ||
319 | set { _PIDTau = value; } | ||
320 | } | ||
321 | |||
322 | // Used for llSetHoverHeight and maybe vehicle height | ||
323 | // Hover Height will override MoveTo target's Z | ||
324 | public override bool PIDHoverActive { | ||
325 | set { _useHoverPID = value; } | ||
326 | } | ||
327 | public override float PIDHoverHeight { | ||
328 | set { _PIDHoverHeight = value; } | ||
329 | } | ||
330 | public override PIDHoverType PIDHoverType { | ||
331 | set { _PIDHoverType = value; } | ||
332 | } | ||
333 | public override float PIDHoverTau { | ||
334 | set { _PIDHoverTao = value; } | ||
335 | } | ||
336 | |||
337 | // For RotLookAt | ||
338 | public override Quaternion APIDTarget { set { return; } } | ||
339 | public override bool APIDActive { set { return; } } | ||
340 | public override float APIDStrength { set { return; } } | ||
341 | public override float APIDDamping { set { return; } } | ||
342 | |||
343 | public override void AddForce(Vector3 force, bool pushforce) { | ||
344 | if (force.IsFinite()) | ||
345 | { | ||
346 | _force.X += force.X; | ||
347 | _force.Y += force.Y; | ||
348 | _force.Z += force.Z; | ||
349 | // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force); | ||
350 | _scene.TaintedObject(delegate() | ||
351 | { | ||
352 | BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force); | ||
353 | }); | ||
354 | } | ||
355 | else | ||
356 | { | ||
357 | m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader); | ||
358 | } | ||
359 | //m_lastUpdateSent = false; | ||
360 | } | ||
361 | public override void AddAngularForce(Vector3 force, bool pushforce) { | ||
362 | } | ||
363 | public override void SetMomentum(Vector3 momentum) { | ||
364 | } | ||
365 | public override void SubscribeEvents(int ms) { | ||
366 | _subscribedEventsMs = ms; | ||
367 | _lastCollisionTime = Util.EnvironmentTickCount() - _subscribedEventsMs; // make first collision happen | ||
368 | } | ||
369 | public override void UnSubscribeEvents() { | ||
370 | _subscribedEventsMs = 0; | ||
371 | } | ||
372 | public override bool SubscribedEvents() { | ||
373 | return (_subscribedEventsMs > 0); | ||
374 | } | ||
375 | |||
376 | // set _avatarVolume and _mass based on capsule size, _density and _scale | ||
377 | private void ComputeAvatarVolumeAndMass() | ||
378 | { | ||
379 | _avatarVolume = (float)( | ||
380 | Math.PI | ||
381 | * _scene.Params.avatarCapsuleRadius * _scale.X | ||
382 | * _scene.Params.avatarCapsuleRadius * _scale.Y | ||
383 | * _scene.Params.avatarCapsuleHeight * _scale.Z); | ||
384 | _mass = _density * _avatarVolume; | ||
385 | } | ||
386 | |||
387 | // The physics engine says that properties have updated. Update same and inform | ||
388 | // the world that things have changed. | ||
389 | public void UpdateProperties(EntityProperties entprop) | ||
390 | { | ||
391 | bool changed = false; | ||
392 | // we assign to the local variables so the normal set action does not happen | ||
393 | if (_position != entprop.Position) | ||
394 | { | ||
395 | _position = entprop.Position; | ||
396 | changed = true; | ||
397 | } | ||
398 | if (_orientation != entprop.Rotation) | ||
399 | { | ||
400 | _orientation = entprop.Rotation; | ||
401 | changed = true; | ||
402 | } | ||
403 | if (_velocity != entprop.Velocity) | ||
404 | { | ||
405 | _velocity = entprop.Velocity; | ||
406 | changed = true; | ||
407 | } | ||
408 | if (_acceleration != entprop.Acceleration) | ||
409 | { | ||
410 | _acceleration = entprop.Acceleration; | ||
411 | changed = true; | ||
412 | } | ||
413 | if (_rotationalVelocity != entprop.RotationalVelocity) | ||
414 | { | ||
415 | _rotationalVelocity = entprop.RotationalVelocity; | ||
416 | changed = true; | ||
417 | } | ||
418 | if (changed) | ||
419 | { | ||
420 | // m_log.DebugFormat("{0}: UpdateProperties: id={1}, c={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation); | ||
421 | // Avatar movement is not done by generating this event. There is a system that | ||
422 | // checks for avatar updates each heartbeat loop. | ||
423 | // base.RequestPhysicsterseUpdate(); | ||
424 | } | ||
425 | } | ||
426 | |||
427 | public void Collide(uint collidingWith, ActorTypes type, Vector3 contactPoint, Vector3 contactNormal, float pentrationDepth) | ||
428 | { | ||
429 | // m_log.DebugFormat("{0}: Collide: ms={1}, id={2}, with={3}", LogHeader, _subscribedEventsMs, LocalID, collidingWith); | ||
430 | |||
431 | // The following makes IsColliding() and IsCollidingGround() work | ||
432 | _collidingStep = _scene.SimulationStep; | ||
433 | if (collidingWith == BSScene.TERRAIN_ID || collidingWith == BSScene.GROUNDPLANE_ID) | ||
434 | { | ||
435 | _collidingGroundStep = _scene.SimulationStep; | ||
436 | } | ||
437 | |||
438 | // throttle collisions to the rate specified in the subscription | ||
439 | if (_subscribedEventsMs == 0) return; // don't want collisions | ||
440 | int nowTime = _scene.SimulationNowTime; | ||
441 | if (nowTime < (_lastCollisionTime + _subscribedEventsMs)) return; | ||
442 | _lastCollisionTime = nowTime; | ||
443 | |||
444 | Dictionary<uint, ContactPoint> contactPoints = new Dictionary<uint, ContactPoint>(); | ||
445 | contactPoints.Add(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); | ||
446 | CollisionEventUpdate args = new CollisionEventUpdate(LocalID, (int)type, 1, contactPoints); | ||
447 | base.SendCollisionUpdate(args); | ||
448 | } | ||
449 | |||
450 | } | ||
451 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs new file mode 100644 index 0000000..046726d --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | |||
@@ -0,0 +1,951 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | /* RA: June 14, 2011. Copied from ODEDynamics.cs and converted to | ||
29 | * call the BulletSim system. | ||
30 | */ | ||
31 | /* Revised Aug, Sept 2009 by Kitto Flora. ODEDynamics.cs replaces | ||
32 | * ODEVehicleSettings.cs. It and ODEPrim.cs are re-organised: | ||
33 | * ODEPrim.cs contains methods dealing with Prim editing, Prim | ||
34 | * characteristics and Kinetic motion. | ||
35 | * ODEDynamics.cs contains methods dealing with Prim Physical motion | ||
36 | * (dynamics) and the associated settings. Old Linear and angular | ||
37 | * motors for dynamic motion have been replace with MoveLinear() | ||
38 | * and MoveAngular(); 'Physical' is used only to switch ODE dynamic | ||
39 | * simualtion on/off; VEHICAL_TYPE_NONE/VEHICAL_TYPE_<other> is to | ||
40 | * switch between 'VEHICLE' parameter use and general dynamics | ||
41 | * settings use. | ||
42 | */ | ||
43 | |||
44 | using System; | ||
45 | using System.Collections.Generic; | ||
46 | using System.Reflection; | ||
47 | using System.Runtime.InteropServices; | ||
48 | using log4net; | ||
49 | using OpenMetaverse; | ||
50 | using OpenSim.Framework; | ||
51 | using OpenSim.Region.Physics.Manager; | ||
52 | |||
53 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
54 | { | ||
55 | public class BSDynamics | ||
56 | { | ||
57 | private int frcount = 0; // Used to limit dynamics debug output to | ||
58 | // every 100th frame | ||
59 | |||
60 | // private BSScene m_parentScene = null; | ||
61 | private BSPrim m_prim; // the prim this dynamic controller belongs to | ||
62 | |||
63 | // Vehicle properties | ||
64 | private Vehicle m_type = Vehicle.TYPE_NONE; // If a 'VEHICLE', and what kind | ||
65 | public Vehicle Type | ||
66 | { | ||
67 | get { return m_type; } | ||
68 | } | ||
69 | // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier | ||
70 | private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings: | ||
71 | // HOVER_TERRAIN_ONLY | ||
72 | // HOVER_GLOBAL_HEIGHT | ||
73 | // NO_DEFLECTION_UP | ||
74 | // HOVER_WATER_ONLY | ||
75 | // HOVER_UP_ONLY | ||
76 | // LIMIT_MOTOR_UP | ||
77 | // LIMIT_ROLL_ONLY | ||
78 | private VehicleFlag m_Hoverflags = (VehicleFlag)0; | ||
79 | private Vector3 m_BlockingEndPoint = Vector3.Zero; | ||
80 | private Quaternion m_RollreferenceFrame = Quaternion.Identity; | ||
81 | // Linear properties | ||
82 | private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time | ||
83 | private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL | ||
84 | private Vector3 m_dir = Vector3.Zero; // velocity applied to body | ||
85 | private Vector3 m_linearFrictionTimescale = Vector3.Zero; | ||
86 | private float m_linearMotorDecayTimescale = 0; | ||
87 | private float m_linearMotorTimescale = 0; | ||
88 | private Vector3 m_lastLinearVelocityVector = Vector3.Zero; | ||
89 | private Vector3 m_lastPositionVector = Vector3.Zero; | ||
90 | // private bool m_LinearMotorSetLastFrame = false; | ||
91 | // private Vector3 m_linearMotorOffset = Vector3.Zero; | ||
92 | |||
93 | //Angular properties | ||
94 | private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor | ||
95 | private int m_angularMotorApply = 0; // application frame counter | ||
96 | private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity | ||
97 | private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate | ||
98 | private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate | ||
99 | private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate | ||
100 | private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body | ||
101 | // private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body | ||
102 | |||
103 | //Deflection properties | ||
104 | // private float m_angularDeflectionEfficiency = 0; | ||
105 | // private float m_angularDeflectionTimescale = 0; | ||
106 | // private float m_linearDeflectionEfficiency = 0; | ||
107 | // private float m_linearDeflectionTimescale = 0; | ||
108 | |||
109 | //Banking properties | ||
110 | // private float m_bankingEfficiency = 0; | ||
111 | // private float m_bankingMix = 0; | ||
112 | // private float m_bankingTimescale = 0; | ||
113 | |||
114 | //Hover and Buoyancy properties | ||
115 | private float m_VhoverHeight = 0f; | ||
116 | // private float m_VhoverEfficiency = 0f; | ||
117 | private float m_VhoverTimescale = 0f; | ||
118 | private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height | ||
119 | private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle. | ||
120 | // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity) | ||
121 | // KF: So far I have found no good method to combine a script-requested .Z velocity and gravity. | ||
122 | // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity. | ||
123 | |||
124 | //Attractor properties | ||
125 | private float m_verticalAttractionEfficiency = 1.0f; // damped | ||
126 | private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor. | ||
127 | |||
128 | public BSDynamics(BSPrim myPrim) | ||
129 | { | ||
130 | m_prim = myPrim; | ||
131 | m_type = Vehicle.TYPE_NONE; | ||
132 | } | ||
133 | |||
134 | internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue) | ||
135 | { | ||
136 | switch (pParam) | ||
137 | { | ||
138 | case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: | ||
139 | if (pValue < 0.01f) pValue = 0.01f; | ||
140 | // m_angularDeflectionEfficiency = pValue; | ||
141 | break; | ||
142 | case Vehicle.ANGULAR_DEFLECTION_TIMESCALE: | ||
143 | if (pValue < 0.01f) pValue = 0.01f; | ||
144 | // m_angularDeflectionTimescale = pValue; | ||
145 | break; | ||
146 | case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: | ||
147 | if (pValue < 0.01f) pValue = 0.01f; | ||
148 | m_angularMotorDecayTimescale = pValue; | ||
149 | break; | ||
150 | case Vehicle.ANGULAR_MOTOR_TIMESCALE: | ||
151 | if (pValue < 0.01f) pValue = 0.01f; | ||
152 | m_angularMotorTimescale = pValue; | ||
153 | break; | ||
154 | case Vehicle.BANKING_EFFICIENCY: | ||
155 | if (pValue < 0.01f) pValue = 0.01f; | ||
156 | // m_bankingEfficiency = pValue; | ||
157 | break; | ||
158 | case Vehicle.BANKING_MIX: | ||
159 | if (pValue < 0.01f) pValue = 0.01f; | ||
160 | // m_bankingMix = pValue; | ||
161 | break; | ||
162 | case Vehicle.BANKING_TIMESCALE: | ||
163 | if (pValue < 0.01f) pValue = 0.01f; | ||
164 | // m_bankingTimescale = pValue; | ||
165 | break; | ||
166 | case Vehicle.BUOYANCY: | ||
167 | if (pValue < -1f) pValue = -1f; | ||
168 | if (pValue > 1f) pValue = 1f; | ||
169 | m_VehicleBuoyancy = pValue; | ||
170 | break; | ||
171 | // case Vehicle.HOVER_EFFICIENCY: | ||
172 | // if (pValue < 0f) pValue = 0f; | ||
173 | // if (pValue > 1f) pValue = 1f; | ||
174 | // m_VhoverEfficiency = pValue; | ||
175 | // break; | ||
176 | case Vehicle.HOVER_HEIGHT: | ||
177 | m_VhoverHeight = pValue; | ||
178 | break; | ||
179 | case Vehicle.HOVER_TIMESCALE: | ||
180 | if (pValue < 0.01f) pValue = 0.01f; | ||
181 | m_VhoverTimescale = pValue; | ||
182 | break; | ||
183 | case Vehicle.LINEAR_DEFLECTION_EFFICIENCY: | ||
184 | if (pValue < 0.01f) pValue = 0.01f; | ||
185 | // m_linearDeflectionEfficiency = pValue; | ||
186 | break; | ||
187 | case Vehicle.LINEAR_DEFLECTION_TIMESCALE: | ||
188 | if (pValue < 0.01f) pValue = 0.01f; | ||
189 | // m_linearDeflectionTimescale = pValue; | ||
190 | break; | ||
191 | case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: | ||
192 | if (pValue < 0.01f) pValue = 0.01f; | ||
193 | m_linearMotorDecayTimescale = pValue; | ||
194 | break; | ||
195 | case Vehicle.LINEAR_MOTOR_TIMESCALE: | ||
196 | if (pValue < 0.01f) pValue = 0.01f; | ||
197 | m_linearMotorTimescale = pValue; | ||
198 | break; | ||
199 | case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: | ||
200 | if (pValue < 0.1f) pValue = 0.1f; // Less goes unstable | ||
201 | if (pValue > 1.0f) pValue = 1.0f; | ||
202 | m_verticalAttractionEfficiency = pValue; | ||
203 | break; | ||
204 | case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: | ||
205 | if (pValue < 0.01f) pValue = 0.01f; | ||
206 | m_verticalAttractionTimescale = pValue; | ||
207 | break; | ||
208 | |||
209 | // These are vector properties but the engine lets you use a single float value to | ||
210 | // set all of the components to the same value | ||
211 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: | ||
212 | m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); | ||
213 | break; | ||
214 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | ||
215 | m_angularMotorDirection = new Vector3(pValue, pValue, pValue); | ||
216 | m_angularMotorApply = 10; | ||
217 | break; | ||
218 | case Vehicle.LINEAR_FRICTION_TIMESCALE: | ||
219 | m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); | ||
220 | break; | ||
221 | case Vehicle.LINEAR_MOTOR_DIRECTION: | ||
222 | m_linearMotorDirection = new Vector3(pValue, pValue, pValue); | ||
223 | m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); | ||
224 | break; | ||
225 | case Vehicle.LINEAR_MOTOR_OFFSET: | ||
226 | // m_linearMotorOffset = new Vector3(pValue, pValue, pValue); | ||
227 | break; | ||
228 | |||
229 | } | ||
230 | }//end ProcessFloatVehicleParam | ||
231 | |||
232 | internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue) | ||
233 | { | ||
234 | switch (pParam) | ||
235 | { | ||
236 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: | ||
237 | m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
238 | break; | ||
239 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | ||
240 | m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
241 | // Limit requested angular speed to 2 rps= 4 pi rads/sec | ||
242 | if (m_angularMotorDirection.X > 12.56f) m_angularMotorDirection.X = 12.56f; | ||
243 | if (m_angularMotorDirection.X < - 12.56f) m_angularMotorDirection.X = - 12.56f; | ||
244 | if (m_angularMotorDirection.Y > 12.56f) m_angularMotorDirection.Y = 12.56f; | ||
245 | if (m_angularMotorDirection.Y < - 12.56f) m_angularMotorDirection.Y = - 12.56f; | ||
246 | if (m_angularMotorDirection.Z > 12.56f) m_angularMotorDirection.Z = 12.56f; | ||
247 | if (m_angularMotorDirection.Z < - 12.56f) m_angularMotorDirection.Z = - 12.56f; | ||
248 | m_angularMotorApply = 10; | ||
249 | break; | ||
250 | case Vehicle.LINEAR_FRICTION_TIMESCALE: | ||
251 | m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
252 | break; | ||
253 | case Vehicle.LINEAR_MOTOR_DIRECTION: | ||
254 | m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
255 | m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
256 | break; | ||
257 | case Vehicle.LINEAR_MOTOR_OFFSET: | ||
258 | // m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
259 | break; | ||
260 | case Vehicle.BLOCK_EXIT: | ||
261 | m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
262 | break; | ||
263 | } | ||
264 | }//end ProcessVectorVehicleParam | ||
265 | |||
266 | internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) | ||
267 | { | ||
268 | switch (pParam) | ||
269 | { | ||
270 | case Vehicle.REFERENCE_FRAME: | ||
271 | // m_referenceFrame = pValue; | ||
272 | break; | ||
273 | case Vehicle.ROLL_FRAME: | ||
274 | m_RollreferenceFrame = pValue; | ||
275 | break; | ||
276 | } | ||
277 | }//end ProcessRotationVehicleParam | ||
278 | |||
279 | internal void ProcessVehicleFlags(int pParam, bool remove) | ||
280 | { | ||
281 | if (remove) | ||
282 | { | ||
283 | if (pParam == -1) | ||
284 | { | ||
285 | m_flags = (VehicleFlag)0; | ||
286 | m_Hoverflags = (VehicleFlag)0; | ||
287 | return; | ||
288 | } | ||
289 | if ((pParam & (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) == (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) | ||
290 | { | ||
291 | if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != (VehicleFlag)0) | ||
292 | m_Hoverflags &= ~(VehicleFlag.HOVER_GLOBAL_HEIGHT); | ||
293 | } | ||
294 | if ((pParam & (int)VehicleFlag.HOVER_TERRAIN_ONLY) == (int)VehicleFlag.HOVER_TERRAIN_ONLY) | ||
295 | { | ||
296 | if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != (VehicleFlag)0) | ||
297 | m_Hoverflags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY); | ||
298 | } | ||
299 | if ((pParam & (int)VehicleFlag.HOVER_UP_ONLY) == (int)VehicleFlag.HOVER_UP_ONLY) | ||
300 | { | ||
301 | if ((m_Hoverflags & VehicleFlag.HOVER_UP_ONLY) != (VehicleFlag)0) | ||
302 | m_Hoverflags &= ~(VehicleFlag.HOVER_UP_ONLY); | ||
303 | } | ||
304 | if ((pParam & (int)VehicleFlag.HOVER_WATER_ONLY) == (int)VehicleFlag.HOVER_WATER_ONLY) | ||
305 | { | ||
306 | if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != (VehicleFlag)0) | ||
307 | m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY); | ||
308 | } | ||
309 | if ((pParam & (int)VehicleFlag.LIMIT_MOTOR_UP) == (int)VehicleFlag.LIMIT_MOTOR_UP) | ||
310 | { | ||
311 | if ((m_flags & VehicleFlag.LIMIT_MOTOR_UP) != (VehicleFlag)0) | ||
312 | m_flags &= ~(VehicleFlag.LIMIT_MOTOR_UP); | ||
313 | } | ||
314 | if ((pParam & (int)VehicleFlag.LIMIT_ROLL_ONLY) == (int)VehicleFlag.LIMIT_ROLL_ONLY) | ||
315 | { | ||
316 | if ((m_flags & VehicleFlag.LIMIT_ROLL_ONLY) != (VehicleFlag)0) | ||
317 | m_flags &= ~(VehicleFlag.LIMIT_ROLL_ONLY); | ||
318 | } | ||
319 | if ((pParam & (int)VehicleFlag.MOUSELOOK_BANK) == (int)VehicleFlag.MOUSELOOK_BANK) | ||
320 | { | ||
321 | if ((m_flags & VehicleFlag.MOUSELOOK_BANK) != (VehicleFlag)0) | ||
322 | m_flags &= ~(VehicleFlag.MOUSELOOK_BANK); | ||
323 | } | ||
324 | if ((pParam & (int)VehicleFlag.MOUSELOOK_STEER) == (int)VehicleFlag.MOUSELOOK_STEER) | ||
325 | { | ||
326 | if ((m_flags & VehicleFlag.MOUSELOOK_STEER) != (VehicleFlag)0) | ||
327 | m_flags &= ~(VehicleFlag.MOUSELOOK_STEER); | ||
328 | } | ||
329 | if ((pParam & (int)VehicleFlag.NO_DEFLECTION_UP) == (int)VehicleFlag.NO_DEFLECTION_UP) | ||
330 | { | ||
331 | if ((m_flags & VehicleFlag.NO_DEFLECTION_UP) != (VehicleFlag)0) | ||
332 | m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP); | ||
333 | } | ||
334 | if ((pParam & (int)VehicleFlag.CAMERA_DECOUPLED) == (int)VehicleFlag.CAMERA_DECOUPLED) | ||
335 | { | ||
336 | if ((m_flags & VehicleFlag.CAMERA_DECOUPLED) != (VehicleFlag)0) | ||
337 | m_flags &= ~(VehicleFlag.CAMERA_DECOUPLED); | ||
338 | } | ||
339 | if ((pParam & (int)VehicleFlag.NO_X) == (int)VehicleFlag.NO_X) | ||
340 | { | ||
341 | if ((m_flags & VehicleFlag.NO_X) != (VehicleFlag)0) | ||
342 | m_flags &= ~(VehicleFlag.NO_X); | ||
343 | } | ||
344 | if ((pParam & (int)VehicleFlag.NO_Y) == (int)VehicleFlag.NO_Y) | ||
345 | { | ||
346 | if ((m_flags & VehicleFlag.NO_Y) != (VehicleFlag)0) | ||
347 | m_flags &= ~(VehicleFlag.NO_Y); | ||
348 | } | ||
349 | if ((pParam & (int)VehicleFlag.NO_Z) == (int)VehicleFlag.NO_Z) | ||
350 | { | ||
351 | if ((m_flags & VehicleFlag.NO_Z) != (VehicleFlag)0) | ||
352 | m_flags &= ~(VehicleFlag.NO_Z); | ||
353 | } | ||
354 | if ((pParam & (int)VehicleFlag.LOCK_HOVER_HEIGHT) == (int)VehicleFlag.LOCK_HOVER_HEIGHT) | ||
355 | { | ||
356 | if ((m_Hoverflags & VehicleFlag.LOCK_HOVER_HEIGHT) != (VehicleFlag)0) | ||
357 | m_Hoverflags &= ~(VehicleFlag.LOCK_HOVER_HEIGHT); | ||
358 | } | ||
359 | if ((pParam & (int)VehicleFlag.NO_DEFLECTION) == (int)VehicleFlag.NO_DEFLECTION) | ||
360 | { | ||
361 | if ((m_flags & VehicleFlag.NO_DEFLECTION) != (VehicleFlag)0) | ||
362 | m_flags &= ~(VehicleFlag.NO_DEFLECTION); | ||
363 | } | ||
364 | if ((pParam & (int)VehicleFlag.LOCK_ROTATION) == (int)VehicleFlag.LOCK_ROTATION) | ||
365 | { | ||
366 | if ((m_flags & VehicleFlag.LOCK_ROTATION) != (VehicleFlag)0) | ||
367 | m_flags &= ~(VehicleFlag.LOCK_ROTATION); | ||
368 | } | ||
369 | } | ||
370 | else | ||
371 | { | ||
372 | if ((pParam & (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) == (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) | ||
373 | { | ||
374 | m_Hoverflags |= (VehicleFlag.HOVER_GLOBAL_HEIGHT | m_flags); | ||
375 | } | ||
376 | if ((pParam & (int)VehicleFlag.HOVER_TERRAIN_ONLY) == (int)VehicleFlag.HOVER_TERRAIN_ONLY) | ||
377 | { | ||
378 | m_Hoverflags |= (VehicleFlag.HOVER_TERRAIN_ONLY | m_flags); | ||
379 | } | ||
380 | if ((pParam & (int)VehicleFlag.HOVER_UP_ONLY) == (int)VehicleFlag.HOVER_UP_ONLY) | ||
381 | { | ||
382 | m_Hoverflags |= (VehicleFlag.HOVER_UP_ONLY | m_flags); | ||
383 | } | ||
384 | if ((pParam & (int)VehicleFlag.HOVER_WATER_ONLY) == (int)VehicleFlag.HOVER_WATER_ONLY) | ||
385 | { | ||
386 | m_Hoverflags |= (VehicleFlag.HOVER_WATER_ONLY | m_flags); | ||
387 | } | ||
388 | if ((pParam & (int)VehicleFlag.LIMIT_MOTOR_UP) == (int)VehicleFlag.LIMIT_MOTOR_UP) | ||
389 | { | ||
390 | m_flags |= (VehicleFlag.LIMIT_MOTOR_UP | m_flags); | ||
391 | } | ||
392 | if ((pParam & (int)VehicleFlag.MOUSELOOK_BANK) == (int)VehicleFlag.MOUSELOOK_BANK) | ||
393 | { | ||
394 | m_flags |= (VehicleFlag.MOUSELOOK_BANK | m_flags); | ||
395 | } | ||
396 | if ((pParam & (int)VehicleFlag.MOUSELOOK_STEER) == (int)VehicleFlag.MOUSELOOK_STEER) | ||
397 | { | ||
398 | m_flags |= (VehicleFlag.MOUSELOOK_STEER | m_flags); | ||
399 | } | ||
400 | if ((pParam & (int)VehicleFlag.NO_DEFLECTION_UP) == (int)VehicleFlag.NO_DEFLECTION_UP) | ||
401 | { | ||
402 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | m_flags); | ||
403 | } | ||
404 | if ((pParam & (int)VehicleFlag.CAMERA_DECOUPLED) == (int)VehicleFlag.CAMERA_DECOUPLED) | ||
405 | { | ||
406 | m_flags |= (VehicleFlag.CAMERA_DECOUPLED | m_flags); | ||
407 | } | ||
408 | if ((pParam & (int)VehicleFlag.NO_X) == (int)VehicleFlag.NO_X) | ||
409 | { | ||
410 | m_flags |= (VehicleFlag.NO_X); | ||
411 | } | ||
412 | if ((pParam & (int)VehicleFlag.NO_Y) == (int)VehicleFlag.NO_Y) | ||
413 | { | ||
414 | m_flags |= (VehicleFlag.NO_Y); | ||
415 | } | ||
416 | if ((pParam & (int)VehicleFlag.NO_Z) == (int)VehicleFlag.NO_Z) | ||
417 | { | ||
418 | m_flags |= (VehicleFlag.NO_Z); | ||
419 | } | ||
420 | if ((pParam & (int)VehicleFlag.LOCK_HOVER_HEIGHT) == (int)VehicleFlag.LOCK_HOVER_HEIGHT) | ||
421 | { | ||
422 | m_Hoverflags |= (VehicleFlag.LOCK_HOVER_HEIGHT); | ||
423 | } | ||
424 | if ((pParam & (int)VehicleFlag.NO_DEFLECTION) == (int)VehicleFlag.NO_DEFLECTION) | ||
425 | { | ||
426 | m_flags |= (VehicleFlag.NO_DEFLECTION); | ||
427 | } | ||
428 | if ((pParam & (int)VehicleFlag.LOCK_ROTATION) == (int)VehicleFlag.LOCK_ROTATION) | ||
429 | { | ||
430 | m_flags |= (VehicleFlag.LOCK_ROTATION); | ||
431 | } | ||
432 | } | ||
433 | }//end ProcessVehicleFlags | ||
434 | |||
435 | internal void ProcessTypeChange(Vehicle pType) | ||
436 | { | ||
437 | // Set Defaults For Type | ||
438 | m_type = pType; | ||
439 | switch (pType) | ||
440 | { | ||
441 | case Vehicle.TYPE_NONE: | ||
442 | m_linearFrictionTimescale = new Vector3(0, 0, 0); | ||
443 | m_angularFrictionTimescale = new Vector3(0, 0, 0); | ||
444 | m_linearMotorDirection = Vector3.Zero; | ||
445 | m_linearMotorTimescale = 0; | ||
446 | m_linearMotorDecayTimescale = 0; | ||
447 | m_angularMotorDirection = Vector3.Zero; | ||
448 | m_angularMotorTimescale = 0; | ||
449 | m_angularMotorDecayTimescale = 0; | ||
450 | m_VhoverHeight = 0; | ||
451 | m_VhoverTimescale = 0; | ||
452 | m_VehicleBuoyancy = 0; | ||
453 | m_flags = (VehicleFlag)0; | ||
454 | break; | ||
455 | |||
456 | case Vehicle.TYPE_SLED: | ||
457 | m_linearFrictionTimescale = new Vector3(30, 1, 1000); | ||
458 | m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); | ||
459 | m_linearMotorDirection = Vector3.Zero; | ||
460 | m_linearMotorTimescale = 1000; | ||
461 | m_linearMotorDecayTimescale = 120; | ||
462 | m_angularMotorDirection = Vector3.Zero; | ||
463 | m_angularMotorTimescale = 1000; | ||
464 | m_angularMotorDecayTimescale = 120; | ||
465 | m_VhoverHeight = 0; | ||
466 | // m_VhoverEfficiency = 1; | ||
467 | m_VhoverTimescale = 10; | ||
468 | m_VehicleBuoyancy = 0; | ||
469 | // m_linearDeflectionEfficiency = 1; | ||
470 | // m_linearDeflectionTimescale = 1; | ||
471 | // m_angularDeflectionEfficiency = 1; | ||
472 | // m_angularDeflectionTimescale = 1000; | ||
473 | // m_bankingEfficiency = 0; | ||
474 | // m_bankingMix = 1; | ||
475 | // m_bankingTimescale = 10; | ||
476 | // m_referenceFrame = Quaternion.Identity; | ||
477 | m_Hoverflags &= | ||
478 | ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | | ||
479 | VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); | ||
480 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP); | ||
481 | break; | ||
482 | case Vehicle.TYPE_CAR: | ||
483 | m_linearFrictionTimescale = new Vector3(100, 2, 1000); | ||
484 | m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); | ||
485 | m_linearMotorDirection = Vector3.Zero; | ||
486 | m_linearMotorTimescale = 1; | ||
487 | m_linearMotorDecayTimescale = 60; | ||
488 | m_angularMotorDirection = Vector3.Zero; | ||
489 | m_angularMotorTimescale = 1; | ||
490 | m_angularMotorDecayTimescale = 0.8f; | ||
491 | m_VhoverHeight = 0; | ||
492 | // m_VhoverEfficiency = 0; | ||
493 | m_VhoverTimescale = 1000; | ||
494 | m_VehicleBuoyancy = 0; | ||
495 | // // m_linearDeflectionEfficiency = 1; | ||
496 | // // m_linearDeflectionTimescale = 2; | ||
497 | // // m_angularDeflectionEfficiency = 0; | ||
498 | // m_angularDeflectionTimescale = 10; | ||
499 | m_verticalAttractionEfficiency = 1f; | ||
500 | m_verticalAttractionTimescale = 10f; | ||
501 | // m_bankingEfficiency = -0.2f; | ||
502 | // m_bankingMix = 1; | ||
503 | // m_bankingTimescale = 1; | ||
504 | // m_referenceFrame = Quaternion.Identity; | ||
505 | m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT); | ||
506 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | | ||
507 | VehicleFlag.LIMIT_MOTOR_UP); | ||
508 | m_Hoverflags |= (VehicleFlag.HOVER_UP_ONLY); | ||
509 | break; | ||
510 | case Vehicle.TYPE_BOAT: | ||
511 | m_linearFrictionTimescale = new Vector3(10, 3, 2); | ||
512 | m_angularFrictionTimescale = new Vector3(10,10,10); | ||
513 | m_linearMotorDirection = Vector3.Zero; | ||
514 | m_linearMotorTimescale = 5; | ||
515 | m_linearMotorDecayTimescale = 60; | ||
516 | m_angularMotorDirection = Vector3.Zero; | ||
517 | m_angularMotorTimescale = 4; | ||
518 | m_angularMotorDecayTimescale = 4; | ||
519 | m_VhoverHeight = 0; | ||
520 | // m_VhoverEfficiency = 0.5f; | ||
521 | m_VhoverTimescale = 2; | ||
522 | m_VehicleBuoyancy = 1; | ||
523 | // m_linearDeflectionEfficiency = 0.5f; | ||
524 | // m_linearDeflectionTimescale = 3; | ||
525 | // m_angularDeflectionEfficiency = 0.5f; | ||
526 | // m_angularDeflectionTimescale = 5; | ||
527 | m_verticalAttractionEfficiency = 0.5f; | ||
528 | m_verticalAttractionTimescale = 5f; | ||
529 | // m_bankingEfficiency = -0.3f; | ||
530 | // m_bankingMix = 0.8f; | ||
531 | // m_bankingTimescale = 1; | ||
532 | // m_referenceFrame = Quaternion.Identity; | ||
533 | m_Hoverflags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY | | ||
534 | VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); | ||
535 | m_flags &= ~(VehicleFlag.LIMIT_ROLL_ONLY); | ||
536 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | | ||
537 | VehicleFlag.LIMIT_MOTOR_UP); | ||
538 | m_Hoverflags |= (VehicleFlag.HOVER_WATER_ONLY); | ||
539 | break; | ||
540 | case Vehicle.TYPE_AIRPLANE: | ||
541 | m_linearFrictionTimescale = new Vector3(200, 10, 5); | ||
542 | m_angularFrictionTimescale = new Vector3(20, 20, 20); | ||
543 | m_linearMotorDirection = Vector3.Zero; | ||
544 | m_linearMotorTimescale = 2; | ||
545 | m_linearMotorDecayTimescale = 60; | ||
546 | m_angularMotorDirection = Vector3.Zero; | ||
547 | m_angularMotorTimescale = 4; | ||
548 | m_angularMotorDecayTimescale = 4; | ||
549 | m_VhoverHeight = 0; | ||
550 | // m_VhoverEfficiency = 0.5f; | ||
551 | m_VhoverTimescale = 1000; | ||
552 | m_VehicleBuoyancy = 0; | ||
553 | // m_linearDeflectionEfficiency = 0.5f; | ||
554 | // m_linearDeflectionTimescale = 3; | ||
555 | // m_angularDeflectionEfficiency = 1; | ||
556 | // m_angularDeflectionTimescale = 2; | ||
557 | m_verticalAttractionEfficiency = 0.9f; | ||
558 | m_verticalAttractionTimescale = 2f; | ||
559 | // m_bankingEfficiency = 1; | ||
560 | // m_bankingMix = 0.7f; | ||
561 | // m_bankingTimescale = 2; | ||
562 | // m_referenceFrame = Quaternion.Identity; | ||
563 | m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | | ||
564 | VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); | ||
565 | m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_MOTOR_UP); | ||
566 | m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); | ||
567 | break; | ||
568 | case Vehicle.TYPE_BALLOON: | ||
569 | m_linearFrictionTimescale = new Vector3(5, 5, 5); | ||
570 | m_angularFrictionTimescale = new Vector3(10, 10, 10); | ||
571 | m_linearMotorDirection = Vector3.Zero; | ||
572 | m_linearMotorTimescale = 5; | ||
573 | m_linearMotorDecayTimescale = 60; | ||
574 | m_angularMotorDirection = Vector3.Zero; | ||
575 | m_angularMotorTimescale = 6; | ||
576 | m_angularMotorDecayTimescale = 10; | ||
577 | m_VhoverHeight = 5; | ||
578 | // m_VhoverEfficiency = 0.8f; | ||
579 | m_VhoverTimescale = 10; | ||
580 | m_VehicleBuoyancy = 1; | ||
581 | // m_linearDeflectionEfficiency = 0; | ||
582 | // m_linearDeflectionTimescale = 5; | ||
583 | // m_angularDeflectionEfficiency = 0; | ||
584 | // m_angularDeflectionTimescale = 5; | ||
585 | m_verticalAttractionEfficiency = 1f; | ||
586 | m_verticalAttractionTimescale = 100f; | ||
587 | // m_bankingEfficiency = 0; | ||
588 | // m_bankingMix = 0.7f; | ||
589 | // m_bankingTimescale = 5; | ||
590 | // m_referenceFrame = Quaternion.Identity; | ||
591 | m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | | ||
592 | VehicleFlag.HOVER_UP_ONLY); | ||
593 | m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_MOTOR_UP); | ||
594 | m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); | ||
595 | m_Hoverflags |= (VehicleFlag.HOVER_GLOBAL_HEIGHT); | ||
596 | break; | ||
597 | |||
598 | } | ||
599 | }//end SetDefaultsForType | ||
600 | |||
601 | internal void Step(float pTimestep, BSScene pParentScene) | ||
602 | { | ||
603 | if (m_type == Vehicle.TYPE_NONE) return; | ||
604 | |||
605 | frcount++; // used to limit debug comment output | ||
606 | if (frcount > 100) | ||
607 | frcount = 0; | ||
608 | |||
609 | MoveLinear(pTimestep, pParentScene); | ||
610 | MoveAngular(pTimestep); | ||
611 | LimitRotation(pTimestep); | ||
612 | }// end Step | ||
613 | |||
614 | private void MoveLinear(float pTimestep, BSScene _pParentScene) | ||
615 | { | ||
616 | if (!m_linearMotorDirection.ApproxEquals(Vector3.Zero, 0.01f)) // requested m_linearMotorDirection is significant | ||
617 | { | ||
618 | // add drive to body | ||
619 | Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale/pTimestep); | ||
620 | m_lastLinearVelocityVector += (addAmount*10); // lastLinearVelocityVector is the current body velocity vector? | ||
621 | |||
622 | // This will work temporarily, but we really need to compare speed on an axis | ||
623 | // KF: Limit body velocity to applied velocity? | ||
624 | if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X)) | ||
625 | m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X; | ||
626 | if (Math.Abs(m_lastLinearVelocityVector.Y) > Math.Abs(m_linearMotorDirectionLASTSET.Y)) | ||
627 | m_lastLinearVelocityVector.Y = m_linearMotorDirectionLASTSET.Y; | ||
628 | if (Math.Abs(m_lastLinearVelocityVector.Z) > Math.Abs(m_linearMotorDirectionLASTSET.Z)) | ||
629 | m_lastLinearVelocityVector.Z = m_linearMotorDirectionLASTSET.Z; | ||
630 | |||
631 | // decay applied velocity | ||
632 | Vector3 decayfraction = ((Vector3.One/(m_linearMotorDecayTimescale/pTimestep))); | ||
633 | //Console.WriteLine("decay: " + decayfraction); | ||
634 | m_linearMotorDirection -= m_linearMotorDirection * decayfraction * 0.5f; | ||
635 | //Console.WriteLine("actual: " + m_linearMotorDirection); | ||
636 | } | ||
637 | else | ||
638 | { // requested is not significant | ||
639 | // if what remains of applied is small, zero it. | ||
640 | if (m_lastLinearVelocityVector.ApproxEquals(Vector3.Zero, 0.01f)) | ||
641 | m_lastLinearVelocityVector = Vector3.Zero; | ||
642 | } | ||
643 | |||
644 | // convert requested object velocity to world-referenced vector | ||
645 | m_dir = m_lastLinearVelocityVector; | ||
646 | Quaternion rot = m_prim.Orientation; | ||
647 | Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object | ||
648 | m_dir *= rotq; // apply obj rotation to velocity vector | ||
649 | |||
650 | // add Gravity andBuoyancy | ||
651 | // KF: So far I have found no good method to combine a script-requested | ||
652 | // .Z velocity and gravity. Therefore only 0g will used script-requested | ||
653 | // .Z velocity. >0g (m_VehicleBuoyancy < 1) will used modified gravity only. | ||
654 | Vector3 grav = Vector3.Zero; | ||
655 | // There is some gravity, make a gravity force vector | ||
656 | // that is applied after object velocity. | ||
657 | float objMass = m_prim.Mass; | ||
658 | // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; | ||
659 | grav.Z = _pParentScene.DefaultGravity.Z * objMass * (1f - m_VehicleBuoyancy); | ||
660 | // Preserve the current Z velocity | ||
661 | Vector3 vel_now = m_prim.Velocity; | ||
662 | m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity | ||
663 | |||
664 | Vector3 pos = m_prim.Position; | ||
665 | // Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f); | ||
666 | Vector3 posChange = new Vector3(); | ||
667 | posChange.X = pos.X - m_lastPositionVector.X; | ||
668 | posChange.Y = pos.Y - m_lastPositionVector.Y; | ||
669 | posChange.Z = pos.Z - m_lastPositionVector.Z; | ||
670 | double Zchange = Math.Abs(posChange.Z); | ||
671 | if (m_BlockingEndPoint != Vector3.Zero) | ||
672 | { | ||
673 | if (pos.X >= (m_BlockingEndPoint.X - (float)1)) | ||
674 | { | ||
675 | pos.X -= posChange.X + 1; | ||
676 | m_prim.Position = pos; | ||
677 | } | ||
678 | if (pos.Y >= (m_BlockingEndPoint.Y - (float)1)) | ||
679 | { | ||
680 | pos.Y -= posChange.Y + 1; | ||
681 | m_prim.Position = pos; | ||
682 | } | ||
683 | if (pos.Z >= (m_BlockingEndPoint.Z - (float)1)) | ||
684 | { | ||
685 | pos.Z -= posChange.Z + 1; | ||
686 | m_prim.Position = pos; | ||
687 | } | ||
688 | if (pos.X <= 0) | ||
689 | { | ||
690 | pos.X += posChange.X + 1; | ||
691 | m_prim.Position = pos; | ||
692 | } | ||
693 | if (pos.Y <= 0) | ||
694 | { | ||
695 | pos.Y += posChange.Y + 1; | ||
696 | m_prim.Position = pos; | ||
697 | } | ||
698 | } | ||
699 | if (pos.Z < _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y)) | ||
700 | { | ||
701 | pos.Z = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y) + 2; | ||
702 | m_prim.Position = pos; | ||
703 | } | ||
704 | |||
705 | // Check if hovering | ||
706 | if ((m_Hoverflags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) | ||
707 | { | ||
708 | // We should hover, get the target height | ||
709 | if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != 0) | ||
710 | { | ||
711 | m_VhoverTargetHeight = _pParentScene.GetWaterLevel() + m_VhoverHeight; | ||
712 | } | ||
713 | if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) | ||
714 | { | ||
715 | m_VhoverTargetHeight = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight; | ||
716 | } | ||
717 | if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) | ||
718 | { | ||
719 | m_VhoverTargetHeight = m_VhoverHeight; | ||
720 | } | ||
721 | |||
722 | if ((m_Hoverflags & VehicleFlag.HOVER_UP_ONLY) != 0) | ||
723 | { | ||
724 | // If body is aready heigher, use its height as target height | ||
725 | if (pos.Z > m_VhoverTargetHeight) m_VhoverTargetHeight = pos.Z; | ||
726 | } | ||
727 | if ((m_Hoverflags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) | ||
728 | { | ||
729 | if ((pos.Z - m_VhoverTargetHeight) > .2 || (pos.Z - m_VhoverTargetHeight) < -.2) | ||
730 | { | ||
731 | m_prim.Position = pos; | ||
732 | } | ||
733 | } | ||
734 | else | ||
735 | { | ||
736 | float herr0 = pos.Z - m_VhoverTargetHeight; | ||
737 | // Replace Vertical speed with correction figure if significant | ||
738 | if (Math.Abs(herr0) > 0.01f) | ||
739 | { | ||
740 | m_dir.Z = -((herr0 * pTimestep * 50.0f) / m_VhoverTimescale); | ||
741 | //KF: m_VhoverEfficiency is not yet implemented | ||
742 | } | ||
743 | else | ||
744 | { | ||
745 | m_dir.Z = 0f; | ||
746 | } | ||
747 | } | ||
748 | |||
749 | // m_VhoverEfficiency = 0f; // 0=boucy, 1=Crit.damped | ||
750 | // m_VhoverTimescale = 0f; // time to acheive height | ||
751 | // pTimestep is time since last frame,in secs | ||
752 | } | ||
753 | |||
754 | if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) | ||
755 | { | ||
756 | //Start Experimental Values | ||
757 | if (Zchange > .3) | ||
758 | { | ||
759 | grav.Z = (float)(grav.Z * 3); | ||
760 | } | ||
761 | if (Zchange > .15) | ||
762 | { | ||
763 | grav.Z = (float)(grav.Z * 2); | ||
764 | } | ||
765 | if (Zchange > .75) | ||
766 | { | ||
767 | grav.Z = (float)(grav.Z * 1.5); | ||
768 | } | ||
769 | if (Zchange > .05) | ||
770 | { | ||
771 | grav.Z = (float)(grav.Z * 1.25); | ||
772 | } | ||
773 | if (Zchange > .025) | ||
774 | { | ||
775 | grav.Z = (float)(grav.Z * 1.125); | ||
776 | } | ||
777 | float terraintemp = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y); | ||
778 | float postemp = (pos.Z - terraintemp); | ||
779 | if (postemp > 2.5f) | ||
780 | { | ||
781 | grav.Z = (float)(grav.Z * 1.037125); | ||
782 | } | ||
783 | //End Experimental Values | ||
784 | } | ||
785 | if ((m_flags & (VehicleFlag.NO_X)) != 0) | ||
786 | { | ||
787 | m_dir.X = 0; | ||
788 | } | ||
789 | if ((m_flags & (VehicleFlag.NO_Y)) != 0) | ||
790 | { | ||
791 | m_dir.Y = 0; | ||
792 | } | ||
793 | if ((m_flags & (VehicleFlag.NO_Z)) != 0) | ||
794 | { | ||
795 | m_dir.Z = 0; | ||
796 | } | ||
797 | |||
798 | m_lastPositionVector = m_prim.Position; | ||
799 | |||
800 | // Apply velocity | ||
801 | m_prim.Velocity = m_dir; | ||
802 | // apply gravity force | ||
803 | m_prim.Force = grav; | ||
804 | |||
805 | |||
806 | // apply friction | ||
807 | Vector3 decayamount = Vector3.One / (m_linearFrictionTimescale / pTimestep); | ||
808 | m_lastLinearVelocityVector -= m_lastLinearVelocityVector * decayamount; | ||
809 | } // end MoveLinear() | ||
810 | |||
811 | private void MoveAngular(float pTimestep) | ||
812 | { | ||
813 | /* | ||
814 | private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor | ||
815 | private int m_angularMotorApply = 0; // application frame counter | ||
816 | private float m_angularMotorVelocity = 0; // current angular motor velocity (ramps up and down) | ||
817 | private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate | ||
818 | private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate | ||
819 | private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate | ||
820 | private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body | ||
821 | */ | ||
822 | |||
823 | // Get what the body is doing, this includes 'external' influences | ||
824 | Vector3 angularVelocity = m_prim.AngularVelocity; | ||
825 | // Vector3 angularVelocity = Vector3.Zero; | ||
826 | |||
827 | if (m_angularMotorApply > 0) | ||
828 | { | ||
829 | // ramp up to new value | ||
830 | // current velocity += error / (time to get there / step interval) | ||
831 | // requested speed - last motor speed | ||
832 | m_angularMotorVelocity.X += (m_angularMotorDirection.X - m_angularMotorVelocity.X) / (m_angularMotorTimescale / pTimestep); | ||
833 | m_angularMotorVelocity.Y += (m_angularMotorDirection.Y - m_angularMotorVelocity.Y) / (m_angularMotorTimescale / pTimestep); | ||
834 | m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep); | ||
835 | |||
836 | m_angularMotorApply--; // This is done so that if script request rate is less than phys frame rate the expected | ||
837 | // velocity may still be acheived. | ||
838 | } | ||
839 | else | ||
840 | { | ||
841 | // no motor recently applied, keep the body velocity | ||
842 | /* m_angularMotorVelocity.X = angularVelocity.X; | ||
843 | m_angularMotorVelocity.Y = angularVelocity.Y; | ||
844 | m_angularMotorVelocity.Z = angularVelocity.Z; */ | ||
845 | |||
846 | // and decay the velocity | ||
847 | m_angularMotorVelocity -= m_angularMotorVelocity / (m_angularMotorDecayTimescale / pTimestep); | ||
848 | } // end motor section | ||
849 | |||
850 | // Vertical attractor section | ||
851 | Vector3 vertattr = Vector3.Zero; | ||
852 | |||
853 | if (m_verticalAttractionTimescale < 300) | ||
854 | { | ||
855 | float VAservo = 0.2f / (m_verticalAttractionTimescale * pTimestep); | ||
856 | // get present body rotation | ||
857 | Quaternion rotq = m_prim.Orientation; | ||
858 | // make a vector pointing up | ||
859 | Vector3 verterr = Vector3.Zero; | ||
860 | verterr.Z = 1.0f; | ||
861 | // rotate it to Body Angle | ||
862 | verterr = verterr * rotq; | ||
863 | // verterr.X and .Y are the World error ammounts. They are 0 when there is no error (Vehicle Body is 'vertical'), and .Z will be 1. | ||
864 | // As the body leans to its side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall and .Z will go | ||
865 | // negative. Similar for tilt and |.Y|. .X and .Y must be modulated to prevent a stable inverted body. | ||
866 | if (verterr.Z < 0.0f) | ||
867 | { | ||
868 | verterr.X = 2.0f - verterr.X; | ||
869 | verterr.Y = 2.0f - verterr.Y; | ||
870 | } | ||
871 | // Error is 0 (no error) to +/- 2 (max error) | ||
872 | // scale it by VAservo | ||
873 | verterr = verterr * VAservo; | ||
874 | //if (frcount == 0) Console.WriteLine("VAerr=" + verterr); | ||
875 | |||
876 | // As the body rotates around the X axis, then verterr.Y increases; Rotated around Y then .X increases, so | ||
877 | // Change Body angular velocity X based on Y, and Y based on X. Z is not changed. | ||
878 | vertattr.X = verterr.Y; | ||
879 | vertattr.Y = - verterr.X; | ||
880 | vertattr.Z = 0f; | ||
881 | |||
882 | // scaling appears better usingsquare-law | ||
883 | float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); | ||
884 | vertattr.X += bounce * angularVelocity.X; | ||
885 | vertattr.Y += bounce * angularVelocity.Y; | ||
886 | |||
887 | } // else vertical attractor is off | ||
888 | |||
889 | // m_lastVertAttractor = vertattr; | ||
890 | |||
891 | // Bank section tba | ||
892 | // Deflection section tba | ||
893 | |||
894 | // Sum velocities | ||
895 | m_lastAngularVelocity = m_angularMotorVelocity + vertattr; // + bank + deflection | ||
896 | |||
897 | if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) | ||
898 | { | ||
899 | m_lastAngularVelocity.X = 0; | ||
900 | m_lastAngularVelocity.Y = 0; | ||
901 | } | ||
902 | |||
903 | if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) | ||
904 | { | ||
905 | m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. | ||
906 | } | ||
907 | |||
908 | // apply friction | ||
909 | Vector3 decayamount = Vector3.One / (m_angularFrictionTimescale / pTimestep); | ||
910 | m_lastAngularVelocity -= m_lastAngularVelocity * decayamount; | ||
911 | |||
912 | // Apply to the body | ||
913 | m_prim.AngularVelocity = m_lastAngularVelocity; | ||
914 | |||
915 | } //end MoveAngular | ||
916 | internal void LimitRotation(float timestep) | ||
917 | { | ||
918 | Quaternion rotq = m_prim.Orientation; // rotq = rotation of object | ||
919 | Quaternion m_rot = rotq; | ||
920 | bool changed = false; | ||
921 | if (m_RollreferenceFrame != Quaternion.Identity) | ||
922 | { | ||
923 | if (rotq.X >= m_RollreferenceFrame.X) | ||
924 | { | ||
925 | m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2); | ||
926 | } | ||
927 | if (rotq.Y >= m_RollreferenceFrame.Y) | ||
928 | { | ||
929 | m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2); | ||
930 | } | ||
931 | if (rotq.X <= -m_RollreferenceFrame.X) | ||
932 | { | ||
933 | m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2); | ||
934 | } | ||
935 | if (rotq.Y <= -m_RollreferenceFrame.Y) | ||
936 | { | ||
937 | m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2); | ||
938 | } | ||
939 | changed = true; | ||
940 | } | ||
941 | if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0) | ||
942 | { | ||
943 | m_rot.X = 0; | ||
944 | m_rot.Y = 0; | ||
945 | changed = true; | ||
946 | } | ||
947 | if (changed) | ||
948 | m_prim.Orientation = m_rot; | ||
949 | } | ||
950 | } | ||
951 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs new file mode 100644 index 0000000..61be56d --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs | |||
@@ -0,0 +1,68 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyrightD | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using OpenSim.Framework; | ||
30 | using OpenSim.Region.Physics.Manager; | ||
31 | using OpenMetaverse; | ||
32 | |||
33 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
34 | { | ||
35 | public class BSPlugin : IPhysicsPlugin | ||
36 | { | ||
37 | //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); | ||
38 | |||
39 | private BSScene _mScene; | ||
40 | |||
41 | public BSPlugin() | ||
42 | { | ||
43 | } | ||
44 | |||
45 | public bool Init() | ||
46 | { | ||
47 | return true; | ||
48 | } | ||
49 | |||
50 | public PhysicsScene GetScene(String sceneIdentifier) | ||
51 | { | ||
52 | if (_mScene == null) | ||
53 | { | ||
54 | _mScene = new BSScene(sceneIdentifier); | ||
55 | } | ||
56 | return (_mScene); | ||
57 | } | ||
58 | |||
59 | public string GetName() | ||
60 | { | ||
61 | return ("BulletSim"); | ||
62 | } | ||
63 | |||
64 | public void Dispose() | ||
65 | { | ||
66 | } | ||
67 | } | ||
68 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs new file mode 100644 index 0000000..bb8d601 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | |||
@@ -0,0 +1,1357 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyrightD | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | using System; | ||
28 | using System.Reflection; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Xml; | ||
31 | using log4net; | ||
32 | using OMV = OpenMetaverse; | ||
33 | using OpenSim.Framework; | ||
34 | using OpenSim.Region.Physics.Manager; | ||
35 | using OpenSim.Region.Physics.ConvexDecompositionDotNet; | ||
36 | |||
37 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
38 | { | ||
39 | [Serializable] | ||
40 | public sealed class BSPrim : PhysicsActor | ||
41 | { | ||
42 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
43 | private static readonly string LogHeader = "[BULLETS PRIM]"; | ||
44 | |||
45 | private IMesh _mesh; | ||
46 | private PrimitiveBaseShape _pbs; | ||
47 | private ShapeData.PhysicsShapeType _shapeType; | ||
48 | private ulong _meshKey; | ||
49 | private ulong _hullKey; | ||
50 | private List<ConvexResult> _hulls; | ||
51 | |||
52 | private BSScene _scene; | ||
53 | private String _avName; | ||
54 | private uint _localID = 0; | ||
55 | |||
56 | // _size is what the user passed. _scale is what we pass to the physics engine with the mesh. | ||
57 | // Often _scale is unity because the meshmerizer will apply _size when creating the mesh. | ||
58 | private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user | ||
59 | private OMV.Vector3 _scale; // the multiplier for each mesh dimension for the mesh as created by the meshmerizer | ||
60 | |||
61 | private bool _stopped; | ||
62 | private bool _grabbed; | ||
63 | private bool _isSelected; | ||
64 | private bool _isVolumeDetect; | ||
65 | private OMV.Vector3 _position; | ||
66 | private float _mass; | ||
67 | private float _density; | ||
68 | private OMV.Vector3 _force; | ||
69 | private OMV.Vector3 _velocity; | ||
70 | private OMV.Vector3 _torque; | ||
71 | private float _collisionScore; | ||
72 | private OMV.Vector3 _acceleration; | ||
73 | private OMV.Quaternion _orientation; | ||
74 | private int _physicsActorType; | ||
75 | private bool _isPhysical; | ||
76 | private bool _flying; | ||
77 | private float _friction; | ||
78 | private float _restitution; | ||
79 | private bool _setAlwaysRun; | ||
80 | private bool _throttleUpdates; | ||
81 | private bool _isColliding; | ||
82 | private bool _collidingGround; | ||
83 | private bool _collidingObj; | ||
84 | private bool _floatOnWater; | ||
85 | private OMV.Vector3 _rotationalVelocity; | ||
86 | private bool _kinematic; | ||
87 | private float _buoyancy; | ||
88 | private OMV.Vector3 _angularVelocity; | ||
89 | |||
90 | private List<BSPrim> _childrenPrims; | ||
91 | private BSPrim _parentPrim; | ||
92 | |||
93 | private int _subscribedEventsMs = 0; | ||
94 | private int _lastCollisionTime = 0; | ||
95 | long _collidingStep; | ||
96 | long _collidingGroundStep; | ||
97 | |||
98 | private BSDynamics _vehicle; | ||
99 | |||
100 | private OMV.Vector3 _PIDTarget; | ||
101 | private bool _usePID; | ||
102 | private float _PIDTau; | ||
103 | private bool _useHoverPID; | ||
104 | private float _PIDHoverHeight; | ||
105 | private PIDHoverType _PIDHoverType; | ||
106 | private float _PIDHoverTao; | ||
107 | |||
108 | public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, | ||
109 | OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) | ||
110 | { | ||
111 | // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID); | ||
112 | _localID = localID; | ||
113 | _avName = primName; | ||
114 | _scene = parent_scene; | ||
115 | _position = pos; | ||
116 | _size = size; | ||
117 | _scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type | ||
118 | _orientation = rotation; | ||
119 | _buoyancy = 1f; | ||
120 | _velocity = OMV.Vector3.Zero; | ||
121 | _rotationalVelocity = OMV.Vector3.Zero; | ||
122 | _angularVelocity = OMV.Vector3.Zero; | ||
123 | _hullKey = 0; | ||
124 | _meshKey = 0; | ||
125 | _pbs = pbs; | ||
126 | _isPhysical = pisPhysical; | ||
127 | _isVolumeDetect = false; | ||
128 | _subscribedEventsMs = 0; | ||
129 | _friction = _scene.Params.defaultFriction; // TODO: compute based on object material | ||
130 | _density = _scene.Params.defaultDensity; // TODO: compute based on object material | ||
131 | _restitution = _scene.Params.defaultRestitution; | ||
132 | _parentPrim = null; // not a child or a parent | ||
133 | _vehicle = new BSDynamics(this); // add vehicleness | ||
134 | _childrenPrims = new List<BSPrim>(); | ||
135 | if (_isPhysical) | ||
136 | _mass = CalculateMass(); | ||
137 | else | ||
138 | _mass = 0f; | ||
139 | // do the actual object creation at taint time | ||
140 | _scene.TaintedObject(delegate() | ||
141 | { | ||
142 | RecreateGeomAndObject(); | ||
143 | }); | ||
144 | } | ||
145 | |||
146 | // called when this prim is being destroyed and we should free all the resources | ||
147 | public void Destroy() | ||
148 | { | ||
149 | // m_log.DebugFormat("{0}: Destroy", LogHeader); | ||
150 | // Undo any vehicle properties | ||
151 | _vehicle.ProcessTypeChange(Vehicle.TYPE_NONE); | ||
152 | _scene.RemoveVehiclePrim(this); // just to make sure | ||
153 | _scene.TaintedObject(delegate() | ||
154 | { | ||
155 | // everything in the C# world will get garbage collected. Tell the C++ world to free stuff. | ||
156 | BulletSimAPI.DestroyObject(_scene.WorldID, _localID); | ||
157 | }); | ||
158 | } | ||
159 | |||
160 | public override bool Stopped { | ||
161 | get { return _stopped; } | ||
162 | } | ||
163 | public override OMV.Vector3 Size { | ||
164 | get { return _size; } | ||
165 | set { | ||
166 | _size = value; | ||
167 | _scene.TaintedObject(delegate() | ||
168 | { | ||
169 | if (_isPhysical) _mass = CalculateMass(); // changing size changes the mass | ||
170 | BulletSimAPI.SetObjectScaleMass(_scene.WorldID, _localID, _scale, _mass, _isPhysical); | ||
171 | RecreateGeomAndObject(); | ||
172 | }); | ||
173 | } | ||
174 | } | ||
175 | public override PrimitiveBaseShape Shape { | ||
176 | set { | ||
177 | _pbs = value; | ||
178 | _scene.TaintedObject(delegate() | ||
179 | { | ||
180 | if (_isPhysical) _mass = CalculateMass(); // changing the shape changes the mass | ||
181 | RecreateGeomAndObject(); | ||
182 | }); | ||
183 | } | ||
184 | } | ||
185 | public override uint LocalID { | ||
186 | set { _localID = value; } | ||
187 | get { return _localID; } | ||
188 | } | ||
189 | public override bool Grabbed { | ||
190 | set { _grabbed = value; | ||
191 | } | ||
192 | } | ||
193 | public override bool Selected { | ||
194 | set { | ||
195 | _isSelected = value; | ||
196 | _scene.TaintedObject(delegate() | ||
197 | { | ||
198 | SetObjectDynamic(); | ||
199 | }); | ||
200 | } | ||
201 | } | ||
202 | public override void CrossingFailure() { return; } | ||
203 | |||
204 | // link me to the specified parent | ||
205 | public override void link(PhysicsActor obj) { | ||
206 | BSPrim parent = (BSPrim)obj; | ||
207 | // m_log.DebugFormat("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, obj.LocalID); | ||
208 | // TODO: decide if this parent checking needs to happen at taint time | ||
209 | if (_parentPrim == null) | ||
210 | { | ||
211 | if (parent != null) | ||
212 | { | ||
213 | // I don't have a parent so I am joining a linkset | ||
214 | parent.AddChildToLinkset(this); | ||
215 | } | ||
216 | } | ||
217 | else | ||
218 | { | ||
219 | // I already have a parent, is parenting changing? | ||
220 | if (parent != _parentPrim) | ||
221 | { | ||
222 | if (parent == null) | ||
223 | { | ||
224 | // we are being removed from a linkset | ||
225 | _parentPrim.RemoveChildFromLinkset(this); | ||
226 | } | ||
227 | else | ||
228 | { | ||
229 | // asking to reparent a prim should not happen | ||
230 | m_log.ErrorFormat("{0}: Reparenting a prim. ", LogHeader); | ||
231 | } | ||
232 | } | ||
233 | } | ||
234 | return; | ||
235 | } | ||
236 | |||
237 | // delink me from my linkset | ||
238 | public override void delink() { | ||
239 | // TODO: decide if this parent checking needs to happen at taint time | ||
240 | // Race condition here: if link() and delink() in same simulation tick, the delink will not happen | ||
241 | // m_log.DebugFormat("{0}: delink {1}/{2}", LogHeader, _avName, _localID); | ||
242 | if (_parentPrim != null) | ||
243 | { | ||
244 | _parentPrim.RemoveChildFromLinkset(this); | ||
245 | } | ||
246 | return; | ||
247 | } | ||
248 | |||
249 | // I am the root of a linkset and a new child is being added | ||
250 | public void AddChildToLinkset(BSPrim pchild) | ||
251 | { | ||
252 | BSPrim child = pchild; | ||
253 | _scene.TaintedObject(delegate() | ||
254 | { | ||
255 | if (!_childrenPrims.Contains(child)) | ||
256 | { | ||
257 | _childrenPrims.Add(child); | ||
258 | child.ParentPrim = this; // the child has gained a parent | ||
259 | RecreateGeomAndObject(); // rebuild my shape with the new child added | ||
260 | } | ||
261 | }); | ||
262 | return; | ||
263 | } | ||
264 | |||
265 | // I am the root of a linkset and one of my children is being removed. | ||
266 | // Safe to call even if the child is not really in my linkset. | ||
267 | public void RemoveChildFromLinkset(BSPrim pchild) | ||
268 | { | ||
269 | BSPrim child = pchild; | ||
270 | _scene.TaintedObject(delegate() | ||
271 | { | ||
272 | if (_childrenPrims.Contains(child)) | ||
273 | { | ||
274 | BulletSimAPI.RemoveConstraint(_scene.WorldID, child.LocalID, this.LocalID); | ||
275 | _childrenPrims.Remove(child); | ||
276 | child.ParentPrim = null; // the child has lost its parent | ||
277 | RecreateGeomAndObject(); // rebuild my shape with the child removed | ||
278 | } | ||
279 | else | ||
280 | { | ||
281 | m_log.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset"); | ||
282 | } | ||
283 | }); | ||
284 | return; | ||
285 | } | ||
286 | |||
287 | public BSPrim ParentPrim | ||
288 | { | ||
289 | set { _parentPrim = value; } | ||
290 | } | ||
291 | |||
292 | // return true if we are the root of a linkset (there are children to manage) | ||
293 | public bool IsRootOfLinkset | ||
294 | { | ||
295 | get { return (_parentPrim == null && _childrenPrims.Count != 0); } | ||
296 | } | ||
297 | |||
298 | // Set motion values to zero. | ||
299 | // Do it to the properties so the values get set in the physics engine. | ||
300 | // Push the setting of the values to the viewer. | ||
301 | private void ZeroMotion() | ||
302 | { | ||
303 | Velocity = OMV.Vector3.Zero; | ||
304 | _acceleration = OMV.Vector3.Zero; | ||
305 | RotationalVelocity = OMV.Vector3.Zero; | ||
306 | base.RequestPhysicsterseUpdate(); | ||
307 | } | ||
308 | |||
309 | public override void LockAngularMotion(OMV.Vector3 axis) { return; } | ||
310 | |||
311 | public override OMV.Vector3 Position { | ||
312 | get { | ||
313 | // don't do the following GetObjectPosition because this function is called a zillion times | ||
314 | // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); | ||
315 | return _position; | ||
316 | } | ||
317 | set { | ||
318 | _position = value; | ||
319 | _scene.TaintedObject(delegate() | ||
320 | { | ||
321 | BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); | ||
322 | // m_log.DebugFormat("{0}: setPosition: id={1}, position={2}", LogHeader, _localID, _position); | ||
323 | }); | ||
324 | } | ||
325 | } | ||
326 | public override float Mass { | ||
327 | get { return _mass; } | ||
328 | } | ||
329 | public override OMV.Vector3 Force { | ||
330 | get { return _force; } | ||
331 | set { | ||
332 | _force = value; | ||
333 | _scene.TaintedObject(delegate() | ||
334 | { | ||
335 | BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force); | ||
336 | }); | ||
337 | } | ||
338 | } | ||
339 | |||
340 | public override int VehicleType { | ||
341 | get { | ||
342 | return (int)_vehicle.Type; // if we are a vehicle, return that type | ||
343 | } | ||
344 | set { | ||
345 | Vehicle type = (Vehicle)value; | ||
346 | _vehicle.ProcessTypeChange(type); | ||
347 | _scene.TaintedObject(delegate() | ||
348 | { | ||
349 | if (type == Vehicle.TYPE_NONE) | ||
350 | { | ||
351 | _scene.RemoveVehiclePrim(this); | ||
352 | } | ||
353 | else | ||
354 | { | ||
355 | // make it so the scene will call us each tick to do vehicle things | ||
356 | _scene.AddVehiclePrim(this); | ||
357 | } | ||
358 | return; | ||
359 | }); | ||
360 | } | ||
361 | } | ||
362 | public override void VehicleFloatParam(int param, float value) | ||
363 | { | ||
364 | _vehicle.ProcessFloatVehicleParam((Vehicle)param, value); | ||
365 | } | ||
366 | public override void VehicleVectorParam(int param, OMV.Vector3 value) | ||
367 | { | ||
368 | _vehicle.ProcessVectorVehicleParam((Vehicle)param, value); | ||
369 | } | ||
370 | public override void VehicleRotationParam(int param, OMV.Quaternion rotation) | ||
371 | { | ||
372 | _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); | ||
373 | } | ||
374 | public override void VehicleFlags(int param, bool remove) | ||
375 | { | ||
376 | _vehicle.ProcessVehicleFlags(param, remove); | ||
377 | } | ||
378 | // Called each simulation step to advance vehicle characteristics | ||
379 | public void StepVehicle(float timeStep) | ||
380 | { | ||
381 | _vehicle.Step(timeStep, _scene); | ||
382 | } | ||
383 | |||
384 | // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more | ||
385 | public override void SetVolumeDetect(int param) { | ||
386 | bool newValue = (param != 0); | ||
387 | if (_isVolumeDetect != newValue) | ||
388 | { | ||
389 | _isVolumeDetect = newValue; | ||
390 | _scene.TaintedObject(delegate() | ||
391 | { | ||
392 | SetObjectDynamic(); | ||
393 | }); | ||
394 | } | ||
395 | return; | ||
396 | } | ||
397 | |||
398 | public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } } | ||
399 | public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } | ||
400 | public override OMV.Vector3 Velocity { | ||
401 | get { return _velocity; } | ||
402 | set { _velocity = value; | ||
403 | _scene.TaintedObject(delegate() | ||
404 | { | ||
405 | BulletSimAPI.SetObjectVelocity(_scene.WorldID, LocalID, _velocity); | ||
406 | }); | ||
407 | } | ||
408 | } | ||
409 | public override OMV.Vector3 Torque { | ||
410 | get { return _torque; } | ||
411 | set { _torque = value; | ||
412 | } | ||
413 | } | ||
414 | public override float CollisionScore { | ||
415 | get { return _collisionScore; } | ||
416 | set { _collisionScore = value; | ||
417 | } | ||
418 | } | ||
419 | public override OMV.Vector3 Acceleration { | ||
420 | get { return _acceleration; } | ||
421 | } | ||
422 | public override OMV.Quaternion Orientation { | ||
423 | get { return _orientation; } | ||
424 | set { | ||
425 | _orientation = value; | ||
426 | // m_log.DebugFormat("{0}: set orientation: id={1}, ori={2}", LogHeader, LocalID, _orientation); | ||
427 | _scene.TaintedObject(delegate() | ||
428 | { | ||
429 | // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); | ||
430 | BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); | ||
431 | }); | ||
432 | } | ||
433 | } | ||
434 | public override int PhysicsActorType { | ||
435 | get { return _physicsActorType; } | ||
436 | set { _physicsActorType = value; | ||
437 | } | ||
438 | } | ||
439 | public override bool IsPhysical { | ||
440 | get { return _isPhysical; } | ||
441 | set { | ||
442 | _isPhysical = value; | ||
443 | _scene.TaintedObject(delegate() | ||
444 | { | ||
445 | SetObjectDynamic(); | ||
446 | }); | ||
447 | } | ||
448 | } | ||
449 | |||
450 | // An object is static (does not move) if selected or not physical | ||
451 | private bool IsStatic | ||
452 | { | ||
453 | get { return _isSelected || !IsPhysical; } | ||
454 | } | ||
455 | |||
456 | // An object is solid if it's not phantom and if it's not doing VolumeDetect | ||
457 | private bool IsSolid | ||
458 | { | ||
459 | get { return !IsPhantom && !_isVolumeDetect; } | ||
460 | } | ||
461 | |||
462 | // make gravity work if the object is physical and not selected | ||
463 | // no locking here because only called when it is safe | ||
464 | private void SetObjectDynamic() | ||
465 | { | ||
466 | // m_log.DebugFormat("{0}: ID={1}, SetObjectDynamic: IsStatic={2}, IsSolid={3}", LogHeader, _localID, IsStatic, IsSolid); | ||
467 | // non-physical things work best with a mass of zero | ||
468 | if (IsStatic) | ||
469 | { | ||
470 | _mass = 0f; | ||
471 | } | ||
472 | else | ||
473 | { | ||
474 | _mass = CalculateMass(); | ||
475 | // If it's dynamic, make sure the hull has been created for it | ||
476 | // This shouldn't do much work if the object had previously been built | ||
477 | RecreateGeomAndObject(); | ||
478 | |||
479 | } | ||
480 | BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), _mass); | ||
481 | } | ||
482 | |||
483 | // prims don't fly | ||
484 | public override bool Flying { | ||
485 | get { return _flying; } | ||
486 | set { _flying = value; } | ||
487 | } | ||
488 | public override bool SetAlwaysRun { | ||
489 | get { return _setAlwaysRun; } | ||
490 | set { _setAlwaysRun = value; } | ||
491 | } | ||
492 | public override bool ThrottleUpdates { | ||
493 | get { return _throttleUpdates; } | ||
494 | set { _throttleUpdates = value; } | ||
495 | } | ||
496 | public override bool IsColliding { | ||
497 | get { return (_collidingStep == _scene.SimulationStep); } | ||
498 | set { _isColliding = value; } | ||
499 | } | ||
500 | public override bool CollidingGround { | ||
501 | get { return (_collidingGroundStep == _scene.SimulationStep); } | ||
502 | set { _collidingGround = value; } | ||
503 | } | ||
504 | public override bool CollidingObj { | ||
505 | get { return _collidingObj; } | ||
506 | set { _collidingObj = value; } | ||
507 | } | ||
508 | public bool IsPhantom { | ||
509 | get { | ||
510 | // SceneObjectPart removes phantom objects from the physics scene | ||
511 | // so, although we could implement touching and such, we never | ||
512 | // are invoked as a phantom object | ||
513 | return false; | ||
514 | } | ||
515 | } | ||
516 | public override bool FloatOnWater { | ||
517 | set { _floatOnWater = value; } | ||
518 | } | ||
519 | public override OMV.Vector3 RotationalVelocity { | ||
520 | get { return _rotationalVelocity; } | ||
521 | set { _rotationalVelocity = value; | ||
522 | // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); | ||
523 | _scene.TaintedObject(delegate() | ||
524 | { | ||
525 | BulletSimAPI.SetObjectAngularVelocity(_scene.WorldID, LocalID, _rotationalVelocity); | ||
526 | }); | ||
527 | } | ||
528 | } | ||
529 | public OMV.Vector3 AngularVelocity { | ||
530 | get { return _angularVelocity; } | ||
531 | set { _angularVelocity = value; } | ||
532 | } | ||
533 | public override bool Kinematic { | ||
534 | get { return _kinematic; } | ||
535 | set { _kinematic = value; | ||
536 | // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic); | ||
537 | } | ||
538 | } | ||
539 | public override float Buoyancy { | ||
540 | get { return _buoyancy; } | ||
541 | set { _buoyancy = value; | ||
542 | _scene.TaintedObject(delegate() | ||
543 | { | ||
544 | BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, _localID, _buoyancy); | ||
545 | }); | ||
546 | } | ||
547 | } | ||
548 | |||
549 | // Used for MoveTo | ||
550 | public override OMV.Vector3 PIDTarget { | ||
551 | set { _PIDTarget = value; } | ||
552 | } | ||
553 | public override bool PIDActive { | ||
554 | set { _usePID = value; } | ||
555 | } | ||
556 | public override float PIDTau { | ||
557 | set { _PIDTau = value; } | ||
558 | } | ||
559 | |||
560 | // Used for llSetHoverHeight and maybe vehicle height | ||
561 | // Hover Height will override MoveTo target's Z | ||
562 | public override bool PIDHoverActive { | ||
563 | set { _useHoverPID = value; } | ||
564 | } | ||
565 | public override float PIDHoverHeight { | ||
566 | set { _PIDHoverHeight = value; } | ||
567 | } | ||
568 | public override PIDHoverType PIDHoverType { | ||
569 | set { _PIDHoverType = value; } | ||
570 | } | ||
571 | public override float PIDHoverTau { | ||
572 | set { _PIDHoverTao = value; } | ||
573 | } | ||
574 | |||
575 | // For RotLookAt | ||
576 | public override OMV.Quaternion APIDTarget { set { return; } } | ||
577 | public override bool APIDActive { set { return; } } | ||
578 | public override float APIDStrength { set { return; } } | ||
579 | public override float APIDDamping { set { return; } } | ||
580 | |||
581 | public override void AddForce(OMV.Vector3 force, bool pushforce) { | ||
582 | if (force.IsFinite()) | ||
583 | { | ||
584 | _force.X += force.X; | ||
585 | _force.Y += force.Y; | ||
586 | _force.Z += force.Z; | ||
587 | } | ||
588 | else | ||
589 | { | ||
590 | m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader); | ||
591 | } | ||
592 | _scene.TaintedObject(delegate() | ||
593 | { | ||
594 | BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force); | ||
595 | }); | ||
596 | } | ||
597 | |||
598 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { | ||
599 | // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce); | ||
600 | } | ||
601 | public override void SetMomentum(OMV.Vector3 momentum) { | ||
602 | } | ||
603 | public override void SubscribeEvents(int ms) { | ||
604 | _subscribedEventsMs = ms; | ||
605 | _lastCollisionTime = Util.EnvironmentTickCount() - _subscribedEventsMs; // make first collision happen | ||
606 | } | ||
607 | public override void UnSubscribeEvents() { | ||
608 | _subscribedEventsMs = 0; | ||
609 | } | ||
610 | public override bool SubscribedEvents() { | ||
611 | return (_subscribedEventsMs > 0); | ||
612 | } | ||
613 | |||
614 | #region Mass Calculation | ||
615 | |||
616 | private float CalculateMass() | ||
617 | { | ||
618 | float volume = _size.X * _size.Y * _size.Z; // default | ||
619 | float tmp; | ||
620 | |||
621 | float returnMass = 0; | ||
622 | float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f; | ||
623 | float hollowVolume = hollowAmount * hollowAmount; | ||
624 | |||
625 | switch (_pbs.ProfileShape) | ||
626 | { | ||
627 | case ProfileShape.Square: | ||
628 | // default box | ||
629 | |||
630 | if (_pbs.PathCurve == (byte)Extrusion.Straight) | ||
631 | { | ||
632 | if (hollowAmount > 0.0) | ||
633 | { | ||
634 | switch (_pbs.HollowShape) | ||
635 | { | ||
636 | case HollowShape.Square: | ||
637 | case HollowShape.Same: | ||
638 | break; | ||
639 | |||
640 | case HollowShape.Circle: | ||
641 | |||
642 | hollowVolume *= 0.78539816339f; | ||
643 | break; | ||
644 | |||
645 | case HollowShape.Triangle: | ||
646 | |||
647 | hollowVolume *= (0.5f * .5f); | ||
648 | break; | ||
649 | |||
650 | default: | ||
651 | hollowVolume = 0; | ||
652 | break; | ||
653 | } | ||
654 | volume *= (1.0f - hollowVolume); | ||
655 | } | ||
656 | } | ||
657 | |||
658 | else if (_pbs.PathCurve == (byte)Extrusion.Curve1) | ||
659 | { | ||
660 | //a tube | ||
661 | |||
662 | volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX); | ||
663 | tmp= 1.0f -2.0e-2f * (float)(200 - _pbs.PathScaleY); | ||
664 | volume -= volume*tmp*tmp; | ||
665 | |||
666 | if (hollowAmount > 0.0) | ||
667 | { | ||
668 | hollowVolume *= hollowAmount; | ||
669 | |||
670 | switch (_pbs.HollowShape) | ||
671 | { | ||
672 | case HollowShape.Square: | ||
673 | case HollowShape.Same: | ||
674 | break; | ||
675 | |||
676 | case HollowShape.Circle: | ||
677 | hollowVolume *= 0.78539816339f;; | ||
678 | break; | ||
679 | |||
680 | case HollowShape.Triangle: | ||
681 | hollowVolume *= 0.5f * 0.5f; | ||
682 | break; | ||
683 | default: | ||
684 | hollowVolume = 0; | ||
685 | break; | ||
686 | } | ||
687 | volume *= (1.0f - hollowVolume); | ||
688 | } | ||
689 | } | ||
690 | |||
691 | break; | ||
692 | |||
693 | case ProfileShape.Circle: | ||
694 | |||
695 | if (_pbs.PathCurve == (byte)Extrusion.Straight) | ||
696 | { | ||
697 | volume *= 0.78539816339f; // elipse base | ||
698 | |||
699 | if (hollowAmount > 0.0) | ||
700 | { | ||
701 | switch (_pbs.HollowShape) | ||
702 | { | ||
703 | case HollowShape.Same: | ||
704 | case HollowShape.Circle: | ||
705 | break; | ||
706 | |||
707 | case HollowShape.Square: | ||
708 | hollowVolume *= 0.5f * 2.5984480504799f; | ||
709 | break; | ||
710 | |||
711 | case HollowShape.Triangle: | ||
712 | hollowVolume *= .5f * 1.27323954473516f; | ||
713 | break; | ||
714 | |||
715 | default: | ||
716 | hollowVolume = 0; | ||
717 | break; | ||
718 | } | ||
719 | volume *= (1.0f - hollowVolume); | ||
720 | } | ||
721 | } | ||
722 | |||
723 | else if (_pbs.PathCurve == (byte)Extrusion.Curve1) | ||
724 | { | ||
725 | volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX); | ||
726 | tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY); | ||
727 | volume *= (1.0f - tmp * tmp); | ||
728 | |||
729 | if (hollowAmount > 0.0) | ||
730 | { | ||
731 | |||
732 | // calculate the hollow volume by it's shape compared to the prim shape | ||
733 | hollowVolume *= hollowAmount; | ||
734 | |||
735 | switch (_pbs.HollowShape) | ||
736 | { | ||
737 | case HollowShape.Same: | ||
738 | case HollowShape.Circle: | ||
739 | break; | ||
740 | |||
741 | case HollowShape.Square: | ||
742 | hollowVolume *= 0.5f * 2.5984480504799f; | ||
743 | break; | ||
744 | |||
745 | case HollowShape.Triangle: | ||
746 | hollowVolume *= .5f * 1.27323954473516f; | ||
747 | break; | ||
748 | |||
749 | default: | ||
750 | hollowVolume = 0; | ||
751 | break; | ||
752 | } | ||
753 | volume *= (1.0f - hollowVolume); | ||
754 | } | ||
755 | } | ||
756 | break; | ||
757 | |||
758 | case ProfileShape.HalfCircle: | ||
759 | if (_pbs.PathCurve == (byte)Extrusion.Curve1) | ||
760 | { | ||
761 | volume *= 0.52359877559829887307710723054658f; | ||
762 | } | ||
763 | break; | ||
764 | |||
765 | case ProfileShape.EquilateralTriangle: | ||
766 | |||
767 | if (_pbs.PathCurve == (byte)Extrusion.Straight) | ||
768 | { | ||
769 | volume *= 0.32475953f; | ||
770 | |||
771 | if (hollowAmount > 0.0) | ||
772 | { | ||
773 | |||
774 | // calculate the hollow volume by it's shape compared to the prim shape | ||
775 | switch (_pbs.HollowShape) | ||
776 | { | ||
777 | case HollowShape.Same: | ||
778 | case HollowShape.Triangle: | ||
779 | hollowVolume *= .25f; | ||
780 | break; | ||
781 | |||
782 | case HollowShape.Square: | ||
783 | hollowVolume *= 0.499849f * 3.07920140172638f; | ||
784 | break; | ||
785 | |||
786 | case HollowShape.Circle: | ||
787 | // Hollow shape is a perfect cyllinder in respect to the cube's scale | ||
788 | // Cyllinder hollow volume calculation | ||
789 | |||
790 | hollowVolume *= 0.1963495f * 3.07920140172638f; | ||
791 | break; | ||
792 | |||
793 | default: | ||
794 | hollowVolume = 0; | ||
795 | break; | ||
796 | } | ||
797 | volume *= (1.0f - hollowVolume); | ||
798 | } | ||
799 | } | ||
800 | else if (_pbs.PathCurve == (byte)Extrusion.Curve1) | ||
801 | { | ||
802 | volume *= 0.32475953f; | ||
803 | volume *= 0.01f * (float)(200 - _pbs.PathScaleX); | ||
804 | tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY); | ||
805 | volume *= (1.0f - tmp * tmp); | ||
806 | |||
807 | if (hollowAmount > 0.0) | ||
808 | { | ||
809 | |||
810 | hollowVolume *= hollowAmount; | ||
811 | |||
812 | switch (_pbs.HollowShape) | ||
813 | { | ||
814 | case HollowShape.Same: | ||
815 | case HollowShape.Triangle: | ||
816 | hollowVolume *= .25f; | ||
817 | break; | ||
818 | |||
819 | case HollowShape.Square: | ||
820 | hollowVolume *= 0.499849f * 3.07920140172638f; | ||
821 | break; | ||
822 | |||
823 | case HollowShape.Circle: | ||
824 | |||
825 | hollowVolume *= 0.1963495f * 3.07920140172638f; | ||
826 | break; | ||
827 | |||
828 | default: | ||
829 | hollowVolume = 0; | ||
830 | break; | ||
831 | } | ||
832 | volume *= (1.0f - hollowVolume); | ||
833 | } | ||
834 | } | ||
835 | break; | ||
836 | |||
837 | default: | ||
838 | break; | ||
839 | } | ||
840 | |||
841 | |||
842 | |||
843 | float taperX1; | ||
844 | float taperY1; | ||
845 | float taperX; | ||
846 | float taperY; | ||
847 | float pathBegin; | ||
848 | float pathEnd; | ||
849 | float profileBegin; | ||
850 | float profileEnd; | ||
851 | |||
852 | if (_pbs.PathCurve == (byte)Extrusion.Straight || _pbs.PathCurve == (byte)Extrusion.Flexible) | ||
853 | { | ||
854 | taperX1 = _pbs.PathScaleX * 0.01f; | ||
855 | if (taperX1 > 1.0f) | ||
856 | taperX1 = 2.0f - taperX1; | ||
857 | taperX = 1.0f - taperX1; | ||
858 | |||
859 | taperY1 = _pbs.PathScaleY * 0.01f; | ||
860 | if (taperY1 > 1.0f) | ||
861 | taperY1 = 2.0f - taperY1; | ||
862 | taperY = 1.0f - taperY1; | ||
863 | } | ||
864 | else | ||
865 | { | ||
866 | taperX = _pbs.PathTaperX * 0.01f; | ||
867 | if (taperX < 0.0f) | ||
868 | taperX = -taperX; | ||
869 | taperX1 = 1.0f - taperX; | ||
870 | |||
871 | taperY = _pbs.PathTaperY * 0.01f; | ||
872 | if (taperY < 0.0f) | ||
873 | taperY = -taperY; | ||
874 | taperY1 = 1.0f - taperY; | ||
875 | |||
876 | } | ||
877 | |||
878 | |||
879 | volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY); | ||
880 | |||
881 | pathBegin = (float)_pbs.PathBegin * 2.0e-5f; | ||
882 | pathEnd = 1.0f - (float)_pbs.PathEnd * 2.0e-5f; | ||
883 | volume *= (pathEnd - pathBegin); | ||
884 | |||
885 | // this is crude aproximation | ||
886 | profileBegin = (float)_pbs.ProfileBegin * 2.0e-5f; | ||
887 | profileEnd = 1.0f - (float)_pbs.ProfileEnd * 2.0e-5f; | ||
888 | volume *= (profileEnd - profileBegin); | ||
889 | |||
890 | returnMass = _density * volume; | ||
891 | |||
892 | if (IsRootOfLinkset) | ||
893 | { | ||
894 | foreach (BSPrim prim in _childrenPrims) | ||
895 | { | ||
896 | returnMass += prim.CalculateMass(); | ||
897 | } | ||
898 | } | ||
899 | |||
900 | if (returnMass <= 0) | ||
901 | returnMass = 0.0001f; | ||
902 | |||
903 | if (returnMass > _scene.MaximumObjectMass) | ||
904 | returnMass = _scene.MaximumObjectMass; | ||
905 | |||
906 | return returnMass; | ||
907 | }// end CalculateMass | ||
908 | #endregion Mass Calculation | ||
909 | |||
910 | // Create the geometry information in Bullet for later use | ||
911 | // The objects needs a hull if it's physical otherwise a mesh is enough | ||
912 | // No locking here because this is done when we know physics is not simulating | ||
913 | // if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used | ||
914 | private void CreateGeom(bool forceRebuild) | ||
915 | { | ||
916 | // the mesher thought this was too simple to mesh. Use a native Bullet collision shape. | ||
917 | if (!_scene.NeedsMeshing(_pbs)) | ||
918 | { | ||
919 | if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1) | ||
920 | { | ||
921 | if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z) | ||
922 | { | ||
923 | // m_log.DebugFormat("{0}: CreateGeom: Defaulting to sphere of size {1}", LogHeader, _size); | ||
924 | _shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE; | ||
925 | // Bullet native objects are scaled by the Bullet engine so pass the size in | ||
926 | _scale = _size; | ||
927 | } | ||
928 | } | ||
929 | else | ||
930 | { | ||
931 | // m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, size={2}", LogHeader, LocalID, _size); | ||
932 | _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX; | ||
933 | _scale = _size; | ||
934 | } | ||
935 | } | ||
936 | else | ||
937 | { | ||
938 | if (IsPhysical) | ||
939 | { | ||
940 | if (forceRebuild || _hullKey == 0) | ||
941 | { | ||
942 | // physical objects require a hull for interaction. | ||
943 | // This will create the mesh if it doesn't already exist | ||
944 | CreateGeomHull(); | ||
945 | } | ||
946 | } | ||
947 | else | ||
948 | { | ||
949 | if (forceRebuild || _meshKey == 0) | ||
950 | { | ||
951 | // Static (non-physical) objects only need a mesh for bumping into | ||
952 | CreateGeomMesh(); | ||
953 | } | ||
954 | } | ||
955 | } | ||
956 | } | ||
957 | |||
958 | // No locking here because this is done when we know physics is not simulating | ||
959 | private void CreateGeomMesh() | ||
960 | { | ||
961 | float lod = _pbs.SculptEntry ? _scene.SculptLOD : _scene.MeshLOD; | ||
962 | ulong newMeshKey = (ulong)_pbs.GetMeshKey(_size, lod); | ||
963 | // m_log.DebugFormat("{0}: CreateGeomMesh: lID={1}, oldKey={2}, newKey={3}", LogHeader, _localID, _meshKey, newMeshKey); | ||
964 | |||
965 | // if this new shape is the same as last time, don't recreate the mesh | ||
966 | if (_meshKey == newMeshKey) return; | ||
967 | |||
968 | // Since we're recreating new, get rid of any previously generated shape | ||
969 | if (_meshKey != 0) | ||
970 | { | ||
971 | // m_log.DebugFormat("{0}: CreateGeom: deleting old mesh. lID={1}, Key={2}", LogHeader, _localID, _meshKey); | ||
972 | BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey); | ||
973 | _mesh = null; | ||
974 | _meshKey = 0; | ||
975 | } | ||
976 | |||
977 | _meshKey = newMeshKey; | ||
978 | // always pass false for physicalness as this creates some sort of bounding box which we don't need | ||
979 | _mesh = _scene.mesher.CreateMesh(_avName, _pbs, _size, lod, false); | ||
980 | |||
981 | int[] indices = _mesh.getIndexListAsInt(); | ||
982 | List<OMV.Vector3> vertices = _mesh.getVertexList(); | ||
983 | |||
984 | float[] verticesAsFloats = new float[vertices.Count * 3]; | ||
985 | int vi = 0; | ||
986 | foreach (OMV.Vector3 vv in vertices) | ||
987 | { | ||
988 | // m_log.DebugFormat("{0}: {1}: <{2:0.00}, {3:0.00}, {4:0.00}>", LogHeader, vi / 3, vv.X, vv.Y, vv.Z); | ||
989 | verticesAsFloats[vi++] = vv.X; | ||
990 | verticesAsFloats[vi++] = vv.Y; | ||
991 | verticesAsFloats[vi++] = vv.Z; | ||
992 | } | ||
993 | |||
994 | // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", | ||
995 | // LogHeader, _localID, _meshKey, indices.Length, vertices.Count); | ||
996 | BulletSimAPI.CreateMesh(_scene.WorldID, _meshKey, indices.GetLength(0), indices, | ||
997 | vertices.Count, verticesAsFloats); | ||
998 | |||
999 | _shapeType = ShapeData.PhysicsShapeType.SHAPE_MESH; | ||
1000 | // meshes are already scaled by the meshmerizer | ||
1001 | _scale = new OMV.Vector3(1f, 1f, 1f); | ||
1002 | return; | ||
1003 | } | ||
1004 | |||
1005 | // No locking here because this is done when we know physics is not simulating | ||
1006 | private void CreateGeomHull() | ||
1007 | { | ||
1008 | float lod = _pbs.SculptEntry ? _scene.SculptLOD : _scene.MeshLOD; | ||
1009 | ulong newHullKey = (ulong)_pbs.GetMeshKey(_size, lod); | ||
1010 | // m_log.DebugFormat("{0}: CreateGeomHull: lID={1}, oldKey={2}, newKey={3}", LogHeader, _localID, _hullKey, newHullKey); | ||
1011 | |||
1012 | // if the hull hasn't changed, don't rebuild it | ||
1013 | if (newHullKey == _hullKey) return; | ||
1014 | |||
1015 | // Since we're recreating new, get rid of any previously generated shape | ||
1016 | if (_hullKey != 0) | ||
1017 | { | ||
1018 | // m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey); | ||
1019 | BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey); | ||
1020 | _hullKey = 0; | ||
1021 | _hulls.Clear(); | ||
1022 | BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey); | ||
1023 | _mesh = null; // the mesh cannot match either | ||
1024 | _meshKey = 0; | ||
1025 | } | ||
1026 | |||
1027 | _hullKey = newHullKey; | ||
1028 | if (_meshKey != _hullKey) | ||
1029 | { | ||
1030 | // if the underlying mesh has changed, rebuild it | ||
1031 | CreateGeomMesh(); | ||
1032 | } | ||
1033 | |||
1034 | int[] indices = _mesh.getIndexListAsInt(); | ||
1035 | List<OMV.Vector3> vertices = _mesh.getVertexList(); | ||
1036 | |||
1037 | //format conversion from IMesh format to DecompDesc format | ||
1038 | List<int> convIndices = new List<int>(); | ||
1039 | List<float3> convVertices = new List<float3>(); | ||
1040 | for (int ii = 0; ii < indices.GetLength(0); ii++) | ||
1041 | { | ||
1042 | convIndices.Add(indices[ii]); | ||
1043 | } | ||
1044 | foreach (OMV.Vector3 vv in vertices) | ||
1045 | { | ||
1046 | convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); | ||
1047 | } | ||
1048 | |||
1049 | // setup and do convex hull conversion | ||
1050 | _hulls = new List<ConvexResult>(); | ||
1051 | DecompDesc dcomp = new DecompDesc(); | ||
1052 | dcomp.mIndices = convIndices; | ||
1053 | dcomp.mVertices = convVertices; | ||
1054 | ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); | ||
1055 | // create the hull into the _hulls variable | ||
1056 | convexBuilder.process(dcomp); | ||
1057 | |||
1058 | // Convert the vertices and indices for passing to unmanaged | ||
1059 | // The hull information is passed as a large floating point array. | ||
1060 | // The format is: | ||
1061 | // convHulls[0] = number of hulls | ||
1062 | // convHulls[1] = number of vertices in first hull | ||
1063 | // convHulls[2] = hull centroid X coordinate | ||
1064 | // convHulls[3] = hull centroid Y coordinate | ||
1065 | // convHulls[4] = hull centroid Z coordinate | ||
1066 | // convHulls[5] = first hull vertex X | ||
1067 | // convHulls[6] = first hull vertex Y | ||
1068 | // convHulls[7] = first hull vertex Z | ||
1069 | // convHulls[8] = second hull vertex X | ||
1070 | // ... | ||
1071 | // convHulls[n] = number of vertices in second hull | ||
1072 | // convHulls[n+1] = second hull centroid X coordinate | ||
1073 | // ... | ||
1074 | // | ||
1075 | // TODO: is is very inefficient. Someday change the convex hull generator to return | ||
1076 | // data structures that do not need to be converted in order to pass to Bullet. | ||
1077 | // And maybe put the values directly into pinned memory rather than marshaling. | ||
1078 | int hullCount = _hulls.Count; | ||
1079 | int totalVertices = 1; // include one for the count of the hulls | ||
1080 | foreach (ConvexResult cr in _hulls) | ||
1081 | { | ||
1082 | totalVertices += 4; // add four for the vertex count and centroid | ||
1083 | totalVertices += cr.HullIndices.Count * 3; // we pass just triangles | ||
1084 | } | ||
1085 | float[] convHulls = new float[totalVertices]; | ||
1086 | |||
1087 | convHulls[0] = (float)hullCount; | ||
1088 | int jj = 1; | ||
1089 | foreach (ConvexResult cr in _hulls) | ||
1090 | { | ||
1091 | // copy vertices for index access | ||
1092 | float3[] verts = new float3[cr.HullVertices.Count]; | ||
1093 | int kk = 0; | ||
1094 | foreach (float3 ff in cr.HullVertices) | ||
1095 | { | ||
1096 | verts[kk++] = ff; | ||
1097 | } | ||
1098 | |||
1099 | // add to the array one hull's worth of data | ||
1100 | convHulls[jj++] = cr.HullIndices.Count; | ||
1101 | convHulls[jj++] = 0f; // centroid x,y,z | ||
1102 | convHulls[jj++] = 0f; | ||
1103 | convHulls[jj++] = 0f; | ||
1104 | foreach (int ind in cr.HullIndices) | ||
1105 | { | ||
1106 | convHulls[jj++] = verts[ind].x; | ||
1107 | convHulls[jj++] = verts[ind].y; | ||
1108 | convHulls[jj++] = verts[ind].z; | ||
1109 | } | ||
1110 | } | ||
1111 | |||
1112 | // create the hull definition in Bullet | ||
1113 | // m_log.DebugFormat("{0}: CreateGeom: calling CreateHull. lid={1}, key={2}, hulls={3}", LogHeader, _localID, _hullKey, hullCount); | ||
1114 | BulletSimAPI.CreateHull(_scene.WorldID, _hullKey, hullCount, convHulls); | ||
1115 | _shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL; | ||
1116 | // meshes are already scaled by the meshmerizer | ||
1117 | _scale = new OMV.Vector3(1f, 1f, 1f); | ||
1118 | return; | ||
1119 | } | ||
1120 | |||
1121 | // Callback from convex hull creater with a newly created hull. | ||
1122 | // Just add it to the collection of hulls for this shape. | ||
1123 | private void HullReturn(ConvexResult result) | ||
1124 | { | ||
1125 | _hulls.Add(result); | ||
1126 | return; | ||
1127 | } | ||
1128 | |||
1129 | // Create an object in Bullet | ||
1130 | // No locking here because this is done when the physics engine is not simulating | ||
1131 | private void CreateObject() | ||
1132 | { | ||
1133 | if (IsRootOfLinkset) | ||
1134 | { | ||
1135 | // Create a linkset around this object | ||
1136 | // CreateLinksetWithCompoundHull(); | ||
1137 | CreateLinksetWithConstraints(); | ||
1138 | } | ||
1139 | else | ||
1140 | { | ||
1141 | // simple object | ||
1142 | // the mesh or hull must have already been created in Bullet | ||
1143 | ShapeData shape; | ||
1144 | FillShapeInfo(out shape); | ||
1145 | // m_log.DebugFormat("{0}: CreateObject: lID={1}, shape={2}", LogHeader, _localID, shape.Type); | ||
1146 | BulletSimAPI.CreateObject(_scene.WorldID, shape); | ||
1147 | } | ||
1148 | } | ||
1149 | |||
1150 | // Create a linkset by creating a compound hull at the root prim that consists of all | ||
1151 | // the children. | ||
1152 | // NOTE: This does not allow proper collisions with the children prims so it is not a workable solution | ||
1153 | void CreateLinksetWithCompoundHull() | ||
1154 | { | ||
1155 | // If I am the root prim of a linkset, replace my physical shape with all the | ||
1156 | // pieces of the children. | ||
1157 | // All of the children should have called CreateGeom so they have a hull | ||
1158 | // in the physics engine already. Here we pull together all of those hulls | ||
1159 | // into one shape. | ||
1160 | int totalPrimsInLinkset = _childrenPrims.Count + 1; | ||
1161 | // m_log.DebugFormat("{0}: CreateLinkset. Root prim={1}, prims={2}", LogHeader, LocalID, totalPrimsInLinkset); | ||
1162 | ShapeData[] shapes = new ShapeData[totalPrimsInLinkset]; | ||
1163 | FillShapeInfo(out shapes[0]); | ||
1164 | int ii = 1; | ||
1165 | foreach (BSPrim prim in _childrenPrims) | ||
1166 | { | ||
1167 | // m_log.DebugFormat("{0}: CreateLinkset: adding prim {1}", LogHeader, prim.LocalID); | ||
1168 | prim.FillShapeInfo(out shapes[ii]); | ||
1169 | ii++; | ||
1170 | } | ||
1171 | BulletSimAPI.CreateLinkset(_scene.WorldID, totalPrimsInLinkset, shapes); | ||
1172 | } | ||
1173 | |||
1174 | // Copy prim's info into the BulletSim shape description structure | ||
1175 | public void FillShapeInfo(out ShapeData shape) | ||
1176 | { | ||
1177 | shape.ID = _localID; | ||
1178 | shape.Type = _shapeType; | ||
1179 | shape.Position = _position; | ||
1180 | shape.Rotation = _orientation; | ||
1181 | shape.Velocity = _velocity; | ||
1182 | shape.Scale = _scale; | ||
1183 | shape.Mass = _isPhysical ? _mass : 0f; | ||
1184 | shape.Buoyancy = _buoyancy; | ||
1185 | shape.HullKey = _hullKey; | ||
1186 | shape.MeshKey = _meshKey; | ||
1187 | shape.Friction = _friction; | ||
1188 | shape.Restitution = _restitution; | ||
1189 | shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse; | ||
1190 | shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue; | ||
1191 | } | ||
1192 | |||
1193 | // Create the linkset by putting constraints between the objects of the set so they cannot move | ||
1194 | // relative to each other. | ||
1195 | // TODO: make this more effeicient: a large linkset gets rebuilt over and over and prims are added | ||
1196 | void CreateLinksetWithConstraints() | ||
1197 | { | ||
1198 | // m_log.DebugFormat("{0}: CreateLinkset. Root prim={1}, prims={2}", LogHeader, LocalID, _childrenPrims.Count+1); | ||
1199 | |||
1200 | // remove any constraints that might be in place | ||
1201 | foreach (BSPrim prim in _childrenPrims) | ||
1202 | { | ||
1203 | // m_log.DebugFormat("{0}: CreateLinkset: RemoveConstraint between root prim {1} and child prim {2}", LogHeader, LocalID, prim.LocalID); | ||
1204 | BulletSimAPI.RemoveConstraint(_scene.WorldID, LocalID, prim.LocalID); | ||
1205 | } | ||
1206 | // create constraints between the root prim and each of the children | ||
1207 | foreach (BSPrim prim in _childrenPrims) | ||
1208 | { | ||
1209 | // m_log.DebugFormat("{0}: CreateLinkset: AddConstraint between root prim {1} and child prim {2}", LogHeader, LocalID, prim.LocalID); | ||
1210 | |||
1211 | // Zero motion for children so they don't interpolate | ||
1212 | prim.ZeroMotion(); | ||
1213 | |||
1214 | // relative position normalized to the root prim | ||
1215 | OMV.Vector3 childRelativePosition = (prim._position - this._position) * OMV.Quaternion.Inverse(this._orientation); | ||
1216 | |||
1217 | // relative rotation of the child to the parent | ||
1218 | OMV.Quaternion relativeRotation = OMV.Quaternion.Inverse(prim._orientation) * this._orientation; | ||
1219 | |||
1220 | // this is a constraint that allows no freedom of movement between the two objects | ||
1221 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 | ||
1222 | BulletSimAPI.AddConstraint(_scene.WorldID, LocalID, prim.LocalID, | ||
1223 | childRelativePosition, | ||
1224 | relativeRotation, | ||
1225 | OMV.Vector3.Zero, | ||
1226 | OMV.Quaternion.Identity, | ||
1227 | OMV.Vector3.Zero, OMV.Vector3.Zero, | ||
1228 | OMV.Vector3.Zero, OMV.Vector3.Zero); | ||
1229 | } | ||
1230 | } | ||
1231 | |||
1232 | // Rebuild the geometry and object. | ||
1233 | // This is called when the shape changes so we need to recreate the mesh/hull. | ||
1234 | // No locking here because this is done when the physics engine is not simulating | ||
1235 | private void RecreateGeomAndObject() | ||
1236 | { | ||
1237 | // m_log.DebugFormat("{0}: RecreateGeomAndObject. lID={1}", LogHeader, _localID); | ||
1238 | CreateGeom(true); | ||
1239 | CreateObject(); | ||
1240 | return; | ||
1241 | } | ||
1242 | |||
1243 | // The physics engine says that properties have updated. Update same and inform | ||
1244 | // the world that things have changed. | ||
1245 | // TODO: do we really need to check for changed? Maybe just copy values and call RequestPhysicsterseUpdate() | ||
1246 | enum UpdatedProperties { | ||
1247 | Position = 1 << 0, | ||
1248 | Rotation = 1 << 1, | ||
1249 | Velocity = 1 << 2, | ||
1250 | Acceleration = 1 << 3, | ||
1251 | RotationalVel = 1 << 4 | ||
1252 | } | ||
1253 | |||
1254 | const float ROTATION_TOLERANCE = 0.01f; | ||
1255 | const float VELOCITY_TOLERANCE = 0.001f; | ||
1256 | const float POSITION_TOLERANCE = 0.05f; | ||
1257 | const float ACCELERATION_TOLERANCE = 0.01f; | ||
1258 | const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f; | ||
1259 | const bool SHOULD_DAMP_UPDATES = false; | ||
1260 | |||
1261 | public void UpdateProperties(EntityProperties entprop) | ||
1262 | { | ||
1263 | UpdatedProperties changed = 0; | ||
1264 | if (SHOULD_DAMP_UPDATES) | ||
1265 | { | ||
1266 | // assign to the local variables so the normal set action does not happen | ||
1267 | // if (_position != entprop.Position) | ||
1268 | if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE)) | ||
1269 | { | ||
1270 | _position = entprop.Position; | ||
1271 | // m_log.DebugFormat("{0}: UpdateProperties: id={1}, pos = {2}", LogHeader, LocalID, _position); | ||
1272 | changed |= UpdatedProperties.Position; | ||
1273 | } | ||
1274 | // if (_orientation != entprop.Rotation) | ||
1275 | if (!_orientation.ApproxEquals(entprop.Rotation, ROTATION_TOLERANCE)) | ||
1276 | { | ||
1277 | _orientation = entprop.Rotation; | ||
1278 | // m_log.DebugFormat("{0}: UpdateProperties: id={1}, rot = {2}", LogHeader, LocalID, _orientation); | ||
1279 | changed |= UpdatedProperties.Rotation; | ||
1280 | } | ||
1281 | // if (_velocity != entprop.Velocity) | ||
1282 | if (!_velocity.ApproxEquals(entprop.Velocity, VELOCITY_TOLERANCE)) | ||
1283 | { | ||
1284 | _velocity = entprop.Velocity; | ||
1285 | // m_log.DebugFormat("{0}: UpdateProperties: velocity = {1}", LogHeader, _velocity); | ||
1286 | changed |= UpdatedProperties.Velocity; | ||
1287 | } | ||
1288 | // if (_acceleration != entprop.Acceleration) | ||
1289 | if (!_acceleration.ApproxEquals(entprop.Acceleration, ACCELERATION_TOLERANCE)) | ||
1290 | { | ||
1291 | _acceleration = entprop.Acceleration; | ||
1292 | // m_log.DebugFormat("{0}: UpdateProperties: acceleration = {1}", LogHeader, _acceleration); | ||
1293 | changed |= UpdatedProperties.Acceleration; | ||
1294 | } | ||
1295 | // if (_rotationalVelocity != entprop.RotationalVelocity) | ||
1296 | if (!_rotationalVelocity.ApproxEquals(entprop.RotationalVelocity, ROTATIONAL_VELOCITY_TOLERANCE)) | ||
1297 | { | ||
1298 | _rotationalVelocity = entprop.RotationalVelocity; | ||
1299 | // m_log.DebugFormat("{0}: UpdateProperties: rotationalVelocity = {1}", LogHeader, _rotationalVelocity); | ||
1300 | changed |= UpdatedProperties.RotationalVel; | ||
1301 | } | ||
1302 | if (changed != 0) | ||
1303 | { | ||
1304 | // m_log.DebugFormat("{0}: UpdateProperties: id={1}, c={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation); | ||
1305 | // Only update the position of single objects and linkset roots | ||
1306 | if (this._parentPrim == null) | ||
1307 | { | ||
1308 | // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation); | ||
1309 | base.RequestPhysicsterseUpdate(); | ||
1310 | } | ||
1311 | } | ||
1312 | } | ||
1313 | else | ||
1314 | { | ||
1315 | // Don't check for damping here -- it's done in BulletSim and SceneObjectPart. | ||
1316 | |||
1317 | // Only updates only for individual prims and for the root object of a linkset. | ||
1318 | if (this._parentPrim == null) | ||
1319 | { | ||
1320 | // Assign to the local variables so the normal set action does not happen | ||
1321 | _position = entprop.Position; | ||
1322 | _orientation = entprop.Rotation; | ||
1323 | _velocity = entprop.Velocity; | ||
1324 | _acceleration = entprop.Acceleration; | ||
1325 | _rotationalVelocity = entprop.RotationalVelocity; | ||
1326 | // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation); | ||
1327 | base.RequestPhysicsterseUpdate(); | ||
1328 | } | ||
1329 | } | ||
1330 | } | ||
1331 | |||
1332 | // I've collided with something | ||
1333 | public void Collide(uint collidingWith, ActorTypes type, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) | ||
1334 | { | ||
1335 | // m_log.DebugFormat("{0}: Collide: ms={1}, id={2}, with={3}", LogHeader, _subscribedEventsMs, LocalID, collidingWith); | ||
1336 | |||
1337 | // The following lines make IsColliding() and IsCollidingGround() work | ||
1338 | _collidingStep = _scene.SimulationStep; | ||
1339 | if (collidingWith == BSScene.TERRAIN_ID || collidingWith == BSScene.GROUNDPLANE_ID) | ||
1340 | { | ||
1341 | _collidingGroundStep = _scene.SimulationStep; | ||
1342 | } | ||
1343 | |||
1344 | if (_subscribedEventsMs == 0) return; // nothing in the object is waiting for collision events | ||
1345 | // throttle the collisions to the number of milliseconds specified in the subscription | ||
1346 | int nowTime = _scene.SimulationNowTime; | ||
1347 | if (nowTime < (_lastCollisionTime + _subscribedEventsMs)) return; | ||
1348 | _lastCollisionTime = nowTime; | ||
1349 | |||
1350 | // create the event for the collision | ||
1351 | Dictionary<uint, ContactPoint> contactPoints = new Dictionary<uint, ContactPoint>(); | ||
1352 | contactPoints.Add(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); | ||
1353 | CollisionEventUpdate args = new CollisionEventUpdate(LocalID, (int)type, 1, contactPoints); | ||
1354 | base.SendCollisionUpdate(args); | ||
1355 | } | ||
1356 | } | ||
1357 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs new file mode 100644 index 0000000..7704002 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | |||
@@ -0,0 +1,860 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyrightD | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Runtime.InteropServices; | ||
30 | using System.Text; | ||
31 | using System.Threading; | ||
32 | using Nini.Config; | ||
33 | using log4net; | ||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Region.Physics.Manager; | ||
36 | using OpenMetaverse; | ||
37 | using OpenSim.Region.Framework; | ||
38 | |||
39 | // TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) | ||
40 | // Adjust character capsule size when height is adjusted (ScenePresence.SetHeight) | ||
41 | // Test sculpties | ||
42 | // Compute physics FPS reasonably | ||
43 | // Based on material, set density and friction | ||
44 | // More efficient memory usage in passing hull information from BSPrim to BulletSim | ||
45 | // Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly? | ||
46 | // In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground) | ||
47 | // At the moment, physical and phantom causes object to drop through the terrain | ||
48 | // Should prim.link() and prim.delink() membership checking happen at taint time? | ||
49 | // Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once | ||
50 | // Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect | ||
51 | // Implement the genCollisions feature in BulletSim::SetObjectProperties (don't pass up unneeded collisions) | ||
52 | // Implement LockAngularMotion | ||
53 | // Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation) | ||
54 | // Does NeedsMeshing() really need to exclude all the different shapes? | ||
55 | // | ||
56 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
57 | { | ||
58 | public class BSScene : PhysicsScene, IPhysicsParameters | ||
59 | { | ||
60 | private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); | ||
61 | private static readonly string LogHeader = "[BULLETS SCENE]"; | ||
62 | |||
63 | public string BulletSimVersion = "?"; | ||
64 | |||
65 | private Dictionary<uint, BSCharacter> m_avatars = new Dictionary<uint, BSCharacter>(); | ||
66 | private Dictionary<uint, BSPrim> m_prims = new Dictionary<uint, BSPrim>(); | ||
67 | private List<BSPrim> m_vehicles = new List<BSPrim>(); | ||
68 | private float[] m_heightMap; | ||
69 | private float m_waterLevel; | ||
70 | private uint m_worldID; | ||
71 | public uint WorldID { get { return m_worldID; } } | ||
72 | |||
73 | private bool m_initialized = false; | ||
74 | |||
75 | public IMesher mesher; | ||
76 | private float m_meshLOD; | ||
77 | public float MeshLOD | ||
78 | { | ||
79 | get { return m_meshLOD; } | ||
80 | } | ||
81 | private float m_sculptLOD; | ||
82 | public float SculptLOD | ||
83 | { | ||
84 | get { return m_sculptLOD; } | ||
85 | } | ||
86 | |||
87 | private int m_maxSubSteps; | ||
88 | private float m_fixedTimeStep; | ||
89 | private long m_simulationStep = 0; | ||
90 | public long SimulationStep { get { return m_simulationStep; } } | ||
91 | |||
92 | // A value of the time now so all the collision and update routines do not have to get their own | ||
93 | // Set to 'now' just before all the prims and actors are called for collisions and updates | ||
94 | private int m_simulationNowTime; | ||
95 | public int SimulationNowTime { get { return m_simulationNowTime; } } | ||
96 | |||
97 | private int m_maxCollisionsPerFrame; | ||
98 | private CollisionDesc[] m_collisionArray; | ||
99 | private GCHandle m_collisionArrayPinnedHandle; | ||
100 | |||
101 | private int m_maxUpdatesPerFrame; | ||
102 | private EntityProperties[] m_updateArray; | ||
103 | private GCHandle m_updateArrayPinnedHandle; | ||
104 | |||
105 | private bool _meshSculptedPrim = true; // cause scuplted prims to get meshed | ||
106 | private bool _forceSimplePrimMeshing = false; // if a cube or sphere, let Bullet do internal shapes | ||
107 | |||
108 | public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero | ||
109 | public const uint GROUNDPLANE_ID = 1; | ||
110 | |||
111 | public ConfigurationParameters Params | ||
112 | { | ||
113 | get { return m_params[0]; } | ||
114 | } | ||
115 | public Vector3 DefaultGravity | ||
116 | { | ||
117 | get { return new Vector3(0f, 0f, Params.gravity); } | ||
118 | } | ||
119 | |||
120 | private float m_maximumObjectMass; | ||
121 | public float MaximumObjectMass | ||
122 | { | ||
123 | get { return m_maximumObjectMass; } | ||
124 | } | ||
125 | |||
126 | public delegate void TaintCallback(); | ||
127 | private List<TaintCallback> _taintedObjects; | ||
128 | private Object _taintLock = new Object(); | ||
129 | |||
130 | // A pointer to an instance if this structure is passed to the C++ code | ||
131 | ConfigurationParameters[] m_params; | ||
132 | GCHandle m_paramsHandle; | ||
133 | |||
134 | private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle; | ||
135 | |||
136 | public BSScene(string identifier) | ||
137 | { | ||
138 | m_initialized = false; | ||
139 | } | ||
140 | |||
141 | public override void Initialise(IMesher meshmerizer, IConfigSource config) | ||
142 | { | ||
143 | // Allocate pinned memory to pass parameters. | ||
144 | m_params = new ConfigurationParameters[1]; | ||
145 | m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned); | ||
146 | |||
147 | // Set default values for physics parameters plus any overrides from the ini file | ||
148 | GetInitialParameterValues(config); | ||
149 | |||
150 | // allocate more pinned memory close to the above in an attempt to get the memory all together | ||
151 | m_collisionArray = new CollisionDesc[m_maxCollisionsPerFrame]; | ||
152 | m_collisionArrayPinnedHandle = GCHandle.Alloc(m_collisionArray, GCHandleType.Pinned); | ||
153 | m_updateArray = new EntityProperties[m_maxUpdatesPerFrame]; | ||
154 | m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned); | ||
155 | |||
156 | // Get the version of the DLL | ||
157 | // TODO: this doesn't work yet. Something wrong with marshaling the returned string. | ||
158 | // BulletSimVersion = BulletSimAPI.GetVersion(); | ||
159 | // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion); | ||
160 | |||
161 | // if Debug, enable logging from the unmanaged code | ||
162 | if (m_log.IsDebugEnabled) | ||
163 | { | ||
164 | m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader); | ||
165 | m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger); | ||
166 | BulletSimAPI.SetDebugLogCallback(m_DebugLogCallbackHandle); | ||
167 | } | ||
168 | |||
169 | _taintedObjects = new List<TaintCallback>(); | ||
170 | |||
171 | mesher = meshmerizer; | ||
172 | // The bounding box for the simulated world | ||
173 | Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, 4096f); | ||
174 | |||
175 | // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader); | ||
176 | m_worldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(), | ||
177 | m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(), | ||
178 | m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject()); | ||
179 | |||
180 | m_initialized = true; | ||
181 | } | ||
182 | |||
183 | // All default parameter values are set here. There should be no values set in the | ||
184 | // variable definitions. | ||
185 | private void GetInitialParameterValues(IConfigSource config) | ||
186 | { | ||
187 | ConfigurationParameters parms = new ConfigurationParameters(); | ||
188 | |||
189 | _meshSculptedPrim = true; // mesh sculpted prims | ||
190 | _forceSimplePrimMeshing = false; // use complex meshing if called for | ||
191 | |||
192 | m_meshLOD = 8f; | ||
193 | m_sculptLOD = 32f; | ||
194 | |||
195 | m_maxSubSteps = 10; | ||
196 | m_fixedTimeStep = 1f / 60f; | ||
197 | m_maxCollisionsPerFrame = 2048; | ||
198 | m_maxUpdatesPerFrame = 2048; | ||
199 | m_maximumObjectMass = 10000.01f; | ||
200 | |||
201 | parms.defaultFriction = 0.5f; | ||
202 | parms.defaultDensity = 10.000006836f; // Aluminum g/cm3 | ||
203 | parms.defaultRestitution = 0f; | ||
204 | parms.collisionMargin = 0.0f; | ||
205 | parms.gravity = -9.80665f; | ||
206 | |||
207 | parms.linearDamping = 0.0f; | ||
208 | parms.angularDamping = 0.0f; | ||
209 | parms.deactivationTime = 0.2f; | ||
210 | parms.linearSleepingThreshold = 0.8f; | ||
211 | parms.angularSleepingThreshold = 1.0f; | ||
212 | parms.ccdMotionThreshold = 0.5f; // set to zero to disable | ||
213 | parms.ccdSweptSphereRadius = 0.2f; | ||
214 | |||
215 | parms.terrainFriction = 0.5f; | ||
216 | parms.terrainHitFraction = 0.8f; | ||
217 | parms.terrainRestitution = 0f; | ||
218 | parms.avatarFriction = 0.0f; | ||
219 | parms.avatarDensity = 60f; | ||
220 | parms.avatarCapsuleRadius = 0.37f; | ||
221 | parms.avatarCapsuleHeight = 1.5f; // 2.140599f | ||
222 | |||
223 | if (config != null) | ||
224 | { | ||
225 | // If there are specifications in the ini file, use those values | ||
226 | // WHEN ADDING OR UPDATING THIS SECTION, BE SURE TO UPDATE OpenSimDefaults.ini | ||
227 | // ALSO REMEMBER TO UPDATE THE RUNTIME SETTING OF THE PARAMETERS. | ||
228 | IConfig pConfig = config.Configs["BulletSim"]; | ||
229 | if (pConfig != null) | ||
230 | { | ||
231 | _meshSculptedPrim = pConfig.GetBoolean("MeshSculptedPrim", _meshSculptedPrim); | ||
232 | _forceSimplePrimMeshing = pConfig.GetBoolean("ForceSimplePrimMeshing", _forceSimplePrimMeshing); | ||
233 | |||
234 | m_meshLOD = pConfig.GetFloat("MeshLevelOfDetail", m_meshLOD); | ||
235 | m_sculptLOD = pConfig.GetFloat("SculptLevelOfDetail", m_sculptLOD); | ||
236 | |||
237 | m_maxSubSteps = pConfig.GetInt("MaxSubSteps", m_maxSubSteps); | ||
238 | m_fixedTimeStep = pConfig.GetFloat("FixedTimeStep", m_fixedTimeStep); | ||
239 | m_maxCollisionsPerFrame = pConfig.GetInt("MaxCollisionsPerFrame", m_maxCollisionsPerFrame); | ||
240 | m_maxUpdatesPerFrame = pConfig.GetInt("MaxUpdatesPerFrame", m_maxUpdatesPerFrame); | ||
241 | m_maximumObjectMass = pConfig.GetFloat("MaxObjectMass", m_maximumObjectMass); | ||
242 | |||
243 | parms.defaultFriction = pConfig.GetFloat("DefaultFriction", parms.defaultFriction); | ||
244 | parms.defaultDensity = pConfig.GetFloat("DefaultDensity", parms.defaultDensity); | ||
245 | parms.defaultRestitution = pConfig.GetFloat("DefaultRestitution", parms.defaultRestitution); | ||
246 | parms.collisionMargin = pConfig.GetFloat("CollisionMargin", parms.collisionMargin); | ||
247 | parms.gravity = pConfig.GetFloat("Gravity", parms.gravity); | ||
248 | |||
249 | parms.linearDamping = pConfig.GetFloat("LinearDamping", parms.linearDamping); | ||
250 | parms.angularDamping = pConfig.GetFloat("AngularDamping", parms.angularDamping); | ||
251 | parms.deactivationTime = pConfig.GetFloat("DeactivationTime", parms.deactivationTime); | ||
252 | parms.linearSleepingThreshold = pConfig.GetFloat("LinearSleepingThreshold", parms.linearSleepingThreshold); | ||
253 | parms.angularSleepingThreshold = pConfig.GetFloat("AngularSleepingThreshold", parms.angularSleepingThreshold); | ||
254 | parms.ccdMotionThreshold = pConfig.GetFloat("CcdMotionThreshold", parms.ccdMotionThreshold); | ||
255 | parms.ccdSweptSphereRadius = pConfig.GetFloat("CcdSweptSphereRadius", parms.ccdSweptSphereRadius); | ||
256 | |||
257 | parms.terrainFriction = pConfig.GetFloat("TerrainFriction", parms.terrainFriction); | ||
258 | parms.terrainHitFraction = pConfig.GetFloat("TerrainHitFraction", parms.terrainHitFraction); | ||
259 | parms.terrainRestitution = pConfig.GetFloat("TerrainRestitution", parms.terrainRestitution); | ||
260 | parms.avatarFriction = pConfig.GetFloat("AvatarFriction", parms.avatarFriction); | ||
261 | parms.avatarDensity = pConfig.GetFloat("AvatarDensity", parms.avatarDensity); | ||
262 | parms.avatarCapsuleRadius = pConfig.GetFloat("AvatarCapsuleRadius", parms.avatarCapsuleRadius); | ||
263 | parms.avatarCapsuleHeight = pConfig.GetFloat("AvatarCapsuleHeight", parms.avatarCapsuleHeight); | ||
264 | } | ||
265 | } | ||
266 | m_params[0] = parms; | ||
267 | } | ||
268 | |||
269 | // Called directly from unmanaged code so don't do much | ||
270 | private void BulletLogger(string msg) | ||
271 | { | ||
272 | m_log.Debug("[BULLETS UNMANAGED]:" + msg); | ||
273 | } | ||
274 | |||
275 | public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying) | ||
276 | { | ||
277 | m_log.ErrorFormat("{0}: CALL TO AddAvatar in BSScene. NOT IMPLEMENTED", LogHeader); | ||
278 | return null; | ||
279 | } | ||
280 | |||
281 | public override PhysicsActor AddAvatar(uint localID, string avName, Vector3 position, Vector3 size, bool isFlying) | ||
282 | { | ||
283 | // m_log.DebugFormat("{0}: AddAvatar: {1}", LogHeader, avName); | ||
284 | BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying); | ||
285 | lock (m_avatars) m_avatars.Add(localID, actor); | ||
286 | return actor; | ||
287 | } | ||
288 | |||
289 | public override void RemoveAvatar(PhysicsActor actor) | ||
290 | { | ||
291 | // m_log.DebugFormat("{0}: RemoveAvatar", LogHeader); | ||
292 | if (actor is BSCharacter) | ||
293 | { | ||
294 | ((BSCharacter)actor).Destroy(); | ||
295 | } | ||
296 | try | ||
297 | { | ||
298 | lock (m_avatars) m_avatars.Remove(actor.LocalID); | ||
299 | } | ||
300 | catch (Exception e) | ||
301 | { | ||
302 | m_log.WarnFormat("{0}: Attempt to remove avatar that is not in physics scene: {1}", LogHeader, e); | ||
303 | } | ||
304 | } | ||
305 | |||
306 | public override void RemovePrim(PhysicsActor prim) | ||
307 | { | ||
308 | // m_log.DebugFormat("{0}: RemovePrim", LogHeader); | ||
309 | if (prim is BSPrim) | ||
310 | { | ||
311 | ((BSPrim)prim).Destroy(); | ||
312 | } | ||
313 | try | ||
314 | { | ||
315 | lock (m_prims) m_prims.Remove(prim.LocalID); | ||
316 | } | ||
317 | catch (Exception e) | ||
318 | { | ||
319 | m_log.WarnFormat("{0}: Attempt to remove prim that is not in physics scene: {1}", LogHeader, e); | ||
320 | } | ||
321 | } | ||
322 | |||
323 | public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, | ||
324 | Vector3 size, Quaternion rotation, bool isPhysical, uint localID) | ||
325 | { | ||
326 | // m_log.DebugFormat("{0}: AddPrimShape2: {1}", LogHeader, primName); | ||
327 | BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical); | ||
328 | lock (m_prims) m_prims.Add(localID, prim); | ||
329 | return prim; | ||
330 | } | ||
331 | |||
332 | // This is a call from the simulator saying that some physical property has been updated. | ||
333 | // The BulletSim driver senses the changing of relevant properties so this taint | ||
334 | // information call is not needed. | ||
335 | public override void AddPhysicsActorTaint(PhysicsActor prim) { } | ||
336 | |||
337 | // Simulate one timestep | ||
338 | public override float Simulate(float timeStep) | ||
339 | { | ||
340 | int updatedEntityCount; | ||
341 | IntPtr updatedEntitiesPtr; | ||
342 | int collidersCount; | ||
343 | IntPtr collidersPtr; | ||
344 | |||
345 | // prevent simulation until we've been initialized | ||
346 | if (!m_initialized) return 10.0f; | ||
347 | |||
348 | // update the prim states while we know the physics engine is not busy | ||
349 | ProcessTaints(); | ||
350 | |||
351 | // Some of the prims operate with special vehicle properties | ||
352 | ProcessVehicles(timeStep); | ||
353 | ProcessTaints(); // the vehicles might have added taints | ||
354 | |||
355 | // step the physical world one interval | ||
356 | m_simulationStep++; | ||
357 | int numSubSteps = BulletSimAPI.PhysicsStep(m_worldID, timeStep, m_maxSubSteps, m_fixedTimeStep, | ||
358 | out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr); | ||
359 | |||
360 | // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in | ||
361 | |||
362 | // Get a value for 'now' so all the collision and update routines don't have to get their own | ||
363 | m_simulationNowTime = Util.EnvironmentTickCount(); | ||
364 | |||
365 | // If there were collisions, process them by sending the event to the prim. | ||
366 | // Collisions must be processed before updates. | ||
367 | if (collidersCount > 0) | ||
368 | { | ||
369 | for (int ii = 0; ii < collidersCount; ii++) | ||
370 | { | ||
371 | uint cA = m_collisionArray[ii].aID; | ||
372 | uint cB = m_collisionArray[ii].bID; | ||
373 | Vector3 point = m_collisionArray[ii].point; | ||
374 | Vector3 normal = m_collisionArray[ii].normal; | ||
375 | SendCollision(cA, cB, point, normal, 0.01f); | ||
376 | SendCollision(cB, cA, point, -normal, 0.01f); | ||
377 | } | ||
378 | } | ||
379 | |||
380 | // If any of the objects had updated properties, tell the object it has been changed by the physics engine | ||
381 | if (updatedEntityCount > 0) | ||
382 | { | ||
383 | for (int ii = 0; ii < updatedEntityCount; ii++) | ||
384 | { | ||
385 | EntityProperties entprop = m_updateArray[ii]; | ||
386 | // m_log.DebugFormat("{0}: entprop[{1}]: id={2}, pos={3}", LogHeader, ii, entprop.ID, entprop.Position); | ||
387 | BSCharacter actor; | ||
388 | if (m_avatars.TryGetValue(entprop.ID, out actor)) | ||
389 | { | ||
390 | actor.UpdateProperties(entprop); | ||
391 | continue; | ||
392 | } | ||
393 | BSPrim prim; | ||
394 | if (m_prims.TryGetValue(entprop.ID, out prim)) | ||
395 | { | ||
396 | prim.UpdateProperties(entprop); | ||
397 | } | ||
398 | } | ||
399 | } | ||
400 | |||
401 | // TODO: FIX THIS: fps calculation wrong. This calculation always returns about 1 in normal operation. | ||
402 | return timeStep / (numSubSteps * m_fixedTimeStep) * 1000f; | ||
403 | } | ||
404 | |||
405 | // Something has collided | ||
406 | private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penitration) | ||
407 | { | ||
408 | if (localID == TERRAIN_ID || localID == GROUNDPLANE_ID) | ||
409 | { | ||
410 | return; // don't send collisions to the terrain | ||
411 | } | ||
412 | |||
413 | ActorTypes type = ActorTypes.Prim; | ||
414 | if (collidingWith == TERRAIN_ID || collidingWith == GROUNDPLANE_ID) | ||
415 | type = ActorTypes.Ground; | ||
416 | else if (m_avatars.ContainsKey(collidingWith)) | ||
417 | type = ActorTypes.Agent; | ||
418 | |||
419 | BSPrim prim; | ||
420 | if (m_prims.TryGetValue(localID, out prim)) { | ||
421 | prim.Collide(collidingWith, type, collidePoint, collideNormal, penitration); | ||
422 | return; | ||
423 | } | ||
424 | BSCharacter actor; | ||
425 | if (m_avatars.TryGetValue(localID, out actor)) { | ||
426 | actor.Collide(collidingWith, type, collidePoint, collideNormal, penitration); | ||
427 | return; | ||
428 | } | ||
429 | return; | ||
430 | } | ||
431 | |||
432 | public override void GetResults() { } | ||
433 | |||
434 | public override void SetTerrain(float[] heightMap) { | ||
435 | m_heightMap = heightMap; | ||
436 | this.TaintedObject(delegate() | ||
437 | { | ||
438 | BulletSimAPI.SetHeightmap(m_worldID, m_heightMap); | ||
439 | }); | ||
440 | } | ||
441 | |||
442 | public float GetTerrainHeightAtXY(float tX, float tY) | ||
443 | { | ||
444 | return m_heightMap[((int)tX) * Constants.RegionSize + ((int)tY)]; | ||
445 | } | ||
446 | |||
447 | public override void SetWaterLevel(float baseheight) | ||
448 | { | ||
449 | m_waterLevel = baseheight; | ||
450 | } | ||
451 | public float GetWaterLevel() | ||
452 | { | ||
453 | return m_waterLevel; | ||
454 | } | ||
455 | |||
456 | public override void DeleteTerrain() | ||
457 | { | ||
458 | m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader); | ||
459 | } | ||
460 | |||
461 | public override void Dispose() | ||
462 | { | ||
463 | m_log.DebugFormat("{0}: Dispose()", LogHeader); | ||
464 | } | ||
465 | |||
466 | public override Dictionary<uint, float> GetTopColliders() | ||
467 | { | ||
468 | return new Dictionary<uint, float>(); | ||
469 | } | ||
470 | |||
471 | public override bool IsThreaded { get { return false; } } | ||
472 | |||
473 | /// <summary> | ||
474 | /// Routine to figure out if we need to mesh this prim with our mesher | ||
475 | /// </summary> | ||
476 | /// <param name="pbs"></param> | ||
477 | /// <returns>true if the prim needs meshing</returns> | ||
478 | public bool NeedsMeshing(PrimitiveBaseShape pbs) | ||
479 | { | ||
480 | // most of this is redundant now as the mesher will return null if it cant mesh a prim | ||
481 | // but we still need to check for sculptie meshing being enabled so this is the most | ||
482 | // convenient place to do it for now... | ||
483 | |||
484 | // int iPropertiesNotSupportedDefault = 0; | ||
485 | |||
486 | if (pbs.SculptEntry && !_meshSculptedPrim) | ||
487 | { | ||
488 | // Render sculpties as boxes | ||
489 | return false; | ||
490 | } | ||
491 | |||
492 | // if it's a standard box or sphere with no cuts, hollows, twist or top shear, return false since Bullet | ||
493 | // can use an internal representation for the prim | ||
494 | if (!_forceSimplePrimMeshing) | ||
495 | { | ||
496 | if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) | ||
497 | || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 | ||
498 | && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)) | ||
499 | { | ||
500 | |||
501 | if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 | ||
502 | && pbs.ProfileHollow == 0 | ||
503 | && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 | ||
504 | && pbs.PathBegin == 0 && pbs.PathEnd == 0 | ||
505 | && pbs.PathTaperX == 0 && pbs.PathTaperY == 0 | ||
506 | && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 | ||
507 | && pbs.PathShearX == 0 && pbs.PathShearY == 0) | ||
508 | { | ||
509 | return false; | ||
510 | } | ||
511 | } | ||
512 | } | ||
513 | |||
514 | /* TODO: verify that the mesher will now do all these shapes | ||
515 | if (pbs.ProfileHollow != 0) | ||
516 | iPropertiesNotSupportedDefault++; | ||
517 | |||
518 | if ((pbs.PathBegin != 0) || pbs.PathEnd != 0) | ||
519 | iPropertiesNotSupportedDefault++; | ||
520 | |||
521 | if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0)) | ||
522 | iPropertiesNotSupportedDefault++; | ||
523 | |||
524 | if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0) | ||
525 | iPropertiesNotSupportedDefault++; | ||
526 | |||
527 | if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100)) | ||
528 | iPropertiesNotSupportedDefault++; | ||
529 | |||
530 | if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0)) | ||
531 | iPropertiesNotSupportedDefault++; | ||
532 | |||
533 | if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight) | ||
534 | iPropertiesNotSupportedDefault++; | ||
535 | |||
536 | if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 && (pbs.Scale.X != pbs.Scale.Y || pbs.Scale.Y != pbs.Scale.Z || pbs.Scale.Z != pbs.Scale.X)) | ||
537 | iPropertiesNotSupportedDefault++; | ||
538 | |||
539 | if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte) Extrusion.Curve1) | ||
540 | iPropertiesNotSupportedDefault++; | ||
541 | |||
542 | // test for torus | ||
543 | if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square) | ||
544 | { | ||
545 | if (pbs.PathCurve == (byte)Extrusion.Curve1) | ||
546 | { | ||
547 | iPropertiesNotSupportedDefault++; | ||
548 | } | ||
549 | } | ||
550 | else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle) | ||
551 | { | ||
552 | if (pbs.PathCurve == (byte)Extrusion.Straight) | ||
553 | { | ||
554 | iPropertiesNotSupportedDefault++; | ||
555 | } | ||
556 | // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits | ||
557 | else if (pbs.PathCurve == (byte)Extrusion.Curve1) | ||
558 | { | ||
559 | iPropertiesNotSupportedDefault++; | ||
560 | } | ||
561 | } | ||
562 | else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle) | ||
563 | { | ||
564 | if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2) | ||
565 | { | ||
566 | iPropertiesNotSupportedDefault++; | ||
567 | } | ||
568 | } | ||
569 | else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle) | ||
570 | { | ||
571 | if (pbs.PathCurve == (byte)Extrusion.Straight) | ||
572 | { | ||
573 | iPropertiesNotSupportedDefault++; | ||
574 | } | ||
575 | else if (pbs.PathCurve == (byte)Extrusion.Curve1) | ||
576 | { | ||
577 | iPropertiesNotSupportedDefault++; | ||
578 | } | ||
579 | } | ||
580 | if (iPropertiesNotSupportedDefault == 0) | ||
581 | { | ||
582 | return false; | ||
583 | } | ||
584 | */ | ||
585 | return true; | ||
586 | } | ||
587 | |||
588 | // The calls to the PhysicsActors can't directly call into the physics engine | ||
589 | // because it might be busy. We we delay changes to a known time. | ||
590 | // We rely on C#'s closure to save and restore the context for the delegate. | ||
591 | public void TaintedObject(TaintCallback callback) | ||
592 | { | ||
593 | lock (_taintLock) | ||
594 | _taintedObjects.Add(callback); | ||
595 | return; | ||
596 | } | ||
597 | |||
598 | // When someone tries to change a property on a BSPrim or BSCharacter, the object queues | ||
599 | // a callback into itself to do the actual property change. That callback is called | ||
600 | // here just before the physics engine is called to step the simulation. | ||
601 | public void ProcessTaints() | ||
602 | { | ||
603 | if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process | ||
604 | { | ||
605 | // swizzle a new list into the list location so we can process what's there | ||
606 | List<TaintCallback> oldList; | ||
607 | lock (_taintLock) | ||
608 | { | ||
609 | oldList = _taintedObjects; | ||
610 | _taintedObjects = new List<TaintCallback>(); | ||
611 | } | ||
612 | |||
613 | foreach (TaintCallback callback in oldList) | ||
614 | { | ||
615 | try | ||
616 | { | ||
617 | callback(); | ||
618 | } | ||
619 | catch (Exception e) | ||
620 | { | ||
621 | m_log.ErrorFormat("{0}: ProcessTaints: Exception: {1}", LogHeader, e); | ||
622 | } | ||
623 | } | ||
624 | oldList.Clear(); | ||
625 | } | ||
626 | } | ||
627 | |||
628 | #region Vehicles | ||
629 | // Make so the scene will call this prim for vehicle actions each tick. | ||
630 | // Safe to call if prim is already in the vehicle list. | ||
631 | public void AddVehiclePrim(BSPrim vehicle) | ||
632 | { | ||
633 | lock (m_vehicles) | ||
634 | { | ||
635 | if (!m_vehicles.Contains(vehicle)) | ||
636 | { | ||
637 | m_vehicles.Add(vehicle); | ||
638 | } | ||
639 | } | ||
640 | } | ||
641 | |||
642 | // Remove a prim from our list of vehicles. | ||
643 | // Safe to call if the prim is not in the vehicle list. | ||
644 | public void RemoveVehiclePrim(BSPrim vehicle) | ||
645 | { | ||
646 | lock (m_vehicles) | ||
647 | { | ||
648 | if (m_vehicles.Contains(vehicle)) | ||
649 | { | ||
650 | m_vehicles.Remove(vehicle); | ||
651 | } | ||
652 | } | ||
653 | } | ||
654 | |||
655 | // Some prims have extra vehicle actions | ||
656 | // no locking because only called when physics engine is not busy | ||
657 | private void ProcessVehicles(float timeStep) | ||
658 | { | ||
659 | foreach (BSPrim prim in m_vehicles) | ||
660 | { | ||
661 | prim.StepVehicle(timeStep); | ||
662 | } | ||
663 | } | ||
664 | #endregion Vehicles | ||
665 | |||
666 | #region Runtime settable parameters | ||
667 | public static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[] | ||
668 | { | ||
669 | new PhysParameterEntry("MeshLOD", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)"), | ||
670 | new PhysParameterEntry("SculptLOD", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)"), | ||
671 | new PhysParameterEntry("MaxSubStep", "In simulation step, maximum number of substeps"), | ||
672 | new PhysParameterEntry("FixedTimeStep", "In simulation step, seconds of one substep (1/60)"), | ||
673 | new PhysParameterEntry("MaxObjectMass", "Maximum object mass (10000.01)"), | ||
674 | |||
675 | new PhysParameterEntry("DefaultFriction", "Friction factor used on new objects"), | ||
676 | new PhysParameterEntry("DefaultDensity", "Density for new objects" ), | ||
677 | new PhysParameterEntry("DefaultRestitution", "Bouncyness of an object" ), | ||
678 | // new PhysParameterEntry("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!!)" ), | ||
679 | new PhysParameterEntry("Gravity", "Vertical force of gravity (negative means down)" ), | ||
680 | |||
681 | new PhysParameterEntry("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)" ), | ||
682 | new PhysParameterEntry("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)" ), | ||
683 | new PhysParameterEntry("DeactivationTime", "Seconds before considering an object potentially static" ), | ||
684 | new PhysParameterEntry("LinearSleepingThreshold", "Seconds to measure linear movement before considering static" ), | ||
685 | new PhysParameterEntry("AngularSleepingThreshold", "Seconds to measure angular movement before considering static" ), | ||
686 | // new PhysParameterEntry("CcdMotionThreshold", "" ), | ||
687 | // new PhysParameterEntry("CcdSweptSphereRadius", "" ), | ||
688 | |||
689 | new PhysParameterEntry("TerrainFriction", "Factor to reduce movement against terrain surface" ), | ||
690 | new PhysParameterEntry("TerrainHitFraction", "Distance to measure hit collisions" ), | ||
691 | new PhysParameterEntry("TerrainRestitution", "Bouncyness" ), | ||
692 | new PhysParameterEntry("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation." ), | ||
693 | new PhysParameterEntry("AvatarDensity", "Density of an avatar. Changed on avatar recreation." ), | ||
694 | new PhysParameterEntry("AvatarRestitution", "Bouncyness. Changed on avatar recreation." ), | ||
695 | new PhysParameterEntry("AvatarCapsuleRadius", "Radius of space around an avatar" ), | ||
696 | new PhysParameterEntry("AvatarCapsuleHeight", "Default height of space around avatar" ) | ||
697 | }; | ||
698 | |||
699 | #region IPhysicsParameters | ||
700 | // Get the list of parameters this physics engine supports | ||
701 | public PhysParameterEntry[] GetParameterList() | ||
702 | { | ||
703 | return SettableParameters; | ||
704 | } | ||
705 | |||
706 | // Set parameter on a specific or all instances. | ||
707 | // Return 'false' if not able to set the parameter. | ||
708 | // Setting the value in the m_params block will change the value the physics engine | ||
709 | // will use the next time since it's pinned and shared memory. | ||
710 | // Some of the values require calling into the physics engine to get the new | ||
711 | // value activated ('terrainFriction' for instance). | ||
712 | public bool SetPhysicsParameter(string parm, float val, uint localID) | ||
713 | { | ||
714 | bool ret = true; | ||
715 | string lparm = parm.ToLower(); | ||
716 | switch (lparm) | ||
717 | { | ||
718 | case "meshlod": m_meshLOD = (int)val; break; | ||
719 | case "sculptlod": m_sculptLOD = (int)val; break; | ||
720 | case "maxsubstep": m_maxSubSteps = (int)val; break; | ||
721 | case "fixedtimestep": m_fixedTimeStep = val; break; | ||
722 | case "maxobjectmass": m_maximumObjectMass = val; break; | ||
723 | |||
724 | case "defaultfriction": m_params[0].defaultFriction = val; break; | ||
725 | case "defaultdensity": m_params[0].defaultDensity = val; break; | ||
726 | case "defaultrestitution": m_params[0].defaultRestitution = val; break; | ||
727 | case "collisionmargin": m_params[0].collisionMargin = val; break; | ||
728 | case "gravity": m_params[0].gravity = val; TaintedUpdateParameter(lparm, PhysParameterEntry.APPLY_TO_NONE, val); break; | ||
729 | |||
730 | case "lineardamping": UpdateParameterPrims(ref m_params[0].linearDamping, lparm, localID, val); break; | ||
731 | case "angulardamping": UpdateParameterPrims(ref m_params[0].angularDamping, lparm, localID, val); break; | ||
732 | case "deactivationtime": UpdateParameterPrims(ref m_params[0].deactivationTime, lparm, localID, val); break; | ||
733 | case "linearsleepingthreshold": UpdateParameterPrims(ref m_params[0].linearSleepingThreshold, lparm, localID, val); break; | ||
734 | case "angularsleepingthreshold": UpdateParameterPrims(ref m_params[0].angularDamping, lparm, localID, val); break; | ||
735 | case "ccdmotionthreshold": UpdateParameterPrims(ref m_params[0].ccdMotionThreshold, lparm, localID, val); break; | ||
736 | case "ccdsweptsphereradius": UpdateParameterPrims(ref m_params[0].ccdSweptSphereRadius, lparm, localID, val); break; | ||
737 | |||
738 | // set a terrain physical feature and cause terrain to be recalculated | ||
739 | case "terrainfriction": m_params[0].terrainFriction = val; TaintedUpdateParameter("terrain", 0, val); break; | ||
740 | case "terrainhitfraction": m_params[0].terrainHitFraction = val; TaintedUpdateParameter("terrain", 0, val); break; | ||
741 | case "terrainrestitution": m_params[0].terrainRestitution = val; TaintedUpdateParameter("terrain", 0, val); break; | ||
742 | // set an avatar physical feature and cause avatar(s) to be recalculated | ||
743 | case "avatarfriction": UpdateParameterAvatars(ref m_params[0].avatarFriction, "avatar", localID, val); break; | ||
744 | case "avatardensity": UpdateParameterAvatars(ref m_params[0].avatarDensity, "avatar", localID, val); break; | ||
745 | case "avatarrestitution": UpdateParameterAvatars(ref m_params[0].avatarRestitution, "avatar", localID, val); break; | ||
746 | case "avatarcapsuleradius": UpdateParameterAvatars(ref m_params[0].avatarCapsuleRadius, "avatar", localID, val); break; | ||
747 | case "avatarcapsuleheight": UpdateParameterAvatars(ref m_params[0].avatarCapsuleHeight, "avatar", localID, val); break; | ||
748 | |||
749 | default: ret = false; break; | ||
750 | } | ||
751 | return ret; | ||
752 | } | ||
753 | |||
754 | // check to see if we are updating a parameter for a particular or all of the prims | ||
755 | private void UpdateParameterPrims(ref float loc, string parm, uint localID, float val) | ||
756 | { | ||
757 | List<uint> operateOn; | ||
758 | lock (m_prims) operateOn = new List<uint>(m_prims.Keys); | ||
759 | UpdateParameterSet(operateOn, ref loc, parm, localID, val); | ||
760 | } | ||
761 | |||
762 | // check to see if we are updating a parameter for a particular or all of the avatars | ||
763 | private void UpdateParameterAvatars(ref float loc, string parm, uint localID, float val) | ||
764 | { | ||
765 | List<uint> operateOn; | ||
766 | lock (m_avatars) operateOn = new List<uint>(m_avatars.Keys); | ||
767 | UpdateParameterSet(operateOn, ref loc, parm, localID, val); | ||
768 | } | ||
769 | |||
770 | // update all the localIDs specified | ||
771 | // If the local ID is APPLY_TO_NONE, just change the default value | ||
772 | // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs | ||
773 | // If the localID is a specific object, apply the parameter change to only that object | ||
774 | private void UpdateParameterSet(List<uint> lIDs, ref float defaultLoc, string parm, uint localID, float val) | ||
775 | { | ||
776 | switch (localID) | ||
777 | { | ||
778 | case PhysParameterEntry.APPLY_TO_NONE: | ||
779 | defaultLoc = val; // setting only the default value | ||
780 | break; | ||
781 | case PhysParameterEntry.APPLY_TO_ALL: | ||
782 | defaultLoc = val; // setting ALL also sets the default value | ||
783 | List<uint> objectIDs = lIDs; | ||
784 | string xparm = parm.ToLower(); | ||
785 | float xval = val; | ||
786 | TaintedObject(delegate() { | ||
787 | foreach (uint lID in objectIDs) | ||
788 | { | ||
789 | BulletSimAPI.UpdateParameter(m_worldID, lID, xparm, xval); | ||
790 | } | ||
791 | }); | ||
792 | break; | ||
793 | default: | ||
794 | // setting only one localID | ||
795 | TaintedUpdateParameter(parm, localID, val); | ||
796 | break; | ||
797 | } | ||
798 | } | ||
799 | |||
800 | // schedule the actual updating of the paramter to when the phys engine is not busy | ||
801 | private void TaintedUpdateParameter(string parm, uint localID, float val) | ||
802 | { | ||
803 | uint xlocalID = localID; | ||
804 | string xparm = parm.ToLower(); | ||
805 | float xval = val; | ||
806 | TaintedObject(delegate() { | ||
807 | BulletSimAPI.UpdateParameter(m_worldID, xlocalID, xparm, xval); | ||
808 | }); | ||
809 | } | ||
810 | |||
811 | // Get parameter. | ||
812 | // Return 'false' if not able to get the parameter. | ||
813 | public bool GetPhysicsParameter(string parm, out float value) | ||
814 | { | ||
815 | float val = 0f; | ||
816 | bool ret = true; | ||
817 | switch (parm.ToLower()) | ||
818 | { | ||
819 | case "meshlod": val = (float)m_meshLOD; break; | ||
820 | case "sculptlod": val = (float)m_sculptLOD; break; | ||
821 | case "maxsubstep": val = (float)m_maxSubSteps; break; | ||
822 | case "fixedtimestep": val = m_fixedTimeStep; break; | ||
823 | case "maxobjectmass": val = m_maximumObjectMass; break; | ||
824 | |||
825 | case "defaultfriction": val = m_params[0].defaultFriction; break; | ||
826 | case "defaultdensity": val = m_params[0].defaultDensity; break; | ||
827 | case "defaultrestitution": val = m_params[0].defaultRestitution; break; | ||
828 | case "collisionmargin": val = m_params[0].collisionMargin; break; | ||
829 | case "gravity": val = m_params[0].gravity; break; | ||
830 | |||
831 | case "lineardamping": val = m_params[0].linearDamping; break; | ||
832 | case "angulardamping": val = m_params[0].angularDamping; break; | ||
833 | case "deactivationtime": val = m_params[0].deactivationTime; break; | ||
834 | case "linearsleepingthreshold": val = m_params[0].linearSleepingThreshold; break; | ||
835 | case "angularsleepingthreshold": val = m_params[0].angularDamping; break; | ||
836 | case "ccdmotionthreshold": val = m_params[0].ccdMotionThreshold; break; | ||
837 | case "ccdsweptsphereradius": val = m_params[0].ccdSweptSphereRadius; break; | ||
838 | |||
839 | case "terrainfriction": val = m_params[0].terrainFriction; break; | ||
840 | case "terrainhitfraction": val = m_params[0].terrainHitFraction; break; | ||
841 | case "terrainrestitution": val = m_params[0].terrainRestitution; break; | ||
842 | |||
843 | case "avatarfriction": val = m_params[0].avatarFriction; break; | ||
844 | case "avatardensity": val = m_params[0].avatarDensity; break; | ||
845 | case "avatarrestitution": val = m_params[0].avatarRestitution; break; | ||
846 | case "avatarcapsuleradius": val = m_params[0].avatarCapsuleRadius; break; | ||
847 | case "avatarcapsuleheight": val = m_params[0].avatarCapsuleHeight; break; | ||
848 | default: ret = false; break; | ||
849 | |||
850 | } | ||
851 | value = val; | ||
852 | return ret; | ||
853 | } | ||
854 | |||
855 | #endregion IPhysicsParameters | ||
856 | |||
857 | #endregion Runtime settable parameters | ||
858 | |||
859 | } | ||
860 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs new file mode 100644 index 0000000..a610c8d --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs | |||
@@ -0,0 +1,257 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyrightD | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | using System; | ||
28 | using System.Runtime.InteropServices; | ||
29 | using System.Security; | ||
30 | using System.Text; | ||
31 | using OpenMetaverse; | ||
32 | |||
33 | namespace OpenSim.Region.Physics.BulletSPlugin { | ||
34 | |||
35 | [StructLayout(LayoutKind.Sequential)] | ||
36 | public struct ConvexHull | ||
37 | { | ||
38 | Vector3 Offset; | ||
39 | int VertexCount; | ||
40 | Vector3[] Vertices; | ||
41 | } | ||
42 | [StructLayout(LayoutKind.Sequential)] | ||
43 | public struct ShapeData | ||
44 | { | ||
45 | public enum PhysicsShapeType | ||
46 | { | ||
47 | SHAPE_AVATAR = 0, | ||
48 | SHAPE_BOX = 1, | ||
49 | SHAPE_CONE = 2, | ||
50 | SHAPE_CYLINDER = 3, | ||
51 | SHAPE_SPHERE = 4, | ||
52 | SHAPE_MESH = 5, | ||
53 | SHAPE_HULL = 6 | ||
54 | }; | ||
55 | public uint ID; | ||
56 | public PhysicsShapeType Type; | ||
57 | public Vector3 Position; | ||
58 | public Quaternion Rotation; | ||
59 | public Vector3 Velocity; | ||
60 | public Vector3 Scale; | ||
61 | public float Mass; | ||
62 | public float Buoyancy; | ||
63 | public System.UInt64 HullKey; | ||
64 | public System.UInt64 MeshKey; | ||
65 | public float Friction; | ||
66 | public float Restitution; | ||
67 | public int Collidable; | ||
68 | public int Static; // true if a static object. Otherwise gravity, etc. | ||
69 | |||
70 | // note that bools are passed as ints since bool size changes by language and architecture | ||
71 | public const int numericTrue = 1; | ||
72 | public const int numericFalse = 0; | ||
73 | } | ||
74 | [StructLayout(LayoutKind.Sequential)] | ||
75 | public struct SweepHit | ||
76 | { | ||
77 | public uint ID; | ||
78 | public float Fraction; | ||
79 | public Vector3 Normal; | ||
80 | public Vector3 Point; | ||
81 | } | ||
82 | [StructLayout(LayoutKind.Sequential)] | ||
83 | public struct RaycastHit | ||
84 | { | ||
85 | public uint ID; | ||
86 | public float Fraction; | ||
87 | public Vector3 Normal; | ||
88 | } | ||
89 | [StructLayout(LayoutKind.Sequential)] | ||
90 | public struct CollisionDesc | ||
91 | { | ||
92 | public uint aID; | ||
93 | public uint bID; | ||
94 | public Vector3 point; | ||
95 | public Vector3 normal; | ||
96 | } | ||
97 | [StructLayout(LayoutKind.Sequential)] | ||
98 | public struct EntityProperties | ||
99 | { | ||
100 | public uint ID; | ||
101 | public Vector3 Position; | ||
102 | public Quaternion Rotation; | ||
103 | public Vector3 Velocity; | ||
104 | public Vector3 Acceleration; | ||
105 | public Vector3 RotationalVelocity; | ||
106 | } | ||
107 | |||
108 | // Format of this structure must match the definition in the C++ code | ||
109 | [StructLayout(LayoutKind.Sequential)] | ||
110 | public struct ConfigurationParameters | ||
111 | { | ||
112 | public float defaultFriction; | ||
113 | public float defaultDensity; | ||
114 | public float defaultRestitution; | ||
115 | public float collisionMargin; | ||
116 | public float gravity; | ||
117 | |||
118 | public float linearDamping; | ||
119 | public float angularDamping; | ||
120 | public float deactivationTime; | ||
121 | public float linearSleepingThreshold; | ||
122 | public float angularSleepingThreshold; | ||
123 | public float ccdMotionThreshold; | ||
124 | public float ccdSweptSphereRadius; | ||
125 | |||
126 | public float terrainFriction; | ||
127 | public float terrainHitFraction; | ||
128 | public float terrainRestitution; | ||
129 | public float avatarFriction; | ||
130 | public float avatarDensity; | ||
131 | public float avatarRestitution; | ||
132 | public float avatarCapsuleRadius; | ||
133 | public float avatarCapsuleHeight; | ||
134 | |||
135 | public const float numericTrue = 1f; | ||
136 | public const float numericFalse = 0f; | ||
137 | } | ||
138 | |||
139 | static class BulletSimAPI { | ||
140 | |||
141 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
142 | [return: MarshalAs(UnmanagedType.LPStr)] | ||
143 | public static extern string GetVersion(); | ||
144 | |||
145 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
146 | public static extern uint Initialize(Vector3 maxPosition, IntPtr parms, | ||
147 | int maxCollisions, IntPtr collisionArray, | ||
148 | int maxUpdates, IntPtr updateArray); | ||
149 | |||
150 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
151 | public static extern bool UpdateParameter(uint worldID, uint localID, | ||
152 | [MarshalAs(UnmanagedType.LPStr)]string paramCode, float value); | ||
153 | |||
154 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
155 | public static extern void SetHeightmap(uint worldID, [MarshalAs(UnmanagedType.LPArray)] float[] heightMap); | ||
156 | |||
157 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
158 | public static extern void Shutdown(uint worldID); | ||
159 | |||
160 | |||
161 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
162 | public static extern int PhysicsStep(uint worldID, float timeStep, int maxSubSteps, float fixedTimeStep, | ||
163 | out int updatedEntityCount, | ||
164 | out IntPtr updatedEntitiesPtr, | ||
165 | out int collidersCount, | ||
166 | out IntPtr collidersPtr); | ||
167 | |||
168 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
169 | public static extern bool CreateHull(uint worldID, System.UInt64 meshKey, | ||
170 | int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls | ||
171 | ); | ||
172 | |||
173 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
174 | public static extern bool CreateMesh(uint worldID, System.UInt64 meshKey, | ||
175 | int indexCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices, | ||
176 | int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices | ||
177 | ); | ||
178 | |||
179 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
180 | public static extern bool DestroyHull(uint worldID, System.UInt64 meshKey); | ||
181 | |||
182 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
183 | public static extern bool DestroyMesh(uint worldID, System.UInt64 meshKey); | ||
184 | |||
185 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
186 | public static extern bool CreateObject(uint worldID, ShapeData shapeData); | ||
187 | |||
188 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
189 | public static extern void CreateLinkset(uint worldID, int objectCount, ShapeData[] shapeDatas); | ||
190 | |||
191 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
192 | public static extern void AddConstraint(uint worldID, uint id1, uint id2, | ||
193 | Vector3 frame1, Quaternion frame1rot, | ||
194 | Vector3 frame2, Quaternion frame2rot, | ||
195 | Vector3 lowLinear, Vector3 hiLinear, Vector3 lowAngular, Vector3 hiAngular); | ||
196 | |||
197 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
198 | public static extern bool RemoveConstraintByID(uint worldID, uint id1); | ||
199 | |||
200 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
201 | public static extern bool RemoveConstraint(uint worldID, uint id1, uint id2); | ||
202 | |||
203 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
204 | public static extern Vector3 GetObjectPosition(uint WorldID, uint id); | ||
205 | |||
206 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
207 | public static extern bool SetObjectTranslation(uint worldID, uint id, Vector3 position, Quaternion rotation); | ||
208 | |||
209 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
210 | public static extern bool SetObjectVelocity(uint worldID, uint id, Vector3 velocity); | ||
211 | |||
212 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
213 | public static extern bool SetObjectAngularVelocity(uint worldID, uint id, Vector3 angularVelocity); | ||
214 | |||
215 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
216 | public static extern bool SetObjectForce(uint worldID, uint id, Vector3 force); | ||
217 | |||
218 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
219 | public static extern bool SetObjectScaleMass(uint worldID, uint id, Vector3 scale, float mass, bool isDynamic); | ||
220 | |||
221 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
222 | public static extern bool SetObjectCollidable(uint worldID, uint id, bool phantom); | ||
223 | |||
224 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
225 | public static extern bool SetObjectDynamic(uint worldID, uint id, bool isDynamic, float mass); | ||
226 | |||
227 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
228 | public static extern bool SetObjectGhost(uint worldID, uint id, bool ghostly); | ||
229 | |||
230 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
231 | public static extern bool SetObjectProperties(uint worldID, uint id, bool isStatic, bool isSolid, bool genCollisions, float mass); | ||
232 | |||
233 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
234 | public static extern bool SetObjectBuoyancy(uint worldID, uint id, float buoyancy); | ||
235 | |||
236 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
237 | public static extern bool HasObject(uint worldID, uint id); | ||
238 | |||
239 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
240 | public static extern bool DestroyObject(uint worldID, uint id); | ||
241 | |||
242 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
243 | public static extern SweepHit ConvexSweepTest(uint worldID, uint id, Vector3 to, float extraMargin); | ||
244 | |||
245 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
246 | public static extern RaycastHit RayTest(uint worldID, uint id, Vector3 from, Vector3 to); | ||
247 | |||
248 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
249 | public static extern Vector3 RecoverFromPenetration(uint worldID, uint id); | ||
250 | |||
251 | // Log a debug message | ||
252 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] | ||
253 | public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg); | ||
254 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
255 | public static extern void SetDebugLogCallback(DebugLogCallback callback); | ||
256 | } | ||
257 | } | ||
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/CTri.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/CTri.cs new file mode 100644 index 0000000..4d84c44 --- /dev/null +++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/CTri.cs | |||
@@ -0,0 +1,341 @@ | |||
1 | /* The MIT License | ||
2 | * | ||
3 | * Copyright (c) 2010 Intel Corporation. | ||
4 | * All rights reserved. | ||
5 | * | ||
6 | * Based on the convexdecomposition library from | ||
7 | * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax. | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
10 | * of this software and associated documentation files (the "Software"), to deal | ||
11 | * in the Software without restriction, including without limitation the rights | ||
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | * copies of the Software, and to permit persons to whom the Software is | ||
14 | * furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
25 | * THE SOFTWARE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | |||
31 | namespace OpenSim.Region.Physics.ConvexDecompositionDotNet | ||
32 | { | ||
33 | public class Wpoint | ||
34 | { | ||
35 | public float3 mPoint; | ||
36 | public float mWeight; | ||
37 | |||
38 | public Wpoint(float3 p, float w) | ||
39 | { | ||
40 | mPoint = p; | ||
41 | mWeight = w; | ||
42 | } | ||
43 | } | ||
44 | |||
45 | public class CTri | ||
46 | { | ||
47 | private const int WSCALE = 4; | ||
48 | |||
49 | public float3 mP1; | ||
50 | public float3 mP2; | ||
51 | public float3 mP3; | ||
52 | public float3 mNear1; | ||
53 | public float3 mNear2; | ||
54 | public float3 mNear3; | ||
55 | public float3 mNormal; | ||
56 | public float mPlaneD; | ||
57 | public float mConcavity; | ||
58 | public float mC1; | ||
59 | public float mC2; | ||
60 | public float mC3; | ||
61 | public int mI1; | ||
62 | public int mI2; | ||
63 | public int mI3; | ||
64 | public int mProcessed; // already been added... | ||
65 | |||
66 | public CTri(float3 p1, float3 p2, float3 p3, int i1, int i2, int i3) | ||
67 | { | ||
68 | mProcessed = 0; | ||
69 | mI1 = i1; | ||
70 | mI2 = i2; | ||
71 | mI3 = i3; | ||
72 | |||
73 | mP1 = new float3(p1); | ||
74 | mP2 = new float3(p2); | ||
75 | mP3 = new float3(p3); | ||
76 | |||
77 | mNear1 = new float3(); | ||
78 | mNear2 = new float3(); | ||
79 | mNear3 = new float3(); | ||
80 | |||
81 | mNormal = new float3(); | ||
82 | mPlaneD = mNormal.ComputePlane(mP1, mP2, mP3); | ||
83 | } | ||
84 | |||
85 | public float Facing(CTri t) | ||
86 | { | ||
87 | return float3.dot(mNormal, t.mNormal); | ||
88 | } | ||
89 | |||
90 | public bool clip(float3 start, ref float3 end) | ||
91 | { | ||
92 | float3 sect = new float3(); | ||
93 | bool hit = lineIntersectsTriangle(start, end, mP1, mP2, mP3, ref sect); | ||
94 | |||
95 | if (hit) | ||
96 | end = sect; | ||
97 | return hit; | ||
98 | } | ||
99 | |||
100 | public bool Concave(float3 p, ref float distance, ref float3 n) | ||
101 | { | ||
102 | n.NearestPointInTriangle(p, mP1, mP2, mP3); | ||
103 | distance = p.Distance(n); | ||
104 | return true; | ||
105 | } | ||
106 | |||
107 | public void addTri(int[] indices, int i1, int i2, int i3, ref int tcount) | ||
108 | { | ||
109 | indices[tcount * 3 + 0] = i1; | ||
110 | indices[tcount * 3 + 1] = i2; | ||
111 | indices[tcount * 3 + 2] = i3; | ||
112 | tcount++; | ||
113 | } | ||
114 | |||
115 | public float getVolume() | ||
116 | { | ||
117 | int[] indices = new int[8 * 3]; | ||
118 | |||
119 | int tcount = 0; | ||
120 | |||
121 | addTri(indices, 0, 1, 2, ref tcount); | ||
122 | addTri(indices, 3, 4, 5, ref tcount); | ||
123 | |||
124 | addTri(indices, 0, 3, 4, ref tcount); | ||
125 | addTri(indices, 0, 4, 1, ref tcount); | ||
126 | |||
127 | addTri(indices, 1, 4, 5, ref tcount); | ||
128 | addTri(indices, 1, 5, 2, ref tcount); | ||
129 | |||
130 | addTri(indices, 0, 3, 5, ref tcount); | ||
131 | addTri(indices, 0, 5, 2, ref tcount); | ||
132 | |||
133 | List<float3> vertices = new List<float3> { mP1, mP2, mP3, mNear1, mNear2, mNear3 }; | ||
134 | List<int> indexList = new List<int>(indices); | ||
135 | |||
136 | float v = Concavity.computeMeshVolume(vertices, indexList); | ||
137 | return v; | ||
138 | } | ||
139 | |||
140 | public float raySect(float3 p, float3 dir, ref float3 sect) | ||
141 | { | ||
142 | float4 plane = new float4(); | ||
143 | |||
144 | plane.x = mNormal.x; | ||
145 | plane.y = mNormal.y; | ||
146 | plane.z = mNormal.z; | ||
147 | plane.w = mPlaneD; | ||
148 | |||
149 | float3 dest = p + dir * 100000f; | ||
150 | |||
151 | intersect(p, dest, ref sect, plane); | ||
152 | |||
153 | return sect.Distance(p); // return the intersection distance | ||
154 | } | ||
155 | |||
156 | public float planeDistance(float3 p) | ||
157 | { | ||
158 | float4 plane = new float4(); | ||
159 | |||
160 | plane.x = mNormal.x; | ||
161 | plane.y = mNormal.y; | ||
162 | plane.z = mNormal.z; | ||
163 | plane.w = mPlaneD; | ||
164 | |||
165 | return DistToPt(p, plane); | ||
166 | } | ||
167 | |||
168 | public bool samePlane(CTri t) | ||
169 | { | ||
170 | const float THRESH = 0.001f; | ||
171 | float dd = Math.Abs(t.mPlaneD - mPlaneD); | ||
172 | if (dd > THRESH) | ||
173 | return false; | ||
174 | dd = Math.Abs(t.mNormal.x - mNormal.x); | ||
175 | if (dd > THRESH) | ||
176 | return false; | ||
177 | dd = Math.Abs(t.mNormal.y - mNormal.y); | ||
178 | if (dd > THRESH) | ||
179 | return false; | ||
180 | dd = Math.Abs(t.mNormal.z - mNormal.z); | ||
181 | if (dd > THRESH) | ||
182 | return false; | ||
183 | return true; | ||
184 | } | ||
185 | |||
186 | public bool hasIndex(int i) | ||
187 | { | ||
188 | if (i == mI1 || i == mI2 || i == mI3) | ||
189 | return true; | ||
190 | return false; | ||
191 | } | ||
192 | |||
193 | public bool sharesEdge(CTri t) | ||
194 | { | ||
195 | bool ret = false; | ||
196 | uint count = 0; | ||
197 | |||
198 | if (t.hasIndex(mI1)) | ||
199 | count++; | ||
200 | if (t.hasIndex(mI2)) | ||
201 | count++; | ||
202 | if (t.hasIndex(mI3)) | ||
203 | count++; | ||
204 | |||
205 | if (count >= 2) | ||
206 | ret = true; | ||
207 | |||
208 | return ret; | ||
209 | } | ||
210 | |||
211 | public float area() | ||
212 | { | ||
213 | float a = mConcavity * mP1.Area(mP2, mP3); | ||
214 | return a; | ||
215 | } | ||
216 | |||
217 | public void addWeighted(List<Wpoint> list) | ||
218 | { | ||
219 | Wpoint p1 = new Wpoint(mP1, mC1); | ||
220 | Wpoint p2 = new Wpoint(mP2, mC2); | ||
221 | Wpoint p3 = new Wpoint(mP3, mC3); | ||
222 | |||
223 | float3 d1 = mNear1 - mP1; | ||
224 | float3 d2 = mNear2 - mP2; | ||
225 | float3 d3 = mNear3 - mP3; | ||
226 | |||
227 | d1 *= WSCALE; | ||
228 | d2 *= WSCALE; | ||
229 | d3 *= WSCALE; | ||
230 | |||
231 | d1 = d1 + mP1; | ||
232 | d2 = d2 + mP2; | ||
233 | d3 = d3 + mP3; | ||
234 | |||
235 | Wpoint p4 = new Wpoint(d1, mC1); | ||
236 | Wpoint p5 = new Wpoint(d2, mC2); | ||
237 | Wpoint p6 = new Wpoint(d3, mC3); | ||
238 | |||
239 | list.Add(p1); | ||
240 | list.Add(p2); | ||
241 | list.Add(p3); | ||
242 | |||
243 | list.Add(p4); | ||
244 | list.Add(p5); | ||
245 | list.Add(p6); | ||
246 | } | ||
247 | |||
248 | private static float DistToPt(float3 p, float4 plane) | ||
249 | { | ||
250 | float x = p.x; | ||
251 | float y = p.y; | ||
252 | float z = p.z; | ||
253 | float d = x*plane.x + y*plane.y + z*plane.z + plane.w; | ||
254 | return d; | ||
255 | } | ||
256 | |||
257 | private static void intersect(float3 p1, float3 p2, ref float3 split, float4 plane) | ||
258 | { | ||
259 | float dp1 = DistToPt(p1, plane); | ||
260 | |||
261 | float3 dir = new float3(); | ||
262 | dir.x = p2[0] - p1[0]; | ||
263 | dir.y = p2[1] - p1[1]; | ||
264 | dir.z = p2[2] - p1[2]; | ||
265 | |||
266 | float dot1 = dir[0] * plane[0] + dir[1] * plane[1] + dir[2] * plane[2]; | ||
267 | float dot2 = dp1 - plane[3]; | ||
268 | |||
269 | float t = -(plane[3] + dot2) / dot1; | ||
270 | |||
271 | split.x = (dir[0] * t) + p1[0]; | ||
272 | split.y = (dir[1] * t) + p1[1]; | ||
273 | split.z = (dir[2] * t) + p1[2]; | ||
274 | } | ||
275 | |||
276 | private static bool rayIntersectsTriangle(float3 p, float3 d, float3 v0, float3 v1, float3 v2, out float t) | ||
277 | { | ||
278 | t = 0f; | ||
279 | |||
280 | float3 e1, e2, h, s, q; | ||
281 | float a, f, u, v; | ||
282 | |||
283 | e1 = v1 - v0; | ||
284 | e2 = v2 - v0; | ||
285 | h = float3.cross(d, e2); | ||
286 | a = float3.dot(e1, h); | ||
287 | |||
288 | if (a > -0.00001f && a < 0.00001f) | ||
289 | return false; | ||
290 | |||
291 | f = 1f / a; | ||
292 | s = p - v0; | ||
293 | u = f * float3.dot(s, h); | ||
294 | |||
295 | if (u < 0.0f || u > 1.0f) | ||
296 | return false; | ||
297 | |||
298 | q = float3.cross(s, e1); | ||
299 | v = f * float3.dot(d, q); | ||
300 | if (v < 0.0f || u + v > 1.0f) | ||
301 | return false; | ||
302 | |||
303 | // at this stage we can compute t to find out where | ||
304 | // the intersection point is on the line | ||
305 | t = f * float3.dot(e2, q); | ||
306 | if (t > 0f) // ray intersection | ||
307 | return true; | ||
308 | else // this means that there is a line intersection but not a ray intersection | ||
309 | return false; | ||
310 | } | ||
311 | |||
312 | private static bool lineIntersectsTriangle(float3 rayStart, float3 rayEnd, float3 p1, float3 p2, float3 p3, ref float3 sect) | ||
313 | { | ||
314 | float3 dir = rayEnd - rayStart; | ||
315 | |||
316 | float d = (float)Math.Sqrt(dir[0] * dir[0] + dir[1] * dir[1] + dir[2] * dir[2]); | ||
317 | float r = 1.0f / d; | ||
318 | |||
319 | dir *= r; | ||
320 | |||
321 | float t; | ||
322 | bool ret = rayIntersectsTriangle(rayStart, dir, p1, p2, p3, out t); | ||
323 | |||
324 | if (ret) | ||
325 | { | ||
326 | if (t > d) | ||
327 | { | ||
328 | sect.x = rayStart.x + dir.x * t; | ||
329 | sect.y = rayStart.y + dir.y * t; | ||
330 | sect.z = rayStart.z + dir.z * t; | ||
331 | } | ||
332 | else | ||
333 | { | ||
334 | ret = false; | ||
335 | } | ||
336 | } | ||
337 | |||
338 | return ret; | ||
339 | } | ||
340 | } | ||
341 | } | ||
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/Concavity.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/Concavity.cs new file mode 100644 index 0000000..cc6383a --- /dev/null +++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/Concavity.cs | |||
@@ -0,0 +1,233 @@ | |||
1 | /* The MIT License | ||
2 | * | ||
3 | * Copyright (c) 2010 Intel Corporation. | ||
4 | * All rights reserved. | ||
5 | * | ||
6 | * Based on the convexdecomposition library from | ||
7 | * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax. | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
10 | * of this software and associated documentation files (the "Software"), to deal | ||
11 | * in the Software without restriction, including without limitation the rights | ||
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | * copies of the Software, and to permit persons to whom the Software is | ||
14 | * furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
25 | * THE SOFTWARE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Text; | ||
31 | |||
32 | namespace OpenSim.Region.Physics.ConvexDecompositionDotNet | ||
33 | { | ||
34 | public static class Concavity | ||
35 | { | ||
36 | // compute's how 'concave' this object is and returns the total volume of the | ||
37 | // convex hull as well as the volume of the 'concavity' which was found. | ||
38 | public static float computeConcavity(List<float3> vertices, List<int> indices, ref float4 plane, ref float volume) | ||
39 | { | ||
40 | float cret = 0f; | ||
41 | volume = 1f; | ||
42 | |||
43 | HullResult result = new HullResult(); | ||
44 | HullDesc desc = new HullDesc(); | ||
45 | |||
46 | desc.MaxFaces = 256; | ||
47 | desc.MaxVertices = 256; | ||
48 | desc.SetHullFlag(HullFlag.QF_TRIANGLES); | ||
49 | desc.Vertices = vertices; | ||
50 | |||
51 | HullError ret = HullUtils.CreateConvexHull(desc, ref result); | ||
52 | |||
53 | if (ret == HullError.QE_OK) | ||
54 | { | ||
55 | volume = computeMeshVolume2(result.OutputVertices, result.Indices); | ||
56 | |||
57 | // ok..now..for each triangle on the original mesh.. | ||
58 | // we extrude the points to the nearest point on the hull. | ||
59 | List<CTri> tris = new List<CTri>(); | ||
60 | |||
61 | for (int i = 0; i < result.Indices.Count / 3; i++) | ||
62 | { | ||
63 | int i1 = result.Indices[i * 3 + 0]; | ||
64 | int i2 = result.Indices[i * 3 + 1]; | ||
65 | int i3 = result.Indices[i * 3 + 2]; | ||
66 | |||
67 | float3 p1 = result.OutputVertices[i1]; | ||
68 | float3 p2 = result.OutputVertices[i2]; | ||
69 | float3 p3 = result.OutputVertices[i3]; | ||
70 | |||
71 | CTri t = new CTri(p1, p2, p3, i1, i2, i3); | ||
72 | tris.Add(t); | ||
73 | } | ||
74 | |||
75 | // we have not pre-computed the plane equation for each triangle in the convex hull.. | ||
76 | float totalVolume = 0; | ||
77 | |||
78 | List<CTri> ftris = new List<CTri>(); // 'feature' triangles. | ||
79 | List<CTri> input_mesh = new List<CTri>(); | ||
80 | |||
81 | for (int i = 0; i < indices.Count / 3; i++) | ||
82 | { | ||
83 | int i1 = indices[i * 3 + 0]; | ||
84 | int i2 = indices[i * 3 + 1]; | ||
85 | int i3 = indices[i * 3 + 2]; | ||
86 | |||
87 | float3 p1 = vertices[i1]; | ||
88 | float3 p2 = vertices[i2]; | ||
89 | float3 p3 = vertices[i3]; | ||
90 | |||
91 | CTri t = new CTri(p1, p2, p3, i1, i2, i3); | ||
92 | input_mesh.Add(t); | ||
93 | } | ||
94 | |||
95 | for (int i = 0; i < indices.Count / 3; i++) | ||
96 | { | ||
97 | int i1 = indices[i * 3 + 0]; | ||
98 | int i2 = indices[i * 3 + 1]; | ||
99 | int i3 = indices[i * 3 + 2]; | ||
100 | |||
101 | float3 p1 = vertices[i1]; | ||
102 | float3 p2 = vertices[i2]; | ||
103 | float3 p3 = vertices[i3]; | ||
104 | |||
105 | CTri t = new CTri(p1, p2, p3, i1, i2, i3); | ||
106 | |||
107 | featureMatch(t, tris, input_mesh); | ||
108 | |||
109 | if (t.mConcavity > 0.05f) | ||
110 | { | ||
111 | float v = t.getVolume(); | ||
112 | totalVolume += v; | ||
113 | ftris.Add(t); | ||
114 | } | ||
115 | } | ||
116 | |||
117 | SplitPlane.computeSplitPlane(vertices, indices, ref plane); | ||
118 | cret = totalVolume; | ||
119 | } | ||
120 | |||
121 | return cret; | ||
122 | } | ||
123 | |||
124 | public static bool featureMatch(CTri m, List<CTri> tris, List<CTri> input_mesh) | ||
125 | { | ||
126 | bool ret = false; | ||
127 | float neardot = 0.707f; | ||
128 | m.mConcavity = 0; | ||
129 | |||
130 | for (int i = 0; i < tris.Count; i++) | ||
131 | { | ||
132 | CTri t = tris[i]; | ||
133 | |||
134 | if (t.samePlane(m)) | ||
135 | { | ||
136 | ret = false; | ||
137 | break; | ||
138 | } | ||
139 | |||
140 | float dot = float3.dot(t.mNormal, m.mNormal); | ||
141 | |||
142 | if (dot > neardot) | ||
143 | { | ||
144 | float d1 = t.planeDistance(m.mP1); | ||
145 | float d2 = t.planeDistance(m.mP2); | ||
146 | float d3 = t.planeDistance(m.mP3); | ||
147 | |||
148 | if (d1 > 0.001f || d2 > 0.001f || d3 > 0.001f) // can't be near coplaner! | ||
149 | { | ||
150 | neardot = dot; | ||
151 | |||
152 | t.raySect(m.mP1, m.mNormal, ref m.mNear1); | ||
153 | t.raySect(m.mP2, m.mNormal, ref m.mNear2); | ||
154 | t.raySect(m.mP3, m.mNormal, ref m.mNear3); | ||
155 | |||
156 | ret = true; | ||
157 | } | ||
158 | } | ||
159 | } | ||
160 | |||
161 | if (ret) | ||
162 | { | ||
163 | m.mC1 = m.mP1.Distance(m.mNear1); | ||
164 | m.mC2 = m.mP2.Distance(m.mNear2); | ||
165 | m.mC3 = m.mP3.Distance(m.mNear3); | ||
166 | |||
167 | m.mConcavity = m.mC1; | ||
168 | |||
169 | if (m.mC2 > m.mConcavity) | ||
170 | m.mConcavity = m.mC2; | ||
171 | if (m.mC3 > m.mConcavity) | ||
172 | m.mConcavity = m.mC3; | ||
173 | } | ||
174 | |||
175 | return ret; | ||
176 | } | ||
177 | |||
178 | private static float det(float3 p1, float3 p2, float3 p3) | ||
179 | { | ||
180 | return p1.x * p2.y * p3.z + p2.x * p3.y * p1.z + p3.x * p1.y * p2.z - p1.x * p3.y * p2.z - p2.x * p1.y * p3.z - p3.x * p2.y * p1.z; | ||
181 | } | ||
182 | |||
183 | public static float computeMeshVolume(List<float3> vertices, List<int> indices) | ||
184 | { | ||
185 | float volume = 0f; | ||
186 | |||
187 | for (int i = 0; i < indices.Count / 3; i++) | ||
188 | { | ||
189 | float3 p1 = vertices[indices[i * 3 + 0]]; | ||
190 | float3 p2 = vertices[indices[i * 3 + 1]]; | ||
191 | float3 p3 = vertices[indices[i * 3 + 2]]; | ||
192 | |||
193 | volume += det(p1, p2, p3); // compute the volume of the tetrahedran relative to the origin. | ||
194 | } | ||
195 | |||
196 | volume *= (1.0f / 6.0f); | ||
197 | if (volume < 0f) | ||
198 | return -volume; | ||
199 | return volume; | ||
200 | } | ||
201 | |||
202 | public static float computeMeshVolume2(List<float3> vertices, List<int> indices) | ||
203 | { | ||
204 | float volume = 0f; | ||
205 | |||
206 | float3 p0 = vertices[0]; | ||
207 | for (int i = 0; i < indices.Count / 3; i++) | ||
208 | { | ||
209 | float3 p1 = vertices[indices[i * 3 + 0]]; | ||
210 | float3 p2 = vertices[indices[i * 3 + 1]]; | ||
211 | float3 p3 = vertices[indices[i * 3 + 2]]; | ||
212 | |||
213 | volume += tetVolume(p0, p1, p2, p3); // compute the volume of the tetrahedron relative to the root vertice | ||
214 | } | ||
215 | |||
216 | return volume * (1.0f / 6.0f); | ||
217 | } | ||
218 | |||
219 | private static float tetVolume(float3 p0, float3 p1, float3 p2, float3 p3) | ||
220 | { | ||
221 | float3 a = p1 - p0; | ||
222 | float3 b = p2 - p0; | ||
223 | float3 c = p3 - p0; | ||
224 | |||
225 | float3 cross = float3.cross(b, c); | ||
226 | float volume = float3.dot(a, cross); | ||
227 | |||
228 | if (volume < 0f) | ||
229 | return -volume; | ||
230 | return volume; | ||
231 | } | ||
232 | } | ||
233 | } | ||
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexBuilder.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexBuilder.cs new file mode 100644 index 0000000..dfaede1 --- /dev/null +++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexBuilder.cs | |||
@@ -0,0 +1,411 @@ | |||
1 | /* The MIT License | ||
2 | * | ||
3 | * Copyright (c) 2010 Intel Corporation. | ||
4 | * All rights reserved. | ||
5 | * | ||
6 | * Based on the convexdecomposition library from | ||
7 | * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax. | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
10 | * of this software and associated documentation files (the "Software"), to deal | ||
11 | * in the Software without restriction, including without limitation the rights | ||
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | * copies of the Software, and to permit persons to whom the Software is | ||
14 | * furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
25 | * THE SOFTWARE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Diagnostics; | ||
31 | |||
32 | namespace OpenSim.Region.Physics.ConvexDecompositionDotNet | ||
33 | { | ||
34 | public class DecompDesc | ||
35 | { | ||
36 | public List<float3> mVertices; | ||
37 | public List<int> mIndices; | ||
38 | |||
39 | // options | ||
40 | public uint mDepth; // depth to split, a maximum of 10, generally not over 7. | ||
41 | public float mCpercent; // the concavity threshold percentage. 0=20 is reasonable. | ||
42 | public float mPpercent; // the percentage volume conservation threshold to collapse hulls. 0-30 is reasonable. | ||
43 | |||
44 | // hull output limits. | ||
45 | public uint mMaxVertices; // maximum number of vertices in the output hull. Recommended 32 or less. | ||
46 | public float mSkinWidth; // a skin width to apply to the output hulls. | ||
47 | |||
48 | public ConvexDecompositionCallback mCallback; // the interface to receive back the results. | ||
49 | |||
50 | public DecompDesc() | ||
51 | { | ||
52 | mDepth = 5; | ||
53 | mCpercent = 5; | ||
54 | mPpercent = 5; | ||
55 | mMaxVertices = 32; | ||
56 | } | ||
57 | } | ||
58 | |||
59 | public class CHull | ||
60 | { | ||
61 | public float[] mMin = new float[3]; | ||
62 | public float[] mMax = new float[3]; | ||
63 | public float mVolume; | ||
64 | public float mDiagonal; | ||
65 | public ConvexResult mResult; | ||
66 | |||
67 | public CHull(ConvexResult result) | ||
68 | { | ||
69 | mResult = new ConvexResult(result); | ||
70 | mVolume = Concavity.computeMeshVolume(result.HullVertices, result.HullIndices); | ||
71 | |||
72 | mDiagonal = getBoundingRegion(result.HullVertices, mMin, mMax); | ||
73 | |||
74 | float dx = mMax[0] - mMin[0]; | ||
75 | float dy = mMax[1] - mMin[1]; | ||
76 | float dz = mMax[2] - mMin[2]; | ||
77 | |||
78 | dx *= 0.1f; // inflate 1/10th on each edge | ||
79 | dy *= 0.1f; // inflate 1/10th on each edge | ||
80 | dz *= 0.1f; // inflate 1/10th on each edge | ||
81 | |||
82 | mMin[0] -= dx; | ||
83 | mMin[1] -= dy; | ||
84 | mMin[2] -= dz; | ||
85 | |||
86 | mMax[0] += dx; | ||
87 | mMax[1] += dy; | ||
88 | mMax[2] += dz; | ||
89 | } | ||
90 | |||
91 | public void Dispose() | ||
92 | { | ||
93 | mResult = null; | ||
94 | } | ||
95 | |||
96 | public bool overlap(CHull h) | ||
97 | { | ||
98 | return overlapAABB(mMin, mMax, h.mMin, h.mMax); | ||
99 | } | ||
100 | |||
101 | // returns the d1Giagonal distance | ||
102 | private static float getBoundingRegion(List<float3> points, float[] bmin, float[] bmax) | ||
103 | { | ||
104 | float3 first = points[0]; | ||
105 | |||
106 | bmin[0] = first.x; | ||
107 | bmin[1] = first.y; | ||
108 | bmin[2] = first.z; | ||
109 | |||
110 | bmax[0] = first.x; | ||
111 | bmax[1] = first.y; | ||
112 | bmax[2] = first.z; | ||
113 | |||
114 | for (int i = 1; i < points.Count; i++) | ||
115 | { | ||
116 | float3 p = points[i]; | ||
117 | |||
118 | if (p[0] < bmin[0]) bmin[0] = p[0]; | ||
119 | if (p[1] < bmin[1]) bmin[1] = p[1]; | ||
120 | if (p[2] < bmin[2]) bmin[2] = p[2]; | ||
121 | |||
122 | if (p[0] > bmax[0]) bmax[0] = p[0]; | ||
123 | if (p[1] > bmax[1]) bmax[1] = p[1]; | ||
124 | if (p[2] > bmax[2]) bmax[2] = p[2]; | ||
125 | } | ||
126 | |||
127 | float dx = bmax[0] - bmin[0]; | ||
128 | float dy = bmax[1] - bmin[1]; | ||
129 | float dz = bmax[2] - bmin[2]; | ||
130 | |||
131 | return (float)Math.Sqrt(dx * dx + dy * dy + dz * dz); | ||
132 | } | ||
133 | |||
134 | // return true if the two AABB's overlap. | ||
135 | private static bool overlapAABB(float[] bmin1, float[] bmax1, float[] bmin2, float[] bmax2) | ||
136 | { | ||
137 | if (bmax2[0] < bmin1[0]) return false; // if the maximum is less than our minimum on any axis | ||
138 | if (bmax2[1] < bmin1[1]) return false; | ||
139 | if (bmax2[2] < bmin1[2]) return false; | ||
140 | |||
141 | if (bmin2[0] > bmax1[0]) return false; // if the minimum is greater than our maximum on any axis | ||
142 | if (bmin2[1] > bmax1[1]) return false; // if the minimum is greater than our maximum on any axis | ||
143 | if (bmin2[2] > bmax1[2]) return false; // if the minimum is greater than our maximum on any axis | ||
144 | |||
145 | return true; // the extents overlap | ||
146 | } | ||
147 | } | ||
148 | |||
149 | public class ConvexBuilder | ||
150 | { | ||
151 | public List<CHull> mChulls = new List<CHull>(); | ||
152 | private ConvexDecompositionCallback mCallback; | ||
153 | |||
154 | private int MAXDEPTH = 8; | ||
155 | private float CONCAVE_PERCENT = 1f; | ||
156 | private float MERGE_PERCENT = 2f; | ||
157 | |||
158 | public ConvexBuilder(ConvexDecompositionCallback callback) | ||
159 | { | ||
160 | mCallback = callback; | ||
161 | } | ||
162 | |||
163 | public void Dispose() | ||
164 | { | ||
165 | int i; | ||
166 | for (i = 0; i < mChulls.Count; i++) | ||
167 | { | ||
168 | CHull cr = mChulls[i]; | ||
169 | cr.Dispose(); | ||
170 | } | ||
171 | } | ||
172 | |||
173 | public bool isDuplicate(uint i1, uint i2, uint i3, uint ci1, uint ci2, uint ci3) | ||
174 | { | ||
175 | uint dcount = 0; | ||
176 | |||
177 | Debug.Assert(i1 != i2 && i1 != i3 && i2 != i3); | ||
178 | Debug.Assert(ci1 != ci2 && ci1 != ci3 && ci2 != ci3); | ||
179 | |||
180 | if (i1 == ci1 || i1 == ci2 || i1 == ci3) | ||
181 | dcount++; | ||
182 | if (i2 == ci1 || i2 == ci2 || i2 == ci3) | ||
183 | dcount++; | ||
184 | if (i3 == ci1 || i3 == ci2 || i3 == ci3) | ||
185 | dcount++; | ||
186 | |||
187 | return dcount == 3; | ||
188 | } | ||
189 | |||
190 | public void getMesh(ConvexResult cr, VertexPool vc, List<int> indices) | ||
191 | { | ||
192 | List<int> src = cr.HullIndices; | ||
193 | |||
194 | for (int i = 0; i < src.Count / 3; i++) | ||
195 | { | ||
196 | int i1 = src[i * 3 + 0]; | ||
197 | int i2 = src[i * 3 + 1]; | ||
198 | int i3 = src[i * 3 + 2]; | ||
199 | |||
200 | float3 p1 = cr.HullVertices[i1]; | ||
201 | float3 p2 = cr.HullVertices[i2]; | ||
202 | float3 p3 = cr.HullVertices[i3]; | ||
203 | |||
204 | i1 = vc.getIndex(p1); | ||
205 | i2 = vc.getIndex(p2); | ||
206 | i3 = vc.getIndex(p3); | ||
207 | } | ||
208 | } | ||
209 | |||
210 | public CHull canMerge(CHull a, CHull b) | ||
211 | { | ||
212 | if (!a.overlap(b)) // if their AABB's (with a little slop) don't overlap, then return. | ||
213 | return null; | ||
214 | |||
215 | CHull ret = null; | ||
216 | |||
217 | // ok..we are going to combine both meshes into a single mesh | ||
218 | // and then we are going to compute the concavity... | ||
219 | |||
220 | VertexPool vc = new VertexPool(); | ||
221 | |||
222 | List<int> indices = new List<int>(); | ||
223 | |||
224 | getMesh(a.mResult, vc, indices); | ||
225 | getMesh(b.mResult, vc, indices); | ||
226 | |||
227 | int vcount = vc.GetSize(); | ||
228 | List<float3> vertices = vc.GetVertices(); | ||
229 | int tcount = indices.Count / 3; | ||
230 | |||
231 | //don't do anything if hull is empty | ||
232 | if (tcount == 0) | ||
233 | { | ||
234 | vc.Clear(); | ||
235 | return null; | ||
236 | } | ||
237 | |||
238 | HullResult hresult = new HullResult(); | ||
239 | HullDesc desc = new HullDesc(); | ||
240 | |||
241 | desc.SetHullFlag(HullFlag.QF_TRIANGLES); | ||
242 | desc.Vertices = vertices; | ||
243 | |||
244 | HullError hret = HullUtils.CreateConvexHull(desc, ref hresult); | ||
245 | |||
246 | if (hret == HullError.QE_OK) | ||
247 | { | ||
248 | float combineVolume = Concavity.computeMeshVolume(hresult.OutputVertices, hresult.Indices); | ||
249 | float sumVolume = a.mVolume + b.mVolume; | ||
250 | |||
251 | float percent = (sumVolume * 100) / combineVolume; | ||
252 | if (percent >= (100.0f - MERGE_PERCENT)) | ||
253 | { | ||
254 | ConvexResult cr = new ConvexResult(hresult.OutputVertices, hresult.Indices); | ||
255 | ret = new CHull(cr); | ||
256 | } | ||
257 | } | ||
258 | |||
259 | vc.Clear(); | ||
260 | return ret; | ||
261 | } | ||
262 | |||
263 | public bool combineHulls() | ||
264 | { | ||
265 | bool combine = false; | ||
266 | |||
267 | sortChulls(mChulls); // sort the convex hulls, largest volume to least... | ||
268 | |||
269 | List<CHull> output = new List<CHull>(); // the output hulls... | ||
270 | |||
271 | int i; | ||
272 | for (i = 0; i < mChulls.Count && !combine; ++i) | ||
273 | { | ||
274 | CHull cr = mChulls[i]; | ||
275 | |||
276 | int j; | ||
277 | for (j = 0; j < mChulls.Count; j++) | ||
278 | { | ||
279 | CHull match = mChulls[j]; | ||
280 | |||
281 | if (cr != match) // don't try to merge a hull with itself, that be stoopid | ||
282 | { | ||
283 | |||
284 | CHull merge = canMerge(cr, match); // if we can merge these two.... | ||
285 | |||
286 | if (merge != null) | ||
287 | { | ||
288 | output.Add(merge); | ||
289 | |||
290 | ++i; | ||
291 | while (i != mChulls.Count) | ||
292 | { | ||
293 | CHull cr2 = mChulls[i]; | ||
294 | if (cr2 != match) | ||
295 | { | ||
296 | output.Add(cr2); | ||
297 | } | ||
298 | i++; | ||
299 | } | ||
300 | |||
301 | cr.Dispose(); | ||
302 | match.Dispose(); | ||
303 | combine = true; | ||
304 | break; | ||
305 | } | ||
306 | } | ||
307 | } | ||
308 | |||
309 | if (combine) | ||
310 | { | ||
311 | break; | ||
312 | } | ||
313 | else | ||
314 | { | ||
315 | output.Add(cr); | ||
316 | } | ||
317 | } | ||
318 | |||
319 | if (combine) | ||
320 | { | ||
321 | mChulls.Clear(); | ||
322 | mChulls = output; | ||
323 | output.Clear(); | ||
324 | } | ||
325 | |||
326 | return combine; | ||
327 | } | ||
328 | |||
329 | public int process(DecompDesc desc) | ||
330 | { | ||
331 | int ret = 0; | ||
332 | |||
333 | MAXDEPTH = (int)desc.mDepth; | ||
334 | CONCAVE_PERCENT = desc.mCpercent; | ||
335 | MERGE_PERCENT = desc.mPpercent; | ||
336 | |||
337 | ConvexDecomposition.calcConvexDecomposition(desc.mVertices, desc.mIndices, ConvexDecompResult, 0f, 0, MAXDEPTH, CONCAVE_PERCENT, MERGE_PERCENT); | ||
338 | |||
339 | while (combineHulls()) // keep combinging hulls until I can't combine any more... | ||
340 | ; | ||
341 | |||
342 | int i; | ||
343 | for (i = 0; i < mChulls.Count; i++) | ||
344 | { | ||
345 | CHull cr = mChulls[i]; | ||
346 | |||
347 | // before we hand it back to the application, we need to regenerate the hull based on the | ||
348 | // limits given by the user. | ||
349 | |||
350 | ConvexResult c = cr.mResult; // the high resolution hull... | ||
351 | |||
352 | HullResult result = new HullResult(); | ||
353 | HullDesc hdesc = new HullDesc(); | ||
354 | |||
355 | hdesc.SetHullFlag(HullFlag.QF_TRIANGLES); | ||
356 | |||
357 | hdesc.Vertices = c.HullVertices; | ||
358 | hdesc.MaxVertices = desc.mMaxVertices; // maximum number of vertices allowed in the output | ||
359 | |||
360 | if (desc.mSkinWidth != 0f) | ||
361 | { | ||
362 | hdesc.SkinWidth = desc.mSkinWidth; | ||
363 | hdesc.SetHullFlag(HullFlag.QF_SKIN_WIDTH); // do skin width computation. | ||
364 | } | ||
365 | |||
366 | HullError ret2 = HullUtils.CreateConvexHull(hdesc, ref result); | ||
367 | |||
368 | if (ret2 == HullError.QE_OK) | ||
369 | { | ||
370 | ConvexResult r = new ConvexResult(result.OutputVertices, result.Indices); | ||
371 | |||
372 | r.mHullVolume = Concavity.computeMeshVolume(result.OutputVertices, result.Indices); // the volume of the hull. | ||
373 | |||
374 | // compute the best fit OBB | ||
375 | //computeBestFitOBB(result.mNumOutputVertices, result.mOutputVertices, sizeof(float) * 3, r.mOBBSides, r.mOBBTransform); | ||
376 | |||
377 | //r.mOBBVolume = r.mOBBSides[0] * r.mOBBSides[1] * r.mOBBSides[2]; // compute the OBB volume. | ||
378 | |||
379 | //fm_getTranslation(r.mOBBTransform, r.mOBBCenter); // get the translation component of the 4x4 matrix. | ||
380 | |||
381 | //fm_matrixToQuat(r.mOBBTransform, r.mOBBOrientation); // extract the orientation as a quaternion. | ||
382 | |||
383 | //r.mSphereRadius = computeBoundingSphere(result.mNumOutputVertices, result.mOutputVertices, r.mSphereCenter); | ||
384 | //r.mSphereVolume = fm_sphereVolume(r.mSphereRadius); | ||
385 | |||
386 | mCallback(r); | ||
387 | } | ||
388 | |||
389 | result = null; | ||
390 | cr.Dispose(); | ||
391 | } | ||
392 | |||
393 | ret = mChulls.Count; | ||
394 | |||
395 | mChulls.Clear(); | ||
396 | |||
397 | return ret; | ||
398 | } | ||
399 | |||
400 | public void ConvexDecompResult(ConvexResult result) | ||
401 | { | ||
402 | CHull ch = new CHull(result); | ||
403 | mChulls.Add(ch); | ||
404 | } | ||
405 | |||
406 | public void sortChulls(List<CHull> hulls) | ||
407 | { | ||
408 | hulls.Sort(delegate(CHull a, CHull b) { return a.mVolume.CompareTo(b.mVolume); }); | ||
409 | } | ||
410 | } | ||
411 | } | ||
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexDecomposition.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexDecomposition.cs new file mode 100644 index 0000000..2e2bb70 --- /dev/null +++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexDecomposition.cs | |||
@@ -0,0 +1,200 @@ | |||
1 | /* The MIT License | ||
2 | * | ||
3 | * Copyright (c) 2010 Intel Corporation. | ||
4 | * All rights reserved. | ||
5 | * | ||
6 | * Based on the convexdecomposition library from | ||
7 | * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax. | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
10 | * of this software and associated documentation files (the "Software"), to deal | ||
11 | * in the Software without restriction, including without limitation the rights | ||
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | * copies of the Software, and to permit persons to whom the Software is | ||
14 | * furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
25 | * THE SOFTWARE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Diagnostics; | ||
31 | |||
32 | namespace OpenSim.Region.Physics.ConvexDecompositionDotNet | ||
33 | { | ||
34 | public delegate void ConvexDecompositionCallback(ConvexResult result); | ||
35 | |||
36 | public class FaceTri | ||
37 | { | ||
38 | public float3 P1; | ||
39 | public float3 P2; | ||
40 | public float3 P3; | ||
41 | |||
42 | public FaceTri() { } | ||
43 | |||
44 | public FaceTri(List<float3> vertices, int i1, int i2, int i3) | ||
45 | { | ||
46 | P1 = new float3(vertices[i1]); | ||
47 | P2 = new float3(vertices[i2]); | ||
48 | P3 = new float3(vertices[i3]); | ||
49 | } | ||
50 | } | ||
51 | |||
52 | public static class ConvexDecomposition | ||
53 | { | ||
54 | private static void addTri(VertexPool vl, List<int> list, float3 p1, float3 p2, float3 p3) | ||
55 | { | ||
56 | int i1 = vl.getIndex(p1); | ||
57 | int i2 = vl.getIndex(p2); | ||
58 | int i3 = vl.getIndex(p3); | ||
59 | |||
60 | // do *not* process degenerate triangles! | ||
61 | if ( i1 != i2 && i1 != i3 && i2 != i3 ) | ||
62 | { | ||
63 | list.Add(i1); | ||
64 | list.Add(i2); | ||
65 | list.Add(i3); | ||
66 | } | ||
67 | } | ||
68 | |||
69 | public static void calcConvexDecomposition(List<float3> vertices, List<int> indices, ConvexDecompositionCallback callback, float masterVolume, int depth, | ||
70 | int maxDepth, float concavePercent, float mergePercent) | ||
71 | { | ||
72 | float4 plane = new float4(); | ||
73 | bool split = false; | ||
74 | |||
75 | if (depth < maxDepth) | ||
76 | { | ||
77 | float volume = 0f; | ||
78 | float c = Concavity.computeConcavity(vertices, indices, ref plane, ref volume); | ||
79 | |||
80 | if (depth == 0) | ||
81 | { | ||
82 | masterVolume = volume; | ||
83 | } | ||
84 | |||
85 | float percent = (c * 100.0f) / masterVolume; | ||
86 | |||
87 | if (percent > concavePercent) // if great than 5% of the total volume is concave, go ahead and keep splitting. | ||
88 | { | ||
89 | split = true; | ||
90 | } | ||
91 | } | ||
92 | |||
93 | if (depth >= maxDepth || !split) | ||
94 | { | ||
95 | HullResult result = new HullResult(); | ||
96 | HullDesc desc = new HullDesc(); | ||
97 | |||
98 | desc.SetHullFlag(HullFlag.QF_TRIANGLES); | ||
99 | |||
100 | desc.Vertices = vertices; | ||
101 | |||
102 | HullError ret = HullUtils.CreateConvexHull(desc, ref result); | ||
103 | |||
104 | if (ret == HullError.QE_OK) | ||
105 | { | ||
106 | ConvexResult r = new ConvexResult(result.OutputVertices, result.Indices); | ||
107 | callback(r); | ||
108 | } | ||
109 | |||
110 | return; | ||
111 | } | ||
112 | |||
113 | List<int> ifront = new List<int>(); | ||
114 | List<int> iback = new List<int>(); | ||
115 | |||
116 | VertexPool vfront = new VertexPool(); | ||
117 | VertexPool vback = new VertexPool(); | ||
118 | |||
119 | // ok..now we are going to 'split' all of the input triangles against this plane! | ||
120 | for (int i = 0; i < indices.Count / 3; i++) | ||
121 | { | ||
122 | int i1 = indices[i * 3 + 0]; | ||
123 | int i2 = indices[i * 3 + 1]; | ||
124 | int i3 = indices[i * 3 + 2]; | ||
125 | |||
126 | FaceTri t = new FaceTri(vertices, i1, i2, i3); | ||
127 | |||
128 | float3[] front = new float3[4]; | ||
129 | float3[] back = new float3[4]; | ||
130 | |||
131 | int fcount = 0; | ||
132 | int bcount = 0; | ||
133 | |||
134 | PlaneTriResult result = PlaneTri.planeTriIntersection(plane, t, 0.00001f, ref front, out fcount, ref back, out bcount); | ||
135 | |||
136 | if (fcount > 4 || bcount > 4) | ||
137 | { | ||
138 | result = PlaneTri.planeTriIntersection(plane, t, 0.00001f, ref front, out fcount, ref back, out bcount); | ||
139 | } | ||
140 | |||
141 | switch (result) | ||
142 | { | ||
143 | case PlaneTriResult.PTR_FRONT: | ||
144 | Debug.Assert(fcount == 3); | ||
145 | addTri(vfront, ifront, front[0], front[1], front[2]); | ||
146 | break; | ||
147 | case PlaneTriResult.PTR_BACK: | ||
148 | Debug.Assert(bcount == 3); | ||
149 | addTri(vback, iback, back[0], back[1], back[2]); | ||
150 | break; | ||
151 | case PlaneTriResult.PTR_SPLIT: | ||
152 | Debug.Assert(fcount >= 3 && fcount <= 4); | ||
153 | Debug.Assert(bcount >= 3 && bcount <= 4); | ||
154 | |||
155 | addTri(vfront, ifront, front[0], front[1], front[2]); | ||
156 | addTri(vback, iback, back[0], back[1], back[2]); | ||
157 | |||
158 | if (fcount == 4) | ||
159 | { | ||
160 | addTri(vfront, ifront, front[0], front[2], front[3]); | ||
161 | } | ||
162 | |||
163 | if (bcount == 4) | ||
164 | { | ||
165 | addTri(vback, iback, back[0], back[2], back[3]); | ||
166 | } | ||
167 | |||
168 | break; | ||
169 | } | ||
170 | } | ||
171 | |||
172 | // ok... here we recursively call | ||
173 | if (ifront.Count > 0) | ||
174 | { | ||
175 | int vcount = vfront.GetSize(); | ||
176 | List<float3> vertices2 = vfront.GetVertices(); | ||
177 | for (int i = 0; i < vertices2.Count; i++) | ||
178 | vertices2[i] = new float3(vertices2[i]); | ||
179 | int tcount = ifront.Count / 3; | ||
180 | |||
181 | calcConvexDecomposition(vertices2, ifront, callback, masterVolume, depth + 1, maxDepth, concavePercent, mergePercent); | ||
182 | } | ||
183 | |||
184 | ifront.Clear(); | ||
185 | vfront.Clear(); | ||
186 | |||
187 | if (iback.Count > 0) | ||
188 | { | ||
189 | int vcount = vback.GetSize(); | ||
190 | List<float3> vertices2 = vback.GetVertices(); | ||
191 | int tcount = iback.Count / 3; | ||
192 | |||
193 | calcConvexDecomposition(vertices2, iback, callback, masterVolume, depth + 1, maxDepth, concavePercent, mergePercent); | ||
194 | } | ||
195 | |||
196 | iback.Clear(); | ||
197 | vback.Clear(); | ||
198 | } | ||
199 | } | ||
200 | } | ||
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexResult.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexResult.cs new file mode 100644 index 0000000..87758b5 --- /dev/null +++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexResult.cs | |||
@@ -0,0 +1,74 @@ | |||
1 | /* The MIT License | ||
2 | * | ||
3 | * Copyright (c) 2010 Intel Corporation. | ||
4 | * All rights reserved. | ||
5 | * | ||
6 | * Based on the convexdecomposition library from | ||
7 | * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax. | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
10 | * of this software and associated documentation files (the "Software"), to deal | ||
11 | * in the Software without restriction, including without limitation the rights | ||
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | * copies of the Software, and to permit persons to whom the Software is | ||
14 | * furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
25 | * THE SOFTWARE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | |||
31 | namespace OpenSim.Region.Physics.ConvexDecompositionDotNet | ||
32 | { | ||
33 | public class ConvexResult | ||
34 | { | ||
35 | public List<float3> HullVertices; | ||
36 | public List<int> HullIndices; | ||
37 | |||
38 | public float mHullVolume; // the volume of the convex hull. | ||
39 | |||
40 | //public float[] OBBSides = new float[3]; // the width, height and breadth of the best fit OBB | ||
41 | //public float[] OBBCenter = new float[3]; // the center of the OBB | ||
42 | //public float[] OBBOrientation = new float[4]; // the quaternion rotation of the OBB. | ||
43 | //public float[] OBBTransform = new float[16]; // the 4x4 transform of the OBB. | ||
44 | //public float OBBVolume; // the volume of the OBB | ||
45 | |||
46 | //public float SphereRadius; // radius and center of best fit sphere | ||
47 | //public float[] SphereCenter = new float[3]; | ||
48 | //public float SphereVolume; // volume of the best fit sphere | ||
49 | |||
50 | public ConvexResult() | ||
51 | { | ||
52 | HullVertices = new List<float3>(); | ||
53 | HullIndices = new List<int>(); | ||
54 | } | ||
55 | |||
56 | public ConvexResult(List<float3> hvertices, List<int> hindices) | ||
57 | { | ||
58 | HullVertices = hvertices; | ||
59 | HullIndices = hindices; | ||
60 | } | ||
61 | |||
62 | public ConvexResult(ConvexResult r) | ||
63 | { | ||
64 | HullVertices = new List<float3>(r.HullVertices); | ||
65 | HullIndices = new List<int>(r.HullIndices); | ||
66 | } | ||
67 | |||
68 | public void Dispose() | ||
69 | { | ||
70 | HullVertices = null; | ||
71 | HullIndices = null; | ||
72 | } | ||
73 | } | ||
74 | } | ||
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/HullClasses.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/HullClasses.cs new file mode 100644 index 0000000..d81df26 --- /dev/null +++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/HullClasses.cs | |||
@@ -0,0 +1,171 @@ | |||
1 | /* The MIT License | ||
2 | * | ||
3 | * Copyright (c) 2010 Intel Corporation. | ||
4 | * All rights reserved. | ||
5 | * | ||
6 | * Based on the convexdecomposition library from | ||
7 | * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax. | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
10 | * of this software and associated documentation files (the "Software"), to deal | ||
11 | * in the Software without restriction, including without limitation the rights | ||
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | * copies of the Software, and to permit persons to whom the Software is | ||
14 | * furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
25 | * THE SOFTWARE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | |||
31 | namespace OpenSim.Region.Physics.ConvexDecompositionDotNet | ||
32 | { | ||
33 | public class HullResult | ||
34 | { | ||
35 | public bool Polygons = true; // true if indices represents polygons, false indices are triangles | ||
36 | public List<float3> OutputVertices = new List<float3>(); | ||
37 | public List<int> Indices; | ||
38 | |||
39 | // If triangles, then indices are array indexes into the vertex list. | ||
40 | // If polygons, indices are in the form (number of points in face) (p1, p2, p3, ..) etc.. | ||
41 | } | ||
42 | |||
43 | public class PHullResult | ||
44 | { | ||
45 | public List<float3> Vertices = new List<float3>(); | ||
46 | public List<int> Indices = new List<int>(); | ||
47 | } | ||
48 | |||
49 | [Flags] | ||
50 | public enum HullFlag : int | ||
51 | { | ||
52 | QF_DEFAULT = 0, | ||
53 | QF_TRIANGLES = (1 << 0), // report results as triangles, not polygons. | ||
54 | QF_SKIN_WIDTH = (1 << 2) // extrude hull based on this skin width | ||
55 | } | ||
56 | |||
57 | public enum HullError : int | ||
58 | { | ||
59 | QE_OK, // success! | ||
60 | QE_FAIL // failed. | ||
61 | } | ||
62 | |||
63 | public class HullDesc | ||
64 | { | ||
65 | public HullFlag Flags; // flags to use when generating the convex hull. | ||
66 | public List<float3> Vertices; | ||
67 | public float NormalEpsilon; // the epsilon for removing duplicates. This is a normalized value, if normalized bit is on. | ||
68 | public float SkinWidth; | ||
69 | public uint MaxVertices; // maximum number of vertices to be considered for the hull! | ||
70 | public uint MaxFaces; | ||
71 | |||
72 | public HullDesc() | ||
73 | { | ||
74 | Flags = HullFlag.QF_DEFAULT; | ||
75 | Vertices = new List<float3>(); | ||
76 | NormalEpsilon = 0.001f; | ||
77 | MaxVertices = 4096; | ||
78 | MaxFaces = 4096; | ||
79 | SkinWidth = 0.01f; | ||
80 | } | ||
81 | |||
82 | public HullDesc(HullFlag flags, List<float3> vertices) | ||
83 | { | ||
84 | Flags = flags; | ||
85 | Vertices = new List<float3>(vertices); | ||
86 | NormalEpsilon = 0.001f; | ||
87 | MaxVertices = 4096; | ||
88 | MaxFaces = 4096; | ||
89 | SkinWidth = 0.01f; | ||
90 | } | ||
91 | |||
92 | public bool HasHullFlag(HullFlag flag) | ||
93 | { | ||
94 | return (Flags & flag) != 0; | ||
95 | } | ||
96 | |||
97 | public void SetHullFlag(HullFlag flag) | ||
98 | { | ||
99 | Flags |= flag; | ||
100 | } | ||
101 | |||
102 | public void ClearHullFlag(HullFlag flag) | ||
103 | { | ||
104 | Flags &= ~flag; | ||
105 | } | ||
106 | } | ||
107 | |||
108 | public class ConvexH | ||
109 | { | ||
110 | public struct HalfEdge | ||
111 | { | ||
112 | public short ea; // the other half of the edge (index into edges list) | ||
113 | public byte v; // the vertex at the start of this edge (index into vertices list) | ||
114 | public byte p; // the facet on which this edge lies (index into facets list) | ||
115 | |||
116 | public HalfEdge(short _ea, byte _v, byte _p) | ||
117 | { | ||
118 | ea = _ea; | ||
119 | v = _v; | ||
120 | p = _p; | ||
121 | } | ||
122 | |||
123 | public HalfEdge(HalfEdge e) | ||
124 | { | ||
125 | ea = e.ea; | ||
126 | v = e.v; | ||
127 | p = e.p; | ||
128 | } | ||
129 | } | ||
130 | |||
131 | public List<float3> vertices = new List<float3>(); | ||
132 | public List<HalfEdge> edges = new List<HalfEdge>(); | ||
133 | public List<Plane> facets = new List<Plane>(); | ||
134 | |||
135 | public ConvexH(int vertices_size, int edges_size, int facets_size) | ||
136 | { | ||
137 | vertices = new List<float3>(vertices_size); | ||
138 | edges = new List<HalfEdge>(edges_size); | ||
139 | facets = new List<Plane>(facets_size); | ||
140 | } | ||
141 | } | ||
142 | |||
143 | public class VertFlag | ||
144 | { | ||
145 | public byte planetest; | ||
146 | public byte junk; | ||
147 | public byte undermap; | ||
148 | public byte overmap; | ||
149 | } | ||
150 | |||
151 | public class EdgeFlag | ||
152 | { | ||
153 | public byte planetest; | ||
154 | public byte fixes; | ||
155 | public short undermap; | ||
156 | public short overmap; | ||
157 | } | ||
158 | |||
159 | public class PlaneFlag | ||
160 | { | ||
161 | public byte undermap; | ||
162 | public byte overmap; | ||
163 | } | ||
164 | |||
165 | public class Coplanar | ||
166 | { | ||
167 | public ushort ea; | ||
168 | public byte v0; | ||
169 | public byte v1; | ||
170 | } | ||
171 | } | ||
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/HullTriangle.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/HullTriangle.cs new file mode 100644 index 0000000..1119a75 --- /dev/null +++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/HullTriangle.cs | |||
@@ -0,0 +1,99 @@ | |||
1 | /* The MIT License | ||
2 | * | ||
3 | * Copyright (c) 2010 Intel Corporation. | ||
4 | * All rights reserved. | ||
5 | * | ||
6 | * Based on the convexdecomposition library from | ||
7 | * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax. | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
10 | * of this software and associated documentation files (the "Software"), to deal | ||
11 | * in the Software without restriction, including without limitation the rights | ||
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | * copies of the Software, and to permit persons to whom the Software is | ||
14 | * furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
25 | * THE SOFTWARE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Diagnostics; | ||
31 | |||
32 | namespace OpenSim.Region.Physics.ConvexDecompositionDotNet | ||
33 | { | ||
34 | public class HullTriangle : int3 | ||
35 | { | ||
36 | public int3 n = new int3(); | ||
37 | public int id; | ||
38 | public int vmax; | ||
39 | public float rise; | ||
40 | private List<HullTriangle> tris; | ||
41 | |||
42 | public HullTriangle(int a, int b, int c, List<HullTriangle> tris) | ||
43 | : base(a, b, c) | ||
44 | { | ||
45 | this.tris = tris; | ||
46 | |||
47 | n = new int3(-1, -1, -1); | ||
48 | id = tris.Count; | ||
49 | tris.Add(this); | ||
50 | vmax = -1; | ||
51 | rise = 0.0f; | ||
52 | } | ||
53 | |||
54 | public void Dispose() | ||
55 | { | ||
56 | Debug.Assert(tris[id] == this); | ||
57 | tris[id] = null; | ||
58 | } | ||
59 | |||
60 | public int neib(int a, int b) | ||
61 | { | ||
62 | int i; | ||
63 | |||
64 | for (i = 0; i < 3; i++) | ||
65 | { | ||
66 | int i1 = (i + 1) % 3; | ||
67 | int i2 = (i + 2) % 3; | ||
68 | if ((this)[i] == a && (this)[i1] == b) | ||
69 | return n[i2]; | ||
70 | if ((this)[i] == b && (this)[i1] == a) | ||
71 | return n[i2]; | ||
72 | } | ||
73 | |||
74 | Debug.Assert(false); | ||
75 | return -1; | ||
76 | } | ||
77 | |||
78 | public void setneib(int a, int b, int value) | ||
79 | { | ||
80 | int i; | ||
81 | |||
82 | for (i = 0; i < 3; i++) | ||
83 | { | ||
84 | int i1 = (i + 1) % 3; | ||
85 | int i2 = (i + 2) % 3; | ||
86 | if ((this)[i] == a && (this)[i1] == b) | ||
87 | { | ||
88 | n[i2] = value; | ||
89 | return; | ||
90 | } | ||
91 | if ((this)[i] == b && (this)[i1] == a) | ||
92 | { | ||
93 | n[i2] = value; | ||
94 | return; | ||
95 | } | ||
96 | } | ||
97 | } | ||
98 | } | ||
99 | } | ||
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/HullUtils.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/HullUtils.cs new file mode 100644 index 0000000..c9ccfe2 --- /dev/null +++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/HullUtils.cs | |||
@@ -0,0 +1,1868 @@ | |||
1 | /* The MIT License | ||
2 | * | ||
3 | * Copyright (c) 2010 Intel Corporation. | ||
4 | * All rights reserved. | ||
5 | * | ||
6 | * Based on the convexdecomposition library from | ||
7 | * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax. | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
10 | * of this software and associated documentation files (the "Software"), to deal | ||
11 | * in the Software without restriction, including without limitation the rights | ||
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | * copies of the Software, and to permit persons to whom the Software is | ||
14 | * furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
25 | * THE SOFTWARE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Diagnostics; | ||
31 | |||
32 | namespace OpenSim.Region.Physics.ConvexDecompositionDotNet | ||
33 | { | ||
34 | public static class HullUtils | ||
35 | { | ||
36 | public static int argmin(float[] a, int n) | ||
37 | { | ||
38 | int r = 0; | ||
39 | for (int i = 1; i < n; i++) | ||
40 | { | ||
41 | if (a[i] < a[r]) | ||
42 | { | ||
43 | r = i; | ||
44 | } | ||
45 | } | ||
46 | return r; | ||
47 | } | ||
48 | |||
49 | public static float clampf(float a) | ||
50 | { | ||
51 | return Math.Min(1.0f, Math.Max(0.0f, a)); | ||
52 | } | ||
53 | |||
54 | public static float Round(float a, float precision) | ||
55 | { | ||
56 | return (float)Math.Floor(0.5f + a / precision) * precision; | ||
57 | } | ||
58 | |||
59 | public static float Interpolate(float f0, float f1, float alpha) | ||
60 | { | ||
61 | return f0 * (1 - alpha) + f1 * alpha; | ||
62 | } | ||
63 | |||
64 | public static void Swap<T>(ref T a, ref T b) | ||
65 | { | ||
66 | T tmp = a; | ||
67 | a = b; | ||
68 | b = tmp; | ||
69 | } | ||
70 | |||
71 | public static bool above(List<float3> vertices, int3 t, float3 p, float epsilon) | ||
72 | { | ||
73 | float3 vtx = vertices[t.x]; | ||
74 | float3 n = TriNormal(vtx, vertices[t.y], vertices[t.z]); | ||
75 | return (float3.dot(n, p - vtx) > epsilon); // EPSILON??? | ||
76 | } | ||
77 | |||
78 | public static int hasedge(int3 t, int a, int b) | ||
79 | { | ||
80 | for (int i = 0; i < 3; i++) | ||
81 | { | ||
82 | int i1 = (i + 1) % 3; | ||
83 | if (t[i] == a && t[i1] == b) | ||
84 | return 1; | ||
85 | } | ||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | public static bool hasvert(int3 t, int v) | ||
90 | { | ||
91 | return (t[0] == v || t[1] == v || t[2] == v); | ||
92 | } | ||
93 | |||
94 | public static int shareedge(int3 a, int3 b) | ||
95 | { | ||
96 | int i; | ||
97 | for (i = 0; i < 3; i++) | ||
98 | { | ||
99 | int i1 = (i + 1) % 3; | ||
100 | if (hasedge(a, b[i1], b[i]) != 0) | ||
101 | return 1; | ||
102 | } | ||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | public static void b2bfix(HullTriangle s, HullTriangle t, List<HullTriangle> tris) | ||
107 | { | ||
108 | int i; | ||
109 | for (i = 0; i < 3; i++) | ||
110 | { | ||
111 | int i1 = (i + 1) % 3; | ||
112 | int i2 = (i + 2) % 3; | ||
113 | int a = (s)[i1]; | ||
114 | int b = (s)[i2]; | ||
115 | Debug.Assert(tris[s.neib(a, b)].neib(b, a) == s.id); | ||
116 | Debug.Assert(tris[t.neib(a, b)].neib(b, a) == t.id); | ||
117 | tris[s.neib(a, b)].setneib(b, a, t.neib(b, a)); | ||
118 | tris[t.neib(b, a)].setneib(a, b, s.neib(a, b)); | ||
119 | } | ||
120 | } | ||
121 | |||
122 | public static void removeb2b(HullTriangle s, HullTriangle t, List<HullTriangle> tris) | ||
123 | { | ||
124 | b2bfix(s, t, tris); | ||
125 | s.Dispose(); | ||
126 | t.Dispose(); | ||
127 | } | ||
128 | |||
129 | public static void checkit(HullTriangle t, List<HullTriangle> tris) | ||
130 | { | ||
131 | int i; | ||
132 | Debug.Assert(tris[t.id] == t); | ||
133 | for (i = 0; i < 3; i++) | ||
134 | { | ||
135 | int i1 = (i + 1) % 3; | ||
136 | int i2 = (i + 2) % 3; | ||
137 | int a = (t)[i1]; | ||
138 | int b = (t)[i2]; | ||
139 | Debug.Assert(a != b); | ||
140 | Debug.Assert(tris[t.n[i]].neib(b, a) == t.id); | ||
141 | } | ||
142 | } | ||
143 | |||
144 | public static void extrude(HullTriangle t0, int v, List<HullTriangle> tris) | ||
145 | { | ||
146 | int3 t = t0; | ||
147 | int n = tris.Count; | ||
148 | HullTriangle ta = new HullTriangle(v, t[1], t[2], tris); | ||
149 | ta.n = new int3(t0.n[0], n + 1, n + 2); | ||
150 | tris[t0.n[0]].setneib(t[1], t[2], n + 0); | ||
151 | HullTriangle tb = new HullTriangle(v, t[2], t[0], tris); | ||
152 | tb.n = new int3(t0.n[1], n + 2, n + 0); | ||
153 | tris[t0.n[1]].setneib(t[2], t[0], n + 1); | ||
154 | HullTriangle tc = new HullTriangle(v, t[0], t[1], tris); | ||
155 | tc.n = new int3(t0.n[2], n + 0, n + 1); | ||
156 | tris[t0.n[2]].setneib(t[0], t[1], n + 2); | ||
157 | checkit(ta, tris); | ||
158 | checkit(tb, tris); | ||
159 | checkit(tc, tris); | ||
160 | if (hasvert(tris[ta.n[0]], v)) | ||
161 | removeb2b(ta, tris[ta.n[0]], tris); | ||
162 | if (hasvert(tris[tb.n[0]], v)) | ||
163 | removeb2b(tb, tris[tb.n[0]], tris); | ||
164 | if (hasvert(tris[tc.n[0]], v)) | ||
165 | removeb2b(tc, tris[tc.n[0]], tris); | ||
166 | t0.Dispose(); | ||
167 | } | ||
168 | |||
169 | public static HullTriangle extrudable(float epsilon, List<HullTriangle> tris) | ||
170 | { | ||
171 | int i; | ||
172 | HullTriangle t = null; | ||
173 | for (i = 0; i < tris.Count; i++) | ||
174 | { | ||
175 | if (t == null || (tris.Count > i && (object)tris[i] != null && t.rise < tris[i].rise)) | ||
176 | { | ||
177 | t = tris[i]; | ||
178 | } | ||
179 | } | ||
180 | return (t.rise > epsilon) ? t : null; | ||
181 | } | ||
182 | |||
183 | public static Quaternion RotationArc(float3 v0, float3 v1) | ||
184 | { | ||
185 | Quaternion q = new Quaternion(); | ||
186 | v0 = float3.normalize(v0); // Comment these two lines out if you know its not needed. | ||
187 | v1 = float3.normalize(v1); // If vector is already unit length then why do it again? | ||
188 | float3 c = float3.cross(v0, v1); | ||
189 | float d = float3.dot(v0, v1); | ||
190 | if (d <= -1.0f) // 180 about x axis | ||
191 | { | ||
192 | return new Quaternion(1f, 0f, 0f, 0f); | ||
193 | } | ||
194 | float s = (float)Math.Sqrt((1 + d) * 2f); | ||
195 | q.x = c.x / s; | ||
196 | q.y = c.y / s; | ||
197 | q.z = c.z / s; | ||
198 | q.w = s / 2.0f; | ||
199 | return q; | ||
200 | } | ||
201 | |||
202 | public static float3 PlaneLineIntersection(Plane plane, float3 p0, float3 p1) | ||
203 | { | ||
204 | // returns the point where the line p0-p1 intersects the plane n&d | ||
205 | float3 dif = p1 - p0; | ||
206 | float dn = float3.dot(plane.normal, dif); | ||
207 | float t = -(plane.dist + float3.dot(plane.normal, p0)) / dn; | ||
208 | return p0 + (dif * t); | ||
209 | } | ||
210 | |||
211 | public static float3 LineProject(float3 p0, float3 p1, float3 a) | ||
212 | { | ||
213 | float3 w = new float3(); | ||
214 | w = p1 - p0; | ||
215 | float t = float3.dot(w, (a - p0)) / (w.x * w.x + w.y * w.y + w.z * w.z); | ||
216 | return p0 + w * t; | ||
217 | } | ||
218 | |||
219 | public static float3 PlaneProject(Plane plane, float3 point) | ||
220 | { | ||
221 | return point - plane.normal * (float3.dot(point, plane.normal) + plane.dist); | ||
222 | } | ||
223 | |||
224 | public static float LineProjectTime(float3 p0, float3 p1, float3 a) | ||
225 | { | ||
226 | float3 w = new float3(); | ||
227 | w = p1 - p0; | ||
228 | float t = float3.dot(w, (a - p0)) / (w.x * w.x + w.y * w.y + w.z * w.z); | ||
229 | return t; | ||
230 | } | ||
231 | |||
232 | public static float3 ThreePlaneIntersection(Plane p0, Plane p1, Plane p2) | ||
233 | { | ||
234 | float3x3 mp = float3x3.Transpose(new float3x3(p0.normal, p1.normal, p2.normal)); | ||
235 | float3x3 mi = float3x3.Inverse(mp); | ||
236 | float3 b = new float3(p0.dist, p1.dist, p2.dist); | ||
237 | return -b * mi; | ||
238 | } | ||
239 | |||
240 | public static bool PolyHit(List<float3> vert, float3 v0, float3 v1) | ||
241 | { | ||
242 | float3 impact = new float3(); | ||
243 | float3 normal = new float3(); | ||
244 | return PolyHit(vert, v0, v1, out impact, out normal); | ||
245 | } | ||
246 | |||
247 | public static bool PolyHit(List<float3> vert, float3 v0, float3 v1, out float3 impact) | ||
248 | { | ||
249 | float3 normal = new float3(); | ||
250 | return PolyHit(vert, v0, v1, out impact, out normal); | ||
251 | } | ||
252 | |||
253 | public static bool PolyHit(List<float3> vert, float3 v0, float3 v1, out float3 impact, out float3 normal) | ||
254 | { | ||
255 | float3 the_point = new float3(); | ||
256 | |||
257 | impact = null; | ||
258 | normal = null; | ||
259 | |||
260 | int i; | ||
261 | float3 nrml = new float3(0, 0, 0); | ||
262 | for (i = 0; i < vert.Count; i++) | ||
263 | { | ||
264 | int i1 = (i + 1) % vert.Count; | ||
265 | int i2 = (i + 2) % vert.Count; | ||
266 | nrml = nrml + float3.cross(vert[i1] - vert[i], vert[i2] - vert[i1]); | ||
267 | } | ||
268 | |||
269 | float m = float3.magnitude(nrml); | ||
270 | if (m == 0.0) | ||
271 | { | ||
272 | return false; | ||
273 | } | ||
274 | nrml = nrml * (1.0f / m); | ||
275 | float dist = -float3.dot(nrml, vert[0]); | ||
276 | float d0; | ||
277 | float d1; | ||
278 | if ((d0 = float3.dot(v0, nrml) + dist) < 0 || (d1 = float3.dot(v1, nrml) + dist) > 0) | ||
279 | { | ||
280 | return false; | ||
281 | } | ||
282 | |||
283 | // By using the cached plane distances d0 and d1 | ||
284 | // we can optimize the following: | ||
285 | // the_point = planelineintersection(nrml,dist,v0,v1); | ||
286 | float a = d0 / (d0 - d1); | ||
287 | the_point = v0 * (1 - a) + v1 * a; | ||
288 | |||
289 | |||
290 | bool inside = true; | ||
291 | for (int j = 0; inside && j < vert.Count; j++) | ||
292 | { | ||
293 | // let inside = 0 if outside | ||
294 | float3 pp1 = new float3(); | ||
295 | float3 pp2 = new float3(); | ||
296 | float3 side = new float3(); | ||
297 | pp1 = vert[j]; | ||
298 | pp2 = vert[(j + 1) % vert.Count]; | ||
299 | side = float3.cross((pp2 - pp1), (the_point - pp1)); | ||
300 | inside = (float3.dot(nrml, side) >= 0.0); | ||
301 | } | ||
302 | if (inside) | ||
303 | { | ||
304 | if (normal != null) | ||
305 | { | ||
306 | normal = nrml; | ||
307 | } | ||
308 | if (impact != null) | ||
309 | { | ||
310 | impact = the_point; | ||
311 | } | ||
312 | } | ||
313 | return inside; | ||
314 | } | ||
315 | |||
316 | public static bool BoxInside(float3 p, float3 bmin, float3 bmax) | ||
317 | { | ||
318 | return (p.x >= bmin.x && p.x <= bmax.x && p.y >= bmin.y && p.y <= bmax.y && p.z >= bmin.z && p.z <= bmax.z); | ||
319 | } | ||
320 | |||
321 | public static bool BoxIntersect(float3 v0, float3 v1, float3 bmin, float3 bmax, float3 impact) | ||
322 | { | ||
323 | if (BoxInside(v0, bmin, bmax)) | ||
324 | { | ||
325 | impact = v0; | ||
326 | return true; | ||
327 | } | ||
328 | if (v0.x <= bmin.x && v1.x >= bmin.x) | ||
329 | { | ||
330 | float a = (bmin.x - v0.x) / (v1.x - v0.x); | ||
331 | //v.x = bmin.x; | ||
332 | float vy = (1 - a) * v0.y + a * v1.y; | ||
333 | float vz = (1 - a) * v0.z + a * v1.z; | ||
334 | if (vy >= bmin.y && vy <= bmax.y && vz >= bmin.z && vz <= bmax.z) | ||
335 | { | ||
336 | impact.x = bmin.x; | ||
337 | impact.y = vy; | ||
338 | impact.z = vz; | ||
339 | return true; | ||
340 | } | ||
341 | } | ||
342 | else if (v0.x >= bmax.x && v1.x <= bmax.x) | ||
343 | { | ||
344 | float a = (bmax.x - v0.x) / (v1.x - v0.x); | ||
345 | //v.x = bmax.x; | ||
346 | float vy = (1 - a) * v0.y + a * v1.y; | ||
347 | float vz = (1 - a) * v0.z + a * v1.z; | ||
348 | if (vy >= bmin.y && vy <= bmax.y && vz >= bmin.z && vz <= bmax.z) | ||
349 | { | ||
350 | impact.x = bmax.x; | ||
351 | impact.y = vy; | ||
352 | impact.z = vz; | ||
353 | return true; | ||
354 | } | ||
355 | } | ||
356 | if (v0.y <= bmin.y && v1.y >= bmin.y) | ||
357 | { | ||
358 | float a = (bmin.y - v0.y) / (v1.y - v0.y); | ||
359 | float vx = (1 - a) * v0.x + a * v1.x; | ||
360 | //v.y = bmin.y; | ||
361 | float vz = (1 - a) * v0.z + a * v1.z; | ||
362 | if (vx >= bmin.x && vx <= bmax.x && vz >= bmin.z && vz <= bmax.z) | ||
363 | { | ||
364 | impact.x = vx; | ||
365 | impact.y = bmin.y; | ||
366 | impact.z = vz; | ||
367 | return true; | ||
368 | } | ||
369 | } | ||
370 | else if (v0.y >= bmax.y && v1.y <= bmax.y) | ||
371 | { | ||
372 | float a = (bmax.y - v0.y) / (v1.y - v0.y); | ||
373 | float vx = (1 - a) * v0.x + a * v1.x; | ||
374 | // vy = bmax.y; | ||
375 | float vz = (1 - a) * v0.z + a * v1.z; | ||
376 | if (vx >= bmin.x && vx <= bmax.x && vz >= bmin.z && vz <= bmax.z) | ||
377 | { | ||
378 | impact.x = vx; | ||
379 | impact.y = bmax.y; | ||
380 | impact.z = vz; | ||
381 | return true; | ||
382 | } | ||
383 | } | ||
384 | if (v0.z <= bmin.z && v1.z >= bmin.z) | ||
385 | { | ||
386 | float a = (bmin.z - v0.z) / (v1.z - v0.z); | ||
387 | float vx = (1 - a) * v0.x + a * v1.x; | ||
388 | float vy = (1 - a) * v0.y + a * v1.y; | ||
389 | // v.z = bmin.z; | ||
390 | if (vy >= bmin.y && vy <= bmax.y && vx >= bmin.x && vx <= bmax.x) | ||
391 | { | ||
392 | impact.x = vx; | ||
393 | impact.y = vy; | ||
394 | impact.z = bmin.z; | ||
395 | return true; | ||
396 | } | ||
397 | } | ||
398 | else if (v0.z >= bmax.z && v1.z <= bmax.z) | ||
399 | { | ||
400 | float a = (bmax.z - v0.z) / (v1.z - v0.z); | ||
401 | float vx = (1 - a) * v0.x + a * v1.x; | ||
402 | float vy = (1 - a) * v0.y + a * v1.y; | ||
403 | // v.z = bmax.z; | ||
404 | if (vy >= bmin.y && vy <= bmax.y && vx >= bmin.x && vx <= bmax.x) | ||
405 | { | ||
406 | impact.x = vx; | ||
407 | impact.y = vy; | ||
408 | impact.z = bmax.z; | ||
409 | return true; | ||
410 | } | ||
411 | } | ||
412 | return false; | ||
413 | } | ||
414 | |||
415 | public static float DistanceBetweenLines(float3 ustart, float3 udir, float3 vstart, float3 vdir, float3 upoint) | ||
416 | { | ||
417 | return DistanceBetweenLines(ustart, udir, vstart, vdir, upoint, null); | ||
418 | } | ||
419 | |||
420 | public static float DistanceBetweenLines(float3 ustart, float3 udir, float3 vstart, float3 vdir) | ||
421 | { | ||
422 | return DistanceBetweenLines(ustart, udir, vstart, vdir, null, null); | ||
423 | } | ||
424 | |||
425 | public static float DistanceBetweenLines(float3 ustart, float3 udir, float3 vstart, float3 vdir, float3 upoint, float3 vpoint) | ||
426 | { | ||
427 | float3 cp = float3.normalize(float3.cross(udir, vdir)); | ||
428 | |||
429 | float distu = -float3.dot(cp, ustart); | ||
430 | float distv = -float3.dot(cp, vstart); | ||
431 | float dist = (float)Math.Abs(distu - distv); | ||
432 | if (upoint != null) | ||
433 | { | ||
434 | Plane plane = new Plane(); | ||
435 | plane.normal = float3.normalize(float3.cross(vdir, cp)); | ||
436 | plane.dist = -float3.dot(plane.normal, vstart); | ||
437 | upoint = PlaneLineIntersection(plane, ustart, ustart + udir); | ||
438 | } | ||
439 | if (vpoint != null) | ||
440 | { | ||
441 | Plane plane = new Plane(); | ||
442 | plane.normal = float3.normalize(float3.cross(udir, cp)); | ||
443 | plane.dist = -float3.dot(plane.normal, ustart); | ||
444 | vpoint = PlaneLineIntersection(plane, vstart, vstart + vdir); | ||
445 | } | ||
446 | return dist; | ||
447 | } | ||
448 | |||
449 | public static float3 TriNormal(float3 v0, float3 v1, float3 v2) | ||
450 | { | ||
451 | // return the normal of the triangle | ||
452 | // inscribed by v0, v1, and v2 | ||
453 | float3 cp = float3.cross(v1 - v0, v2 - v1); | ||
454 | float m = float3.magnitude(cp); | ||
455 | if (m == 0) | ||
456 | return new float3(1, 0, 0); | ||
457 | return cp * (1.0f / m); | ||
458 | } | ||
459 | |||
460 | public static int PlaneTest(Plane p, float3 v, float planetestepsilon) | ||
461 | { | ||
462 | float a = float3.dot(v, p.normal) + p.dist; | ||
463 | int flag = (a > planetestepsilon) ? (2) : ((a < -planetestepsilon) ? (1) : (0)); | ||
464 | return flag; | ||
465 | } | ||
466 | |||
467 | public static int SplitTest(ref ConvexH convex, Plane plane, float planetestepsilon) | ||
468 | { | ||
469 | int flag = 0; | ||
470 | for (int i = 0; i < convex.vertices.Count; i++) | ||
471 | { | ||
472 | flag |= PlaneTest(plane, convex.vertices[i], planetestepsilon); | ||
473 | } | ||
474 | return flag; | ||
475 | } | ||
476 | |||
477 | public static Quaternion VirtualTrackBall(float3 cop, float3 cor, float3 dir1, float3 dir2) | ||
478 | { | ||
479 | // routine taken from game programming gems. | ||
480 | // Implement track ball functionality to spin stuf on the screen | ||
481 | // cop center of projection | ||
482 | // cor center of rotation | ||
483 | // dir1 old mouse direction | ||
484 | // dir2 new mouse direction | ||
485 | // pretend there is a sphere around cor. Then find the points | ||
486 | // where dir1 and dir2 intersect that sphere. Find the | ||
487 | // rotation that takes the first point to the second. | ||
488 | float m; | ||
489 | // compute plane | ||
490 | float3 nrml = cor - cop; | ||
491 | float fudgefactor = 1.0f / (float3.magnitude(nrml) * 0.25f); // since trackball proportional to distance from cop | ||
492 | nrml = float3.normalize(nrml); | ||
493 | float dist = -float3.dot(nrml, cor); | ||
494 | float3 u = PlaneLineIntersection(new Plane(nrml, dist), cop, cop + dir1); | ||
495 | u = u - cor; | ||
496 | u = u * fudgefactor; | ||
497 | m = float3.magnitude(u); | ||
498 | if (m > 1) | ||
499 | { | ||
500 | u /= m; | ||
501 | } | ||
502 | else | ||
503 | { | ||
504 | u = u - (nrml * (float)Math.Sqrt(1 - m * m)); | ||
505 | } | ||
506 | float3 v = PlaneLineIntersection(new Plane(nrml, dist), cop, cop + dir2); | ||
507 | v = v - cor; | ||
508 | v = v * fudgefactor; | ||
509 | m = float3.magnitude(v); | ||
510 | if (m > 1) | ||
511 | { | ||
512 | v /= m; | ||
513 | } | ||
514 | else | ||
515 | { | ||
516 | v = v - (nrml * (float)Math.Sqrt(1 - m * m)); | ||
517 | } | ||
518 | return RotationArc(u, v); | ||
519 | } | ||
520 | |||
521 | public static bool AssertIntact(ConvexH convex, float planetestepsilon) | ||
522 | { | ||
523 | int i; | ||
524 | int estart = 0; | ||
525 | for (i = 0; i < convex.edges.Count; i++) | ||
526 | { | ||
527 | if (convex.edges[estart].p != convex.edges[i].p) | ||
528 | { | ||
529 | estart = i; | ||
530 | } | ||
531 | int inext = i + 1; | ||
532 | if (inext >= convex.edges.Count || convex.edges[inext].p != convex.edges[i].p) | ||
533 | { | ||
534 | inext = estart; | ||
535 | } | ||
536 | Debug.Assert(convex.edges[inext].p == convex.edges[i].p); | ||
537 | int nb = convex.edges[i].ea; | ||
538 | Debug.Assert(nb != 255); | ||
539 | if (nb == 255 || nb == -1) | ||
540 | return false; | ||
541 | Debug.Assert(nb != -1); | ||
542 | Debug.Assert(i == convex.edges[nb].ea); | ||
543 | } | ||
544 | for (i = 0; i < convex.edges.Count; i++) | ||
545 | { | ||
546 | Debug.Assert((0) == PlaneTest(convex.facets[convex.edges[i].p], convex.vertices[convex.edges[i].v], planetestepsilon)); | ||
547 | if ((0) != PlaneTest(convex.facets[convex.edges[i].p], convex.vertices[convex.edges[i].v], planetestepsilon)) | ||
548 | return false; | ||
549 | if (convex.edges[estart].p != convex.edges[i].p) | ||
550 | { | ||
551 | estart = i; | ||
552 | } | ||
553 | int i1 = i + 1; | ||
554 | if (i1 >= convex.edges.Count || convex.edges[i1].p != convex.edges[i].p) | ||
555 | { | ||
556 | i1 = estart; | ||
557 | } | ||
558 | int i2 = i1 + 1; | ||
559 | if (i2 >= convex.edges.Count || convex.edges[i2].p != convex.edges[i].p) | ||
560 | { | ||
561 | i2 = estart; | ||
562 | } | ||
563 | if (i == i2) // i sliced tangent to an edge and created 2 meaningless edges | ||
564 | continue; | ||
565 | float3 localnormal = TriNormal(convex.vertices[convex.edges[i].v], convex.vertices[convex.edges[i1].v], convex.vertices[convex.edges[i2].v]); | ||
566 | Debug.Assert(float3.dot(localnormal, convex.facets[convex.edges[i].p].normal) > 0); | ||
567 | if (float3.dot(localnormal, convex.facets[convex.edges[i].p].normal) <= 0) | ||
568 | return false; | ||
569 | } | ||
570 | return true; | ||
571 | } | ||
572 | |||
573 | public static ConvexH test_btbq(float planetestepsilon) | ||
574 | { | ||
575 | // back to back quads | ||
576 | ConvexH convex = new ConvexH(4, 8, 2); | ||
577 | convex.vertices[0] = new float3(0, 0, 0); | ||
578 | convex.vertices[1] = new float3(1, 0, 0); | ||
579 | convex.vertices[2] = new float3(1, 1, 0); | ||
580 | convex.vertices[3] = new float3(0, 1, 0); | ||
581 | convex.facets[0] = new Plane(new float3(0, 0, 1), 0); | ||
582 | convex.facets[1] = new Plane(new float3(0, 0, -1), 0); | ||
583 | convex.edges[0] = new ConvexH.HalfEdge(7, 0, 0); | ||
584 | convex.edges[1] = new ConvexH.HalfEdge(6, 1, 0); | ||
585 | convex.edges[2] = new ConvexH.HalfEdge(5, 2, 0); | ||
586 | convex.edges[3] = new ConvexH.HalfEdge(4, 3, 0); | ||
587 | |||
588 | convex.edges[4] = new ConvexH.HalfEdge(3, 0, 1); | ||
589 | convex.edges[5] = new ConvexH.HalfEdge(2, 3, 1); | ||
590 | convex.edges[6] = new ConvexH.HalfEdge(1, 2, 1); | ||
591 | convex.edges[7] = new ConvexH.HalfEdge(0, 1, 1); | ||
592 | AssertIntact(convex, planetestepsilon); | ||
593 | return convex; | ||
594 | } | ||
595 | |||
596 | public static ConvexH test_cube() | ||
597 | { | ||
598 | ConvexH convex = new ConvexH(8, 24, 6); | ||
599 | convex.vertices[0] = new float3(0, 0, 0); | ||
600 | convex.vertices[1] = new float3(0, 0, 1); | ||
601 | convex.vertices[2] = new float3(0, 1, 0); | ||
602 | convex.vertices[3] = new float3(0, 1, 1); | ||
603 | convex.vertices[4] = new float3(1, 0, 0); | ||
604 | convex.vertices[5] = new float3(1, 0, 1); | ||
605 | convex.vertices[6] = new float3(1, 1, 0); | ||
606 | convex.vertices[7] = new float3(1, 1, 1); | ||
607 | |||
608 | convex.facets[0] = new Plane(new float3(-1, 0, 0), 0); | ||
609 | convex.facets[1] = new Plane(new float3(1, 0, 0), -1); | ||
610 | convex.facets[2] = new Plane(new float3(0, -1, 0), 0); | ||
611 | convex.facets[3] = new Plane(new float3(0, 1, 0), -1); | ||
612 | convex.facets[4] = new Plane(new float3(0, 0, -1), 0); | ||
613 | convex.facets[5] = new Plane(new float3(0, 0, 1), -1); | ||
614 | |||
615 | convex.edges[0] = new ConvexH.HalfEdge(11, 0, 0); | ||
616 | convex.edges[1] = new ConvexH.HalfEdge(23, 1, 0); | ||
617 | convex.edges[2] = new ConvexH.HalfEdge(15, 3, 0); | ||
618 | convex.edges[3] = new ConvexH.HalfEdge(16, 2, 0); | ||
619 | |||
620 | convex.edges[4] = new ConvexH.HalfEdge(13, 6, 1); | ||
621 | convex.edges[5] = new ConvexH.HalfEdge(21, 7, 1); | ||
622 | convex.edges[6] = new ConvexH.HalfEdge(9, 5, 1); | ||
623 | convex.edges[7] = new ConvexH.HalfEdge(18, 4, 1); | ||
624 | |||
625 | convex.edges[8] = new ConvexH.HalfEdge(19, 0, 2); | ||
626 | convex.edges[9] = new ConvexH.HalfEdge(6, 4, 2); | ||
627 | convex.edges[10] = new ConvexH.HalfEdge(20, 5, 2); | ||
628 | convex.edges[11] = new ConvexH.HalfEdge(0, 1, 2); | ||
629 | |||
630 | convex.edges[12] = new ConvexH.HalfEdge(22, 3, 3); | ||
631 | convex.edges[13] = new ConvexH.HalfEdge(4, 7, 3); | ||
632 | convex.edges[14] = new ConvexH.HalfEdge(17, 6, 3); | ||
633 | convex.edges[15] = new ConvexH.HalfEdge(2, 2, 3); | ||
634 | |||
635 | convex.edges[16] = new ConvexH.HalfEdge(3, 0, 4); | ||
636 | convex.edges[17] = new ConvexH.HalfEdge(14, 2, 4); | ||
637 | convex.edges[18] = new ConvexH.HalfEdge(7, 6, 4); | ||
638 | convex.edges[19] = new ConvexH.HalfEdge(8, 4, 4); | ||
639 | |||
640 | convex.edges[20] = new ConvexH.HalfEdge(10, 1, 5); | ||
641 | convex.edges[21] = new ConvexH.HalfEdge(5, 5, 5); | ||
642 | convex.edges[22] = new ConvexH.HalfEdge(12, 7, 5); | ||
643 | convex.edges[23] = new ConvexH.HalfEdge(1, 3, 5); | ||
644 | |||
645 | return convex; | ||
646 | } | ||
647 | |||
648 | public static ConvexH ConvexHMakeCube(float3 bmin, float3 bmax) | ||
649 | { | ||
650 | ConvexH convex = test_cube(); | ||
651 | convex.vertices[0] = new float3(bmin.x, bmin.y, bmin.z); | ||
652 | convex.vertices[1] = new float3(bmin.x, bmin.y, bmax.z); | ||
653 | convex.vertices[2] = new float3(bmin.x, bmax.y, bmin.z); | ||
654 | convex.vertices[3] = new float3(bmin.x, bmax.y, bmax.z); | ||
655 | convex.vertices[4] = new float3(bmax.x, bmin.y, bmin.z); | ||
656 | convex.vertices[5] = new float3(bmax.x, bmin.y, bmax.z); | ||
657 | convex.vertices[6] = new float3(bmax.x, bmax.y, bmin.z); | ||
658 | convex.vertices[7] = new float3(bmax.x, bmax.y, bmax.z); | ||
659 | |||
660 | convex.facets[0] = new Plane(new float3(-1, 0, 0), bmin.x); | ||
661 | convex.facets[1] = new Plane(new float3(1, 0, 0), -bmax.x); | ||
662 | convex.facets[2] = new Plane(new float3(0, -1, 0), bmin.y); | ||
663 | convex.facets[3] = new Plane(new float3(0, 1, 0), -bmax.y); | ||
664 | convex.facets[4] = new Plane(new float3(0, 0, -1), bmin.z); | ||
665 | convex.facets[5] = new Plane(new float3(0, 0, 1), -bmax.z); | ||
666 | return convex; | ||
667 | } | ||
668 | |||
669 | public static ConvexH ConvexHCrop(ref ConvexH convex, Plane slice, float planetestepsilon) | ||
670 | { | ||
671 | int i; | ||
672 | int vertcountunder = 0; | ||
673 | int vertcountover = 0; | ||
674 | List<int> vertscoplanar = new List<int>(); // existing vertex members of convex that are coplanar | ||
675 | List<int> edgesplit = new List<int>(); // existing edges that members of convex that cross the splitplane | ||
676 | |||
677 | Debug.Assert(convex.edges.Count < 480); | ||
678 | |||
679 | EdgeFlag[] edgeflag = new EdgeFlag[512]; | ||
680 | VertFlag[] vertflag = new VertFlag[256]; | ||
681 | PlaneFlag[] planeflag = new PlaneFlag[128]; | ||
682 | ConvexH.HalfEdge[] tmpunderedges = new ConvexH.HalfEdge[512]; | ||
683 | Plane[] tmpunderplanes = new Plane[128]; | ||
684 | Coplanar[] coplanaredges = new Coplanar[512]; | ||
685 | int coplanaredges_num = 0; | ||
686 | |||
687 | List<float3> createdverts = new List<float3>(); | ||
688 | |||
689 | // do the side-of-plane tests | ||
690 | for (i = 0; i < convex.vertices.Count; i++) | ||
691 | { | ||
692 | vertflag[i].planetest = (byte)PlaneTest(slice, convex.vertices[i], planetestepsilon); | ||
693 | if (vertflag[i].planetest == (0)) | ||
694 | { | ||
695 | // ? vertscoplanar.Add(i); | ||
696 | vertflag[i].undermap = (byte)vertcountunder++; | ||
697 | vertflag[i].overmap = (byte)vertcountover++; | ||
698 | } | ||
699 | else if (vertflag[i].planetest == (1)) | ||
700 | { | ||
701 | vertflag[i].undermap = (byte)vertcountunder++; | ||
702 | } | ||
703 | else | ||
704 | { | ||
705 | Debug.Assert(vertflag[i].planetest == (2)); | ||
706 | vertflag[i].overmap = (byte)vertcountover++; | ||
707 | vertflag[i].undermap = 255; // for debugging purposes | ||
708 | } | ||
709 | } | ||
710 | int vertcountunderold = vertcountunder; // for debugging only | ||
711 | |||
712 | int under_edge_count = 0; | ||
713 | int underplanescount = 0; | ||
714 | int e0 = 0; | ||
715 | |||
716 | for (int currentplane = 0; currentplane < convex.facets.Count; currentplane++) | ||
717 | { | ||
718 | int estart = e0; | ||
719 | int enextface = 0; | ||
720 | int planeside = 0; | ||
721 | int e1 = e0 + 1; | ||
722 | int vout = -1; | ||
723 | int vin = -1; | ||
724 | int coplanaredge = -1; | ||
725 | do | ||
726 | { | ||
727 | |||
728 | if (e1 >= convex.edges.Count || convex.edges[e1].p != currentplane) | ||
729 | { | ||
730 | enextface = e1; | ||
731 | e1 = estart; | ||
732 | } | ||
733 | ConvexH.HalfEdge edge0 = convex.edges[e0]; | ||
734 | ConvexH.HalfEdge edge1 = convex.edges[e1]; | ||
735 | ConvexH.HalfEdge edgea = convex.edges[edge0.ea]; | ||
736 | |||
737 | planeside |= vertflag[edge0.v].planetest; | ||
738 | //if((vertflag[edge0.v].planetest & vertflag[edge1.v].planetest) == COPLANAR) { | ||
739 | // assert(ecop==-1); | ||
740 | // ecop=e; | ||
741 | //} | ||
742 | |||
743 | if (vertflag[edge0.v].planetest == (2) && vertflag[edge1.v].planetest == (2)) | ||
744 | { | ||
745 | // both endpoints over plane | ||
746 | edgeflag[e0].undermap = -1; | ||
747 | } | ||
748 | else if ((vertflag[edge0.v].planetest | vertflag[edge1.v].planetest) == (1)) | ||
749 | { | ||
750 | // at least one endpoint under, the other coplanar or under | ||
751 | |||
752 | edgeflag[e0].undermap = (short)under_edge_count; | ||
753 | tmpunderedges[under_edge_count].v = vertflag[edge0.v].undermap; | ||
754 | tmpunderedges[under_edge_count].p = (byte)underplanescount; | ||
755 | if (edge0.ea < e0) | ||
756 | { | ||
757 | // connect the neighbors | ||
758 | Debug.Assert(edgeflag[edge0.ea].undermap != -1); | ||
759 | tmpunderedges[under_edge_count].ea = edgeflag[edge0.ea].undermap; | ||
760 | tmpunderedges[edgeflag[edge0.ea].undermap].ea = (short)under_edge_count; | ||
761 | } | ||
762 | under_edge_count++; | ||
763 | } | ||
764 | else if ((vertflag[edge0.v].planetest | vertflag[edge1.v].planetest) == (0)) | ||
765 | { | ||
766 | // both endpoints coplanar | ||
767 | // must check a 3rd point to see if UNDER | ||
768 | int e2 = e1 + 1; | ||
769 | if (e2 >= convex.edges.Count || convex.edges[e2].p != currentplane) | ||
770 | { | ||
771 | e2 = estart; | ||
772 | } | ||
773 | Debug.Assert(convex.edges[e2].p == currentplane); | ||
774 | ConvexH.HalfEdge edge2 = convex.edges[e2]; | ||
775 | if (vertflag[edge2.v].planetest == (1)) | ||
776 | { | ||
777 | |||
778 | edgeflag[e0].undermap = (short)under_edge_count; | ||
779 | tmpunderedges[under_edge_count].v = vertflag[edge0.v].undermap; | ||
780 | tmpunderedges[under_edge_count].p = (byte)underplanescount; | ||
781 | tmpunderedges[under_edge_count].ea = -1; | ||
782 | // make sure this edge is added to the "coplanar" list | ||
783 | coplanaredge = under_edge_count; | ||
784 | vout = vertflag[edge0.v].undermap; | ||
785 | vin = vertflag[edge1.v].undermap; | ||
786 | under_edge_count++; | ||
787 | } | ||
788 | else | ||
789 | { | ||
790 | edgeflag[e0].undermap = -1; | ||
791 | } | ||
792 | } | ||
793 | else if (vertflag[edge0.v].planetest == (1) && vertflag[edge1.v].planetest == (2)) | ||
794 | { | ||
795 | // first is under 2nd is over | ||
796 | |||
797 | edgeflag[e0].undermap = (short)under_edge_count; | ||
798 | tmpunderedges[under_edge_count].v = vertflag[edge0.v].undermap; | ||
799 | tmpunderedges[under_edge_count].p = (byte)underplanescount; | ||
800 | if (edge0.ea < e0) | ||
801 | { | ||
802 | Debug.Assert(edgeflag[edge0.ea].undermap != -1); | ||
803 | // connect the neighbors | ||
804 | tmpunderedges[under_edge_count].ea = edgeflag[edge0.ea].undermap; | ||
805 | tmpunderedges[edgeflag[edge0.ea].undermap].ea = (short)under_edge_count; | ||
806 | vout = tmpunderedges[edgeflag[edge0.ea].undermap].v; | ||
807 | } | ||
808 | else | ||
809 | { | ||
810 | Plane p0 = convex.facets[edge0.p]; | ||
811 | Plane pa = convex.facets[edgea.p]; | ||
812 | createdverts.Add(ThreePlaneIntersection(p0, pa, slice)); | ||
813 | //createdverts.Add(PlaneProject(slice,PlaneLineIntersection(slice,convex.vertices[edge0.v],convex.vertices[edgea.v]))); | ||
814 | //createdverts.Add(PlaneLineIntersection(slice,convex.vertices[edge0.v],convex.vertices[edgea.v])); | ||
815 | vout = vertcountunder++; | ||
816 | } | ||
817 | under_edge_count++; | ||
818 | /// hmmm something to think about: i might be able to output this edge regarless of | ||
819 | // wheter or not we know v-in yet. ok i;ll try this now: | ||
820 | tmpunderedges[under_edge_count].v = (byte)vout; | ||
821 | tmpunderedges[under_edge_count].p = (byte)underplanescount; | ||
822 | tmpunderedges[under_edge_count].ea = -1; | ||
823 | coplanaredge = under_edge_count; | ||
824 | under_edge_count++; | ||
825 | |||
826 | if (vin != -1) | ||
827 | { | ||
828 | // we previously processed an edge where we came under | ||
829 | // now we know about vout as well | ||
830 | |||
831 | // ADD THIS EDGE TO THE LIST OF EDGES THAT NEED NEIGHBOR ON PARTITION PLANE!! | ||
832 | } | ||
833 | |||
834 | } | ||
835 | else if (vertflag[edge0.v].planetest == (0) && vertflag[edge1.v].planetest == (2)) | ||
836 | { | ||
837 | // first is coplanar 2nd is over | ||
838 | |||
839 | edgeflag[e0].undermap = -1; | ||
840 | vout = vertflag[edge0.v].undermap; | ||
841 | // I hate this but i have to make sure part of this face is UNDER before ouputting this vert | ||
842 | int k = estart; | ||
843 | Debug.Assert(edge0.p == currentplane); | ||
844 | while (!((planeside & 1) != 0) && k < convex.edges.Count && convex.edges[k].p == edge0.p) | ||
845 | { | ||
846 | planeside |= vertflag[convex.edges[k].v].planetest; | ||
847 | k++; | ||
848 | } | ||
849 | if ((planeside & 1) != 0) | ||
850 | { | ||
851 | tmpunderedges[under_edge_count].v = (byte)vout; | ||
852 | tmpunderedges[under_edge_count].p = (byte)underplanescount; | ||
853 | tmpunderedges[under_edge_count].ea = -1; | ||
854 | coplanaredge = under_edge_count; // hmmm should make a note of the edge # for later on | ||
855 | under_edge_count++; | ||
856 | |||
857 | } | ||
858 | } | ||
859 | else if (vertflag[edge0.v].planetest == (2) && vertflag[edge1.v].planetest == (1)) | ||
860 | { | ||
861 | // first is over next is under | ||
862 | // new vertex!!! | ||
863 | Debug.Assert(vin == -1); | ||
864 | if (e0 < edge0.ea) | ||
865 | { | ||
866 | Plane p0 = convex.facets[edge0.p]; | ||
867 | Plane pa = convex.facets[edgea.p]; | ||
868 | createdverts.Add(ThreePlaneIntersection(p0, pa, slice)); | ||
869 | //createdverts.Add(PlaneLineIntersection(slice,convex.vertices[edge0.v],convex.vertices[edgea.v])); | ||
870 | //createdverts.Add(PlaneProject(slice,PlaneLineIntersection(slice,convex.vertices[edge0.v],convex.vertices[edgea.v]))); | ||
871 | vin = vertcountunder++; | ||
872 | } | ||
873 | else | ||
874 | { | ||
875 | // find the new vertex that was created by edge[edge0.ea] | ||
876 | int nea = edgeflag[edge0.ea].undermap; | ||
877 | Debug.Assert(tmpunderedges[nea].p == tmpunderedges[nea + 1].p); | ||
878 | vin = tmpunderedges[nea + 1].v; | ||
879 | Debug.Assert(vin < vertcountunder); | ||
880 | Debug.Assert(vin >= vertcountunderold); // for debugging only | ||
881 | } | ||
882 | if (vout != -1) | ||
883 | { | ||
884 | // we previously processed an edge where we went over | ||
885 | // now we know vin too | ||
886 | // ADD THIS EDGE TO THE LIST OF EDGES THAT NEED NEIGHBOR ON PARTITION PLANE!! | ||
887 | } | ||
888 | // output edge | ||
889 | tmpunderedges[under_edge_count].v = (byte)vin; | ||
890 | tmpunderedges[under_edge_count].p = (byte)underplanescount; | ||
891 | edgeflag[e0].undermap = (short)under_edge_count; | ||
892 | if (e0 > edge0.ea) | ||
893 | { | ||
894 | Debug.Assert(edgeflag[edge0.ea].undermap != -1); | ||
895 | // connect the neighbors | ||
896 | tmpunderedges[under_edge_count].ea = edgeflag[edge0.ea].undermap; | ||
897 | tmpunderedges[edgeflag[edge0.ea].undermap].ea = (short)under_edge_count; | ||
898 | } | ||
899 | Debug.Assert(edgeflag[e0].undermap == under_edge_count); | ||
900 | under_edge_count++; | ||
901 | } | ||
902 | else if (vertflag[edge0.v].planetest == (2) && vertflag[edge1.v].planetest == (0)) | ||
903 | { | ||
904 | // first is over next is coplanar | ||
905 | |||
906 | edgeflag[e0].undermap = -1; | ||
907 | vin = vertflag[edge1.v].undermap; | ||
908 | Debug.Assert(vin != -1); | ||
909 | if (vout != -1) | ||
910 | { | ||
911 | // we previously processed an edge where we came under | ||
912 | // now we know both endpoints | ||
913 | // ADD THIS EDGE TO THE LIST OF EDGES THAT NEED NEIGHBOR ON PARTITION PLANE!! | ||
914 | } | ||
915 | |||
916 | } | ||
917 | else | ||
918 | { | ||
919 | Debug.Assert(false); | ||
920 | } | ||
921 | |||
922 | |||
923 | e0 = e1; | ||
924 | e1++; // do the modulo at the beginning of the loop | ||
925 | |||
926 | } while (e0 != estart); | ||
927 | e0 = enextface; | ||
928 | if ((planeside & 1) != 0) | ||
929 | { | ||
930 | planeflag[currentplane].undermap = (byte)underplanescount; | ||
931 | tmpunderplanes[underplanescount] = convex.facets[currentplane]; | ||
932 | underplanescount++; | ||
933 | } | ||
934 | else | ||
935 | { | ||
936 | planeflag[currentplane].undermap = 0; | ||
937 | } | ||
938 | if (vout >= 0 && (planeside & 1) != 0) | ||
939 | { | ||
940 | Debug.Assert(vin >= 0); | ||
941 | Debug.Assert(coplanaredge >= 0); | ||
942 | Debug.Assert(coplanaredge != 511); | ||
943 | coplanaredges[coplanaredges_num].ea = (ushort)coplanaredge; | ||
944 | coplanaredges[coplanaredges_num].v0 = (byte)vin; | ||
945 | coplanaredges[coplanaredges_num].v1 = (byte)vout; | ||
946 | coplanaredges_num++; | ||
947 | } | ||
948 | } | ||
949 | |||
950 | // add the new plane to the mix: | ||
951 | if (coplanaredges_num > 0) | ||
952 | { | ||
953 | tmpunderplanes[underplanescount++] = slice; | ||
954 | } | ||
955 | for (i = 0; i < coplanaredges_num - 1; i++) | ||
956 | { | ||
957 | if (coplanaredges[i].v1 != coplanaredges[i + 1].v0) | ||
958 | { | ||
959 | int j = 0; | ||
960 | for (j = i + 2; j < coplanaredges_num; j++) | ||
961 | { | ||
962 | if (coplanaredges[i].v1 == coplanaredges[j].v0) | ||
963 | { | ||
964 | Coplanar tmp = coplanaredges[i + 1]; | ||
965 | coplanaredges[i + 1] = coplanaredges[j]; | ||
966 | coplanaredges[j] = tmp; | ||
967 | break; | ||
968 | } | ||
969 | } | ||
970 | if (j >= coplanaredges_num) | ||
971 | { | ||
972 | Debug.Assert(j < coplanaredges_num); | ||
973 | return null; | ||
974 | } | ||
975 | } | ||
976 | } | ||
977 | |||
978 | ConvexH punder = new ConvexH(vertcountunder, under_edge_count + coplanaredges_num, underplanescount); | ||
979 | ConvexH under = punder; | ||
980 | |||
981 | { | ||
982 | int k = 0; | ||
983 | for (i = 0; i < convex.vertices.Count; i++) | ||
984 | { | ||
985 | if (vertflag[i].planetest != (2)) | ||
986 | { | ||
987 | under.vertices[k++] = convex.vertices[i]; | ||
988 | } | ||
989 | } | ||
990 | i = 0; | ||
991 | while (k < vertcountunder) | ||
992 | { | ||
993 | under.vertices[k++] = createdverts[i++]; | ||
994 | } | ||
995 | Debug.Assert(i == createdverts.Count); | ||
996 | } | ||
997 | |||
998 | for (i = 0; i < coplanaredges_num; i++) | ||
999 | { | ||
1000 | ConvexH.HalfEdge edge = under.edges[under_edge_count + i]; | ||
1001 | edge.p = (byte)(underplanescount - 1); | ||
1002 | edge.ea = (short)coplanaredges[i].ea; | ||
1003 | edge.v = (byte)coplanaredges[i].v0; | ||
1004 | under.edges[under_edge_count + i] = edge; | ||
1005 | |||
1006 | tmpunderedges[coplanaredges[i].ea].ea = (short)(under_edge_count + i); | ||
1007 | } | ||
1008 | |||
1009 | under.edges = new List<ConvexH.HalfEdge>(tmpunderedges); | ||
1010 | under.facets = new List<Plane>(tmpunderplanes); | ||
1011 | return punder; | ||
1012 | } | ||
1013 | |||
1014 | public static ConvexH ConvexHDup(ConvexH src) | ||
1015 | { | ||
1016 | ConvexH dst = new ConvexH(src.vertices.Count, src.edges.Count, src.facets.Count); | ||
1017 | dst.vertices = new List<float3>(src.vertices.Count); | ||
1018 | foreach (float3 f in src.vertices) | ||
1019 | dst.vertices.Add(new float3(f)); | ||
1020 | dst.edges = new List<ConvexH.HalfEdge>(src.edges.Count); | ||
1021 | foreach (ConvexH.HalfEdge e in src.edges) | ||
1022 | dst.edges.Add(new ConvexH.HalfEdge(e)); | ||
1023 | dst.facets = new List<Plane>(src.facets.Count); | ||
1024 | foreach (Plane p in src.facets) | ||
1025 | dst.facets.Add(new Plane(p)); | ||
1026 | return dst; | ||
1027 | } | ||
1028 | |||
1029 | public static int candidateplane(List<Plane> planes, int planes_count, ConvexH convex, float epsilon) | ||
1030 | { | ||
1031 | int p = 0; | ||
1032 | float md = 0; | ||
1033 | int i; | ||
1034 | for (i = 0; i < planes_count; i++) | ||
1035 | { | ||
1036 | float d = 0; | ||
1037 | for (int j = 0; j < convex.vertices.Count; j++) | ||
1038 | { | ||
1039 | d = Math.Max(d, float3.dot(convex.vertices[j], planes[i].normal) + planes[i].dist); | ||
1040 | } | ||
1041 | if (i == 0 || d > md) | ||
1042 | { | ||
1043 | p = i; | ||
1044 | md = d; | ||
1045 | } | ||
1046 | } | ||
1047 | return (md > epsilon) ? p : -1; | ||
1048 | } | ||
1049 | |||
1050 | public static float3 orth(float3 v) | ||
1051 | { | ||
1052 | float3 a = float3.cross(v, new float3(0f, 0f, 1f)); | ||
1053 | float3 b = float3.cross(v, new float3(0f, 1f, 0f)); | ||
1054 | return float3.normalize((float3.magnitude(a) > float3.magnitude(b)) ? a : b); | ||
1055 | } | ||
1056 | |||
1057 | public static int maxdir(List<float3> p, int count, float3 dir) | ||
1058 | { | ||
1059 | Debug.Assert(count != 0); | ||
1060 | int m = 0; | ||
1061 | float currDotm = float3.dot(p[0], dir); | ||
1062 | for (int i = 1; i < count; i++) | ||
1063 | { | ||
1064 | float currDoti = float3.dot(p[i], dir); | ||
1065 | if (currDoti > currDotm) | ||
1066 | { | ||
1067 | currDotm = currDoti; | ||
1068 | m = i; | ||
1069 | } | ||
1070 | } | ||
1071 | return m; | ||
1072 | } | ||
1073 | |||
1074 | public static int maxdirfiltered(List<float3> p, int count, float3 dir, byte[] allow) | ||
1075 | { | ||
1076 | //Debug.Assert(count != 0); | ||
1077 | int m = 0; | ||
1078 | float currDotm = float3.dot(p[0], dir); | ||
1079 | float currDoti; | ||
1080 | |||
1081 | while (allow[m] == 0) | ||
1082 | m++; | ||
1083 | |||
1084 | for (int i = 1; i < count; i++) | ||
1085 | { | ||
1086 | if (allow[i] != 0) | ||
1087 | { | ||
1088 | currDoti = float3.dot(p[i], dir); | ||
1089 | if (currDoti > currDotm) | ||
1090 | { | ||
1091 | currDotm = currDoti; | ||
1092 | m = i; | ||
1093 | } | ||
1094 | } | ||
1095 | } | ||
1096 | //Debug.Assert(m != -1); | ||
1097 | return m; | ||
1098 | } | ||
1099 | |||
1100 | public static int maxdirsterid(List<float3> p, int count, float3 dir, byte[] allow) | ||
1101 | { | ||
1102 | int m = -1; | ||
1103 | while (m == -1) | ||
1104 | { | ||
1105 | m = maxdirfiltered(p, count, dir, allow); | ||
1106 | if (allow[m] == 3) | ||
1107 | return m; | ||
1108 | float3 u = orth(dir); | ||
1109 | float3 v = float3.cross(u, dir); | ||
1110 | int ma = -1; | ||
1111 | for (float x = 0.0f; x <= 360.0f; x += 45.0f) | ||
1112 | { | ||
1113 | int mb; | ||
1114 | { | ||
1115 | float s = (float)Math.Sin((3.14159264f / 180.0f) * (x)); | ||
1116 | float c = (float)Math.Cos((3.14159264f / 180.0f) * (x)); | ||
1117 | mb = maxdirfiltered(p, count, dir + (u * s + v * c) * 0.025f, allow); | ||
1118 | } | ||
1119 | if (ma == m && mb == m) | ||
1120 | { | ||
1121 | allow[m] = 3; | ||
1122 | return m; | ||
1123 | } | ||
1124 | if (ma != -1 && ma != mb) // Yuck - this is really ugly | ||
1125 | { | ||
1126 | int mc = ma; | ||
1127 | for (float xx = x - 40.0f; xx <= x; xx += 5.0f) | ||
1128 | { | ||
1129 | float s = (float)Math.Sin((3.14159264f / 180.0f) * (xx)); | ||
1130 | float c = (float)Math.Cos((3.14159264f / 180.0f) * (xx)); | ||
1131 | int md = maxdirfiltered(p, count, dir + (u * s + v * c) * 0.025f, allow); | ||
1132 | if (mc == m && md == m) | ||
1133 | { | ||
1134 | allow[m] = 3; | ||
1135 | return m; | ||
1136 | } | ||
1137 | mc = md; | ||
1138 | } | ||
1139 | } | ||
1140 | ma = mb; | ||
1141 | } | ||
1142 | allow[m] = 0; | ||
1143 | m = -1; | ||
1144 | } | ||
1145 | |||
1146 | Debug.Assert(false); | ||
1147 | return m; | ||
1148 | } | ||
1149 | |||
1150 | public static int4 FindSimplex(List<float3> verts, byte[] allow) | ||
1151 | { | ||
1152 | float3[] basis = new float3[3]; | ||
1153 | basis[0] = new float3(0.01f, 0.02f, 1.0f); | ||
1154 | int p0 = maxdirsterid(verts, verts.Count, basis[0], allow); | ||
1155 | int p1 = maxdirsterid(verts, verts.Count, -basis[0], allow); | ||
1156 | basis[0] = verts[p0] - verts[p1]; | ||
1157 | if (p0 == p1 || basis[0] == new float3(0, 0, 0)) | ||
1158 | return new int4(-1, -1, -1, -1); | ||
1159 | basis[1] = float3.cross(new float3(1, 0.02f, 0), basis[0]); | ||
1160 | basis[2] = float3.cross(new float3(-0.02f, 1, 0), basis[0]); | ||
1161 | basis[1] = float3.normalize((float3.magnitude(basis[1]) > float3.magnitude(basis[2])) ? basis[1] : basis[2]); | ||
1162 | int p2 = maxdirsterid(verts, verts.Count, basis[1], allow); | ||
1163 | if (p2 == p0 || p2 == p1) | ||
1164 | { | ||
1165 | p2 = maxdirsterid(verts, verts.Count, -basis[1], allow); | ||
1166 | } | ||
1167 | if (p2 == p0 || p2 == p1) | ||
1168 | return new int4(-1, -1, -1, -1); | ||
1169 | basis[1] = verts[p2] - verts[p0]; | ||
1170 | basis[2] = float3.normalize(float3.cross(basis[1], basis[0])); | ||
1171 | int p3 = maxdirsterid(verts, verts.Count, basis[2], allow); | ||
1172 | if (p3 == p0 || p3 == p1 || p3 == p2) | ||
1173 | p3 = maxdirsterid(verts, verts.Count, -basis[2], allow); | ||
1174 | if (p3 == p0 || p3 == p1 || p3 == p2) | ||
1175 | return new int4(-1, -1, -1, -1); | ||
1176 | Debug.Assert(!(p0 == p1 || p0 == p2 || p0 == p3 || p1 == p2 || p1 == p3 || p2 == p3)); | ||
1177 | if (float3.dot(verts[p3] - verts[p0], float3.cross(verts[p1] - verts[p0], verts[p2] - verts[p0])) < 0) | ||
1178 | { | ||
1179 | Swap(ref p2, ref p3); | ||
1180 | } | ||
1181 | return new int4(p0, p1, p2, p3); | ||
1182 | } | ||
1183 | |||
1184 | public static float GetDist(float px, float py, float pz, float3 p2) | ||
1185 | { | ||
1186 | float dx = px - p2.x; | ||
1187 | float dy = py - p2.y; | ||
1188 | float dz = pz - p2.z; | ||
1189 | |||
1190 | return dx * dx + dy * dy + dz * dz; | ||
1191 | } | ||
1192 | |||
1193 | public static void ReleaseHull(PHullResult result) | ||
1194 | { | ||
1195 | if (result.Indices != null) | ||
1196 | result.Indices = null; | ||
1197 | if (result.Vertices != null) | ||
1198 | result.Vertices = null; | ||
1199 | } | ||
1200 | |||
1201 | public static int calchullgen(List<float3> verts, int vlimit, List<HullTriangle> tris) | ||
1202 | { | ||
1203 | if (verts.Count < 4) | ||
1204 | return 0; | ||
1205 | if (vlimit == 0) | ||
1206 | vlimit = 1000000000; | ||
1207 | int j; | ||
1208 | float3 bmin = new float3(verts[0]); | ||
1209 | float3 bmax = new float3(verts[0]); | ||
1210 | List<int> isextreme = new List<int>(verts.Count); | ||
1211 | byte[] allow = new byte[verts.Count]; | ||
1212 | for (j = 0; j < verts.Count; j++) | ||
1213 | { | ||
1214 | allow[j] = 1; | ||
1215 | isextreme.Add(0); | ||
1216 | bmin = float3.VectorMin(bmin, verts[j]); | ||
1217 | bmax = float3.VectorMax(bmax, verts[j]); | ||
1218 | } | ||
1219 | float epsilon = float3.magnitude(bmax - bmin) * 0.001f; | ||
1220 | |||
1221 | int4 p = FindSimplex(verts, allow); | ||
1222 | if (p.x == -1) // simplex failed | ||
1223 | return 0; | ||
1224 | |||
1225 | float3 center = (verts[p[0]] + verts[p[1]] + verts[p[2]] + verts[p[3]]) / 4.0f; // a valid interior point | ||
1226 | HullTriangle t0 = new HullTriangle(p[2], p[3], p[1], tris); | ||
1227 | t0.n = new int3(2, 3, 1); | ||
1228 | HullTriangle t1 = new HullTriangle(p[3], p[2], p[0], tris); | ||
1229 | t1.n = new int3(3, 2, 0); | ||
1230 | HullTriangle t2 = new HullTriangle(p[0], p[1], p[3], tris); | ||
1231 | t2.n = new int3(0, 1, 3); | ||
1232 | HullTriangle t3 = new HullTriangle(p[1], p[0], p[2], tris); | ||
1233 | t3.n = new int3(1, 0, 2); | ||
1234 | isextreme[p[0]] = isextreme[p[1]] = isextreme[p[2]] = isextreme[p[3]] = 1; | ||
1235 | checkit(t0, tris); | ||
1236 | checkit(t1, tris); | ||
1237 | checkit(t2, tris); | ||
1238 | checkit(t3, tris); | ||
1239 | |||
1240 | for (j = 0; j < tris.Count; j++) | ||
1241 | { | ||
1242 | HullTriangle t = tris[j]; | ||
1243 | Debug.Assert((object)t != null); | ||
1244 | Debug.Assert(t.vmax < 0); | ||
1245 | float3 n = TriNormal(verts[(t)[0]], verts[(t)[1]], verts[(t)[2]]); | ||
1246 | t.vmax = maxdirsterid(verts, verts.Count, n, allow); | ||
1247 | t.rise = float3.dot(n, verts[t.vmax] - verts[(t)[0]]); | ||
1248 | } | ||
1249 | HullTriangle te; | ||
1250 | vlimit -= 4; | ||
1251 | while (vlimit > 0 && (te = extrudable(epsilon, tris)) != null) | ||
1252 | { | ||
1253 | int3 ti = te; | ||
1254 | int v = te.vmax; | ||
1255 | Debug.Assert(isextreme[v] == 0); // wtf we've already done this vertex | ||
1256 | isextreme[v] = 1; | ||
1257 | //if(v==p0 || v==p1 || v==p2 || v==p3) continue; // done these already | ||
1258 | j = tris.Count; | ||
1259 | while (j-- != 0) | ||
1260 | { | ||
1261 | if (tris.Count <= j || (object)tris[j] == null) | ||
1262 | continue; | ||
1263 | int3 t = tris[j]; | ||
1264 | if (above(verts, t, verts[v], 0.01f * epsilon)) | ||
1265 | { | ||
1266 | extrude(tris[j], v, tris); | ||
1267 | } | ||
1268 | } | ||
1269 | // now check for those degenerate cases where we have a flipped triangle or a really skinny triangle | ||
1270 | j = tris.Count; | ||
1271 | while (j-- != 0) | ||
1272 | { | ||
1273 | if (tris.Count <= j || (object)tris[j] == null) | ||
1274 | continue; | ||
1275 | if (!hasvert(tris[j], v)) | ||
1276 | break; | ||
1277 | int3 nt = tris[j]; | ||
1278 | if (above(verts, nt, center, 0.01f * epsilon) || float3.magnitude(float3.cross(verts[nt[1]] - verts[nt[0]], verts[nt[2]] - verts[nt[1]])) < epsilon * epsilon * 0.1f) | ||
1279 | { | ||
1280 | HullTriangle nb = tris[tris[j].n[0]]; | ||
1281 | Debug.Assert(nb != null); | ||
1282 | Debug.Assert(!hasvert(nb, v)); | ||
1283 | Debug.Assert(nb.id < j); | ||
1284 | extrude(nb, v, tris); | ||
1285 | j = tris.Count; | ||
1286 | } | ||
1287 | } | ||
1288 | j = tris.Count; | ||
1289 | while (j-- != 0) | ||
1290 | { | ||
1291 | HullTriangle t = tris[j]; | ||
1292 | if (t == null) | ||
1293 | continue; | ||
1294 | if (t.vmax >= 0) | ||
1295 | break; | ||
1296 | float3 n = TriNormal(verts[(t)[0]], verts[(t)[1]], verts[(t)[2]]); | ||
1297 | t.vmax = maxdirsterid(verts, verts.Count, n, allow); | ||
1298 | if (isextreme[t.vmax] != 0) | ||
1299 | { | ||
1300 | t.vmax = -1; // already done that vertex - algorithm needs to be able to terminate. | ||
1301 | } | ||
1302 | else | ||
1303 | { | ||
1304 | t.rise = float3.dot(n, verts[t.vmax] - verts[(t)[0]]); | ||
1305 | } | ||
1306 | } | ||
1307 | vlimit--; | ||
1308 | } | ||
1309 | return 1; | ||
1310 | } | ||
1311 | |||
1312 | public static bool calchull(List<float3> verts, out List<int> tris_out, int vlimit, List<HullTriangle> tris) | ||
1313 | { | ||
1314 | tris_out = null; | ||
1315 | |||
1316 | int rc = calchullgen(verts, vlimit, tris); | ||
1317 | if (rc == 0) | ||
1318 | return false; | ||
1319 | List<int> ts = new List<int>(); | ||
1320 | for (int i = 0; i < tris.Count; i++) | ||
1321 | { | ||
1322 | if ((object)tris[i] != null) | ||
1323 | { | ||
1324 | for (int j = 0; j < 3; j++) | ||
1325 | ts.Add((tris[i])[j]); | ||
1326 | tris[i] = null; | ||
1327 | } | ||
1328 | } | ||
1329 | |||
1330 | tris_out = ts; | ||
1331 | tris.Clear(); | ||
1332 | return true; | ||
1333 | } | ||
1334 | |||
1335 | public static int calchullpbev(List<float3> verts, int vlimit, out List<Plane> planes, float bevangle, List<HullTriangle> tris) | ||
1336 | { | ||
1337 | int i; | ||
1338 | int j; | ||
1339 | planes = new List<Plane>(); | ||
1340 | int rc = calchullgen(verts, vlimit, tris); | ||
1341 | if (rc == 0) | ||
1342 | return 0; | ||
1343 | for (i = 0; i < tris.Count; i++) | ||
1344 | { | ||
1345 | if (tris[i] != null) | ||
1346 | { | ||
1347 | Plane p = new Plane(); | ||
1348 | HullTriangle t = tris[i]; | ||
1349 | p.normal = TriNormal(verts[(t)[0]], verts[(t)[1]], verts[(t)[2]]); | ||
1350 | p.dist = -float3.dot(p.normal, verts[(t)[0]]); | ||
1351 | planes.Add(p); | ||
1352 | for (j = 0; j < 3; j++) | ||
1353 | { | ||
1354 | if (t.n[j] < t.id) | ||
1355 | continue; | ||
1356 | HullTriangle s = tris[t.n[j]]; | ||
1357 | float3 snormal = TriNormal(verts[(s)[0]], verts[(s)[1]], verts[(s)[2]]); | ||
1358 | if (float3.dot(snormal, p.normal) >= Math.Cos(bevangle * (3.14159264f / 180.0f))) | ||
1359 | continue; | ||
1360 | float3 n = float3.normalize(snormal + p.normal); | ||
1361 | planes.Add(new Plane(n, -float3.dot(n, verts[maxdir(verts, verts.Count, n)]))); | ||
1362 | } | ||
1363 | } | ||
1364 | } | ||
1365 | |||
1366 | tris.Clear(); | ||
1367 | return 1; | ||
1368 | } | ||
1369 | |||
1370 | public static int overhull(List<Plane> planes, List<float3> verts, int maxplanes, out List<float3> verts_out, out List<int> faces_out, float inflate) | ||
1371 | { | ||
1372 | verts_out = null; | ||
1373 | faces_out = null; | ||
1374 | |||
1375 | int i; | ||
1376 | int j; | ||
1377 | if (verts.Count < 4) | ||
1378 | return 0; | ||
1379 | maxplanes = Math.Min(maxplanes, planes.Count); | ||
1380 | float3 bmin = new float3(verts[0]); | ||
1381 | float3 bmax = new float3(verts[0]); | ||
1382 | for (i = 0; i < verts.Count; i++) | ||
1383 | { | ||
1384 | bmin = float3.VectorMin(bmin, verts[i]); | ||
1385 | bmax = float3.VectorMax(bmax, verts[i]); | ||
1386 | } | ||
1387 | // float diameter = magnitude(bmax-bmin); | ||
1388 | // inflate *=diameter; // RELATIVE INFLATION | ||
1389 | bmin -= new float3(inflate, inflate, inflate); | ||
1390 | bmax += new float3(inflate, inflate, inflate); | ||
1391 | for (i = 0; i < planes.Count; i++) | ||
1392 | { | ||
1393 | planes[i].dist -= inflate; | ||
1394 | } | ||
1395 | float3 emin = new float3(bmin); | ||
1396 | float3 emax = new float3(bmax); | ||
1397 | float epsilon = float3.magnitude(emax - emin) * 0.025f; | ||
1398 | float planetestepsilon = float3.magnitude(emax - emin) * (0.001f); | ||
1399 | // todo: add bounding cube planes to force bevel. or try instead not adding the diameter expansion ??? must think. | ||
1400 | // ConvexH *convex = ConvexHMakeCube(bmin - float3(diameter,diameter,diameter),bmax+float3(diameter,diameter,diameter)); | ||
1401 | ConvexH c = ConvexHMakeCube(new float3(bmin), new float3(bmax)); | ||
1402 | int k; | ||
1403 | while (maxplanes-- != 0 && (k = candidateplane(planes, planes.Count, c, epsilon)) >= 0) | ||
1404 | { | ||
1405 | ConvexH tmp = c; | ||
1406 | c = ConvexHCrop(ref tmp, planes[k], planetestepsilon); | ||
1407 | if (c == null) // might want to debug this case better!!! | ||
1408 | { | ||
1409 | c = tmp; | ||
1410 | break; | ||
1411 | } | ||
1412 | if (AssertIntact(c, planetestepsilon) == false) // might want to debug this case better too!!! | ||
1413 | { | ||
1414 | c = tmp; | ||
1415 | break; | ||
1416 | } | ||
1417 | tmp.edges = null; | ||
1418 | tmp.facets = null; | ||
1419 | tmp.vertices = null; | ||
1420 | } | ||
1421 | |||
1422 | Debug.Assert(AssertIntact(c, planetestepsilon)); | ||
1423 | //return c; | ||
1424 | //C++ TO C# CONVERTER TODO TASK: The memory management function 'malloc' has no equivalent in C#: | ||
1425 | faces_out = new List<int>(); //(int)malloc(sizeof(int) * (1 + c.facets.Count + c.edges.Count)); // new int[1+c->facets.count+c->edges.count]; | ||
1426 | int faces_count_out = 0; | ||
1427 | i = 0; | ||
1428 | faces_out[faces_count_out++] = -1; | ||
1429 | k = 0; | ||
1430 | while (i < c.edges.Count) | ||
1431 | { | ||
1432 | j = 1; | ||
1433 | while (j + i < c.edges.Count && c.edges[i].p == c.edges[i + j].p) | ||
1434 | { | ||
1435 | j++; | ||
1436 | } | ||
1437 | faces_out[faces_count_out++] = j; | ||
1438 | while (j-- != 0) | ||
1439 | { | ||
1440 | faces_out[faces_count_out++] = c.edges[i].v; | ||
1441 | i++; | ||
1442 | } | ||
1443 | k++; | ||
1444 | } | ||
1445 | faces_out[0] = k; // number of faces. | ||
1446 | Debug.Assert(k == c.facets.Count); | ||
1447 | Debug.Assert(faces_count_out == 1 + c.facets.Count + c.edges.Count); | ||
1448 | verts_out = c.vertices; // new float3[c->vertices.count]; | ||
1449 | int verts_count_out = c.vertices.Count; | ||
1450 | for (i = 0; i < c.vertices.Count; i++) | ||
1451 | { | ||
1452 | verts_out[i] = new float3(c.vertices[i]); | ||
1453 | } | ||
1454 | |||
1455 | c.edges = null; | ||
1456 | c.facets = null; | ||
1457 | c.vertices = null; | ||
1458 | return 1; | ||
1459 | } | ||
1460 | |||
1461 | public static int overhullv(List<float3> verts, int maxplanes, out List<float3> verts_out, out List<int> faces_out, float inflate, float bevangle, int vlimit, List<HullTriangle> tris) | ||
1462 | { | ||
1463 | verts_out = null; | ||
1464 | faces_out = null; | ||
1465 | |||
1466 | if (verts.Count == 0) | ||
1467 | return 0; | ||
1468 | List<Plane> planes = new List<Plane>(); | ||
1469 | int rc = calchullpbev(verts, vlimit, out planes, bevangle, tris); | ||
1470 | if (rc == 0) | ||
1471 | return 0; | ||
1472 | return overhull(planes, verts, maxplanes, out verts_out, out faces_out, inflate); | ||
1473 | } | ||
1474 | |||
1475 | public static void addPoint(ref uint vcount, List<float3> p, float x, float y, float z) | ||
1476 | { | ||
1477 | p.Add(new float3(x, y, z)); | ||
1478 | vcount++; | ||
1479 | } | ||
1480 | |||
1481 | public static bool ComputeHull(List<float3> vertices, ref PHullResult result, int vlimit, float inflate) | ||
1482 | { | ||
1483 | List<HullTriangle> tris = new List<HullTriangle>(); | ||
1484 | List<int> faces; | ||
1485 | List<float3> verts_out; | ||
1486 | |||
1487 | if (inflate == 0.0f) | ||
1488 | { | ||
1489 | List<int> tris_out; | ||
1490 | bool ret = calchull(vertices, out tris_out, vlimit, tris); | ||
1491 | if (ret == false) | ||
1492 | return false; | ||
1493 | |||
1494 | result.Indices = tris_out; | ||
1495 | result.Vertices = vertices; | ||
1496 | return true; | ||
1497 | } | ||
1498 | else | ||
1499 | { | ||
1500 | int ret = overhullv(vertices, 35, out verts_out, out faces, inflate, 120.0f, vlimit, tris); | ||
1501 | if (ret == 0) | ||
1502 | return false; | ||
1503 | |||
1504 | List<int3> tris2 = new List<int3>(); | ||
1505 | int n = faces[0]; | ||
1506 | int k = 1; | ||
1507 | for (int i = 0; i < n; i++) | ||
1508 | { | ||
1509 | int pn = faces[k++]; | ||
1510 | for (int j = 2; j < pn; j++) | ||
1511 | tris2.Add(new int3(faces[k], faces[k + j - 1], faces[k + j])); | ||
1512 | k += pn; | ||
1513 | } | ||
1514 | Debug.Assert(tris2.Count == faces.Count - 1 - (n * 3)); | ||
1515 | |||
1516 | result.Indices = new List<int>(tris2.Count * 3); | ||
1517 | for (int i = 0; i < tris2.Count; i++) | ||
1518 | { | ||
1519 | result.Indices.Add(tris2[i].x); | ||
1520 | result.Indices.Add(tris2[i].y); | ||
1521 | result.Indices.Add(tris2[i].z); | ||
1522 | } | ||
1523 | result.Vertices = verts_out; | ||
1524 | |||
1525 | return true; | ||
1526 | } | ||
1527 | } | ||
1528 | |||
1529 | private static bool CleanupVertices(List<float3> svertices, out List<float3> vertices, float normalepsilon, out float3 scale) | ||
1530 | { | ||
1531 | const float EPSILON = 0.000001f; | ||
1532 | |||
1533 | vertices = new List<float3>(); | ||
1534 | scale = new float3(1f, 1f, 1f); | ||
1535 | |||
1536 | if (svertices.Count == 0) | ||
1537 | return false; | ||
1538 | |||
1539 | uint vcount = 0; | ||
1540 | |||
1541 | float[] recip = new float[3]; | ||
1542 | |||
1543 | float[] bmin = { Single.MaxValue, Single.MaxValue, Single.MaxValue }; | ||
1544 | float[] bmax = { Single.MinValue, Single.MinValue, Single.MinValue }; | ||
1545 | |||
1546 | for (int i = 0; i < svertices.Count; i++) | ||
1547 | { | ||
1548 | float3 p = svertices[i]; | ||
1549 | |||
1550 | for (int j = 0; j < 3; j++) | ||
1551 | { | ||
1552 | if (p[j] < bmin[j]) | ||
1553 | bmin[j] = p[j]; | ||
1554 | if (p[j] > bmax[j]) | ||
1555 | bmax[j] = p[j]; | ||
1556 | } | ||
1557 | } | ||
1558 | |||
1559 | float dx = bmax[0] - bmin[0]; | ||
1560 | float dy = bmax[1] - bmin[1]; | ||
1561 | float dz = bmax[2] - bmin[2]; | ||
1562 | |||
1563 | float3 center = new float3(); | ||
1564 | |||
1565 | center.x = dx * 0.5f + bmin[0]; | ||
1566 | center.y = dy * 0.5f + bmin[1]; | ||
1567 | center.z = dz * 0.5f + bmin[2]; | ||
1568 | |||
1569 | if (dx < EPSILON || dy < EPSILON || dz < EPSILON || svertices.Count < 3) | ||
1570 | { | ||
1571 | float len = Single.MaxValue; | ||
1572 | |||
1573 | if (dx > EPSILON && dx < len) | ||
1574 | len = dx; | ||
1575 | if (dy > EPSILON && dy < len) | ||
1576 | len = dy; | ||
1577 | if (dz > EPSILON && dz < len) | ||
1578 | len = dz; | ||
1579 | |||
1580 | if (len == Single.MaxValue) | ||
1581 | { | ||
1582 | dx = dy = dz = 0.01f; // one centimeter | ||
1583 | } | ||
1584 | else | ||
1585 | { | ||
1586 | if (dx < EPSILON) // 1/5th the shortest non-zero edge. | ||
1587 | dx = len * 0.05f; | ||
1588 | if (dy < EPSILON) | ||
1589 | dy = len * 0.05f; | ||
1590 | if (dz < EPSILON) | ||
1591 | dz = len * 0.05f; | ||
1592 | } | ||
1593 | |||
1594 | float x1 = center[0] - dx; | ||
1595 | float x2 = center[0] + dx; | ||
1596 | |||
1597 | float y1 = center[1] - dy; | ||
1598 | float y2 = center[1] + dy; | ||
1599 | |||
1600 | float z1 = center[2] - dz; | ||
1601 | float z2 = center[2] + dz; | ||
1602 | |||
1603 | addPoint(ref vcount, vertices, x1, y1, z1); | ||
1604 | addPoint(ref vcount, vertices, x2, y1, z1); | ||
1605 | addPoint(ref vcount, vertices, x2, y2, z1); | ||
1606 | addPoint(ref vcount, vertices, x1, y2, z1); | ||
1607 | addPoint(ref vcount, vertices, x1, y1, z2); | ||
1608 | addPoint(ref vcount, vertices, x2, y1, z2); | ||
1609 | addPoint(ref vcount, vertices, x2, y2, z2); | ||
1610 | addPoint(ref vcount, vertices, x1, y2, z2); | ||
1611 | |||
1612 | return true; // return cube | ||
1613 | } | ||
1614 | else | ||
1615 | { | ||
1616 | scale.x = dx; | ||
1617 | scale.y = dy; | ||
1618 | scale.z = dz; | ||
1619 | |||
1620 | recip[0] = 1f / dx; | ||
1621 | recip[1] = 1f / dy; | ||
1622 | recip[2] = 1f / dz; | ||
1623 | |||
1624 | center.x *= recip[0]; | ||
1625 | center.y *= recip[1]; | ||
1626 | center.z *= recip[2]; | ||
1627 | } | ||
1628 | |||
1629 | for (int i = 0; i < svertices.Count; i++) | ||
1630 | { | ||
1631 | float3 p = svertices[i]; | ||
1632 | |||
1633 | float px = p[0]; | ||
1634 | float py = p[1]; | ||
1635 | float pz = p[2]; | ||
1636 | |||
1637 | px = px * recip[0]; // normalize | ||
1638 | py = py * recip[1]; // normalize | ||
1639 | pz = pz * recip[2]; // normalize | ||
1640 | |||
1641 | if (true) | ||
1642 | { | ||
1643 | int j; | ||
1644 | |||
1645 | for (j = 0; j < vcount; j++) | ||
1646 | { | ||
1647 | float3 v = vertices[j]; | ||
1648 | |||
1649 | float x = v[0]; | ||
1650 | float y = v[1]; | ||
1651 | float z = v[2]; | ||
1652 | |||
1653 | float dx1 = Math.Abs(x - px); | ||
1654 | float dy1 = Math.Abs(y - py); | ||
1655 | float dz1 = Math.Abs(z - pz); | ||
1656 | |||
1657 | if (dx1 < normalepsilon && dy1 < normalepsilon && dz1 < normalepsilon) | ||
1658 | { | ||
1659 | // ok, it is close enough to the old one | ||
1660 | // now let us see if it is further from the center of the point cloud than the one we already recorded. | ||
1661 | // in which case we keep this one instead. | ||
1662 | float dist1 = GetDist(px, py, pz, center); | ||
1663 | float dist2 = GetDist(v[0], v[1], v[2], center); | ||
1664 | |||
1665 | if (dist1 > dist2) | ||
1666 | { | ||
1667 | v.x = px; | ||
1668 | v.y = py; | ||
1669 | v.z = pz; | ||
1670 | } | ||
1671 | |||
1672 | break; | ||
1673 | } | ||
1674 | } | ||
1675 | |||
1676 | if (j == vcount) | ||
1677 | { | ||
1678 | float3 dest = new float3(px, py, pz); | ||
1679 | vertices.Add(dest); | ||
1680 | vcount++; | ||
1681 | } | ||
1682 | } | ||
1683 | } | ||
1684 | |||
1685 | // ok..now make sure we didn't prune so many vertices it is now invalid. | ||
1686 | if (true) | ||
1687 | { | ||
1688 | float[] bmin2 = { Single.MaxValue, Single.MaxValue, Single.MaxValue }; | ||
1689 | float[] bmax2 = { Single.MinValue, Single.MinValue, Single.MinValue }; | ||
1690 | |||
1691 | for (int i = 0; i < vcount; i++) | ||
1692 | { | ||
1693 | float3 p = vertices[i]; | ||
1694 | for (int j = 0; j < 3; j++) | ||
1695 | { | ||
1696 | if (p[j] < bmin2[j]) | ||
1697 | bmin2[j] = p[j]; | ||
1698 | if (p[j] > bmax2[j]) | ||
1699 | bmax2[j] = p[j]; | ||
1700 | } | ||
1701 | } | ||
1702 | |||
1703 | float dx2 = bmax2[0] - bmin2[0]; | ||
1704 | float dy2 = bmax2[1] - bmin2[1]; | ||
1705 | float dz2 = bmax2[2] - bmin2[2]; | ||
1706 | |||
1707 | if (dx2 < EPSILON || dy2 < EPSILON || dz2 < EPSILON || vcount < 3) | ||
1708 | { | ||
1709 | float cx = dx2 * 0.5f + bmin2[0]; | ||
1710 | float cy = dy2 * 0.5f + bmin2[1]; | ||
1711 | float cz = dz2 * 0.5f + bmin2[2]; | ||
1712 | |||
1713 | float len = Single.MaxValue; | ||
1714 | |||
1715 | if (dx2 >= EPSILON && dx2 < len) | ||
1716 | len = dx2; | ||
1717 | if (dy2 >= EPSILON && dy2 < len) | ||
1718 | len = dy2; | ||
1719 | if (dz2 >= EPSILON && dz2 < len) | ||
1720 | len = dz2; | ||
1721 | |||
1722 | if (len == Single.MaxValue) | ||
1723 | { | ||
1724 | dx2 = dy2 = dz2 = 0.01f; // one centimeter | ||
1725 | } | ||
1726 | else | ||
1727 | { | ||
1728 | if (dx2 < EPSILON) // 1/5th the shortest non-zero edge. | ||
1729 | dx2 = len * 0.05f; | ||
1730 | if (dy2 < EPSILON) | ||
1731 | dy2 = len * 0.05f; | ||
1732 | if (dz2 < EPSILON) | ||
1733 | dz2 = len * 0.05f; | ||
1734 | } | ||
1735 | |||
1736 | float x1 = cx - dx2; | ||
1737 | float x2 = cx + dx2; | ||
1738 | |||
1739 | float y1 = cy - dy2; | ||
1740 | float y2 = cy + dy2; | ||
1741 | |||
1742 | float z1 = cz - dz2; | ||
1743 | float z2 = cz + dz2; | ||
1744 | |||
1745 | vcount = 0; // add box | ||
1746 | |||
1747 | addPoint(ref vcount, vertices, x1, y1, z1); | ||
1748 | addPoint(ref vcount, vertices, x2, y1, z1); | ||
1749 | addPoint(ref vcount, vertices, x2, y2, z1); | ||
1750 | addPoint(ref vcount, vertices, x1, y2, z1); | ||
1751 | addPoint(ref vcount, vertices, x1, y1, z2); | ||
1752 | addPoint(ref vcount, vertices, x2, y1, z2); | ||
1753 | addPoint(ref vcount, vertices, x2, y2, z2); | ||
1754 | addPoint(ref vcount, vertices, x1, y2, z2); | ||
1755 | |||
1756 | return true; | ||
1757 | } | ||
1758 | } | ||
1759 | |||
1760 | return true; | ||
1761 | } | ||
1762 | |||
1763 | private static void BringOutYourDead(List<float3> verts, out List<float3> overts, List<int> indices) | ||
1764 | { | ||
1765 | int[] used = new int[verts.Count]; | ||
1766 | int ocount = 0; | ||
1767 | |||
1768 | overts = new List<float3>(); | ||
1769 | |||
1770 | for (int i = 0; i < indices.Count; i++) | ||
1771 | { | ||
1772 | int v = indices[i]; // original array index | ||
1773 | |||
1774 | Debug.Assert(v >= 0 && v < verts.Count); | ||
1775 | |||
1776 | if (used[v] != 0) // if already remapped | ||
1777 | { | ||
1778 | indices[i] = used[v] - 1; // index to new array | ||
1779 | } | ||
1780 | else | ||
1781 | { | ||
1782 | indices[i] = ocount; // new index mapping | ||
1783 | |||
1784 | overts.Add(verts[v]); // copy old vert to new vert array | ||
1785 | |||
1786 | ocount++; // increment output vert count | ||
1787 | |||
1788 | Debug.Assert(ocount >= 0 && ocount <= verts.Count); | ||
1789 | |||
1790 | used[v] = ocount; // assign new index remapping | ||
1791 | } | ||
1792 | } | ||
1793 | } | ||
1794 | |||
1795 | public static HullError CreateConvexHull(HullDesc desc, ref HullResult result) | ||
1796 | { | ||
1797 | HullError ret = HullError.QE_FAIL; | ||
1798 | |||
1799 | PHullResult hr = new PHullResult(); | ||
1800 | |||
1801 | uint vcount = (uint)desc.Vertices.Count; | ||
1802 | if (vcount < 8) | ||
1803 | vcount = 8; | ||
1804 | |||
1805 | List<float3> vsource; | ||
1806 | float3 scale = new float3(); | ||
1807 | |||
1808 | bool ok = CleanupVertices(desc.Vertices, out vsource, desc.NormalEpsilon, out scale); // normalize point cloud, remove duplicates! | ||
1809 | |||
1810 | if (ok) | ||
1811 | { | ||
1812 | if (true) // scale vertices back to their original size. | ||
1813 | { | ||
1814 | for (int i = 0; i < vsource.Count; i++) | ||
1815 | { | ||
1816 | float3 v = vsource[i]; | ||
1817 | v.x *= scale[0]; | ||
1818 | v.y *= scale[1]; | ||
1819 | v.z *= scale[2]; | ||
1820 | } | ||
1821 | } | ||
1822 | |||
1823 | float skinwidth = 0; | ||
1824 | if (desc.HasHullFlag(HullFlag.QF_SKIN_WIDTH)) | ||
1825 | skinwidth = desc.SkinWidth; | ||
1826 | |||
1827 | ok = ComputeHull(vsource, ref hr, (int)desc.MaxVertices, skinwidth); | ||
1828 | |||
1829 | if (ok) | ||
1830 | { | ||
1831 | List<float3> vscratch; | ||
1832 | BringOutYourDead(hr.Vertices, out vscratch, hr.Indices); | ||
1833 | |||
1834 | ret = HullError.QE_OK; | ||
1835 | |||
1836 | if (desc.HasHullFlag(HullFlag.QF_TRIANGLES)) // if he wants the results as triangle! | ||
1837 | { | ||
1838 | result.Polygons = false; | ||
1839 | result.Indices = hr.Indices; | ||
1840 | result.OutputVertices = vscratch; | ||
1841 | } | ||
1842 | else | ||
1843 | { | ||
1844 | result.Polygons = true; | ||
1845 | result.OutputVertices = vscratch; | ||
1846 | |||
1847 | if (true) | ||
1848 | { | ||
1849 | List<int> source = hr.Indices; | ||
1850 | List<int> dest = new List<int>(); | ||
1851 | for (int i = 0; i < hr.Indices.Count / 3; i++) | ||
1852 | { | ||
1853 | dest.Add(3); | ||
1854 | dest.Add(source[i * 3 + 0]); | ||
1855 | dest.Add(source[i * 3 + 1]); | ||
1856 | dest.Add(source[i * 3 + 2]); | ||
1857 | } | ||
1858 | |||
1859 | result.Indices = dest; | ||
1860 | } | ||
1861 | } | ||
1862 | } | ||
1863 | } | ||
1864 | |||
1865 | return ret; | ||
1866 | } | ||
1867 | } | ||
1868 | } | ||
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/LICENSE.txt b/OpenSim/Region/Physics/ConvexDecompositionDotNet/LICENSE.txt new file mode 100644 index 0000000..714ae89 --- /dev/null +++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/LICENSE.txt | |||
@@ -0,0 +1,28 @@ | |||
1 | ConvexDecompositionDotNet | ||
2 | ------------------------- | ||
3 | |||
4 | The MIT License | ||
5 | |||
6 | Copyright (c) 2010 Intel Corporation. | ||
7 | All rights reserved. | ||
8 | |||
9 | Based on the convexdecomposition library from | ||
10 | <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax. | ||
11 | |||
12 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
13 | of this software and associated documentation files (the "Software"), to deal | ||
14 | in the Software without restriction, including without limitation the rights | ||
15 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
16 | copies of the Software, and to permit persons to whom the Software is | ||
17 | furnished to do so, subject to the following conditions: | ||
18 | |||
19 | The above copyright notice and this permission notice shall be included in | ||
20 | all copies or substantial portions of the Software. | ||
21 | |||
22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
23 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
24 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
25 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
26 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
27 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
28 | THE SOFTWARE. | ||
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/Plane.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/Plane.cs new file mode 100644 index 0000000..d099676 --- /dev/null +++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/Plane.cs | |||
@@ -0,0 +1,99 @@ | |||
1 | /* The MIT License | ||
2 | * | ||
3 | * Copyright (c) 2010 Intel Corporation. | ||
4 | * All rights reserved. | ||
5 | * | ||
6 | * Based on the convexdecomposition library from | ||
7 | * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax. | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
10 | * of this software and associated documentation files (the "Software"), to deal | ||
11 | * in the Software without restriction, including without limitation the rights | ||
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | * copies of the Software, and to permit persons to whom the Software is | ||
14 | * furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
25 | * THE SOFTWARE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | |||
30 | namespace OpenSim.Region.Physics.ConvexDecompositionDotNet | ||
31 | { | ||
32 | public class Plane | ||
33 | { | ||
34 | public float3 normal = new float3(); | ||
35 | public float dist; // distance below origin - the D from plane equasion Ax+By+Cz+D=0 | ||
36 | |||
37 | public Plane(float3 n, float d) | ||
38 | { | ||
39 | normal = new float3(n); | ||
40 | dist = d; | ||
41 | } | ||
42 | |||
43 | public Plane(Plane p) | ||
44 | { | ||
45 | normal = new float3(p.normal); | ||
46 | dist = p.dist; | ||
47 | } | ||
48 | |||
49 | public Plane() | ||
50 | { | ||
51 | dist = 0; | ||
52 | } | ||
53 | |||
54 | public void Transform(float3 position, Quaternion orientation) | ||
55 | { | ||
56 | // Transforms the plane to the space defined by the | ||
57 | // given position/orientation | ||
58 | float3 newNormal = Quaternion.Inverse(orientation) * normal; | ||
59 | float3 origin = Quaternion.Inverse(orientation) * (-normal * dist - position); | ||
60 | |||
61 | normal = newNormal; | ||
62 | dist = -float3.dot(newNormal, origin); | ||
63 | } | ||
64 | |||
65 | public override int GetHashCode() | ||
66 | { | ||
67 | return normal.GetHashCode() ^ dist.GetHashCode(); | ||
68 | } | ||
69 | |||
70 | public override bool Equals(object obj) | ||
71 | { | ||
72 | Plane p = obj as Plane; | ||
73 | if (p == null) | ||
74 | return false; | ||
75 | |||
76 | return this == p; | ||
77 | } | ||
78 | |||
79 | public static bool operator ==(Plane a, Plane b) | ||
80 | { | ||
81 | return (a.normal == b.normal && a.dist == b.dist); | ||
82 | } | ||
83 | |||
84 | public static bool operator !=(Plane a, Plane b) | ||
85 | { | ||
86 | return !(a == b); | ||
87 | } | ||
88 | |||
89 | public static Plane PlaneFlip(Plane plane) | ||
90 | { | ||
91 | return new Plane(-plane.normal, -plane.dist); | ||
92 | } | ||
93 | |||
94 | public static bool coplanar(Plane a, Plane b) | ||
95 | { | ||
96 | return (a == b || a == PlaneFlip(b)); | ||
97 | } | ||
98 | } | ||
99 | } | ||
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/PlaneTri.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/PlaneTri.cs new file mode 100644 index 0000000..31f0182 --- /dev/null +++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/PlaneTri.cs | |||
@@ -0,0 +1,211 @@ | |||
1 | /* The MIT License | ||
2 | * | ||
3 | * Copyright (c) 2010 Intel Corporation. | ||
4 | * All rights reserved. | ||
5 | * | ||
6 | * Based on the convexdecomposition library from | ||
7 | * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax. | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
10 | * of this software and associated documentation files (the "Software"), to deal | ||
11 | * in the Software without restriction, including without limitation the rights | ||
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | * copies of the Software, and to permit persons to whom the Software is | ||
14 | * furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
25 | * THE SOFTWARE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Diagnostics; | ||
31 | |||
32 | namespace OpenSim.Region.Physics.ConvexDecompositionDotNet | ||
33 | { | ||
34 | public enum PlaneTriResult : int | ||
35 | { | ||
36 | PTR_FRONT, | ||
37 | PTR_BACK, | ||
38 | PTR_SPLIT | ||
39 | } | ||
40 | |||
41 | public static class PlaneTri | ||
42 | { | ||
43 | private static float DistToPt(float3 p, float4 plane) | ||
44 | { | ||
45 | return p.x * plane.x + p.y * plane.y + p.z * plane.z + plane.w; | ||
46 | } | ||
47 | |||
48 | private static PlaneTriResult getSidePlane(float3 p, float4 plane, float epsilon) | ||
49 | { | ||
50 | float d = DistToPt(p, plane); | ||
51 | |||
52 | if ((d + epsilon) > 0f) | ||
53 | return PlaneTriResult.PTR_FRONT; // it is 'in front' within the provided epsilon value. | ||
54 | |||
55 | return PlaneTriResult.PTR_BACK; | ||
56 | } | ||
57 | |||
58 | private static void add(float3 p, float3[] dest, ref int pcount) | ||
59 | { | ||
60 | dest[pcount++] = new float3(p); | ||
61 | Debug.Assert(pcount <= 4); | ||
62 | } | ||
63 | |||
64 | // assumes that the points are on opposite sides of the plane! | ||
65 | private static void intersect(float3 p1, float3 p2, float3 split, float4 plane) | ||
66 | { | ||
67 | float dp1 = DistToPt(p1, plane); | ||
68 | float[] dir = new float[3]; | ||
69 | |||
70 | dir[0] = p2[0] - p1[0]; | ||
71 | dir[1] = p2[1] - p1[1]; | ||
72 | dir[2] = p2[2] - p1[2]; | ||
73 | |||
74 | float dot1 = dir[0] * plane[0] + dir[1] * plane[1] + dir[2] * plane[2]; | ||
75 | float dot2 = dp1 - plane[3]; | ||
76 | |||
77 | float t = -(plane[3] + dot2) / dot1; | ||
78 | |||
79 | split.x = (dir[0] * t) + p1[0]; | ||
80 | split.y = (dir[1] * t) + p1[1]; | ||
81 | split.z = (dir[2] * t) + p1[2]; | ||
82 | } | ||
83 | |||
84 | public static PlaneTriResult planeTriIntersection(float4 plane, FaceTri triangle, float epsilon, ref float3[] front, out int fcount, ref float3[] back, out int bcount) | ||
85 | { | ||
86 | fcount = 0; | ||
87 | bcount = 0; | ||
88 | |||
89 | // get the three vertices of the triangle. | ||
90 | float3 p1 = triangle.P1; | ||
91 | float3 p2 = triangle.P2; | ||
92 | float3 p3 = triangle.P3; | ||
93 | |||
94 | PlaneTriResult r1 = getSidePlane(p1, plane, epsilon); // compute the side of the plane each vertex is on | ||
95 | PlaneTriResult r2 = getSidePlane(p2, plane, epsilon); | ||
96 | PlaneTriResult r3 = getSidePlane(p3, plane, epsilon); | ||
97 | |||
98 | if (r1 == r2 && r1 == r3) // if all three vertices are on the same side of the plane. | ||
99 | { | ||
100 | if (r1 == PlaneTriResult.PTR_FRONT) // if all three are in front of the plane, then copy to the 'front' output triangle. | ||
101 | { | ||
102 | add(p1, front, ref fcount); | ||
103 | add(p2, front, ref fcount); | ||
104 | add(p3, front, ref fcount); | ||
105 | } | ||
106 | else | ||
107 | { | ||
108 | add(p1, back, ref bcount); // if all three are in 'back' then copy to the 'back' output triangle. | ||
109 | add(p2, back, ref bcount); | ||
110 | add(p3, back, ref bcount); | ||
111 | } | ||
112 | return r1; // if all three points are on the same side of the plane return result | ||
113 | } | ||
114 | |||
115 | // ok.. we need to split the triangle at the plane. | ||
116 | |||
117 | // First test ray segment P1 to P2 | ||
118 | if (r1 == r2) // if these are both on the same side... | ||
119 | { | ||
120 | if (r1 == PlaneTriResult.PTR_FRONT) | ||
121 | { | ||
122 | add(p1, front, ref fcount); | ||
123 | add(p2, front, ref fcount); | ||
124 | } | ||
125 | else | ||
126 | { | ||
127 | add(p1, back, ref bcount); | ||
128 | add(p2, back, ref bcount); | ||
129 | } | ||
130 | } | ||
131 | else | ||
132 | { | ||
133 | float3 split = new float3(); | ||
134 | intersect(p1, p2, split, plane); | ||
135 | |||
136 | if (r1 == PlaneTriResult.PTR_FRONT) | ||
137 | { | ||
138 | |||
139 | add(p1, front, ref fcount); | ||
140 | add(split, front, ref fcount); | ||
141 | |||
142 | add(split, back, ref bcount); | ||
143 | add(p2, back, ref bcount); | ||
144 | |||
145 | } | ||
146 | else | ||
147 | { | ||
148 | add(p1, back, ref bcount); | ||
149 | add(split, back, ref bcount); | ||
150 | |||
151 | add(split, front, ref fcount); | ||
152 | add(p2, front, ref fcount); | ||
153 | } | ||
154 | |||
155 | } | ||
156 | |||
157 | // Next test ray segment P2 to P3 | ||
158 | if (r2 == r3) // if these are both on the same side... | ||
159 | { | ||
160 | if (r3 == PlaneTriResult.PTR_FRONT) | ||
161 | { | ||
162 | add(p3, front, ref fcount); | ||
163 | } | ||
164 | else | ||
165 | { | ||
166 | add(p3, back, ref bcount); | ||
167 | } | ||
168 | } | ||
169 | else | ||
170 | { | ||
171 | float3 split = new float3(); // split the point | ||
172 | intersect(p2, p3, split, plane); | ||
173 | |||
174 | if (r3 == PlaneTriResult.PTR_FRONT) | ||
175 | { | ||
176 | add(split, front, ref fcount); | ||
177 | add(split, back, ref bcount); | ||
178 | |||
179 | add(p3, front, ref fcount); | ||
180 | } | ||
181 | else | ||
182 | { | ||
183 | add(split, front, ref fcount); | ||
184 | add(split, back, ref bcount); | ||
185 | |||
186 | add(p3, back, ref bcount); | ||
187 | } | ||
188 | } | ||
189 | |||
190 | // Next test ray segment P3 to P1 | ||
191 | if (r3 != r1) // if these are both on the same side... | ||
192 | { | ||
193 | float3 split = new float3(); // split the point | ||
194 | intersect(p3, p1, split, plane); | ||
195 | |||
196 | if (r1 == PlaneTriResult.PTR_FRONT) | ||
197 | { | ||
198 | add(split, front, ref fcount); | ||
199 | add(split, back, ref bcount); | ||
200 | } | ||
201 | else | ||
202 | { | ||
203 | add(split, front, ref fcount); | ||
204 | add(split, back, ref bcount); | ||
205 | } | ||
206 | } | ||
207 | |||
208 | return PlaneTriResult.PTR_SPLIT; | ||
209 | } | ||
210 | } | ||
211 | } | ||
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..4285e8c --- /dev/null +++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs | |||
@@ -0,0 +1,36 @@ | |||
1 | using System.Reflection; | ||
2 | using System.Runtime.CompilerServices; | ||
3 | using System.Runtime.InteropServices; | ||
4 | |||
5 | // General Information about an assembly is controlled through the following | ||
6 | // set of attributes. Change these attribute values to modify the information | ||
7 | // associated with an assembly. | ||
8 | [assembly: AssemblyTitle("ConvexDecompositionDotNet")] | ||
9 | [assembly: AssemblyDescription("")] | ||
10 | [assembly: AssemblyConfiguration("")] | ||
11 | [assembly: AssemblyCompany("Intel Corporation")] | ||
12 | [assembly: AssemblyProduct("ConvexDecompositionDotNet")] | ||
13 | [assembly: AssemblyCopyright("Copyright © Intel Corporation 2010")] | ||
14 | [assembly: AssemblyTrademark("")] | ||
15 | [assembly: AssemblyCulture("")] | ||
16 | |||
17 | // Setting ComVisible to false makes the types in this assembly not visible | ||
18 | // to COM components. If you need to access a type in this assembly from | ||
19 | // COM, set the ComVisible attribute to true on that type. | ||
20 | [assembly: ComVisible(false)] | ||
21 | |||
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM | ||
23 | [assembly: Guid("2a1c9467-1a17-4c8d-bf9f-4b4d86dd0cbb")] | ||
24 | |||
25 | // Version information for an assembly consists of the following four values: | ||
26 | // | ||
27 | // Major Version | ||
28 | // Minor Version | ||
29 | // Build Number | ||
30 | // Revision | ||
31 | // | ||
32 | // You can specify all the values or you can default the Build and Revision Numbers | ||
33 | // by using the '*' as shown below: | ||
34 | // [assembly: AssemblyVersion("1.0.*")] | ||
35 | [assembly: AssemblyVersion("1.0.0.0")] | ||
36 | [assembly: AssemblyFileVersion("1.0.0.0")] | ||
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/Quaternion.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/Quaternion.cs new file mode 100644 index 0000000..0ba8f17 --- /dev/null +++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/Quaternion.cs | |||
@@ -0,0 +1,209 @@ | |||
1 | /* The MIT License | ||
2 | * | ||
3 | * Copyright (c) 2010 Intel Corporation. | ||
4 | * All rights reserved. | ||
5 | * | ||
6 | * Based on the convexdecomposition library from | ||
7 | * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax. | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
10 | * of this software and associated documentation files (the "Software"), to deal | ||
11 | * in the Software without restriction, including without limitation the rights | ||
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | * copies of the Software, and to permit persons to whom the Software is | ||
14 | * furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
25 | * THE SOFTWARE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | |||
30 | namespace OpenSim.Region.Physics.ConvexDecompositionDotNet | ||
31 | { | ||
32 | public class Quaternion : float4 | ||
33 | { | ||
34 | public Quaternion() | ||
35 | { | ||
36 | x = y = z = 0.0f; | ||
37 | w = 1.0f; | ||
38 | } | ||
39 | |||
40 | public Quaternion(float3 v, float t) | ||
41 | { | ||
42 | v = float3.normalize(v); | ||
43 | w = (float)Math.Cos(t / 2.0f); | ||
44 | v = v * (float)Math.Sin(t / 2.0f); | ||
45 | x = v.x; | ||
46 | y = v.y; | ||
47 | z = v.z; | ||
48 | } | ||
49 | |||
50 | public Quaternion(float _x, float _y, float _z, float _w) | ||
51 | { | ||
52 | x = _x; | ||
53 | y = _y; | ||
54 | z = _z; | ||
55 | w = _w; | ||
56 | } | ||
57 | |||
58 | public float angle() | ||
59 | { | ||
60 | return (float)Math.Acos(w) * 2.0f; | ||
61 | } | ||
62 | |||
63 | public float3 axis() | ||
64 | { | ||
65 | float3 a = new float3(x, y, z); | ||
66 | if (Math.Abs(angle()) < 0.0000001f) | ||
67 | return new float3(1f, 0f, 0f); | ||
68 | return a * (1 / (float)Math.Sin(angle() / 2.0f)); | ||
69 | } | ||
70 | |||
71 | public float3 xdir() | ||
72 | { | ||
73 | return new float3(1 - 2 * (y * y + z * z), 2 * (x * y + w * z), 2 * (x * z - w * y)); | ||
74 | } | ||
75 | |||
76 | public float3 ydir() | ||
77 | { | ||
78 | return new float3(2 * (x * y - w * z), 1 - 2 * (x * x + z * z), 2 * (y * z + w * x)); | ||
79 | } | ||
80 | |||
81 | public float3 zdir() | ||
82 | { | ||
83 | return new float3(2 * (x * z + w * y), 2 * (y * z - w * x), 1 - 2 * (x * x + y * y)); | ||
84 | } | ||
85 | |||
86 | public float3x3 getmatrix() | ||
87 | { | ||
88 | return new float3x3(xdir(), ydir(), zdir()); | ||
89 | } | ||
90 | |||
91 | public static implicit operator float3x3(Quaternion q) | ||
92 | { | ||
93 | return q.getmatrix(); | ||
94 | } | ||
95 | |||
96 | public static Quaternion operator *(Quaternion a, Quaternion b) | ||
97 | { | ||
98 | Quaternion c = new Quaternion(); | ||
99 | c.w = a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z; | ||
100 | c.x = a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y; | ||
101 | c.y = a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x; | ||
102 | c.z = a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w; | ||
103 | return c; | ||
104 | } | ||
105 | |||
106 | public static float3 operator *(Quaternion q, float3 v) | ||
107 | { | ||
108 | // The following is equivalent to: | ||
109 | //return (q.getmatrix() * v); | ||
110 | float qx2 = q.x * q.x; | ||
111 | float qy2 = q.y * q.y; | ||
112 | float qz2 = q.z * q.z; | ||
113 | |||
114 | float qxqy = q.x * q.y; | ||
115 | float qxqz = q.x * q.z; | ||
116 | float qxqw = q.x * q.w; | ||
117 | float qyqz = q.y * q.z; | ||
118 | float qyqw = q.y * q.w; | ||
119 | float qzqw = q.z * q.w; | ||
120 | return new float3((1 - 2 * (qy2 + qz2)) * v.x + (2 * (qxqy - qzqw)) * v.y + (2 * (qxqz + qyqw)) * v.z, (2 * (qxqy + qzqw)) * v.x + (1 - 2 * (qx2 + qz2)) * v.y + (2 * (qyqz - qxqw)) * v.z, (2 * (qxqz - qyqw)) * v.x + (2 * (qyqz + qxqw)) * v.y + (1 - 2 * (qx2 + qy2)) * v.z); | ||
121 | } | ||
122 | |||
123 | public static Quaternion operator +(Quaternion a, Quaternion b) | ||
124 | { | ||
125 | return new Quaternion(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); | ||
126 | } | ||
127 | |||
128 | public static Quaternion operator *(Quaternion a, float b) | ||
129 | { | ||
130 | return new Quaternion(a.x *b, a.y *b, a.z *b, a.w *b); | ||
131 | } | ||
132 | |||
133 | public static Quaternion normalize(Quaternion a) | ||
134 | { | ||
135 | float m = (float)Math.Sqrt(a.w * a.w + a.x * a.x + a.y * a.y + a.z * a.z); | ||
136 | if (m < 0.000000001f) | ||
137 | { | ||
138 | a.w = 1; | ||
139 | a.x = a.y = a.z = 0; | ||
140 | return a; | ||
141 | } | ||
142 | return a * (1f / m); | ||
143 | } | ||
144 | |||
145 | public static float dot(Quaternion a, Quaternion b) | ||
146 | { | ||
147 | return (a.w * b.w + a.x * b.x + a.y * b.y + a.z * b.z); | ||
148 | } | ||
149 | |||
150 | public static Quaternion slerp(Quaternion a, Quaternion b, float interp) | ||
151 | { | ||
152 | if (dot(a, b) < 0.0) | ||
153 | { | ||
154 | a.w = -a.w; | ||
155 | a.x = -a.x; | ||
156 | a.y = -a.y; | ||
157 | a.z = -a.z; | ||
158 | } | ||
159 | float d = dot(a, b); | ||
160 | if (d >= 1.0) | ||
161 | { | ||
162 | return a; | ||
163 | } | ||
164 | float theta = (float)Math.Acos(d); | ||
165 | if (theta == 0.0f) | ||
166 | { | ||
167 | return (a); | ||
168 | } | ||
169 | return a * ((float)Math.Sin(theta - interp * theta) / (float)Math.Sin(theta)) + b * ((float)Math.Sin(interp * theta) / (float)Math.Sin(theta)); | ||
170 | } | ||
171 | |||
172 | public static Quaternion Interpolate(Quaternion q0, Quaternion q1, float alpha) | ||
173 | { | ||
174 | return slerp(q0, q1, alpha); | ||
175 | } | ||
176 | |||
177 | public static Quaternion Inverse(Quaternion q) | ||
178 | { | ||
179 | return new Quaternion(-q.x, -q.y, -q.z, q.w); | ||
180 | } | ||
181 | |||
182 | public static Quaternion YawPitchRoll(float yaw, float pitch, float roll) | ||
183 | { | ||
184 | roll *= (3.14159264f / 180.0f); | ||
185 | yaw *= (3.14159264f / 180.0f); | ||
186 | pitch *= (3.14159264f / 180.0f); | ||
187 | return new Quaternion(new float3(0.0f, 0.0f, 1.0f), yaw) * new Quaternion(new float3(1.0f, 0.0f, 0.0f), pitch) * new Quaternion(new float3(0.0f, 1.0f, 0.0f), roll); | ||
188 | } | ||
189 | |||
190 | public static float Yaw(Quaternion q) | ||
191 | { | ||
192 | float3 v = q.ydir(); | ||
193 | return (v.y == 0.0 && v.x == 0.0) ? 0.0f : (float)Math.Atan2(-v.x, v.y) * (180.0f / 3.14159264f); | ||
194 | } | ||
195 | |||
196 | public static float Pitch(Quaternion q) | ||
197 | { | ||
198 | float3 v = q.ydir(); | ||
199 | return (float)Math.Atan2(v.z, Math.Sqrt(v.x * v.x + v.y * v.y)) * (180.0f / 3.14159264f); | ||
200 | } | ||
201 | |||
202 | public static float Roll(Quaternion q) | ||
203 | { | ||
204 | q = new Quaternion(new float3(0.0f, 0.0f, 1.0f), -Yaw(q) * (3.14159264f / 180.0f)) * q; | ||
205 | q = new Quaternion(new float3(1.0f, 0.0f, 0.0f), -Pitch(q) * (3.14159264f / 180.0f)) * q; | ||
206 | return (float)Math.Atan2(-q.xdir().z, q.xdir().x) * (180.0f / 3.14159264f); | ||
207 | } | ||
208 | } | ||
209 | } | ||
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/README.txt b/OpenSim/Region/Physics/ConvexDecompositionDotNet/README.txt new file mode 100644 index 0000000..fc53ae7 --- /dev/null +++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/README.txt | |||
@@ -0,0 +1,7 @@ | |||
1 | ConvexDecompositionDotNet | ||
2 | ========================= | ||
3 | |||
4 | A C# port of the ConvexDecomposition library by John W. Ratcliff and Stan Melax. | ||
5 | The original C++ version is available at <http://codesuppository.googlecode.com/>. | ||
6 | See the blog post at <http://codesuppository.blogspot.com/2006/08/approximate-convexdecomposition.html> | ||
7 | for a thorough explanation of generating convex hulls from concave meshes. | ||
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/SplitPlane.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/SplitPlane.cs new file mode 100644 index 0000000..9f06a9a --- /dev/null +++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/SplitPlane.cs | |||
@@ -0,0 +1,265 @@ | |||
1 | /* The MIT License | ||
2 | * | ||
3 | * Copyright (c) 2010 Intel Corporation. | ||
4 | * All rights reserved. | ||
5 | * | ||
6 | * Based on the convexdecomposition library from | ||
7 | * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax. | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
10 | * of this software and associated documentation files (the "Software"), to deal | ||
11 | * in the Software without restriction, including without limitation the rights | ||
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | * copies of the Software, and to permit persons to whom the Software is | ||
14 | * furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
25 | * THE SOFTWARE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | |||
31 | namespace OpenSim.Region.Physics.ConvexDecompositionDotNet | ||
32 | { | ||
33 | public class Rect3d | ||
34 | { | ||
35 | public float[] mMin = new float[3]; | ||
36 | public float[] mMax = new float[3]; | ||
37 | |||
38 | public Rect3d() | ||
39 | { | ||
40 | } | ||
41 | |||
42 | public Rect3d(float[] bmin, float[] bmax) | ||
43 | { | ||
44 | mMin[0] = bmin[0]; | ||
45 | mMin[1] = bmin[1]; | ||
46 | mMin[2] = bmin[2]; | ||
47 | |||
48 | mMax[0] = bmax[0]; | ||
49 | mMax[1] = bmax[1]; | ||
50 | mMax[2] = bmax[2]; | ||
51 | } | ||
52 | |||
53 | public void SetMin(float[] bmin) | ||
54 | { | ||
55 | mMin[0] = bmin[0]; | ||
56 | mMin[1] = bmin[1]; | ||
57 | mMin[2] = bmin[2]; | ||
58 | } | ||
59 | |||
60 | public void SetMax(float[] bmax) | ||
61 | { | ||
62 | mMax[0] = bmax[0]; | ||
63 | mMax[1] = bmax[1]; | ||
64 | mMax[2] = bmax[2]; | ||
65 | } | ||
66 | |||
67 | public void SetMin(float x, float y, float z) | ||
68 | { | ||
69 | mMin[0] = x; | ||
70 | mMin[1] = y; | ||
71 | mMin[2] = z; | ||
72 | } | ||
73 | |||
74 | public void SetMax(float x, float y, float z) | ||
75 | { | ||
76 | mMax[0] = x; | ||
77 | mMax[1] = y; | ||
78 | mMax[2] = z; | ||
79 | } | ||
80 | } | ||
81 | |||
82 | public static class SplitPlane | ||
83 | { | ||
84 | public static bool computeSplitPlane(List<float3> vertices, List<int> indices, ref float4 plane) | ||
85 | { | ||
86 | float[] bmin = { Single.MaxValue, Single.MaxValue, Single.MaxValue }; | ||
87 | float[] bmax = { Single.MinValue, Single.MinValue, Single.MinValue }; | ||
88 | |||
89 | for (int i = 0; i < vertices.Count; i++) | ||
90 | { | ||
91 | float3 p = vertices[i]; | ||
92 | |||
93 | if (p[0] < bmin[0]) | ||
94 | bmin[0] = p[0]; | ||
95 | if (p[1] < bmin[1]) | ||
96 | bmin[1] = p[1]; | ||
97 | if (p[2] < bmin[2]) | ||
98 | bmin[2] = p[2]; | ||
99 | |||
100 | if (p[0] > bmax[0]) | ||
101 | bmax[0] = p[0]; | ||
102 | if (p[1] > bmax[1]) | ||
103 | bmax[1] = p[1]; | ||
104 | if (p[2] > bmax[2]) | ||
105 | bmax[2] = p[2]; | ||
106 | } | ||
107 | |||
108 | float dx = bmax[0] - bmin[0]; | ||
109 | float dy = bmax[1] - bmin[1]; | ||
110 | float dz = bmax[2] - bmin[2]; | ||
111 | |||
112 | float laxis = dx; | ||
113 | |||
114 | int axis = 0; | ||
115 | |||
116 | if (dy > dx) | ||
117 | { | ||
118 | axis = 1; | ||
119 | laxis = dy; | ||
120 | } | ||
121 | |||
122 | if (dz > dx && dz > dy) | ||
123 | { | ||
124 | axis = 2; | ||
125 | laxis = dz; | ||
126 | } | ||
127 | |||
128 | float[] p1 = new float[3]; | ||
129 | float[] p2 = new float[3]; | ||
130 | float[] p3 = new float[3]; | ||
131 | |||
132 | p3[0] = p2[0] = p1[0] = bmin[0] + dx * 0.5f; | ||
133 | p3[1] = p2[1] = p1[1] = bmin[1] + dy * 0.5f; | ||
134 | p3[2] = p2[2] = p1[2] = bmin[2] + dz * 0.5f; | ||
135 | |||
136 | Rect3d b = new Rect3d(bmin, bmax); | ||
137 | |||
138 | Rect3d b1 = new Rect3d(); | ||
139 | Rect3d b2 = new Rect3d(); | ||
140 | |||
141 | splitRect(axis, b, b1, b2, p1); | ||
142 | |||
143 | switch (axis) | ||
144 | { | ||
145 | case 0: | ||
146 | p2[1] = bmin[1]; | ||
147 | p2[2] = bmin[2]; | ||
148 | |||
149 | if (dz > dy) | ||
150 | { | ||
151 | p3[1] = bmax[1]; | ||
152 | p3[2] = bmin[2]; | ||
153 | } | ||
154 | else | ||
155 | { | ||
156 | p3[1] = bmin[1]; | ||
157 | p3[2] = bmax[2]; | ||
158 | } | ||
159 | |||
160 | break; | ||
161 | case 1: | ||
162 | p2[0] = bmin[0]; | ||
163 | p2[2] = bmin[2]; | ||
164 | |||
165 | if (dx > dz) | ||
166 | { | ||
167 | p3[0] = bmax[0]; | ||
168 | p3[2] = bmin[2]; | ||
169 | } | ||
170 | else | ||
171 | { | ||
172 | p3[0] = bmin[0]; | ||
173 | p3[2] = bmax[2]; | ||
174 | } | ||
175 | |||
176 | break; | ||
177 | case 2: | ||
178 | p2[0] = bmin[0]; | ||
179 | p2[1] = bmin[1]; | ||
180 | |||
181 | if (dx > dy) | ||
182 | { | ||
183 | p3[0] = bmax[0]; | ||
184 | p3[1] = bmin[1]; | ||
185 | } | ||
186 | else | ||
187 | { | ||
188 | p3[0] = bmin[0]; | ||
189 | p3[1] = bmax[1]; | ||
190 | } | ||
191 | |||
192 | break; | ||
193 | } | ||
194 | |||
195 | computePlane(p1, p2, p3, plane); | ||
196 | |||
197 | return true; | ||
198 | } | ||
199 | |||
200 | internal static void computePlane(float[] A, float[] B, float[] C, float4 plane) | ||
201 | { | ||
202 | float vx = (B[0] - C[0]); | ||
203 | float vy = (B[1] - C[1]); | ||
204 | float vz = (B[2] - C[2]); | ||
205 | |||
206 | float wx = (A[0] - B[0]); | ||
207 | float wy = (A[1] - B[1]); | ||
208 | float wz = (A[2] - B[2]); | ||
209 | |||
210 | float vw_x = vy * wz - vz * wy; | ||
211 | float vw_y = vz * wx - vx * wz; | ||
212 | float vw_z = vx * wy - vy * wx; | ||
213 | |||
214 | float mag = (float)Math.Sqrt((vw_x * vw_x) + (vw_y * vw_y) + (vw_z * vw_z)); | ||
215 | |||
216 | if (mag < 0.000001f) | ||
217 | { | ||
218 | mag = 0; | ||
219 | } | ||
220 | else | ||
221 | { | ||
222 | mag = 1.0f / mag; | ||
223 | } | ||
224 | |||
225 | float x = vw_x * mag; | ||
226 | float y = vw_y * mag; | ||
227 | float z = vw_z * mag; | ||
228 | |||
229 | float D = 0.0f - ((x * A[0]) + (y * A[1]) + (z * A[2])); | ||
230 | |||
231 | plane.x = x; | ||
232 | plane.y = y; | ||
233 | plane.z = z; | ||
234 | plane.w = D; | ||
235 | } | ||
236 | |||
237 | public static void splitRect(int axis, Rect3d source, Rect3d b1, Rect3d b2, float[] midpoint) | ||
238 | { | ||
239 | switch (axis) | ||
240 | { | ||
241 | case 0: | ||
242 | b1.SetMin(source.mMin); | ||
243 | b1.SetMax(midpoint[0], source.mMax[1], source.mMax[2]); | ||
244 | |||
245 | b2.SetMin(midpoint[0], source.mMin[1], source.mMin[2]); | ||
246 | b2.SetMax(source.mMax); | ||
247 | break; | ||
248 | case 1: | ||
249 | b1.SetMin(source.mMin); | ||
250 | b1.SetMax(source.mMax[0], midpoint[1], source.mMax[2]); | ||
251 | |||
252 | b2.SetMin(source.mMin[0], midpoint[1], source.mMin[2]); | ||
253 | b2.SetMax(source.mMax); | ||
254 | break; | ||
255 | case 2: | ||
256 | b1.SetMin(source.mMin); | ||
257 | b1.SetMax(source.mMax[0], source.mMax[1], midpoint[2]); | ||
258 | |||
259 | b2.SetMin(source.mMin[0], source.mMin[1], midpoint[2]); | ||
260 | b2.SetMax(source.mMax); | ||
261 | break; | ||
262 | } | ||
263 | } | ||
264 | } | ||
265 | } | ||
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/VertexLookup.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/VertexLookup.cs new file mode 100644 index 0000000..6f17c9f --- /dev/null +++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/VertexLookup.cs | |||
@@ -0,0 +1,70 @@ | |||
1 | /* The MIT License | ||
2 | * | ||
3 | * Copyright (c) 2010 Intel Corporation. | ||
4 | * All rights reserved. | ||
5 | * | ||
6 | * Based on the convexdecomposition library from | ||
7 | * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax. | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
10 | * of this software and associated documentation files (the "Software"), to deal | ||
11 | * in the Software without restriction, including without limitation the rights | ||
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | * copies of the Software, and to permit persons to whom the Software is | ||
14 | * furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
25 | * THE SOFTWARE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | |||
31 | namespace OpenSim.Region.Physics.ConvexDecompositionDotNet | ||
32 | { | ||
33 | public class VertexPool | ||
34 | { | ||
35 | private List<float3> mVertices = new List<float3>(); | ||
36 | private Dictionary<float3, int> mIndices = new Dictionary<float3, int>(); | ||
37 | |||
38 | public int getIndex(float3 vtx) | ||
39 | { | ||
40 | int idx; | ||
41 | if (mIndices.TryGetValue(vtx, out idx)) | ||
42 | return idx; | ||
43 | |||
44 | idx = mVertices.Count; | ||
45 | mVertices.Add(vtx); | ||
46 | mIndices.Add(vtx, idx); | ||
47 | return idx; | ||
48 | } | ||
49 | |||
50 | public float3 Get(int idx) | ||
51 | { | ||
52 | return mVertices[idx]; | ||
53 | } | ||
54 | |||
55 | public int GetSize() | ||
56 | { | ||
57 | return mVertices.Count; | ||
58 | } | ||
59 | |||
60 | public List<float3> GetVertices() | ||
61 | { | ||
62 | return mVertices; | ||
63 | } | ||
64 | |||
65 | public void Clear() | ||
66 | { | ||
67 | mVertices.Clear(); | ||
68 | } | ||
69 | } | ||
70 | } | ||
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/float2.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/float2.cs new file mode 100644 index 0000000..ce88fc8 --- /dev/null +++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/float2.cs | |||
@@ -0,0 +1,70 @@ | |||
1 | /* The MIT License | ||
2 | * | ||
3 | * Copyright (c) 2010 Intel Corporation. | ||
4 | * All rights reserved. | ||
5 | * | ||
6 | * Based on the convexdecomposition library from | ||
7 | * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax. | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
10 | * of this software and associated documentation files (the "Software"), to deal | ||
11 | * in the Software without restriction, including without limitation the rights | ||
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | * copies of the Software, and to permit persons to whom the Software is | ||
14 | * furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
25 | * THE SOFTWARE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | |||
30 | namespace OpenSim.Region.Physics.ConvexDecompositionDotNet | ||
31 | { | ||
32 | public class float2 | ||
33 | { | ||
34 | public float x; | ||
35 | public float y; | ||
36 | |||
37 | public float2() | ||
38 | { | ||
39 | } | ||
40 | |||
41 | public float2(float _x, float _y) | ||
42 | { | ||
43 | x = _x; | ||
44 | y = _y; | ||
45 | } | ||
46 | |||
47 | public float this[int i] | ||
48 | { | ||
49 | get | ||
50 | { | ||
51 | switch (i) | ||
52 | { | ||
53 | case 0: return x; | ||
54 | case 1: return y; | ||
55 | } | ||
56 | throw new ArgumentOutOfRangeException(); | ||
57 | } | ||
58 | } | ||
59 | |||
60 | public static float2 operator -(float2 a, float2 b) | ||
61 | { | ||
62 | return new float2(a.x - b.x, a.y - b.y); | ||
63 | } | ||
64 | |||
65 | public static float2 operator +(float2 a, float2 b) | ||
66 | { | ||
67 | return new float2(a.x + b.x, a.y + b.y); | ||
68 | } | ||
69 | } | ||
70 | } | ||
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/float3.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/float3.cs new file mode 100644 index 0000000..4389114 --- /dev/null +++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/float3.cs | |||
@@ -0,0 +1,444 @@ | |||
1 | /* The MIT License | ||
2 | * | ||
3 | * Copyright (c) 2010 Intel Corporation. | ||
4 | * All rights reserved. | ||
5 | * | ||
6 | * Based on the convexdecomposition library from | ||
7 | * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax. | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
10 | * of this software and associated documentation files (the "Software"), to deal | ||
11 | * in the Software without restriction, including without limitation the rights | ||
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | * copies of the Software, and to permit persons to whom the Software is | ||
14 | * furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
25 | * THE SOFTWARE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | |||
30 | namespace OpenSim.Region.Physics.ConvexDecompositionDotNet | ||
31 | { | ||
32 | public class float3 : IEquatable<float3> | ||
33 | { | ||
34 | public float x; | ||
35 | public float y; | ||
36 | public float z; | ||
37 | |||
38 | public float3() | ||
39 | { | ||
40 | x = 0; | ||
41 | y = 0; | ||
42 | z = 0; | ||
43 | } | ||
44 | |||
45 | public float3(float _x, float _y, float _z) | ||
46 | { | ||
47 | x = _x; | ||
48 | y = _y; | ||
49 | z = _z; | ||
50 | } | ||
51 | |||
52 | public float3(float3 f) | ||
53 | { | ||
54 | x = f.x; | ||
55 | y = f.y; | ||
56 | z = f.z; | ||
57 | } | ||
58 | |||
59 | public float this[int i] | ||
60 | { | ||
61 | get | ||
62 | { | ||
63 | switch (i) | ||
64 | { | ||
65 | case 0: return x; | ||
66 | case 1: return y; | ||
67 | case 2: return z; | ||
68 | } | ||
69 | throw new ArgumentOutOfRangeException(); | ||
70 | } | ||
71 | } | ||
72 | |||
73 | public float Distance(float3 a) | ||
74 | { | ||
75 | float3 d = new float3(a.x - x, a.y - y, a.z - z); | ||
76 | return d.Length(); | ||
77 | } | ||
78 | |||
79 | public float Distance2(float3 a) | ||
80 | { | ||
81 | float dx = a.x - x; | ||
82 | float dy = a.y - y; | ||
83 | float dz = a.z - z; | ||
84 | return dx * dx + dy * dy + dz * dz; | ||
85 | } | ||
86 | |||
87 | public float Length() | ||
88 | { | ||
89 | return (float)Math.Sqrt(x * x + y * y + z * z); | ||
90 | } | ||
91 | |||
92 | public float Area(float3 p1, float3 p2) | ||
93 | { | ||
94 | float A = Partial(p1); | ||
95 | A += p1.Partial(p2); | ||
96 | A += p2.Partial(this); | ||
97 | return A * 0.5f; | ||
98 | } | ||
99 | |||
100 | public float Partial(float3 p) | ||
101 | { | ||
102 | return (x * p.y) - (p.x * y); | ||
103 | } | ||
104 | |||
105 | // Given a point and a line (defined by two points), compute the closest point | ||
106 | // in the line. (The line is treated as infinitely long.) | ||
107 | public void NearestPointInLine(float3 point, float3 line0, float3 line1) | ||
108 | { | ||
109 | float3 nearestPoint = new float3(); | ||
110 | float3 lineDelta = line1 - line0; | ||
111 | |||
112 | // Handle degenerate lines | ||
113 | if (lineDelta == float3.Zero) | ||
114 | { | ||
115 | nearestPoint = line0; | ||
116 | } | ||
117 | else | ||
118 | { | ||
119 | float delta = float3.dot(point - line0, lineDelta) / float3.dot(lineDelta, lineDelta); | ||
120 | nearestPoint = line0 + lineDelta * delta; | ||
121 | } | ||
122 | |||
123 | this.x = nearestPoint.x; | ||
124 | this.y = nearestPoint.y; | ||
125 | this.z = nearestPoint.z; | ||
126 | } | ||
127 | |||
128 | // Given a point and a line segment (defined by two points), compute the closest point | ||
129 | // in the line. Cap the point at the endpoints of the line segment. | ||
130 | public void NearestPointInLineSegment(float3 point, float3 line0, float3 line1) | ||
131 | { | ||
132 | float3 nearestPoint = new float3(); | ||
133 | float3 lineDelta = line1 - line0; | ||
134 | |||
135 | // Handle degenerate lines | ||
136 | if (lineDelta == Zero) | ||
137 | { | ||
138 | nearestPoint = line0; | ||
139 | } | ||
140 | else | ||
141 | { | ||
142 | float delta = float3.dot(point - line0, lineDelta) / float3.dot(lineDelta, lineDelta); | ||
143 | |||
144 | // Clamp the point to conform to the segment's endpoints | ||
145 | if (delta < 0) | ||
146 | delta = 0; | ||
147 | else if (delta > 1) | ||
148 | delta = 1; | ||
149 | |||
150 | nearestPoint = line0 + lineDelta * delta; | ||
151 | } | ||
152 | |||
153 | this.x = nearestPoint.x; | ||
154 | this.y = nearestPoint.y; | ||
155 | this.z = nearestPoint.z; | ||
156 | } | ||
157 | |||
158 | // Given a point and a triangle (defined by three points), compute the closest point | ||
159 | // in the triangle. Clamp the point so it's confined to the area of the triangle. | ||
160 | public void NearestPointInTriangle(float3 point, float3 triangle0, float3 triangle1, float3 triangle2) | ||
161 | { | ||
162 | float3 nearestPoint = new float3(); | ||
163 | |||
164 | float3 lineDelta0 = triangle1 - triangle0; | ||
165 | float3 lineDelta1 = triangle2 - triangle0; | ||
166 | |||
167 | // Handle degenerate triangles | ||
168 | if ((lineDelta0 == Zero) || (lineDelta1 == Zero)) | ||
169 | { | ||
170 | nearestPoint.NearestPointInLineSegment(point, triangle1, triangle2); | ||
171 | } | ||
172 | else if (lineDelta0 == lineDelta1) | ||
173 | { | ||
174 | nearestPoint.NearestPointInLineSegment(point, triangle0, triangle1); | ||
175 | } | ||
176 | else | ||
177 | { | ||
178 | float3[] axis = new float3[3] { new float3(), new float3(), new float3() }; | ||
179 | axis[0].NearestPointInLine(triangle0, triangle1, triangle2); | ||
180 | axis[1].NearestPointInLine(triangle1, triangle0, triangle2); | ||
181 | axis[2].NearestPointInLine(triangle2, triangle0, triangle1); | ||
182 | |||
183 | float3 axisDot = new float3(); | ||
184 | axisDot.x = dot(triangle0 - axis[0], point - axis[0]); | ||
185 | axisDot.y = dot(triangle1 - axis[1], point - axis[1]); | ||
186 | axisDot.z = dot(triangle2 - axis[2], point - axis[2]); | ||
187 | |||
188 | bool bForce = true; | ||
189 | float bestMagnitude2 = 0; | ||
190 | float closeMagnitude2; | ||
191 | float3 closePoint = new float3(); | ||
192 | |||
193 | if (axisDot.x < 0f) | ||
194 | { | ||
195 | closePoint.NearestPointInLineSegment(point, triangle1, triangle2); | ||
196 | closeMagnitude2 = point.Distance2(closePoint); | ||
197 | if (bForce || (bestMagnitude2 > closeMagnitude2)) | ||
198 | { | ||
199 | bForce = false; | ||
200 | bestMagnitude2 = closeMagnitude2; | ||
201 | nearestPoint = closePoint; | ||
202 | } | ||
203 | } | ||
204 | if (axisDot.y < 0f) | ||
205 | { | ||
206 | closePoint.NearestPointInLineSegment(point, triangle0, triangle2); | ||
207 | closeMagnitude2 = point.Distance2(closePoint); | ||
208 | if (bForce || (bestMagnitude2 > closeMagnitude2)) | ||
209 | { | ||
210 | bForce = false; | ||
211 | bestMagnitude2 = closeMagnitude2; | ||
212 | nearestPoint = closePoint; | ||
213 | } | ||
214 | } | ||
215 | if (axisDot.z < 0f) | ||
216 | { | ||
217 | closePoint.NearestPointInLineSegment(point, triangle0, triangle1); | ||
218 | closeMagnitude2 = point.Distance2(closePoint); | ||
219 | if (bForce || (bestMagnitude2 > closeMagnitude2)) | ||
220 | { | ||
221 | bForce = false; | ||
222 | bestMagnitude2 = closeMagnitude2; | ||
223 | nearestPoint = closePoint; | ||
224 | } | ||
225 | } | ||
226 | |||
227 | // If bForce is true at this point, it means the nearest point lies | ||
228 | // inside the triangle; use the nearest-point-on-a-plane equation | ||
229 | if (bForce) | ||
230 | { | ||
231 | float3 normal; | ||
232 | |||
233 | // Get the normal of the polygon (doesn't have to be a unit vector) | ||
234 | normal = float3.cross(lineDelta0, lineDelta1); | ||
235 | |||
236 | float3 pointDelta = point - triangle0; | ||
237 | float delta = float3.dot(normal, pointDelta) / float3.dot(normal, normal); | ||
238 | |||
239 | nearestPoint = point - normal * delta; | ||
240 | } | ||
241 | } | ||
242 | |||
243 | this.x = nearestPoint.x; | ||
244 | this.y = nearestPoint.y; | ||
245 | this.z = nearestPoint.z; | ||
246 | } | ||
247 | |||
248 | public static float3 operator +(float3 a, float3 b) | ||
249 | { | ||
250 | return new float3(a.x + b.x, a.y + b.y, a.z + b.z); | ||
251 | } | ||
252 | |||
253 | public static float3 operator -(float3 a, float3 b) | ||
254 | { | ||
255 | return new float3(a.x - b.x, a.y - b.y, a.z - b.z); | ||
256 | } | ||
257 | |||
258 | public static float3 operator -(float3 a, float s) | ||
259 | { | ||
260 | return new float3(a.x - s, a.y - s, a.z - s); | ||
261 | } | ||
262 | |||
263 | public static float3 operator -(float3 v) | ||
264 | { | ||
265 | return new float3(-v.x, -v.y, -v.z); | ||
266 | } | ||
267 | |||
268 | public static float3 operator *(float3 v, float s) | ||
269 | { | ||
270 | return new float3(v.x * s, v.y * s, v.z * s); | ||
271 | } | ||
272 | |||
273 | public static float3 operator *(float s, float3 v) | ||
274 | { | ||
275 | return new float3(v.x * s, v.y * s, v.z * s); | ||
276 | } | ||
277 | |||
278 | public static float3 operator *(float3 v, float3x3 m) | ||
279 | { | ||
280 | return new float3((m.x.x * v.x + m.y.x * v.y + m.z.x * v.z), (m.x.y * v.x + m.y.y * v.y + m.z.y * v.z), (m.x.z * v.x + m.y.z * v.y + m.z.z * v.z)); | ||
281 | } | ||
282 | |||
283 | public static float3 operator *(float3x3 m, float3 v) | ||
284 | { | ||
285 | return new float3(dot(m.x, v), dot(m.y, v), dot(m.z, v)); | ||
286 | } | ||
287 | |||
288 | public static float3 operator /(float3 v, float s) | ||
289 | { | ||
290 | float sinv = 1.0f / s; | ||
291 | return new float3(v.x * sinv, v.y * sinv, v.z * sinv); | ||
292 | } | ||
293 | |||
294 | public bool Equals(float3 other) | ||
295 | { | ||
296 | return this == other; | ||
297 | } | ||
298 | |||
299 | public override bool Equals(object obj) | ||
300 | { | ||
301 | float3 f = obj as float3; | ||
302 | if (f == null) | ||
303 | return false; | ||
304 | |||
305 | return this == f; | ||
306 | } | ||
307 | |||
308 | public override int GetHashCode() | ||
309 | { | ||
310 | return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode(); | ||
311 | } | ||
312 | |||
313 | public static bool operator ==(float3 a, float3 b) | ||
314 | { | ||
315 | // If both are null, or both are same instance, return true. | ||
316 | if (System.Object.ReferenceEquals(a, b)) | ||
317 | return true; | ||
318 | // If one is null, but not both, return false. | ||
319 | if (((object)a == null) || ((object)b == null)) | ||
320 | return false; | ||
321 | |||
322 | return (a.x == b.x && a.y == b.y && a.z == b.z); | ||
323 | } | ||
324 | |||
325 | public static bool operator !=(float3 a, float3 b) | ||
326 | { | ||
327 | return (a.x != b.x || a.y != b.y || a.z != b.z); | ||
328 | } | ||
329 | |||
330 | public static float dot(float3 a, float3 b) | ||
331 | { | ||
332 | return a.x * b.x + a.y * b.y + a.z * b.z; | ||
333 | } | ||
334 | |||
335 | public static float3 cmul(float3 v1, float3 v2) | ||
336 | { | ||
337 | return new float3(v1.x * v2.x, v1.y * v2.y, v1.z * v2.z); | ||
338 | } | ||
339 | |||
340 | public static float3 cross(float3 a, float3 b) | ||
341 | { | ||
342 | return new float3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); | ||
343 | } | ||
344 | |||
345 | public static float3 Interpolate(float3 v0, float3 v1, float alpha) | ||
346 | { | ||
347 | return v0 * (1 - alpha) + v1 * alpha; | ||
348 | } | ||
349 | |||
350 | public static float3 Round(float3 a, int digits) | ||
351 | { | ||
352 | return new float3((float)Math.Round(a.x, digits), (float)Math.Round(a.y, digits), (float)Math.Round(a.z, digits)); | ||
353 | } | ||
354 | |||
355 | public static float3 VectorMax(float3 a, float3 b) | ||
356 | { | ||
357 | return new float3(Math.Max(a.x, b.x), Math.Max(a.y, b.y), Math.Max(a.z, b.z)); | ||
358 | } | ||
359 | |||
360 | public static float3 VectorMin(float3 a, float3 b) | ||
361 | { | ||
362 | return new float3(Math.Min(a.x, b.x), Math.Min(a.y, b.y), Math.Min(a.z, b.z)); | ||
363 | } | ||
364 | |||
365 | public static float3 vabs(float3 v) | ||
366 | { | ||
367 | return new float3(Math.Abs(v.x), Math.Abs(v.y), Math.Abs(v.z)); | ||
368 | } | ||
369 | |||
370 | public static float magnitude(float3 v) | ||
371 | { | ||
372 | return (float)Math.Sqrt(v.x * v.x + v.y * v.y + v.z * v.z); | ||
373 | } | ||
374 | |||
375 | public static float3 normalize(float3 v) | ||
376 | { | ||
377 | float d = magnitude(v); | ||
378 | if (d == 0) | ||
379 | d = 0.1f; | ||
380 | d = 1 / d; | ||
381 | return new float3(v.x * d, v.y * d, v.z * d); | ||
382 | } | ||
383 | |||
384 | public static float3 safenormalize(float3 v) | ||
385 | { | ||
386 | if (magnitude(v) <= 0.0f) | ||
387 | return new float3(1, 0, 0); | ||
388 | else | ||
389 | return normalize(v); | ||
390 | } | ||
391 | |||
392 | public static float Yaw(float3 v) | ||
393 | { | ||
394 | return (v.y == 0.0 && v.x == 0.0) ? 0.0f : (float)Math.Atan2(-v.x, v.y) * (180.0f / 3.14159264f); | ||
395 | } | ||
396 | |||
397 | public static float Pitch(float3 v) | ||
398 | { | ||
399 | return (float)Math.Atan2(v.z, Math.Sqrt(v.x * v.x + v.y * v.y)) * (180.0f / 3.14159264f); | ||
400 | } | ||
401 | |||
402 | public float ComputePlane(float3 A, float3 B, float3 C) | ||
403 | { | ||
404 | float vx, vy, vz, wx, wy, wz, vw_x, vw_y, vw_z, mag; | ||
405 | |||
406 | vx = (B.x - C.x); | ||
407 | vy = (B.y - C.y); | ||
408 | vz = (B.z - C.z); | ||
409 | |||
410 | wx = (A.x - B.x); | ||
411 | wy = (A.y - B.y); | ||
412 | wz = (A.z - B.z); | ||
413 | |||
414 | vw_x = vy * wz - vz * wy; | ||
415 | vw_y = vz * wx - vx * wz; | ||
416 | vw_z = vx * wy - vy * wx; | ||
417 | |||
418 | mag = (float)Math.Sqrt((vw_x * vw_x) + (vw_y * vw_y) + (vw_z * vw_z)); | ||
419 | |||
420 | if (mag < 0.000001f) | ||
421 | { | ||
422 | mag = 0; | ||
423 | } | ||
424 | else | ||
425 | { | ||
426 | mag = 1.0f / mag; | ||
427 | } | ||
428 | |||
429 | x = vw_x * mag; | ||
430 | y = vw_y * mag; | ||
431 | z = vw_z * mag; | ||
432 | |||
433 | float D = 0.0f - ((x * A.x) + (y * A.y) + (z * A.z)); | ||
434 | return D; | ||
435 | } | ||
436 | |||
437 | public override string ToString() | ||
438 | { | ||
439 | return String.Format("<{0}, {1}, {2}>", x, y, z); | ||
440 | } | ||
441 | |||
442 | public static readonly float3 Zero = new float3(); | ||
443 | } | ||
444 | } | ||
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/float3x3.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/float3x3.cs new file mode 100644 index 0000000..76cf063 --- /dev/null +++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/float3x3.cs | |||
@@ -0,0 +1,195 @@ | |||
1 | /* The MIT License | ||
2 | * | ||
3 | * Copyright (c) 2010 Intel Corporation. | ||
4 | * All rights reserved. | ||
5 | * | ||
6 | * Based on the convexdecomposition library from | ||
7 | * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax. | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
10 | * of this software and associated documentation files (the "Software"), to deal | ||
11 | * in the Software without restriction, including without limitation the rights | ||
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | * copies of the Software, and to permit persons to whom the Software is | ||
14 | * furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
25 | * THE SOFTWARE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Diagnostics; | ||
31 | |||
32 | namespace OpenSim.Region.Physics.ConvexDecompositionDotNet | ||
33 | { | ||
34 | public class float3x3 | ||
35 | { | ||
36 | public float3 x = new float3(); | ||
37 | public float3 y = new float3(); | ||
38 | public float3 z = new float3(); | ||
39 | |||
40 | public float3x3() | ||
41 | { | ||
42 | } | ||
43 | |||
44 | public float3x3(float xx, float xy, float xz, float yx, float yy, float yz, float zx, float zy, float zz) | ||
45 | { | ||
46 | x = new float3(xx, xy, xz); | ||
47 | y = new float3(yx, yy, yz); | ||
48 | z = new float3(zx, zy, zz); | ||
49 | } | ||
50 | |||
51 | public float3x3(float3 _x, float3 _y, float3 _z) | ||
52 | { | ||
53 | x = new float3(_x); | ||
54 | y = new float3(_y); | ||
55 | z = new float3(_z); | ||
56 | } | ||
57 | |||
58 | public float3 this[int i] | ||
59 | { | ||
60 | get | ||
61 | { | ||
62 | switch (i) | ||
63 | { | ||
64 | case 0: return x; | ||
65 | case 1: return y; | ||
66 | case 2: return z; | ||
67 | } | ||
68 | throw new ArgumentOutOfRangeException(); | ||
69 | } | ||
70 | } | ||
71 | |||
72 | public float this[int i, int j] | ||
73 | { | ||
74 | get | ||
75 | { | ||
76 | switch (i) | ||
77 | { | ||
78 | case 0: | ||
79 | switch (j) | ||
80 | { | ||
81 | case 0: return x.x; | ||
82 | case 1: return x.y; | ||
83 | case 2: return x.z; | ||
84 | } | ||
85 | break; | ||
86 | case 1: | ||
87 | switch (j) | ||
88 | { | ||
89 | case 0: return y.x; | ||
90 | case 1: return y.y; | ||
91 | case 2: return y.z; | ||
92 | } | ||
93 | break; | ||
94 | case 2: | ||
95 | switch (j) | ||
96 | { | ||
97 | case 0: return z.x; | ||
98 | case 1: return z.y; | ||
99 | case 2: return z.z; | ||
100 | } | ||
101 | break; | ||
102 | } | ||
103 | throw new ArgumentOutOfRangeException(); | ||
104 | } | ||
105 | set | ||
106 | { | ||
107 | switch (i) | ||
108 | { | ||
109 | case 0: | ||
110 | switch (j) | ||
111 | { | ||
112 | case 0: x.x = value; return; | ||
113 | case 1: x.y = value; return; | ||
114 | case 2: x.z = value; return; | ||
115 | } | ||
116 | break; | ||
117 | case 1: | ||
118 | switch (j) | ||
119 | { | ||
120 | case 0: y.x = value; return; | ||
121 | case 1: y.y = value; return; | ||
122 | case 2: y.z = value; return; | ||
123 | } | ||
124 | break; | ||
125 | case 2: | ||
126 | switch (j) | ||
127 | { | ||
128 | case 0: z.x = value; return; | ||
129 | case 1: z.y = value; return; | ||
130 | case 2: z.z = value; return; | ||
131 | } | ||
132 | break; | ||
133 | } | ||
134 | throw new ArgumentOutOfRangeException(); | ||
135 | } | ||
136 | } | ||
137 | |||
138 | public static float3x3 Transpose(float3x3 m) | ||
139 | { | ||
140 | return new float3x3(new float3(m.x.x, m.y.x, m.z.x), new float3(m.x.y, m.y.y, m.z.y), new float3(m.x.z, m.y.z, m.z.z)); | ||
141 | } | ||
142 | |||
143 | public static float3x3 operator *(float3x3 a, float3x3 b) | ||
144 | { | ||
145 | return new float3x3(a.x * b, a.y * b, a.z * b); | ||
146 | } | ||
147 | |||
148 | public static float3x3 operator *(float3x3 a, float s) | ||
149 | { | ||
150 | return new float3x3(a.x * s, a.y * s, a.z * s); | ||
151 | } | ||
152 | |||
153 | public static float3x3 operator /(float3x3 a, float s) | ||
154 | { | ||
155 | float t = 1f / s; | ||
156 | return new float3x3(a.x * t, a.y * t, a.z * t); | ||
157 | } | ||
158 | |||
159 | public static float3x3 operator +(float3x3 a, float3x3 b) | ||
160 | { | ||
161 | return new float3x3(a.x + b.x, a.y + b.y, a.z + b.z); | ||
162 | } | ||
163 | |||
164 | public static float3x3 operator -(float3x3 a, float3x3 b) | ||
165 | { | ||
166 | return new float3x3(a.x - b.x, a.y - b.y, a.z - b.z); | ||
167 | } | ||
168 | |||
169 | public static float Determinant(float3x3 m) | ||
170 | { | ||
171 | return m.x.x * m.y.y * m.z.z + m.y.x * m.z.y * m.x.z + m.z.x * m.x.y * m.y.z - m.x.x * m.z.y * m.y.z - m.y.x * m.x.y * m.z.z - m.z.x * m.y.y * m.x.z; | ||
172 | } | ||
173 | |||
174 | public static float3x3 Inverse(float3x3 a) | ||
175 | { | ||
176 | float3x3 b = new float3x3(); | ||
177 | float d = Determinant(a); | ||
178 | Debug.Assert(d != 0); | ||
179 | for (int i = 0; i < 3; i++) | ||
180 | { | ||
181 | for (int j = 0; j < 3; j++) | ||
182 | { | ||
183 | int i1 = (i + 1) % 3; | ||
184 | int i2 = (i + 2) % 3; | ||
185 | int j1 = (j + 1) % 3; | ||
186 | int j2 = (j + 2) % 3; | ||
187 | |||
188 | // reverse indexs i&j to take transpose | ||
189 | b[i, j] = (a[i1][j1] * a[i2][j2] - a[i1][j2] * a[i2][j1]) / d; | ||
190 | } | ||
191 | } | ||
192 | return b; | ||
193 | } | ||
194 | } | ||
195 | } | ||
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/float4.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/float4.cs new file mode 100644 index 0000000..fa60876 --- /dev/null +++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/float4.cs | |||
@@ -0,0 +1,170 @@ | |||
1 | /* The MIT License | ||
2 | * | ||
3 | * Copyright (c) 2010 Intel Corporation. | ||
4 | * All rights reserved. | ||
5 | * | ||
6 | * Based on the convexdecomposition library from | ||
7 | * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax. | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
10 | * of this software and associated documentation files (the "Software"), to deal | ||
11 | * in the Software without restriction, including without limitation the rights | ||
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | * copies of the Software, and to permit persons to whom the Software is | ||
14 | * furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
25 | * THE SOFTWARE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | |||
30 | namespace OpenSim.Region.Physics.ConvexDecompositionDotNet | ||
31 | { | ||
32 | public class float4 | ||
33 | { | ||
34 | public float x; | ||
35 | public float y; | ||
36 | public float z; | ||
37 | public float w; | ||
38 | |||
39 | public float4() | ||
40 | { | ||
41 | x = 0; | ||
42 | y = 0; | ||
43 | z = 0; | ||
44 | w = 0; | ||
45 | } | ||
46 | |||
47 | public float4(float _x, float _y, float _z, float _w) | ||
48 | { | ||
49 | x = _x; | ||
50 | y = _y; | ||
51 | z = _z; | ||
52 | w = _w; | ||
53 | } | ||
54 | |||
55 | public float4(float3 v, float _w) | ||
56 | { | ||
57 | x = v.x; | ||
58 | y = v.y; | ||
59 | z = v.z; | ||
60 | w = _w; | ||
61 | } | ||
62 | |||
63 | public float4(float4 f) | ||
64 | { | ||
65 | x = f.x; | ||
66 | y = f.y; | ||
67 | z = f.z; | ||
68 | w = f.w; | ||
69 | } | ||
70 | |||
71 | public float this[int i] | ||
72 | { | ||
73 | get | ||
74 | { | ||
75 | switch (i) | ||
76 | { | ||
77 | case 0: return x; | ||
78 | case 1: return y; | ||
79 | case 2: return z; | ||
80 | case 3: return w; | ||
81 | } | ||
82 | throw new ArgumentOutOfRangeException(); | ||
83 | } | ||
84 | } | ||
85 | |||
86 | public float3 xyz() | ||
87 | { | ||
88 | return new float3(x, y, z); | ||
89 | } | ||
90 | |||
91 | public void setxyz(float3 xyz) | ||
92 | { | ||
93 | x = xyz.x; | ||
94 | y = xyz.y; | ||
95 | z = xyz.z; | ||
96 | } | ||
97 | |||
98 | public override int GetHashCode() | ||
99 | { | ||
100 | return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode(); | ||
101 | } | ||
102 | |||
103 | public override bool Equals(object obj) | ||
104 | { | ||
105 | float4 f = obj as float4; | ||
106 | if (f == null) | ||
107 | return false; | ||
108 | |||
109 | return this == f; | ||
110 | } | ||
111 | |||
112 | public static float4 Homogenize(float3 v3) | ||
113 | { | ||
114 | return Homogenize(v3, 1.0f); | ||
115 | } | ||
116 | |||
117 | //C++ TO C# CONVERTER NOTE: C# does not allow default values for parameters. Overloaded methods are inserted above. | ||
118 | //ORIGINAL LINE: float4 Homogenize(const float3 &v3, const float &w =1.0f) | ||
119 | public static float4 Homogenize(float3 v3, float w) | ||
120 | { | ||
121 | return new float4(v3.x, v3.y, v3.z, w); | ||
122 | } | ||
123 | |||
124 | public static float4 cmul(float4 a, float4 b) | ||
125 | { | ||
126 | return new float4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); | ||
127 | } | ||
128 | |||
129 | public static float4 operator +(float4 a, float4 b) | ||
130 | { | ||
131 | return new float4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); | ||
132 | } | ||
133 | public static float4 operator -(float4 a, float4 b) | ||
134 | { | ||
135 | return new float4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); | ||
136 | } | ||
137 | |||
138 | public static float4 operator *(float4 v, float4x4 m) | ||
139 | { | ||
140 | return v.x * m.x + v.y * m.y + v.z * m.z + v.w * m.w; // yes this actually works | ||
141 | } | ||
142 | |||
143 | public static bool operator ==(float4 a, float4 b) | ||
144 | { | ||
145 | // If both are null, or both are same instance, return true. | ||
146 | if (System.Object.ReferenceEquals(a, b)) | ||
147 | return true; | ||
148 | // If one is null, but not both, return false. | ||
149 | if (((object)a == null) || ((object)b == null)) | ||
150 | return false; | ||
151 | |||
152 | return (a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w); | ||
153 | } | ||
154 | |||
155 | public static bool operator !=(float4 a, float4 b) | ||
156 | { | ||
157 | return !(a == b); | ||
158 | } | ||
159 | |||
160 | public static float4 operator *(float4 v, float s) | ||
161 | { | ||
162 | return new float4(v.x * s, v.y * s, v.z * s, v.w * s); | ||
163 | } | ||
164 | |||
165 | public static float4 operator *(float s, float4 v) | ||
166 | { | ||
167 | return new float4(v.x * s, v.y * s, v.z * s, v.w * s); | ||
168 | } | ||
169 | } | ||
170 | } | ||
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/float4x4.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/float4x4.cs new file mode 100644 index 0000000..7d1592f --- /dev/null +++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/float4x4.cs | |||
@@ -0,0 +1,284 @@ | |||
1 | /* The MIT License | ||
2 | * | ||
3 | * Copyright (c) 2010 Intel Corporation. | ||
4 | * All rights reserved. | ||
5 | * | ||
6 | * Based on the convexdecomposition library from | ||
7 | * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax. | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
10 | * of this software and associated documentation files (the "Software"), to deal | ||
11 | * in the Software without restriction, including without limitation the rights | ||
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | * copies of the Software, and to permit persons to whom the Software is | ||
14 | * furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
25 | * THE SOFTWARE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Linq; | ||
31 | using System.Text; | ||
32 | |||
33 | namespace OpenSim.Region.Physics.ConvexDecompositionDotNet | ||
34 | { | ||
35 | public class float4x4 | ||
36 | { | ||
37 | public float4 x = new float4(); | ||
38 | public float4 y = new float4(); | ||
39 | public float4 z = new float4(); | ||
40 | public float4 w = new float4(); | ||
41 | |||
42 | public float4x4() | ||
43 | { | ||
44 | } | ||
45 | |||
46 | public float4x4(float4 _x, float4 _y, float4 _z, float4 _w) | ||
47 | { | ||
48 | x = new float4(_x); | ||
49 | y = new float4(_y); | ||
50 | z = new float4(_z); | ||
51 | w = new float4(_w); | ||
52 | } | ||
53 | |||
54 | public float4x4( | ||
55 | float m00, float m01, float m02, float m03, | ||
56 | float m10, float m11, float m12, float m13, | ||
57 | float m20, float m21, float m22, float m23, | ||
58 | float m30, float m31, float m32, float m33) | ||
59 | { | ||
60 | x = new float4(m00, m01, m02, m03); | ||
61 | y = new float4(m10, m11, m12, m13); | ||
62 | z = new float4(m20, m21, m22, m23); | ||
63 | w = new float4(m30, m31, m32, m33); | ||
64 | } | ||
65 | |||
66 | public float4x4(float4x4 m) | ||
67 | { | ||
68 | x = new float4(m.x); | ||
69 | y = new float4(m.y); | ||
70 | z = new float4(m.z); | ||
71 | w = new float4(m.w); | ||
72 | } | ||
73 | |||
74 | public float4 this[int i] | ||
75 | { | ||
76 | get | ||
77 | { | ||
78 | switch (i) | ||
79 | { | ||
80 | case 0: return x; | ||
81 | case 1: return y; | ||
82 | case 2: return z; | ||
83 | case 3: return w; | ||
84 | } | ||
85 | throw new ArgumentOutOfRangeException(); | ||
86 | } | ||
87 | set | ||
88 | { | ||
89 | switch (i) | ||
90 | { | ||
91 | case 0: x = value; return; | ||
92 | case 1: y = value; return; | ||
93 | case 2: z = value; return; | ||
94 | case 3: w = value; return; | ||
95 | } | ||
96 | throw new ArgumentOutOfRangeException(); | ||
97 | } | ||
98 | } | ||
99 | |||
100 | public override int GetHashCode() | ||
101 | { | ||
102 | return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode(); | ||
103 | } | ||
104 | |||
105 | public override bool Equals(object obj) | ||
106 | { | ||
107 | float4x4 m = obj as float4x4; | ||
108 | if (m == null) | ||
109 | return false; | ||
110 | |||
111 | return this == m; | ||
112 | } | ||
113 | |||
114 | public static float4x4 operator *(float4x4 a, float4x4 b) | ||
115 | { | ||
116 | return new float4x4(a.x * b, a.y * b, a.z * b, a.w * b); | ||
117 | } | ||
118 | |||
119 | public static bool operator ==(float4x4 a, float4x4 b) | ||
120 | { | ||
121 | return (a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w); | ||
122 | } | ||
123 | |||
124 | public static bool operator !=(float4x4 a, float4x4 b) | ||
125 | { | ||
126 | return !(a == b); | ||
127 | } | ||
128 | |||
129 | public static float4x4 Inverse(float4x4 m) | ||
130 | { | ||
131 | float4x4 d = new float4x4(); | ||
132 | //float dst = d.x.x; | ||
133 | float[] tmp = new float[12]; // temp array for pairs | ||
134 | float[] src = new float[16]; // array of transpose source matrix | ||
135 | float det; // determinant | ||
136 | // transpose matrix | ||
137 | for (int i = 0; i < 4; i++) | ||
138 | { | ||
139 | src[i] = m[i].x; | ||
140 | src[i + 4] = m[i].y; | ||
141 | src[i + 8] = m[i].z; | ||
142 | src[i + 12] = m[i].w; | ||
143 | } | ||
144 | // calculate pairs for first 8 elements (cofactors) | ||
145 | tmp[0] = src[10] * src[15]; | ||
146 | tmp[1] = src[11] * src[14]; | ||
147 | tmp[2] = src[9] * src[15]; | ||
148 | tmp[3] = src[11] * src[13]; | ||
149 | tmp[4] = src[9] * src[14]; | ||
150 | tmp[5] = src[10] * src[13]; | ||
151 | tmp[6] = src[8] * src[15]; | ||
152 | tmp[7] = src[11] * src[12]; | ||
153 | tmp[8] = src[8] * src[14]; | ||
154 | tmp[9] = src[10] * src[12]; | ||
155 | tmp[10] = src[8] * src[13]; | ||
156 | tmp[11] = src[9] * src[12]; | ||
157 | // calculate first 8 elements (cofactors) | ||
158 | d.x.x = tmp[0]*src[5] + tmp[3]*src[6] + tmp[4]*src[7]; | ||
159 | d.x.x -= tmp[1]*src[5] + tmp[2]*src[6] + tmp[5]*src[7]; | ||
160 | d.x.y = tmp[1]*src[4] + tmp[6]*src[6] + tmp[9]*src[7]; | ||
161 | d.x.y -= tmp[0]*src[4] + tmp[7]*src[6] + tmp[8]*src[7]; | ||
162 | d.x.z = tmp[2]*src[4] + tmp[7]*src[5] + tmp[10]*src[7]; | ||
163 | d.x.z -= tmp[3]*src[4] + tmp[6]*src[5] + tmp[11]*src[7]; | ||
164 | d.x.w = tmp[5]*src[4] + tmp[8]*src[5] + tmp[11]*src[6]; | ||
165 | d.x.w -= tmp[4]*src[4] + tmp[9]*src[5] + tmp[10]*src[6]; | ||
166 | d.y.x = tmp[1]*src[1] + tmp[2]*src[2] + tmp[5]*src[3]; | ||
167 | d.y.x -= tmp[0]*src[1] + tmp[3]*src[2] + tmp[4]*src[3]; | ||
168 | d.y.y = tmp[0]*src[0] + tmp[7]*src[2] + tmp[8]*src[3]; | ||
169 | d.y.y -= tmp[1]*src[0] + tmp[6]*src[2] + tmp[9]*src[3]; | ||
170 | d.y.z = tmp[3]*src[0] + tmp[6]*src[1] + tmp[11]*src[3]; | ||
171 | d.y.z -= tmp[2]*src[0] + tmp[7]*src[1] + tmp[10]*src[3]; | ||
172 | d.y.w = tmp[4]*src[0] + tmp[9]*src[1] + tmp[10]*src[2]; | ||
173 | d.y.w -= tmp[5]*src[0] + tmp[8]*src[1] + tmp[11]*src[2]; | ||
174 | // calculate pairs for second 8 elements (cofactors) | ||
175 | tmp[0] = src[2]*src[7]; | ||
176 | tmp[1] = src[3]*src[6]; | ||
177 | tmp[2] = src[1]*src[7]; | ||
178 | tmp[3] = src[3]*src[5]; | ||
179 | tmp[4] = src[1]*src[6]; | ||
180 | tmp[5] = src[2]*src[5]; | ||
181 | tmp[6] = src[0]*src[7]; | ||
182 | tmp[7] = src[3]*src[4]; | ||
183 | tmp[8] = src[0]*src[6]; | ||
184 | tmp[9] = src[2]*src[4]; | ||
185 | tmp[10] = src[0]*src[5]; | ||
186 | tmp[11] = src[1]*src[4]; | ||
187 | // calculate second 8 elements (cofactors) | ||
188 | d.z.x = tmp[0]*src[13] + tmp[3]*src[14] + tmp[4]*src[15]; | ||
189 | d.z.x -= tmp[1]*src[13] + tmp[2]*src[14] + tmp[5]*src[15]; | ||
190 | d.z.y = tmp[1]*src[12] + tmp[6]*src[14] + tmp[9]*src[15]; | ||
191 | d.z.y -= tmp[0]*src[12] + tmp[7]*src[14] + tmp[8]*src[15]; | ||
192 | d.z.z = tmp[2]*src[12] + tmp[7]*src[13] + tmp[10]*src[15]; | ||
193 | d.z.z -= tmp[3]*src[12] + tmp[6]*src[13] + tmp[11]*src[15]; | ||
194 | d.z.w = tmp[5]*src[12] + tmp[8]*src[13] + tmp[11]*src[14]; | ||
195 | d.z.w-= tmp[4]*src[12] + tmp[9]*src[13] + tmp[10]*src[14]; | ||
196 | d.w.x = tmp[2]*src[10] + tmp[5]*src[11] + tmp[1]*src[9]; | ||
197 | d.w.x-= tmp[4]*src[11] + tmp[0]*src[9] + tmp[3]*src[10]; | ||
198 | d.w.y = tmp[8]*src[11] + tmp[0]*src[8] + tmp[7]*src[10]; | ||
199 | d.w.y-= tmp[6]*src[10] + tmp[9]*src[11] + tmp[1]*src[8]; | ||
200 | d.w.z = tmp[6]*src[9] + tmp[11]*src[11] + tmp[3]*src[8]; | ||
201 | d.w.z-= tmp[10]*src[11] + tmp[2]*src[8] + tmp[7]*src[9]; | ||
202 | d.w.w = tmp[10]*src[10] + tmp[4]*src[8] + tmp[9]*src[9]; | ||
203 | d.w.w-= tmp[8]*src[9] + tmp[11]*src[10] + tmp[5]*src[8]; | ||
204 | // calculate determinant | ||
205 | det = src[0] * d.x.x + src[1] * d.x.y + src[2] * d.x.z + src[3] * d.x.w; | ||
206 | // calculate matrix inverse | ||
207 | det = 1/det; | ||
208 | for (int j = 0; j < 4; j++) | ||
209 | d[j] *= det; | ||
210 | return d; | ||
211 | } | ||
212 | |||
213 | public static float4x4 MatrixRigidInverse(float4x4 m) | ||
214 | { | ||
215 | float4x4 trans_inverse = MatrixTranslation(-m.w.xyz()); | ||
216 | float4x4 rot = new float4x4(m); | ||
217 | rot.w = new float4(0f, 0f, 0f, 1f); | ||
218 | return trans_inverse * MatrixTranspose(rot); | ||
219 | } | ||
220 | public static float4x4 MatrixTranspose(float4x4 m) | ||
221 | { | ||
222 | return new float4x4(m.x.x, m.y.x, m.z.x, m.w.x, m.x.y, m.y.y, m.z.y, m.w.y, m.x.z, m.y.z, m.z.z, m.w.z, m.x.w, m.y.w, m.z.w, m.w.w); | ||
223 | } | ||
224 | public static float4x4 MatrixPerspectiveFov(float fovy, float aspect, float zn, float zf) | ||
225 | { | ||
226 | float h = 1.0f / (float)Math.Tan(fovy / 2.0f); // view space height | ||
227 | float w = h / aspect; // view space width | ||
228 | return new float4x4(w, 0, 0, 0, 0, h, 0, 0, 0, 0, zf / (zn - zf), -1, 0, 0, zn * zf / (zn - zf), 0); | ||
229 | } | ||
230 | public static float4x4 MatrixTranslation(float3 t) | ||
231 | { | ||
232 | return new float4x4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, t.x, t.y, t.z, 1); | ||
233 | } | ||
234 | public static float4x4 MatrixRotationZ(float angle_radians) | ||
235 | { | ||
236 | float s = (float)Math.Sin(angle_radians); | ||
237 | float c = (float)Math.Cos(angle_radians); | ||
238 | return new float4x4(c, s, 0, 0, -s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); | ||
239 | } | ||
240 | public static float4x4 MatrixLookAt(float3 eye, float3 at, float3 up) | ||
241 | { | ||
242 | float4x4 m = new float4x4(); | ||
243 | m.w.w = 1.0f; | ||
244 | m.w.setxyz(eye); | ||
245 | m.z.setxyz(float3.normalize(eye - at)); | ||
246 | m.x.setxyz(float3.normalize(float3.cross(up, m.z.xyz()))); | ||
247 | m.y.setxyz(float3.cross(m.z.xyz(), m.x.xyz())); | ||
248 | return MatrixRigidInverse(m); | ||
249 | } | ||
250 | |||
251 | public static float4x4 MatrixFromQuatVec(Quaternion q, float3 v) | ||
252 | { | ||
253 | // builds a 4x4 transformation matrix based on orientation q and translation v | ||
254 | float qx2 = q.x * q.x; | ||
255 | float qy2 = q.y * q.y; | ||
256 | float qz2 = q.z * q.z; | ||
257 | |||
258 | float qxqy = q.x * q.y; | ||
259 | float qxqz = q.x * q.z; | ||
260 | float qxqw = q.x * q.w; | ||
261 | float qyqz = q.y * q.z; | ||
262 | float qyqw = q.y * q.w; | ||
263 | float qzqw = q.z * q.w; | ||
264 | |||
265 | return new float4x4( | ||
266 | 1 - 2 * (qy2 + qz2), | ||
267 | 2 * (qxqy + qzqw), | ||
268 | 2 * (qxqz - qyqw), | ||
269 | 0, | ||
270 | 2 * (qxqy - qzqw), | ||
271 | 1 - 2 * (qx2 + qz2), | ||
272 | 2 * (qyqz + qxqw), | ||
273 | 0, | ||
274 | 2 * (qxqz + qyqw), | ||
275 | 2 * (qyqz - qxqw), | ||
276 | 1 - 2 * (qx2 + qy2), | ||
277 | 0, | ||
278 | v.x, | ||
279 | v.y, | ||
280 | v.z, | ||
281 | 1.0f); | ||
282 | } | ||
283 | } | ||
284 | } | ||
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/int3.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/int3.cs new file mode 100644 index 0000000..9c5760d --- /dev/null +++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/int3.cs | |||
@@ -0,0 +1,128 @@ | |||
1 | /* The MIT License | ||
2 | * | ||
3 | * Copyright (c) 2010 Intel Corporation. | ||
4 | * All rights reserved. | ||
5 | * | ||
6 | * Based on the convexdecomposition library from | ||
7 | * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax. | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
10 | * of this software and associated documentation files (the "Software"), to deal | ||
11 | * in the Software without restriction, including without limitation the rights | ||
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | * copies of the Software, and to permit persons to whom the Software is | ||
14 | * furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
25 | * THE SOFTWARE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | |||
30 | namespace OpenSim.Region.Physics.ConvexDecompositionDotNet | ||
31 | { | ||
32 | public class int3 | ||
33 | { | ||
34 | public int x; | ||
35 | public int y; | ||
36 | public int z; | ||
37 | |||
38 | public int3() | ||
39 | { | ||
40 | } | ||
41 | |||
42 | public int3(int _x, int _y, int _z) | ||
43 | { | ||
44 | x = _x; | ||
45 | y = _y; | ||
46 | z = _z; | ||
47 | } | ||
48 | |||
49 | public int this[int i] | ||
50 | { | ||
51 | get | ||
52 | { | ||
53 | switch (i) | ||
54 | { | ||
55 | case 0: return x; | ||
56 | case 1: return y; | ||
57 | case 2: return z; | ||
58 | } | ||
59 | throw new ArgumentOutOfRangeException(); | ||
60 | } | ||
61 | set | ||
62 | { | ||
63 | switch (i) | ||
64 | { | ||
65 | case 0: x = value; return; | ||
66 | case 1: y = value; return; | ||
67 | case 2: z = value; return; | ||
68 | } | ||
69 | throw new ArgumentOutOfRangeException(); | ||
70 | } | ||
71 | } | ||
72 | |||
73 | public override int GetHashCode() | ||
74 | { | ||
75 | return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode(); | ||
76 | } | ||
77 | |||
78 | public override bool Equals(object obj) | ||
79 | { | ||
80 | int3 i = obj as int3; | ||
81 | if (i == null) | ||
82 | return false; | ||
83 | |||
84 | return this == i; | ||
85 | } | ||
86 | |||
87 | public static bool operator ==(int3 a, int3 b) | ||
88 | { | ||
89 | // If both are null, or both are same instance, return true. | ||
90 | if (System.Object.ReferenceEquals(a, b)) | ||
91 | return true; | ||
92 | // If one is null, but not both, return false. | ||
93 | if (((object)a == null) || ((object)b == null)) | ||
94 | return false; | ||
95 | |||
96 | for (int i = 0; i < 3; i++) | ||
97 | { | ||
98 | if (a[i] != b[i]) | ||
99 | return false; | ||
100 | } | ||
101 | return true; | ||
102 | } | ||
103 | |||
104 | public static bool operator !=(int3 a, int3 b) | ||
105 | { | ||
106 | return !(a == b); | ||
107 | } | ||
108 | |||
109 | public static int3 roll3(int3 a) | ||
110 | { | ||
111 | int tmp = a[0]; | ||
112 | a[0] = a[1]; | ||
113 | a[1] = a[2]; | ||
114 | a[2] = tmp; | ||
115 | return a; | ||
116 | } | ||
117 | |||
118 | public static bool isa(int3 a, int3 b) | ||
119 | { | ||
120 | return (a == b || roll3(a) == b || a == roll3(b)); | ||
121 | } | ||
122 | |||
123 | public static bool b2b(int3 a, int3 b) | ||
124 | { | ||
125 | return isa(a, new int3(b[2], b[1], b[0])); | ||
126 | } | ||
127 | } | ||
128 | } | ||
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/int4.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/int4.cs new file mode 100644 index 0000000..c2b32e5 --- /dev/null +++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/int4.cs | |||
@@ -0,0 +1,66 @@ | |||
1 | /* The MIT License | ||
2 | * | ||
3 | * Copyright (c) 2010 Intel Corporation. | ||
4 | * All rights reserved. | ||
5 | * | ||
6 | * Based on the convexdecomposition library from | ||
7 | * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax. | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
10 | * of this software and associated documentation files (the "Software"), to deal | ||
11 | * in the Software without restriction, including without limitation the rights | ||
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | * copies of the Software, and to permit persons to whom the Software is | ||
14 | * furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
25 | * THE SOFTWARE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | |||
30 | namespace OpenSim.Region.Physics.ConvexDecompositionDotNet | ||
31 | { | ||
32 | public class int4 | ||
33 | { | ||
34 | public int x; | ||
35 | public int y; | ||
36 | public int z; | ||
37 | public int w; | ||
38 | |||
39 | public int4() | ||
40 | { | ||
41 | } | ||
42 | |||
43 | public int4(int _x, int _y, int _z, int _w) | ||
44 | { | ||
45 | x = _x; | ||
46 | y = _y; | ||
47 | z = _z; | ||
48 | w = _w; | ||
49 | } | ||
50 | |||
51 | public int this[int i] | ||
52 | { | ||
53 | get | ||
54 | { | ||
55 | switch (i) | ||
56 | { | ||
57 | case 0: return x; | ||
58 | case 1: return y; | ||
59 | case 2: return z; | ||
60 | case 3: return w; | ||
61 | } | ||
62 | throw new ArgumentOutOfRangeException(); | ||
63 | } | ||
64 | } | ||
65 | } | ||
66 | } | ||
diff --git a/OpenSim/Region/Physics/Manager/IMesher.cs b/OpenSim/Region/Physics/Manager/IMesher.cs index 1181b8d..3a9ca1b 100644 --- a/OpenSim/Region/Physics/Manager/IMesher.cs +++ b/OpenSim/Region/Physics/Manager/IMesher.cs | |||
@@ -38,6 +38,17 @@ namespace OpenSim.Region.Physics.Manager | |||
38 | IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical); | 38 | IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical); |
39 | } | 39 | } |
40 | 40 | ||
41 | // Values for level of detail to be passed to the mesher. | ||
42 | // Values origionally chosen for the LOD of sculpties (the sqrt(width*heigth) of sculpt texture) | ||
43 | // Lower level of detail reduces the number of vertices used to represent the meshed shape. | ||
44 | public enum LevelOfDetail | ||
45 | { | ||
46 | High = 32, | ||
47 | Medium = 16, | ||
48 | Low = 8, | ||
49 | VeryLow = 4 | ||
50 | } | ||
51 | |||
41 | public interface IVertex | 52 | public interface IVertex |
42 | { | 53 | { |
43 | } | 54 | } |
diff --git a/OpenSim/Region/Physics/Manager/IPhysicsParameters.cs b/OpenSim/Region/Physics/Manager/IPhysicsParameters.cs new file mode 100755 index 0000000..b8676ba --- /dev/null +++ b/OpenSim/Region/Physics/Manager/IPhysicsParameters.cs | |||
@@ -0,0 +1,73 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using OpenSim.Framework; | ||
31 | using OpenMetaverse; | ||
32 | |||
33 | namespace OpenSim.Region.Physics.Manager | ||
34 | { | ||
35 | public struct PhysParameterEntry | ||
36 | { | ||
37 | // flags to say to apply to all or no instances (I wish one could put consts into interfaces) | ||
38 | public const uint APPLY_TO_ALL = 0xfffffff3; | ||
39 | public const uint APPLY_TO_NONE = 0xfffffff4; | ||
40 | |||
41 | // values that denote true and false values | ||
42 | public const float NUMERIC_TRUE = 1f; | ||
43 | public const float NUMERIC_FALSE = 0f; | ||
44 | |||
45 | public string name; | ||
46 | public string desc; | ||
47 | |||
48 | public PhysParameterEntry(string n, string d) | ||
49 | { | ||
50 | name = n; | ||
51 | desc = d; | ||
52 | } | ||
53 | } | ||
54 | |||
55 | // Interface for a physics scene that implements the runtime setting and getting of physics parameters | ||
56 | public interface IPhysicsParameters | ||
57 | { | ||
58 | // Get the list of parameters this physics engine supports | ||
59 | PhysParameterEntry[] GetParameterList(); | ||
60 | |||
61 | // Set parameter on a specific or all instances. | ||
62 | // Return 'false' if not able to set the parameter. | ||
63 | bool SetPhysicsParameter(string parm, float value, uint localID); | ||
64 | |||
65 | // Get parameter. | ||
66 | // Return 'false' if not able to get the parameter. | ||
67 | bool GetPhysicsParameter(string parm, out float value); | ||
68 | |||
69 | // Get parameter from a particular object | ||
70 | // TODO: | ||
71 | // bool GetPhysicsParameter(string parm, out float value, uint localID); | ||
72 | } | ||
73 | } | ||
diff --git a/OpenSim/Region/Physics/Manager/PhysicsScene.cs b/OpenSim/Region/Physics/Manager/PhysicsScene.cs index de22fae..72b01ac 100644 --- a/OpenSim/Region/Physics/Manager/PhysicsScene.cs +++ b/OpenSim/Region/Physics/Manager/PhysicsScene.cs | |||
@@ -37,6 +37,18 @@ namespace OpenSim.Region.Physics.Manager | |||
37 | public delegate void physicsCrash(); | 37 | public delegate void physicsCrash(); |
38 | 38 | ||
39 | public delegate void RaycastCallback(bool hitYN, Vector3 collisionPoint, uint localid, float distance, Vector3 normal); | 39 | public delegate void RaycastCallback(bool hitYN, Vector3 collisionPoint, uint localid, float distance, Vector3 normal); |
40 | public delegate void RayCallback(List<ContactResult> list); | ||
41 | |||
42 | /// <summary> | ||
43 | /// Contact result from a raycast. | ||
44 | /// </summary> | ||
45 | public struct ContactResult | ||
46 | { | ||
47 | public Vector3 Pos; | ||
48 | public float Depth; | ||
49 | public uint ConsumerID; | ||
50 | public Vector3 Normal; | ||
51 | } | ||
40 | 52 | ||
41 | public abstract class PhysicsScene | 53 | public abstract class PhysicsScene |
42 | { | 54 | { |
@@ -61,7 +73,6 @@ namespace OpenSim.Region.Physics.Manager | |||
61 | } | 73 | } |
62 | } | 74 | } |
63 | 75 | ||
64 | |||
65 | public abstract void Initialise(IMesher meshmerizer, IConfigSource config); | 76 | public abstract void Initialise(IMesher meshmerizer, IConfigSource config); |
66 | 77 | ||
67 | public abstract PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying); | 78 | public abstract PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying); |
@@ -75,6 +86,10 @@ namespace OpenSim.Region.Physics.Manager | |||
75 | 86 | ||
76 | public abstract void RemoveAvatar(PhysicsActor actor); | 87 | public abstract void RemoveAvatar(PhysicsActor actor); |
77 | 88 | ||
89 | /// <summary> | ||
90 | /// Remove a prim from the physics scene. | ||
91 | /// </summary> | ||
92 | /// <param name="prim"></param> | ||
78 | public abstract void RemovePrim(PhysicsActor prim); | 93 | public abstract void RemovePrim(PhysicsActor prim); |
79 | 94 | ||
80 | //public abstract PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, | 95 | //public abstract PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, |
@@ -83,17 +98,6 @@ namespace OpenSim.Region.Physics.Manager | |||
83 | public abstract PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, | 98 | public abstract PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, |
84 | Vector3 size, Quaternion rotation, bool isPhysical, uint localid); | 99 | Vector3 size, Quaternion rotation, bool isPhysical, uint localid); |
85 | 100 | ||
86 | public virtual PhysicsActor AddPrimShape(uint localID, string primName, PrimitiveBaseShape pbs, Vector3 position, | ||
87 | Vector3 size, Quaternion rotation, bool isPhysical, uint localid) | ||
88 | { | ||
89 | PhysicsActor ret = AddPrimShape(primName, pbs, position, size, rotation, isPhysical, localid); | ||
90 | |||
91 | if (ret != null) | ||
92 | ret.LocalID = localID; | ||
93 | |||
94 | return ret; | ||
95 | } | ||
96 | |||
97 | public virtual float TimeDilation | 101 | public virtual float TimeDilation |
98 | { | 102 | { |
99 | get { return 1.0f; } | 103 | get { return 1.0f; } |
@@ -226,6 +230,17 @@ namespace OpenSim.Region.Physics.Manager | |||
226 | retMethod(false, Vector3.Zero, 0, 999999999999f, Vector3.Zero); | 230 | retMethod(false, Vector3.Zero, 0, 999999999999f, Vector3.Zero); |
227 | } | 231 | } |
228 | 232 | ||
233 | public virtual void RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayCallback retMethod) | ||
234 | { | ||
235 | if (retMethod != null) | ||
236 | retMethod(new List<ContactResult>()); | ||
237 | } | ||
238 | |||
239 | public virtual List<ContactResult> RaycastWorld(Vector3 position, Vector3 direction, float length, int Count) | ||
240 | { | ||
241 | return new List<ContactResult>(); | ||
242 | } | ||
243 | |||
229 | private class NullPhysicsScene : PhysicsScene | 244 | private class NullPhysicsScene : PhysicsScene |
230 | { | 245 | { |
231 | private static int m_workIndicator; | 246 | private static int m_workIndicator; |
diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs index b79e1a1..53d5e4c 100644 --- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs | |||
@@ -193,67 +193,6 @@ namespace OpenSim.Region.Physics.Meshing | |||
193 | m_log.Error("****** PrimMesh Parameters ******\n" + primMesh.ParamsToDisplayString()); | 193 | m_log.Error("****** PrimMesh Parameters ******\n" + primMesh.ParamsToDisplayString()); |
194 | } | 194 | } |
195 | 195 | ||
196 | private ulong GetMeshKey(PrimitiveBaseShape pbs, Vector3 size, float lod) | ||
197 | { | ||
198 | ulong hash = 5381; | ||
199 | |||
200 | hash = djb2(hash, pbs.PathCurve); | ||
201 | hash = djb2(hash, (byte)((byte)pbs.HollowShape | (byte)pbs.ProfileShape)); | ||
202 | hash = djb2(hash, pbs.PathBegin); | ||
203 | hash = djb2(hash, pbs.PathEnd); | ||
204 | hash = djb2(hash, pbs.PathScaleX); | ||
205 | hash = djb2(hash, pbs.PathScaleY); | ||
206 | hash = djb2(hash, pbs.PathShearX); | ||
207 | hash = djb2(hash, pbs.PathShearY); | ||
208 | hash = djb2(hash, (byte)pbs.PathTwist); | ||
209 | hash = djb2(hash, (byte)pbs.PathTwistBegin); | ||
210 | hash = djb2(hash, (byte)pbs.PathRadiusOffset); | ||
211 | hash = djb2(hash, (byte)pbs.PathTaperX); | ||
212 | hash = djb2(hash, (byte)pbs.PathTaperY); | ||
213 | hash = djb2(hash, pbs.PathRevolutions); | ||
214 | hash = djb2(hash, (byte)pbs.PathSkew); | ||
215 | hash = djb2(hash, pbs.ProfileBegin); | ||
216 | hash = djb2(hash, pbs.ProfileEnd); | ||
217 | hash = djb2(hash, pbs.ProfileHollow); | ||
218 | |||
219 | // TODO: Separate scale out from the primitive shape data (after | ||
220 | // scaling is supported at the physics engine level) | ||
221 | byte[] scaleBytes = size.GetBytes(); | ||
222 | for (int i = 0; i < scaleBytes.Length; i++) | ||
223 | hash = djb2(hash, scaleBytes[i]); | ||
224 | |||
225 | // Include LOD in hash, accounting for endianness | ||
226 | byte[] lodBytes = new byte[4]; | ||
227 | Buffer.BlockCopy(BitConverter.GetBytes(lod), 0, lodBytes, 0, 4); | ||
228 | if (!BitConverter.IsLittleEndian) | ||
229 | { | ||
230 | Array.Reverse(lodBytes, 0, 4); | ||
231 | } | ||
232 | for (int i = 0; i < lodBytes.Length; i++) | ||
233 | hash = djb2(hash, lodBytes[i]); | ||
234 | |||
235 | // include sculpt UUID | ||
236 | if (pbs.SculptEntry) | ||
237 | { | ||
238 | scaleBytes = pbs.SculptTexture.GetBytes(); | ||
239 | for (int i = 0; i < scaleBytes.Length; i++) | ||
240 | hash = djb2(hash, scaleBytes[i]); | ||
241 | } | ||
242 | |||
243 | return hash; | ||
244 | } | ||
245 | |||
246 | private ulong djb2(ulong hash, byte c) | ||
247 | { | ||
248 | return ((hash << 5) + hash) + (ulong)c; | ||
249 | } | ||
250 | |||
251 | private ulong djb2(ulong hash, ushort c) | ||
252 | { | ||
253 | hash = ((hash << 5) + hash) + (ulong)((byte)c); | ||
254 | return ((hash << 5) + hash) + (ulong)(c >> 8); | ||
255 | } | ||
256 | |||
257 | /// <summary> | 196 | /// <summary> |
258 | /// Add a submesh to an existing list of coords and faces. | 197 | /// Add a submesh to an existing list of coords and faces. |
259 | /// </summary> | 198 | /// </summary> |
@@ -301,16 +240,22 @@ namespace OpenSim.Region.Physics.Meshing | |||
301 | } | 240 | } |
302 | } | 241 | } |
303 | 242 | ||
243 | /// <summary> | ||
244 | /// Create a physics mesh from data that comes with the prim. The actual data used depends on the prim type. | ||
245 | /// </summary> | ||
246 | /// <param name="primName"></param> | ||
247 | /// <param name="primShape"></param> | ||
248 | /// <param name="size"></param> | ||
249 | /// <param name="lod"></param> | ||
250 | /// <returns></returns> | ||
304 | private Mesh CreateMeshFromPrimMesher(string primName, PrimitiveBaseShape primShape, Vector3 size, float lod) | 251 | private Mesh CreateMeshFromPrimMesher(string primName, PrimitiveBaseShape primShape, Vector3 size, float lod) |
305 | { | 252 | { |
306 | PrimMesh primMesh; | 253 | // m_log.DebugFormat( |
307 | PrimMesher.SculptMesh sculptMesh; | 254 | // "[MESH]: Creating physics proxy for {0}, shape {1}", |
308 | 255 | // primName, (OpenMetaverse.SculptType)primShape.SculptType); | |
309 | List<Coord> coords = new List<Coord>(); | ||
310 | List<Face> faces = new List<Face>(); | ||
311 | 256 | ||
312 | Image idata = null; | 257 | List<Coord> coords; |
313 | string decodedSculptFileName = ""; | 258 | List<Face> faces; |
314 | 259 | ||
315 | if (primShape.SculptEntry) | 260 | if (primShape.SculptEntry) |
316 | { | 261 | { |
@@ -319,337 +264,440 @@ namespace OpenSim.Region.Physics.Meshing | |||
319 | if (!useMeshiesPhysicsMesh) | 264 | if (!useMeshiesPhysicsMesh) |
320 | return null; | 265 | return null; |
321 | 266 | ||
322 | m_log.Debug("[MESH]: experimental mesh proxy generation"); | 267 | if (!GenerateCoordsAndFacesFromPrimMeshData(primName, primShape, size, out coords, out faces)) |
268 | return null; | ||
269 | } | ||
270 | else | ||
271 | { | ||
272 | if (!GenerateCoordsAndFacesFromPrimSculptData(primName, primShape, size, lod, out coords, out faces)) | ||
273 | return null; | ||
274 | } | ||
275 | } | ||
276 | else | ||
277 | { | ||
278 | if (!GenerateCoordsAndFacesFromPrimShapeData(primName, primShape, size, lod, out coords, out faces)) | ||
279 | return null; | ||
280 | } | ||
323 | 281 | ||
324 | OSD meshOsd = null; | 282 | // Remove the reference to any JPEG2000 sculpt data so it can be GCed |
283 | primShape.SculptData = Utils.EmptyBytes; | ||
325 | 284 | ||
326 | if (primShape.SculptData.Length <= 0) | 285 | int numCoords = coords.Count; |
327 | { | 286 | int numFaces = faces.Count; |
328 | m_log.Error("[MESH]: asset data is zero length"); | ||
329 | return null; | ||
330 | } | ||
331 | 287 | ||
332 | long start = 0; | 288 | // Create the list of vertices |
333 | using (MemoryStream data = new MemoryStream(primShape.SculptData)) | 289 | List<Vertex> vertices = new List<Vertex>(); |
334 | { | 290 | for (int i = 0; i < numCoords; i++) |
335 | try | 291 | { |
336 | { | 292 | Coord c = coords[i]; |
337 | OSD osd = OSDParser.DeserializeLLSDBinary(data); | 293 | vertices.Add(new Vertex(c.X, c.Y, c.Z)); |
338 | if (osd is OSDMap) | 294 | } |
339 | meshOsd = (OSDMap)osd; | ||
340 | else | ||
341 | { | ||
342 | m_log.Warn("[Mesh}: unable to cast mesh asset to OSDMap"); | ||
343 | return null; | ||
344 | } | ||
345 | } | ||
346 | catch (Exception e) | ||
347 | { | ||
348 | m_log.Error("[MESH]: Exception deserializing mesh asset header:" + e.ToString()); | ||
349 | } | ||
350 | 295 | ||
351 | start = data.Position; | 296 | Mesh mesh = new Mesh(); |
352 | } | 297 | // Add the corresponding triangles to the mesh |
298 | for (int i = 0; i < numFaces; i++) | ||
299 | { | ||
300 | Face f = faces[i]; | ||
301 | mesh.Add(new Triangle(vertices[f.v1], vertices[f.v2], vertices[f.v3])); | ||
302 | } | ||
303 | |||
304 | return mesh; | ||
305 | } | ||
306 | |||
307 | /// <summary> | ||
308 | /// Generate the co-ords and faces necessary to construct a mesh from the mesh data the accompanies a prim. | ||
309 | /// </summary> | ||
310 | /// <param name="primName"></param> | ||
311 | /// <param name="primShape"></param> | ||
312 | /// <param name="size"></param> | ||
313 | /// <param name="coords">Coords are added to this list by the method.</param> | ||
314 | /// <param name="faces">Faces are added to this list by the method.</param> | ||
315 | /// <returns>true if coords and faces were successfully generated, false if not</returns> | ||
316 | private bool GenerateCoordsAndFacesFromPrimMeshData( | ||
317 | string primName, PrimitiveBaseShape primShape, Vector3 size, out List<Coord> coords, out List<Face> faces) | ||
318 | { | ||
319 | m_log.DebugFormat("[MESH]: experimental mesh proxy generation for {0}", primName); | ||
320 | |||
321 | coords = new List<Coord>(); | ||
322 | faces = new List<Face>(); | ||
323 | OSD meshOsd = null; | ||
324 | |||
325 | if (primShape.SculptData.Length <= 0) | ||
326 | { | ||
327 | m_log.Error("[MESH]: asset data is zero length"); | ||
328 | return false; | ||
329 | } | ||
353 | 330 | ||
354 | if (meshOsd is OSDMap) | 331 | long start = 0; |
332 | using (MemoryStream data = new MemoryStream(primShape.SculptData)) | ||
333 | { | ||
334 | try | ||
335 | { | ||
336 | OSD osd = OSDParser.DeserializeLLSDBinary(data); | ||
337 | if (osd is OSDMap) | ||
338 | meshOsd = (OSDMap)osd; | ||
339 | else | ||
355 | { | 340 | { |
356 | OSDMap physicsParms = null; | 341 | m_log.Warn("[Mesh}: unable to cast mesh asset to OSDMap"); |
357 | OSDMap map = (OSDMap)meshOsd; | 342 | return false; |
358 | if (map.ContainsKey("physics_shape")) | 343 | } |
359 | physicsParms = (OSDMap)map["physics_shape"]; // old asset format | 344 | } |
360 | else if (map.ContainsKey("physics_mesh")) | 345 | catch (Exception e) |
361 | physicsParms = (OSDMap)map["physics_mesh"]; // new asset format | 346 | { |
362 | 347 | m_log.Error("[MESH]: Exception deserializing mesh asset header:" + e.ToString()); | |
363 | if (physicsParms == null) | 348 | } |
364 | { | 349 | |
365 | m_log.Warn("[MESH]: no recognized physics mesh found in mesh asset"); | 350 | start = data.Position; |
366 | return null; | 351 | } |
367 | } | 352 | |
353 | if (meshOsd is OSDMap) | ||
354 | { | ||
355 | OSDMap physicsParms = null; | ||
356 | OSDMap map = (OSDMap)meshOsd; | ||
357 | if (map.ContainsKey("physics_shape")) | ||
358 | physicsParms = (OSDMap)map["physics_shape"]; // old asset format | ||
359 | else if (map.ContainsKey("physics_mesh")) | ||
360 | physicsParms = (OSDMap)map["physics_mesh"]; // new asset format | ||
361 | |||
362 | if (physicsParms == null) | ||
363 | { | ||
364 | m_log.Warn("[MESH]: no recognized physics mesh found in mesh asset"); | ||
365 | return false; | ||
366 | } | ||
368 | 367 | ||
369 | int physOffset = physicsParms["offset"].AsInteger() + (int)start; | 368 | int physOffset = physicsParms["offset"].AsInteger() + (int)start; |
370 | int physSize = physicsParms["size"].AsInteger(); | 369 | int physSize = physicsParms["size"].AsInteger(); |
371 | 370 | ||
372 | if (physOffset < 0 || physSize == 0) | 371 | if (physOffset < 0 || physSize == 0) |
373 | return null; // no mesh data in asset | 372 | return false; // no mesh data in asset |
374 | 373 | ||
375 | OSD decodedMeshOsd = new OSD(); | 374 | OSD decodedMeshOsd = new OSD(); |
376 | byte[] meshBytes = new byte[physSize]; | 375 | byte[] meshBytes = new byte[physSize]; |
377 | System.Buffer.BlockCopy(primShape.SculptData, physOffset, meshBytes, 0, physSize); | 376 | System.Buffer.BlockCopy(primShape.SculptData, physOffset, meshBytes, 0, physSize); |
378 | // byte[] decompressed = new byte[physSize * 5]; | 377 | // byte[] decompressed = new byte[physSize * 5]; |
379 | try | 378 | try |
379 | { | ||
380 | using (MemoryStream inMs = new MemoryStream(meshBytes)) | ||
381 | { | ||
382 | using (MemoryStream outMs = new MemoryStream()) | ||
380 | { | 383 | { |
381 | using (MemoryStream inMs = new MemoryStream(meshBytes)) | 384 | using (ZOutputStream zOut = new ZOutputStream(outMs)) |
382 | { | 385 | { |
383 | using (MemoryStream outMs = new MemoryStream()) | 386 | byte[] readBuffer = new byte[2048]; |
387 | int readLen = 0; | ||
388 | while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0) | ||
384 | { | 389 | { |
385 | using (ZOutputStream zOut = new ZOutputStream(outMs)) | 390 | zOut.Write(readBuffer, 0, readLen); |
386 | { | ||
387 | byte[] readBuffer = new byte[2048]; | ||
388 | int readLen = 0; | ||
389 | while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0) | ||
390 | { | ||
391 | zOut.Write(readBuffer, 0, readLen); | ||
392 | } | ||
393 | zOut.Flush(); | ||
394 | outMs.Seek(0, SeekOrigin.Begin); | ||
395 | |||
396 | byte[] decompressedBuf = outMs.GetBuffer(); | ||
397 | |||
398 | decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf); | ||
399 | } | ||
400 | } | 391 | } |
392 | zOut.Flush(); | ||
393 | outMs.Seek(0, SeekOrigin.Begin); | ||
394 | |||
395 | byte[] decompressedBuf = outMs.GetBuffer(); | ||
396 | |||
397 | decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf); | ||
401 | } | 398 | } |
402 | } | 399 | } |
403 | catch (Exception e) | 400 | } |
404 | { | 401 | } |
405 | m_log.Error("[MESH]: exception decoding physical mesh: " + e.ToString()); | 402 | catch (Exception e) |
406 | return null; | 403 | { |
407 | } | 404 | m_log.Error("[MESH]: exception decoding physical mesh: " + e.ToString()); |
405 | return false; | ||
406 | } | ||
408 | 407 | ||
409 | OSDArray decodedMeshOsdArray = null; | 408 | OSDArray decodedMeshOsdArray = null; |
410 | 409 | ||
411 | // physics_shape is an array of OSDMaps, one for each submesh | 410 | // physics_shape is an array of OSDMaps, one for each submesh |
412 | if (decodedMeshOsd is OSDArray) | 411 | if (decodedMeshOsd is OSDArray) |
413 | { | 412 | { |
414 | // Console.WriteLine("decodedMeshOsd for {0} - {1}", primName, Util.GetFormattedXml(decodedMeshOsd)); | 413 | // Console.WriteLine("decodedMeshOsd for {0} - {1}", primName, Util.GetFormattedXml(decodedMeshOsd)); |
415 | 414 | ||
416 | decodedMeshOsdArray = (OSDArray)decodedMeshOsd; | 415 | decodedMeshOsdArray = (OSDArray)decodedMeshOsd; |
417 | foreach (OSD subMeshOsd in decodedMeshOsdArray) | 416 | foreach (OSD subMeshOsd in decodedMeshOsdArray) |
418 | { | 417 | { |
419 | if (subMeshOsd is OSDMap) | 418 | if (subMeshOsd is OSDMap) |
420 | AddSubMesh(subMeshOsd as OSDMap, size, coords, faces); | 419 | AddSubMesh(subMeshOsd as OSDMap, size, coords, faces); |
421 | } | ||
422 | } | ||
423 | } | 420 | } |
424 | } | 421 | } |
425 | else | 422 | } |
423 | |||
424 | return true; | ||
425 | } | ||
426 | |||
427 | /// <summary> | ||
428 | /// Generate the co-ords and faces necessary to construct a mesh from the sculpt data the accompanies a prim. | ||
429 | /// </summary> | ||
430 | /// <param name="primName"></param> | ||
431 | /// <param name="primShape"></param> | ||
432 | /// <param name="size"></param> | ||
433 | /// <param name="lod"></param> | ||
434 | /// <param name="coords">Coords are added to this list by the method.</param> | ||
435 | /// <param name="faces">Faces are added to this list by the method.</param> | ||
436 | /// <returns>true if coords and faces were successfully generated, false if not</returns> | ||
437 | private bool GenerateCoordsAndFacesFromPrimSculptData( | ||
438 | string primName, PrimitiveBaseShape primShape, Vector3 size, float lod, out List<Coord> coords, out List<Face> faces) | ||
439 | { | ||
440 | coords = new List<Coord>(); | ||
441 | faces = new List<Face>(); | ||
442 | PrimMesher.SculptMesh sculptMesh; | ||
443 | Image idata = null; | ||
444 | string decodedSculptFileName = ""; | ||
445 | |||
446 | if (cacheSculptMaps && primShape.SculptTexture != UUID.Zero) | ||
447 | { | ||
448 | decodedSculptFileName = System.IO.Path.Combine(decodedSculptMapPath, "smap_" + primShape.SculptTexture.ToString()); | ||
449 | try | ||
426 | { | 450 | { |
427 | if (cacheSculptMaps && primShape.SculptTexture != UUID.Zero) | 451 | if (File.Exists(decodedSculptFileName)) |
428 | { | 452 | { |
429 | decodedSculptFileName = System.IO.Path.Combine(decodedSculptMapPath, "smap_" + primShape.SculptTexture.ToString()); | 453 | idata = Image.FromFile(decodedSculptFileName); |
430 | try | ||
431 | { | ||
432 | if (File.Exists(decodedSculptFileName)) | ||
433 | { | ||
434 | idata = Image.FromFile(decodedSculptFileName); | ||
435 | } | ||
436 | } | ||
437 | catch (Exception e) | ||
438 | { | ||
439 | m_log.Error("[SCULPT]: unable to load cached sculpt map " + decodedSculptFileName + " " + e.Message); | ||
440 | |||
441 | } | ||
442 | //if (idata != null) | ||
443 | // m_log.Debug("[SCULPT]: loaded cached map asset for map ID: " + primShape.SculptTexture.ToString()); | ||
444 | } | 454 | } |
455 | } | ||
456 | catch (Exception e) | ||
457 | { | ||
458 | m_log.Error("[SCULPT]: unable to load cached sculpt map " + decodedSculptFileName + " " + e.Message); | ||
459 | |||
460 | } | ||
461 | //if (idata != null) | ||
462 | // m_log.Debug("[SCULPT]: loaded cached map asset for map ID: " + primShape.SculptTexture.ToString()); | ||
463 | } | ||
464 | |||
465 | if (idata == null) | ||
466 | { | ||
467 | if (primShape.SculptData == null || primShape.SculptData.Length == 0) | ||
468 | return false; | ||
469 | |||
470 | try | ||
471 | { | ||
472 | OpenMetaverse.Imaging.ManagedImage unusedData; | ||
473 | OpenMetaverse.Imaging.OpenJPEG.DecodeToImage(primShape.SculptData, out unusedData, out idata); | ||
445 | 474 | ||
446 | if (idata == null) | 475 | if (idata == null) |
447 | { | 476 | { |
448 | if (primShape.SculptData == null || primShape.SculptData.Length == 0) | 477 | // In some cases it seems that the decode can return a null bitmap without throwing |
449 | return null; | 478 | // an exception |
479 | m_log.WarnFormat("[PHYSICS]: OpenJPEG decoded sculpt data for {0} to a null bitmap. Ignoring.", primName); | ||
450 | 480 | ||
451 | try | 481 | return false; |
452 | { | 482 | } |
453 | OpenMetaverse.Imaging.ManagedImage unusedData; | ||
454 | OpenMetaverse.Imaging.OpenJPEG.DecodeToImage(primShape.SculptData, out unusedData, out idata); | ||
455 | unusedData = null; | ||
456 | 483 | ||
457 | //idata = CSJ2K.J2kImage.FromBytes(primShape.SculptData); | 484 | unusedData = null; |
458 | 485 | ||
459 | if (cacheSculptMaps && idata != null) | 486 | //idata = CSJ2K.J2kImage.FromBytes(primShape.SculptData); |
460 | { | ||
461 | try { idata.Save(decodedSculptFileName, ImageFormat.MemoryBmp); } | ||
462 | catch (Exception e) { m_log.Error("[SCULPT]: unable to cache sculpt map " + decodedSculptFileName + " " + e.Message); } | ||
463 | } | ||
464 | } | ||
465 | catch (DllNotFoundException) | ||
466 | { | ||
467 | m_log.Error("[PHYSICS]: OpenJpeg is not installed correctly on this system. Physics Proxy generation failed. Often times this is because of an old version of GLIBC. You must have version 2.4 or above!"); | ||
468 | return null; | ||
469 | } | ||
470 | catch (IndexOutOfRangeException) | ||
471 | { | ||
472 | m_log.Error("[PHYSICS]: OpenJpeg was unable to decode this. Physics Proxy generation failed"); | ||
473 | return null; | ||
474 | } | ||
475 | catch (Exception ex) | ||
476 | { | ||
477 | m_log.Error("[PHYSICS]: Unable to generate a Sculpty physics proxy. Sculpty texture decode failed: " + ex.Message); | ||
478 | return null; | ||
479 | } | ||
480 | } | ||
481 | 487 | ||
482 | PrimMesher.SculptMesh.SculptType sculptType; | 488 | if (cacheSculptMaps) |
483 | switch ((OpenMetaverse.SculptType)primShape.SculptType) | ||
484 | { | 489 | { |
485 | case OpenMetaverse.SculptType.Cylinder: | 490 | try { idata.Save(decodedSculptFileName, ImageFormat.MemoryBmp); } |
486 | sculptType = PrimMesher.SculptMesh.SculptType.cylinder; | 491 | catch (Exception e) { m_log.Error("[SCULPT]: unable to cache sculpt map " + decodedSculptFileName + " " + e.Message); } |
487 | break; | ||
488 | case OpenMetaverse.SculptType.Plane: | ||
489 | sculptType = PrimMesher.SculptMesh.SculptType.plane; | ||
490 | break; | ||
491 | case OpenMetaverse.SculptType.Torus: | ||
492 | sculptType = PrimMesher.SculptMesh.SculptType.torus; | ||
493 | break; | ||
494 | case OpenMetaverse.SculptType.Sphere: | ||
495 | sculptType = PrimMesher.SculptMesh.SculptType.sphere; | ||
496 | break; | ||
497 | default: | ||
498 | sculptType = PrimMesher.SculptMesh.SculptType.plane; | ||
499 | break; | ||
500 | } | 492 | } |
493 | } | ||
494 | catch (DllNotFoundException) | ||
495 | { | ||
496 | m_log.Error("[PHYSICS]: OpenJpeg is not installed correctly on this system. Physics Proxy generation failed. Often times this is because of an old version of GLIBC. You must have version 2.4 or above!"); | ||
497 | return false; | ||
498 | } | ||
499 | catch (IndexOutOfRangeException) | ||
500 | { | ||
501 | m_log.Error("[PHYSICS]: OpenJpeg was unable to decode this. Physics Proxy generation failed"); | ||
502 | return false; | ||
503 | } | ||
504 | catch (Exception ex) | ||
505 | { | ||
506 | m_log.Error("[PHYSICS]: Unable to generate a Sculpty physics proxy. Sculpty texture decode failed: " + ex.Message); | ||
507 | return false; | ||
508 | } | ||
509 | } | ||
510 | |||
511 | PrimMesher.SculptMesh.SculptType sculptType; | ||
512 | switch ((OpenMetaverse.SculptType)primShape.SculptType) | ||
513 | { | ||
514 | case OpenMetaverse.SculptType.Cylinder: | ||
515 | sculptType = PrimMesher.SculptMesh.SculptType.cylinder; | ||
516 | break; | ||
517 | case OpenMetaverse.SculptType.Plane: | ||
518 | sculptType = PrimMesher.SculptMesh.SculptType.plane; | ||
519 | break; | ||
520 | case OpenMetaverse.SculptType.Torus: | ||
521 | sculptType = PrimMesher.SculptMesh.SculptType.torus; | ||
522 | break; | ||
523 | case OpenMetaverse.SculptType.Sphere: | ||
524 | sculptType = PrimMesher.SculptMesh.SculptType.sphere; | ||
525 | break; | ||
526 | default: | ||
527 | sculptType = PrimMesher.SculptMesh.SculptType.plane; | ||
528 | break; | ||
529 | } | ||
501 | 530 | ||
502 | bool mirror = ((primShape.SculptType & 128) != 0); | 531 | bool mirror = ((primShape.SculptType & 128) != 0); |
503 | bool invert = ((primShape.SculptType & 64) != 0); | 532 | bool invert = ((primShape.SculptType & 64) != 0); |
504 | 533 | ||
505 | sculptMesh = new PrimMesher.SculptMesh((Bitmap)idata, sculptType, (int)lod, false, mirror, invert); | 534 | sculptMesh = new PrimMesher.SculptMesh((Bitmap)idata, sculptType, (int)lod, false, mirror, invert); |
506 | |||
507 | idata.Dispose(); | ||
508 | 535 | ||
509 | sculptMesh.DumpRaw(baseDir, primName, "primMesh"); | 536 | idata.Dispose(); |
510 | 537 | ||
511 | sculptMesh.Scale(size.X, size.Y, size.Z); | 538 | sculptMesh.DumpRaw(baseDir, primName, "primMesh"); |
512 | 539 | ||
513 | coords = sculptMesh.coords; | 540 | sculptMesh.Scale(size.X, size.Y, size.Z); |
514 | faces = sculptMesh.faces; | 541 | |
542 | coords = sculptMesh.coords; | ||
543 | faces = sculptMesh.faces; | ||
544 | |||
545 | return true; | ||
546 | } | ||
547 | |||
548 | /// <summary> | ||
549 | /// Generate the co-ords and faces necessary to construct a mesh from the shape data the accompanies a prim. | ||
550 | /// </summary> | ||
551 | /// <param name="primName"></param> | ||
552 | /// <param name="primShape"></param> | ||
553 | /// <param name="size"></param> | ||
554 | /// <param name="coords">Coords are added to this list by the method.</param> | ||
555 | /// <param name="faces">Faces are added to this list by the method.</param> | ||
556 | /// <returns>true if coords and faces were successfully generated, false if not</returns> | ||
557 | private bool GenerateCoordsAndFacesFromPrimShapeData( | ||
558 | string primName, PrimitiveBaseShape primShape, Vector3 size, float lod, out List<Coord> coords, out List<Face> faces) | ||
559 | { | ||
560 | PrimMesh primMesh; | ||
561 | coords = new List<Coord>(); | ||
562 | faces = new List<Face>(); | ||
563 | |||
564 | float pathShearX = primShape.PathShearX < 128 ? (float)primShape.PathShearX * 0.01f : (float)(primShape.PathShearX - 256) * 0.01f; | ||
565 | float pathShearY = primShape.PathShearY < 128 ? (float)primShape.PathShearY * 0.01f : (float)(primShape.PathShearY - 256) * 0.01f; | ||
566 | float pathBegin = (float)primShape.PathBegin * 2.0e-5f; | ||
567 | float pathEnd = 1.0f - (float)primShape.PathEnd * 2.0e-5f; | ||
568 | float pathScaleX = (float)(primShape.PathScaleX - 100) * 0.01f; | ||
569 | float pathScaleY = (float)(primShape.PathScaleY - 100) * 0.01f; | ||
570 | |||
571 | float profileBegin = (float)primShape.ProfileBegin * 2.0e-5f; | ||
572 | float profileEnd = 1.0f - (float)primShape.ProfileEnd * 2.0e-5f; | ||
573 | float profileHollow = (float)primShape.ProfileHollow * 2.0e-5f; | ||
574 | if (profileHollow > 0.95f) | ||
575 | profileHollow = 0.95f; | ||
576 | |||
577 | int sides = 4; | ||
578 | LevelOfDetail iLOD = (LevelOfDetail)lod; | ||
579 | if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle) | ||
580 | sides = 3; | ||
581 | else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Circle) | ||
582 | { | ||
583 | switch (iLOD) | ||
584 | { | ||
585 | case LevelOfDetail.High: sides = 24; break; | ||
586 | case LevelOfDetail.Medium: sides = 12; break; | ||
587 | case LevelOfDetail.Low: sides = 6; break; | ||
588 | case LevelOfDetail.VeryLow: sides = 3; break; | ||
589 | default: sides = 24; break; | ||
515 | } | 590 | } |
516 | } | 591 | } |
517 | else | 592 | else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle) |
593 | { // half circle, prim is a sphere | ||
594 | switch (iLOD) | ||
595 | { | ||
596 | case LevelOfDetail.High: sides = 24; break; | ||
597 | case LevelOfDetail.Medium: sides = 12; break; | ||
598 | case LevelOfDetail.Low: sides = 6; break; | ||
599 | case LevelOfDetail.VeryLow: sides = 3; break; | ||
600 | default: sides = 24; break; | ||
601 | } | ||
602 | |||
603 | profileBegin = 0.5f * profileBegin + 0.5f; | ||
604 | profileEnd = 0.5f * profileEnd + 0.5f; | ||
605 | } | ||
606 | |||
607 | int hollowSides = sides; | ||
608 | if (primShape.HollowShape == HollowShape.Circle) | ||
518 | { | 609 | { |
519 | float pathShearX = primShape.PathShearX < 128 ? (float)primShape.PathShearX * 0.01f : (float)(primShape.PathShearX - 256) * 0.01f; | 610 | switch (iLOD) |
520 | float pathShearY = primShape.PathShearY < 128 ? (float)primShape.PathShearY * 0.01f : (float)(primShape.PathShearY - 256) * 0.01f; | 611 | { |
521 | float pathBegin = (float)primShape.PathBegin * 2.0e-5f; | 612 | case LevelOfDetail.High: hollowSides = 24; break; |
522 | float pathEnd = 1.0f - (float)primShape.PathEnd * 2.0e-5f; | 613 | case LevelOfDetail.Medium: hollowSides = 12; break; |
523 | float pathScaleX = (float)(primShape.PathScaleX - 100) * 0.01f; | 614 | case LevelOfDetail.Low: hollowSides = 6; break; |
524 | float pathScaleY = (float)(primShape.PathScaleY - 100) * 0.01f; | 615 | case LevelOfDetail.VeryLow: hollowSides = 3; break; |
525 | 616 | default: hollowSides = 24; break; | |
526 | float profileBegin = (float)primShape.ProfileBegin * 2.0e-5f; | ||
527 | float profileEnd = 1.0f - (float)primShape.ProfileEnd * 2.0e-5f; | ||
528 | float profileHollow = (float)primShape.ProfileHollow * 2.0e-5f; | ||
529 | if (profileHollow > 0.95f) | ||
530 | profileHollow = 0.95f; | ||
531 | |||
532 | int sides = 4; | ||
533 | if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle) | ||
534 | sides = 3; | ||
535 | else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Circle) | ||
536 | sides = 24; | ||
537 | else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle) | ||
538 | { // half circle, prim is a sphere | ||
539 | sides = 24; | ||
540 | |||
541 | profileBegin = 0.5f * profileBegin + 0.5f; | ||
542 | profileEnd = 0.5f * profileEnd + 0.5f; | ||
543 | } | 617 | } |
618 | } | ||
619 | else if (primShape.HollowShape == HollowShape.Square) | ||
620 | hollowSides = 4; | ||
621 | else if (primShape.HollowShape == HollowShape.Triangle) | ||
622 | hollowSides = 3; | ||
544 | 623 | ||
545 | int hollowSides = sides; | 624 | primMesh = new PrimMesh(sides, profileBegin, profileEnd, profileHollow, hollowSides); |
546 | if (primShape.HollowShape == HollowShape.Circle) | ||
547 | hollowSides = 24; | ||
548 | else if (primShape.HollowShape == HollowShape.Square) | ||
549 | hollowSides = 4; | ||
550 | else if (primShape.HollowShape == HollowShape.Triangle) | ||
551 | hollowSides = 3; | ||
552 | 625 | ||
553 | primMesh = new PrimMesh(sides, profileBegin, profileEnd, profileHollow, hollowSides); | 626 | if (primMesh.errorMessage != null) |
627 | if (primMesh.errorMessage.Length > 0) | ||
628 | m_log.Error("[ERROR] " + primMesh.errorMessage); | ||
554 | 629 | ||
555 | if (primMesh.errorMessage != null) | 630 | primMesh.topShearX = pathShearX; |
556 | if (primMesh.errorMessage.Length > 0) | 631 | primMesh.topShearY = pathShearY; |
557 | m_log.Error("[ERROR] " + primMesh.errorMessage); | 632 | primMesh.pathCutBegin = pathBegin; |
633 | primMesh.pathCutEnd = pathEnd; | ||
558 | 634 | ||
559 | primMesh.topShearX = pathShearX; | 635 | if (primShape.PathCurve == (byte)Extrusion.Straight || primShape.PathCurve == (byte) Extrusion.Flexible) |
560 | primMesh.topShearY = pathShearY; | 636 | { |
561 | primMesh.pathCutBegin = pathBegin; | 637 | primMesh.twistBegin = primShape.PathTwistBegin * 18 / 10; |
562 | primMesh.pathCutEnd = pathEnd; | 638 | primMesh.twistEnd = primShape.PathTwist * 18 / 10; |
639 | primMesh.taperX = pathScaleX; | ||
640 | primMesh.taperY = pathScaleY; | ||
563 | 641 | ||
564 | if (primShape.PathCurve == (byte)Extrusion.Straight || primShape.PathCurve == (byte) Extrusion.Flexible) | 642 | if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f) |
565 | { | 643 | { |
566 | primMesh.twistBegin = primShape.PathTwistBegin * 18 / 10; | 644 | ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh); |
567 | primMesh.twistEnd = primShape.PathTwist * 18 / 10; | 645 | if (profileBegin < 0.0f) profileBegin = 0.0f; |
568 | primMesh.taperX = pathScaleX; | 646 | if (profileEnd > 1.0f) profileEnd = 1.0f; |
569 | primMesh.taperY = pathScaleY; | 647 | } |
570 | |||
571 | if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f) | ||
572 | { | ||
573 | ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh); | ||
574 | if (profileBegin < 0.0f) profileBegin = 0.0f; | ||
575 | if (profileEnd > 1.0f) profileEnd = 1.0f; | ||
576 | } | ||
577 | #if SPAM | 648 | #if SPAM |
578 | m_log.Debug("****** PrimMesh Parameters (Linear) ******\n" + primMesh.ParamsToDisplayString()); | 649 | m_log.Debug("****** PrimMesh Parameters (Linear) ******\n" + primMesh.ParamsToDisplayString()); |
579 | #endif | 650 | #endif |
580 | try | 651 | try |
581 | { | 652 | { |
582 | primMesh.ExtrudeLinear(); | 653 | primMesh.ExtrudeLinear(); |
583 | } | ||
584 | catch (Exception ex) | ||
585 | { | ||
586 | ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh); | ||
587 | return null; | ||
588 | } | ||
589 | } | 654 | } |
590 | else | 655 | catch (Exception ex) |
591 | { | 656 | { |
592 | primMesh.holeSizeX = (200 - primShape.PathScaleX) * 0.01f; | 657 | ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh); |
593 | primMesh.holeSizeY = (200 - primShape.PathScaleY) * 0.01f; | 658 | return false; |
594 | primMesh.radius = 0.01f * primShape.PathRadiusOffset; | 659 | } |
595 | primMesh.revolutions = 1.0f + 0.015f * primShape.PathRevolutions; | 660 | } |
596 | primMesh.skew = 0.01f * primShape.PathSkew; | 661 | else |
597 | primMesh.twistBegin = primShape.PathTwistBegin * 36 / 10; | 662 | { |
598 | primMesh.twistEnd = primShape.PathTwist * 36 / 10; | 663 | primMesh.holeSizeX = (200 - primShape.PathScaleX) * 0.01f; |
599 | primMesh.taperX = primShape.PathTaperX * 0.01f; | 664 | primMesh.holeSizeY = (200 - primShape.PathScaleY) * 0.01f; |
600 | primMesh.taperY = primShape.PathTaperY * 0.01f; | 665 | primMesh.radius = 0.01f * primShape.PathRadiusOffset; |
601 | 666 | primMesh.revolutions = 1.0f + 0.015f * primShape.PathRevolutions; | |
602 | if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f) | 667 | primMesh.skew = 0.01f * primShape.PathSkew; |
603 | { | 668 | primMesh.twistBegin = primShape.PathTwistBegin * 36 / 10; |
604 | ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh); | 669 | primMesh.twistEnd = primShape.PathTwist * 36 / 10; |
605 | if (profileBegin < 0.0f) profileBegin = 0.0f; | 670 | primMesh.taperX = primShape.PathTaperX * 0.01f; |
606 | if (profileEnd > 1.0f) profileEnd = 1.0f; | 671 | primMesh.taperY = primShape.PathTaperY * 0.01f; |
607 | } | 672 | |
673 | if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f) | ||
674 | { | ||
675 | ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh); | ||
676 | if (profileBegin < 0.0f) profileBegin = 0.0f; | ||
677 | if (profileEnd > 1.0f) profileEnd = 1.0f; | ||
678 | } | ||
608 | #if SPAM | 679 | #if SPAM |
609 | m_log.Debug("****** PrimMesh Parameters (Circular) ******\n" + primMesh.ParamsToDisplayString()); | 680 | m_log.Debug("****** PrimMesh Parameters (Circular) ******\n" + primMesh.ParamsToDisplayString()); |
610 | #endif | 681 | #endif |
611 | try | 682 | try |
612 | { | 683 | { |
613 | primMesh.ExtrudeCircular(); | 684 | primMesh.ExtrudeCircular(); |
614 | } | 685 | } |
615 | catch (Exception ex) | 686 | catch (Exception ex) |
616 | { | 687 | { |
617 | ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh); | 688 | ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh); |
618 | return null; | 689 | return false; |
619 | } | ||
620 | } | 690 | } |
621 | |||
622 | primMesh.DumpRaw(baseDir, primName, "primMesh"); | ||
623 | |||
624 | primMesh.Scale(size.X, size.Y, size.Z); | ||
625 | |||
626 | coords = primMesh.coords; | ||
627 | faces = primMesh.faces; | ||
628 | } | 691 | } |
629 | 692 | ||
630 | // Remove the reference to any JPEG2000 sculpt data so it can be GCed | 693 | primMesh.DumpRaw(baseDir, primName, "primMesh"); |
631 | primShape.SculptData = Utils.EmptyBytes; | ||
632 | 694 | ||
633 | int numCoords = coords.Count; | 695 | primMesh.Scale(size.X, size.Y, size.Z); |
634 | int numFaces = faces.Count; | ||
635 | |||
636 | // Create the list of vertices | ||
637 | List<Vertex> vertices = new List<Vertex>(); | ||
638 | for (int i = 0; i < numCoords; i++) | ||
639 | { | ||
640 | Coord c = coords[i]; | ||
641 | vertices.Add(new Vertex(c.X, c.Y, c.Z)); | ||
642 | } | ||
643 | 696 | ||
644 | Mesh mesh = new Mesh(); | 697 | coords = primMesh.coords; |
645 | // Add the corresponding triangles to the mesh | 698 | faces = primMesh.faces; |
646 | for (int i = 0; i < numFaces; i++) | ||
647 | { | ||
648 | Face f = faces[i]; | ||
649 | mesh.Add(new Triangle(vertices[f.v1], vertices[f.v2], vertices[f.v3])); | ||
650 | } | ||
651 | 699 | ||
652 | return mesh; | 700 | return true; |
653 | } | 701 | } |
654 | 702 | ||
655 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) | 703 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) |
@@ -668,8 +716,7 @@ namespace OpenSim.Region.Physics.Meshing | |||
668 | 716 | ||
669 | // If this mesh has been created already, return it instead of creating another copy | 717 | // If this mesh has been created already, return it instead of creating another copy |
670 | // For large regions with 100k+ prims and hundreds of copies of each, this can save a GB or more of memory | 718 | // For large regions with 100k+ prims and hundreds of copies of each, this can save a GB or more of memory |
671 | 719 | key = primShape.GetMeshKey(size, lod); | |
672 | key = GetMeshKey(primShape, size, lod); | ||
673 | if (m_uniqueMeshes.TryGetValue(key, out mesh)) | 720 | if (m_uniqueMeshes.TryGetValue(key, out mesh)) |
674 | return mesh; | 721 | return mesh; |
675 | 722 | ||
diff --git a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs index 0e7dd81..c165a41 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs | |||
@@ -258,7 +258,11 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
258 | public override bool Flying | 258 | public override bool Flying |
259 | { | 259 | { |
260 | get { return flying; } | 260 | get { return flying; } |
261 | set { flying = value; } | 261 | set |
262 | { | ||
263 | flying = value; | ||
264 | // m_log.DebugFormat("[PHYSICS]: Set OdeCharacter Flying to {0}", flying); | ||
265 | } | ||
262 | } | 266 | } |
263 | 267 | ||
264 | /// <summary> | 268 | /// <summary> |
@@ -305,10 +309,12 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
305 | { | 309 | { |
306 | m_iscolliding = true; | 310 | m_iscolliding = true; |
307 | } | 311 | } |
312 | |||
308 | if (m_wascolliding != m_iscolliding) | 313 | if (m_wascolliding != m_iscolliding) |
309 | { | 314 | { |
310 | //base.SendCollisionUpdate(new CollisionEventUpdate()); | 315 | //base.SendCollisionUpdate(new CollisionEventUpdate()); |
311 | } | 316 | } |
317 | |||
312 | m_wascolliding = m_iscolliding; | 318 | m_wascolliding = m_iscolliding; |
313 | } | 319 | } |
314 | } | 320 | } |
@@ -1219,18 +1225,23 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1219 | { | 1225 | { |
1220 | m_requestedUpdateFrequency = ms; | 1226 | m_requestedUpdateFrequency = ms; |
1221 | m_eventsubscription = ms; | 1227 | m_eventsubscription = ms; |
1222 | _parent_scene.addCollisionEventReporting(this); | 1228 | _parent_scene.AddCollisionEventReporting(this); |
1223 | } | 1229 | } |
1230 | |||
1224 | public override void UnSubscribeEvents() | 1231 | public override void UnSubscribeEvents() |
1225 | { | 1232 | { |
1226 | _parent_scene.remCollisionEventReporting(this); | 1233 | _parent_scene.RemoveCollisionEventReporting(this); |
1227 | m_requestedUpdateFrequency = 0; | 1234 | m_requestedUpdateFrequency = 0; |
1228 | m_eventsubscription = 0; | 1235 | m_eventsubscription = 0; |
1229 | } | 1236 | } |
1237 | |||
1230 | public void AddCollisionEvent(uint CollidedWith, ContactPoint contact) | 1238 | public void AddCollisionEvent(uint CollidedWith, ContactPoint contact) |
1231 | { | 1239 | { |
1232 | if (m_eventsubscription > 0) | 1240 | if (m_eventsubscription > 0) |
1233 | { | 1241 | { |
1242 | // m_log.DebugFormat( | ||
1243 | // "[PHYSICS]: Adding collision event for {0}, collidedWith {1}, contact {2}", "", CollidedWith, contact); | ||
1244 | |||
1234 | CollisionEventsThisFrame.addCollider(CollidedWith, contact); | 1245 | CollisionEventsThisFrame.addCollider(CollidedWith, contact); |
1235 | } | 1246 | } |
1236 | } | 1247 | } |
@@ -1247,6 +1258,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1247 | m_eventsubscription = 0; | 1258 | m_eventsubscription = 0; |
1248 | } | 1259 | } |
1249 | } | 1260 | } |
1261 | |||
1250 | public override bool SubscribedEvents() | 1262 | public override bool SubscribedEvents() |
1251 | { | 1263 | { |
1252 | if (m_eventsubscription > 0) | 1264 | if (m_eventsubscription > 0) |
diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs index 5fe0775..0a4fc51 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs | |||
@@ -61,6 +61,22 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
61 | { | 61 | { |
62 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 62 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
63 | 63 | ||
64 | private bool m_isphysical; | ||
65 | |||
66 | /// <summary> | ||
67 | /// Is this prim subject to physics? Even if not, it's still solid for collision purposes. | ||
68 | /// </summary> | ||
69 | public override bool IsPhysical | ||
70 | { | ||
71 | get { return m_isphysical; } | ||
72 | set | ||
73 | { | ||
74 | m_isphysical = value; | ||
75 | if (!m_isphysical) // Zero the remembered last velocity | ||
76 | m_lastVelocity = Vector3.Zero; | ||
77 | } | ||
78 | } | ||
79 | |||
64 | private Vector3 _position; | 80 | private Vector3 _position; |
65 | private Vector3 _velocity; | 81 | private Vector3 _velocity; |
66 | private Vector3 _torque; | 82 | private Vector3 _torque; |
@@ -138,12 +154,15 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
138 | private List<Vector3> m_forcelist = new List<Vector3>(); | 154 | private List<Vector3> m_forcelist = new List<Vector3>(); |
139 | private List<Vector3> m_angularforcelist = new List<Vector3>(); | 155 | private List<Vector3> m_angularforcelist = new List<Vector3>(); |
140 | 156 | ||
141 | private IMesh _mesh; | ||
142 | private PrimitiveBaseShape _pbs; | 157 | private PrimitiveBaseShape _pbs; |
143 | private OdeScene _parent_scene; | 158 | private OdeScene _parent_scene; |
159 | |||
160 | /// <summary> | ||
161 | /// The physics space which contains prim geometries | ||
162 | /// </summary> | ||
144 | public IntPtr m_targetSpace = IntPtr.Zero; | 163 | public IntPtr m_targetSpace = IntPtr.Zero; |
164 | |||
145 | public IntPtr prim_geom; | 165 | public IntPtr prim_geom; |
146 | public IntPtr prev_geom; | ||
147 | public IntPtr _triMeshData; | 166 | public IntPtr _triMeshData; |
148 | 167 | ||
149 | private IntPtr _linkJointGroup = IntPtr.Zero; | 168 | private IntPtr _linkJointGroup = IntPtr.Zero; |
@@ -153,7 +172,6 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
153 | private List<OdePrim> childrenPrim = new List<OdePrim>(); | 172 | private List<OdePrim> childrenPrim = new List<OdePrim>(); |
154 | 173 | ||
155 | private bool iscolliding; | 174 | private bool iscolliding; |
156 | private bool m_isphysical; | ||
157 | private bool m_isSelected; | 175 | private bool m_isSelected; |
158 | 176 | ||
159 | internal bool m_isVolumeDetect; // If true, this prim only detects collisions but doesn't collide actively | 177 | internal bool m_isVolumeDetect; // If true, this prim only detects collisions but doesn't collide actively |
@@ -188,7 +206,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
188 | internal int m_material = (int)Material.Wood; | 206 | internal int m_material = (int)Material.Wood; |
189 | 207 | ||
190 | public OdePrim(String primName, OdeScene parent_scene, Vector3 pos, Vector3 size, | 208 | public OdePrim(String primName, OdeScene parent_scene, Vector3 pos, Vector3 size, |
191 | Quaternion rotation, IMesh mesh, PrimitiveBaseShape pbs, bool pisPhysical, CollisionLocker dode) | 209 | Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical, CollisionLocker dode) |
192 | { | 210 | { |
193 | Name = primName; | 211 | Name = primName; |
194 | m_vehicle = new ODEDynamics(); | 212 | m_vehicle = new ODEDynamics(); |
@@ -208,9 +226,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
208 | // m_tensor = parent_scene.bodyMotorJointMaxforceTensor; | 226 | // m_tensor = parent_scene.bodyMotorJointMaxforceTensor; |
209 | body_autodisable_frames = parent_scene.bodyFramesAutoDisable; | 227 | body_autodisable_frames = parent_scene.bodyFramesAutoDisable; |
210 | 228 | ||
211 | |||
212 | prim_geom = IntPtr.Zero; | 229 | prim_geom = IntPtr.Zero; |
213 | prev_geom = IntPtr.Zero; | ||
214 | 230 | ||
215 | if (!pos.IsFinite()) | 231 | if (!pos.IsFinite()) |
216 | { | 232 | { |
@@ -233,20 +249,21 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
233 | 249 | ||
234 | _orientation = rotation; | 250 | _orientation = rotation; |
235 | m_taintrot = _orientation; | 251 | m_taintrot = _orientation; |
236 | _mesh = mesh; | ||
237 | _pbs = pbs; | 252 | _pbs = pbs; |
238 | 253 | ||
239 | _parent_scene = parent_scene; | 254 | _parent_scene = parent_scene; |
240 | m_targetSpace = (IntPtr)0; | 255 | m_targetSpace = (IntPtr)0; |
241 | 256 | ||
242 | if (pos.Z < 0) | 257 | if (pos.Z < 0) |
243 | m_isphysical = false; | 258 | { |
259 | IsPhysical = false; | ||
260 | } | ||
244 | else | 261 | else |
245 | { | 262 | { |
246 | m_isphysical = pisPhysical; | 263 | IsPhysical = pisPhysical; |
247 | // If we're physical, we need to be in the master space for now. | 264 | // If we're physical, we need to be in the master space for now. |
248 | // linksets *should* be in a space together.. but are not currently | 265 | // linksets *should* be in a space together.. but are not currently |
249 | if (m_isphysical) | 266 | if (IsPhysical) |
250 | m_targetSpace = _parent_scene.space; | 267 | m_targetSpace = _parent_scene.space; |
251 | } | 268 | } |
252 | 269 | ||
@@ -289,7 +306,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
289 | // through it while it's selected | 306 | // through it while it's selected |
290 | m_collisionscore = 0; | 307 | m_collisionscore = 0; |
291 | 308 | ||
292 | if ((m_isphysical && !_zeroFlag) || !value) | 309 | if ((IsPhysical && !_zeroFlag) || !value) |
293 | { | 310 | { |
294 | m_taintselected = value; | 311 | m_taintselected = value; |
295 | _parent_scene.AddPhysicsActorTaint(this); | 312 | _parent_scene.AddPhysicsActorTaint(this); |
@@ -305,15 +322,21 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
305 | } | 322 | } |
306 | } | 323 | } |
307 | 324 | ||
325 | /// <summary> | ||
326 | /// Set a new geometry for this prim. | ||
327 | /// </summary> | ||
328 | /// <param name="geom"></param> | ||
308 | public void SetGeom(IntPtr geom) | 329 | public void SetGeom(IntPtr geom) |
309 | { | 330 | { |
310 | prev_geom = prim_geom; | ||
311 | prim_geom = geom; | 331 | prim_geom = geom; |
312 | //Console.WriteLine("SetGeom to " + prim_geom + " for " + Name); | 332 | //Console.WriteLine("SetGeom to " + prim_geom + " for " + Name); |
313 | if (prim_geom != IntPtr.Zero) | 333 | if (prim_geom != IntPtr.Zero) |
314 | { | 334 | { |
315 | d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); | 335 | d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); |
316 | d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); | 336 | d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); |
337 | |||
338 | _parent_scene.geom_name_map[prim_geom] = Name; | ||
339 | _parent_scene.actor_name_map[prim_geom] = this; | ||
317 | } | 340 | } |
318 | 341 | ||
319 | if (childPrim) | 342 | if (childPrim) |
@@ -332,7 +355,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
332 | { | 355 | { |
333 | if (!childPrim) | 356 | if (!childPrim) |
334 | { | 357 | { |
335 | if (m_isphysical && Body != IntPtr.Zero) | 358 | if (IsPhysical && Body != IntPtr.Zero) |
336 | { | 359 | { |
337 | d.BodyEnable(Body); | 360 | d.BodyEnable(Body); |
338 | if (m_vehicle.Type != Vehicle.TYPE_NONE) | 361 | if (m_vehicle.Type != Vehicle.TYPE_NONE) |
@@ -347,12 +370,15 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
347 | { | 370 | { |
348 | m_disabled = true; | 371 | m_disabled = true; |
349 | 372 | ||
350 | if (m_isphysical && Body != IntPtr.Zero) | 373 | if (IsPhysical && Body != IntPtr.Zero) |
351 | { | 374 | { |
352 | d.BodyDisable(Body); | 375 | d.BodyDisable(Body); |
353 | } | 376 | } |
354 | } | 377 | } |
355 | 378 | ||
379 | /// <summary> | ||
380 | /// Make a prim subject to physics. | ||
381 | /// </summary> | ||
356 | public void enableBody() | 382 | public void enableBody() |
357 | { | 383 | { |
358 | // Don't enable this body if we're a child prim | 384 | // Don't enable this body if we're a child prim |
@@ -638,7 +664,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
638 | float profileEnd; | 664 | float profileEnd; |
639 | 665 | ||
640 | if (_pbs.PathCurve == (byte)Extrusion.Straight || _pbs.PathCurve == (byte)Extrusion.Flexible) | 666 | if (_pbs.PathCurve == (byte)Extrusion.Straight || _pbs.PathCurve == (byte)Extrusion.Flexible) |
641 | { | 667 | { |
642 | taperX1 = _pbs.PathScaleX * 0.01f; | 668 | taperX1 = _pbs.PathScaleX * 0.01f; |
643 | if (taperX1 > 1.0f) | 669 | if (taperX1 > 1.0f) |
644 | taperX1 = 2.0f - taperX1; | 670 | taperX1 = 2.0f - taperX1; |
@@ -648,9 +674,9 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
648 | if (taperY1 > 1.0f) | 674 | if (taperY1 > 1.0f) |
649 | taperY1 = 2.0f - taperY1; | 675 | taperY1 = 2.0f - taperY1; |
650 | taperY = 1.0f - taperY1; | 676 | taperY = 1.0f - taperY1; |
651 | } | 677 | } |
652 | else | 678 | else |
653 | { | 679 | { |
654 | taperX = _pbs.PathTaperX * 0.01f; | 680 | taperX = _pbs.PathTaperX * 0.01f; |
655 | if (taperX < 0.0f) | 681 | if (taperX < 0.0f) |
656 | taperX = -taperX; | 682 | taperX = -taperX; |
@@ -660,9 +686,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
660 | if (taperY < 0.0f) | 686 | if (taperY < 0.0f) |
661 | taperY = -taperY; | 687 | taperY = -taperY; |
662 | taperY1 = 1.0f - taperY; | 688 | taperY1 = 1.0f - taperY; |
663 | 689 | } | |
664 | } | ||
665 | |||
666 | 690 | ||
667 | volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY); | 691 | volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY); |
668 | 692 | ||
@@ -730,6 +754,9 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
730 | } | 754 | } |
731 | } | 755 | } |
732 | 756 | ||
757 | /// <summary> | ||
758 | /// Stop a prim from being subject to physics. | ||
759 | /// </summary> | ||
733 | public void disableBody() | 760 | public void disableBody() |
734 | { | 761 | { |
735 | //this kills the body so things like 'mesh' can re-create it. | 762 | //this kills the body so things like 'mesh' can re-create it. |
@@ -780,6 +807,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
780 | Body = IntPtr.Zero; | 807 | Body = IntPtr.Zero; |
781 | } | 808 | } |
782 | } | 809 | } |
810 | |||
783 | m_disabled = true; | 811 | m_disabled = true; |
784 | m_collisionscore = 0; | 812 | m_collisionscore = 0; |
785 | } | 813 | } |
@@ -846,7 +874,6 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
846 | return; | 874 | return; |
847 | } | 875 | } |
848 | 876 | ||
849 | |||
850 | // if (IsPhysical && Body == (IntPtr) 0) | 877 | // if (IsPhysical && Body == (IntPtr) 0) |
851 | // { | 878 | // { |
852 | // Recreate the body | 879 | // Recreate the body |
@@ -859,7 +886,9 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
859 | 886 | ||
860 | public void ProcessTaints(float timestep) | 887 | public void ProcessTaints(float timestep) |
861 | { | 888 | { |
862 | Console.WriteLine("ProcessTaints for " + Name); | 889 | #if SPAM |
890 | Console.WriteLine("ZProcessTaints for " + Name); | ||
891 | #endif | ||
863 | if (m_taintadd) | 892 | if (m_taintadd) |
864 | { | 893 | { |
865 | changeadd(timestep); | 894 | changeadd(timestep); |
@@ -887,7 +916,7 @@ Console.WriteLine("ProcessTaints for " + Name); | |||
887 | } | 916 | } |
888 | } | 917 | } |
889 | 918 | ||
890 | if (m_taintPhysics != m_isphysical && !(m_taintparent != _parent)) | 919 | if (m_taintPhysics != IsPhysical && !(m_taintparent != _parent)) |
891 | changePhysicsStatus(timestep); | 920 | changePhysicsStatus(timestep); |
892 | 921 | ||
893 | if (!_size.ApproxEquals(m_taintsize, 0f)) | 922 | if (!_size.ApproxEquals(m_taintsize, 0f)) |
@@ -969,7 +998,7 @@ Console.WriteLine("ProcessTaints for " + Name); | |||
969 | OdePrim obj = (OdePrim)m_taintparent; | 998 | OdePrim obj = (OdePrim)m_taintparent; |
970 | //obj.disableBody(); | 999 | //obj.disableBody(); |
971 | //Console.WriteLine("changelink calls ParentPrim"); | 1000 | //Console.WriteLine("changelink calls ParentPrim"); |
972 | obj.ParentPrim(this); | 1001 | obj.AddChildPrim(this); |
973 | 1002 | ||
974 | /* | 1003 | /* |
975 | if (obj.Body != (IntPtr)0 && Body != (IntPtr)0 && obj.Body != Body) | 1004 | if (obj.Body != (IntPtr)0 && Body != (IntPtr)0 && obj.Body != Body) |
@@ -1006,14 +1035,16 @@ Console.WriteLine("ProcessTaints for " + Name); | |||
1006 | } | 1035 | } |
1007 | 1036 | ||
1008 | _parent = m_taintparent; | 1037 | _parent = m_taintparent; |
1009 | m_taintPhysics = m_isphysical; | 1038 | m_taintPhysics = IsPhysical; |
1010 | } | 1039 | } |
1011 | 1040 | ||
1012 | // I'm the parent | 1041 | /// <summary> |
1013 | // prim is the child | 1042 | /// Add a child prim to this parent prim. |
1014 | public void ParentPrim(OdePrim prim) | 1043 | /// </summary> |
1044 | /// <param name="prim">Child prim</param> | ||
1045 | public void AddChildPrim(OdePrim prim) | ||
1015 | { | 1046 | { |
1016 | //Console.WriteLine("ParentPrim " + Name); | 1047 | //Console.WriteLine("AddChildPrim " + Name); |
1017 | if (this.m_localID != prim.m_localID) | 1048 | if (this.m_localID != prim.m_localID) |
1018 | { | 1049 | { |
1019 | if (Body == IntPtr.Zero) | 1050 | if (Body == IntPtr.Zero) |
@@ -1036,7 +1067,6 @@ Console.WriteLine("ProcessTaints for " + Name); | |||
1036 | d.MassSetZero(out m2); | 1067 | d.MassSetZero(out m2); |
1037 | d.MassSetBoxTotal(out m2, prim.CalculateMass(), prm._size.X, prm._size.Y, prm._size.Z); | 1068 | d.MassSetBoxTotal(out m2, prim.CalculateMass(), prm._size.X, prm._size.Y, prm._size.Z); |
1038 | 1069 | ||
1039 | |||
1040 | d.Quaternion quat = new d.Quaternion(); | 1070 | d.Quaternion quat = new d.Quaternion(); |
1041 | quat.W = prm._orientation.W; | 1071 | quat.W = prm._orientation.W; |
1042 | quat.X = prm._orientation.X; | 1072 | quat.X = prm._orientation.X; |
@@ -1106,6 +1136,7 @@ Console.WriteLine("ProcessTaints for " + Name); | |||
1106 | prm.Body = Body; | 1136 | prm.Body = Body; |
1107 | _parent_scene.addActivePrim(prm); | 1137 | _parent_scene.addActivePrim(prm); |
1108 | } | 1138 | } |
1139 | |||
1109 | m_collisionCategories |= CollisionCategories.Body; | 1140 | m_collisionCategories |= CollisionCategories.Body; |
1110 | m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind); | 1141 | m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind); |
1111 | 1142 | ||
@@ -1114,7 +1145,6 @@ Console.WriteLine("ProcessTaints for " + Name); | |||
1114 | //Console.WriteLine(" Post GeomSetCategoryBits 2"); | 1145 | //Console.WriteLine(" Post GeomSetCategoryBits 2"); |
1115 | d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); | 1146 | d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); |
1116 | 1147 | ||
1117 | |||
1118 | d.Quaternion quat2 = new d.Quaternion(); | 1148 | d.Quaternion quat2 = new d.Quaternion(); |
1119 | quat2.W = _orientation.W; | 1149 | quat2.W = _orientation.W; |
1120 | quat2.X = _orientation.X; | 1150 | quat2.X = _orientation.X; |
@@ -1136,7 +1166,6 @@ Console.WriteLine("ProcessTaints for " + Name); | |||
1136 | d.BodySetAutoDisableFlag(Body, true); | 1166 | d.BodySetAutoDisableFlag(Body, true); |
1137 | d.BodySetAutoDisableSteps(Body, body_autodisable_frames); | 1167 | d.BodySetAutoDisableSteps(Body, body_autodisable_frames); |
1138 | 1168 | ||
1139 | |||
1140 | m_interpenetrationcount = 0; | 1169 | m_interpenetrationcount = 0; |
1141 | m_collisionscore = 0; | 1170 | m_collisionscore = 0; |
1142 | m_disabled = false; | 1171 | m_disabled = false; |
@@ -1147,7 +1176,9 @@ Console.WriteLine("ProcessTaints for " + Name); | |||
1147 | createAMotor(m_angularlock); | 1176 | createAMotor(m_angularlock); |
1148 | } | 1177 | } |
1149 | d.BodySetPosition(Body, Position.X, Position.Y, Position.Z); | 1178 | d.BodySetPosition(Body, Position.X, Position.Y, Position.Z); |
1150 | if (m_vehicle.Type != Vehicle.TYPE_NONE) m_vehicle.Enable(Body, _parent_scene); | 1179 | if (m_vehicle.Type != Vehicle.TYPE_NONE) |
1180 | m_vehicle.Enable(Body, _parent_scene); | ||
1181 | |||
1151 | _parent_scene.addActivePrim(this); | 1182 | _parent_scene.addActivePrim(this); |
1152 | } | 1183 | } |
1153 | } | 1184 | } |
@@ -1157,7 +1188,7 @@ Console.WriteLine("ProcessTaints for " + Name); | |||
1157 | 1188 | ||
1158 | private void ChildSetGeom(OdePrim odePrim) | 1189 | private void ChildSetGeom(OdePrim odePrim) |
1159 | { | 1190 | { |
1160 | //if (m_isphysical && Body != IntPtr.Zero) | 1191 | //if (IsPhysical && Body != IntPtr.Zero) |
1161 | lock (childrenPrim) | 1192 | lock (childrenPrim) |
1162 | { | 1193 | { |
1163 | foreach (OdePrim prm in childrenPrim) | 1194 | foreach (OdePrim prm in childrenPrim) |
@@ -1173,7 +1204,6 @@ Console.WriteLine("ProcessTaints for " + Name); | |||
1173 | } | 1204 | } |
1174 | disableBody(); | 1205 | disableBody(); |
1175 | 1206 | ||
1176 | |||
1177 | if (Body != IntPtr.Zero) | 1207 | if (Body != IntPtr.Zero) |
1178 | { | 1208 | { |
1179 | _parent_scene.remActivePrim(this); | 1209 | _parent_scene.remActivePrim(this); |
@@ -1184,10 +1214,9 @@ Console.WriteLine("ProcessTaints for " + Name); | |||
1184 | foreach (OdePrim prm in childrenPrim) | 1214 | foreach (OdePrim prm in childrenPrim) |
1185 | { | 1215 | { |
1186 | //Console.WriteLine("ChildSetGeom calls ParentPrim"); | 1216 | //Console.WriteLine("ChildSetGeom calls ParentPrim"); |
1187 | ParentPrim(prm); | 1217 | AddChildPrim(prm); |
1188 | } | 1218 | } |
1189 | } | 1219 | } |
1190 | |||
1191 | } | 1220 | } |
1192 | 1221 | ||
1193 | private void ChildDelink(OdePrim odePrim) | 1222 | private void ChildDelink(OdePrim odePrim) |
@@ -1224,7 +1253,7 @@ Console.WriteLine("ProcessTaints for " + Name); | |||
1224 | foreach (OdePrim prm in childrenPrim) | 1253 | foreach (OdePrim prm in childrenPrim) |
1225 | { | 1254 | { |
1226 | //Console.WriteLine("ChildDelink calls ParentPrim"); | 1255 | //Console.WriteLine("ChildDelink calls ParentPrim"); |
1227 | ParentPrim(prm); | 1256 | AddChildPrim(prm); |
1228 | } | 1257 | } |
1229 | } | 1258 | } |
1230 | } | 1259 | } |
@@ -1258,7 +1287,7 @@ Console.WriteLine("ProcessTaints for " + Name); | |||
1258 | // first 50 again. then the last 50 are disabled. then the first 50, which were just woken | 1287 | // first 50 again. then the last 50 are disabled. then the first 50, which were just woken |
1259 | // up, start simulating again, which in turn wakes up the last 50. | 1288 | // up, start simulating again, which in turn wakes up the last 50. |
1260 | 1289 | ||
1261 | if (m_isphysical) | 1290 | if (IsPhysical) |
1262 | { | 1291 | { |
1263 | disableBodySoft(); | 1292 | disableBodySoft(); |
1264 | } | 1293 | } |
@@ -1269,7 +1298,7 @@ Console.WriteLine("ProcessTaints for " + Name); | |||
1269 | d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); | 1298 | d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); |
1270 | } | 1299 | } |
1271 | 1300 | ||
1272 | if (m_isphysical) | 1301 | if (IsPhysical) |
1273 | { | 1302 | { |
1274 | disableBodySoft(); | 1303 | disableBodySoft(); |
1275 | } | 1304 | } |
@@ -1278,7 +1307,7 @@ Console.WriteLine("ProcessTaints for " + Name); | |||
1278 | { | 1307 | { |
1279 | m_collisionCategories = CollisionCategories.Geom; | 1308 | m_collisionCategories = CollisionCategories.Geom; |
1280 | 1309 | ||
1281 | if (m_isphysical) | 1310 | if (IsPhysical) |
1282 | m_collisionCategories |= CollisionCategories.Body; | 1311 | m_collisionCategories |= CollisionCategories.Body; |
1283 | 1312 | ||
1284 | m_collisionFlags = m_default_collisionFlags; | 1313 | m_collisionFlags = m_default_collisionFlags; |
@@ -1293,7 +1322,8 @@ Console.WriteLine("ProcessTaints for " + Name); | |||
1293 | d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); | 1322 | d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); |
1294 | d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); | 1323 | d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); |
1295 | } | 1324 | } |
1296 | if (m_isphysical) | 1325 | |
1326 | if (IsPhysical) | ||
1297 | { | 1327 | { |
1298 | if (Body != IntPtr.Zero) | 1328 | if (Body != IntPtr.Zero) |
1299 | { | 1329 | { |
@@ -1312,7 +1342,7 @@ Console.WriteLine("ProcessTaints for " + Name); | |||
1312 | { | 1342 | { |
1313 | m_taintposition = _position; | 1343 | m_taintposition = _position; |
1314 | m_taintrot = _orientation; | 1344 | m_taintrot = _orientation; |
1315 | m_taintPhysics = m_isphysical; | 1345 | m_taintPhysics = IsPhysical; |
1316 | m_taintselected = m_isSelected; | 1346 | m_taintselected = m_isSelected; |
1317 | m_taintsize = _size; | 1347 | m_taintsize = _size; |
1318 | m_taintshape = false; | 1348 | m_taintshape = false; |
@@ -1321,12 +1351,19 @@ Console.WriteLine("ProcessTaints for " + Name); | |||
1321 | m_taintVelocity = Vector3.Zero; | 1351 | m_taintVelocity = Vector3.Zero; |
1322 | } | 1352 | } |
1323 | 1353 | ||
1324 | public void CreateGeom(IntPtr m_targetSpace, IMesh _mesh) | 1354 | /// <summary> |
1355 | /// Create a geometry for the given mesh in the given target space. | ||
1356 | /// </summary> | ||
1357 | /// <param name="m_targetSpace"></param> | ||
1358 | /// <param name="mesh">If null, then a mesh is used that is based on the profile shape data.</param> | ||
1359 | public void CreateGeom(IntPtr m_targetSpace, IMesh mesh) | ||
1325 | { | 1360 | { |
1326 | //Console.WriteLine("CreateGeom:"); | 1361 | #if SPAM |
1327 | if (_mesh != null) | 1362 | Console.WriteLine("CreateGeom:"); |
1363 | #endif | ||
1364 | if (mesh != null) | ||
1328 | { | 1365 | { |
1329 | setMesh(_parent_scene, _mesh); | 1366 | setMesh(_parent_scene, mesh); |
1330 | } | 1367 | } |
1331 | else | 1368 | else |
1332 | { | 1369 | { |
@@ -1399,6 +1436,39 @@ Console.WriteLine("ProcessTaints for " + Name); | |||
1399 | } | 1436 | } |
1400 | } | 1437 | } |
1401 | 1438 | ||
1439 | /// <summary> | ||
1440 | /// Remove the existing geom from this prim. | ||
1441 | /// </summary> | ||
1442 | /// <param name="m_targetSpace"></param> | ||
1443 | /// <param name="mesh">If null, then a mesh is used that is based on the profile shape data.</param> | ||
1444 | /// <returns>true if the geom was successfully removed, false if it was already gone or the remove failed.</returns> | ||
1445 | public bool RemoveGeom() | ||
1446 | { | ||
1447 | if (prim_geom != IntPtr.Zero) | ||
1448 | { | ||
1449 | try | ||
1450 | { | ||
1451 | _parent_scene.geom_name_map.Remove(prim_geom); | ||
1452 | _parent_scene.actor_name_map.Remove(prim_geom); | ||
1453 | d.GeomDestroy(prim_geom); | ||
1454 | prim_geom = IntPtr.Zero; | ||
1455 | } | ||
1456 | catch (System.AccessViolationException) | ||
1457 | { | ||
1458 | prim_geom = IntPtr.Zero; | ||
1459 | m_log.ErrorFormat("[PHYSICS]: PrimGeom dead for {0}", Name); | ||
1460 | |||
1461 | return false; | ||
1462 | } | ||
1463 | |||
1464 | return true; | ||
1465 | } | ||
1466 | else | ||
1467 | { | ||
1468 | return false; | ||
1469 | } | ||
1470 | } | ||
1471 | |||
1402 | public void changeadd(float timestep) | 1472 | public void changeadd(float timestep) |
1403 | { | 1473 | { |
1404 | int[] iprimspaceArrItem = _parent_scene.calculateSpaceArrayItemFromPos(_position); | 1474 | int[] iprimspaceArrItem = _parent_scene.calculateSpaceArrayItemFromPos(_position); |
@@ -1409,15 +1479,14 @@ Console.WriteLine("ProcessTaints for " + Name); | |||
1409 | 1479 | ||
1410 | m_targetSpace = targetspace; | 1480 | m_targetSpace = targetspace; |
1411 | 1481 | ||
1412 | if (_mesh == null) | 1482 | IMesh mesh = null; |
1483 | |||
1484 | if (_parent_scene.needsMeshing(_pbs)) | ||
1413 | { | 1485 | { |
1414 | if (_parent_scene.needsMeshing(_pbs)) | 1486 | // Don't need to re-enable body.. it's done in SetMesh |
1415 | { | 1487 | mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, _parent_scene.meshSculptLOD, IsPhysical); |
1416 | // Don't need to re-enable body.. it's done in SetMesh | 1488 | // createmesh returns null when it's a shape that isn't a cube. |
1417 | _mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, _parent_scene.meshSculptLOD, IsPhysical); | 1489 | // m_log.Debug(m_localID); |
1418 | // createmesh returns null when it's a shape that isn't a cube. | ||
1419 | // m_log.Debug(m_localID); | ||
1420 | } | ||
1421 | } | 1490 | } |
1422 | 1491 | ||
1423 | lock (_parent_scene.OdeLock) | 1492 | lock (_parent_scene.OdeLock) |
@@ -1425,7 +1494,7 @@ Console.WriteLine("ProcessTaints for " + Name); | |||
1425 | #if SPAM | 1494 | #if SPAM |
1426 | Console.WriteLine("changeadd 1"); | 1495 | Console.WriteLine("changeadd 1"); |
1427 | #endif | 1496 | #endif |
1428 | CreateGeom(m_targetSpace, _mesh); | 1497 | CreateGeom(m_targetSpace, mesh); |
1429 | 1498 | ||
1430 | if (prim_geom != IntPtr.Zero) | 1499 | if (prim_geom != IntPtr.Zero) |
1431 | { | 1500 | { |
@@ -1438,15 +1507,12 @@ Console.WriteLine("changeadd 1"); | |||
1438 | d.GeomSetQuaternion(prim_geom, ref myrot); | 1507 | d.GeomSetQuaternion(prim_geom, ref myrot); |
1439 | } | 1508 | } |
1440 | 1509 | ||
1441 | if (m_isphysical && Body == IntPtr.Zero) | 1510 | if (IsPhysical && Body == IntPtr.Zero) |
1442 | { | 1511 | { |
1443 | enableBody(); | 1512 | enableBody(); |
1444 | } | 1513 | } |
1445 | } | 1514 | } |
1446 | 1515 | ||
1447 | _parent_scene.geom_name_map[prim_geom] = this.Name; | ||
1448 | _parent_scene.actor_name_map[prim_geom] = (PhysicsActor)this; | ||
1449 | |||
1450 | changeSelectedStatus(timestep); | 1516 | changeSelectedStatus(timestep); |
1451 | 1517 | ||
1452 | m_taintadd = false; | 1518 | m_taintadd = false; |
@@ -1454,9 +1520,8 @@ Console.WriteLine("changeadd 1"); | |||
1454 | 1520 | ||
1455 | public void changemove(float timestep) | 1521 | public void changemove(float timestep) |
1456 | { | 1522 | { |
1457 | if (m_isphysical) | 1523 | if (IsPhysical) |
1458 | { | 1524 | { |
1459 | |||
1460 | if (!m_disabled && !m_taintremove && !childPrim) | 1525 | if (!m_disabled && !m_taintremove && !childPrim) |
1461 | { | 1526 | { |
1462 | if (Body == IntPtr.Zero) | 1527 | if (Body == IntPtr.Zero) |
@@ -1788,7 +1853,7 @@ Console.WriteLine(" JointCreateFixed"); | |||
1788 | { | 1853 | { |
1789 | // KF: If this is a root prim do BodySet | 1854 | // KF: If this is a root prim do BodySet |
1790 | d.BodySetQuaternion(Body, ref myrot); | 1855 | d.BodySetQuaternion(Body, ref myrot); |
1791 | if (m_isphysical) | 1856 | if (IsPhysical) |
1792 | { | 1857 | { |
1793 | if (!m_angularlock.ApproxEquals(Vector3.One, 0f)) | 1858 | if (!m_angularlock.ApproxEquals(Vector3.One, 0f)) |
1794 | createAMotor(m_angularlock); | 1859 | createAMotor(m_angularlock); |
@@ -1825,7 +1890,7 @@ Console.WriteLine(" JointCreateFixed"); | |||
1825 | 1890 | ||
1826 | public void changePhysicsStatus(float timestep) | 1891 | public void changePhysicsStatus(float timestep) |
1827 | { | 1892 | { |
1828 | if (m_isphysical == true) | 1893 | if (IsPhysical) |
1829 | { | 1894 | { |
1830 | if (Body == IntPtr.Zero) | 1895 | if (Body == IntPtr.Zero) |
1831 | { | 1896 | { |
@@ -1845,25 +1910,12 @@ Console.WriteLine(" JointCreateFixed"); | |||
1845 | { | 1910 | { |
1846 | if (_pbs.SculptEntry && _parent_scene.meshSculptedPrim) | 1911 | if (_pbs.SculptEntry && _parent_scene.meshSculptedPrim) |
1847 | { | 1912 | { |
1848 | 1913 | RemoveGeom(); | |
1849 | 1914 | ||
1850 | if (prim_geom != IntPtr.Zero) | ||
1851 | { | ||
1852 | try | ||
1853 | { | ||
1854 | d.GeomDestroy(prim_geom); | ||
1855 | prim_geom = IntPtr.Zero; | ||
1856 | _mesh = null; | ||
1857 | } | ||
1858 | catch (System.AccessViolationException) | ||
1859 | { | ||
1860 | prim_geom = IntPtr.Zero; | ||
1861 | m_log.ErrorFormat("[PHYSICS]: PrimGeom dead for {0}", Name); | ||
1862 | } | ||
1863 | } | ||
1864 | //Console.WriteLine("changePhysicsStatus for " + Name); | 1915 | //Console.WriteLine("changePhysicsStatus for " + Name); |
1865 | changeadd(2f); | 1916 | changeadd(2f); |
1866 | } | 1917 | } |
1918 | |||
1867 | if (childPrim) | 1919 | if (childPrim) |
1868 | { | 1920 | { |
1869 | if (_parent != null) | 1921 | if (_parent != null) |
@@ -1882,7 +1934,7 @@ Console.WriteLine(" JointCreateFixed"); | |||
1882 | changeSelectedStatus(timestep); | 1934 | changeSelectedStatus(timestep); |
1883 | 1935 | ||
1884 | resetCollisionAccounting(); | 1936 | resetCollisionAccounting(); |
1885 | m_taintPhysics = m_isphysical; | 1937 | m_taintPhysics = IsPhysical; |
1886 | } | 1938 | } |
1887 | 1939 | ||
1888 | public void changesize(float timestamp) | 1940 | public void changesize(float timestamp) |
@@ -1891,18 +1943,10 @@ Console.WriteLine(" JointCreateFixed"); | |||
1891 | m_log.DebugFormat("[ODE PRIM]: Called changesize"); | 1943 | m_log.DebugFormat("[ODE PRIM]: Called changesize"); |
1892 | #endif | 1944 | #endif |
1893 | 1945 | ||
1894 | string oldname = _parent_scene.geom_name_map[prim_geom]; | ||
1895 | |||
1896 | if (_size.X <= 0) _size.X = 0.01f; | 1946 | if (_size.X <= 0) _size.X = 0.01f; |
1897 | if (_size.Y <= 0) _size.Y = 0.01f; | 1947 | if (_size.Y <= 0) _size.Y = 0.01f; |
1898 | if (_size.Z <= 0) _size.Z = 0.01f; | 1948 | if (_size.Z <= 0) _size.Z = 0.01f; |
1899 | 1949 | ||
1900 | // Cleanup of old prim geometry | ||
1901 | if (_mesh != null) | ||
1902 | { | ||
1903 | // TODO: Cleanup meshing here | ||
1904 | } | ||
1905 | |||
1906 | //kill body to rebuild | 1950 | //kill body to rebuild |
1907 | if (IsPhysical && Body != IntPtr.Zero) | 1951 | if (IsPhysical && Body != IntPtr.Zero) |
1908 | { | 1952 | { |
@@ -1926,10 +1970,12 @@ Console.WriteLine(" JointCreateFixed"); | |||
1926 | d.SpaceRemove(m_targetSpace, prim_geom); | 1970 | d.SpaceRemove(m_targetSpace, prim_geom); |
1927 | } | 1971 | } |
1928 | 1972 | ||
1929 | d.GeomDestroy(prim_geom); | 1973 | RemoveGeom(); |
1930 | prim_geom = IntPtr.Zero; | 1974 | |
1931 | // we don't need to do space calculation because the client sends a position update also. | 1975 | // we don't need to do space calculation because the client sends a position update also. |
1932 | 1976 | ||
1977 | IMesh mesh = null; | ||
1978 | |||
1933 | // Construction of new prim | 1979 | // Construction of new prim |
1934 | if (_parent_scene.needsMeshing(_pbs)) | 1980 | if (_parent_scene.needsMeshing(_pbs)) |
1935 | { | 1981 | { |
@@ -1939,28 +1985,11 @@ Console.WriteLine(" JointCreateFixed"); | |||
1939 | meshlod = _parent_scene.MeshSculptphysicalLOD; | 1985 | meshlod = _parent_scene.MeshSculptphysicalLOD; |
1940 | // Don't need to re-enable body.. it's done in SetMesh | 1986 | // Don't need to re-enable body.. it's done in SetMesh |
1941 | 1987 | ||
1942 | IMesh mesh = null; | ||
1943 | |||
1944 | if (_parent_scene.needsMeshing(_pbs)) | 1988 | if (_parent_scene.needsMeshing(_pbs)) |
1945 | mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, meshlod, IsPhysical); | 1989 | mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, meshlod, IsPhysical); |
1946 | |||
1947 | //IMesh mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, meshlod, IsPhysical); | ||
1948 | #if SPAM | ||
1949 | Console.WriteLine("changesize 1"); | ||
1950 | #endif | ||
1951 | CreateGeom(m_targetSpace, mesh); | ||
1952 | } | ||
1953 | else | ||
1954 | { | ||
1955 | _mesh = null; | ||
1956 | |||
1957 | #if SPAM | ||
1958 | Console.WriteLine("changesize 2"); | ||
1959 | #endif | ||
1960 | |||
1961 | CreateGeom(m_targetSpace, _mesh); | ||
1962 | } | 1990 | } |
1963 | 1991 | ||
1992 | CreateGeom(m_targetSpace, mesh); | ||
1964 | d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); | 1993 | d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); |
1965 | d.Quaternion myrot = new d.Quaternion(); | 1994 | d.Quaternion myrot = new d.Quaternion(); |
1966 | myrot.X = _orientation.X; | 1995 | myrot.X = _orientation.X; |
@@ -1978,8 +2007,6 @@ Console.WriteLine("changesize 2"); | |||
1978 | d.BodyEnable(Body); | 2007 | d.BodyEnable(Body); |
1979 | } | 2008 | } |
1980 | 2009 | ||
1981 | _parent_scene.geom_name_map[prim_geom] = oldname; | ||
1982 | |||
1983 | changeSelectedStatus(timestamp); | 2010 | changeSelectedStatus(timestamp); |
1984 | if (childPrim) | 2011 | if (childPrim) |
1985 | { | 2012 | { |
@@ -2013,8 +2040,6 @@ Console.WriteLine("changesize 2"); | |||
2013 | 2040 | ||
2014 | public void changeshape(float timestamp) | 2041 | public void changeshape(float timestamp) |
2015 | { | 2042 | { |
2016 | string oldname = _parent_scene.geom_name_map[prim_geom]; | ||
2017 | |||
2018 | // Cleanup of old prim geometry and Bodies | 2043 | // Cleanup of old prim geometry and Bodies |
2019 | if (IsPhysical && Body != IntPtr.Zero) | 2044 | if (IsPhysical && Body != IntPtr.Zero) |
2020 | { | 2045 | { |
@@ -2031,23 +2056,17 @@ Console.WriteLine("changesize 2"); | |||
2031 | disableBody(); | 2056 | disableBody(); |
2032 | } | 2057 | } |
2033 | } | 2058 | } |
2034 | try | ||
2035 | { | ||
2036 | d.GeomDestroy(prim_geom); | ||
2037 | } | ||
2038 | catch (System.AccessViolationException) | ||
2039 | { | ||
2040 | prim_geom = IntPtr.Zero; | ||
2041 | m_log.ErrorFormat("[PHYSICS]: PrimGeom dead for {0}", Name); | ||
2042 | } | ||
2043 | 2059 | ||
2044 | prim_geom = IntPtr.Zero; | 2060 | RemoveGeom(); |
2061 | |||
2045 | // we don't need to do space calculation because the client sends a position update also. | 2062 | // we don't need to do space calculation because the client sends a position update also. |
2046 | if (_size.X <= 0) _size.X = 0.01f; | 2063 | if (_size.X <= 0) _size.X = 0.01f; |
2047 | if (_size.Y <= 0) _size.Y = 0.01f; | 2064 | if (_size.Y <= 0) _size.Y = 0.01f; |
2048 | if (_size.Z <= 0) _size.Z = 0.01f; | 2065 | if (_size.Z <= 0) _size.Z = 0.01f; |
2049 | // Construction of new prim | 2066 | // Construction of new prim |
2050 | 2067 | ||
2068 | IMesh mesh = null; | ||
2069 | |||
2051 | if (_parent_scene.needsMeshing(_pbs)) | 2070 | if (_parent_scene.needsMeshing(_pbs)) |
2052 | { | 2071 | { |
2053 | // Don't need to re-enable body.. it's done in CreateMesh | 2072 | // Don't need to re-enable body.. it's done in CreateMesh |
@@ -2056,23 +2075,11 @@ Console.WriteLine("changesize 2"); | |||
2056 | if (IsPhysical) | 2075 | if (IsPhysical) |
2057 | meshlod = _parent_scene.MeshSculptphysicalLOD; | 2076 | meshlod = _parent_scene.MeshSculptphysicalLOD; |
2058 | 2077 | ||
2059 | IMesh mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, meshlod, IsPhysical); | ||
2060 | // createmesh returns null when it doesn't mesh. | 2078 | // createmesh returns null when it doesn't mesh. |
2061 | #if SPAM | 2079 | mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, meshlod, IsPhysical); |
2062 | Console.WriteLine("changeshape needed meshing"); | ||
2063 | #endif | ||
2064 | CreateGeom(m_targetSpace, mesh); | ||
2065 | } | ||
2066 | else | ||
2067 | { | ||
2068 | _mesh = null; | ||
2069 | |||
2070 | #if SPAM | ||
2071 | Console.WriteLine("changeshape not need meshing"); | ||
2072 | #endif | ||
2073 | CreateGeom(m_targetSpace, null); | ||
2074 | } | 2080 | } |
2075 | 2081 | ||
2082 | CreateGeom(m_targetSpace, mesh); | ||
2076 | d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); | 2083 | d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); |
2077 | d.Quaternion myrot = new d.Quaternion(); | 2084 | d.Quaternion myrot = new d.Quaternion(); |
2078 | //myrot.W = _orientation.w; | 2085 | //myrot.W = _orientation.w; |
@@ -2093,7 +2100,6 @@ Console.WriteLine("changeshape not need meshing"); | |||
2093 | d.BodyEnable(Body); | 2100 | d.BodyEnable(Body); |
2094 | } | 2101 | } |
2095 | } | 2102 | } |
2096 | _parent_scene.geom_name_map[prim_geom] = oldname; | ||
2097 | 2103 | ||
2098 | changeSelectedStatus(timestamp); | 2104 | changeSelectedStatus(timestamp); |
2099 | if (childPrim) | 2105 | if (childPrim) |
@@ -2104,6 +2110,7 @@ Console.WriteLine("changeshape not need meshing"); | |||
2104 | parent.ChildSetGeom(this); | 2110 | parent.ChildSetGeom(this); |
2105 | } | 2111 | } |
2106 | } | 2112 | } |
2113 | |||
2107 | resetCollisionAccounting(); | 2114 | resetCollisionAccounting(); |
2108 | m_taintshape = false; | 2115 | m_taintshape = false; |
2109 | } | 2116 | } |
@@ -2215,16 +2222,6 @@ Console.WriteLine("changeshape not need meshing"); | |||
2215 | m_taintVelocity = Vector3.Zero; | 2222 | m_taintVelocity = Vector3.Zero; |
2216 | } | 2223 | } |
2217 | 2224 | ||
2218 | public override bool IsPhysical | ||
2219 | { | ||
2220 | get { return m_isphysical; } | ||
2221 | set { | ||
2222 | m_isphysical = value; | ||
2223 | if (!m_isphysical) // Zero the remembered last velocity | ||
2224 | m_lastVelocity = Vector3.Zero; | ||
2225 | } | ||
2226 | } | ||
2227 | |||
2228 | public void setPrimForRemoval() | 2225 | public void setPrimForRemoval() |
2229 | { | 2226 | { |
2230 | m_taintremove = true; | 2227 | m_taintremove = true; |
@@ -2283,6 +2280,7 @@ Console.WriteLine("changeshape not need meshing"); | |||
2283 | if (value.IsFinite()) | 2280 | if (value.IsFinite()) |
2284 | { | 2281 | { |
2285 | _size = value; | 2282 | _size = value; |
2283 | // m_log.DebugFormat("[PHYSICS]: Set size on {0} to {1}", Name, value); | ||
2286 | } | 2284 | } |
2287 | else | 2285 | else |
2288 | { | 2286 | { |
@@ -2343,7 +2341,7 @@ Console.WriteLine("changeshape not need meshing"); | |||
2343 | { | 2341 | { |
2344 | lock (_parent_scene.OdeLock) | 2342 | lock (_parent_scene.OdeLock) |
2345 | { | 2343 | { |
2346 | m_isVolumeDetect = (param!=0); | 2344 | m_isVolumeDetect = (param != 0); |
2347 | } | 2345 | } |
2348 | } | 2346 | } |
2349 | 2347 | ||
@@ -2402,7 +2400,7 @@ Console.WriteLine("changeshape not need meshing"); | |||
2402 | { | 2400 | { |
2403 | get | 2401 | get |
2404 | { | 2402 | { |
2405 | if (!m_isphysical || Body == IntPtr.Zero) | 2403 | if (!IsPhysical || Body == IntPtr.Zero) |
2406 | return Vector3.Zero; | 2404 | return Vector3.Zero; |
2407 | 2405 | ||
2408 | return _torque; | 2406 | return _torque; |
@@ -2984,12 +2982,12 @@ Console.WriteLine("changeshape not need meshing"); | |||
2984 | public override void SubscribeEvents(int ms) | 2982 | public override void SubscribeEvents(int ms) |
2985 | { | 2983 | { |
2986 | m_eventsubscription = ms; | 2984 | m_eventsubscription = ms; |
2987 | _parent_scene.addCollisionEventReporting(this); | 2985 | _parent_scene.AddCollisionEventReporting(this); |
2988 | } | 2986 | } |
2989 | 2987 | ||
2990 | public override void UnSubscribeEvents() | 2988 | public override void UnSubscribeEvents() |
2991 | { | 2989 | { |
2992 | _parent_scene.remCollisionEventReporting(this); | 2990 | _parent_scene.RemoveCollisionEventReporting(this); |
2993 | m_eventsubscription = 0; | 2991 | m_eventsubscription = 0; |
2994 | } | 2992 | } |
2995 | 2993 | ||
@@ -2997,6 +2995,7 @@ Console.WriteLine("changeshape not need meshing"); | |||
2997 | { | 2995 | { |
2998 | if (CollisionEventsThisFrame == null) | 2996 | if (CollisionEventsThisFrame == null) |
2999 | CollisionEventsThisFrame = new CollisionEventUpdate(); | 2997 | CollisionEventsThisFrame = new CollisionEventUpdate(); |
2998 | |||
3000 | CollisionEventsThisFrame.addCollider(CollidedWith, contact); | 2999 | CollisionEventsThisFrame.addCollider(CollidedWith, contact); |
3001 | } | 3000 | } |
3002 | 3001 | ||
diff --git a/OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs b/OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs index 15ccddc..9d7aa94 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs | |||
@@ -45,11 +45,16 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
45 | public class ODERayCastRequestManager | 45 | public class ODERayCastRequestManager |
46 | { | 46 | { |
47 | /// <summary> | 47 | /// <summary> |
48 | /// Pending Raycast Requests | 48 | /// Pending raycast requests |
49 | /// </summary> | 49 | /// </summary> |
50 | protected List<ODERayCastRequest> m_PendingRequests = new List<ODERayCastRequest>(); | 50 | protected List<ODERayCastRequest> m_PendingRequests = new List<ODERayCastRequest>(); |
51 | 51 | ||
52 | /// <summary> | 52 | /// <summary> |
53 | /// Pending ray requests | ||
54 | /// </summary> | ||
55 | protected List<ODERayRequest> m_PendingRayRequests = new List<ODERayRequest>(); | ||
56 | |||
57 | /// <summary> | ||
53 | /// Scene that created this object. | 58 | /// Scene that created this object. |
54 | /// </summary> | 59 | /// </summary> |
55 | private OdeScene m_scene; | 60 | private OdeScene m_scene; |
@@ -96,6 +101,29 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
96 | } | 101 | } |
97 | 102 | ||
98 | /// <summary> | 103 | /// <summary> |
104 | /// Queues a raycast | ||
105 | /// </summary> | ||
106 | /// <param name="position">Origin of Ray</param> | ||
107 | /// <param name="direction">Ray normal</param> | ||
108 | /// <param name="length">Ray length</param> | ||
109 | /// <param name="count"></param> | ||
110 | /// <param name="retMethod">Return method to send the results</param> | ||
111 | public void QueueRequest(Vector3 position, Vector3 direction, float length, int count, RayCallback retMethod) | ||
112 | { | ||
113 | lock (m_PendingRequests) | ||
114 | { | ||
115 | ODERayRequest req = new ODERayRequest(); | ||
116 | req.callbackMethod = retMethod; | ||
117 | req.length = length; | ||
118 | req.Normal = direction; | ||
119 | req.Origin = position; | ||
120 | req.Count = count; | ||
121 | |||
122 | m_PendingRayRequests.Add(req); | ||
123 | } | ||
124 | } | ||
125 | |||
126 | /// <summary> | ||
99 | /// Process all queued raycast requests | 127 | /// Process all queued raycast requests |
100 | /// </summary> | 128 | /// </summary> |
101 | /// <returns>Time in MS the raycasts took to process.</returns> | 129 | /// <returns>Time in MS the raycasts took to process.</returns> |
@@ -119,15 +147,23 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
119 | //Fail silently | 147 | //Fail silently |
120 | } | 148 | } |
121 | } | 149 | } |
122 | /* | 150 | |
123 | foreach (ODERayCastRequest req in m_PendingRequests) | 151 | m_PendingRequests.Clear(); |
152 | } | ||
153 | } | ||
154 | |||
155 | lock (m_PendingRayRequests) | ||
156 | { | ||
157 | if (m_PendingRayRequests.Count > 0) | ||
158 | { | ||
159 | ODERayRequest[] reqs = m_PendingRayRequests.ToArray(); | ||
160 | for (int i = 0; i < reqs.Length; i++) | ||
124 | { | 161 | { |
125 | if (req.callbackMethod != null) // quick optimization here, don't raycast | 162 | if (reqs[i].callbackMethod != null) // quick optimization here, don't raycast |
126 | RayCast(req); // if there isn't anyone to send results to | 163 | RayCast(reqs[i]); // if there isn't anyone to send results |
127 | |||
128 | } | 164 | } |
129 | */ | 165 | |
130 | m_PendingRequests.Clear(); | 166 | m_PendingRayRequests.Clear(); |
131 | } | 167 | } |
132 | } | 168 | } |
133 | 169 | ||
@@ -153,7 +189,6 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
153 | // Remove Ray | 189 | // Remove Ray |
154 | d.GeomDestroy(ray); | 190 | d.GeomDestroy(ray); |
155 | 191 | ||
156 | |||
157 | // Define default results | 192 | // Define default results |
158 | bool hitYN = false; | 193 | bool hitYN = false; |
159 | uint hitConsumerID = 0; | 194 | uint hitConsumerID = 0; |
@@ -184,6 +219,31 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
184 | req.callbackMethod(hitYN, closestcontact, hitConsumerID, distance, snormal); | 219 | req.callbackMethod(hitYN, closestcontact, hitConsumerID, distance, snormal); |
185 | } | 220 | } |
186 | 221 | ||
222 | /// <summary> | ||
223 | /// Method that actually initiates the raycast | ||
224 | /// </summary> | ||
225 | /// <param name="req"></param> | ||
226 | private void RayCast(ODERayRequest req) | ||
227 | { | ||
228 | // Create the ray | ||
229 | IntPtr ray = d.CreateRay(m_scene.space, req.length); | ||
230 | d.GeomRaySet(ray, req.Origin.X, req.Origin.Y, req.Origin.Z, req.Normal.X, req.Normal.Y, req.Normal.Z); | ||
231 | |||
232 | // Collide test | ||
233 | d.SpaceCollide2(m_scene.space, ray, IntPtr.Zero, nearCallback); | ||
234 | |||
235 | // Remove Ray | ||
236 | d.GeomDestroy(ray); | ||
237 | |||
238 | // Find closest contact and object. | ||
239 | lock (m_contactResults) | ||
240 | { | ||
241 | // Return results | ||
242 | if (req.callbackMethod != null) | ||
243 | req.callbackMethod(m_contactResults); | ||
244 | } | ||
245 | } | ||
246 | |||
187 | // This is the standard Near. Uses space AABBs to speed up detection. | 247 | // This is the standard Near. Uses space AABBs to speed up detection. |
188 | private void near(IntPtr space, IntPtr g1, IntPtr g2) | 248 | private void near(IntPtr space, IntPtr g1, IntPtr g2) |
189 | { | 249 | { |
@@ -349,10 +409,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
349 | m_contactResults.Add(collisionresult); | 409 | m_contactResults.Add(collisionresult); |
350 | } | 410 | } |
351 | } | 411 | } |
352 | |||
353 | |||
354 | } | 412 | } |
355 | |||
356 | } | 413 | } |
357 | 414 | ||
358 | /// <summary> | 415 | /// <summary> |
@@ -372,11 +429,12 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
372 | public RaycastCallback callbackMethod; | 429 | public RaycastCallback callbackMethod; |
373 | } | 430 | } |
374 | 431 | ||
375 | public struct ContactResult | 432 | public struct ODERayRequest |
376 | { | 433 | { |
377 | public Vector3 Pos; | 434 | public Vector3 Origin; |
378 | public float Depth; | ||
379 | public uint ConsumerID; | ||
380 | public Vector3 Normal; | 435 | public Vector3 Normal; |
436 | public int Count; | ||
437 | public float length; | ||
438 | public RayCallback callbackMethod; | ||
381 | } | 439 | } |
382 | } | 440 | } \ No newline at end of file |
diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs index 88902b0..6e603e8 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs | |||
@@ -26,7 +26,7 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | //#define USE_DRAWSTUFF | 28 | //#define USE_DRAWSTUFF |
29 | #define SPAM | 29 | //#define SPAM |
30 | 30 | ||
31 | using System; | 31 | using System; |
32 | using System.Collections.Generic; | 32 | using System.Collections.Generic; |
@@ -100,7 +100,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
100 | Rubber = 6 | 100 | Rubber = 6 |
101 | } | 101 | } |
102 | 102 | ||
103 | public sealed class OdeScene : PhysicsScene | 103 | public class OdeScene : PhysicsScene |
104 | { | 104 | { |
105 | private readonly ILog m_log; | 105 | private readonly ILog m_log; |
106 | // private Dictionary<string, sCollisionData> m_storedCollisions = new Dictionary<string, sCollisionData>(); | 106 | // private Dictionary<string, sCollisionData> m_storedCollisions = new Dictionary<string, sCollisionData>(); |
@@ -198,7 +198,12 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
198 | private readonly List<OdePrim> _taintedPrimL = new List<OdePrim>(); | 198 | private readonly List<OdePrim> _taintedPrimL = new List<OdePrim>(); |
199 | private readonly HashSet<OdeCharacter> _taintedActors = new HashSet<OdeCharacter>(); | 199 | private readonly HashSet<OdeCharacter> _taintedActors = new HashSet<OdeCharacter>(); |
200 | private readonly List<d.ContactGeom> _perloopContact = new List<d.ContactGeom>(); | 200 | private readonly List<d.ContactGeom> _perloopContact = new List<d.ContactGeom>(); |
201 | |||
202 | /// <summary> | ||
203 | /// A list of actors that should receive collision events. | ||
204 | /// </summary> | ||
201 | private readonly List<PhysicsActor> _collisionEventPrim = new List<PhysicsActor>(); | 205 | private readonly List<PhysicsActor> _collisionEventPrim = new List<PhysicsActor>(); |
206 | |||
202 | private readonly HashSet<OdeCharacter> _badCharacter = new HashSet<OdeCharacter>(); | 207 | private readonly HashSet<OdeCharacter> _badCharacter = new HashSet<OdeCharacter>(); |
203 | public Dictionary<IntPtr, String> geom_name_map = new Dictionary<IntPtr, String>(); | 208 | public Dictionary<IntPtr, String> geom_name_map = new Dictionary<IntPtr, String>(); |
204 | public Dictionary<IntPtr, PhysicsActor> actor_name_map = new Dictionary<IntPtr, PhysicsActor>(); | 209 | public Dictionary<IntPtr, PhysicsActor> actor_name_map = new Dictionary<IntPtr, PhysicsActor>(); |
@@ -299,7 +304,6 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
299 | // Create the world and the first space | 304 | // Create the world and the first space |
300 | world = d.WorldCreate(); | 305 | world = d.WorldCreate(); |
301 | space = d.HashSpaceCreate(IntPtr.Zero); | 306 | space = d.HashSpaceCreate(IntPtr.Zero); |
302 | |||
303 | 307 | ||
304 | contactgroup = d.JointGroupCreate(0); | 308 | contactgroup = d.JointGroupCreate(0); |
305 | //contactgroup | 309 | //contactgroup |
@@ -952,7 +956,6 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
952 | character.SetPidStatus(true); | 956 | character.SetPidStatus(true); |
953 | } | 957 | } |
954 | } | 958 | } |
955 | |||
956 | 959 | ||
957 | if (p1.PhysicsActorType == (int) ActorTypes.Agent) | 960 | if (p1.PhysicsActorType == (int) ActorTypes.Agent) |
958 | { | 961 | { |
@@ -1053,9 +1056,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1053 | { | 1056 | { |
1054 | joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]); | 1057 | joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]); |
1055 | m_global_contactcount++; | 1058 | m_global_contactcount++; |
1056 | |||
1057 | } | 1059 | } |
1058 | |||
1059 | } | 1060 | } |
1060 | else | 1061 | else |
1061 | { | 1062 | { |
@@ -1078,7 +1079,6 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1078 | { | 1079 | { |
1079 | joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]); | 1080 | joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]); |
1080 | m_global_contactcount++; | 1081 | m_global_contactcount++; |
1081 | |||
1082 | } | 1082 | } |
1083 | } | 1083 | } |
1084 | } | 1084 | } |
@@ -1290,6 +1290,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1290 | 1290 | ||
1291 | //returncollisions = true; | 1291 | //returncollisions = true; |
1292 | break; | 1292 | break; |
1293 | |||
1293 | case ActorTypes.Prim: | 1294 | case ActorTypes.Prim: |
1294 | if (p1 is OdePrim) | 1295 | if (p1 is OdePrim) |
1295 | { | 1296 | { |
@@ -1317,6 +1318,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1317 | 1318 | ||
1318 | cc2.AddCollisionEvent(obj2LocalID, contact); | 1319 | cc2.AddCollisionEvent(obj2LocalID, contact); |
1319 | break; | 1320 | break; |
1321 | |||
1320 | case ActorTypes.Prim: | 1322 | case ActorTypes.Prim: |
1321 | 1323 | ||
1322 | if (p2 is OdePrim) | 1324 | if (p2 is OdePrim) |
@@ -1421,18 +1423,18 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1421 | 1423 | ||
1422 | public int TriCallback(IntPtr trimesh, IntPtr refObject, int triangleIndex) | 1424 | public int TriCallback(IntPtr trimesh, IntPtr refObject, int triangleIndex) |
1423 | { | 1425 | { |
1424 | String name1 = null; | 1426 | // String name1 = null; |
1425 | String name2 = null; | 1427 | // String name2 = null; |
1426 | 1428 | // | |
1427 | if (!geom_name_map.TryGetValue(trimesh, out name1)) | 1429 | // if (!geom_name_map.TryGetValue(trimesh, out name1)) |
1428 | { | 1430 | // { |
1429 | name1 = "null"; | 1431 | // name1 = "null"; |
1430 | } | 1432 | // } |
1431 | 1433 | // | |
1432 | if (!geom_name_map.TryGetValue(refObject, out name2)) | 1434 | // if (!geom_name_map.TryGetValue(refObject, out name2)) |
1433 | { | 1435 | // { |
1434 | name2 = "null"; | 1436 | // name2 = "null"; |
1435 | } | 1437 | // } |
1436 | 1438 | ||
1437 | // m_log.InfoFormat("TriCallback: A collision was detected between {1} and {2}. Index was {3}", 0, name1, name2, triangleIndex); | 1439 | // m_log.InfoFormat("TriCallback: A collision was detected between {1} and {2}. Index was {3}", 0, name1, name2, triangleIndex); |
1438 | 1440 | ||
@@ -1604,7 +1606,11 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1604 | } | 1606 | } |
1605 | // End recovered. Kitto Flora | 1607 | // End recovered. Kitto Flora |
1606 | 1608 | ||
1607 | public void addCollisionEventReporting(PhysicsActor obj) | 1609 | /// <summary> |
1610 | /// Add actor to the list that should receive collision events in the simulate loop. | ||
1611 | /// </summary> | ||
1612 | /// <param name="obj"></param> | ||
1613 | public void AddCollisionEventReporting(PhysicsActor obj) | ||
1608 | { | 1614 | { |
1609 | lock (_collisionEventPrim) | 1615 | lock (_collisionEventPrim) |
1610 | { | 1616 | { |
@@ -1613,7 +1619,11 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1613 | } | 1619 | } |
1614 | } | 1620 | } |
1615 | 1621 | ||
1616 | public void remCollisionEventReporting(PhysicsActor obj) | 1622 | /// <summary> |
1623 | /// Remove actor from the list that should receive collision events in the simulate loop. | ||
1624 | /// </summary> | ||
1625 | /// <param name="obj"></param> | ||
1626 | public void RemoveCollisionEventReporting(PhysicsActor obj) | ||
1617 | { | 1627 | { |
1618 | lock (_collisionEventPrim) | 1628 | lock (_collisionEventPrim) |
1619 | { | 1629 | { |
@@ -1677,7 +1687,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1677 | } | 1687 | } |
1678 | 1688 | ||
1679 | private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation, | 1689 | private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation, |
1680 | IMesh mesh, PrimitiveBaseShape pbs, bool isphysical) | 1690 | PrimitiveBaseShape pbs, bool isphysical, uint localID) |
1681 | { | 1691 | { |
1682 | Vector3 pos = position; | 1692 | Vector3 pos = position; |
1683 | Vector3 siz = size; | 1693 | Vector3 siz = size; |
@@ -1686,12 +1696,12 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1686 | OdePrim newPrim; | 1696 | OdePrim newPrim; |
1687 | lock (OdeLock) | 1697 | lock (OdeLock) |
1688 | { | 1698 | { |
1689 | newPrim = new OdePrim(name, this, pos, siz, rot, mesh, pbs, isphysical, ode); | 1699 | newPrim = new OdePrim(name, this, pos, siz, rot, pbs, isphysical, ode); |
1690 | 1700 | ||
1691 | lock (_prims) | 1701 | lock (_prims) |
1692 | _prims.Add(newPrim); | 1702 | _prims.Add(newPrim); |
1693 | } | 1703 | } |
1694 | 1704 | newPrim.LocalID = localID; | |
1695 | return newPrim; | 1705 | return newPrim; |
1696 | } | 1706 | } |
1697 | 1707 | ||
@@ -1714,27 +1724,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1714 | m_log.DebugFormat("[PHYSICS]: Adding physics actor to {0}", primName); | 1724 | m_log.DebugFormat("[PHYSICS]: Adding physics actor to {0}", primName); |
1715 | #endif | 1725 | #endif |
1716 | 1726 | ||
1717 | PhysicsActor result; | 1727 | return AddPrim(primName, position, size, rotation, pbs, isPhysical, localid); |
1718 | IMesh mesh = null; | ||
1719 | |||
1720 | if (needsMeshing(pbs)) | ||
1721 | { | ||
1722 | try | ||
1723 | { | ||
1724 | mesh = mesher.CreateMesh(primName, pbs, size, 32f, isPhysical); | ||
1725 | } | ||
1726 | catch(Exception e) | ||
1727 | { | ||
1728 | m_log.ErrorFormat("[PHYSICS]: Exception while meshing prim {0}.", primName); | ||
1729 | m_log.Debug(e.ToString()); | ||
1730 | mesh = null; | ||
1731 | return null; | ||
1732 | } | ||
1733 | } | ||
1734 | |||
1735 | result = AddPrim(primName, position, size, rotation, mesh, pbs, isPhysical); | ||
1736 | |||
1737 | return result; | ||
1738 | } | 1728 | } |
1739 | 1729 | ||
1740 | public override float TimeDilation | 1730 | public override float TimeDilation |
@@ -2104,6 +2094,8 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
2104 | 2094 | ||
2105 | public override void RemovePrim(PhysicsActor prim) | 2095 | public override void RemovePrim(PhysicsActor prim) |
2106 | { | 2096 | { |
2097 | // As with all ODE physics operations, we don't remove the prim immediately but signal that it should be | ||
2098 | // removed in the next physics simulate pass. | ||
2107 | if (prim is OdePrim) | 2099 | if (prim is OdePrim) |
2108 | { | 2100 | { |
2109 | lock (OdeLock) | 2101 | lock (OdeLock) |
@@ -2120,6 +2112,9 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
2120 | /// <summary> | 2112 | /// <summary> |
2121 | /// This is called from within simulate but outside the locked portion | 2113 | /// This is called from within simulate but outside the locked portion |
2122 | /// We need to do our own locking here | 2114 | /// We need to do our own locking here |
2115 | /// (Note: As of 20110801 this no longer appears to be true - this is being called within lock (odeLock) in | ||
2116 | /// Simulate() -- justincc). | ||
2117 | /// | ||
2123 | /// Essentially, we need to remove the prim from our space segment, whatever segment it's in. | 2118 | /// Essentially, we need to remove the prim from our space segment, whatever segment it's in. |
2124 | /// | 2119 | /// |
2125 | /// If there are no more prim in the segment, we need to empty (spacedestroy)the segment and reclaim memory | 2120 | /// If there are no more prim in the segment, we need to empty (spacedestroy)the segment and reclaim memory |
@@ -2131,7 +2126,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
2131 | //Console.WriteLine("RemovePrimThreadLocked " + prim.m_primName); | 2126 | //Console.WriteLine("RemovePrimThreadLocked " + prim.m_primName); |
2132 | lock (prim) | 2127 | lock (prim) |
2133 | { | 2128 | { |
2134 | remCollisionEventReporting(prim); | 2129 | RemoveCollisionEventReporting(prim); |
2135 | lock (ode) | 2130 | lock (ode) |
2136 | { | 2131 | { |
2137 | if (prim.prim_geom != IntPtr.Zero) | 2132 | if (prim.prim_geom != IntPtr.Zero) |
@@ -2176,24 +2171,12 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
2176 | //} | 2171 | //} |
2177 | //} | 2172 | //} |
2178 | //m_log.Warn(prim.prim_geom); | 2173 | //m_log.Warn(prim.prim_geom); |
2179 | try | 2174 | |
2180 | { | 2175 | if (!prim.RemoveGeom()) |
2181 | if (prim.prim_geom != IntPtr.Zero) | 2176 | m_log.Warn("[PHYSICS]: Unable to remove prim from physics scene"); |
2182 | { | 2177 | |
2183 | d.GeomDestroy(prim.prim_geom); | ||
2184 | prim.prim_geom = IntPtr.Zero; | ||
2185 | } | ||
2186 | else | ||
2187 | { | ||
2188 | m_log.Warn("[PHYSICS]: Unable to remove prim from physics scene"); | ||
2189 | } | ||
2190 | } | ||
2191 | catch (AccessViolationException) | ||
2192 | { | ||
2193 | m_log.Info("[PHYSICS]: Couldn't remove prim from physics scene, it was already be removed."); | ||
2194 | } | ||
2195 | lock (_prims) | 2178 | lock (_prims) |
2196 | _prims.Remove(prim); | 2179 | _prims.Remove(prim); |
2197 | 2180 | ||
2198 | //If there are no more geometries in the sub-space, we don't need it in the main space anymore | 2181 | //If there are no more geometries in the sub-space, we don't need it in the main space anymore |
2199 | //if (d.SpaceGetNumGeoms(prim.m_targetSpace) == 0) | 2182 | //if (d.SpaceGetNumGeoms(prim.m_targetSpace) == 0) |
@@ -2584,7 +2567,9 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
2584 | { | 2567 | { |
2585 | if (!(_taintedPrimH.Contains(taintedprim))) | 2568 | if (!(_taintedPrimH.Contains(taintedprim))) |
2586 | { | 2569 | { |
2587 | //Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.m_primName); | 2570 | #if SPAM |
2571 | Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.Name); | ||
2572 | #endif | ||
2588 | _taintedPrimH.Add(taintedprim); // HashSet for searching | 2573 | _taintedPrimH.Add(taintedprim); // HashSet for searching |
2589 | _taintedPrimL.Add(taintedprim); // List for ordered readout | 2574 | _taintedPrimL.Add(taintedprim); // List for ordered readout |
2590 | } | 2575 | } |
@@ -2684,320 +2669,148 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
2684 | //if (!ode.lockquery()) | 2669 | //if (!ode.lockquery()) |
2685 | //{ | 2670 | //{ |
2686 | // ode.dlock(world); | 2671 | // ode.dlock(world); |
2687 | try | ||
2688 | { | ||
2689 | // Insert, remove Characters | ||
2690 | bool processedtaints = false; | ||
2691 | 2672 | ||
2692 | lock (_taintedActors) | 2673 | try |
2693 | { | 2674 | { |
2694 | if (_taintedActors.Count > 0) | 2675 | // Insert, remove Characters |
2695 | { | 2676 | bool processedtaints = false; |
2696 | foreach (OdeCharacter character in _taintedActors) | ||
2697 | { | ||
2698 | character.ProcessTaints(timeStep); | ||
2699 | 2677 | ||
2700 | processedtaints = true; | 2678 | lock (_taintedActors) |
2701 | //character.m_collisionscore = 0; | 2679 | { |
2702 | } | 2680 | if (_taintedActors.Count > 0) |
2681 | { | ||
2682 | foreach (OdeCharacter character in _taintedActors) | ||
2683 | { | ||
2684 | character.ProcessTaints(timeStep); | ||
2703 | 2685 | ||
2704 | if (processedtaints) | 2686 | processedtaints = true; |
2705 | _taintedActors.Clear(); | 2687 | //character.m_collisionscore = 0; |
2706 | } | ||
2707 | } | 2688 | } |
2708 | 2689 | ||
2709 | // Modify other objects in the scene. | 2690 | if (processedtaints) |
2710 | processedtaints = false; | 2691 | _taintedActors.Clear(); |
2692 | } | ||
2693 | } | ||
2694 | |||
2695 | // Modify other objects in the scene. | ||
2696 | processedtaints = false; | ||
2711 | 2697 | ||
2712 | lock (_taintedPrimLock) | 2698 | lock (_taintedPrimLock) |
2699 | { | ||
2700 | foreach (OdePrim prim in _taintedPrimL) | ||
2701 | { | ||
2702 | if (prim.m_taintremove) | ||
2713 | { | 2703 | { |
2714 | foreach (OdePrim prim in _taintedPrimL) | 2704 | // Console.WriteLine("Simulate calls RemovePrimThreadLocked for {0}", prim.Name); |
2715 | { | 2705 | RemovePrimThreadLocked(prim); |
2716 | if (prim.m_taintremove) | 2706 | } |
2717 | { | 2707 | else |
2718 | //Console.WriteLine("Simulate calls RemovePrimThreadLocked"); | 2708 | { |
2719 | RemovePrimThreadLocked(prim); | 2709 | // Console.WriteLine("Simulate calls ProcessTaints for {0}", prim.Name); |
2720 | } | 2710 | prim.ProcessTaints(timeStep); |
2721 | else | 2711 | } |
2722 | { | ||
2723 | //Console.WriteLine("Simulate calls ProcessTaints"); | ||
2724 | prim.ProcessTaints(timeStep); | ||
2725 | } | ||
2726 | processedtaints = true; | ||
2727 | prim.m_collisionscore = 0; | ||
2728 | |||
2729 | // This loop can block up the Heartbeat for a very long time on large regions. | ||
2730 | // We need to let the Watchdog know that the Heartbeat is not dead | ||
2731 | // NOTE: This is currently commented out, but if things like OAR loading are | ||
2732 | // timing the heartbeat out we will need to uncomment it | ||
2733 | //Watchdog.UpdateThread(); | ||
2734 | } | ||
2735 | 2712 | ||
2736 | if (SupportsNINJAJoints) | 2713 | processedtaints = true; |
2737 | { | 2714 | prim.m_collisionscore = 0; |
2738 | // Create pending joints, if possible | ||
2739 | 2715 | ||
2740 | // joints can only be processed after ALL bodies are processed (and exist in ODE), since creating | 2716 | // This loop can block up the Heartbeat for a very long time on large regions. |
2741 | // a joint requires specifying the body id of both involved bodies | 2717 | // We need to let the Watchdog know that the Heartbeat is not dead |
2742 | if (pendingJoints.Count > 0) | 2718 | // NOTE: This is currently commented out, but if things like OAR loading are |
2743 | { | 2719 | // timing the heartbeat out we will need to uncomment it |
2744 | List<PhysicsJoint> successfullyProcessedPendingJoints = new List<PhysicsJoint>(); | 2720 | //Watchdog.UpdateThread(); |
2745 | //DoJointErrorMessage(joints_connecting_actor, "taint: " + pendingJoints.Count + " pending joints"); | 2721 | } |
2746 | foreach (PhysicsJoint joint in pendingJoints) | 2722 | |
2747 | { | 2723 | if (SupportsNINJAJoints) |
2748 | //DoJointErrorMessage(joint, "taint: time to create joint with parms: " + joint.RawParams); | 2724 | SimulatePendingNINJAJoints(); |
2749 | string[] jointParams = joint.RawParams.Split(" ".ToCharArray(), System.StringSplitOptions.RemoveEmptyEntries); | ||
2750 | List<IntPtr> jointBodies = new List<IntPtr>(); | ||
2751 | bool allJointBodiesAreReady = true; | ||
2752 | foreach (string jointParam in jointParams) | ||
2753 | { | ||
2754 | if (jointParam == "NULL") | ||
2755 | { | ||
2756 | //DoJointErrorMessage(joint, "attaching NULL joint to world"); | ||
2757 | jointBodies.Add(IntPtr.Zero); | ||
2758 | } | ||
2759 | else | ||
2760 | { | ||
2761 | //DoJointErrorMessage(joint, "looking for prim name: " + jointParam); | ||
2762 | bool foundPrim = false; | ||
2763 | lock (_prims) | ||
2764 | { | ||
2765 | foreach (OdePrim prim in _prims) // FIXME: inefficient | ||
2766 | { | ||
2767 | if (prim.SOPName == jointParam) | ||
2768 | { | ||
2769 | //DoJointErrorMessage(joint, "found for prim name: " + jointParam); | ||
2770 | if (prim.IsPhysical && prim.Body != IntPtr.Zero) | ||
2771 | { | ||
2772 | jointBodies.Add(prim.Body); | ||
2773 | foundPrim = true; | ||
2774 | break; | ||
2775 | } | ||
2776 | else | ||
2777 | { | ||
2778 | DoJointErrorMessage(joint, "prim name " + jointParam + | ||
2779 | " exists but is not (yet) physical; deferring joint creation. " + | ||
2780 | "IsPhysical property is " + prim.IsPhysical + | ||
2781 | " and body is " + prim.Body); | ||
2782 | foundPrim = false; | ||
2783 | break; | ||
2784 | } | ||
2785 | } | ||
2786 | } | ||
2787 | } | ||
2788 | if (foundPrim) | ||
2789 | { | ||
2790 | // all is fine | ||
2791 | } | ||
2792 | else | ||
2793 | { | ||
2794 | allJointBodiesAreReady = false; | ||
2795 | break; | ||
2796 | } | ||
2797 | } | ||
2798 | } | ||
2799 | if (allJointBodiesAreReady) | ||
2800 | { | ||
2801 | //DoJointErrorMessage(joint, "allJointBodiesAreReady for " + joint.ObjectNameInScene + " with parms " + joint.RawParams); | ||
2802 | if (jointBodies[0] == jointBodies[1]) | ||
2803 | { | ||
2804 | DoJointErrorMessage(joint, "ERROR: joint cannot be created; the joint bodies are the same, body1==body2. Raw body is " + jointBodies[0] + ". raw parms: " + joint.RawParams); | ||
2805 | } | ||
2806 | else | ||
2807 | { | ||
2808 | switch (joint.Type) | ||
2809 | { | ||
2810 | case PhysicsJointType.Ball: | ||
2811 | { | ||
2812 | IntPtr odeJoint; | ||
2813 | //DoJointErrorMessage(joint, "ODE creating ball joint "); | ||
2814 | odeJoint = d.JointCreateBall(world, IntPtr.Zero); | ||
2815 | //DoJointErrorMessage(joint, "ODE attaching ball joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]); | ||
2816 | d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]); | ||
2817 | //DoJointErrorMessage(joint, "ODE setting ball anchor: " + odeJoint + " to vec:" + joint.Position); | ||
2818 | d.JointSetBallAnchor(odeJoint, | ||
2819 | joint.Position.X, | ||
2820 | joint.Position.Y, | ||
2821 | joint.Position.Z); | ||
2822 | //DoJointErrorMessage(joint, "ODE joint setting OK"); | ||
2823 | //DoJointErrorMessage(joint, "The ball joint's bodies are here: b0: "); | ||
2824 | //DoJointErrorMessage(joint, "" + (jointBodies[0] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[0]) : "fixed environment")); | ||
2825 | //DoJointErrorMessage(joint, "The ball joint's bodies are here: b1: "); | ||
2826 | //DoJointErrorMessage(joint, "" + (jointBodies[1] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[1]) : "fixed environment")); | ||
2827 | |||
2828 | if (joint is OdePhysicsJoint) | ||
2829 | { | ||
2830 | ((OdePhysicsJoint)joint).jointID = odeJoint; | ||
2831 | } | ||
2832 | else | ||
2833 | { | ||
2834 | DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!"); | ||
2835 | } | ||
2836 | } | ||
2837 | break; | ||
2838 | case PhysicsJointType.Hinge: | ||
2839 | { | ||
2840 | IntPtr odeJoint; | ||
2841 | //DoJointErrorMessage(joint, "ODE creating hinge joint "); | ||
2842 | odeJoint = d.JointCreateHinge(world, IntPtr.Zero); | ||
2843 | //DoJointErrorMessage(joint, "ODE attaching hinge joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]); | ||
2844 | d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]); | ||
2845 | //DoJointErrorMessage(joint, "ODE setting hinge anchor: " + odeJoint + " to vec:" + joint.Position); | ||
2846 | d.JointSetHingeAnchor(odeJoint, | ||
2847 | joint.Position.X, | ||
2848 | joint.Position.Y, | ||
2849 | joint.Position.Z); | ||
2850 | // We use the orientation of the x-axis of the joint's coordinate frame | ||
2851 | // as the axis for the hinge. | ||
2852 | |||
2853 | // Therefore, we must get the joint's coordinate frame based on the | ||
2854 | // joint.Rotation field, which originates from the orientation of the | ||
2855 | // joint's proxy object in the scene. | ||
2856 | |||
2857 | // The joint's coordinate frame is defined as the transformation matrix | ||
2858 | // that converts a vector from joint-local coordinates into world coordinates. | ||
2859 | // World coordinates are defined as the XYZ coordinate system of the sim, | ||
2860 | // as shown in the top status-bar of the viewer. | ||
2861 | |||
2862 | // Once we have the joint's coordinate frame, we extract its X axis (AtAxis) | ||
2863 | // and use that as the hinge axis. | ||
2864 | |||
2865 | //joint.Rotation.Normalize(); | ||
2866 | Matrix4 proxyFrame = Matrix4.CreateFromQuaternion(joint.Rotation); | ||
2867 | |||
2868 | // Now extract the X axis of the joint's coordinate frame. | ||
2869 | |||
2870 | // Do not try to use proxyFrame.AtAxis or you will become mired in the | ||
2871 | // tar pit of transposed, inverted, and generally messed-up orientations. | ||
2872 | // (In other words, Matrix4.AtAxis() is borked.) | ||
2873 | // Vector3 jointAxis = proxyFrame.AtAxis; <--- this path leadeth to madness | ||
2874 | |||
2875 | // Instead, compute the X axis of the coordinate frame by transforming | ||
2876 | // the (1,0,0) vector. At least that works. | ||
2877 | |||
2878 | //m_log.Debug("PHY: making axis: complete matrix is " + proxyFrame); | ||
2879 | Vector3 jointAxis = Vector3.Transform(Vector3.UnitX, proxyFrame); | ||
2880 | //m_log.Debug("PHY: making axis: hinge joint axis is " + jointAxis); | ||
2881 | //DoJointErrorMessage(joint, "ODE setting hinge axis: " + odeJoint + " to vec:" + jointAxis); | ||
2882 | d.JointSetHingeAxis(odeJoint, | ||
2883 | jointAxis.X, | ||
2884 | jointAxis.Y, | ||
2885 | jointAxis.Z); | ||
2886 | //d.JointSetHingeParam(odeJoint, (int)dParam.CFM, 0.1f); | ||
2887 | if (joint is OdePhysicsJoint) | ||
2888 | { | ||
2889 | ((OdePhysicsJoint)joint).jointID = odeJoint; | ||
2890 | } | ||
2891 | else | ||
2892 | { | ||
2893 | DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!"); | ||
2894 | } | ||
2895 | } | ||
2896 | break; | ||
2897 | } | ||
2898 | successfullyProcessedPendingJoints.Add(joint); | ||
2899 | } | ||
2900 | } | ||
2901 | else | ||
2902 | { | ||
2903 | DoJointErrorMessage(joint, "joint could not yet be created; still pending"); | ||
2904 | } | ||
2905 | } | ||
2906 | foreach (PhysicsJoint successfullyProcessedJoint in successfullyProcessedPendingJoints) | ||
2907 | { | ||
2908 | //DoJointErrorMessage(successfullyProcessedJoint, "finalizing succesfully procsssed joint " + successfullyProcessedJoint.ObjectNameInScene + " parms " + successfullyProcessedJoint.RawParams); | ||
2909 | //DoJointErrorMessage(successfullyProcessedJoint, "removing from pending"); | ||
2910 | InternalRemovePendingJoint(successfullyProcessedJoint); | ||
2911 | //DoJointErrorMessage(successfullyProcessedJoint, "adding to active"); | ||
2912 | InternalAddActiveJoint(successfullyProcessedJoint); | ||
2913 | //DoJointErrorMessage(successfullyProcessedJoint, "done"); | ||
2914 | } | ||
2915 | } | ||
2916 | } | ||
2917 | 2725 | ||
2918 | if (processedtaints) | 2726 | if (processedtaints) |
2727 | { | ||
2919 | //Console.WriteLine("Simulate calls Clear of _taintedPrim list"); | 2728 | //Console.WriteLine("Simulate calls Clear of _taintedPrim list"); |
2920 | _taintedPrimH.Clear(); | 2729 | _taintedPrimH.Clear(); |
2921 | _taintedPrimL.Clear(); | 2730 | _taintedPrimL.Clear(); |
2922 | } | 2731 | } |
2732 | } | ||
2923 | 2733 | ||
2924 | // Move characters | 2734 | // Move characters |
2925 | lock (_characters) | 2735 | lock (_characters) |
2736 | { | ||
2737 | List<OdeCharacter> defects = new List<OdeCharacter>(); | ||
2738 | foreach (OdeCharacter actor in _characters) | ||
2739 | { | ||
2740 | if (actor != null) | ||
2741 | actor.Move(timeStep, defects); | ||
2742 | } | ||
2743 | if (0 != defects.Count) | ||
2744 | { | ||
2745 | foreach (OdeCharacter defect in defects) | ||
2926 | { | 2746 | { |
2927 | List<OdeCharacter> defects = new List<OdeCharacter>(); | 2747 | RemoveCharacter(defect); |
2928 | foreach (OdeCharacter actor in _characters) | ||
2929 | { | ||
2930 | if (actor != null) | ||
2931 | actor.Move(timeStep, defects); | ||
2932 | } | ||
2933 | if (0 != defects.Count) | ||
2934 | { | ||
2935 | foreach (OdeCharacter defect in defects) | ||
2936 | { | ||
2937 | RemoveCharacter(defect); | ||
2938 | } | ||
2939 | } | ||
2940 | } | 2748 | } |
2749 | } | ||
2750 | } | ||
2941 | 2751 | ||
2942 | // Move other active objects | 2752 | // Move other active objects |
2943 | lock (_activeprims) | 2753 | lock (_activeprims) |
2944 | { | 2754 | { |
2945 | foreach (OdePrim prim in _activeprims) | 2755 | foreach (OdePrim prim in _activeprims) |
2946 | { | 2756 | { |
2947 | prim.m_collisionscore = 0; | 2757 | prim.m_collisionscore = 0; |
2948 | prim.Move(timeStep); | 2758 | prim.Move(timeStep); |
2949 | } | 2759 | } |
2950 | } | 2760 | } |
2951 | 2761 | ||
2952 | //if ((framecount % m_randomizeWater) == 0) | 2762 | //if ((framecount % m_randomizeWater) == 0) |
2953 | // randomizeWater(waterlevel); | 2763 | // randomizeWater(waterlevel); |
2954 | 2764 | ||
2955 | //int RayCastTimeMS = m_rayCastManager.ProcessQueuedRequests(); | 2765 | //int RayCastTimeMS = m_rayCastManager.ProcessQueuedRequests(); |
2956 | m_rayCastManager.ProcessQueuedRequests(); | 2766 | m_rayCastManager.ProcessQueuedRequests(); |
2767 | |||
2768 | collision_optimized(timeStep); | ||
2769 | |||
2770 | lock (_collisionEventPrim) | ||
2771 | { | ||
2772 | foreach (PhysicsActor obj in _collisionEventPrim) | ||
2773 | { | ||
2774 | if (obj == null) | ||
2775 | continue; | ||
2957 | 2776 | ||
2958 | collision_optimized(timeStep); | 2777 | // m_log.DebugFormat("[PHYSICS]: Assessing {0} for collision events", obj.SOPName); |
2959 | 2778 | ||
2960 | lock (_collisionEventPrim) | 2779 | switch ((ActorTypes)obj.PhysicsActorType) |
2961 | { | 2780 | { |
2962 | foreach (PhysicsActor obj in _collisionEventPrim) | 2781 | case ActorTypes.Agent: |
2963 | { | 2782 | OdeCharacter cobj = (OdeCharacter)obj; |
2964 | if (obj == null) | 2783 | cobj.AddCollisionFrameTime(100); |
2965 | continue; | 2784 | cobj.SendCollisions(); |
2785 | break; | ||
2966 | 2786 | ||
2967 | switch ((ActorTypes)obj.PhysicsActorType) | 2787 | case ActorTypes.Prim: |
2968 | { | 2788 | OdePrim pobj = (OdePrim)obj; |
2969 | case ActorTypes.Agent: | 2789 | pobj.SendCollisions(); |
2970 | OdeCharacter cobj = (OdeCharacter)obj; | 2790 | break; |
2971 | cobj.AddCollisionFrameTime(100); | ||
2972 | cobj.SendCollisions(); | ||
2973 | break; | ||
2974 | case ActorTypes.Prim: | ||
2975 | OdePrim pobj = (OdePrim)obj; | ||
2976 | pobj.SendCollisions(); | ||
2977 | break; | ||
2978 | } | ||
2979 | } | ||
2980 | } | 2791 | } |
2792 | } | ||
2793 | } | ||
2981 | 2794 | ||
2982 | //if (m_global_contactcount > 5) | 2795 | //if (m_global_contactcount > 5) |
2983 | //{ | 2796 | //{ |
2984 | // m_log.DebugFormat("[PHYSICS]: Contacts:{0}", m_global_contactcount); | 2797 | // m_log.DebugFormat("[PHYSICS]: Contacts:{0}", m_global_contactcount); |
2985 | //} | 2798 | //} |
2986 | 2799 | ||
2987 | m_global_contactcount = 0; | 2800 | m_global_contactcount = 0; |
2988 | 2801 | ||
2989 | d.WorldQuickStep(world, ODE_STEPSIZE); | 2802 | d.WorldQuickStep(world, ODE_STEPSIZE); |
2990 | d.JointGroupEmpty(contactgroup); | 2803 | d.JointGroupEmpty(contactgroup); |
2991 | //ode.dunlock(world); | 2804 | //ode.dunlock(world); |
2992 | } | 2805 | } |
2993 | catch (Exception e) | 2806 | catch (Exception e) |
2994 | { | 2807 | { |
2995 | m_log.ErrorFormat("[PHYSICS]: {0}, {1}, {2}", e.Message, e.TargetSite, e); | 2808 | m_log.ErrorFormat("[PHYSICS]: {0}, {1}, {2}", e.Message, e.TargetSite, e); |
2996 | ode.dunlock(world); | 2809 | ode.dunlock(world); |
2997 | } | 2810 | } |
2998 | 2811 | ||
2999 | step_time -= ODE_STEPSIZE; | 2812 | step_time -= ODE_STEPSIZE; |
3000 | i++; | 2813 | i++; |
3001 | //} | 2814 | //} |
3002 | //else | 2815 | //else |
3003 | //{ | 2816 | //{ |
@@ -3014,6 +2827,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
3014 | { | 2827 | { |
3015 | if (actor.bad) | 2828 | if (actor.bad) |
3016 | m_log.WarnFormat("[PHYSICS]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid); | 2829 | m_log.WarnFormat("[PHYSICS]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid); |
2830 | |||
3017 | actor.UpdatePositionAndVelocity(); | 2831 | actor.UpdatePositionAndVelocity(); |
3018 | } | 2832 | } |
3019 | } | 2833 | } |
@@ -3027,6 +2841,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
3027 | { | 2841 | { |
3028 | RemoveCharacter(chr); | 2842 | RemoveCharacter(chr); |
3029 | } | 2843 | } |
2844 | |||
3030 | _badCharacter.Clear(); | 2845 | _badCharacter.Clear(); |
3031 | } | 2846 | } |
3032 | } | 2847 | } |
@@ -3042,30 +2857,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
3042 | actor.UpdatePositionAndVelocity(); | 2857 | actor.UpdatePositionAndVelocity(); |
3043 | 2858 | ||
3044 | if (SupportsNINJAJoints) | 2859 | if (SupportsNINJAJoints) |
3045 | { | 2860 | SimulateActorPendingJoints(actor); |
3046 | // If an actor moved, move its joint proxy objects as well. | ||
3047 | // There seems to be an event PhysicsActor.OnPositionUpdate that could be used | ||
3048 | // for this purpose but it is never called! So we just do the joint | ||
3049 | // movement code here. | ||
3050 | |||
3051 | if (actor.SOPName != null && | ||
3052 | joints_connecting_actor.ContainsKey(actor.SOPName) && | ||
3053 | joints_connecting_actor[actor.SOPName] != null && | ||
3054 | joints_connecting_actor[actor.SOPName].Count > 0) | ||
3055 | { | ||
3056 | foreach (PhysicsJoint affectedJoint in joints_connecting_actor[actor.SOPName]) | ||
3057 | { | ||
3058 | if (affectedJoint.IsInPhysicsEngine) | ||
3059 | { | ||
3060 | DoJointMoved(affectedJoint); | ||
3061 | } | ||
3062 | else | ||
3063 | { | ||
3064 | DoJointErrorMessage(affectedJoint, "a body connected to a joint was moved, but the joint doesn't exist yet! this will lead to joint error. joint was: " + affectedJoint.ObjectNameInScene + " parms:" + affectedJoint.RawParams); | ||
3065 | } | ||
3066 | } | ||
3067 | } | ||
3068 | } | ||
3069 | } | 2861 | } |
3070 | } | 2862 | } |
3071 | } | 2863 | } |
@@ -3076,7 +2868,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
3076 | // Finished with all sim stepping. If requested, dump world state to file for debugging. | 2868 | // Finished with all sim stepping. If requested, dump world state to file for debugging. |
3077 | // TODO: This call to the export function is already inside lock (OdeLock) - but is an extra lock needed? | 2869 | // TODO: This call to the export function is already inside lock (OdeLock) - but is an extra lock needed? |
3078 | // TODO: This overwrites all dump files in-place. Should this be a growing logfile, or separate snapshots? | 2870 | // TODO: This overwrites all dump files in-place. Should this be a growing logfile, or separate snapshots? |
3079 | if (physics_logging && (physics_logging_interval>0) && (framecount % physics_logging_interval == 0)) | 2871 | if (physics_logging && (physics_logging_interval > 0) && (framecount % physics_logging_interval == 0)) |
3080 | { | 2872 | { |
3081 | string fname = "state-" + world.ToString() + ".DIF"; // give each physics world a separate filename | 2873 | string fname = "state-" + world.ToString() + ".DIF"; // give each physics world a separate filename |
3082 | string prefix = "world" + world.ToString(); // prefix for variable names in exported .DIF file | 2874 | string prefix = "world" + world.ToString(); // prefix for variable names in exported .DIF file |
@@ -3088,8 +2880,10 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
3088 | fwriter.WriteLine(header); | 2880 | fwriter.WriteLine(header); |
3089 | fwriter.Close(); | 2881 | fwriter.Close(); |
3090 | } | 2882 | } |
2883 | |||
3091 | d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix); | 2884 | d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix); |
3092 | } | 2885 | } |
2886 | |||
3093 | latertickcount = Util.EnvironmentTickCount() - tickCountFrameRun; | 2887 | latertickcount = Util.EnvironmentTickCount() - tickCountFrameRun; |
3094 | 2888 | ||
3095 | // OpenSimulator above does 10 fps. 10 fps = means that the main thread loop and physics | 2889 | // OpenSimulator above does 10 fps. 10 fps = means that the main thread loop and physics |
@@ -3098,7 +2892,9 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
3098 | // If Physics stalls, it takes longer which makes the tick count ms larger. | 2892 | // If Physics stalls, it takes longer which makes the tick count ms larger. |
3099 | 2893 | ||
3100 | if (latertickcount < 100) | 2894 | if (latertickcount < 100) |
2895 | { | ||
3101 | m_timeDilation = 1.0f; | 2896 | m_timeDilation = 1.0f; |
2897 | } | ||
3102 | else | 2898 | else |
3103 | { | 2899 | { |
3104 | m_timeDilation = 100f / latertickcount; | 2900 | m_timeDilation = 100f / latertickcount; |
@@ -3111,6 +2907,229 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
3111 | return fps; | 2907 | return fps; |
3112 | } | 2908 | } |
3113 | 2909 | ||
2910 | /// <summary> | ||
2911 | /// Simulate pending NINJA joints. | ||
2912 | /// </summary> | ||
2913 | /// <remarks> | ||
2914 | /// Called by the main Simulate() loop if NINJA joints are active. Should not be called from anywhere else. | ||
2915 | /// </remarks> | ||
2916 | protected void SimulatePendingNINJAJoints() | ||
2917 | { | ||
2918 | // Create pending joints, if possible | ||
2919 | |||
2920 | // joints can only be processed after ALL bodies are processed (and exist in ODE), since creating | ||
2921 | // a joint requires specifying the body id of both involved bodies | ||
2922 | if (pendingJoints.Count > 0) | ||
2923 | { | ||
2924 | List<PhysicsJoint> successfullyProcessedPendingJoints = new List<PhysicsJoint>(); | ||
2925 | //DoJointErrorMessage(joints_connecting_actor, "taint: " + pendingJoints.Count + " pending joints"); | ||
2926 | foreach (PhysicsJoint joint in pendingJoints) | ||
2927 | { | ||
2928 | //DoJointErrorMessage(joint, "taint: time to create joint with parms: " + joint.RawParams); | ||
2929 | string[] jointParams = joint.RawParams.Split(" ".ToCharArray(), System.StringSplitOptions.RemoveEmptyEntries); | ||
2930 | List<IntPtr> jointBodies = new List<IntPtr>(); | ||
2931 | bool allJointBodiesAreReady = true; | ||
2932 | foreach (string jointParam in jointParams) | ||
2933 | { | ||
2934 | if (jointParam == "NULL") | ||
2935 | { | ||
2936 | //DoJointErrorMessage(joint, "attaching NULL joint to world"); | ||
2937 | jointBodies.Add(IntPtr.Zero); | ||
2938 | } | ||
2939 | else | ||
2940 | { | ||
2941 | //DoJointErrorMessage(joint, "looking for prim name: " + jointParam); | ||
2942 | bool foundPrim = false; | ||
2943 | lock (_prims) | ||
2944 | { | ||
2945 | foreach (OdePrim prim in _prims) // FIXME: inefficient | ||
2946 | { | ||
2947 | if (prim.SOPName == jointParam) | ||
2948 | { | ||
2949 | //DoJointErrorMessage(joint, "found for prim name: " + jointParam); | ||
2950 | if (prim.IsPhysical && prim.Body != IntPtr.Zero) | ||
2951 | { | ||
2952 | jointBodies.Add(prim.Body); | ||
2953 | foundPrim = true; | ||
2954 | break; | ||
2955 | } | ||
2956 | else | ||
2957 | { | ||
2958 | DoJointErrorMessage(joint, "prim name " + jointParam + | ||
2959 | " exists but is not (yet) physical; deferring joint creation. " + | ||
2960 | "IsPhysical property is " + prim.IsPhysical + | ||
2961 | " and body is " + prim.Body); | ||
2962 | foundPrim = false; | ||
2963 | break; | ||
2964 | } | ||
2965 | } | ||
2966 | } | ||
2967 | } | ||
2968 | if (foundPrim) | ||
2969 | { | ||
2970 | // all is fine | ||
2971 | } | ||
2972 | else | ||
2973 | { | ||
2974 | allJointBodiesAreReady = false; | ||
2975 | break; | ||
2976 | } | ||
2977 | } | ||
2978 | } | ||
2979 | |||
2980 | if (allJointBodiesAreReady) | ||
2981 | { | ||
2982 | //DoJointErrorMessage(joint, "allJointBodiesAreReady for " + joint.ObjectNameInScene + " with parms " + joint.RawParams); | ||
2983 | if (jointBodies[0] == jointBodies[1]) | ||
2984 | { | ||
2985 | DoJointErrorMessage(joint, "ERROR: joint cannot be created; the joint bodies are the same, body1==body2. Raw body is " + jointBodies[0] + ". raw parms: " + joint.RawParams); | ||
2986 | } | ||
2987 | else | ||
2988 | { | ||
2989 | switch (joint.Type) | ||
2990 | { | ||
2991 | case PhysicsJointType.Ball: | ||
2992 | { | ||
2993 | IntPtr odeJoint; | ||
2994 | //DoJointErrorMessage(joint, "ODE creating ball joint "); | ||
2995 | odeJoint = d.JointCreateBall(world, IntPtr.Zero); | ||
2996 | //DoJointErrorMessage(joint, "ODE attaching ball joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]); | ||
2997 | d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]); | ||
2998 | //DoJointErrorMessage(joint, "ODE setting ball anchor: " + odeJoint + " to vec:" + joint.Position); | ||
2999 | d.JointSetBallAnchor(odeJoint, | ||
3000 | joint.Position.X, | ||
3001 | joint.Position.Y, | ||
3002 | joint.Position.Z); | ||
3003 | //DoJointErrorMessage(joint, "ODE joint setting OK"); | ||
3004 | //DoJointErrorMessage(joint, "The ball joint's bodies are here: b0: "); | ||
3005 | //DoJointErrorMessage(joint, "" + (jointBodies[0] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[0]) : "fixed environment")); | ||
3006 | //DoJointErrorMessage(joint, "The ball joint's bodies are here: b1: "); | ||
3007 | //DoJointErrorMessage(joint, "" + (jointBodies[1] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[1]) : "fixed environment")); | ||
3008 | |||
3009 | if (joint is OdePhysicsJoint) | ||
3010 | { | ||
3011 | ((OdePhysicsJoint)joint).jointID = odeJoint; | ||
3012 | } | ||
3013 | else | ||
3014 | { | ||
3015 | DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!"); | ||
3016 | } | ||
3017 | } | ||
3018 | break; | ||
3019 | case PhysicsJointType.Hinge: | ||
3020 | { | ||
3021 | IntPtr odeJoint; | ||
3022 | //DoJointErrorMessage(joint, "ODE creating hinge joint "); | ||
3023 | odeJoint = d.JointCreateHinge(world, IntPtr.Zero); | ||
3024 | //DoJointErrorMessage(joint, "ODE attaching hinge joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]); | ||
3025 | d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]); | ||
3026 | //DoJointErrorMessage(joint, "ODE setting hinge anchor: " + odeJoint + " to vec:" + joint.Position); | ||
3027 | d.JointSetHingeAnchor(odeJoint, | ||
3028 | joint.Position.X, | ||
3029 | joint.Position.Y, | ||
3030 | joint.Position.Z); | ||
3031 | // We use the orientation of the x-axis of the joint's coordinate frame | ||
3032 | // as the axis for the hinge. | ||
3033 | |||
3034 | // Therefore, we must get the joint's coordinate frame based on the | ||
3035 | // joint.Rotation field, which originates from the orientation of the | ||
3036 | // joint's proxy object in the scene. | ||
3037 | |||
3038 | // The joint's coordinate frame is defined as the transformation matrix | ||
3039 | // that converts a vector from joint-local coordinates into world coordinates. | ||
3040 | // World coordinates are defined as the XYZ coordinate system of the sim, | ||
3041 | // as shown in the top status-bar of the viewer. | ||
3042 | |||
3043 | // Once we have the joint's coordinate frame, we extract its X axis (AtAxis) | ||
3044 | // and use that as the hinge axis. | ||
3045 | |||
3046 | //joint.Rotation.Normalize(); | ||
3047 | Matrix4 proxyFrame = Matrix4.CreateFromQuaternion(joint.Rotation); | ||
3048 | |||
3049 | // Now extract the X axis of the joint's coordinate frame. | ||
3050 | |||
3051 | // Do not try to use proxyFrame.AtAxis or you will become mired in the | ||
3052 | // tar pit of transposed, inverted, and generally messed-up orientations. | ||
3053 | // (In other words, Matrix4.AtAxis() is borked.) | ||
3054 | // Vector3 jointAxis = proxyFrame.AtAxis; <--- this path leadeth to madness | ||
3055 | |||
3056 | // Instead, compute the X axis of the coordinate frame by transforming | ||
3057 | // the (1,0,0) vector. At least that works. | ||
3058 | |||
3059 | //m_log.Debug("PHY: making axis: complete matrix is " + proxyFrame); | ||
3060 | Vector3 jointAxis = Vector3.Transform(Vector3.UnitX, proxyFrame); | ||
3061 | //m_log.Debug("PHY: making axis: hinge joint axis is " + jointAxis); | ||
3062 | //DoJointErrorMessage(joint, "ODE setting hinge axis: " + odeJoint + " to vec:" + jointAxis); | ||
3063 | d.JointSetHingeAxis(odeJoint, | ||
3064 | jointAxis.X, | ||
3065 | jointAxis.Y, | ||
3066 | jointAxis.Z); | ||
3067 | //d.JointSetHingeParam(odeJoint, (int)dParam.CFM, 0.1f); | ||
3068 | if (joint is OdePhysicsJoint) | ||
3069 | { | ||
3070 | ((OdePhysicsJoint)joint).jointID = odeJoint; | ||
3071 | } | ||
3072 | else | ||
3073 | { | ||
3074 | DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!"); | ||
3075 | } | ||
3076 | } | ||
3077 | break; | ||
3078 | } | ||
3079 | successfullyProcessedPendingJoints.Add(joint); | ||
3080 | } | ||
3081 | } | ||
3082 | else | ||
3083 | { | ||
3084 | DoJointErrorMessage(joint, "joint could not yet be created; still pending"); | ||
3085 | } | ||
3086 | } | ||
3087 | |||
3088 | foreach (PhysicsJoint successfullyProcessedJoint in successfullyProcessedPendingJoints) | ||
3089 | { | ||
3090 | //DoJointErrorMessage(successfullyProcessedJoint, "finalizing succesfully procsssed joint " + successfullyProcessedJoint.ObjectNameInScene + " parms " + successfullyProcessedJoint.RawParams); | ||
3091 | //DoJointErrorMessage(successfullyProcessedJoint, "removing from pending"); | ||
3092 | InternalRemovePendingJoint(successfullyProcessedJoint); | ||
3093 | //DoJointErrorMessage(successfullyProcessedJoint, "adding to active"); | ||
3094 | InternalAddActiveJoint(successfullyProcessedJoint); | ||
3095 | //DoJointErrorMessage(successfullyProcessedJoint, "done"); | ||
3096 | } | ||
3097 | } | ||
3098 | } | ||
3099 | |||
3100 | /// <summary> | ||
3101 | /// Simulate the joint proxies of a NINJA actor. | ||
3102 | /// </summary> | ||
3103 | /// <remarks> | ||
3104 | /// Called as part of the Simulate() loop if NINJA physics is active. Must only be called from there. | ||
3105 | /// </remarks> | ||
3106 | /// <param name="actor"></param> | ||
3107 | protected void SimulateActorPendingJoints(OdePrim actor) | ||
3108 | { | ||
3109 | // If an actor moved, move its joint proxy objects as well. | ||
3110 | // There seems to be an event PhysicsActor.OnPositionUpdate that could be used | ||
3111 | // for this purpose but it is never called! So we just do the joint | ||
3112 | // movement code here. | ||
3113 | |||
3114 | if (actor.SOPName != null && | ||
3115 | joints_connecting_actor.ContainsKey(actor.SOPName) && | ||
3116 | joints_connecting_actor[actor.SOPName] != null && | ||
3117 | joints_connecting_actor[actor.SOPName].Count > 0) | ||
3118 | { | ||
3119 | foreach (PhysicsJoint affectedJoint in joints_connecting_actor[actor.SOPName]) | ||
3120 | { | ||
3121 | if (affectedJoint.IsInPhysicsEngine) | ||
3122 | { | ||
3123 | DoJointMoved(affectedJoint); | ||
3124 | } | ||
3125 | else | ||
3126 | { | ||
3127 | DoJointErrorMessage(affectedJoint, "a body connected to a joint was moved, but the joint doesn't exist yet! this will lead to joint error. joint was: " + affectedJoint.ObjectNameInScene + " parms:" + affectedJoint.RawParams); | ||
3128 | } | ||
3129 | } | ||
3130 | } | ||
3131 | } | ||
3132 | |||
3114 | public override void GetResults() | 3133 | public override void GetResults() |
3115 | { | 3134 | { |
3116 | } | 3135 | } |
@@ -3456,24 +3475,21 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
3456 | float hfmin = 2000; | 3475 | float hfmin = 2000; |
3457 | float hfmax = -2000; | 3476 | float hfmax = -2000; |
3458 | 3477 | ||
3459 | for (int x = 0; x < heightmapWidthSamples; x++) | 3478 | for (int x = 0; x < heightmapWidthSamples; x++) |
3479 | { | ||
3480 | for (int y = 0; y < heightmapHeightSamples; y++) | ||
3460 | { | 3481 | { |
3461 | for (int y = 0; y < heightmapHeightSamples; y++) | 3482 | int xx = Util.Clip(x - 1, 0, regionsize - 1); |
3462 | { | 3483 | int yy = Util.Clip(y - 1, 0, regionsize - 1); |
3463 | int xx = Util.Clip(x - 1, 0, regionsize - 1); | 3484 | |
3464 | int yy = Util.Clip(y - 1, 0, regionsize - 1); | 3485 | |
3465 | 3486 | float val= heightMap[yy * (int)Constants.RegionSize + xx]; | |
3466 | 3487 | _heightmap[x * ((int)Constants.RegionSize + 2) + y] = val; | |
3467 | float val= heightMap[yy * (int)Constants.RegionSize + xx]; | 3488 | |
3468 | _heightmap[x * ((int)Constants.RegionSize + 2) + y] = val; | 3489 | hfmin = (val < hfmin) ? val : hfmin; |
3469 | 3490 | hfmax = (val > hfmax) ? val : hfmax; | |
3470 | hfmin = (val < hfmin) ? val : hfmin; | ||
3471 | hfmax = (val > hfmax) ? val : hfmax; | ||
3472 | } | ||
3473 | } | 3491 | } |
3474 | 3492 | } | |
3475 | |||
3476 | |||
3477 | 3493 | ||
3478 | lock (OdeLock) | 3494 | lock (OdeLock) |
3479 | { | 3495 | { |
@@ -3528,7 +3544,6 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
3528 | } | 3544 | } |
3529 | RegionTerrain.Add(pOffset, GroundGeom, GroundGeom); | 3545 | RegionTerrain.Add(pOffset, GroundGeom, GroundGeom); |
3530 | TerrainHeightFieldHeights.Add(GroundGeom,_heightmap); | 3546 | TerrainHeightFieldHeights.Add(GroundGeom,_heightmap); |
3531 | |||
3532 | } | 3547 | } |
3533 | } | 3548 | } |
3534 | 3549 | ||
@@ -3691,6 +3706,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
3691 | //d.CloseODE(); | 3706 | //d.CloseODE(); |
3692 | } | 3707 | } |
3693 | } | 3708 | } |
3709 | |||
3694 | public override Dictionary<uint, float> GetTopColliders() | 3710 | public override Dictionary<uint, float> GetTopColliders() |
3695 | { | 3711 | { |
3696 | Dictionary<uint, float> returncolliders = new Dictionary<uint, float>(); | 3712 | Dictionary<uint, float> returncolliders = new Dictionary<uint, float>(); |
@@ -3727,6 +3743,34 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
3727 | } | 3743 | } |
3728 | } | 3744 | } |
3729 | 3745 | ||
3746 | public override void RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayCallback retMethod) | ||
3747 | { | ||
3748 | if (retMethod != null) | ||
3749 | { | ||
3750 | m_rayCastManager.QueueRequest(position, direction, length, Count, retMethod); | ||
3751 | } | ||
3752 | } | ||
3753 | |||
3754 | public override List<ContactResult> RaycastWorld(Vector3 position, Vector3 direction, float length, int Count) | ||
3755 | { | ||
3756 | ContactResult[] ourResults = null; | ||
3757 | RayCallback retMethod = delegate(List<ContactResult> results) | ||
3758 | { | ||
3759 | ourResults = new ContactResult[results.Count]; | ||
3760 | results.CopyTo(ourResults, 0); | ||
3761 | }; | ||
3762 | int waitTime = 0; | ||
3763 | m_rayCastManager.QueueRequest(position, direction, length, Count, retMethod); | ||
3764 | while (ourResults == null && waitTime < 1000) | ||
3765 | { | ||
3766 | Thread.Sleep(1); | ||
3767 | waitTime++; | ||
3768 | } | ||
3769 | if (ourResults == null) | ||
3770 | return new List<ContactResult> (); | ||
3771 | return new List<ContactResult>(ourResults); | ||
3772 | } | ||
3773 | |||
3730 | #if USE_DRAWSTUFF | 3774 | #if USE_DRAWSTUFF |
3731 | // Keyboard callback | 3775 | // Keyboard callback |
3732 | public void command(int cmd) | 3776 | public void command(int cmd) |
diff --git a/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs b/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs index 5dcd6f5..2ea810f 100644 --- a/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs +++ b/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs | |||
@@ -31,17 +31,18 @@ using NUnit.Framework; | |||
31 | using OpenMetaverse; | 31 | using OpenMetaverse; |
32 | using OpenSim.Framework; | 32 | using OpenSim.Framework; |
33 | using OpenSim.Region.Physics.Manager; | 33 | using OpenSim.Region.Physics.Manager; |
34 | using OpenSim.Region.Physics.OdePlugin; | ||
34 | using log4net; | 35 | using log4net; |
35 | using System.Reflection; | 36 | using System.Reflection; |
36 | 37 | ||
37 | namespace OpenSim.Region.Physics.OdePlugin | 38 | namespace OpenSim.Region.Physics.OdePlugin.Tests |
38 | { | 39 | { |
39 | [TestFixture] | 40 | [TestFixture] |
40 | public class ODETestClass | 41 | public class ODETestClass |
41 | { | 42 | { |
42 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 43 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
43 | 44 | ||
44 | private OdePlugin cbt; | 45 | private OpenSim.Region.Physics.OdePlugin.OdePlugin cbt; |
45 | private PhysicsScene ps; | 46 | private PhysicsScene ps; |
46 | private IMeshingPlugin imp; | 47 | private IMeshingPlugin imp; |
47 | 48 | ||
diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs index 8b7871b..0cc0fe7 100644 --- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs | |||
@@ -58,7 +58,11 @@ namespace OpenSim.Region.ScriptEngine.Interfaces | |||
58 | /// </summary> | 58 | /// </summary> |
59 | public interface IScriptInstance | 59 | public interface IScriptInstance |
60 | { | 60 | { |
61 | /// <summary> | ||
62 | /// Is this script currently running? | ||
63 | /// </summary> | ||
61 | bool Running { get; set; } | 64 | bool Running { get; set; } |
65 | |||
62 | bool ShuttingDown { get; set; } | 66 | bool ShuttingDown { get; set; } |
63 | string State { get; set; } | 67 | string State { get; set; } |
64 | IScriptEngine Engine { get; } | 68 | IScriptEngine Engine { get; } |
@@ -78,7 +82,14 @@ namespace OpenSim.Region.ScriptEngine.Interfaces | |||
78 | 82 | ||
79 | void Init(); | 83 | void Init(); |
80 | void Start(); | 84 | void Start(); |
85 | |||
86 | /// <summary> | ||
87 | /// Stop the script. | ||
88 | /// </summary> | ||
89 | /// <param name="timeout"></param> | ||
90 | /// <returns>true if the script was successfully stopped, false otherwise</returns> | ||
81 | bool Stop(int timeout); | 91 | bool Stop(int timeout); |
92 | |||
82 | void SetState(string state); | 93 | void SetState(string state); |
83 | 94 | ||
84 | void PostEvent(EventParams data); | 95 | void PostEvent(EventParams data); |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index ecfac6f..bf791a9 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | |||
@@ -303,35 +303,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
303 | switch (linkType) | 303 | switch (linkType) |
304 | { | 304 | { |
305 | case ScriptBaseClass.LINK_SET: | 305 | case ScriptBaseClass.LINK_SET: |
306 | if (m_host.ParentGroup != null) | 306 | return new List<SceneObjectPart>(m_host.ParentGroup.Parts); |
307 | { | ||
308 | return new List<SceneObjectPart>(m_host.ParentGroup.Parts); | ||
309 | } | ||
310 | return ret; | ||
311 | 307 | ||
312 | case ScriptBaseClass.LINK_ROOT: | 308 | case ScriptBaseClass.LINK_ROOT: |
313 | if (m_host.ParentGroup != null) | 309 | ret = new List<SceneObjectPart>(); |
314 | { | 310 | ret.Add(m_host.ParentGroup.RootPart); |
315 | ret = new List<SceneObjectPart>(); | ||
316 | ret.Add(m_host.ParentGroup.RootPart); | ||
317 | return ret; | ||
318 | } | ||
319 | return ret; | 311 | return ret; |
320 | 312 | ||
321 | case ScriptBaseClass.LINK_ALL_OTHERS: | 313 | case ScriptBaseClass.LINK_ALL_OTHERS: |
322 | if (m_host.ParentGroup == null) | ||
323 | return new List<SceneObjectPart>(); | ||
324 | |||
325 | ret = new List<SceneObjectPart>(m_host.ParentGroup.Parts); | 314 | ret = new List<SceneObjectPart>(m_host.ParentGroup.Parts); |
326 | 315 | ||
327 | if (ret.Contains(m_host)) | 316 | if (ret.Contains(m_host)) |
328 | ret.Remove(m_host); | 317 | ret.Remove(m_host); |
318 | |||
329 | return ret; | 319 | return ret; |
330 | 320 | ||
331 | case ScriptBaseClass.LINK_ALL_CHILDREN: | 321 | case ScriptBaseClass.LINK_ALL_CHILDREN: |
332 | if (m_host.ParentGroup == null) | ||
333 | return new List<SceneObjectPart>(); | ||
334 | |||
335 | ret = new List<SceneObjectPart>(m_host.ParentGroup.Parts); | 322 | ret = new List<SceneObjectPart>(m_host.ParentGroup.Parts); |
336 | 323 | ||
337 | if (ret.Contains(m_host.ParentGroup.RootPart)) | 324 | if (ret.Contains(m_host.ParentGroup.RootPart)) |
@@ -342,15 +329,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
342 | return ret; | 329 | return ret; |
343 | 330 | ||
344 | default: | 331 | default: |
345 | if (linkType < 0 || m_host.ParentGroup == null) | 332 | if (linkType < 0) |
346 | return new List<SceneObjectPart>(); | 333 | return new List<SceneObjectPart>(); |
334 | |||
347 | SceneObjectPart target = m_host.ParentGroup.GetLinkNumPart(linkType); | 335 | SceneObjectPart target = m_host.ParentGroup.GetLinkNumPart(linkType); |
348 | if (target == null) | 336 | if (target == null) |
349 | return new List<SceneObjectPart>(); | 337 | return new List<SceneObjectPart>(); |
350 | ret = new List<SceneObjectPart>(); | 338 | ret = new List<SceneObjectPart>(); |
351 | ret.Add(target); | 339 | ret.Add(target); |
352 | return ret; | 340 | return ret; |
353 | |||
354 | } | 341 | } |
355 | } | 342 | } |
356 | 343 | ||
@@ -450,7 +437,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
450 | } | 437 | } |
451 | 438 | ||
452 | // convert a LSL_Rotation to a Quaternion | 439 | // convert a LSL_Rotation to a Quaternion |
453 | protected Quaternion Rot2Quaternion(LSL_Rotation r) | 440 | public static Quaternion Rot2Quaternion(LSL_Rotation r) |
454 | { | 441 | { |
455 | Quaternion q = new Quaternion((float)r.x, (float)r.y, (float)r.z, (float)r.s); | 442 | Quaternion q = new Quaternion((float)r.x, (float)r.y, (float)r.z, (float)r.s); |
456 | q.Normalize(); | 443 | q.Normalize(); |
@@ -957,6 +944,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
957 | wComm.DeliverMessage(ChatTypeEnum.Region, channelID, m_host.Name, m_host.UUID, text); | 944 | wComm.DeliverMessage(ChatTypeEnum.Region, channelID, m_host.Name, m_host.UUID, text); |
958 | } | 945 | } |
959 | 946 | ||
947 | public void llRegionSayTo(string target, int channel, string msg) | ||
948 | { | ||
949 | string error = String.Empty; | ||
950 | |||
951 | if (msg.Length > 1023) | ||
952 | msg = msg.Substring(0, 1023); | ||
953 | |||
954 | m_host.AddScriptLPS(1); | ||
955 | |||
956 | UUID TargetID; | ||
957 | UUID.TryParse(target, out TargetID); | ||
958 | |||
959 | IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>(); | ||
960 | if (wComm != null) | ||
961 | if (!wComm.DeliverMessageTo(TargetID, channel, m_host.AbsolutePosition, m_host.Name, m_host.UUID, msg, out error)) | ||
962 | LSLError(error); | ||
963 | } | ||
964 | |||
960 | public LSL_Integer llListen(int channelID, string name, string ID, string msg) | 965 | public LSL_Integer llListen(int channelID, string name, string ID, string msg) |
961 | { | 966 | { |
962 | m_host.AddScriptLPS(1); | 967 | m_host.AddScriptLPS(1); |
@@ -1298,8 +1303,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1298 | if (value != 0) | 1303 | if (value != 0) |
1299 | { | 1304 | { |
1300 | SceneObjectGroup group = m_host.ParentGroup; | 1305 | SceneObjectGroup group = m_host.ParentGroup; |
1301 | if (group == null) | ||
1302 | return; | ||
1303 | bool allow = true; | 1306 | bool allow = true; |
1304 | 1307 | ||
1305 | foreach (SceneObjectPart part in group.Parts) | 1308 | foreach (SceneObjectPart part in group.Parts) |
@@ -1313,18 +1316,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1313 | 1316 | ||
1314 | if (!allow) | 1317 | if (!allow) |
1315 | return; | 1318 | return; |
1319 | |||
1316 | m_host.ScriptSetPhysicsStatus(true); | 1320 | m_host.ScriptSetPhysicsStatus(true); |
1317 | } | 1321 | } |
1318 | else | 1322 | else |
1323 | { | ||
1319 | m_host.ScriptSetPhysicsStatus(false); | 1324 | m_host.ScriptSetPhysicsStatus(false); |
1325 | } | ||
1320 | } | 1326 | } |
1321 | 1327 | ||
1322 | if ((status & ScriptBaseClass.STATUS_PHANTOM) == ScriptBaseClass.STATUS_PHANTOM) | 1328 | if ((status & ScriptBaseClass.STATUS_PHANTOM) == ScriptBaseClass.STATUS_PHANTOM) |
1323 | { | 1329 | { |
1324 | if (value != 0) | 1330 | m_host.ParentGroup.ScriptSetPhantomStatus(value != 0); |
1325 | m_host.ScriptSetPhantomStatus(true); | ||
1326 | else | ||
1327 | m_host.ScriptSetPhantomStatus(false); | ||
1328 | } | 1331 | } |
1329 | 1332 | ||
1330 | if ((status & ScriptBaseClass.STATUS_CAST_SHADOWS) == ScriptBaseClass.STATUS_CAST_SHADOWS) | 1333 | if ((status & ScriptBaseClass.STATUS_CAST_SHADOWS) == ScriptBaseClass.STATUS_CAST_SHADOWS) |
@@ -1466,8 +1469,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1466 | protected void SetScale(SceneObjectPart part, LSL_Vector scale) | 1469 | protected void SetScale(SceneObjectPart part, LSL_Vector scale) |
1467 | { | 1470 | { |
1468 | // TODO: this needs to trigger a persistance save as well | 1471 | // TODO: this needs to trigger a persistance save as well |
1469 | if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) | 1472 | if (part == null || part.ParentGroup.IsDeleted) |
1470 | return; | 1473 | return; |
1474 | |||
1471 | if (scale.x < 0.01) | 1475 | if (scale.x < 0.01) |
1472 | scale.x = 0.01; | 1476 | scale.x = 0.01; |
1473 | if (scale.y < 0.01) | 1477 | if (scale.y < 0.01) |
@@ -1510,7 +1514,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1510 | { | 1514 | { |
1511 | m_host.AddScriptLPS(1); | 1515 | m_host.AddScriptLPS(1); |
1512 | m_host.ClickAction = (byte)action; | 1516 | m_host.ClickAction = (byte)action; |
1513 | if (m_host.ParentGroup != null) m_host.ParentGroup.HasGroupChanged = true; | 1517 | m_host.ParentGroup.HasGroupChanged = true; |
1514 | m_host.ScheduleFullUpdate(); | 1518 | m_host.ScheduleFullUpdate(); |
1515 | return; | 1519 | return; |
1516 | } | 1520 | } |
@@ -1786,9 +1790,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1786 | tex.FaceTextures[i].RGBA = texcolor; | 1790 | tex.FaceTextures[i].RGBA = texcolor; |
1787 | } | 1791 | } |
1788 | } | 1792 | } |
1789 | texcolor = tex.DefaultTexture.RGBA; | 1793 | |
1790 | texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f); | 1794 | // In some cases, the default texture can be null, eg when every face |
1791 | tex.DefaultTexture.RGBA = texcolor; | 1795 | // has a unique texture |
1796 | if (tex.DefaultTexture != null) | ||
1797 | { | ||
1798 | texcolor = tex.DefaultTexture.RGBA; | ||
1799 | texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f); | ||
1800 | tex.DefaultTexture.RGBA = texcolor; | ||
1801 | } | ||
1802 | |||
1792 | part.UpdateTexture(tex); | 1803 | part.UpdateTexture(tex); |
1793 | return; | 1804 | return; |
1794 | } | 1805 | } |
@@ -2149,7 +2160,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2149 | 2160 | ||
2150 | if (part.ParentGroup.RootPart == part) | 2161 | if (part.ParentGroup.RootPart == part) |
2151 | { | 2162 | { |
2152 | if ((targetPos.z < ground) && disable_underground_movement && m_host.AttachmentPoint == 0) | 2163 | if ((targetPos.z < ground) && disable_underground_movement && m_host.ParentGroup.AttachmentPoint == 0) |
2153 | targetPos.z = ground; | 2164 | targetPos.z = ground; |
2154 | } | 2165 | } |
2155 | LSL_Vector real_vec = SetPosAdjust(fromPos, targetPos); | 2166 | LSL_Vector real_vec = SetPosAdjust(fromPos, targetPos); |
@@ -2236,14 +2247,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2236 | else | 2247 | else |
2237 | { | 2248 | { |
2238 | // we are a child. The rotation values will be set to the one of root modified by rot, as in SL. Don't ask. | 2249 | // we are a child. The rotation values will be set to the one of root modified by rot, as in SL. Don't ask. |
2239 | SceneObjectGroup group = m_host.ParentGroup; | 2250 | SceneObjectPart rootPart = m_host.ParentGroup.RootPart; |
2240 | if (group != null) // a bit paranoid, maybe | 2251 | if (rootPart != null) // better safe than sorry |
2241 | { | 2252 | { |
2242 | SceneObjectPart rootPart = group.RootPart; | 2253 | SetRot(m_host, rootPart.RotationOffset * Rot2Quaternion(rot)); |
2243 | if (rootPart != null) // again, better safe than sorry | ||
2244 | { | ||
2245 | SetRot(m_host, rootPart.RotationOffset * Rot2Quaternion(rot)); | ||
2246 | } | ||
2247 | } | 2254 | } |
2248 | } | 2255 | } |
2249 | 2256 | ||
@@ -2292,6 +2299,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2292 | { | 2299 | { |
2293 | return llGetRootRotation(); | 2300 | return llGetRootRotation(); |
2294 | } | 2301 | } |
2302 | |||
2295 | m_host.AddScriptLPS(1); | 2303 | m_host.AddScriptLPS(1); |
2296 | Quaternion q = m_host.GetWorldRotation(); | 2304 | Quaternion q = m_host.GetWorldRotation(); |
2297 | return new LSL_Rotation(q.X, q.Y, q.Z, q.W); | 2305 | return new LSL_Rotation(q.X, q.Y, q.Z, q.W); |
@@ -2302,9 +2310,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2302 | Quaternion q; | 2310 | Quaternion q; |
2303 | if (part.LinkNum == 0 || part.LinkNum == 1) // unlinked or root prim | 2311 | if (part.LinkNum == 0 || part.LinkNum == 1) // unlinked or root prim |
2304 | { | 2312 | { |
2305 | if (part.ParentGroup.RootPart.AttachmentPoint != 0) | 2313 | if (part.ParentGroup.AttachmentPoint != 0) |
2306 | { | 2314 | { |
2307 | ScenePresence avatar = World.GetScenePresence(part.AttachedAvatar); | 2315 | ScenePresence avatar = World.GetScenePresence(part.ParentGroup.AttachedAvatar); |
2308 | if (avatar != null) | 2316 | if (avatar != null) |
2309 | { | 2317 | { |
2310 | if ((avatar.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0) | 2318 | if ((avatar.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0) |
@@ -2333,15 +2341,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2333 | { | 2341 | { |
2334 | m_host.AddScriptLPS(1); | 2342 | m_host.AddScriptLPS(1); |
2335 | 2343 | ||
2336 | if (m_host.ParentGroup != null) | 2344 | if (!m_host.ParentGroup.IsDeleted) |
2337 | { | 2345 | { |
2338 | if (!m_host.ParentGroup.IsDeleted) | 2346 | if (local != 0) |
2339 | { | 2347 | force *= llGetRot(); |
2340 | if (local != 0) | ||
2341 | force *= llGetRot(); | ||
2342 | 2348 | ||
2343 | m_host.ParentGroup.RootPart.SetForce(new Vector3((float)force.x, (float)force.y, (float)force.z)); | 2349 | m_host.ParentGroup.RootPart.SetForce(new Vector3((float)force.x, (float)force.y, (float)force.z)); |
2344 | } | ||
2345 | } | 2350 | } |
2346 | } | 2351 | } |
2347 | 2352 | ||
@@ -2351,15 +2356,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2351 | 2356 | ||
2352 | m_host.AddScriptLPS(1); | 2357 | m_host.AddScriptLPS(1); |
2353 | 2358 | ||
2354 | if (m_host.ParentGroup != null) | 2359 | if (!m_host.ParentGroup.IsDeleted) |
2355 | { | 2360 | { |
2356 | if (!m_host.ParentGroup.IsDeleted) | 2361 | Vector3 tmpForce = m_host.ParentGroup.RootPart.GetForce(); |
2357 | { | 2362 | force.x = tmpForce.X; |
2358 | Vector3 tmpForce = m_host.ParentGroup.RootPart.GetForce(); | 2363 | force.y = tmpForce.Y; |
2359 | force.x = tmpForce.X; | 2364 | force.z = tmpForce.Z; |
2360 | force.y = tmpForce.Y; | ||
2361 | force.z = tmpForce.Z; | ||
2362 | } | ||
2363 | } | 2365 | } |
2364 | 2366 | ||
2365 | return force; | 2367 | return force; |
@@ -2368,25 +2370,27 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2368 | public LSL_Integer llTarget(LSL_Vector position, double range) | 2370 | public LSL_Integer llTarget(LSL_Vector position, double range) |
2369 | { | 2371 | { |
2370 | m_host.AddScriptLPS(1); | 2372 | m_host.AddScriptLPS(1); |
2371 | return m_host.registerTargetWaypoint(new Vector3((float)position.x, (float)position.y, (float)position.z), (float)range); | 2373 | return m_host.ParentGroup.registerTargetWaypoint( |
2374 | new Vector3((float)position.x, (float)position.y, (float)position.z), (float)range); | ||
2372 | } | 2375 | } |
2373 | 2376 | ||
2374 | public void llTargetRemove(int number) | 2377 | public void llTargetRemove(int number) |
2375 | { | 2378 | { |
2376 | m_host.AddScriptLPS(1); | 2379 | m_host.AddScriptLPS(1); |
2377 | m_host.unregisterTargetWaypoint(number); | 2380 | m_host.ParentGroup.unregisterTargetWaypoint(number); |
2378 | } | 2381 | } |
2379 | 2382 | ||
2380 | public LSL_Integer llRotTarget(LSL_Rotation rot, double error) | 2383 | public LSL_Integer llRotTarget(LSL_Rotation rot, double error) |
2381 | { | 2384 | { |
2382 | m_host.AddScriptLPS(1); | 2385 | m_host.AddScriptLPS(1); |
2383 | return m_host.registerRotTargetWaypoint(new Quaternion((float)rot.x, (float)rot.y, (float)rot.z, (float)rot.s), (float)error); | 2386 | return m_host.ParentGroup.registerRotTargetWaypoint( |
2387 | new Quaternion((float)rot.x, (float)rot.y, (float)rot.z, (float)rot.s), (float)error); | ||
2384 | } | 2388 | } |
2385 | 2389 | ||
2386 | public void llRotTargetRemove(int number) | 2390 | public void llRotTargetRemove(int number) |
2387 | { | 2391 | { |
2388 | m_host.AddScriptLPS(1); | 2392 | m_host.AddScriptLPS(1); |
2389 | m_host.unregisterRotTargetWaypoint(number); | 2393 | m_host.ParentGroup.unregisterRotTargetWaypoint(number); |
2390 | } | 2394 | } |
2391 | 2395 | ||
2392 | public void llMoveToTarget(LSL_Vector target, double tau) | 2396 | public void llMoveToTarget(LSL_Vector target, double tau) |
@@ -2429,7 +2433,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2429 | public LSL_Vector llGetTorque() | 2433 | public LSL_Vector llGetTorque() |
2430 | { | 2434 | { |
2431 | m_host.AddScriptLPS(1); | 2435 | m_host.AddScriptLPS(1); |
2432 | Vector3 torque = m_host.GetTorque(); | 2436 | Vector3 torque = m_host.ParentGroup.GetTorque(); |
2433 | return new LSL_Vector(torque.X,torque.Y,torque.Z); | 2437 | return new LSL_Vector(torque.X,torque.Y,torque.Z); |
2434 | } | 2438 | } |
2435 | 2439 | ||
@@ -2443,7 +2447,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2443 | public LSL_Vector llGetVel() | 2447 | public LSL_Vector llGetVel() |
2444 | { | 2448 | { |
2445 | m_host.AddScriptLPS(1); | 2449 | m_host.AddScriptLPS(1); |
2446 | return new LSL_Vector(m_host.Velocity.X, m_host.Velocity.Y, m_host.Velocity.Z); | 2450 | |
2451 | Vector3 vel; | ||
2452 | |||
2453 | if (m_host.ParentGroup.IsAttachment) | ||
2454 | { | ||
2455 | ScenePresence avatar = m_host.ParentGroup.Scene.GetScenePresence(m_host.ParentGroup.AttachedAvatar); | ||
2456 | vel = avatar.Velocity; | ||
2457 | } | ||
2458 | else | ||
2459 | { | ||
2460 | vel = m_host.Velocity; | ||
2461 | } | ||
2462 | |||
2463 | return new LSL_Vector(vel.X, vel.Y, vel.Z); | ||
2447 | } | 2464 | } |
2448 | 2465 | ||
2449 | public LSL_Vector llGetAccel() | 2466 | public LSL_Vector llGetAccel() |
@@ -2739,10 +2756,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2739 | /// negative (indicating end-relative) and may be inverted, | 2756 | /// negative (indicating end-relative) and may be inverted, |
2740 | /// i.e. end < start. | 2757 | /// i.e. end < start. |
2741 | /// </summary> | 2758 | /// </summary> |
2742 | |||
2743 | public LSL_String llDeleteSubString(string src, int start, int end) | 2759 | public LSL_String llDeleteSubString(string src, int start, int end) |
2744 | { | 2760 | { |
2745 | |||
2746 | m_host.AddScriptLPS(1); | 2761 | m_host.AddScriptLPS(1); |
2747 | 2762 | ||
2748 | // Normalize indices (if negative). | 2763 | // Normalize indices (if negative). |
@@ -2822,10 +2837,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2822 | /// which case it is end-relative. The index may exceed either | 2837 | /// which case it is end-relative. The index may exceed either |
2823 | /// string bound, with the result being a concatenation. | 2838 | /// string bound, with the result being a concatenation. |
2824 | /// </summary> | 2839 | /// </summary> |
2825 | |||
2826 | public LSL_String llInsertString(string dest, int index, string src) | 2840 | public LSL_String llInsertString(string dest, int index, string src) |
2827 | { | 2841 | { |
2828 | |||
2829 | m_host.AddScriptLPS(1); | 2842 | m_host.AddScriptLPS(1); |
2830 | 2843 | ||
2831 | // Normalize indices (if negative). | 2844 | // Normalize indices (if negative). |
@@ -2983,8 +2996,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2983 | // If either of these are null, then there was an unknown error. | 2996 | // If either of these are null, then there was an unknown error. |
2984 | if (new_group == null) | 2997 | if (new_group == null) |
2985 | continue; | 2998 | continue; |
2986 | if (new_group.RootPart == null) | ||
2987 | continue; | ||
2988 | 2999 | ||
2989 | // objects rezzed with this method are die_at_edge by default. | 3000 | // objects rezzed with this method are die_at_edge by default. |
2990 | new_group.RootPart.SetDieAtEdge(true); | 3001 | new_group.RootPart.SetDieAtEdge(true); |
@@ -3248,7 +3259,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3248 | { | 3259 | { |
3249 | m_host.AddScriptLPS(1); | 3260 | m_host.AddScriptLPS(1); |
3250 | 3261 | ||
3251 | if (m_host.ParentGroup.RootPart.AttachmentPoint == 0) | 3262 | if (m_host.ParentGroup.AttachmentPoint == 0) |
3252 | return; | 3263 | return; |
3253 | 3264 | ||
3254 | TaskInventoryItem item; | 3265 | TaskInventoryItem item; |
@@ -3288,7 +3299,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3288 | 3299 | ||
3289 | IAttachmentsModule attachmentsModule = m_ScriptEngine.World.AttachmentsModule; | 3300 | IAttachmentsModule attachmentsModule = m_ScriptEngine.World.AttachmentsModule; |
3290 | if (attachmentsModule != null) | 3301 | if (attachmentsModule != null) |
3291 | attachmentsModule.ShowDetachInUserInventory(itemID, presence.ControllingClient); | 3302 | attachmentsModule.DetachSingleAttachmentToInv(itemID, presence.ControllingClient); |
3292 | } | 3303 | } |
3293 | 3304 | ||
3294 | public void llTakeCamera(string avatar) | 3305 | public void llTakeCamera(string avatar) |
@@ -3449,12 +3460,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3449 | public void llSetBuoyancy(double buoyancy) | 3460 | public void llSetBuoyancy(double buoyancy) |
3450 | { | 3461 | { |
3451 | m_host.AddScriptLPS(1); | 3462 | m_host.AddScriptLPS(1); |
3452 | if (m_host.ParentGroup != null) | 3463 | |
3464 | if (!m_host.ParentGroup.IsDeleted) | ||
3453 | { | 3465 | { |
3454 | if (!m_host.ParentGroup.IsDeleted) | 3466 | m_host.ParentGroup.RootPart.SetBuoyancy((float)buoyancy); |
3455 | { | ||
3456 | m_host.ParentGroup.RootPart.Buoyancy = (float)buoyancy; | ||
3457 | } | ||
3458 | } | 3467 | } |
3459 | } | 3468 | } |
3460 | 3469 | ||
@@ -3683,7 +3692,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3683 | 3692 | ||
3684 | m_host.AddScriptLPS(1); | 3693 | m_host.AddScriptLPS(1); |
3685 | 3694 | ||
3686 | if (m_host.ParentGroup.IsAttachment && (UUID)agent == m_host.ParentGroup.RootPart.AttachedAvatar) | 3695 | if (m_host.ParentGroup.IsAttachment && (UUID)agent == m_host.ParentGroup.AttachedAvatar) |
3687 | { | 3696 | { |
3688 | // When attached, certain permissions are implicit if requested from owner | 3697 | // When attached, certain permissions are implicit if requested from owner |
3689 | int implicitPerms = ScriptBaseClass.PERMISSION_TAKE_CONTROLS | | 3698 | int implicitPerms = ScriptBaseClass.PERMISSION_TAKE_CONTROLS | |
@@ -3909,7 +3918,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3909 | 3918 | ||
3910 | SceneObjectPart targetPart = World.GetSceneObjectPart((UUID)targetID); | 3919 | SceneObjectPart targetPart = World.GetSceneObjectPart((UUID)targetID); |
3911 | 3920 | ||
3912 | if (targetPart.ParentGroup.RootPart.AttachmentPoint != 0) | 3921 | if (targetPart.ParentGroup.AttachmentPoint != 0) |
3913 | return; // Fail silently if attached | 3922 | return; // Fail silently if attached |
3914 | 3923 | ||
3915 | if (targetPart.ParentGroup.RootPart.OwnerID != m_host.ParentGroup.RootPart.OwnerID) | 3924 | if (targetPart.ParentGroup.RootPart.OwnerID != m_host.ParentGroup.RootPart.OwnerID) |
@@ -3967,7 +3976,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3967 | 3976 | ||
3968 | SceneObjectGroup parentPrim = m_host.ParentGroup; | 3977 | SceneObjectGroup parentPrim = m_host.ParentGroup; |
3969 | 3978 | ||
3970 | if (parentPrim.RootPart.AttachmentPoint != 0) | 3979 | if (parentPrim.AttachmentPoint != 0) |
3971 | return; // Fail silently if attached | 3980 | return; // Fail silently if attached |
3972 | SceneObjectPart childPrim = null; | 3981 | SceneObjectPart childPrim = null; |
3973 | 3982 | ||
@@ -4075,7 +4084,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
4075 | } | 4084 | } |
4076 | 4085 | ||
4077 | SceneObjectGroup parentPrim = m_host.ParentGroup; | 4086 | SceneObjectGroup parentPrim = m_host.ParentGroup; |
4078 | if (parentPrim.RootPart.AttachmentPoint != 0) | 4087 | if (parentPrim.AttachmentPoint != 0) |
4079 | return; // Fail silently if attached | 4088 | return; // Fail silently if attached |
4080 | 4089 | ||
4081 | List<SceneObjectPart> parts = new List<SceneObjectPart>(parentPrim.Parts); | 4090 | List<SceneObjectPart> parts = new List<SceneObjectPart>(parentPrim.Parts); |
@@ -4311,7 +4320,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
4311 | GridInstantMessage msg = new GridInstantMessage(World, | 4320 | GridInstantMessage msg = new GridInstantMessage(World, |
4312 | m_host.UUID, m_host.Name+", an object owned by "+ | 4321 | m_host.UUID, m_host.Name+", an object owned by "+ |
4313 | resolveName(m_host.OwnerID)+",", destId, | 4322 | resolveName(m_host.OwnerID)+",", destId, |
4314 | (byte)InstantMessageDialog.InventoryOffered, | 4323 | (byte)InstantMessageDialog.TaskInventoryOffered, |
4315 | false, objName+"\n"+m_host.Name+" is located at "+ | 4324 | false, objName+"\n"+m_host.Name+" is located at "+ |
4316 | World.RegionInfo.RegionName+" "+ | 4325 | World.RegionInfo.RegionName+" "+ |
4317 | m_host.AbsolutePosition.ToString(), | 4326 | m_host.AbsolutePosition.ToString(), |
@@ -4749,7 +4758,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
4749 | return; | 4758 | return; |
4750 | 4759 | ||
4751 | // Object not pushable. Not an attachment and has no physics component | 4760 | // Object not pushable. Not an attachment and has no physics component |
4752 | if (!pusheeob.IsAttachment && pusheeob.PhysActor == null) | 4761 | if (!pusheeob.ParentGroup.IsAttachment && pusheeob.PhysActor == null) |
4753 | return; | 4762 | return; |
4754 | 4763 | ||
4755 | PusheePos = pusheeob.AbsolutePosition; | 4764 | PusheePos = pusheeob.AbsolutePosition; |
@@ -6279,7 +6288,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
6279 | public LSL_Integer llGetAttached() | 6288 | public LSL_Integer llGetAttached() |
6280 | { | 6289 | { |
6281 | m_host.AddScriptLPS(1); | 6290 | m_host.AddScriptLPS(1); |
6282 | return m_host.ParentGroup.RootPart.AttachmentPoint; | 6291 | return m_host.ParentGroup.AttachmentPoint; |
6283 | } | 6292 | } |
6284 | 6293 | ||
6285 | public virtual LSL_Integer llGetFreeMemory() | 6294 | public virtual LSL_Integer llGetFreeMemory() |
@@ -6663,12 +6672,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
6663 | public void llSetVehicleType(int type) | 6672 | public void llSetVehicleType(int type) |
6664 | { | 6673 | { |
6665 | m_host.AddScriptLPS(1); | 6674 | m_host.AddScriptLPS(1); |
6666 | if (m_host.ParentGroup != null) | 6675 | |
6676 | if (!m_host.ParentGroup.IsDeleted) | ||
6667 | { | 6677 | { |
6668 | if (!m_host.ParentGroup.IsDeleted) | 6678 | m_host.ParentGroup.RootPart.SetVehicleType(type); |
6669 | { | ||
6670 | m_host.ParentGroup.RootPart.SetVehicleType(type); | ||
6671 | } | ||
6672 | } | 6679 | } |
6673 | } | 6680 | } |
6674 | 6681 | ||
@@ -6678,12 +6685,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
6678 | { | 6685 | { |
6679 | m_host.AddScriptLPS(1); | 6686 | m_host.AddScriptLPS(1); |
6680 | 6687 | ||
6681 | if (m_host.ParentGroup != null) | 6688 | if (!m_host.ParentGroup.IsDeleted) |
6682 | { | 6689 | { |
6683 | if (!m_host.ParentGroup.IsDeleted) | 6690 | m_host.ParentGroup.RootPart.SetVehicleFloatParam(param, (float)value); |
6684 | { | ||
6685 | m_host.ParentGroup.RootPart.SetVehicleFloatParam(param, (float)value); | ||
6686 | } | ||
6687 | } | 6691 | } |
6688 | } | 6692 | } |
6689 | 6693 | ||
@@ -6692,13 +6696,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
6692 | public void llSetVehicleVectorParam(int param, LSL_Vector vec) | 6696 | public void llSetVehicleVectorParam(int param, LSL_Vector vec) |
6693 | { | 6697 | { |
6694 | m_host.AddScriptLPS(1); | 6698 | m_host.AddScriptLPS(1); |
6695 | if (m_host.ParentGroup != null) | 6699 | |
6700 | if (!m_host.ParentGroup.IsDeleted) | ||
6696 | { | 6701 | { |
6697 | if (!m_host.ParentGroup.IsDeleted) | 6702 | m_host.ParentGroup.RootPart.SetVehicleVectorParam(param, |
6698 | { | 6703 | new Vector3((float)vec.x, (float)vec.y, (float)vec.z)); |
6699 | m_host.ParentGroup.RootPart.SetVehicleVectorParam(param, | ||
6700 | new Vector3((float)vec.x, (float)vec.y, (float)vec.z)); | ||
6701 | } | ||
6702 | } | 6704 | } |
6703 | } | 6705 | } |
6704 | 6706 | ||
@@ -6707,37 +6709,30 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
6707 | public void llSetVehicleRotationParam(int param, LSL_Rotation rot) | 6709 | public void llSetVehicleRotationParam(int param, LSL_Rotation rot) |
6708 | { | 6710 | { |
6709 | m_host.AddScriptLPS(1); | 6711 | m_host.AddScriptLPS(1); |
6710 | if (m_host.ParentGroup != null) | 6712 | |
6713 | if (!m_host.ParentGroup.IsDeleted) | ||
6711 | { | 6714 | { |
6712 | if (!m_host.ParentGroup.IsDeleted) | 6715 | m_host.ParentGroup.RootPart.SetVehicleRotationParam(param, Rot2Quaternion(rot)); |
6713 | { | ||
6714 | m_host.ParentGroup.RootPart.SetVehicleRotationParam(param, | ||
6715 | Rot2Quaternion(rot)); | ||
6716 | } | ||
6717 | } | 6716 | } |
6718 | } | 6717 | } |
6719 | 6718 | ||
6720 | public void llSetVehicleFlags(int flags) | 6719 | public void llSetVehicleFlags(int flags) |
6721 | { | 6720 | { |
6722 | m_host.AddScriptLPS(1); | 6721 | m_host.AddScriptLPS(1); |
6723 | if (m_host.ParentGroup != null) | 6722 | |
6723 | if (!m_host.ParentGroup.IsDeleted) | ||
6724 | { | 6724 | { |
6725 | if (!m_host.ParentGroup.IsDeleted) | 6725 | m_host.ParentGroup.RootPart.SetVehicleFlags(flags, false); |
6726 | { | ||
6727 | m_host.ParentGroup.RootPart.SetVehicleFlags(flags, false); | ||
6728 | } | ||
6729 | } | 6726 | } |
6730 | } | 6727 | } |
6731 | 6728 | ||
6732 | public void llRemoveVehicleFlags(int flags) | 6729 | public void llRemoveVehicleFlags(int flags) |
6733 | { | 6730 | { |
6734 | m_host.AddScriptLPS(1); | 6731 | m_host.AddScriptLPS(1); |
6735 | if (m_host.ParentGroup != null) | 6732 | |
6733 | if (!m_host.ParentGroup.IsDeleted) | ||
6736 | { | 6734 | { |
6737 | if (!m_host.ParentGroup.IsDeleted) | 6735 | m_host.ParentGroup.RootPart.SetVehicleFlags(flags, true); |
6738 | { | ||
6739 | m_host.ParentGroup.RootPart.SetVehicleFlags(flags, true); | ||
6740 | } | ||
6741 | } | 6736 | } |
6742 | } | 6737 | } |
6743 | 6738 | ||
@@ -6891,20 +6886,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
6891 | public void llVolumeDetect(int detect) | 6886 | public void llVolumeDetect(int detect) |
6892 | { | 6887 | { |
6893 | m_host.AddScriptLPS(1); | 6888 | m_host.AddScriptLPS(1); |
6894 | if (m_host.ParentGroup != null) | 6889 | |
6895 | { | 6890 | if (!m_host.ParentGroup.IsDeleted) |
6896 | if (!m_host.ParentGroup.IsDeleted) | 6891 | m_host.ParentGroup.ScriptSetVolumeDetect(detect != 0); |
6897 | { | ||
6898 | m_host.ParentGroup.RootPart.ScriptSetVolumeDetect(detect!=0); | ||
6899 | } | ||
6900 | } | ||
6901 | } | 6892 | } |
6902 | 6893 | ||
6903 | /// <summary> | 6894 | /// <summary> |
6904 | /// This is a depecated function so this just replicates the result of | 6895 | /// This is a depecated function so this just replicates the result of |
6905 | /// invoking it in SL | 6896 | /// invoking it in SL |
6906 | /// </summary> | 6897 | /// </summary> |
6907 | |||
6908 | public void llRemoteLoadScript(string target, string name, int running, int start_param) | 6898 | public void llRemoteLoadScript(string target, string name, int running, int start_param) |
6909 | { | 6899 | { |
6910 | m_host.AddScriptLPS(1); | 6900 | m_host.AddScriptLPS(1); |
@@ -7046,7 +7036,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
7046 | return Util.SHA1Hash(src, Encoding.UTF8).ToLower(); | 7036 | return Util.SHA1Hash(src, Encoding.UTF8).ToLower(); |
7047 | } | 7037 | } |
7048 | 7038 | ||
7049 | protected ObjectShapePacket.ObjectDataBlock SetPrimitiveBlockShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist) | 7039 | protected ObjectShapePacket.ObjectDataBlock SetPrimitiveBlockShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, byte profileshape, byte pathcurve) |
7050 | { | 7040 | { |
7051 | ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock(); | 7041 | ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock(); |
7052 | if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) | 7042 | if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) |
@@ -7059,7 +7049,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
7059 | { | 7049 | { |
7060 | holeshape = (int)ScriptBaseClass.PRIM_HOLE_DEFAULT; | 7050 | holeshape = (int)ScriptBaseClass.PRIM_HOLE_DEFAULT; |
7061 | } | 7051 | } |
7062 | shapeBlock.ProfileCurve = (byte)holeshape; | 7052 | shapeBlock.PathCurve = pathcurve; |
7053 | shapeBlock.ProfileCurve = (byte)holeshape; // Set the hole shape. | ||
7054 | shapeBlock.ProfileCurve += profileshape; // Add in the profile shape. | ||
7063 | if (cut.x < 0f) | 7055 | if (cut.x < 0f) |
7064 | { | 7056 | { |
7065 | cut.x = 0f; | 7057 | cut.x = 0f; |
@@ -7091,9 +7083,26 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
7091 | { | 7083 | { |
7092 | hollow = 0f; | 7084 | hollow = 0f; |
7093 | } | 7085 | } |
7094 | if (hollow > 0.95) | 7086 | // If the prim is a Cylinder, Prism, Sphere, Torus or Ring (or not a |
7087 | // Box or Tube) and the hole shape is a square, hollow is limited to | ||
7088 | // a max of 70%. The viewer performs its own check on this value but | ||
7089 | // we need to do it here also so llGetPrimitiveParams can have access | ||
7090 | // to the correct value. | ||
7091 | if (profileshape != (byte)ProfileCurve.Square && | ||
7092 | holeshape == (int)ScriptBaseClass.PRIM_HOLE_SQUARE) | ||
7095 | { | 7093 | { |
7096 | hollow = 0.95f; | 7094 | if (hollow > 0.70f) |
7095 | { | ||
7096 | hollow = 0.70f; | ||
7097 | } | ||
7098 | } | ||
7099 | // Otherwise, hollow is limited to 95%. | ||
7100 | else | ||
7101 | { | ||
7102 | if (hollow > 0.95f) | ||
7103 | { | ||
7104 | hollow = 0.95f; | ||
7105 | } | ||
7097 | } | 7106 | } |
7098 | shapeBlock.ProfileHollow = (ushort)(50000 * hollow); | 7107 | shapeBlock.ProfileHollow = (ushort)(50000 * hollow); |
7099 | if (twist.x < -1.0f) | 7108 | if (twist.x < -1.0f) |
@@ -7117,23 +7126,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
7117 | 7126 | ||
7118 | shapeBlock.ObjectLocalID = part.LocalId; | 7127 | shapeBlock.ObjectLocalID = part.LocalId; |
7119 | 7128 | ||
7120 | // retain pathcurve | ||
7121 | shapeBlock.PathCurve = part.Shape.PathCurve; | ||
7122 | |||
7123 | part.Shape.SculptEntry = false; | 7129 | part.Shape.SculptEntry = false; |
7124 | return shapeBlock; | 7130 | return shapeBlock; |
7125 | } | 7131 | } |
7126 | 7132 | ||
7127 | protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector taper_b, LSL_Vector topshear, byte fudge) | 7133 | // Prim type box, cylinder and prism. |
7134 | protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector taper_b, LSL_Vector topshear, byte profileshape, byte pathcurve) | ||
7128 | { | 7135 | { |
7129 | if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) | 7136 | if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) |
7130 | return; | 7137 | return; |
7131 | 7138 | ||
7132 | ObjectShapePacket.ObjectDataBlock shapeBlock; | 7139 | ObjectShapePacket.ObjectDataBlock shapeBlock; |
7133 | 7140 | ||
7134 | shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist); | 7141 | shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist, profileshape, pathcurve); |
7135 | |||
7136 | shapeBlock.ProfileCurve += fudge; | ||
7137 | 7142 | ||
7138 | if (taper_b.x < 0f) | 7143 | if (taper_b.x < 0f) |
7139 | { | 7144 | { |
@@ -7176,21 +7181,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
7176 | part.UpdateShape(shapeBlock); | 7181 | part.UpdateShape(shapeBlock); |
7177 | } | 7182 | } |
7178 | 7183 | ||
7179 | protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector dimple, byte fudge) | 7184 | // Prim type sphere. |
7185 | protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector dimple, byte profileshape, byte pathcurve) | ||
7180 | { | 7186 | { |
7181 | if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) | 7187 | if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) |
7182 | return; | 7188 | return; |
7183 | 7189 | ||
7184 | ObjectShapePacket.ObjectDataBlock shapeBlock; | 7190 | ObjectShapePacket.ObjectDataBlock shapeBlock; |
7185 | 7191 | ||
7186 | shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist); | 7192 | shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist, profileshape, pathcurve); |
7187 | 7193 | ||
7188 | // profile/path swapped for a sphere | 7194 | // profile/path swapped for a sphere |
7189 | shapeBlock.PathBegin = shapeBlock.ProfileBegin; | 7195 | shapeBlock.PathBegin = shapeBlock.ProfileBegin; |
7190 | shapeBlock.PathEnd = shapeBlock.ProfileEnd; | 7196 | shapeBlock.PathEnd = shapeBlock.ProfileEnd; |
7191 | 7197 | ||
7192 | shapeBlock.ProfileCurve += fudge; | ||
7193 | |||
7194 | shapeBlock.PathScaleX = 100; | 7198 | shapeBlock.PathScaleX = 100; |
7195 | shapeBlock.PathScaleY = 100; | 7199 | shapeBlock.PathScaleY = 100; |
7196 | 7200 | ||
@@ -7221,16 +7225,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
7221 | part.UpdateShape(shapeBlock); | 7225 | part.UpdateShape(shapeBlock); |
7222 | } | 7226 | } |
7223 | 7227 | ||
7224 | protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector holesize, LSL_Vector topshear, LSL_Vector profilecut, LSL_Vector taper_a, float revolutions, float radiusoffset, float skew, byte fudge) | 7228 | // Prim type torus, tube and ring. |
7229 | protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector holesize, LSL_Vector topshear, LSL_Vector profilecut, LSL_Vector taper_a, float revolutions, float radiusoffset, float skew, byte profileshape, byte pathcurve) | ||
7225 | { | 7230 | { |
7226 | if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) | 7231 | if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) |
7227 | return; | 7232 | return; |
7228 | 7233 | ||
7229 | ObjectShapePacket.ObjectDataBlock shapeBlock; | 7234 | ObjectShapePacket.ObjectDataBlock shapeBlock; |
7230 | 7235 | ||
7231 | shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist); | 7236 | shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist, profileshape, pathcurve); |
7232 | |||
7233 | shapeBlock.ProfileCurve += fudge; | ||
7234 | 7237 | ||
7235 | // profile/path swapped for a torrus, tube, ring | 7238 | // profile/path swapped for a torrus, tube, ring |
7236 | shapeBlock.PathBegin = shapeBlock.ProfileBegin; | 7239 | shapeBlock.PathBegin = shapeBlock.ProfileBegin; |
@@ -7350,7 +7353,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
7350 | part.UpdateShape(shapeBlock); | 7353 | part.UpdateShape(shapeBlock); |
7351 | } | 7354 | } |
7352 | 7355 | ||
7353 | protected void SetPrimitiveShapeParams(SceneObjectPart part, string map, int type) | 7356 | // Prim type sculpt. |
7357 | protected void SetPrimitiveShapeParams(SceneObjectPart part, string map, int type, byte pathcurve) | ||
7354 | { | 7358 | { |
7355 | if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) | 7359 | if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) |
7356 | return; | 7360 | return; |
@@ -7366,6 +7370,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
7366 | if (sculptId == UUID.Zero) | 7370 | if (sculptId == UUID.Zero) |
7367 | return; | 7371 | return; |
7368 | 7372 | ||
7373 | shapeBlock.PathCurve = pathcurve; | ||
7369 | shapeBlock.ObjectLocalID = part.LocalId; | 7374 | shapeBlock.ObjectLocalID = part.LocalId; |
7370 | shapeBlock.PathScaleX = 100; | 7375 | shapeBlock.PathScaleX = 100; |
7371 | shapeBlock.PathScaleY = 150; | 7376 | shapeBlock.PathScaleY = 150; |
@@ -7379,9 +7384,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
7379 | type = type | (int)ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE; | 7384 | type = type | (int)ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE; |
7380 | } | 7385 | } |
7381 | 7386 | ||
7382 | // retain pathcurve | ||
7383 | shapeBlock.PathCurve = part.Shape.PathCurve; | ||
7384 | |||
7385 | part.Shape.SetSculptProperties((byte)type, sculptId); | 7387 | part.Shape.SetSculptProperties((byte)type, sculptId); |
7386 | part.Shape.SculptEntry = true; | 7388 | part.Shape.SculptEntry = true; |
7387 | part.UpdateShape(shapeBlock); | 7389 | part.UpdateShape(shapeBlock); |
@@ -7518,15 +7520,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
7518 | else | 7520 | else |
7519 | { | 7521 | { |
7520 | // we are a child. The rotation values will be set to the one of root modified by rot, as in SL. Don't ask. | 7522 | // we are a child. The rotation values will be set to the one of root modified by rot, as in SL. Don't ask. |
7521 | SceneObjectGroup group = part.ParentGroup; | 7523 | SceneObjectPart rootPart = part.ParentGroup.RootPart; |
7522 | if (group != null) // a bit paranoid, maybe | 7524 | SetRot(part, rootPart.RotationOffset * Rot2Quaternion(q)); |
7523 | { | ||
7524 | SceneObjectPart rootPart = group.RootPart; | ||
7525 | if (rootPart != null) // again, better safe than sorry | ||
7526 | { | ||
7527 | SetRot(part, rootPart.RotationOffset * Rot2Quaternion(q)); | ||
7528 | } | ||
7529 | } | ||
7530 | } | 7525 | } |
7531 | 7526 | ||
7532 | break; | 7527 | break; |
@@ -7561,8 +7556,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
7561 | taper_b = rules.GetVector3Item(idx++); | 7556 | taper_b = rules.GetVector3Item(idx++); |
7562 | topshear = rules.GetVector3Item(idx++); | 7557 | topshear = rules.GetVector3Item(idx++); |
7563 | 7558 | ||
7564 | part.Shape.PathCurve = (byte)Extrusion.Straight; | 7559 | SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b, topshear, |
7565 | SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b, topshear, 1); | 7560 | (byte)ProfileShape.Square, (byte)Extrusion.Straight); |
7566 | break; | 7561 | break; |
7567 | 7562 | ||
7568 | case (int)ScriptBaseClass.PRIM_TYPE_CYLINDER: | 7563 | case (int)ScriptBaseClass.PRIM_TYPE_CYLINDER: |
@@ -7575,9 +7570,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
7575 | twist = rules.GetVector3Item(idx++); | 7570 | twist = rules.GetVector3Item(idx++); |
7576 | taper_b = rules.GetVector3Item(idx++); | 7571 | taper_b = rules.GetVector3Item(idx++); |
7577 | topshear = rules.GetVector3Item(idx++); | 7572 | topshear = rules.GetVector3Item(idx++); |
7578 | part.Shape.ProfileShape = ProfileShape.Circle; | 7573 | SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b, topshear, |
7579 | part.Shape.PathCurve = (byte)Extrusion.Straight; | 7574 | (byte)ProfileShape.Circle, (byte)Extrusion.Straight); |
7580 | SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b, topshear, 0); | ||
7581 | break; | 7575 | break; |
7582 | 7576 | ||
7583 | case (int)ScriptBaseClass.PRIM_TYPE_PRISM: | 7577 | case (int)ScriptBaseClass.PRIM_TYPE_PRISM: |
@@ -7590,8 +7584,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
7590 | twist = rules.GetVector3Item(idx++); | 7584 | twist = rules.GetVector3Item(idx++); |
7591 | taper_b = rules.GetVector3Item(idx++); | 7585 | taper_b = rules.GetVector3Item(idx++); |
7592 | topshear = rules.GetVector3Item(idx++); | 7586 | topshear = rules.GetVector3Item(idx++); |
7593 | part.Shape.PathCurve = (byte)Extrusion.Straight; | 7587 | SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b, topshear, |
7594 | SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b, topshear, 3); | 7588 | (byte)ProfileShape.EquilateralTriangle, (byte)Extrusion.Straight); |
7595 | break; | 7589 | break; |
7596 | 7590 | ||
7597 | case (int)ScriptBaseClass.PRIM_TYPE_SPHERE: | 7591 | case (int)ScriptBaseClass.PRIM_TYPE_SPHERE: |
@@ -7603,8 +7597,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
7603 | hollow = (float)rules.GetLSLFloatItem(idx++); | 7597 | hollow = (float)rules.GetLSLFloatItem(idx++); |
7604 | twist = rules.GetVector3Item(idx++); | 7598 | twist = rules.GetVector3Item(idx++); |
7605 | taper_b = rules.GetVector3Item(idx++); // dimple | 7599 | taper_b = rules.GetVector3Item(idx++); // dimple |
7606 | part.Shape.PathCurve = (byte)Extrusion.Curve1; | 7600 | SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b, |
7607 | SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b, 5); | 7601 | (byte)ProfileShape.HalfCircle, (byte)Extrusion.Curve1); |
7608 | break; | 7602 | break; |
7609 | 7603 | ||
7610 | case (int)ScriptBaseClass.PRIM_TYPE_TORUS: | 7604 | case (int)ScriptBaseClass.PRIM_TYPE_TORUS: |
@@ -7622,9 +7616,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
7622 | revolutions = (float)rules.GetLSLFloatItem(idx++); | 7616 | revolutions = (float)rules.GetLSLFloatItem(idx++); |
7623 | radiusoffset = (float)rules.GetLSLFloatItem(idx++); | 7617 | radiusoffset = (float)rules.GetLSLFloatItem(idx++); |
7624 | skew = (float)rules.GetLSLFloatItem(idx++); | 7618 | skew = (float)rules.GetLSLFloatItem(idx++); |
7625 | part.Shape.PathCurve = (byte)Extrusion.Curve1; | ||
7626 | SetPrimitiveShapeParams(part, face, v, hollow, twist, holesize, topshear, profilecut, taper_b, | 7619 | SetPrimitiveShapeParams(part, face, v, hollow, twist, holesize, topshear, profilecut, taper_b, |
7627 | revolutions, radiusoffset, skew, 0); | 7620 | revolutions, radiusoffset, skew, (byte)ProfileShape.Circle, (byte)Extrusion.Curve1); |
7628 | break; | 7621 | break; |
7629 | 7622 | ||
7630 | case (int)ScriptBaseClass.PRIM_TYPE_TUBE: | 7623 | case (int)ScriptBaseClass.PRIM_TYPE_TUBE: |
@@ -7642,9 +7635,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
7642 | revolutions = (float)rules.GetLSLFloatItem(idx++); | 7635 | revolutions = (float)rules.GetLSLFloatItem(idx++); |
7643 | radiusoffset = (float)rules.GetLSLFloatItem(idx++); | 7636 | radiusoffset = (float)rules.GetLSLFloatItem(idx++); |
7644 | skew = (float)rules.GetLSLFloatItem(idx++); | 7637 | skew = (float)rules.GetLSLFloatItem(idx++); |
7645 | part.Shape.PathCurve = (byte)Extrusion.Curve1; | ||
7646 | SetPrimitiveShapeParams(part, face, v, hollow, twist, holesize, topshear, profilecut, taper_b, | 7638 | SetPrimitiveShapeParams(part, face, v, hollow, twist, holesize, topshear, profilecut, taper_b, |
7647 | revolutions, radiusoffset, skew, 1); | 7639 | revolutions, radiusoffset, skew, (byte)ProfileShape.Square, (byte)Extrusion.Curve1); |
7648 | break; | 7640 | break; |
7649 | 7641 | ||
7650 | case (int)ScriptBaseClass.PRIM_TYPE_RING: | 7642 | case (int)ScriptBaseClass.PRIM_TYPE_RING: |
@@ -7662,9 +7654,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
7662 | revolutions = (float)rules.GetLSLFloatItem(idx++); | 7654 | revolutions = (float)rules.GetLSLFloatItem(idx++); |
7663 | radiusoffset = (float)rules.GetLSLFloatItem(idx++); | 7655 | radiusoffset = (float)rules.GetLSLFloatItem(idx++); |
7664 | skew = (float)rules.GetLSLFloatItem(idx++); | 7656 | skew = (float)rules.GetLSLFloatItem(idx++); |
7665 | part.Shape.PathCurve = (byte)Extrusion.Curve1; | ||
7666 | SetPrimitiveShapeParams(part, face, v, hollow, twist, holesize, topshear, profilecut, taper_b, | 7657 | SetPrimitiveShapeParams(part, face, v, hollow, twist, holesize, topshear, profilecut, taper_b, |
7667 | revolutions, radiusoffset, skew, 3); | 7658 | revolutions, radiusoffset, skew, (byte)ProfileShape.EquilateralTriangle, (byte)Extrusion.Curve1); |
7668 | break; | 7659 | break; |
7669 | 7660 | ||
7670 | case (int)ScriptBaseClass.PRIM_TYPE_SCULPT: | 7661 | case (int)ScriptBaseClass.PRIM_TYPE_SCULPT: |
@@ -7673,8 +7664,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
7673 | 7664 | ||
7674 | string map = rules.Data[idx++].ToString(); | 7665 | string map = rules.Data[idx++].ToString(); |
7675 | face = (int)rules.GetLSLIntegerItem(idx++); // type | 7666 | face = (int)rules.GetLSLIntegerItem(idx++); // type |
7676 | part.Shape.PathCurve = (byte)Extrusion.Curve1; | 7667 | SetPrimitiveShapeParams(part, map, face, (byte)Extrusion.Curve1); |
7677 | SetPrimitiveShapeParams(part, map, face); | ||
7678 | break; | 7668 | break; |
7679 | } | 7669 | } |
7680 | 7670 | ||
@@ -7779,18 +7769,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
7779 | break; | 7769 | break; |
7780 | 7770 | ||
7781 | case (int)ScriptBaseClass.PRIM_PHANTOM: | 7771 | case (int)ScriptBaseClass.PRIM_PHANTOM: |
7782 | if (remain < 1) | 7772 | if (remain < 1) |
7783 | return; | 7773 | return; |
7784 | 7774 | ||
7785 | string ph = rules.Data[idx++].ToString(); | 7775 | string ph = rules.Data[idx++].ToString(); |
7786 | bool phantom; | 7776 | m_host.ParentGroup.ScriptSetPhantomStatus(ph.Equals("1")); |
7787 | 7777 | ||
7788 | if (ph.Equals("1")) | ||
7789 | phantom = true; | ||
7790 | else | ||
7791 | phantom = false; | ||
7792 | |||
7793 | part.ScriptSetPhantomStatus(phantom); | ||
7794 | break; | 7778 | break; |
7795 | 7779 | ||
7796 | case (int)ScriptBaseClass.PRIM_PHYSICS: | 7780 | case (int)ScriptBaseClass.PRIM_PHYSICS: |
@@ -7811,14 +7795,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
7811 | if (remain < 1) | 7795 | if (remain < 1) |
7812 | return; | 7796 | return; |
7813 | string temp = rules.Data[idx++].ToString(); | 7797 | string temp = rules.Data[idx++].ToString(); |
7814 | bool tempOnRez; | ||
7815 | 7798 | ||
7816 | if (temp.Equals("1")) | 7799 | m_host.ParentGroup.ScriptSetTemporaryStatus(temp.Equals("1")); |
7817 | tempOnRez = true; | ||
7818 | else | ||
7819 | tempOnRez = false; | ||
7820 | 7800 | ||
7821 | part.ScriptSetTemporaryStatus(tempOnRez); | ||
7822 | break; | 7801 | break; |
7823 | 7802 | ||
7824 | case (int)ScriptBaseClass.PRIM_TEXGEN: | 7803 | case (int)ScriptBaseClass.PRIM_TEXGEN: |
@@ -7983,9 +7962,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
7983 | { | 7962 | { |
7984 | m_host.AddScriptLPS(1); | 7963 | m_host.AddScriptLPS(1); |
7985 | Quaternion q; | 7964 | Quaternion q; |
7986 | if (m_host.ParentGroup.RootPart.AttachmentPoint != 0) | 7965 | if (m_host.ParentGroup.AttachmentPoint != 0) |
7987 | { | 7966 | { |
7988 | ScenePresence avatar = World.GetScenePresence(m_host.AttachedAvatar); | 7967 | ScenePresence avatar = World.GetScenePresence(m_host.ParentGroup.AttachedAvatar); |
7989 | if (avatar != null) | 7968 | if (avatar != null) |
7990 | if ((avatar.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0) | 7969 | if ((avatar.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0) |
7991 | q = avatar.CameraRotation; // Mouselook | 7970 | q = avatar.CameraRotation; // Mouselook |
@@ -8238,7 +8217,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
8238 | case ScriptBaseClass.PRIM_TYPE_BOX: | 8217 | case ScriptBaseClass.PRIM_TYPE_BOX: |
8239 | case ScriptBaseClass.PRIM_TYPE_CYLINDER: | 8218 | case ScriptBaseClass.PRIM_TYPE_CYLINDER: |
8240 | case ScriptBaseClass.PRIM_TYPE_PRISM: | 8219 | case ScriptBaseClass.PRIM_TYPE_PRISM: |
8241 | res.Add(new LSL_Integer(Shape.ProfileCurve)); | 8220 | res.Add(new LSL_Integer(Shape.ProfileCurve) & 0xf0); // Isolate hole shape nibble. |
8242 | res.Add(new LSL_Vector(Shape.ProfileBegin / 50000.0, 1 - Shape.ProfileEnd / 50000.0, 0)); | 8221 | res.Add(new LSL_Vector(Shape.ProfileBegin / 50000.0, 1 - Shape.ProfileEnd / 50000.0, 0)); |
8243 | res.Add(new LSL_Float(Shape.ProfileHollow / 50000.0)); | 8222 | res.Add(new LSL_Float(Shape.ProfileHollow / 50000.0)); |
8244 | res.Add(new LSL_Vector(Shape.PathTwistBegin / 100.0, Shape.PathTwist / 100.0, 0)); | 8223 | res.Add(new LSL_Vector(Shape.PathTwistBegin / 100.0, Shape.PathTwist / 100.0, 0)); |
@@ -8247,7 +8226,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
8247 | break; | 8226 | break; |
8248 | 8227 | ||
8249 | case ScriptBaseClass.PRIM_TYPE_SPHERE: | 8228 | case ScriptBaseClass.PRIM_TYPE_SPHERE: |
8250 | res.Add(new LSL_Integer(Shape.ProfileCurve)); | 8229 | res.Add(new LSL_Integer(Shape.ProfileCurve) & 0xf0); // Isolate hole shape nibble. |
8251 | res.Add(new LSL_Vector(Shape.PathBegin / 50000.0, 1 - Shape.PathEnd / 50000.0, 0)); | 8230 | res.Add(new LSL_Vector(Shape.PathBegin / 50000.0, 1 - Shape.PathEnd / 50000.0, 0)); |
8252 | res.Add(new LSL_Float(Shape.ProfileHollow / 50000.0)); | 8231 | res.Add(new LSL_Float(Shape.ProfileHollow / 50000.0)); |
8253 | res.Add(new LSL_Vector(Shape.PathTwistBegin / 100.0, Shape.PathTwist / 100.0, 0)); | 8232 | res.Add(new LSL_Vector(Shape.PathTwistBegin / 100.0, Shape.PathTwist / 100.0, 0)); |
@@ -8263,7 +8242,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
8263 | case ScriptBaseClass.PRIM_TYPE_TUBE: | 8242 | case ScriptBaseClass.PRIM_TYPE_TUBE: |
8264 | case ScriptBaseClass.PRIM_TYPE_TORUS: | 8243 | case ScriptBaseClass.PRIM_TYPE_TORUS: |
8265 | // holeshape | 8244 | // holeshape |
8266 | res.Add(new LSL_Integer(Shape.ProfileCurve)); | 8245 | res.Add(new LSL_Integer(Shape.ProfileCurve) & 0xf0); // Isolate hole shape nibble. |
8267 | 8246 | ||
8268 | // cut | 8247 | // cut |
8269 | res.Add(new LSL_Vector(Shape.PathBegin / 50000.0, 1 - Shape.PathEnd / 50000.0, 0)); | 8248 | res.Add(new LSL_Vector(Shape.PathBegin / 50000.0, 1 - Shape.PathEnd / 50000.0, 0)); |
@@ -10666,6 +10645,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
10666 | public LSL_List llGetObjectDetails(string id, LSL_List args) | 10645 | public LSL_List llGetObjectDetails(string id, LSL_List args) |
10667 | { | 10646 | { |
10668 | m_host.AddScriptLPS(1); | 10647 | m_host.AddScriptLPS(1); |
10648 | |||
10669 | LSL_List ret = new LSL_List(); | 10649 | LSL_List ret = new LSL_List(); |
10670 | UUID key = new UUID(); | 10650 | UUID key = new UUID(); |
10671 | if (UUID.TryParse(id, out key)) | 10651 | if (UUID.TryParse(id, out key)) |
@@ -10676,72 +10656,76 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
10676 | { | 10656 | { |
10677 | foreach (object o in args.Data) | 10657 | foreach (object o in args.Data) |
10678 | { | 10658 | { |
10679 | switch (o.ToString()) | 10659 | switch (int.Parse(o.ToString())) |
10680 | { | 10660 | { |
10681 | case "1": | 10661 | case ScriptBaseClass.OBJECT_NAME: |
10682 | ret.Add(new LSL_String(av.Firstname + " " + av.Lastname)); | 10662 | ret.Add(new LSL_String(av.Firstname + " " + av.Lastname)); |
10683 | break; | 10663 | break; |
10684 | case "2": | 10664 | case ScriptBaseClass.OBJECT_DESC: |
10685 | ret.Add(new LSL_String("")); | 10665 | ret.Add(new LSL_String("")); |
10686 | break; | 10666 | break; |
10687 | case "3": | 10667 | case ScriptBaseClass.OBJECT_POS: |
10688 | ret.Add(new LSL_Vector((double)av.AbsolutePosition.X, (double)av.AbsolutePosition.Y, (double)av.AbsolutePosition.Z)); | 10668 | ret.Add(new LSL_Vector((double)av.AbsolutePosition.X, (double)av.AbsolutePosition.Y, (double)av.AbsolutePosition.Z)); |
10689 | break; | 10669 | break; |
10690 | case "4": | 10670 | case ScriptBaseClass.OBJECT_ROT: |
10691 | ret.Add(new LSL_Rotation((double)av.Rotation.X, (double)av.Rotation.Y, (double)av.Rotation.Z, (double)av.Rotation.W)); | 10671 | ret.Add(new LSL_Rotation((double)av.Rotation.X, (double)av.Rotation.Y, (double)av.Rotation.Z, (double)av.Rotation.W)); |
10692 | break; | 10672 | break; |
10693 | case "5": | 10673 | case ScriptBaseClass.OBJECT_VELOCITY: |
10694 | ret.Add(new LSL_Vector(av.Velocity.X, av.Velocity.Y, av.Velocity.Z)); | 10674 | ret.Add(new LSL_Vector(av.Velocity.X, av.Velocity.Y, av.Velocity.Z)); |
10695 | break; | 10675 | break; |
10696 | case "6": | 10676 | case ScriptBaseClass.OBJECT_OWNER: |
10697 | ret.Add(new LSL_String(id)); | 10677 | ret.Add(new LSL_String(id)); |
10698 | break; | 10678 | break; |
10699 | case "7": | 10679 | case ScriptBaseClass.OBJECT_GROUP: |
10700 | ret.Add(new LSL_String(UUID.Zero.ToString())); | 10680 | ret.Add(new LSL_String(UUID.Zero.ToString())); |
10701 | break; | 10681 | break; |
10702 | case "8": | 10682 | case ScriptBaseClass.OBJECT_CREATOR: |
10703 | ret.Add(new LSL_String(UUID.Zero.ToString())); | 10683 | ret.Add(new LSL_String(UUID.Zero.ToString())); |
10704 | break; | 10684 | break; |
10705 | } | 10685 | } |
10706 | } | 10686 | } |
10687 | |||
10707 | return ret; | 10688 | return ret; |
10708 | } | 10689 | } |
10690 | |||
10709 | SceneObjectPart obj = World.GetSceneObjectPart(key); | 10691 | SceneObjectPart obj = World.GetSceneObjectPart(key); |
10710 | if (obj != null) | 10692 | if (obj != null) |
10711 | { | 10693 | { |
10712 | foreach (object o in args.Data) | 10694 | foreach (object o in args.Data) |
10713 | { | 10695 | { |
10714 | switch (o.ToString()) | 10696 | switch (int.Parse(o.ToString())) |
10715 | { | 10697 | { |
10716 | case "1": | 10698 | case ScriptBaseClass.OBJECT_NAME: |
10717 | ret.Add(new LSL_String(obj.Name)); | 10699 | ret.Add(new LSL_String(obj.Name)); |
10718 | break; | 10700 | break; |
10719 | case "2": | 10701 | case ScriptBaseClass.OBJECT_DESC: |
10720 | ret.Add(new LSL_String(obj.Description)); | 10702 | ret.Add(new LSL_String(obj.Description)); |
10721 | break; | 10703 | break; |
10722 | case "3": | 10704 | case ScriptBaseClass.OBJECT_POS: |
10723 | ret.Add(new LSL_Vector(obj.AbsolutePosition.X, obj.AbsolutePosition.Y, obj.AbsolutePosition.Z)); | 10705 | ret.Add(new LSL_Vector(obj.AbsolutePosition.X, obj.AbsolutePosition.Y, obj.AbsolutePosition.Z)); |
10724 | break; | 10706 | break; |
10725 | case "4": | 10707 | case ScriptBaseClass.OBJECT_ROT: |
10726 | ret.Add(new LSL_Rotation(obj.RotationOffset.X, obj.RotationOffset.Y, obj.RotationOffset.Z, obj.RotationOffset.W)); | 10708 | ret.Add(new LSL_Rotation(obj.RotationOffset.X, obj.RotationOffset.Y, obj.RotationOffset.Z, obj.RotationOffset.W)); |
10727 | break; | 10709 | break; |
10728 | case "5": | 10710 | case ScriptBaseClass.OBJECT_VELOCITY: |
10729 | ret.Add(new LSL_Vector(obj.Velocity.X, obj.Velocity.Y, obj.Velocity.Z)); | 10711 | ret.Add(new LSL_Vector(obj.Velocity.X, obj.Velocity.Y, obj.Velocity.Z)); |
10730 | break; | 10712 | break; |
10731 | case "6": | 10713 | case ScriptBaseClass.OBJECT_OWNER: |
10732 | ret.Add(new LSL_String(obj.OwnerID.ToString())); | 10714 | ret.Add(new LSL_String(obj.OwnerID.ToString())); |
10733 | break; | 10715 | break; |
10734 | case "7": | 10716 | case ScriptBaseClass.OBJECT_GROUP: |
10735 | ret.Add(new LSL_String(obj.GroupID.ToString())); | 10717 | ret.Add(new LSL_String(obj.GroupID.ToString())); |
10736 | break; | 10718 | break; |
10737 | case "8": | 10719 | case ScriptBaseClass.OBJECT_CREATOR: |
10738 | ret.Add(new LSL_String(obj.CreatorID.ToString())); | 10720 | ret.Add(new LSL_String(obj.CreatorID.ToString())); |
10739 | break; | 10721 | break; |
10740 | } | 10722 | } |
10741 | } | 10723 | } |
10724 | |||
10742 | return ret; | 10725 | return ret; |
10743 | } | 10726 | } |
10744 | } | 10727 | } |
10728 | |||
10745 | return new LSL_List(); | 10729 | return new LSL_List(); |
10746 | } | 10730 | } |
10747 | 10731 | ||
@@ -11000,31 +10984,173 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
11000 | { | 10984 | { |
11001 | m_SayShoutCount = 0; | 10985 | m_SayShoutCount = 0; |
11002 | } | 10986 | } |
10987 | public LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options) | ||
10988 | { | ||
10989 | m_host.AddScriptLPS(1); | ||
10990 | |||
10991 | Vector3 dir = new Vector3((float)(end-start).x, (float)(end-start).y, (float)(end-start).z); | ||
10992 | Vector3 startvector = new Vector3((float)start.x, (float)start.y, (float)start.z); | ||
10993 | Vector3 endvector = new Vector3((float)end.x, (float)end.y, (float)end.z); | ||
10994 | |||
10995 | int count = 0; | ||
10996 | // int detectPhantom = 0; | ||
10997 | int dataFlags = 0; | ||
10998 | int rejectTypes = 0; | ||
10999 | |||
11000 | for (int i = 0; i < options.Length; i += 2) | ||
11001 | { | ||
11002 | if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_MAX_HITS) | ||
11003 | { | ||
11004 | count = options.GetLSLIntegerItem(i + 1); | ||
11005 | } | ||
11006 | // else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DETECT_PHANTOM) | ||
11007 | // { | ||
11008 | // detectPhantom = options.GetLSLIntegerItem(i + 1); | ||
11009 | // } | ||
11010 | else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DATA_FLAGS) | ||
11011 | { | ||
11012 | dataFlags = options.GetLSLIntegerItem(i + 1); | ||
11013 | } | ||
11014 | else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_REJECT_TYPES) | ||
11015 | { | ||
11016 | rejectTypes = options.GetLSLIntegerItem(i + 1); | ||
11017 | } | ||
11018 | } | ||
11019 | |||
11020 | LSL_List list = new LSL_List(); | ||
11021 | List<ContactResult> results = World.PhysicsScene.RaycastWorld(startvector, dir, dir.Length(), count); | ||
11022 | |||
11023 | double distance = Util.GetDistanceTo(startvector, endvector); | ||
11024 | |||
11025 | if (distance == 0) | ||
11026 | distance = 0.001; | ||
11027 | |||
11028 | Vector3 posToCheck = startvector; | ||
11029 | ITerrainChannel channel = World.RequestModuleInterface<ITerrainChannel>(); | ||
11030 | |||
11031 | bool checkTerrain = !((rejectTypes & ScriptBaseClass.RC_REJECT_LAND) == ScriptBaseClass.RC_REJECT_LAND); | ||
11032 | bool checkAgents = !((rejectTypes & ScriptBaseClass.RC_REJECT_AGENTS) == ScriptBaseClass.RC_REJECT_AGENTS); | ||
11033 | bool checkNonPhysical = !((rejectTypes & ScriptBaseClass.RC_REJECT_NONPHYSICAL) == ScriptBaseClass.RC_REJECT_NONPHYSICAL); | ||
11034 | bool checkPhysical = !((rejectTypes & ScriptBaseClass.RC_REJECT_PHYSICAL) == ScriptBaseClass.RC_REJECT_PHYSICAL); | ||
11035 | |||
11036 | for (float i = 0; i <= distance; i += 0.1f) | ||
11037 | { | ||
11038 | posToCheck = startvector + (dir * (i / (float)distance)); | ||
11039 | |||
11040 | if (checkTerrain && channel[(int)(posToCheck.X + startvector.X), (int)(posToCheck.Y + startvector.Y)] < posToCheck.Z) | ||
11041 | { | ||
11042 | ContactResult result = new ContactResult(); | ||
11043 | result.ConsumerID = 0; | ||
11044 | result.Depth = 0; | ||
11045 | result.Normal = Vector3.Zero; | ||
11046 | result.Pos = posToCheck; | ||
11047 | results.Add(result); | ||
11048 | checkTerrain = false; | ||
11049 | } | ||
11050 | |||
11051 | if (checkAgents) | ||
11052 | { | ||
11053 | World.ForEachScenePresence(delegate(ScenePresence sp) | ||
11054 | { | ||
11055 | if (sp.AbsolutePosition.ApproxEquals(posToCheck, sp.PhysicsActor.Size.X)) | ||
11056 | { | ||
11057 | ContactResult result = new ContactResult (); | ||
11058 | result.ConsumerID = sp.LocalId; | ||
11059 | result.Depth = 0; | ||
11060 | result.Normal = Vector3.Zero; | ||
11061 | result.Pos = posToCheck; | ||
11062 | results.Add(result); | ||
11063 | } | ||
11064 | }); | ||
11065 | } | ||
11066 | } | ||
11067 | |||
11068 | int refcount = 0; | ||
11069 | foreach (ContactResult result in results) | ||
11070 | { | ||
11071 | if ((rejectTypes & ScriptBaseClass.RC_REJECT_LAND) | ||
11072 | == ScriptBaseClass.RC_REJECT_LAND && result.ConsumerID == 0) | ||
11073 | continue; | ||
11074 | |||
11075 | ISceneEntity entity = World.GetSceneObjectPart(result.ConsumerID); | ||
11076 | |||
11077 | if (entity == null && (rejectTypes & ScriptBaseClass.RC_REJECT_AGENTS) != ScriptBaseClass.RC_REJECT_AGENTS) | ||
11078 | entity = World.GetScenePresence(result.ConsumerID); //Only check if we should be looking for agents | ||
11079 | |||
11080 | if (entity == null) | ||
11081 | { | ||
11082 | list.Add(UUID.Zero); | ||
11083 | |||
11084 | if ((dataFlags & ScriptBaseClass.RC_GET_LINK_NUM) == ScriptBaseClass.RC_GET_LINK_NUM) | ||
11085 | list.Add(0); | ||
11086 | |||
11087 | list.Add(result.Pos); | ||
11088 | |||
11089 | if ((dataFlags & ScriptBaseClass.RC_GET_NORMAL) == ScriptBaseClass.RC_GET_NORMAL) | ||
11090 | list.Add(result.Normal); | ||
11091 | |||
11092 | continue; //Can't find it, so add UUID.Zero | ||
11093 | } | ||
11094 | |||
11095 | /*if (detectPhantom == 0 && intersection.obj is ISceneChildEntity && | ||
11096 | ((ISceneChildEntity)intersection.obj).PhysActor == null) | ||
11097 | continue;*/ //Can't do this ATM, physics engine knows only of non phantom objects | ||
11098 | |||
11099 | if (entity is SceneObjectPart) | ||
11100 | { | ||
11101 | if (((SceneObjectPart)entity).PhysActor != null && ((SceneObjectPart)entity).PhysActor.IsPhysical) | ||
11102 | { | ||
11103 | if (!checkPhysical) | ||
11104 | continue; | ||
11105 | } | ||
11106 | else | ||
11107 | { | ||
11108 | if (!checkNonPhysical) | ||
11109 | continue; | ||
11110 | } | ||
11111 | } | ||
11112 | |||
11113 | refcount++; | ||
11114 | if ((dataFlags & ScriptBaseClass.RC_GET_ROOT_KEY) == ScriptBaseClass.RC_GET_ROOT_KEY && entity is SceneObjectPart) | ||
11115 | list.Add(((SceneObjectPart)entity).ParentGroup.UUID); | ||
11116 | else | ||
11117 | list.Add(entity.UUID); | ||
11118 | |||
11119 | if ((dataFlags & ScriptBaseClass.RC_GET_LINK_NUM) == ScriptBaseClass.RC_GET_LINK_NUM) | ||
11120 | { | ||
11121 | if (entity is SceneObjectPart) | ||
11122 | list.Add(((SceneObjectPart)entity).LinkNum); | ||
11123 | else | ||
11124 | list.Add(0); | ||
11125 | } | ||
11126 | |||
11127 | list.Add(result.Pos); | ||
11128 | |||
11129 | if ((dataFlags & ScriptBaseClass.RC_GET_NORMAL) == ScriptBaseClass.RC_GET_NORMAL) | ||
11130 | list.Add(result.Normal); | ||
11131 | } | ||
11132 | |||
11133 | list.Add(refcount); //The status code, either the # of contacts, RCERR_SIM_PERF_LOW, or RCERR_CAST_TIME_EXCEEDED | ||
11134 | |||
11135 | return list; | ||
11136 | } | ||
11003 | 11137 | ||
11004 | #region Not Implemented | 11138 | #region Not Implemented |
11005 | // | 11139 | // |
11006 | // Listing the unimplemented lsl functions here, please move | 11140 | // Listing the unimplemented lsl functions here, please move |
11007 | // them from this region as they are completed | 11141 | // them from this region as they are completed |
11008 | // | 11142 | // |
11009 | public void llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options) | ||
11010 | { | ||
11011 | m_host.AddScriptLPS(1); | ||
11012 | NotImplemented("llCastRay"); | ||
11013 | |||
11014 | } | ||
11015 | 11143 | ||
11016 | public void llGetEnv(LSL_String name) | 11144 | public void llGetEnv(LSL_String name) |
11017 | { | 11145 | { |
11018 | m_host.AddScriptLPS(1); | 11146 | m_host.AddScriptLPS(1); |
11019 | NotImplemented("llGetEnv"); | 11147 | NotImplemented("llGetEnv"); |
11020 | |||
11021 | } | 11148 | } |
11022 | 11149 | ||
11023 | public void llGetSPMaxMemory() | 11150 | public void llGetSPMaxMemory() |
11024 | { | 11151 | { |
11025 | m_host.AddScriptLPS(1); | 11152 | m_host.AddScriptLPS(1); |
11026 | NotImplemented("llGetSPMaxMemory"); | 11153 | NotImplemented("llGetSPMaxMemory"); |
11027 | |||
11028 | } | 11154 | } |
11029 | 11155 | ||
11030 | public virtual LSL_Integer llGetUsedMemory() | 11156 | public virtual LSL_Integer llGetUsedMemory() |
@@ -11034,18 +11160,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
11034 | return 0; | 11160 | return 0; |
11035 | } | 11161 | } |
11036 | 11162 | ||
11037 | public void llRegionSayTo( LSL_Key target, LSL_Integer channel, LSL_String msg ) | 11163 | public void llScriptProfiler(LSL_Integer flags) |
11038 | { | ||
11039 | m_host.AddScriptLPS(1); | ||
11040 | NotImplemented("llRegionSayTo"); | ||
11041 | |||
11042 | } | ||
11043 | |||
11044 | public void llScriptProfiler( LSL_Integer flags ) | ||
11045 | { | 11164 | { |
11046 | m_host.AddScriptLPS(1); | 11165 | m_host.AddScriptLPS(1); |
11047 | //NotImplemented("llScriptProfiler"); | 11166 | //NotImplemented("llScriptProfiler"); |
11048 | |||
11049 | } | 11167 | } |
11050 | 11168 | ||
11051 | public void llSetSoundQueueing(int queue) | 11169 | public void llSetSoundQueueing(int queue) |
@@ -11164,9 +11282,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
11164 | } | 11282 | } |
11165 | } | 11283 | } |
11166 | 11284 | ||
11167 | public static string GetLine(UUID assetID, int line, int maxLength) | 11285 | /// <summary> |
11286 | /// Get a notecard line. | ||
11287 | /// </summary> | ||
11288 | /// <param name="assetID"></param> | ||
11289 | /// <param name="line">Lines start at index 0</param> | ||
11290 | /// <returns></returns> | ||
11291 | public static string GetLine(UUID assetID, int lineNumber) | ||
11168 | { | 11292 | { |
11169 | if (line < 0) | 11293 | if (lineNumber < 0) |
11170 | return ""; | 11294 | return ""; |
11171 | 11295 | ||
11172 | string data; | 11296 | string data; |
@@ -11178,17 +11302,32 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
11178 | { | 11302 | { |
11179 | m_Notecards[assetID].lastRef = DateTime.Now; | 11303 | m_Notecards[assetID].lastRef = DateTime.Now; |
11180 | 11304 | ||
11181 | if (line >= m_Notecards[assetID].text.Length) | 11305 | if (lineNumber >= m_Notecards[assetID].text.Length) |
11182 | return "\n\n\n"; | 11306 | return "\n\n\n"; |
11183 | 11307 | ||
11184 | data = m_Notecards[assetID].text[line]; | 11308 | data = m_Notecards[assetID].text[lineNumber]; |
11185 | if (data.Length > maxLength) | ||
11186 | data = data.Substring(0, maxLength); | ||
11187 | 11309 | ||
11188 | return data; | 11310 | return data; |
11189 | } | 11311 | } |
11190 | } | 11312 | } |
11191 | 11313 | ||
11314 | /// <summary> | ||
11315 | /// Get a notecard line. | ||
11316 | /// </summary> | ||
11317 | /// <param name="assetID"></param> | ||
11318 | /// <param name="line">Lines start at index 0</param> | ||
11319 | /// <param name="maxLength">Maximum length of the returned line. Longer lines will be truncated</para> | ||
11320 | /// <returns></returns> | ||
11321 | public static string GetLine(UUID assetID, int lineNumber, int maxLength) | ||
11322 | { | ||
11323 | string line = GetLine(assetID, lineNumber); | ||
11324 | |||
11325 | if (line.Length > maxLength) | ||
11326 | line = line.Substring(0, maxLength); | ||
11327 | |||
11328 | return line; | ||
11329 | } | ||
11330 | |||
11192 | public static void CacheCheck() | 11331 | public static void CacheCheck() |
11193 | { | 11332 | { |
11194 | foreach (UUID key in new List<UUID>(m_Notecards.Keys)) | 11333 | foreach (UUID key in new List<UUID>(m_Notecards.Keys)) |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs index 645566e..80daf5b 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs | |||
@@ -130,7 +130,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
130 | int idx = 0; | 130 | int idx = 0; |
131 | while (idx < rules.Length) | 131 | while (idx < rules.Length) |
132 | { | 132 | { |
133 | uint rule = (uint)rules.GetLSLIntegerItem(idx); | 133 | LSL_Integer ruleInt = rules.GetLSLIntegerItem(idx); |
134 | uint rule = (uint)ruleInt; | ||
134 | LSL_List toadd = new LSL_List(); | 135 | LSL_List toadd = new LSL_List(); |
135 | 136 | ||
136 | switch (rule) | 137 | switch (rule) |
@@ -247,7 +248,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
247 | 248 | ||
248 | if (toadd.Length > 0) | 249 | if (toadd.Length > 0) |
249 | { | 250 | { |
250 | values.Add(rule); | 251 | values.Add(ruleInt); |
251 | values.Add(toadd.Data[0]); | 252 | values.Add(toadd.Data[0]); |
252 | } | 253 | } |
253 | idx++; | 254 | idx++; |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index 6d2efce..9ec8a42 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs | |||
@@ -28,11 +28,16 @@ | |||
28 | using System; | 28 | using System; |
29 | using System.Collections; | 29 | using System.Collections; |
30 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
31 | using System.IO; | ||
32 | using System.Reflection; | ||
31 | using System.Runtime.Remoting.Lifetime; | 33 | using System.Runtime.Remoting.Lifetime; |
32 | using System.Text; | 34 | using System.Text; |
33 | using System.Net; | 35 | using System.Net; |
34 | using System.Threading; | 36 | using System.Threading; |
37 | using System.Xml; | ||
38 | using log4net; | ||
35 | using OpenMetaverse; | 39 | using OpenMetaverse; |
40 | using OpenMetaverse.StructuredData; | ||
36 | using Nini.Config; | 41 | using Nini.Config; |
37 | using OpenSim; | 42 | using OpenSim; |
38 | using OpenSim.Framework; | 43 | using OpenSim.Framework; |
@@ -119,6 +124,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
119 | [Serializable] | 124 | [Serializable] |
120 | public class OSSL_Api : MarshalByRefObject, IOSSL_Api, IScriptApi | 125 | public class OSSL_Api : MarshalByRefObject, IOSSL_Api, IScriptApi |
121 | { | 126 | { |
127 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
128 | |||
122 | internal IScriptEngine m_ScriptEngine; | 129 | internal IScriptEngine m_ScriptEngine; |
123 | internal ILSL_Api m_LSL_Api = null; // get a reference to the LSL API so we can call methods housed there | 130 | internal ILSL_Api m_LSL_Api = null; // get a reference to the LSL API so we can call methods housed there |
124 | internal SceneObjectPart m_host; | 131 | internal SceneObjectPart m_host; |
@@ -357,20 +364,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
357 | System.Threading.Thread.Sleep(delay); | 364 | System.Threading.Thread.Sleep(delay); |
358 | } | 365 | } |
359 | 366 | ||
360 | // | ||
361 | // OpenSim functions | ||
362 | // | ||
363 | public LSL_Integer osSetTerrainHeight(int x, int y, double val) | 367 | public LSL_Integer osSetTerrainHeight(int x, int y, double val) |
364 | { | 368 | { |
365 | CheckThreatLevel(ThreatLevel.High, "osSetTerrainHeight"); | 369 | CheckThreatLevel(ThreatLevel.High, "osSetTerrainHeight"); |
366 | return SetTerrainHeight(x, y, val); | 370 | return SetTerrainHeight(x, y, val); |
367 | } | 371 | } |
372 | |||
368 | public LSL_Integer osTerrainSetHeight(int x, int y, double val) | 373 | public LSL_Integer osTerrainSetHeight(int x, int y, double val) |
369 | { | 374 | { |
370 | CheckThreatLevel(ThreatLevel.High, "osTerrainSetHeight"); | 375 | CheckThreatLevel(ThreatLevel.High, "osTerrainSetHeight"); |
371 | OSSLDeprecated("osTerrainSetHeight", "osSetTerrainHeight"); | 376 | OSSLDeprecated("osTerrainSetHeight", "osSetTerrainHeight"); |
372 | return SetTerrainHeight(x, y, val); | 377 | return SetTerrainHeight(x, y, val); |
373 | } | 378 | } |
379 | |||
374 | private LSL_Integer SetTerrainHeight(int x, int y, double val) | 380 | private LSL_Integer SetTerrainHeight(int x, int y, double val) |
375 | { | 381 | { |
376 | m_host.AddScriptLPS(1); | 382 | m_host.AddScriptLPS(1); |
@@ -393,12 +399,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
393 | CheckThreatLevel(ThreatLevel.None, "osGetTerrainHeight"); | 399 | CheckThreatLevel(ThreatLevel.None, "osGetTerrainHeight"); |
394 | return GetTerrainHeight(x, y); | 400 | return GetTerrainHeight(x, y); |
395 | } | 401 | } |
402 | |||
396 | public LSL_Float osTerrainGetHeight(int x, int y) | 403 | public LSL_Float osTerrainGetHeight(int x, int y) |
397 | { | 404 | { |
398 | CheckThreatLevel(ThreatLevel.None, "osTerrainGetHeight"); | 405 | CheckThreatLevel(ThreatLevel.None, "osTerrainGetHeight"); |
399 | OSSLDeprecated("osTerrainGetHeight", "osGetTerrainHeight"); | 406 | OSSLDeprecated("osTerrainGetHeight", "osGetTerrainHeight"); |
400 | return GetTerrainHeight(x, y); | 407 | return GetTerrainHeight(x, y); |
401 | } | 408 | } |
409 | |||
402 | private LSL_Float GetTerrainHeight(int x, int y) | 410 | private LSL_Float GetTerrainHeight(int x, int y) |
403 | { | 411 | { |
404 | m_host.AddScriptLPS(1); | 412 | m_host.AddScriptLPS(1); |
@@ -673,13 +681,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
673 | CheckThreatLevel(ThreatLevel.VeryLow, "osSetPrimFloatOnWater"); | 681 | CheckThreatLevel(ThreatLevel.VeryLow, "osSetPrimFloatOnWater"); |
674 | 682 | ||
675 | m_host.AddScriptLPS(1); | 683 | m_host.AddScriptLPS(1); |
676 | if (m_host.ParentGroup != null) | 684 | |
677 | { | 685 | m_host.ParentGroup.RootPart.SetFloatOnWater(floatYN); |
678 | if (m_host.ParentGroup.RootPart != null) | ||
679 | { | ||
680 | m_host.ParentGroup.RootPart.SetFloatOnWater(floatYN); | ||
681 | } | ||
682 | } | ||
683 | } | 686 | } |
684 | 687 | ||
685 | // Teleport functions | 688 | // Teleport functions |
@@ -870,7 +873,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
870 | ScenePresence target = (ScenePresence)World.Entities[avatarID]; | 873 | ScenePresence target = (ScenePresence)World.Entities[avatarID]; |
871 | if (target != null) | 874 | if (target != null) |
872 | { | 875 | { |
873 | UUID animID=UUID.Zero; | 876 | UUID animID = UUID.Zero; |
874 | m_host.TaskInventory.LockItemsForRead(true); | 877 | m_host.TaskInventory.LockItemsForRead(true); |
875 | foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) | 878 | foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) |
876 | { | 879 | { |
@@ -1028,6 +1031,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1028 | drawList += "PenColor " + color + "; "; | 1031 | drawList += "PenColor " + color + "; "; |
1029 | return drawList; | 1032 | return drawList; |
1030 | } | 1033 | } |
1034 | |||
1031 | // Deprecated | 1035 | // Deprecated |
1032 | public string osSetPenColour(string drawList, string colour) | 1036 | public string osSetPenColour(string drawList, string colour) |
1033 | { | 1037 | { |
@@ -1189,11 +1193,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1189 | OSSLDeprecated("osSunGetParam", "osGetSunParam"); | 1193 | OSSLDeprecated("osSunGetParam", "osGetSunParam"); |
1190 | return GetSunParam(param); | 1194 | return GetSunParam(param); |
1191 | } | 1195 | } |
1196 | |||
1192 | public double osGetSunParam(string param) | 1197 | public double osGetSunParam(string param) |
1193 | { | 1198 | { |
1194 | CheckThreatLevel(ThreatLevel.None, "osGetSunParam"); | 1199 | CheckThreatLevel(ThreatLevel.None, "osGetSunParam"); |
1195 | return GetSunParam(param); | 1200 | return GetSunParam(param); |
1196 | } | 1201 | } |
1202 | |||
1197 | private double GetSunParam(string param) | 1203 | private double GetSunParam(string param) |
1198 | { | 1204 | { |
1199 | m_host.AddScriptLPS(1); | 1205 | m_host.AddScriptLPS(1); |
@@ -1215,11 +1221,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1215 | OSSLDeprecated("osSunSetParam", "osSetSunParam"); | 1221 | OSSLDeprecated("osSunSetParam", "osSetSunParam"); |
1216 | SetSunParam(param, value); | 1222 | SetSunParam(param, value); |
1217 | } | 1223 | } |
1224 | |||
1218 | public void osSetSunParam(string param, double value) | 1225 | public void osSetSunParam(string param, double value) |
1219 | { | 1226 | { |
1220 | CheckThreatLevel(ThreatLevel.None, "osSetSunParam"); | 1227 | CheckThreatLevel(ThreatLevel.None, "osSetSunParam"); |
1221 | SetSunParam(param, value); | 1228 | SetSunParam(param, value); |
1222 | } | 1229 | } |
1230 | |||
1223 | private void SetSunParam(string param, double value) | 1231 | private void SetSunParam(string param, double value) |
1224 | { | 1232 | { |
1225 | m_host.AddScriptLPS(1); | 1233 | m_host.AddScriptLPS(1); |
@@ -1229,10 +1237,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1229 | { | 1237 | { |
1230 | module.SetSunParameter(param, value); | 1238 | module.SetSunParameter(param, value); |
1231 | } | 1239 | } |
1232 | |||
1233 | } | 1240 | } |
1234 | 1241 | ||
1235 | |||
1236 | public string osWindActiveModelPluginName() | 1242 | public string osWindActiveModelPluginName() |
1237 | { | 1243 | { |
1238 | CheckThreatLevel(ThreatLevel.None, "osWindActiveModelPluginName"); | 1244 | CheckThreatLevel(ThreatLevel.None, "osWindActiveModelPluginName"); |
@@ -1311,12 +1317,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1311 | OSSLDeprecated(functionName, "osSetParcelDetails"); | 1317 | OSSLDeprecated(functionName, "osSetParcelDetails"); |
1312 | SetParcelDetails(pos, rules, functionName); | 1318 | SetParcelDetails(pos, rules, functionName); |
1313 | } | 1319 | } |
1320 | |||
1314 | public void osSetParcelDetails(LSL_Vector pos, LSL_List rules) | 1321 | public void osSetParcelDetails(LSL_Vector pos, LSL_List rules) |
1315 | { | 1322 | { |
1316 | const string functionName = "osSetParcelDetails"; | 1323 | const string functionName = "osSetParcelDetails"; |
1317 | CheckThreatLevel(ThreatLevel.High, functionName); | 1324 | CheckThreatLevel(ThreatLevel.High, functionName); |
1318 | SetParcelDetails(pos, rules, functionName); | 1325 | SetParcelDetails(pos, rules, functionName); |
1319 | } | 1326 | } |
1327 | |||
1320 | private void SetParcelDetails(LSL_Vector pos, LSL_List rules, string functionName) | 1328 | private void SetParcelDetails(LSL_Vector pos, LSL_List rules, string functionName) |
1321 | { | 1329 | { |
1322 | m_host.AddScriptLPS(1); | 1330 | m_host.AddScriptLPS(1); |
@@ -1436,8 +1444,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1436 | voiceModule.setLandSIPAddress(SIPAddress,land.LandData.GlobalID); | 1444 | voiceModule.setLandSIPAddress(SIPAddress,land.LandData.GlobalID); |
1437 | else | 1445 | else |
1438 | OSSLError("osSetParcelSIPAddress: No voice module enabled for this land"); | 1446 | OSSLError("osSetParcelSIPAddress: No voice module enabled for this land"); |
1439 | |||
1440 | |||
1441 | } | 1447 | } |
1442 | 1448 | ||
1443 | public string osGetScriptEngineName() | 1449 | public string osGetScriptEngineName() |
@@ -1690,8 +1696,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1690 | return jsondata; | 1696 | return jsondata; |
1691 | } | 1697 | } |
1692 | 1698 | ||
1693 | // send a message to to object identified by the given UUID, a script in the object must implement the dataserver function | 1699 | /// <summary> |
1694 | // the dataserver function is passed the ID of the calling function and a string message | 1700 | /// Send a message to to object identified by the given UUID |
1701 | /// </summary> | ||
1702 | /// <remarks> | ||
1703 | /// A script in the object must implement the dataserver function | ||
1704 | /// the dataserver function is passed the ID of the calling function and a string message | ||
1705 | /// </remarks> | ||
1706 | /// <param name="objectUUID"></param> | ||
1707 | /// <param name="message"></param> | ||
1695 | public void osMessageObject(LSL_Key objectUUID, string message) | 1708 | public void osMessageObject(LSL_Key objectUUID, string message) |
1696 | { | 1709 | { |
1697 | CheckThreatLevel(ThreatLevel.Low, "osMessageObject"); | 1710 | CheckThreatLevel(ThreatLevel.Low, "osMessageObject"); |
@@ -1706,34 +1719,56 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1706 | "dataserver", resobj, new DetectParams[0])); | 1719 | "dataserver", resobj, new DetectParams[0])); |
1707 | } | 1720 | } |
1708 | 1721 | ||
1709 | 1722 | /// <summary> | |
1710 | // This needs ThreatLevel high. It is an excellent griefer tool, | 1723 | /// Write a notecard directly to the prim's inventory. |
1711 | // In a loop, it can cause asset bloat and DOS levels of asset | 1724 | /// </summary> |
1712 | // writes. | 1725 | /// <remarks> |
1713 | // | 1726 | /// This needs ThreatLevel high. It is an excellent griefer tool, |
1727 | /// In a loop, it can cause asset bloat and DOS levels of asset | ||
1728 | /// writes. | ||
1729 | /// </remarks> | ||
1730 | /// <param name="notecardName">The name of the notecard to write.</param> | ||
1731 | /// <param name="contents">The contents of the notecard.</param> | ||
1714 | public void osMakeNotecard(string notecardName, LSL_Types.list contents) | 1732 | public void osMakeNotecard(string notecardName, LSL_Types.list contents) |
1715 | { | 1733 | { |
1716 | CheckThreatLevel(ThreatLevel.High, "osMakeNotecard"); | 1734 | CheckThreatLevel(ThreatLevel.High, "osMakeNotecard"); |
1717 | m_host.AddScriptLPS(1); | 1735 | m_host.AddScriptLPS(1); |
1718 | 1736 | ||
1719 | // Create new asset | 1737 | StringBuilder notecardData = new StringBuilder(); |
1720 | AssetBase asset = new AssetBase(UUID.Random(), notecardName, (sbyte)AssetType.Notecard, m_host.OwnerID.ToString()); | ||
1721 | asset.Description = "Script Generated Notecard"; | ||
1722 | string notecardData = String.Empty; | ||
1723 | 1738 | ||
1724 | for (int i = 0; i < contents.Length; i++) { | 1739 | for (int i = 0; i < contents.Length; i++) |
1725 | notecardData += contents.GetLSLStringItem(i) + "\n"; | 1740 | notecardData.Append((string)(contents.GetLSLStringItem(i) + "\n")); |
1726 | } | 1741 | |
1742 | SaveNotecard(notecardName, "Script generated notecard", notecardData.ToString(), false); | ||
1743 | } | ||
1727 | 1744 | ||
1728 | int textLength = notecardData.Length; | 1745 | /// <summary> |
1729 | notecardData = "Linden text version 2\n{\nLLEmbeddedItems version 1\n{\ncount 0\n}\nText length " | 1746 | /// Save a notecard to prim inventory. |
1730 | + textLength.ToString() + "\n" + notecardData + "}\n"; | 1747 | /// </summary> |
1748 | /// <param name="name"></param> | ||
1749 | /// <param name="description">Description of notecard</param> | ||
1750 | /// <param name="notecardData"></param> | ||
1751 | /// <param name="forceSameName"> | ||
1752 | /// If true, then if an item exists with the same name, it is replaced. | ||
1753 | /// If false, then a new item is created witha slightly different name (e.g. name 1) | ||
1754 | /// </param> | ||
1755 | /// <returns>Prim inventory item created.</returns> | ||
1756 | protected TaskInventoryItem SaveNotecard(string name, string description, string data, bool forceSameName) | ||
1757 | { | ||
1758 | // Create new asset | ||
1759 | AssetBase asset = new AssetBase(UUID.Random(), name, (sbyte)AssetType.Notecard, m_host.OwnerID.ToString()); | ||
1760 | asset.Description = description; | ||
1761 | |||
1762 | int textLength = data.Length; | ||
1763 | data | ||
1764 | = "Linden text version 2\n{\nLLEmbeddedItems version 1\n{\ncount 0\n}\nText length " | ||
1765 | + textLength.ToString() + "\n" + data + "}\n"; | ||
1731 | 1766 | ||
1732 | asset.Data = Util.UTF8.GetBytes(notecardData); | 1767 | asset.Data = Util.UTF8.GetBytes(data); |
1733 | World.AssetService.Store(asset); | 1768 | World.AssetService.Store(asset); |
1734 | 1769 | ||
1735 | // Create Task Entry | 1770 | // Create Task Entry |
1736 | TaskInventoryItem taskItem=new TaskInventoryItem(); | 1771 | TaskInventoryItem taskItem = new TaskInventoryItem(); |
1737 | 1772 | ||
1738 | taskItem.ResetIDs(m_host.UUID); | 1773 | taskItem.ResetIDs(m_host.UUID); |
1739 | taskItem.ParentID = m_host.UUID; | 1774 | taskItem.ParentID = m_host.UUID; |
@@ -1755,29 +1790,54 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1755 | taskItem.PermsMask = 0; | 1790 | taskItem.PermsMask = 0; |
1756 | taskItem.AssetID = asset.FullID; | 1791 | taskItem.AssetID = asset.FullID; |
1757 | 1792 | ||
1758 | m_host.Inventory.AddInventoryItem(taskItem, false); | 1793 | if (forceSameName) |
1794 | m_host.Inventory.AddInventoryItemExclusive(taskItem, false); | ||
1795 | else | ||
1796 | m_host.Inventory.AddInventoryItem(taskItem, false); | ||
1797 | |||
1798 | return taskItem; | ||
1759 | } | 1799 | } |
1760 | 1800 | ||
1801 | /// <summary> | ||
1802 | /// Load the notecard data found at the given prim inventory item name or asset uuid. | ||
1803 | /// </summary> | ||
1804 | /// <param name="notecardNameOrUuid"></param> | ||
1805 | /// <returns>The text loaded. Null if no notecard was found.</returns> | ||
1806 | protected string LoadNotecard(string notecardNameOrUuid) | ||
1807 | { | ||
1808 | UUID assetID = CacheNotecard(notecardNameOrUuid); | ||
1809 | StringBuilder notecardData = new StringBuilder(); | ||
1761 | 1810 | ||
1762 | /*Instead of using the LSL Dataserver event to pull notecard data, | 1811 | for (int count = 0; count < NotecardCache.GetLines(assetID); count++) |
1763 | this will simply read the requested line and return its data as a string. | 1812 | { |
1813 | string line = NotecardCache.GetLine(assetID, count) + "\n"; | ||
1764 | 1814 | ||
1765 | Warning - due to the synchronous method this function uses to fetch assets, its use | 1815 | // m_log.DebugFormat("[OSSL]: From notecard {0} loading line {1}", notecardNameOrUuid, line); |
1766 | may be dangerous and unreliable while running in grid mode. | 1816 | |
1767 | */ | 1817 | notecardData.Append(line); |
1768 | public string osGetNotecardLine(string name, int line) | 1818 | } |
1769 | { | 1819 | |
1770 | CheckThreatLevel(ThreatLevel.VeryHigh, "osGetNotecardLine"); | 1820 | return notecardData.ToString(); |
1771 | m_host.AddScriptLPS(1); | 1821 | } |
1772 | 1822 | ||
1823 | /// <summary> | ||
1824 | /// Cache a notecard's contents. | ||
1825 | /// </summary> | ||
1826 | /// <param name="notecardNameOrUuid"></param> | ||
1827 | /// <returns> | ||
1828 | /// The asset id of the notecard, which is used for retrieving the cached data. | ||
1829 | /// UUID.Zero if no asset could be found. | ||
1830 | /// </returns> | ||
1831 | protected UUID CacheNotecard(string notecardNameOrUuid) | ||
1832 | { | ||
1773 | UUID assetID = UUID.Zero; | 1833 | UUID assetID = UUID.Zero; |
1774 | 1834 | ||
1775 | if (!UUID.TryParse(name, out assetID)) | 1835 | if (!UUID.TryParse(notecardNameOrUuid, out assetID)) |
1776 | { | 1836 | { |
1777 | m_host.TaskInventory.LockItemsForRead(true); | 1837 | m_host.TaskInventory.LockItemsForRead(true); |
1778 | foreach (TaskInventoryItem item in m_host.TaskInventory.Values) | 1838 | foreach (TaskInventoryItem item in m_host.TaskInventory.Values) |
1779 | { | 1839 | { |
1780 | if (item.Type == 7 && item.Name == name) | 1840 | if (item.Type == 7 && item.Name == notecardNameOrUuid) |
1781 | { | 1841 | { |
1782 | assetID = item.AssetID; | 1842 | assetID = item.AssetID; |
1783 | } | 1843 | } |
@@ -1786,118 +1846,100 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1786 | } | 1846 | } |
1787 | 1847 | ||
1788 | if (assetID == UUID.Zero) | 1848 | if (assetID == UUID.Zero) |
1789 | { | 1849 | return UUID.Zero; |
1790 | OSSLShoutError("Notecard '" + name + "' could not be found."); | ||
1791 | return "ERROR!"; | ||
1792 | } | ||
1793 | 1850 | ||
1794 | if (!NotecardCache.IsCached(assetID)) | 1851 | if (!NotecardCache.IsCached(assetID)) |
1795 | { | 1852 | { |
1796 | AssetBase a = World.AssetService.Get(assetID.ToString()); | 1853 | AssetBase a = World.AssetService.Get(assetID.ToString()); |
1797 | if (a != null) | ||
1798 | { | ||
1799 | System.Text.UTF8Encoding enc = new System.Text.UTF8Encoding(); | ||
1800 | string data = enc.GetString(a.Data); | ||
1801 | NotecardCache.Cache(assetID, data); | ||
1802 | } | ||
1803 | else | ||
1804 | { | ||
1805 | OSSLShoutError("Notecard '" + name + "' could not be found."); | ||
1806 | return "ERROR!"; | ||
1807 | } | ||
1808 | }; | ||
1809 | 1854 | ||
1810 | return NotecardCache.GetLine(assetID, line, 255); | 1855 | if (a == null) |
1856 | return UUID.Zero; | ||
1811 | 1857 | ||
1858 | System.Text.UTF8Encoding enc = new System.Text.UTF8Encoding(); | ||
1859 | string data = enc.GetString(a.Data); | ||
1860 | NotecardCache.Cache(assetID, data); | ||
1861 | }; | ||
1812 | 1862 | ||
1863 | return assetID; | ||
1813 | } | 1864 | } |
1814 | 1865 | ||
1815 | /*Instead of using the LSL Dataserver event to pull notecard data line by line, | 1866 | /// <summary> |
1816 | this will simply read the entire notecard and return its data as a string. | 1867 | /// Directly get an entire notecard at once. |
1868 | /// </summary> | ||
1869 | /// <remarks> | ||
1870 | /// Instead of using the LSL Dataserver event to pull notecard data | ||
1871 | /// this will simply read the entire notecard and return its data as a string. | ||
1872 | /// | ||
1873 | /// Warning - due to the synchronous method this function uses to fetch assets, its use | ||
1874 | /// may be dangerous and unreliable while running in grid mode. | ||
1875 | /// </remarks> | ||
1876 | /// <param name="name">Name of the notecard or its asset id</param> | ||
1877 | /// <param name="line">The line number to read. The first line is line 0</param> | ||
1878 | /// <returns>Notecard line</returns> | ||
1879 | public string osGetNotecardLine(string name, int line) | ||
1880 | { | ||
1881 | CheckThreatLevel(ThreatLevel.VeryHigh, "osGetNotecardLine"); | ||
1882 | m_host.AddScriptLPS(1); | ||
1817 | 1883 | ||
1818 | Warning - due to the synchronous method this function uses to fetch assets, its use | 1884 | UUID assetID = CacheNotecard(name); |
1819 | may be dangerous and unreliable while running in grid mode. | ||
1820 | */ | ||
1821 | 1885 | ||
1886 | if (assetID == UUID.Zero) | ||
1887 | { | ||
1888 | OSSLShoutError("Notecard '" + name + "' could not be found."); | ||
1889 | return "ERROR!"; | ||
1890 | } | ||
1891 | |||
1892 | return NotecardCache.GetLine(assetID, line); | ||
1893 | } | ||
1894 | |||
1895 | /// <summary> | ||
1896 | /// Get an entire notecard at once. | ||
1897 | /// </summary> | ||
1898 | /// <remarks> | ||
1899 | /// Instead of using the LSL Dataserver event to pull notecard data line by line, | ||
1900 | /// this will simply read the entire notecard and return its data as a string. | ||
1901 | /// | ||
1902 | /// Warning - due to the synchronous method this function uses to fetch assets, its use | ||
1903 | /// may be dangerous and unreliable while running in grid mode. | ||
1904 | /// </remarks> | ||
1905 | /// <param name="name">Name of the notecard or its asset id</param> | ||
1906 | /// <returns>Notecard text</returns> | ||
1822 | public string osGetNotecard(string name) | 1907 | public string osGetNotecard(string name) |
1823 | { | 1908 | { |
1824 | CheckThreatLevel(ThreatLevel.VeryHigh, "osGetNotecard"); | 1909 | CheckThreatLevel(ThreatLevel.VeryHigh, "osGetNotecard"); |
1825 | m_host.AddScriptLPS(1); | 1910 | m_host.AddScriptLPS(1); |
1826 | 1911 | ||
1827 | UUID assetID = UUID.Zero; | 1912 | string text = LoadNotecard(name); |
1828 | string NotecardData = ""; | ||
1829 | 1913 | ||
1830 | if (!UUID.TryParse(name, out assetID)) | 1914 | if (text == null) |
1831 | { | ||
1832 | m_host.TaskInventory.LockItemsForRead(true); | ||
1833 | foreach (TaskInventoryItem item in m_host.TaskInventory.Values) | ||
1834 | { | ||
1835 | if (item.Type == 7 && item.Name == name) | ||
1836 | { | ||
1837 | assetID = item.AssetID; | ||
1838 | } | ||
1839 | } | ||
1840 | m_host.TaskInventory.LockItemsForRead(false); | ||
1841 | } | ||
1842 | |||
1843 | if (assetID == UUID.Zero) | ||
1844 | { | 1915 | { |
1845 | OSSLShoutError("Notecard '" + name + "' could not be found."); | 1916 | OSSLShoutError("Notecard '" + name + "' could not be found."); |
1846 | return "ERROR!"; | 1917 | return "ERROR!"; |
1847 | } | 1918 | } |
1848 | 1919 | else | |
1849 | if (!NotecardCache.IsCached(assetID)) | ||
1850 | { | ||
1851 | AssetBase a = World.AssetService.Get(assetID.ToString()); | ||
1852 | if (a != null) | ||
1853 | { | ||
1854 | System.Text.UTF8Encoding enc = new System.Text.UTF8Encoding(); | ||
1855 | string data = enc.GetString(a.Data); | ||
1856 | NotecardCache.Cache(assetID, data); | ||
1857 | } | ||
1858 | else | ||
1859 | { | ||
1860 | OSSLShoutError("Notecard '" + name + "' could not be found."); | ||
1861 | return "ERROR!"; | ||
1862 | } | ||
1863 | }; | ||
1864 | |||
1865 | for (int count = 0; count < NotecardCache.GetLines(assetID); count++) | ||
1866 | { | 1920 | { |
1867 | NotecardData += NotecardCache.GetLine(assetID, count, 255) + "\n"; | 1921 | return text; |
1868 | } | 1922 | } |
1869 | |||
1870 | return NotecardData; | ||
1871 | |||
1872 | |||
1873 | } | 1923 | } |
1874 | 1924 | ||
1875 | /*Instead of using the LSL Dataserver event to pull notecard data, | 1925 | /// <summary> |
1876 | this will simply read the number of note card lines and return this data as an integer. | 1926 | /// Get the number of lines in the given notecard. |
1877 | 1927 | /// </summary> | |
1878 | Warning - due to the synchronous method this function uses to fetch assets, its use | 1928 | /// <remarks> |
1879 | may be dangerous and unreliable while running in grid mode. | 1929 | /// Instead of using the LSL Dataserver event to pull notecard data, |
1880 | */ | 1930 | /// this will simply read the number of note card lines and return this data as an integer. |
1881 | 1931 | /// | |
1932 | /// Warning - due to the synchronous method this function uses to fetch assets, its use | ||
1933 | /// may be dangerous and unreliable while running in grid mode. | ||
1934 | /// </remarks> | ||
1935 | /// <param name="name">Name of the notecard or its asset id</param> | ||
1936 | /// <returns></returns> | ||
1882 | public int osGetNumberOfNotecardLines(string name) | 1937 | public int osGetNumberOfNotecardLines(string name) |
1883 | { | 1938 | { |
1884 | CheckThreatLevel(ThreatLevel.VeryHigh, "osGetNumberOfNotecardLines"); | 1939 | CheckThreatLevel(ThreatLevel.VeryHigh, "osGetNumberOfNotecardLines"); |
1885 | m_host.AddScriptLPS(1); | 1940 | m_host.AddScriptLPS(1); |
1886 | 1941 | ||
1887 | UUID assetID = UUID.Zero; | 1942 | UUID assetID = CacheNotecard(name); |
1888 | |||
1889 | if (!UUID.TryParse(name, out assetID)) | ||
1890 | { | ||
1891 | m_host.TaskInventory.LockItemsForRead(true); | ||
1892 | foreach (TaskInventoryItem item in m_host.TaskInventory.Values) | ||
1893 | { | ||
1894 | if (item.Type == 7 && item.Name == name) | ||
1895 | { | ||
1896 | assetID = item.AssetID; | ||
1897 | } | ||
1898 | } | ||
1899 | m_host.TaskInventory.LockItemsForRead(false); | ||
1900 | } | ||
1901 | 1943 | ||
1902 | if (assetID == UUID.Zero) | 1944 | if (assetID == UUID.Zero) |
1903 | { | 1945 | { |
@@ -1905,25 +1947,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1905 | return -1; | 1947 | return -1; |
1906 | } | 1948 | } |
1907 | 1949 | ||
1908 | if (!NotecardCache.IsCached(assetID)) | ||
1909 | { | ||
1910 | AssetBase a = World.AssetService.Get(assetID.ToString()); | ||
1911 | if (a != null) | ||
1912 | { | ||
1913 | System.Text.UTF8Encoding enc = new System.Text.UTF8Encoding(); | ||
1914 | string data = enc.GetString(a.Data); | ||
1915 | NotecardCache.Cache(assetID, data); | ||
1916 | } | ||
1917 | else | ||
1918 | { | ||
1919 | OSSLShoutError("Notecard '" + name + "' could not be found."); | ||
1920 | return -1; | ||
1921 | } | ||
1922 | }; | ||
1923 | |||
1924 | return NotecardCache.GetLines(assetID); | 1950 | return NotecardCache.GetLines(assetID); |
1925 | |||
1926 | |||
1927 | } | 1951 | } |
1928 | 1952 | ||
1929 | public string osAvatarName2Key(string firstname, string lastname) | 1953 | public string osAvatarName2Key(string firstname, string lastname) |
@@ -1962,15 +1986,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1962 | { | 1986 | { |
1963 | return ""; | 1987 | return ""; |
1964 | } | 1988 | } |
1965 | |||
1966 | } | 1989 | } |
1967 | 1990 | ||
1991 | /// <summary> | ||
1992 | /// Get the nickname of this grid, as set in the [GridInfo] config section. | ||
1993 | /// </summary> | ||
1994 | /// <remarks> | ||
1968 | /// Threat level is Moderate because intentional abuse, for instance | 1995 | /// Threat level is Moderate because intentional abuse, for instance |
1969 | /// scripts that are written to be malicious only on one grid, | 1996 | /// scripts that are written to be malicious only on one grid, |
1970 | /// for instance in a HG scenario, are a distinct possibility. | 1997 | /// for instance in a HG scenario, are a distinct possibility. |
1971 | /// | 1998 | /// </remarks> |
1972 | /// Use value from the config file and return it. | 1999 | /// <returns></returns> |
1973 | /// | ||
1974 | public string osGetGridNick() | 2000 | public string osGetGridNick() |
1975 | { | 2001 | { |
1976 | CheckThreatLevel(ThreatLevel.Moderate, "osGetGridNick"); | 2002 | CheckThreatLevel(ThreatLevel.Moderate, "osGetGridNick"); |
@@ -2037,7 +2063,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2037 | // Find matches beginning at start position | 2063 | // Find matches beginning at start position |
2038 | Regex matcher = new Regex(pattern); | 2064 | Regex matcher = new Regex(pattern); |
2039 | Match match = matcher.Match(src, start); | 2065 | Match match = matcher.Match(src, start); |
2040 | if (match.Success) | 2066 | while (match.Success) |
2041 | { | 2067 | { |
2042 | foreach (System.Text.RegularExpressions.Group g in match.Groups) | 2068 | foreach (System.Text.RegularExpressions.Group g in match.Groups) |
2043 | { | 2069 | { |
@@ -2047,6 +2073,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2047 | result.Add(new LSL_Integer(g.Index)); | 2073 | result.Add(new LSL_Integer(g.Index)); |
2048 | } | 2074 | } |
2049 | } | 2075 | } |
2076 | |||
2077 | match = match.NextMatch(); | ||
2050 | } | 2078 | } |
2051 | 2079 | ||
2052 | return result; | 2080 | return result; |
@@ -2076,12 +2104,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2076 | return World.RegionInfo.RegionSettings.LoadedCreationID; | 2104 | return World.RegionInfo.RegionSettings.LoadedCreationID; |
2077 | } | 2105 | } |
2078 | 2106 | ||
2079 | // Threat level is 'Low' because certain users could possibly be tricked into | 2107 | /// <summary> |
2080 | // dropping an unverified script into one of their own objects, which could | 2108 | /// Get the primitive parameters of a linked prim. |
2081 | // then gather the physical construction details of the object and transmit it | 2109 | /// </summary> |
2082 | // to an unscrupulous third party, thus permitting unauthorized duplication of | 2110 | /// <remarks> |
2083 | // the object's form. | 2111 | /// Threat level is 'Low' because certain users could possibly be tricked into |
2084 | // | 2112 | /// dropping an unverified script into one of their own objects, which could |
2113 | /// then gather the physical construction details of the object and transmit it | ||
2114 | /// to an unscrupulous third party, thus permitting unauthorized duplication of | ||
2115 | /// the object's form. | ||
2116 | /// </remarks> | ||
2117 | /// <param name="linknumber"></param> | ||
2118 | /// <param name="rules"></param> | ||
2119 | /// <returns></returns> | ||
2085 | public LSL_List osGetLinkPrimitiveParams(int linknumber, LSL_List rules) | 2120 | public LSL_List osGetLinkPrimitiveParams(int linknumber, LSL_List rules) |
2086 | { | 2121 | { |
2087 | CheckThreatLevel(ThreatLevel.High, "osGetLinkPrimitiveParams"); | 2122 | CheckThreatLevel(ThreatLevel.High, "osGetLinkPrimitiveParams"); |
@@ -2096,25 +2131,122 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2096 | return retVal; | 2131 | return retVal; |
2097 | } | 2132 | } |
2098 | 2133 | ||
2099 | public LSL_Key osNpcCreate(string firstname, string lastname, LSL_Vector position, LSL_Key cloneFrom) | 2134 | public LSL_Key osNpcCreate(string firstname, string lastname, LSL_Vector position, string notecard) |
2100 | { | 2135 | { |
2101 | CheckThreatLevel(ThreatLevel.High, "osNpcCreate"); | 2136 | CheckThreatLevel(ThreatLevel.High, "osNpcCreate"); |
2102 | //QueueUserWorkItem | ||
2103 | 2137 | ||
2104 | INPCModule module = World.RequestModuleInterface<INPCModule>(); | 2138 | INPCModule module = World.RequestModuleInterface<INPCModule>(); |
2105 | if (module != null) | 2139 | if (module != null) |
2106 | { | 2140 | { |
2141 | AvatarAppearance appearance = null; | ||
2142 | |||
2143 | UUID id; | ||
2144 | if (UUID.TryParse(notecard, out id)) | ||
2145 | { | ||
2146 | ScenePresence clonePresence = World.GetScenePresence(id); | ||
2147 | if (clonePresence != null) | ||
2148 | appearance = clonePresence.Appearance; | ||
2149 | } | ||
2150 | |||
2151 | if (appearance == null) | ||
2152 | { | ||
2153 | string appearanceSerialized = LoadNotecard(notecard); | ||
2154 | |||
2155 | if (appearanceSerialized != null) | ||
2156 | { | ||
2157 | OSDMap appearanceOsd = (OSDMap)OSDParser.DeserializeLLSDXml(appearanceSerialized); | ||
2158 | appearance = new AvatarAppearance(); | ||
2159 | appearance.Unpack(appearanceOsd); | ||
2160 | } | ||
2161 | } | ||
2162 | |||
2163 | if (appearance == null) | ||
2164 | return new LSL_Key(UUID.Zero.ToString()); | ||
2165 | |||
2107 | UUID x = module.CreateNPC(firstname, | 2166 | UUID x = module.CreateNPC(firstname, |
2108 | lastname, | 2167 | lastname, |
2109 | new Vector3((float) position.x, (float) position.y, (float) position.z), | 2168 | new Vector3((float) position.x, (float) position.y, (float) position.z), |
2110 | World, | 2169 | World, |
2111 | new UUID(cloneFrom)); | 2170 | appearance); |
2112 | 2171 | ||
2113 | return new LSL_Key(x.ToString()); | 2172 | return new LSL_Key(x.ToString()); |
2114 | } | 2173 | } |
2174 | |||
2175 | return new LSL_Key(UUID.Zero.ToString()); | ||
2176 | } | ||
2177 | |||
2178 | /// <summary> | ||
2179 | /// Save the current appearance of the NPC permanently to the named notecard. | ||
2180 | /// </summary> | ||
2181 | /// <param name="avatar"></param> | ||
2182 | /// <param name="notecard">The name of the notecard to which to save the appearance.</param> | ||
2183 | /// <returns>The asset ID of the notecard saved.</returns> | ||
2184 | public LSL_Key osNpcSaveAppearance(LSL_Key npc, string notecard) | ||
2185 | { | ||
2186 | CheckThreatLevel(ThreatLevel.High, "osNpcSaveAppearance"); | ||
2187 | |||
2188 | INPCModule npcModule = World.RequestModuleInterface<INPCModule>(); | ||
2189 | |||
2190 | if (npcModule != null) | ||
2191 | { | ||
2192 | UUID npcId; | ||
2193 | if (!UUID.TryParse(npc.m_string, out npcId)) | ||
2194 | return new LSL_Key(UUID.Zero.ToString()); | ||
2195 | |||
2196 | if (!npcModule.IsNPC(npcId, m_host.ParentGroup.Scene)) | ||
2197 | return new LSL_Key(UUID.Zero.ToString()); | ||
2198 | |||
2199 | return SaveAppearanceToNotecard(npcId, notecard); | ||
2200 | } | ||
2201 | |||
2115 | return new LSL_Key(UUID.Zero.ToString()); | 2202 | return new LSL_Key(UUID.Zero.ToString()); |
2116 | } | 2203 | } |
2117 | 2204 | ||
2205 | public void osNpcLoadAppearance(LSL_Key npc, string notecard) | ||
2206 | { | ||
2207 | CheckThreatLevel(ThreatLevel.High, "osNpcLoadAppearance"); | ||
2208 | |||
2209 | INPCModule npcModule = World.RequestModuleInterface<INPCModule>(); | ||
2210 | |||
2211 | if (npcModule != null) | ||
2212 | { | ||
2213 | UUID npcId; | ||
2214 | if (!UUID.TryParse(npc.m_string, out npcId)) | ||
2215 | return; | ||
2216 | |||
2217 | string appearanceSerialized = LoadNotecard(notecard); | ||
2218 | OSDMap appearanceOsd = (OSDMap)OSDParser.DeserializeLLSDXml(appearanceSerialized); | ||
2219 | // OSD a = OSDParser.DeserializeLLSDXml(appearanceSerialized); | ||
2220 | // Console.WriteLine("appearanceSerialized {0}", appearanceSerialized); | ||
2221 | // Console.WriteLine("a.Type {0}, a.ToString() {1}", a.Type, a); | ||
2222 | AvatarAppearance appearance = new AvatarAppearance(); | ||
2223 | appearance.Unpack(appearanceOsd); | ||
2224 | |||
2225 | npcModule.SetNPCAppearance(npcId, appearance, m_host.ParentGroup.Scene); | ||
2226 | } | ||
2227 | } | ||
2228 | |||
2229 | public LSL_Vector osNpcGetPos(LSL_Key npc) | ||
2230 | { | ||
2231 | CheckThreatLevel(ThreatLevel.High, "osNpcGetPos"); | ||
2232 | |||
2233 | INPCModule npcModule = World.RequestModuleInterface<INPCModule>(); | ||
2234 | if (npcModule != null) | ||
2235 | { | ||
2236 | UUID npcId; | ||
2237 | if (!UUID.TryParse(npc.m_string, out npcId)) | ||
2238 | return new LSL_Vector(0, 0, 0); | ||
2239 | |||
2240 | if (!npcModule.IsNPC(npcId, m_host.ParentGroup.Scene)) | ||
2241 | return new LSL_Vector(0, 0, 0); | ||
2242 | |||
2243 | Vector3 pos = World.GetScenePresence(npcId).AbsolutePosition; | ||
2244 | return new LSL_Vector(pos.X, pos.Y, pos.Z); | ||
2245 | } | ||
2246 | |||
2247 | return new LSL_Vector(0, 0, 0); | ||
2248 | } | ||
2249 | |||
2118 | public void osNpcMoveTo(LSL_Key npc, LSL_Vector position) | 2250 | public void osNpcMoveTo(LSL_Key npc, LSL_Vector position) |
2119 | { | 2251 | { |
2120 | CheckThreatLevel(ThreatLevel.High, "osNpcMoveTo"); | 2252 | CheckThreatLevel(ThreatLevel.High, "osNpcMoveTo"); |
@@ -2122,11 +2254,87 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2122 | INPCModule module = World.RequestModuleInterface<INPCModule>(); | 2254 | INPCModule module = World.RequestModuleInterface<INPCModule>(); |
2123 | if (module != null) | 2255 | if (module != null) |
2124 | { | 2256 | { |
2257 | UUID npcId; | ||
2258 | if (!UUID.TryParse(npc.m_string, out npcId)) | ||
2259 | return; | ||
2260 | |||
2125 | Vector3 pos = new Vector3((float) position.x, (float) position.y, (float) position.z); | 2261 | Vector3 pos = new Vector3((float) position.x, (float) position.y, (float) position.z); |
2126 | module.Autopilot(new UUID(npc.m_string), World, pos); | 2262 | module.MoveToTarget(npcId, World, pos, false, true); |
2127 | } | 2263 | } |
2128 | } | 2264 | } |
2129 | 2265 | ||
2266 | public void osNpcMoveToTarget(LSL_Key npc, LSL_Vector target, int options) | ||
2267 | { | ||
2268 | CheckThreatLevel(ThreatLevel.High, "osNpcMoveToTarget"); | ||
2269 | |||
2270 | INPCModule module = World.RequestModuleInterface<INPCModule>(); | ||
2271 | if (module != null) | ||
2272 | { | ||
2273 | UUID npcId; | ||
2274 | if (!UUID.TryParse(npc.m_string, out npcId)) | ||
2275 | return; | ||
2276 | |||
2277 | Vector3 pos = new Vector3((float)target.x, (float)target.y, (float)target.z); | ||
2278 | module.MoveToTarget( | ||
2279 | new UUID(npc.m_string), | ||
2280 | World, | ||
2281 | pos, | ||
2282 | (options & ScriptBaseClass.OS_NPC_NO_FLY) != 0, | ||
2283 | (options & ScriptBaseClass.OS_NPC_LAND_AT_TARGET) != 0); | ||
2284 | } | ||
2285 | } | ||
2286 | |||
2287 | public LSL_Rotation osNpcGetRot(LSL_Key npc) | ||
2288 | { | ||
2289 | CheckThreatLevel(ThreatLevel.High, "osNpcGetRot"); | ||
2290 | |||
2291 | INPCModule npcModule = World.RequestModuleInterface<INPCModule>(); | ||
2292 | if (npcModule != null) | ||
2293 | { | ||
2294 | UUID npcId; | ||
2295 | if (!UUID.TryParse(npc.m_string, out npcId)) | ||
2296 | return new LSL_Rotation(Quaternion.Identity.X, Quaternion.Identity.Y, Quaternion.Identity.Z, Quaternion.Identity.W); | ||
2297 | |||
2298 | if (!npcModule.IsNPC(npcId, m_host.ParentGroup.Scene)) | ||
2299 | return new LSL_Rotation(Quaternion.Identity.X, Quaternion.Identity.Y, Quaternion.Identity.Z, Quaternion.Identity.W); | ||
2300 | |||
2301 | ScenePresence sp = World.GetScenePresence(npcId); | ||
2302 | Quaternion rot = sp.Rotation; | ||
2303 | |||
2304 | return new LSL_Rotation(rot.X, rot.Y, rot.Z, rot.W); | ||
2305 | } | ||
2306 | |||
2307 | return new LSL_Rotation(Quaternion.Identity.X, Quaternion.Identity.Y, Quaternion.Identity.Z, Quaternion.Identity.W); | ||
2308 | } | ||
2309 | |||
2310 | public void osNpcSetRot(LSL_Key npc, LSL_Rotation rotation) | ||
2311 | { | ||
2312 | CheckThreatLevel(ThreatLevel.High, "osNpcSetRot"); | ||
2313 | |||
2314 | INPCModule npcModule = World.RequestModuleInterface<INPCModule>(); | ||
2315 | if (npcModule != null) | ||
2316 | { | ||
2317 | UUID npcId; | ||
2318 | if (!UUID.TryParse(npc.m_string, out npcId)) | ||
2319 | return; | ||
2320 | |||
2321 | if (!npcModule.IsNPC(npcId, m_host.ParentGroup.Scene)) | ||
2322 | return; | ||
2323 | |||
2324 | ScenePresence sp = World.GetScenePresence(npcId); | ||
2325 | sp.Rotation = LSL_Api.Rot2Quaternion(rotation); | ||
2326 | } | ||
2327 | } | ||
2328 | |||
2329 | public void osNpcStopMoveToTarget(LSL_Key npc) | ||
2330 | { | ||
2331 | CheckThreatLevel(ThreatLevel.VeryLow, "osNpcStopMoveTo"); | ||
2332 | |||
2333 | INPCModule module = World.RequestModuleInterface<INPCModule>(); | ||
2334 | if (module != null) | ||
2335 | module.StopMoveToTarget(new UUID(npc.m_string), World); | ||
2336 | } | ||
2337 | |||
2130 | public void osNpcSay(LSL_Key npc, string message) | 2338 | public void osNpcSay(LSL_Key npc, string message) |
2131 | { | 2339 | { |
2132 | CheckThreatLevel(ThreatLevel.High, "osNpcSay"); | 2340 | CheckThreatLevel(ThreatLevel.High, "osNpcSay"); |
@@ -2148,6 +2356,64 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2148 | module.DeleteNPC(new UUID(npc.m_string), World); | 2356 | module.DeleteNPC(new UUID(npc.m_string), World); |
2149 | } | 2357 | } |
2150 | } | 2358 | } |
2359 | |||
2360 | /// <summary> | ||
2361 | /// Save the current appearance of the script owner permanently to the named notecard. | ||
2362 | /// </summary> | ||
2363 | /// <param name="notecard">The name of the notecard to which to save the appearance.</param> | ||
2364 | /// <returns>The asset ID of the notecard saved.</returns> | ||
2365 | public LSL_Key osOwnerSaveAppearance(string notecard) | ||
2366 | { | ||
2367 | CheckThreatLevel(ThreatLevel.High, "osOwnerSaveAppearance"); | ||
2368 | |||
2369 | return SaveAppearanceToNotecard(m_host.OwnerID, notecard); | ||
2370 | } | ||
2371 | |||
2372 | public LSL_Key osAgentSaveAppearance(LSL_Key avatarId, string notecard) | ||
2373 | { | ||
2374 | CheckThreatLevel(ThreatLevel.VeryHigh, "osAgentSaveAppearance"); | ||
2375 | |||
2376 | return SaveAppearanceToNotecard(avatarId, notecard); | ||
2377 | } | ||
2378 | |||
2379 | protected LSL_Key SaveAppearanceToNotecard(ScenePresence sp, string notecard) | ||
2380 | { | ||
2381 | IAvatarFactory appearanceModule = World.RequestModuleInterface<IAvatarFactory>(); | ||
2382 | |||
2383 | if (appearanceModule != null) | ||
2384 | { | ||
2385 | appearanceModule.SaveBakedTextures(sp.UUID); | ||
2386 | OSDMap appearancePacked = sp.Appearance.Pack(); | ||
2387 | |||
2388 | TaskInventoryItem item | ||
2389 | = SaveNotecard(notecard, "Avatar Appearance", Util.GetFormattedXml(appearancePacked as OSD), true); | ||
2390 | |||
2391 | return new LSL_Key(item.AssetID.ToString()); | ||
2392 | } | ||
2393 | else | ||
2394 | { | ||
2395 | return new LSL_Key(UUID.Zero.ToString()); | ||
2396 | } | ||
2397 | } | ||
2398 | |||
2399 | protected LSL_Key SaveAppearanceToNotecard(UUID avatarId, string notecard) | ||
2400 | { | ||
2401 | ScenePresence sp = World.GetScenePresence(avatarId); | ||
2402 | |||
2403 | if (sp == null || sp.IsChildAgent) | ||
2404 | return new LSL_Key(UUID.Zero.ToString()); | ||
2405 | |||
2406 | return SaveAppearanceToNotecard(sp, notecard); | ||
2407 | } | ||
2408 | |||
2409 | protected LSL_Key SaveAppearanceToNotecard(LSL_Key rawAvatarId, string notecard) | ||
2410 | { | ||
2411 | UUID avatarId; | ||
2412 | if (!UUID.TryParse(rawAvatarId, out avatarId)) | ||
2413 | return new LSL_Key(UUID.Zero.ToString()); | ||
2414 | |||
2415 | return SaveAppearanceToNotecard(avatarId, notecard); | ||
2416 | } | ||
2151 | 2417 | ||
2152 | /// <summary> | 2418 | /// <summary> |
2153 | /// Get current region's map texture UUID | 2419 | /// Get current region's map texture UUID |
@@ -2357,10 +2623,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2357 | obj.Shape.ProjectionFocus = (float)focus; | 2623 | obj.Shape.ProjectionFocus = (float)focus; |
2358 | obj.Shape.ProjectionAmbiance = (float)amb; | 2624 | obj.Shape.ProjectionAmbiance = (float)amb; |
2359 | 2625 | ||
2360 | |||
2361 | obj.ParentGroup.HasGroupChanged = true; | 2626 | obj.ParentGroup.HasGroupChanged = true; |
2362 | obj.ScheduleFullUpdate(); | 2627 | obj.ScheduleFullUpdate(); |
2363 | |||
2364 | } | 2628 | } |
2365 | 2629 | ||
2366 | /// <summary> | 2630 | /// <summary> |
@@ -2385,6 +2649,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2385 | } | 2649 | } |
2386 | } | 2650 | } |
2387 | }); | 2651 | }); |
2652 | |||
2388 | return result; | 2653 | return result; |
2389 | } | 2654 | } |
2390 | 2655 | ||
@@ -2404,4 +2669,4 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2404 | return date.ToString("yyyy-MM-ddTHH:mm:ss.fffffffZ"); | 2669 | return date.ToString("yyyy-MM-ddTHH:mm:ss.fffffffZ"); |
2405 | } | 2670 | } |
2406 | } | 2671 | } |
2407 | } | 2672 | } \ No newline at end of file |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs index d695a0c..6de0773 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs | |||
@@ -304,12 +304,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
304 | 304 | ||
305 | // Quaternion q = SensePoint.RotationOffset; | 305 | // Quaternion q = SensePoint.RotationOffset; |
306 | Quaternion q = SensePoint.GetWorldRotation(); // non-attached prim Sensor *always* uses World rotation! | 306 | Quaternion q = SensePoint.GetWorldRotation(); // non-attached prim Sensor *always* uses World rotation! |
307 | if (SensePoint.ParentGroup.RootPart.IsAttachment) | 307 | if (SensePoint.ParentGroup.IsAttachment) |
308 | { | 308 | { |
309 | // In attachments, the sensor cone always orients with the | 309 | // In attachments, the sensor cone always orients with the |
310 | // avatar rotation. This may include a nonzero elevation if | 310 | // avatar rotation. This may include a nonzero elevation if |
311 | // in mouselook. | 311 | // in mouselook. |
312 | ScenePresence avatar = m_CmdManager.m_ScriptEngine.World.GetScenePresence(SensePoint.ParentGroup.RootPart.AttachedAvatar); | 312 | ScenePresence avatar = m_CmdManager.m_ScriptEngine.World.GetScenePresence(SensePoint.ParentGroup.AttachedAvatar); |
313 | fromRegionPos = avatar.AbsolutePosition; | 313 | fromRegionPos = avatar.AbsolutePosition; |
314 | q = avatar.Rotation; | 314 | q = avatar.Rotation; |
315 | } | 315 | } |
@@ -354,7 +354,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
354 | objtype = 0; | 354 | objtype = 0; |
355 | 355 | ||
356 | part = ((SceneObjectGroup)ent).RootPart; | 356 | part = ((SceneObjectGroup)ent).RootPart; |
357 | if (part.AttachmentPoint != 0) // Attached so ignore | 357 | if (part.ParentGroup.AttachmentPoint != 0) // Attached so ignore |
358 | continue; | 358 | continue; |
359 | 359 | ||
360 | if (part.Inventory.ContainsScripts()) | 360 | if (part.Inventory.ContainsScripts()) |
@@ -425,13 +425,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
425 | Vector3 fromRegionPos = SensePoint.AbsolutePosition; | 425 | Vector3 fromRegionPos = SensePoint.AbsolutePosition; |
426 | 426 | ||
427 | Quaternion q = SensePoint.RotationOffset; | 427 | Quaternion q = SensePoint.RotationOffset; |
428 | if (SensePoint.ParentGroup.RootPart.IsAttachment) | 428 | if (SensePoint.ParentGroup.IsAttachment) |
429 | { | 429 | { |
430 | // In attachments, the sensor cone always orients with the | 430 | // In attachments, the sensor cone always orients with the |
431 | // avatar rotation. This may include a nonzero elevation if | 431 | // avatar rotation. This may include a nonzero elevation if |
432 | // in mouselook. | 432 | // in mouselook. |
433 | 433 | ScenePresence avatar = m_CmdManager.m_ScriptEngine.World.GetScenePresence(SensePoint.ParentGroup.AttachedAvatar); | |
434 | ScenePresence avatar = m_CmdManager.m_ScriptEngine.World.GetScenePresence(SensePoint.ParentGroup.RootPart.AttachedAvatar); | ||
435 | fromRegionPos = avatar.AbsolutePosition; | 434 | fromRegionPos = avatar.AbsolutePosition; |
436 | q = avatar.Rotation; | 435 | q = avatar.Rotation; |
437 | } | 436 | } |
@@ -439,7 +438,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
439 | LSL_Types.Quaternion r = new LSL_Types.Quaternion(q.X, q.Y, q.Z, q.W); | 438 | LSL_Types.Quaternion r = new LSL_Types.Quaternion(q.X, q.Y, q.Z, q.W); |
440 | LSL_Types.Vector3 forward_dir = (new LSL_Types.Vector3(1, 0, 0) * r); | 439 | LSL_Types.Vector3 forward_dir = (new LSL_Types.Vector3(1, 0, 0) * r); |
441 | double mag_fwd = LSL_Types.Vector3.Mag(forward_dir); | 440 | double mag_fwd = LSL_Types.Vector3.Mag(forward_dir); |
442 | bool attached = (SensePoint.AttachmentPoint != 0); | 441 | bool attached = (SensePoint.ParentGroup.AttachmentPoint != 0); |
443 | Vector3 toRegionPos; | 442 | Vector3 toRegionPos; |
444 | double dis; | 443 | double dis; |
445 | 444 | ||
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs index ce13d6b..7c388fe 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs | |||
@@ -60,6 +60,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces | |||
60 | LSL_String llBase64ToString(string str); | 60 | LSL_String llBase64ToString(string str); |
61 | void llBreakAllLinks(); | 61 | void llBreakAllLinks(); |
62 | void llBreakLink(int linknum); | 62 | void llBreakLink(int linknum); |
63 | LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options); | ||
63 | LSL_Integer llCeil(double f); | 64 | LSL_Integer llCeil(double f); |
64 | void llClearCameraParams(); | 65 | void llClearCameraParams(); |
65 | LSL_Integer llClearPrimMedia(LSL_Integer face); | 66 | LSL_Integer llClearPrimMedia(LSL_Integer face); |
@@ -271,6 +272,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces | |||
271 | void llPushObject(string target, LSL_Vector impulse, LSL_Vector ang_impulse, int local); | 272 | void llPushObject(string target, LSL_Vector impulse, LSL_Vector ang_impulse, int local); |
272 | void llRefreshPrimURL(); | 273 | void llRefreshPrimURL(); |
273 | void llRegionSay(int channelID, string text); | 274 | void llRegionSay(int channelID, string text); |
275 | void llRegionSayTo(string target, int channelID, string text); | ||
274 | void llReleaseCamera(string avatar); | 276 | void llReleaseCamera(string avatar); |
275 | void llReleaseControls(); | 277 | void llReleaseControls(); |
276 | void llReleaseURL(string url); | 278 | void llReleaseURL(string url); |
@@ -405,7 +407,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces | |||
405 | LSL_String llXorBase64StringsCorrect(string str1, string str2); | 407 | LSL_String llXorBase64StringsCorrect(string str1, string str2); |
406 | LSL_Integer llGetLinkNumberOfSides(LSL_Integer link); | 408 | LSL_Integer llGetLinkNumberOfSides(LSL_Integer link); |
407 | 409 | ||
408 | void SetPrimitiveParamsEx(LSL_Key prim, LSL_List rules); | 410 | void SetPrimitiveParamsEx(LSL_Key prim, LSL_List rules); |
409 | LSL_List GetLinkPrimitiveParamsEx(LSL_Key prim, LSL_List rules); | 411 | LSL_List GetLinkPrimitiveParamsEx(LSL_Key prim, LSL_List rules); |
410 | } | 412 | } |
411 | } | 413 | } |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs index 5a809e6..5ddba60 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs | |||
@@ -168,12 +168,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces | |||
168 | 168 | ||
169 | LSL_List osGetLinkPrimitiveParams(int linknumber, LSL_List rules); | 169 | LSL_List osGetLinkPrimitiveParams(int linknumber, LSL_List rules); |
170 | 170 | ||
171 | 171 | key osNpcCreate(string user, string name, vector position, string notecard); | |
172 | key osNpcCreate(string user, string name, vector position, key cloneFrom); | 172 | LSL_Key osNpcSaveAppearance(key npc, string notecard); |
173 | void osNpcLoadAppearance(key npc, string notecard); | ||
174 | vector osNpcGetPos(key npc); | ||
173 | void osNpcMoveTo(key npc, vector position); | 175 | void osNpcMoveTo(key npc, vector position); |
176 | void osNpcMoveToTarget(key npc, vector target, int options); | ||
177 | rotation osNpcGetRot(key npc); | ||
178 | void osNpcSetRot(LSL_Key npc, rotation rot); | ||
179 | void osNpcStopMoveToTarget(LSL_Key npc); | ||
174 | void osNpcSay(key npc, string message); | 180 | void osNpcSay(key npc, string message); |
175 | void osNpcRemove(key npc); | 181 | void osNpcRemove(key npc); |
176 | 182 | ||
183 | LSL_Key osOwnerSaveAppearance(string notecard); | ||
184 | LSL_Key osAgentSaveAppearance(key agentId, string notecard); | ||
185 | |||
177 | key osGetMapTexture(); | 186 | key osGetMapTexture(); |
178 | key osGetRegionMapTexture(string regionName); | 187 | key osGetRegionMapTexture(string regionName); |
179 | LSL_List osGetRegionStats(); | 188 | LSL_List osGetRegionStats(); |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs index 5f94ff5..59eaccb 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs | |||
@@ -594,7 +594,28 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase | |||
594 | public const int STATS_ACTIVE_SCRIPTS = 19; | 594 | public const int STATS_ACTIVE_SCRIPTS = 19; |
595 | public const int STATS_SCRIPT_LPS = 20; | 595 | public const int STATS_SCRIPT_LPS = 20; |
596 | 596 | ||
597 | // Constants for osNpc* functions | ||
598 | public const int OS_NPC_FLY = 0; | ||
599 | public const int OS_NPC_NO_FLY = 1; | ||
600 | public const int OS_NPC_LAND_AT_TARGET = 2; | ||
601 | |||
597 | public const string URL_REQUEST_GRANTED = "URL_REQUEST_GRANTED"; | 602 | public const string URL_REQUEST_GRANTED = "URL_REQUEST_GRANTED"; |
598 | public const string URL_REQUEST_DENIED = "URL_REQUEST_DENIED"; | 603 | public const string URL_REQUEST_DENIED = "URL_REQUEST_DENIED"; |
604 | |||
605 | public static readonly LSLInteger RC_REJECT_TYPES = 2; | ||
606 | public static readonly LSLInteger RC_DATA_FLAGS = 4; | ||
607 | public static readonly LSLInteger RC_MAX_HITS = 8; | ||
608 | public static readonly LSLInteger RC_DETECT_PHANTOM = 16; | ||
609 | |||
610 | public static readonly LSLInteger RC_REJECT_AGENTS = 2; | ||
611 | public static readonly LSLInteger RC_REJECT_PHYSICAL = 4; | ||
612 | public static readonly LSLInteger RC_REJECT_NONPHYSICAL = 8; | ||
613 | public static readonly LSLInteger RC_REJECT_LAND = 16; | ||
614 | |||
615 | public static readonly LSLInteger RC_GET_NORMAL = 2; | ||
616 | public static readonly LSLInteger RC_GET_ROOT_KEY = 4; | ||
617 | public static readonly LSLInteger RC_GET_LINK_NUM = 8; | ||
618 | |||
619 | public static readonly LSLInteger RCERR_CAST_TIME_EXCEEDED = 1; | ||
599 | } | 620 | } |
600 | } | 621 | } |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs index 7d7e54e..ca54862 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs | |||
@@ -1206,6 +1206,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase | |||
1206 | m_LSL_Functions.llRegionSay(channelID, text); | 1206 | m_LSL_Functions.llRegionSay(channelID, text); |
1207 | } | 1207 | } |
1208 | 1208 | ||
1209 | public void llRegionSayTo(string key, int channelID, string text) | ||
1210 | { | ||
1211 | m_LSL_Functions.llRegionSayTo(key, channelID, text); | ||
1212 | } | ||
1213 | |||
1209 | public void llReleaseCamera(string avatar) | 1214 | public void llReleaseCamera(string avatar) |
1210 | { | 1215 | { |
1211 | m_LSL_Functions.llReleaseCamera(avatar); | 1216 | m_LSL_Functions.llReleaseCamera(avatar); |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs index 7c59098..bbc8cc6 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs | |||
@@ -483,11 +483,46 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase | |||
483 | return m_OSSL_Functions.osNpcCreate(user, name, position, cloneFrom); | 483 | return m_OSSL_Functions.osNpcCreate(user, name, position, cloneFrom); |
484 | } | 484 | } |
485 | 485 | ||
486 | public key osNpcSaveAppearance(key npc, string notecard) | ||
487 | { | ||
488 | return m_OSSL_Functions.osNpcSaveAppearance(npc, notecard); | ||
489 | } | ||
490 | |||
491 | public void osNpcLoadAppearance(key npc, string notecard) | ||
492 | { | ||
493 | m_OSSL_Functions.osNpcLoadAppearance(npc, notecard); | ||
494 | } | ||
495 | |||
496 | public vector osNpcGetPos(LSL_Key npc) | ||
497 | { | ||
498 | return m_OSSL_Functions.osNpcGetPos(npc); | ||
499 | } | ||
500 | |||
486 | public void osNpcMoveTo(key npc, vector position) | 501 | public void osNpcMoveTo(key npc, vector position) |
487 | { | 502 | { |
488 | m_OSSL_Functions.osNpcMoveTo(npc, position); | 503 | m_OSSL_Functions.osNpcMoveTo(npc, position); |
489 | } | 504 | } |
490 | 505 | ||
506 | public void osNpcMoveToTarget(key npc, vector target, int options) | ||
507 | { | ||
508 | m_OSSL_Functions.osNpcMoveToTarget(npc, target, options); | ||
509 | } | ||
510 | |||
511 | public rotation osNpcGetRot(key npc) | ||
512 | { | ||
513 | return m_OSSL_Functions.osNpcGetRot(npc); | ||
514 | } | ||
515 | |||
516 | public void osNpcSetRot(key npc, rotation rot) | ||
517 | { | ||
518 | m_OSSL_Functions.osNpcSetRot(npc, rot); | ||
519 | } | ||
520 | |||
521 | public void osNpcStopMoveToTarget(LSL_Key npc) | ||
522 | { | ||
523 | m_OSSL_Functions.osNpcStopMoveToTarget(npc); | ||
524 | } | ||
525 | |||
491 | public void osNpcSay(key npc, string message) | 526 | public void osNpcSay(key npc, string message) |
492 | { | 527 | { |
493 | m_OSSL_Functions.osNpcSay(npc, message); | 528 | m_OSSL_Functions.osNpcSay(npc, message); |
@@ -498,6 +533,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase | |||
498 | m_OSSL_Functions.osNpcRemove(npc); | 533 | m_OSSL_Functions.osNpcRemove(npc); |
499 | } | 534 | } |
500 | 535 | ||
536 | public LSL_Key osOwnerSaveAppearance(string notecard) | ||
537 | { | ||
538 | return m_OSSL_Functions.osOwnerSaveAppearance(notecard); | ||
539 | } | ||
540 | |||
541 | public LSL_Key osAgentSaveAppearance(LSL_Key agentId, string notecard) | ||
542 | { | ||
543 | return m_OSSL_Functions.osAgentSaveAppearance(agentId, notecard); | ||
544 | } | ||
545 | |||
501 | public OSSLPrim Prim; | 546 | public OSSLPrim Prim; |
502 | 547 | ||
503 | [Serializable] | 548 | [Serializable] |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Helpers.cs b/OpenSim/Region/ScriptEngine/Shared/Helpers.cs index e9edf6c..7e7e278 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Helpers.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Helpers.cs | |||
@@ -205,7 +205,7 @@ namespace OpenSim.Region.ScriptEngine.Shared | |||
205 | return; | 205 | return; |
206 | } | 206 | } |
207 | 207 | ||
208 | part=part.ParentGroup.RootPart; // We detect objects only | 208 | part = part.ParentGroup.RootPart; // We detect objects only |
209 | 209 | ||
210 | LinkNum = 0; // Not relevant | 210 | LinkNum = 0; // Not relevant |
211 | 211 | ||
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index 9548253..cf25189 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs | |||
@@ -234,7 +234,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
234 | m_MaxScriptQueue = maxScriptQueue; | 234 | m_MaxScriptQueue = maxScriptQueue; |
235 | m_stateSource = stateSource; | 235 | m_stateSource = stateSource; |
236 | m_postOnRez = postOnRez; | 236 | m_postOnRez = postOnRez; |
237 | m_AttachedAvatar = part.AttachedAvatar; | 237 | m_AttachedAvatar = part.ParentGroup.AttachedAvatar; |
238 | m_RegionID = part.ParentGroup.Scene.RegionInfo.RegionID; | 238 | m_RegionID = part.ParentGroup.Scene.RegionInfo.RegionID; |
239 | 239 | ||
240 | if (part != null) | 240 | if (part != null) |
@@ -772,13 +772,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
772 | else if ((e is TargetInvocationException) && (e.InnerException is SelfDeleteException)) | 772 | else if ((e is TargetInvocationException) && (e.InnerException is SelfDeleteException)) |
773 | { | 773 | { |
774 | m_InSelfDelete = true; | 774 | m_InSelfDelete = true; |
775 | if (part != null && part.ParentGroup != null) | 775 | if (part != null) |
776 | m_Engine.World.DeleteSceneObject(part.ParentGroup, false); | 776 | m_Engine.World.DeleteSceneObject(part.ParentGroup, false); |
777 | } | 777 | } |
778 | else if ((e is TargetInvocationException) && (e.InnerException is ScriptDeleteException)) | 778 | else if ((e is TargetInvocationException) && (e.InnerException is ScriptDeleteException)) |
779 | { | 779 | { |
780 | m_InSelfDelete = true; | 780 | m_InSelfDelete = true; |
781 | if (part != null && part.ParentGroup != null) | 781 | if (part != null) |
782 | part.Inventory.RemoveInventoryItem(m_ItemID); | 782 | part.Inventory.RemoveInventoryItem(m_ItemID); |
783 | } | 783 | } |
784 | } | 784 | } |
diff --git a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs index 6bfee91..9e6752c 100644 --- a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs +++ b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs | |||
@@ -1373,7 +1373,9 @@ namespace OpenSim.Region.ScriptEngine.Shared | |||
1373 | public struct LSLString | 1373 | public struct LSLString |
1374 | { | 1374 | { |
1375 | public string m_string; | 1375 | public string m_string; |
1376 | |||
1376 | #region Constructors | 1377 | #region Constructors |
1378 | |||
1377 | public LSLString(string s) | 1379 | public LSLString(string s) |
1378 | { | 1380 | { |
1379 | m_string = s; | 1381 | m_string = s; |
@@ -1381,22 +1383,24 @@ namespace OpenSim.Region.ScriptEngine.Shared | |||
1381 | 1383 | ||
1382 | public LSLString(double d) | 1384 | public LSLString(double d) |
1383 | { | 1385 | { |
1384 | string s=String.Format(Culture.FormatProvider, "{0:0.000000}", d); | 1386 | string s = String.Format(Culture.FormatProvider, "{0:0.000000}", d); |
1385 | m_string=s; | 1387 | m_string = s; |
1386 | } | 1388 | } |
1387 | 1389 | ||
1388 | public LSLString(LSLFloat f) | 1390 | public LSLString(LSLFloat f) |
1389 | { | 1391 | { |
1390 | string s = String.Format(Culture.FormatProvider, "{0:0.000000}", f.value); | 1392 | string s = String.Format(Culture.FormatProvider, "{0:0.000000}", f.value); |
1391 | m_string=s; | 1393 | m_string = s; |
1392 | } | 1394 | } |
1393 | 1395 | ||
1394 | public LSLString(LSLInteger i) | 1396 | public LSLString(int i) |
1395 | { | 1397 | { |
1396 | string s = String.Format("{0}", i); | 1398 | string s = String.Format("{0}", i); |
1397 | m_string = s; | 1399 | m_string = s; |
1398 | } | 1400 | } |
1399 | 1401 | ||
1402 | public LSLString(LSLInteger i) : this(i.value) {} | ||
1403 | |||
1400 | #endregion | 1404 | #endregion |
1401 | 1405 | ||
1402 | #region Operators | 1406 | #region Operators |
@@ -1463,6 +1467,11 @@ namespace OpenSim.Region.ScriptEngine.Shared | |||
1463 | { | 1467 | { |
1464 | return new LSLString(d); | 1468 | return new LSLString(d); |
1465 | } | 1469 | } |
1470 | |||
1471 | static public explicit operator LSLString(int i) | ||
1472 | { | ||
1473 | return new LSLString(i); | ||
1474 | } | ||
1466 | 1475 | ||
1467 | public static explicit operator LSLString(LSLFloat f) | 1476 | public static explicit operator LSLString(LSLFloat f) |
1468 | { | 1477 | { |
@@ -1736,7 +1745,17 @@ namespace OpenSim.Region.ScriptEngine.Shared | |||
1736 | public override bool Equals(Object o) | 1745 | public override bool Equals(Object o) |
1737 | { | 1746 | { |
1738 | if (!(o is LSLInteger)) | 1747 | if (!(o is LSLInteger)) |
1739 | return false; | 1748 | { |
1749 | if (o is int) | ||
1750 | { | ||
1751 | return value == (int)o; | ||
1752 | } | ||
1753 | else | ||
1754 | { | ||
1755 | return false; | ||
1756 | } | ||
1757 | } | ||
1758 | |||
1740 | return value == ((LSLInteger)o).value; | 1759 | return value == ((LSLInteger)o).value; |
1741 | } | 1760 | } |
1742 | 1761 | ||
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs index 80b60a4..8cd1e84 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs | |||
@@ -27,11 +27,13 @@ | |||
27 | 27 | ||
28 | using System.Collections.Generic; | 28 | using System.Collections.Generic; |
29 | using NUnit.Framework; | 29 | using NUnit.Framework; |
30 | using OpenSim.Framework; | ||
30 | using OpenSim.Tests.Common; | 31 | using OpenSim.Tests.Common; |
31 | using OpenSim.Region.ScriptEngine.Shared; | 32 | using OpenSim.Region.ScriptEngine.Shared; |
32 | using OpenSim.Region.Framework.Scenes; | 33 | using OpenSim.Region.Framework.Scenes; |
33 | using Nini.Config; | 34 | using Nini.Config; |
34 | using OpenSim.Region.ScriptEngine.Shared.Api; | 35 | using OpenSim.Region.ScriptEngine.Shared.Api; |
36 | using OpenSim.Region.ScriptEngine.Shared.ScriptBase; | ||
35 | using OpenMetaverse; | 37 | using OpenMetaverse; |
36 | using System; | 38 | using System; |
37 | using OpenSim.Tests.Common.Mock; | 39 | using OpenSim.Tests.Common.Mock; |
@@ -47,6 +49,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests | |||
47 | 49 | ||
48 | private const double ANGLE_ACCURACY_IN_RADIANS = 1E-6; | 50 | private const double ANGLE_ACCURACY_IN_RADIANS = 1E-6; |
49 | private const double VECTOR_COMPONENT_ACCURACY = 0.0000005d; | 51 | private const double VECTOR_COMPONENT_ACCURACY = 0.0000005d; |
52 | private const double FLOAT_ACCURACY = 0.00005d; | ||
50 | private LSL_Api m_lslApi; | 53 | private LSL_Api m_lslApi; |
51 | 54 | ||
52 | [SetUp] | 55 | [SetUp] |
@@ -57,8 +60,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests | |||
57 | IConfig config = initConfigSource.AddConfig("XEngine"); | 60 | IConfig config = initConfigSource.AddConfig("XEngine"); |
58 | config.Set("Enabled", "true"); | 61 | config.Set("Enabled", "true"); |
59 | 62 | ||
60 | Scene scene = SceneSetupHelpers.SetupScene(); | 63 | Scene scene = SceneHelpers.SetupScene(); |
61 | SceneObjectPart part = SceneSetupHelpers.AddSceneObject(scene); | 64 | SceneObjectPart part = SceneHelpers.AddSceneObject(scene); |
62 | 65 | ||
63 | XEngine.XEngine engine = new XEngine.XEngine(); | 66 | XEngine.XEngine engine = new XEngine.XEngine(); |
64 | engine.Initialise(initConfigSource); | 67 | engine.Initialise(initConfigSource); |
@@ -166,6 +169,231 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests | |||
166 | } | 169 | } |
167 | 170 | ||
168 | [Test] | 171 | [Test] |
172 | // llSetPrimitiveParams and llGetPrimitiveParams test. | ||
173 | public void TestllSetPrimitiveParams() | ||
174 | { | ||
175 | // Create Prim1. | ||
176 | Scene scene = SceneHelpers.SetupScene(); | ||
177 | string obj1Name = "Prim1"; | ||
178 | UUID objUuid = new UUID("00000000-0000-0000-0000-000000000001"); | ||
179 | SceneObjectPart part1 = | ||
180 | new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, | ||
181 | Vector3.Zero, Quaternion.Identity, | ||
182 | Vector3.Zero) { Name = obj1Name, UUID = objUuid }; | ||
183 | Assert.That(scene.AddNewSceneObject(new SceneObjectGroup(part1), false), Is.True); | ||
184 | |||
185 | // Note that prim hollow check is passed with the other prim params in order to allow the | ||
186 | // specification of a different check value from the prim param. A cylinder, prism, sphere, | ||
187 | // torus or ring, with a hole shape of square, is limited to a hollow of 70%. Test 5 below | ||
188 | // specifies a value of 95% and checks to see if 70% was properly returned. | ||
189 | |||
190 | // Test a sphere. | ||
191 | CheckllSetPrimitiveParams( | ||
192 | "test 1", // Prim test identification string | ||
193 | new LSL_Types.Vector3(6.0d, 9.9d, 9.9d), // Prim size | ||
194 | ScriptBaseClass.PRIM_TYPE_SPHERE, // Prim type | ||
195 | ScriptBaseClass.PRIM_HOLE_DEFAULT, // Prim hole type | ||
196 | new LSL_Types.Vector3(0.0d, 0.075d, 0.0d), // Prim cut | ||
197 | 0.80d, // Prim hollow | ||
198 | new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim twist | ||
199 | new LSL_Types.Vector3(0.32d, 0.76d, 0.0d), // Prim dimple | ||
200 | 0.80d); // Prim hollow check | ||
201 | |||
202 | // Test a prism. | ||
203 | CheckllSetPrimitiveParams( | ||
204 | "test 2", // Prim test identification string | ||
205 | new LSL_Types.Vector3(3.5d, 3.5d, 3.5d), // Prim size | ||
206 | ScriptBaseClass.PRIM_TYPE_PRISM, // Prim type | ||
207 | ScriptBaseClass.PRIM_HOLE_CIRCLE, // Prim hole type | ||
208 | new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim cut | ||
209 | 0.90d, // Prim hollow | ||
210 | new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim twist | ||
211 | new LSL_Types.Vector3(2.0d, 1.0d, 0.0d), // Prim taper | ||
212 | new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim shear | ||
213 | 0.90d); // Prim hollow check | ||
214 | |||
215 | // Test a box. | ||
216 | CheckllSetPrimitiveParams( | ||
217 | "test 3", // Prim test identification string | ||
218 | new LSL_Types.Vector3(3.5d, 3.5d, 3.5d), // Prim size | ||
219 | ScriptBaseClass.PRIM_TYPE_BOX, // Prim type | ||
220 | ScriptBaseClass.PRIM_HOLE_TRIANGLE, // Prim hole type | ||
221 | new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim cut | ||
222 | 0.95d, // Prim hollow | ||
223 | new LSL_Types.Vector3(1.0d, 0.0d, 0.0d), // Prim twist | ||
224 | new LSL_Types.Vector3(1.0d, 1.0d, 0.0d), // Prim taper | ||
225 | new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim shear | ||
226 | 0.95d); // Prim hollow check | ||
227 | |||
228 | // Test a tube. | ||
229 | CheckllSetPrimitiveParams( | ||
230 | "test 4", // Prim test identification string | ||
231 | new LSL_Types.Vector3(4.2d, 4.2d, 4.2d), // Prim size | ||
232 | ScriptBaseClass.PRIM_TYPE_TUBE, // Prim type | ||
233 | ScriptBaseClass.PRIM_HOLE_SQUARE, // Prim hole type | ||
234 | new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim cut | ||
235 | 0.00d, // Prim hollow | ||
236 | new LSL_Types.Vector3(1.0d, -1.0d, 0.0d), // Prim twist | ||
237 | new LSL_Types.Vector3(1.0d, 0.5d, 0.0d), // Prim hole size | ||
238 | new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim shear | ||
239 | new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim profile cut | ||
240 | new LSL_Types.Vector3(-1.0d, 1.0d, 0.0d), // Prim taper | ||
241 | 1.0d, // Prim revolutions | ||
242 | 1.0d, // Prim radius | ||
243 | 0.0d, // Prim skew | ||
244 | 0.00d); // Prim hollow check | ||
245 | |||
246 | // Test a prism. | ||
247 | CheckllSetPrimitiveParams( | ||
248 | "test 5", // Prim test identification string | ||
249 | new LSL_Types.Vector3(3.5d, 3.5d, 3.5d), // Prim size | ||
250 | ScriptBaseClass.PRIM_TYPE_PRISM, // Prim type | ||
251 | ScriptBaseClass.PRIM_HOLE_SQUARE, // Prim hole type | ||
252 | new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim cut | ||
253 | 0.95d, // Prim hollow | ||
254 | new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim twist | ||
255 | new LSL_Types.Vector3(2.0d, 1.0d, 0.0d), // Prim taper | ||
256 | new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim shear | ||
257 | 0.70d); // Prim hollow check | ||
258 | |||
259 | // Test a sculpted prim. | ||
260 | CheckllSetPrimitiveParams( | ||
261 | "test 6", // Prim test identification string | ||
262 | new LSL_Types.Vector3(2.0d, 2.0d, 2.0d), // Prim size | ||
263 | ScriptBaseClass.PRIM_TYPE_SCULPT, // Prim type | ||
264 | "be293869-d0d9-0a69-5989-ad27f1946fd4", // Prim map | ||
265 | ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE); // Prim sculpt type | ||
266 | } | ||
267 | |||
268 | // Set prim params for a box, cylinder or prism and check results. | ||
269 | public void CheckllSetPrimitiveParams(string primTest, | ||
270 | LSL_Types.Vector3 primSize, int primType, int primHoleType, LSL_Types.Vector3 primCut, | ||
271 | double primHollow, LSL_Types.Vector3 primTwist, LSL_Types.Vector3 primTaper, LSL_Types.Vector3 primShear, | ||
272 | double primHollowCheck) | ||
273 | { | ||
274 | // Set the prim params. | ||
275 | m_lslApi.llSetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, primSize, | ||
276 | ScriptBaseClass.PRIM_TYPE, primType, primHoleType, | ||
277 | primCut, primHollow, primTwist, primTaper, primShear)); | ||
278 | |||
279 | // Get params for prim to validate settings. | ||
280 | LSL_Types.list primParams = | ||
281 | m_lslApi.llGetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, ScriptBaseClass.PRIM_TYPE)); | ||
282 | |||
283 | // Validate settings. | ||
284 | CheckllSetPrimitiveParamsVector(primSize, m_lslApi.llList2Vector(primParams, 0), primTest + " prim size"); | ||
285 | Assert.AreEqual(primType, m_lslApi.llList2Integer(primParams, 1), | ||
286 | "TestllSetPrimitiveParams " + primTest + " prim type check fail"); | ||
287 | Assert.AreEqual(primHoleType, m_lslApi.llList2Integer(primParams, 2), | ||
288 | "TestllSetPrimitiveParams " + primTest + " prim hole default check fail"); | ||
289 | CheckllSetPrimitiveParamsVector(primCut, m_lslApi.llList2Vector(primParams, 3), primTest + " prim cut"); | ||
290 | Assert.AreEqual(primHollowCheck, m_lslApi.llList2Float(primParams, 4), FLOAT_ACCURACY, | ||
291 | "TestllSetPrimitiveParams " + primTest + " prim hollow check fail"); | ||
292 | CheckllSetPrimitiveParamsVector(primTwist, m_lslApi.llList2Vector(primParams, 5), primTest + " prim twist"); | ||
293 | CheckllSetPrimitiveParamsVector(primTaper, m_lslApi.llList2Vector(primParams, 6), primTest + " prim taper"); | ||
294 | CheckllSetPrimitiveParamsVector(primShear, m_lslApi.llList2Vector(primParams, 7), primTest + " prim shear"); | ||
295 | } | ||
296 | |||
297 | // Set prim params for a sphere and check results. | ||
298 | public void CheckllSetPrimitiveParams(string primTest, | ||
299 | LSL_Types.Vector3 primSize, int primType, int primHoleType, LSL_Types.Vector3 primCut, | ||
300 | double primHollow, LSL_Types.Vector3 primTwist, LSL_Types.Vector3 primDimple, double primHollowCheck) | ||
301 | { | ||
302 | // Set the prim params. | ||
303 | m_lslApi.llSetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, primSize, | ||
304 | ScriptBaseClass.PRIM_TYPE, primType, primHoleType, | ||
305 | primCut, primHollow, primTwist, primDimple)); | ||
306 | |||
307 | // Get params for prim to validate settings. | ||
308 | LSL_Types.list primParams = | ||
309 | m_lslApi.llGetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, ScriptBaseClass.PRIM_TYPE)); | ||
310 | |||
311 | // Validate settings. | ||
312 | CheckllSetPrimitiveParamsVector(primSize, m_lslApi.llList2Vector(primParams, 0), primTest + " prim size"); | ||
313 | Assert.AreEqual(primType, m_lslApi.llList2Integer(primParams, 1), | ||
314 | "TestllSetPrimitiveParams " + primTest + " prim type check fail"); | ||
315 | Assert.AreEqual(primHoleType, m_lslApi.llList2Integer(primParams, 2), | ||
316 | "TestllSetPrimitiveParams " + primTest + " prim hole default check fail"); | ||
317 | CheckllSetPrimitiveParamsVector(primCut, m_lslApi.llList2Vector(primParams, 3), primTest + " prim cut"); | ||
318 | Assert.AreEqual(primHollowCheck, m_lslApi.llList2Float(primParams, 4), FLOAT_ACCURACY, | ||
319 | "TestllSetPrimitiveParams " + primTest + " prim hollow check fail"); | ||
320 | CheckllSetPrimitiveParamsVector(primTwist, m_lslApi.llList2Vector(primParams, 5), primTest + " prim twist"); | ||
321 | CheckllSetPrimitiveParamsVector(primDimple, m_lslApi.llList2Vector(primParams, 6), primTest + " prim dimple"); | ||
322 | } | ||
323 | |||
324 | // Set prim params for a torus, tube or ring and check results. | ||
325 | public void CheckllSetPrimitiveParams(string primTest, | ||
326 | LSL_Types.Vector3 primSize, int primType, int primHoleType, LSL_Types.Vector3 primCut, | ||
327 | double primHollow, LSL_Types.Vector3 primTwist, LSL_Types.Vector3 primHoleSize, | ||
328 | LSL_Types.Vector3 primShear, LSL_Types.Vector3 primProfCut, LSL_Types.Vector3 primTaper, | ||
329 | double primRev, double primRadius, double primSkew, double primHollowCheck) | ||
330 | { | ||
331 | // Set the prim params. | ||
332 | m_lslApi.llSetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, primSize, | ||
333 | ScriptBaseClass.PRIM_TYPE, primType, primHoleType, | ||
334 | primCut, primHollow, primTwist, primHoleSize, primShear, primProfCut, | ||
335 | primTaper, primRev, primRadius, primSkew)); | ||
336 | |||
337 | // Get params for prim to validate settings. | ||
338 | LSL_Types.list primParams = | ||
339 | m_lslApi.llGetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, ScriptBaseClass.PRIM_TYPE)); | ||
340 | |||
341 | // Valdate settings. | ||
342 | CheckllSetPrimitiveParamsVector(primSize, m_lslApi.llList2Vector(primParams, 0), primTest + " prim size"); | ||
343 | Assert.AreEqual(primType, m_lslApi.llList2Integer(primParams, 1), | ||
344 | "TestllSetPrimitiveParams " + primTest + " prim type check fail"); | ||
345 | Assert.AreEqual(primHoleType, m_lslApi.llList2Integer(primParams, 2), | ||
346 | "TestllSetPrimitiveParams " + primTest + " prim hole default check fail"); | ||
347 | CheckllSetPrimitiveParamsVector(primCut, m_lslApi.llList2Vector(primParams, 3), primTest + " prim cut"); | ||
348 | Assert.AreEqual(primHollowCheck, m_lslApi.llList2Float(primParams, 4), FLOAT_ACCURACY, | ||
349 | "TestllSetPrimitiveParams " + primTest + " prim hollow check fail"); | ||
350 | CheckllSetPrimitiveParamsVector(primTwist, m_lslApi.llList2Vector(primParams, 5), primTest + " prim twist"); | ||
351 | CheckllSetPrimitiveParamsVector(primHoleSize, m_lslApi.llList2Vector(primParams, 6), primTest + " prim hole size"); | ||
352 | CheckllSetPrimitiveParamsVector(primShear, m_lslApi.llList2Vector(primParams, 7), primTest + " prim shear"); | ||
353 | CheckllSetPrimitiveParamsVector(primProfCut, m_lslApi.llList2Vector(primParams, 8), primTest + " prim profile cut"); | ||
354 | CheckllSetPrimitiveParamsVector(primTaper, m_lslApi.llList2Vector(primParams, 9), primTest + " prim taper"); | ||
355 | Assert.AreEqual(primRev, m_lslApi.llList2Float(primParams, 10), FLOAT_ACCURACY, | ||
356 | "TestllSetPrimitiveParams " + primTest + " prim revolution fail"); | ||
357 | Assert.AreEqual(primRadius, m_lslApi.llList2Float(primParams, 11), FLOAT_ACCURACY, | ||
358 | "TestllSetPrimitiveParams " + primTest + " prim radius fail"); | ||
359 | Assert.AreEqual(primSkew, m_lslApi.llList2Float(primParams, 12), FLOAT_ACCURACY, | ||
360 | "TestllSetPrimitiveParams " + primTest + " prim skew fail"); | ||
361 | } | ||
362 | |||
363 | // Set prim params for a sculpted prim and check results. | ||
364 | public void CheckllSetPrimitiveParams(string primTest, | ||
365 | LSL_Types.Vector3 primSize, int primType, string primMap, int primSculptType) | ||
366 | { | ||
367 | // Set the prim params. | ||
368 | m_lslApi.llSetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, primSize, | ||
369 | ScriptBaseClass.PRIM_TYPE, primType, primMap, primSculptType)); | ||
370 | |||
371 | // Get params for prim to validate settings. | ||
372 | LSL_Types.list primParams = | ||
373 | m_lslApi.llGetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, ScriptBaseClass.PRIM_TYPE)); | ||
374 | |||
375 | // Validate settings. | ||
376 | CheckllSetPrimitiveParamsVector(primSize, m_lslApi.llList2Vector(primParams, 0), primTest + " prim size"); | ||
377 | Assert.AreEqual(primType, m_lslApi.llList2Integer(primParams, 1), | ||
378 | "TestllSetPrimitiveParams " + primTest + " prim type check fail"); | ||
379 | Assert.AreEqual(primMap, (string)m_lslApi.llList2String(primParams, 2), | ||
380 | "TestllSetPrimitiveParams " + primTest + " prim map check fail"); | ||
381 | Assert.AreEqual(primSculptType, m_lslApi.llList2Integer(primParams, 3), | ||
382 | "TestllSetPrimitiveParams " + primTest + " prim type scuplt check fail"); | ||
383 | } | ||
384 | |||
385 | public void CheckllSetPrimitiveParamsVector(LSL_Types.Vector3 vecCheck, LSL_Types.Vector3 vecReturned, string msg) | ||
386 | { | ||
387 | // Check each vector component against expected result. | ||
388 | Assert.AreEqual(vecCheck.x, vecReturned.x, VECTOR_COMPONENT_ACCURACY, | ||
389 | "TestllSetPrimitiveParams " + msg + " vector check fail on x component"); | ||
390 | Assert.AreEqual(vecCheck.y, vecReturned.y, VECTOR_COMPONENT_ACCURACY, | ||
391 | "TestllSetPrimitiveParams " + msg + " vector check fail on y component"); | ||
392 | Assert.AreEqual(vecCheck.z, vecReturned.z, VECTOR_COMPONENT_ACCURACY, | ||
393 | "TestllSetPrimitiveParams " + msg + " vector check fail on z component"); | ||
394 | } | ||
395 | |||
396 | [Test] | ||
169 | // llVecNorm test. | 397 | // llVecNorm test. |
170 | public void TestllVecNorm() | 398 | public void TestllVecNorm() |
171 | { | 399 | { |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs new file mode 100644 index 0000000..7573dff --- /dev/null +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs | |||
@@ -0,0 +1,229 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using System.Text; | ||
32 | using log4net; | ||
33 | using Nini.Config; | ||
34 | using NUnit.Framework; | ||
35 | using OpenMetaverse; | ||
36 | using OpenMetaverse.Assets; | ||
37 | using OpenMetaverse.StructuredData; | ||
38 | using OpenSim.Framework; | ||
39 | using OpenSim.Region.CoreModules.Avatar.AvatarFactory; | ||
40 | using OpenSim.Region.OptionalModules.World.NPC; | ||
41 | using OpenSim.Region.Framework.Scenes; | ||
42 | using OpenSim.Region.ScriptEngine.Shared; | ||
43 | using OpenSim.Region.ScriptEngine.Shared.Api; | ||
44 | using OpenSim.Services.Interfaces; | ||
45 | using OpenSim.Tests.Common; | ||
46 | using OpenSim.Tests.Common.Mock; | ||
47 | |||
48 | namespace OpenSim.Region.ScriptEngine.Shared.Tests | ||
49 | { | ||
50 | /// <summary> | ||
51 | /// Tests for OSSL_Api | ||
52 | /// </summary> | ||
53 | [TestFixture] | ||
54 | public class OSSL_ApiAppearanceTest | ||
55 | { | ||
56 | protected Scene m_scene; | ||
57 | protected XEngine.XEngine m_engine; | ||
58 | |||
59 | [SetUp] | ||
60 | public void SetUp() | ||
61 | { | ||
62 | IConfigSource initConfigSource = new IniConfigSource(); | ||
63 | IConfig config = initConfigSource.AddConfig("XEngine"); | ||
64 | config.Set("Enabled", "true"); | ||
65 | config.Set("AllowOSFunctions", "true"); | ||
66 | config.Set("OSFunctionThreatLevel", "Severe"); | ||
67 | config = initConfigSource.AddConfig("NPC"); | ||
68 | config.Set("Enabled", "true"); | ||
69 | |||
70 | m_scene = SceneHelpers.SetupScene(); | ||
71 | SceneHelpers.SetupSceneModules(m_scene, initConfigSource, new AvatarFactoryModule(), new NPCModule()); | ||
72 | |||
73 | m_engine = new XEngine.XEngine(); | ||
74 | m_engine.Initialise(initConfigSource); | ||
75 | m_engine.AddRegion(m_scene); | ||
76 | } | ||
77 | |||
78 | /// <summary> | ||
79 | /// Test creation of an NPC where the appearance data comes from a notecard | ||
80 | /// </summary> | ||
81 | [Test] | ||
82 | public void TestOsNpcCreateFromNotecard() | ||
83 | { | ||
84 | TestHelpers.InMethod(); | ||
85 | // log4net.Config.XmlConfigurator.Configure(); | ||
86 | |||
87 | // Store an avatar with a different height from default in a notecard. | ||
88 | UUID userId = TestHelpers.ParseTail(0x1); | ||
89 | float newHeight = 1.9f; | ||
90 | |||
91 | ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId); | ||
92 | sp.Appearance.AvatarHeight = newHeight; | ||
93 | SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId); | ||
94 | SceneObjectPart part = so.RootPart; | ||
95 | m_scene.AddSceneObject(so); | ||
96 | |||
97 | OSSL_Api osslApi = new OSSL_Api(); | ||
98 | osslApi.Initialize(m_engine, part, part.LocalId, part.UUID); | ||
99 | |||
100 | string notecardName = "appearanceNc"; | ||
101 | osslApi.osOwnerSaveAppearance(notecardName); | ||
102 | |||
103 | // Try creating a bot using the appearance in the notecard. | ||
104 | string npcRaw = osslApi.osNpcCreate("Jane", "Doe", new LSL_Types.Vector3(128, 128, 128), notecardName); | ||
105 | Assert.That(npcRaw, Is.Not.Null); | ||
106 | |||
107 | UUID npcId = new UUID(npcRaw); | ||
108 | ScenePresence npc = m_scene.GetScenePresence(npcId); | ||
109 | Assert.That(npc, Is.Not.Null); | ||
110 | Assert.That(npc.Appearance.AvatarHeight, Is.EqualTo(newHeight)); | ||
111 | } | ||
112 | |||
113 | /// <summary> | ||
114 | /// Test creation of an NPC where the appearance data comes from an avatar already in the region. | ||
115 | /// </summary> | ||
116 | [Test] | ||
117 | public void TestOsNpcCreateFromAvatar() | ||
118 | { | ||
119 | TestHelpers.InMethod(); | ||
120 | // log4net.Config.XmlConfigurator.Configure(); | ||
121 | |||
122 | // Store an avatar with a different height from default in a notecard. | ||
123 | UUID userId = TestHelpers.ParseTail(0x1); | ||
124 | float newHeight = 1.9f; | ||
125 | |||
126 | ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId); | ||
127 | sp.Appearance.AvatarHeight = newHeight; | ||
128 | SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId); | ||
129 | SceneObjectPart part = so.RootPart; | ||
130 | m_scene.AddSceneObject(so); | ||
131 | |||
132 | OSSL_Api osslApi = new OSSL_Api(); | ||
133 | osslApi.Initialize(m_engine, part, part.LocalId, part.UUID); | ||
134 | |||
135 | string notecardName = "appearanceNc"; | ||
136 | osslApi.osOwnerSaveAppearance(notecardName); | ||
137 | |||
138 | // Try creating a bot using the existing avatar's appearance | ||
139 | string npcRaw = osslApi.osNpcCreate("Jane", "Doe", new LSL_Types.Vector3(128, 128, 128), sp.UUID.ToString()); | ||
140 | Assert.That(npcRaw, Is.Not.Null); | ||
141 | |||
142 | UUID npcId = new UUID(npcRaw); | ||
143 | ScenePresence npc = m_scene.GetScenePresence(npcId); | ||
144 | Assert.That(npc, Is.Not.Null); | ||
145 | Assert.That(npc.Appearance.AvatarHeight, Is.EqualTo(newHeight)); | ||
146 | } | ||
147 | |||
148 | [Test] | ||
149 | public void TestOsOwnerSaveAppearance() | ||
150 | { | ||
151 | TestHelpers.InMethod(); | ||
152 | // log4net.Config.XmlConfigurator.Configure(); | ||
153 | |||
154 | UUID userId = TestHelpers.ParseTail(0x1); | ||
155 | float newHeight = 1.9f; | ||
156 | |||
157 | ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId); | ||
158 | sp.Appearance.AvatarHeight = newHeight; | ||
159 | SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId); | ||
160 | SceneObjectPart part = so.RootPart; | ||
161 | m_scene.AddSceneObject(so); | ||
162 | |||
163 | OSSL_Api osslApi = new OSSL_Api(); | ||
164 | osslApi.Initialize(m_engine, part, part.LocalId, part.UUID); | ||
165 | |||
166 | string notecardName = "appearanceNc"; | ||
167 | |||
168 | osslApi.osOwnerSaveAppearance(notecardName); | ||
169 | |||
170 | IList<TaskInventoryItem> items = part.Inventory.GetInventoryItems(notecardName); | ||
171 | Assert.That(items.Count, Is.EqualTo(1)); | ||
172 | |||
173 | TaskInventoryItem ncItem = items[0]; | ||
174 | Assert.That(ncItem.Name, Is.EqualTo(notecardName)); | ||
175 | |||
176 | AssetBase ncAsset = m_scene.AssetService.Get(ncItem.AssetID.ToString()); | ||
177 | Assert.That(ncAsset, Is.Not.Null); | ||
178 | |||
179 | AssetNotecard anc = new AssetNotecard(UUID.Zero, ncAsset.Data); | ||
180 | anc.Decode(); | ||
181 | OSDMap appearanceOsd = (OSDMap)OSDParser.DeserializeLLSDXml(anc.BodyText); | ||
182 | AvatarAppearance savedAppearance = new AvatarAppearance(); | ||
183 | savedAppearance.Unpack(appearanceOsd); | ||
184 | |||
185 | Assert.That(savedAppearance.AvatarHeight, Is.EqualTo(sp.Appearance.AvatarHeight)); | ||
186 | } | ||
187 | |||
188 | [Test] | ||
189 | public void TestOsAgentSaveAppearance() | ||
190 | { | ||
191 | TestHelpers.InMethod(); | ||
192 | // log4net.Config.XmlConfigurator.Configure(); | ||
193 | |||
194 | UUID ownerId = TestHelpers.ParseTail(0x1); | ||
195 | UUID nonOwnerId = TestHelpers.ParseTail(0x2); | ||
196 | float newHeight = 1.9f; | ||
197 | |||
198 | ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, nonOwnerId); | ||
199 | sp.Appearance.AvatarHeight = newHeight; | ||
200 | SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, ownerId); | ||
201 | SceneObjectPart part = so.RootPart; | ||
202 | m_scene.AddSceneObject(so); | ||
203 | |||
204 | OSSL_Api osslApi = new OSSL_Api(); | ||
205 | osslApi.Initialize(m_engine, part, part.LocalId, part.UUID); | ||
206 | |||
207 | string notecardName = "appearanceNc"; | ||
208 | |||
209 | osslApi.osAgentSaveAppearance(new LSL_Types.LSLString(nonOwnerId.ToString()), notecardName); | ||
210 | |||
211 | IList<TaskInventoryItem> items = part.Inventory.GetInventoryItems(notecardName); | ||
212 | Assert.That(items.Count, Is.EqualTo(1)); | ||
213 | |||
214 | TaskInventoryItem ncItem = items[0]; | ||
215 | Assert.That(ncItem.Name, Is.EqualTo(notecardName)); | ||
216 | |||
217 | AssetBase ncAsset = m_scene.AssetService.Get(ncItem.AssetID.ToString()); | ||
218 | Assert.That(ncAsset, Is.Not.Null); | ||
219 | |||
220 | AssetNotecard anc = new AssetNotecard(UUID.Zero, ncAsset.Data); | ||
221 | anc.Decode(); | ||
222 | OSDMap appearanceOsd = (OSDMap)OSDParser.DeserializeLLSDXml(anc.BodyText); | ||
223 | AvatarAppearance savedAppearance = new AvatarAppearance(); | ||
224 | savedAppearance.Unpack(appearanceOsd); | ||
225 | |||
226 | Assert.That(savedAppearance.AvatarHeight, Is.EqualTo(sp.Appearance.AvatarHeight)); | ||
227 | } | ||
228 | } | ||
229 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/ScriptEngine/XEngine/EventManager.cs b/OpenSim/Region/ScriptEngine/XEngine/EventManager.cs index 0ac8b5c..5c4174e 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/EventManager.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/EventManager.cs | |||
@@ -97,13 +97,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
97 | return; | 97 | return; |
98 | 98 | ||
99 | m_log.Debug("Paid: " + objectID + " from " + agentID + ", amount " + amount); | 99 | m_log.Debug("Paid: " + objectID + " from " + agentID + ", amount " + amount); |
100 | if (part.ParentGroup != null) | ||
101 | part = part.ParentGroup.RootPart; | ||
102 | 100 | ||
103 | if (part != null) | 101 | part = part.ParentGroup.RootPart; |
104 | { | 102 | money(part.LocalId, agentID, amount); |
105 | money(part.LocalId, agentID, amount); | ||
106 | } | ||
107 | } | 103 | } |
108 | 104 | ||
109 | /// <summary> | 105 | /// <summary> |
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index 4f3432d..9cb074a 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs | |||
@@ -1373,9 +1373,15 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1373 | 1373 | ||
1374 | public string GetXMLState(UUID itemID) | 1374 | public string GetXMLState(UUID itemID) |
1375 | { | 1375 | { |
1376 | // m_log.DebugFormat("[XEngine]: Getting XML state for {0}", itemID); | ||
1377 | |||
1376 | IScriptInstance instance = GetInstance(itemID); | 1378 | IScriptInstance instance = GetInstance(itemID); |
1377 | if (instance == null) | 1379 | if (instance == null) |
1380 | { | ||
1381 | // m_log.DebugFormat("[XEngine]: Found no script for {0}, returning empty string", itemID); | ||
1378 | return ""; | 1382 | return ""; |
1383 | } | ||
1384 | |||
1379 | string xml = instance.GetXMLState(); | 1385 | string xml = instance.GetXMLState(); |
1380 | 1386 | ||
1381 | XmlDocument sdoc = new XmlDocument(); | 1387 | XmlDocument sdoc = new XmlDocument(); |
@@ -1516,6 +1522,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1516 | mapData.InnerText = map; | 1522 | mapData.InnerText = map; |
1517 | 1523 | ||
1518 | stateData.AppendChild(mapData); | 1524 | stateData.AppendChild(mapData); |
1525 | |||
1526 | // m_log.DebugFormat("[XEngine]: Got XML state for {0}", itemID); | ||
1527 | |||
1519 | return doc.InnerXml; | 1528 | return doc.InnerXml; |
1520 | } | 1529 | } |
1521 | 1530 | ||