diff options
Diffstat (limited to 'OpenSim/Region')
106 files changed, 3479 insertions, 1769 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs index d604cf6..ed8ec16 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs | |||
@@ -44,7 +44,7 @@ using OpenSim.Tests.Common.Mock; | |||
44 | namespace OpenSim.Region.ClientStack.Linden.Tests | 44 | namespace OpenSim.Region.ClientStack.Linden.Tests |
45 | { | 45 | { |
46 | [TestFixture] | 46 | [TestFixture] |
47 | public class EventQueueTests | 47 | public class EventQueueTests : OpenSimTestCase |
48 | { | 48 | { |
49 | private TestScene m_scene; | 49 | private TestScene m_scene; |
50 | 50 | ||
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 4860da0..ee66485 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | |||
@@ -12122,11 +12122,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12122 | if (logPacket) | 12122 | if (logPacket) |
12123 | m_log.DebugFormat( | 12123 | m_log.DebugFormat( |
12124 | "[CLIENT]: PACKET IN from {0} ({1}) in {2} - {3}", | 12124 | "[CLIENT]: PACKET IN from {0} ({1}) in {2} - {3}", |
12125 | Name, SceneAgent.IsChildAgent ? "child" : "root ", m_scene.RegionInfo.RegionName, packet.Type); | 12125 | Name, SceneAgent.IsChildAgent ? "child" : "root ", Scene.Name, packet.Type); |
12126 | } | 12126 | } |
12127 | 12127 | ||
12128 | if (!ProcessPacketMethod(packet)) | 12128 | if (!ProcessPacketMethod(packet)) |
12129 | m_log.Warn("[CLIENT]: unhandled packet " + packet.Type); | 12129 | m_log.WarnFormat( |
12130 | "[CLIENT]: Unhandled packet {0} from {1} ({2}) in {3}. Ignoring.", | ||
12131 | packet.Type, Name, SceneAgent.IsChildAgent ? "child" : "root ", Scene.Name); | ||
12130 | } | 12132 | } |
12131 | 12133 | ||
12132 | private static PrimitiveBaseShape GetShapeFromAddPacket(ObjectAddPacket addPacket) | 12134 | private static PrimitiveBaseShape GetShapeFromAddPacket(ObjectAddPacket addPacket) |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs index 5fcf376..7d9f581 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs | |||
@@ -43,7 +43,7 @@ using OpenSim.Tests.Common.Mock; | |||
43 | namespace OpenSim.Region.ClientStack.LindenUDP.Tests | 43 | namespace OpenSim.Region.ClientStack.LindenUDP.Tests |
44 | { | 44 | { |
45 | [TestFixture] | 45 | [TestFixture] |
46 | public class LLImageManagerTests | 46 | public class LLImageManagerTests : OpenSimTestCase |
47 | { | 47 | { |
48 | private AssetBase m_testImageAsset; | 48 | private AssetBase m_testImageAsset; |
49 | private Scene scene; | 49 | private Scene scene; |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs index 0f88ec6..5f73a94 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs | |||
@@ -39,7 +39,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
39 | /// Tests for the LL packet handler | 39 | /// Tests for the LL packet handler |
40 | /// </summary> | 40 | /// </summary> |
41 | [TestFixture] | 41 | [TestFixture] |
42 | public class PacketHandlerTests | 42 | public class PacketHandlerTests : OpenSimTestCase |
43 | { | 43 | { |
44 | // [Test] | 44 | // [Test] |
45 | // /// <summary> | 45 | // /// <summary> |
diff --git a/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs b/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs index 1c2bfd0..fd02b08 100644 --- a/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs +++ b/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs | |||
@@ -47,14 +47,16 @@ namespace OpenSim.Region.CoreModules.Asset.Tests | |||
47 | /// At the moment we're only test the in-memory part of the FlotsamAssetCache. This is a considerable weakness. | 47 | /// At the moment we're only test the in-memory part of the FlotsamAssetCache. This is a considerable weakness. |
48 | /// </summary> | 48 | /// </summary> |
49 | [TestFixture] | 49 | [TestFixture] |
50 | public class FlotsamAssetCacheTests | 50 | public class FlotsamAssetCacheTests : OpenSimTestCase |
51 | { | 51 | { |
52 | protected TestScene m_scene; | 52 | protected TestScene m_scene; |
53 | protected FlotsamAssetCache m_cache; | 53 | protected FlotsamAssetCache m_cache; |
54 | 54 | ||
55 | [SetUp] | 55 | [SetUp] |
56 | public void SetUp() | 56 | public override void SetUp() |
57 | { | 57 | { |
58 | base.SetUp(); | ||
59 | |||
58 | IConfigSource config = new IniConfigSource(); | 60 | IConfigSource config = new IniConfigSource(); |
59 | 61 | ||
60 | config.AddConfig("Modules"); | 62 | config.AddConfig("Modules"); |
diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs index 848b3bf..1830d41 100644 --- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs | |||
@@ -39,7 +39,7 @@ using OpenSim.Tests.Common.Mock; | |||
39 | namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | 39 | namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory |
40 | { | 40 | { |
41 | [TestFixture] | 41 | [TestFixture] |
42 | public class AvatarFactoryModuleTests | 42 | public class AvatarFactoryModuleTests : OpenSimTestCase |
43 | { | 43 | { |
44 | /// <summary> | 44 | /// <summary> |
45 | /// Only partial right now since we don't yet test that it's ended up in the avatar appearance service. | 45 | /// Only partial right now since we don't yet test that it's ended up in the avatar appearance service. |
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs index 7a197f7..961117e 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs | |||
@@ -40,7 +40,7 @@ using OpenSim.Tests.Common.Mock; | |||
40 | namespace OpenSim.Region.CoreModules.Avatar.Friends.Tests | 40 | namespace OpenSim.Region.CoreModules.Avatar.Friends.Tests |
41 | { | 41 | { |
42 | [TestFixture] | 42 | [TestFixture] |
43 | public class FriendsModuleTests | 43 | public class FriendsModuleTests : OpenSimTestCase |
44 | { | 44 | { |
45 | private FriendsModule m_fm; | 45 | private FriendsModule m_fm; |
46 | private TestScene m_scene; | 46 | private TestScene m_scene; |
diff --git a/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs b/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs index af54c1a..b735c61 100644 --- a/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs | |||
@@ -81,7 +81,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Groups | |||
81 | } | 81 | } |
82 | 82 | ||
83 | if (groupsConfig.GetString("Module", "Default") != "Default") | 83 | if (groupsConfig.GetString("Module", "Default") != "Default") |
84 | { | ||
85 | m_Enabled = false; | ||
84 | return; | 86 | return; |
87 | } | ||
85 | } | 88 | } |
86 | 89 | ||
87 | } | 90 | } |
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs index cc266df..1627f6c 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs | |||
@@ -153,7 +153,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
153 | if (sp != null && !sp.IsChildAgent) | 153 | if (sp != null && !sp.IsChildAgent) |
154 | { | 154 | { |
155 | // Local message | 155 | // Local message |
156 | m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to root agent {0} {1}", sp.Name, toAgentID); | 156 | // m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to root agent {0} {1}", sp.Name, toAgentID); |
157 | 157 | ||
158 | sp.ControllingClient.SendInstantMessage(im); | 158 | sp.ControllingClient.SendInstantMessage(im); |
159 | 159 | ||
@@ -166,14 +166,14 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
166 | // try child avatar second | 166 | // try child avatar second |
167 | foreach (Scene scene in m_Scenes) | 167 | foreach (Scene scene in m_Scenes) |
168 | { | 168 | { |
169 | //m_log.DebugFormat( | 169 | // m_log.DebugFormat( |
170 | // "[INSTANT MESSAGE]: Looking for child of {0} in {1}", toAgentID, scene.RegionInfo.RegionName); | 170 | // "[INSTANT MESSAGE]: Looking for child of {0} in {1}", toAgentID, scene.RegionInfo.RegionName); |
171 | 171 | ||
172 | ScenePresence sp = scene.GetScenePresence(toAgentID); | 172 | ScenePresence sp = scene.GetScenePresence(toAgentID); |
173 | if (sp != null) | 173 | if (sp != null) |
174 | { | 174 | { |
175 | // Local message | 175 | // Local message |
176 | m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to child agent {0} {1}", sp.Name, toAgentID); | 176 | // m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to child agent {0} {1}", sp.Name, toAgentID); |
177 | 177 | ||
178 | sp.ControllingClient.SendInstantMessage(im); | 178 | sp.ControllingClient.SendInstantMessage(im); |
179 | 179 | ||
@@ -183,7 +183,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
183 | } | 183 | } |
184 | } | 184 | } |
185 | 185 | ||
186 | m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to {0} via XMLRPC", im.toAgentID); | 186 | // m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to {0} via XMLRPC", im.toAgentID); |
187 | 187 | ||
188 | SendGridInstantMessageViaXMLRPC(im, result); | 188 | SendGridInstantMessageViaXMLRPC(im, result); |
189 | } | 189 | } |
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs index 3a44cc5..2d46276 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs | |||
@@ -189,20 +189,24 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
189 | { | 189 | { |
190 | foreach (GridInstantMessage im in msglist) | 190 | foreach (GridInstantMessage im in msglist) |
191 | { | 191 | { |
192 | // client.SendInstantMessage(im); | 192 | if (im.dialog == (byte)InstantMessageDialog.InventoryOffered) |
193 | 193 | // send it directly or else the item will be given twice | |
194 | // Send through scene event manager so all modules get a chance | 194 | client.SendInstantMessage(im); |
195 | // to look at this message before it gets delivered. | 195 | else |
196 | // | 196 | { |
197 | // Needed for proper state management for stored group | 197 | // Send through scene event manager so all modules get a chance |
198 | // invitations | 198 | // to look at this message before it gets delivered. |
199 | // | 199 | // |
200 | 200 | // Needed for proper state management for stored group | |
201 | im.offline = 1; | 201 | // invitations |
202 | 202 | // | |
203 | Scene s = FindScene(client.AgentId); | 203 | |
204 | if (s != null) | 204 | im.offline = 1; |
205 | s.EventManager.TriggerIncomingInstantMessage(im); | 205 | |
206 | Scene s = FindScene(client.AgentId); | ||
207 | if (s != null) | ||
208 | s.EventManager.TriggerIncomingInstantMessage(im); | ||
209 | } | ||
206 | } | 210 | } |
207 | } | 211 | } |
208 | } | 212 | } |
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs index 4cfa33d..ae58dfd 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs | |||
@@ -316,76 +316,74 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer | |||
316 | } | 316 | } |
317 | } | 317 | } |
318 | 318 | ||
319 | // Disabled for now as it looks like http://opensimulator.org/mantis/view.php?id=6311 was fixed by fixes | 319 | // XXX: This code was placed here to try and accomodate RLV which moves given folders named #RLV/~<name> |
320 | // to inventory folder versioning allowing the viewer to move the received folder itself as happens on the | 320 | // to the requested folder, which in this case is #RLV. However, it is the viewer that appears to be |
321 | // LL grid. Doing it again server-side then wrongly does a second create and move | 321 | // response from renaming the #RLV/~example folder to ~example. For some reason this is not yet |
322 | // // XXX: This code was placed here to try and accomdate RLV which moves given folders named #RLV/~<name> | 322 | // happening, possibly because we are not sending the correct inventory update messages with the correct |
323 | // // to a folder called name in #RLV. However, this approach may not be ultimately correct - from analysis | 323 | // transaction IDs |
324 | // // of Firestorm 4.2.2 on sending an InventoryOffered instead of TaskInventoryOffered (as was previously | 324 | else if (im.dialog == (byte) InstantMessageDialog.TaskInventoryAccepted) |
325 | // // done), the viewer itself would appear to move and rename the folder, rather than the simulator doing it here. | 325 | { |
326 | // else if (im.dialog == (byte) InstantMessageDialog.TaskInventoryAccepted) | 326 | UUID destinationFolderID = UUID.Zero; |
327 | // { | 327 | |
328 | // UUID destinationFolderID = UUID.Zero; | 328 | if (im.binaryBucket != null && im.binaryBucket.Length >= 16) |
329 | // | 329 | { |
330 | // if (im.binaryBucket != null && im.binaryBucket.Length >= 16) | 330 | destinationFolderID = new UUID(im.binaryBucket, 0); |
331 | // { | 331 | } |
332 | // destinationFolderID = new UUID(im.binaryBucket, 0); | 332 | |
333 | // } | 333 | if (destinationFolderID != UUID.Zero) |
334 | // | 334 | { |
335 | // if (destinationFolderID != UUID.Zero) | 335 | InventoryFolderBase destinationFolder = new InventoryFolderBase(destinationFolderID, client.AgentId); |
336 | // { | 336 | if (destinationFolder == null) |
337 | // InventoryFolderBase destinationFolder = new InventoryFolderBase(destinationFolderID, client.AgentId); | 337 | { |
338 | // if (destinationFolder == null) | 338 | m_log.WarnFormat( |
339 | // { | 339 | "[INVENTORY TRANSFER]: TaskInventoryAccepted message from {0} in {1} specified folder {2} which does not exist", |
340 | // m_log.WarnFormat( | 340 | client.Name, scene.Name, destinationFolderID); |
341 | // "[INVENTORY TRANSFER]: TaskInventoryAccepted message from {0} in {1} specified folder {2} which does not exist", | 341 | |
342 | // client.Name, scene.Name, destinationFolderID); | 342 | return; |
343 | // | 343 | } |
344 | // return; | 344 | |
345 | // } | 345 | IInventoryService invService = scene.InventoryService; |
346 | // | 346 | |
347 | // IInventoryService invService = scene.InventoryService; | 347 | UUID inventoryID = new UUID(im.imSessionID); // The inventory item/folder, back from it's trip |
348 | // | 348 | |
349 | // UUID inventoryID = new UUID(im.imSessionID); // The inventory item/folder, back from it's trip | 349 | InventoryItemBase item = new InventoryItemBase(inventoryID, client.AgentId); |
350 | // | 350 | item = invService.GetItem(item); |
351 | // InventoryItemBase item = new InventoryItemBase(inventoryID, client.AgentId); | 351 | InventoryFolderBase folder = null; |
352 | // item = invService.GetItem(item); | 352 | UUID? previousParentFolderID = null; |
353 | // InventoryFolderBase folder = null; | 353 | |
354 | // UUID? previousParentFolderID = null; | 354 | if (item != null) // It's an item |
355 | // | 355 | { |
356 | // if (item != null) // It's an item | 356 | previousParentFolderID = item.Folder; |
357 | // { | 357 | item.Folder = destinationFolderID; |
358 | // previousParentFolderID = item.Folder; | 358 | |
359 | // item.Folder = destinationFolderID; | 359 | invService.DeleteItems(item.Owner, new List<UUID>() { item.ID }); |
360 | // | 360 | scene.AddInventoryItem(client, item); |
361 | // invService.DeleteItems(item.Owner, new List<UUID>() { item.ID }); | 361 | } |
362 | // scene.AddInventoryItem(client, item); | 362 | else |
363 | // } | 363 | { |
364 | // else | 364 | folder = new InventoryFolderBase(inventoryID, client.AgentId); |
365 | // { | 365 | folder = invService.GetFolder(folder); |
366 | // folder = new InventoryFolderBase(inventoryID, client.AgentId); | 366 | |
367 | // folder = invService.GetFolder(folder); | 367 | if (folder != null) // It's a folder |
368 | // | 368 | { |
369 | // if (folder != null) // It's a folder | 369 | previousParentFolderID = folder.ParentID; |
370 | // { | 370 | folder.ParentID = destinationFolderID; |
371 | // previousParentFolderID = folder.ParentID; | 371 | invService.MoveFolder(folder); |
372 | // folder.ParentID = destinationFolderID; | 372 | } |
373 | // invService.MoveFolder(folder); | 373 | } |
374 | // } | 374 | |
375 | // } | 375 | // Tell client about updates to original parent and new parent (this should probably be factored with existing move item/folder code). |
376 | // | 376 | if (previousParentFolderID != null) |
377 | // // Tell client about updates to original parent and new parent (this should probably be factored with existing move item/folder code). | 377 | { |
378 | // if (previousParentFolderID != null) | 378 | InventoryFolderBase previousParentFolder |
379 | // { | 379 | = new InventoryFolderBase((UUID)previousParentFolderID, client.AgentId); |
380 | // InventoryFolderBase previousParentFolder | 380 | previousParentFolder = invService.GetFolder(previousParentFolder); |
381 | // = new InventoryFolderBase((UUID)previousParentFolderID, client.AgentId); | 381 | scene.SendInventoryUpdate(client, previousParentFolder, true, true); |
382 | // previousParentFolder = invService.GetFolder(previousParentFolder); | 382 | |
383 | // scene.SendInventoryUpdate(client, previousParentFolder, true, true); | 383 | scene.SendInventoryUpdate(client, destinationFolder, true, true); |
384 | // | 384 | } |
385 | // scene.SendInventoryUpdate(client, destinationFolder, true, true); | 385 | } |
386 | // } | 386 | } |
387 | // } | ||
388 | // } | ||
389 | else if ( | 387 | else if ( |
390 | im.dialog == (byte)InstantMessageDialog.InventoryDeclined | 388 | im.dialog == (byte)InstantMessageDialog.InventoryDeclined |
391 | || im.dialog == (byte)InstantMessageDialog.TaskInventoryDeclined) | 389 | || im.dialog == (byte)InstantMessageDialog.TaskInventoryDeclined) |
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs index f8ec6de..7871eda 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs | |||
@@ -71,7 +71,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
71 | 71 | ||
72 | #region Internal functions | 72 | #region Internal functions |
73 | 73 | ||
74 | public AssetMetadata FetchMetadata(string url, UUID assetID) | 74 | private AssetMetadata FetchMetadata(string url, UUID assetID) |
75 | { | 75 | { |
76 | if (!url.EndsWith("/") && !url.EndsWith("=")) | 76 | if (!url.EndsWith("/") && !url.EndsWith("=")) |
77 | url = url + "/"; | 77 | url = url + "/"; |
@@ -86,6 +86,27 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
86 | return meta; | 86 | return meta; |
87 | } | 87 | } |
88 | 88 | ||
89 | private AssetBase FetchAsset(string url, UUID assetID) | ||
90 | { | ||
91 | // Test if it's already here | ||
92 | AssetBase asset = m_scene.AssetService.Get(assetID.ToString()); | ||
93 | if (asset == null) | ||
94 | { | ||
95 | if (!url.EndsWith("/") && !url.EndsWith("=")) | ||
96 | url = url + "/"; | ||
97 | |||
98 | asset = m_scene.AssetService.Get(url + assetID.ToString()); | ||
99 | |||
100 | //if (asset != null) | ||
101 | // m_log.DebugFormat("[HG ASSET MAPPER]: Fetched asset {0} of type {1} from {2} ", assetID, asset.Metadata.Type, url); | ||
102 | //else | ||
103 | // m_log.DebugFormat("[HG ASSET MAPPER]: Unable to fetch asset {0} from {1} ", assetID, url); | ||
104 | |||
105 | } | ||
106 | |||
107 | return asset; | ||
108 | } | ||
109 | |||
89 | public bool PostAsset(string url, AssetBase asset) | 110 | public bool PostAsset(string url, AssetBase asset) |
90 | { | 111 | { |
91 | if (asset != null) | 112 | if (asset != null) |
@@ -228,11 +249,22 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
228 | if (meta == null) | 249 | if (meta == null) |
229 | return; | 250 | return; |
230 | 251 | ||
231 | // The act of gathering UUIDs downloads the assets from the remote server | 252 | // The act of gathering UUIDs downloads some assets from the remote server |
253 | // but not all... | ||
232 | Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>(); | 254 | Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>(); |
233 | HGUuidGatherer uuidGatherer = new HGUuidGatherer(m_scene.AssetService, userAssetURL); | 255 | HGUuidGatherer uuidGatherer = new HGUuidGatherer(m_scene.AssetService, userAssetURL); |
234 | uuidGatherer.GatherAssetUuids(assetID, (AssetType)meta.Type, ids); | 256 | uuidGatherer.GatherAssetUuids(assetID, (AssetType)meta.Type, ids); |
235 | 257 | m_log.DebugFormat("[HG ASSET MAPPER]: Preparing to get {0} assets", ids.Count); | |
258 | bool success = true; | ||
259 | foreach (UUID uuid in ids.Keys) | ||
260 | if (FetchAsset(userAssetURL, uuid) == null) | ||
261 | success = false; | ||
262 | |||
263 | // maybe all pieces got here... | ||
264 | if (!success) | ||
265 | m_log.DebugFormat("[HG ASSET MAPPER]: Problems getting item {0} from asset server {1}", assetID, userAssetURL); | ||
266 | else | ||
267 | m_log.DebugFormat("[HG ASSET MAPPER]: Successfully got item {0} from asset server {1}", assetID, userAssetURL); | ||
236 | } | 268 | } |
237 | 269 | ||
238 | 270 | ||
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs index 21d8bd7..ac25a93 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs | |||
@@ -49,7 +49,7 @@ using OpenSim.Tests.Common.Mock; | |||
49 | namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests | 49 | namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests |
50 | { | 50 | { |
51 | [TestFixture] | 51 | [TestFixture] |
52 | public class InventoryAccessModuleTests | 52 | public class InventoryAccessModuleTests : OpenSimTestCase |
53 | { | 53 | { |
54 | protected TestScene m_scene; | 54 | protected TestScene m_scene; |
55 | protected BasicInventoryAccessModule m_iam; | 55 | protected BasicInventoryAccessModule m_iam; |
@@ -57,8 +57,10 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests | |||
57 | protected TestClient m_tc; | 57 | protected TestClient m_tc; |
58 | 58 | ||
59 | [SetUp] | 59 | [SetUp] |
60 | public void SetUp() | 60 | public override void SetUp() |
61 | { | 61 | { |
62 | base.SetUp(); | ||
63 | |||
62 | m_iam = new BasicInventoryAccessModule(); | 64 | m_iam = new BasicInventoryAccessModule(); |
63 | 65 | ||
64 | IConfigSource config = new IniConfigSource(); | 66 | IConfigSource config = new IniConfigSource(); |
diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 86e7004..77e8b00 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs | |||
@@ -181,6 +181,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
181 | 181 | ||
182 | m_log.DebugFormat("[USER MANAGEMENT MODULE]: HandleAvatarPickerRequest for {0}", query); | 182 | m_log.DebugFormat("[USER MANAGEMENT MODULE]: HandleAvatarPickerRequest for {0}", query); |
183 | 183 | ||
184 | // searhc the user accounts service | ||
184 | List<UserAccount> accs = m_Scenes[0].UserAccountService.GetUserAccounts(m_Scenes[0].RegionInfo.ScopeID, query); | 185 | List<UserAccount> accs = m_Scenes[0].UserAccountService.GetUserAccounts(m_Scenes[0].RegionInfo.ScopeID, query); |
185 | 186 | ||
186 | List<UserData> users = new List<UserData>(); | 187 | List<UserData> users = new List<UserData>(); |
@@ -196,6 +197,12 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
196 | } | 197 | } |
197 | } | 198 | } |
198 | 199 | ||
200 | // search the local cache | ||
201 | foreach (UserData data in m_UserCache.Values) | ||
202 | if (users.Find(delegate(UserData d) { return d.Id == data.Id; }) == null && | ||
203 | (data.FirstName.StartsWith(query) || data.LastName.StartsWith(query))) | ||
204 | users.Add(data); | ||
205 | |||
199 | AddAdditionalUsers(avatarID, query, users); | 206 | AddAdditionalUsers(avatarID, query, users); |
200 | 207 | ||
201 | AvatarPickerReplyPacket replyPacket = (AvatarPickerReplyPacket)PacketPool.Instance.GetPacket(PacketType.AvatarPickerReply); | 208 | AvatarPickerReplyPacket replyPacket = (AvatarPickerReplyPacket)PacketPool.Instance.GetPacket(PacketType.AvatarPickerReply); |
@@ -433,6 +440,9 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
433 | public void AddUser(UUID uuid, string first, string last, string homeURL) | 440 | public void AddUser(UUID uuid, string first, string last, string homeURL) |
434 | { | 441 | { |
435 | //m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, first {1}, last {2}, url {3}", uuid, first, last, homeURL); | 442 | //m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, first {1}, last {2}, url {3}", uuid, first, last, homeURL); |
443 | if (homeURL == string.Empty) | ||
444 | return; | ||
445 | |||
436 | AddUser(uuid, homeURL + ";" + first + " " + last); | 446 | AddUser(uuid, homeURL + ";" + first + " " + last); |
437 | } | 447 | } |
438 | 448 | ||
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs index 32e47f9..69bac82 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs | |||
@@ -35,7 +35,6 @@ using NUnit.Framework; | |||
35 | using OpenMetaverse; | 35 | using OpenMetaverse; |
36 | using OpenSim.Framework; | 36 | using OpenSim.Framework; |
37 | using Nini.Config; | 37 | using Nini.Config; |
38 | |||
39 | using OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence; | 38 | using OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence; |
40 | using OpenSim.Region.Framework.Scenes; | 39 | using OpenSim.Region.Framework.Scenes; |
41 | using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo; | 40 | using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo; |
@@ -44,11 +43,14 @@ using OpenSim.Tests.Common; | |||
44 | namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence.Tests | 43 | namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence.Tests |
45 | { | 44 | { |
46 | [TestFixture] | 45 | [TestFixture] |
47 | public class PresenceConnectorsTests | 46 | public class PresenceConnectorsTests : OpenSimTestCase |
48 | { | 47 | { |
49 | LocalPresenceServicesConnector m_LocalConnector; | 48 | LocalPresenceServicesConnector m_LocalConnector; |
50 | private void SetUp() | 49 | |
50 | public override void SetUp() | ||
51 | { | 51 | { |
52 | base.SetUp(); | ||
53 | |||
52 | IConfigSource config = new IniConfigSource(); | 54 | IConfigSource config = new IniConfigSource(); |
53 | config.AddConfig("Modules"); | 55 | config.AddConfig("Modules"); |
54 | config.AddConfig("PresenceService"); | 56 | config.AddConfig("PresenceService"); |
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs index ade5e76..01f1c63 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs | |||
@@ -570,13 +570,22 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
570 | 570 | ||
571 | // Validate User and Group UUID's | 571 | // Validate User and Group UUID's |
572 | 572 | ||
573 | if (!ResolveUserUuid(scene, parcel.OwnerID)) | 573 | if (parcel.IsGroupOwned) |
574 | parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner; | ||
575 | |||
576 | if (!ResolveGroupUuid(parcel.GroupID)) | ||
577 | { | 574 | { |
578 | parcel.GroupID = UUID.Zero; | 575 | if (!ResolveGroupUuid(parcel.GroupID)) |
579 | parcel.IsGroupOwned = false; | 576 | { |
577 | parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner; | ||
578 | parcel.GroupID = UUID.Zero; | ||
579 | parcel.IsGroupOwned = false; | ||
580 | } | ||
581 | } | ||
582 | else | ||
583 | { | ||
584 | if (!ResolveUserUuid(scene, parcel.OwnerID)) | ||
585 | parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner; | ||
586 | |||
587 | if (!ResolveGroupUuid(parcel.GroupID)) | ||
588 | parcel.GroupID = UUID.Zero; | ||
580 | } | 589 | } |
581 | 590 | ||
582 | List<LandAccessEntry> accessList = new List<LandAccessEntry>(); | 591 | List<LandAccessEntry> accessList = new List<LandAccessEntry>(); |
@@ -589,8 +598,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
589 | parcel.ParcelAccessList = accessList; | 598 | parcel.ParcelAccessList = accessList; |
590 | 599 | ||
591 | // m_log.DebugFormat( | 600 | // m_log.DebugFormat( |
592 | // "[ARCHIVER]: Adding parcel {0}, local id {1}, area {2}", | 601 | // "[ARCHIVER]: Adding parcel {0}, local id {1}, owner {2}, group {3}, isGroupOwned {4}, area {5}", |
593 | // parcel.Name, parcel.LocalID, parcel.Area); | 602 | // parcel.Name, parcel.LocalID, parcel.OwnerID, parcel.GroupID, parcel.IsGroupOwned, parcel.Area); |
594 | 603 | ||
595 | landData.Add(parcel); | 604 | landData.Add(parcel); |
596 | } | 605 | } |
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs index d751b1c..7bdd65c 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs | |||
@@ -167,7 +167,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
167 | } | 167 | } |
168 | scenesGroup.CalcSceneLocations(); | 168 | scenesGroup.CalcSceneLocations(); |
169 | 169 | ||
170 | |||
171 | m_archiveWriter = new TarArchiveWriter(m_saveStream); | 170 | m_archiveWriter = new TarArchiveWriter(m_saveStream); |
172 | 171 | ||
173 | try | 172 | try |
@@ -216,7 +215,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
216 | } | 215 | } |
217 | } | 216 | } |
218 | 217 | ||
219 | |||
220 | private void ArchiveOneRegion(Scene scene, string regionDir, Dictionary<UUID, AssetType> assetUuids) | 218 | private void ArchiveOneRegion(Scene scene, string regionDir, Dictionary<UUID, AssetType> assetUuids) |
221 | { | 219 | { |
222 | m_log.InfoFormat("[ARCHIVER]: Writing region {0}", scene.RegionInfo.RegionName); | 220 | m_log.InfoFormat("[ARCHIVER]: Writing region {0}", scene.RegionInfo.RegionName); |
@@ -540,7 +538,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
540 | xtw.WriteElementString("size_in_meters", string.Format("{0},{1}", size.X, size.Y)); | 538 | xtw.WriteElementString("size_in_meters", string.Format("{0},{1}", size.X, size.Y)); |
541 | } | 539 | } |
542 | 540 | ||
543 | |||
544 | protected void Save(Scene scene, List<SceneObjectGroup> sceneObjects, string regionDir) | 541 | protected void Save(Scene scene, List<SceneObjectGroup> sceneObjects, string regionDir) |
545 | { | 542 | { |
546 | if (regionDir != string.Empty) | 543 | if (regionDir != string.Empty) |
@@ -560,8 +557,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
560 | foreach (ILandObject lo in landObjects) | 557 | foreach (ILandObject lo in landObjects) |
561 | { | 558 | { |
562 | LandData landData = lo.LandData; | 559 | LandData landData = lo.LandData; |
563 | string landDataPath = String.Format("{0}{1}{2}.xml", | 560 | string landDataPath |
564 | regionDir, ArchiveConstants.LANDDATA_PATH, landData.GlobalID.ToString()); | 561 | = String.Format("{0}{1}", regionDir, ArchiveConstants.CreateOarLandDataPath(landData)); |
565 | m_archiveWriter.WriteFile(landDataPath, LandDataSerializer.Serialize(landData, m_options)); | 562 | m_archiveWriter.WriteFile(landDataPath, LandDataSerializer.Serialize(landData, m_options)); |
566 | } | 563 | } |
567 | 564 | ||
@@ -604,7 +601,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
604 | 601 | ||
605 | CloseArchive(String.Empty); | 602 | CloseArchive(String.Empty); |
606 | } | 603 | } |
607 | |||
608 | 604 | ||
609 | /// <summary> | 605 | /// <summary> |
610 | /// Closes the archive and notifies that we're done. | 606 | /// Closes the archive and notifies that we're done. |
@@ -629,6 +625,5 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
629 | 625 | ||
630 | m_rootScene.EventManager.TriggerOarFileSaved(m_requestId, errorMessage); | 626 | m_rootScene.EventManager.TriggerOarFileSaved(m_requestId, errorMessage); |
631 | } | 627 | } |
632 | |||
633 | } | 628 | } |
634 | } | 629 | } \ No newline at end of file |
diff --git a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs index 82f49b0..eec1cec 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs | |||
@@ -31,16 +31,19 @@ using System.IO; | |||
31 | using System.Reflection; | 31 | using System.Reflection; |
32 | using System.Threading; | 32 | using System.Threading; |
33 | using log4net.Config; | 33 | using log4net.Config; |
34 | using Nini.Config; | ||
34 | using NUnit.Framework; | 35 | using NUnit.Framework; |
35 | using OpenMetaverse; | 36 | using OpenMetaverse; |
36 | using OpenMetaverse.Assets; | 37 | using OpenMetaverse.Assets; |
37 | using OpenSim.Framework; | 38 | using OpenSim.Framework; |
38 | using OpenSim.Framework.Serialization; | 39 | using OpenSim.Framework.Serialization; |
39 | using OpenSim.Framework.Serialization.External; | 40 | using OpenSim.Framework.Serialization.External; |
41 | using OpenSim.Region.CoreModules.World.Land; | ||
40 | using OpenSim.Region.CoreModules.World.Serialiser; | 42 | using OpenSim.Region.CoreModules.World.Serialiser; |
41 | using OpenSim.Region.CoreModules.World.Terrain; | 43 | using OpenSim.Region.CoreModules.World.Terrain; |
42 | using OpenSim.Region.Framework.Scenes; | 44 | using OpenSim.Region.Framework.Scenes; |
43 | using OpenSim.Region.Framework.Scenes.Serialization; | 45 | using OpenSim.Region.Framework.Scenes.Serialization; |
46 | using OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups; | ||
44 | using OpenSim.Tests.Common; | 47 | using OpenSim.Tests.Common; |
45 | using OpenSim.Tests.Common.Mock; | 48 | using OpenSim.Tests.Common.Mock; |
46 | using ArchiveConstants = OpenSim.Framework.Serialization.ArchiveConstants; | 49 | using ArchiveConstants = OpenSim.Framework.Serialization.ArchiveConstants; |
@@ -69,9 +72,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
69 | { | 72 | { |
70 | base.SetUp(); | 73 | base.SetUp(); |
71 | 74 | ||
72 | // FIXME: Do something about this - relying on statics in unit tests causes trouble sooner or later | ||
73 | new SceneManager(); | ||
74 | |||
75 | m_archiverModule = new ArchiverModule(); | 75 | m_archiverModule = new ArchiverModule(); |
76 | m_serialiserModule = new SerialiserModule(); | 76 | m_serialiserModule = new SerialiserModule(); |
77 | TerrainModule terrainModule = new TerrainModule(); | 77 | TerrainModule terrainModule = new TerrainModule(); |
@@ -127,6 +127,53 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
127 | 127 | ||
128 | return new SceneObjectPart(ownerId, shape, groupPosition, rotationOffset, offsetPosition) { Name = partName }; | 128 | return new SceneObjectPart(ownerId, shape, groupPosition, rotationOffset, offsetPosition) { Name = partName }; |
129 | } | 129 | } |
130 | |||
131 | private void CreateTestObjects(Scene scene, out SceneObjectGroup sog1, out SceneObjectGroup sog2, out UUID ncAssetUuid) | ||
132 | { | ||
133 | SceneObjectPart part1 = CreateSceneObjectPart1(); | ||
134 | sog1 = new SceneObjectGroup(part1); | ||
135 | scene.AddNewSceneObject(sog1, false); | ||
136 | |||
137 | AssetNotecard nc = new AssetNotecard(); | ||
138 | nc.BodyText = "Hello World!"; | ||
139 | nc.Encode(); | ||
140 | ncAssetUuid = UUID.Random(); | ||
141 | UUID ncItemUuid = UUID.Random(); | ||
142 | AssetBase ncAsset | ||
143 | = AssetHelpers.CreateAsset(ncAssetUuid, AssetType.Notecard, nc.AssetData, UUID.Zero); | ||
144 | m_scene.AssetService.Store(ncAsset); | ||
145 | |||
146 | TaskInventoryItem ncItem | ||
147 | = new TaskInventoryItem { Name = "ncItem", AssetID = ncAssetUuid, ItemID = ncItemUuid }; | ||
148 | SceneObjectPart part2 = CreateSceneObjectPart2(); | ||
149 | sog2 = new SceneObjectGroup(part2); | ||
150 | part2.Inventory.AddInventoryItem(ncItem, true); | ||
151 | |||
152 | scene.AddNewSceneObject(sog2, false); | ||
153 | } | ||
154 | |||
155 | private static void CreateSoundAsset(TarArchiveWriter tar, Assembly assembly, string soundDataResourceName, out byte[] soundData, out UUID soundUuid) | ||
156 | { | ||
157 | using (Stream resource = assembly.GetManifestResourceStream(soundDataResourceName)) | ||
158 | { | ||
159 | using (BinaryReader br = new BinaryReader(resource)) | ||
160 | { | ||
161 | // FIXME: Use the inspector instead | ||
162 | soundData = br.ReadBytes(99999999); | ||
163 | soundUuid = UUID.Parse("00000000-0000-0000-0000-000000000001"); | ||
164 | string soundAssetFileName | ||
165 | = ArchiveConstants.ASSETS_PATH + soundUuid | ||
166 | + ArchiveConstants.ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.SoundWAV]; | ||
167 | tar.WriteFile(soundAssetFileName, soundData); | ||
168 | |||
169 | /* | ||
170 | AssetBase soundAsset = AssetHelpers.CreateAsset(soundUuid, soundData); | ||
171 | scene.AssetService.Store(soundAsset); | ||
172 | asset1FileName = ArchiveConstants.ASSETS_PATH + soundUuid + ".wav"; | ||
173 | */ | ||
174 | } | ||
175 | } | ||
176 | } | ||
130 | 177 | ||
131 | /// <summary> | 178 | /// <summary> |
132 | /// Test saving an OpenSim Region Archive. | 179 | /// Test saving an OpenSim Region Archive. |
@@ -204,30 +251,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
204 | // TODO: Test presence of more files and contents of files. | 251 | // TODO: Test presence of more files and contents of files. |
205 | } | 252 | } |
206 | 253 | ||
207 | private void CreateTestObjects(Scene scene, out SceneObjectGroup sog1, out SceneObjectGroup sog2, out UUID ncAssetUuid) | ||
208 | { | ||
209 | SceneObjectPart part1 = CreateSceneObjectPart1(); | ||
210 | sog1 = new SceneObjectGroup(part1); | ||
211 | scene.AddNewSceneObject(sog1, false); | ||
212 | |||
213 | AssetNotecard nc = new AssetNotecard(); | ||
214 | nc.BodyText = "Hello World!"; | ||
215 | nc.Encode(); | ||
216 | ncAssetUuid = UUID.Random(); | ||
217 | UUID ncItemUuid = UUID.Random(); | ||
218 | AssetBase ncAsset | ||
219 | = AssetHelpers.CreateAsset(ncAssetUuid, AssetType.Notecard, nc.AssetData, UUID.Zero); | ||
220 | m_scene.AssetService.Store(ncAsset); | ||
221 | |||
222 | TaskInventoryItem ncItem | ||
223 | = new TaskInventoryItem { Name = "ncItem", AssetID = ncAssetUuid, ItemID = ncItemUuid }; | ||
224 | SceneObjectPart part2 = CreateSceneObjectPart2(); | ||
225 | sog2 = new SceneObjectGroup(part2); | ||
226 | part2.Inventory.AddInventoryItem(ncItem, true); | ||
227 | |||
228 | scene.AddNewSceneObject(sog2, false); | ||
229 | } | ||
230 | |||
231 | /// <summary> | 254 | /// <summary> |
232 | /// Test saving an OpenSim Region Archive with the no assets option | 255 | /// Test saving an OpenSim Region Archive with the no assets option |
233 | /// </summary> | 256 | /// </summary> |
@@ -309,59 +332,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
309 | } | 332 | } |
310 | 333 | ||
311 | /// <summary> | 334 | /// <summary> |
312 | /// Test loading an OpenSim Region Archive where the scene object parts are not ordered by link number (e.g. | ||
313 | /// 2 can come after 3). | ||
314 | /// </summary> | ||
315 | [Test] | ||
316 | public void TestLoadOarUnorderedParts() | ||
317 | { | ||
318 | TestHelpers.InMethod(); | ||
319 | |||
320 | UUID ownerId = TestHelpers.ParseTail(0xaaaa); | ||
321 | |||
322 | MemoryStream archiveWriteStream = new MemoryStream(); | ||
323 | TarArchiveWriter tar = new TarArchiveWriter(archiveWriteStream); | ||
324 | |||
325 | tar.WriteFile( | ||
326 | ArchiveConstants.CONTROL_FILE_PATH, | ||
327 | new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup())); | ||
328 | |||
329 | SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, ownerId, "obj1-", 0x11); | ||
330 | SceneObjectPart sop2 | ||
331 | = SceneHelpers.CreateSceneObjectPart("obj1-Part2", TestHelpers.ParseTail(0x12), ownerId); | ||
332 | SceneObjectPart sop3 | ||
333 | = SceneHelpers.CreateSceneObjectPart("obj1-Part3", TestHelpers.ParseTail(0x13), ownerId); | ||
334 | |||
335 | // Add the parts so they will be written out in reverse order to the oar | ||
336 | sog1.AddPart(sop3); | ||
337 | sop3.LinkNum = 3; | ||
338 | sog1.AddPart(sop2); | ||
339 | sop2.LinkNum = 2; | ||
340 | |||
341 | tar.WriteFile( | ||
342 | ArchiveConstants.CreateOarObjectPath(sog1.Name, sog1.UUID, sog1.AbsolutePosition), | ||
343 | SceneObjectSerializer.ToXml2Format(sog1)); | ||
344 | |||
345 | tar.Close(); | ||
346 | |||
347 | MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray()); | ||
348 | |||
349 | lock (this) | ||
350 | { | ||
351 | m_scene.EventManager.OnOarFileLoaded += LoadCompleted; | ||
352 | m_archiverModule.DearchiveRegion(archiveReadStream); | ||
353 | } | ||
354 | |||
355 | Assert.That(m_lastErrorMessage, Is.Null); | ||
356 | |||
357 | SceneObjectPart part2 = m_scene.GetSceneObjectPart("obj1-Part2"); | ||
358 | Assert.That(part2.LinkNum, Is.EqualTo(2)); | ||
359 | |||
360 | SceneObjectPart part3 = m_scene.GetSceneObjectPart("obj1-Part3"); | ||
361 | Assert.That(part3.LinkNum, Is.EqualTo(3)); | ||
362 | } | ||
363 | |||
364 | /// <summary> | ||
365 | /// Test loading an OpenSim Region Archive. | 335 | /// Test loading an OpenSim Region Archive. |
366 | /// </summary> | 336 | /// </summary> |
367 | [Test] | 337 | [Test] |
@@ -435,50 +405,57 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
435 | TestLoadedRegion(part1, soundItemName, soundData); | 405 | TestLoadedRegion(part1, soundItemName, soundData); |
436 | } | 406 | } |
437 | 407 | ||
438 | private static void CreateSoundAsset(TarArchiveWriter tar, Assembly assembly, string soundDataResourceName, out byte[] soundData, out UUID soundUuid) | 408 | /// <summary> |
409 | /// Test loading an OpenSim Region Archive where the scene object parts are not ordered by link number (e.g. | ||
410 | /// 2 can come after 3). | ||
411 | /// </summary> | ||
412 | [Test] | ||
413 | public void TestLoadOarUnorderedParts() | ||
439 | { | 414 | { |
440 | using (Stream resource = assembly.GetManifestResourceStream(soundDataResourceName)) | 415 | TestHelpers.InMethod(); |
441 | { | ||
442 | using (BinaryReader br = new BinaryReader(resource)) | ||
443 | { | ||
444 | // FIXME: Use the inspector instead | ||
445 | soundData = br.ReadBytes(99999999); | ||
446 | soundUuid = UUID.Parse("00000000-0000-0000-0000-000000000001"); | ||
447 | string soundAssetFileName | ||
448 | = ArchiveConstants.ASSETS_PATH + soundUuid | ||
449 | + ArchiveConstants.ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.SoundWAV]; | ||
450 | tar.WriteFile(soundAssetFileName, soundData); | ||
451 | 416 | ||
452 | /* | 417 | UUID ownerId = TestHelpers.ParseTail(0xaaaa); |
453 | AssetBase soundAsset = AssetHelpers.CreateAsset(soundUuid, soundData); | ||
454 | scene.AssetService.Store(soundAsset); | ||
455 | asset1FileName = ArchiveConstants.ASSETS_PATH + soundUuid + ".wav"; | ||
456 | */ | ||
457 | } | ||
458 | } | ||
459 | } | ||
460 | 418 | ||
461 | private void TestLoadedRegion(SceneObjectPart part1, string soundItemName, byte[] soundData) | 419 | MemoryStream archiveWriteStream = new MemoryStream(); |
462 | { | 420 | TarArchiveWriter tar = new TarArchiveWriter(archiveWriteStream); |
463 | SceneObjectPart object1PartLoaded = m_scene.GetSceneObjectPart(part1.Name); | ||
464 | 421 | ||
465 | Assert.That(object1PartLoaded, Is.Not.Null, "object1 was not loaded"); | 422 | tar.WriteFile( |
466 | Assert.That(object1PartLoaded.Name, Is.EqualTo(part1.Name), "object1 names not identical"); | 423 | ArchiveConstants.CONTROL_FILE_PATH, |
467 | Assert.That(object1PartLoaded.GroupPosition, Is.EqualTo(part1.GroupPosition), "object1 group position not equal"); | 424 | new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup())); |
468 | Assert.That( | ||
469 | object1PartLoaded.RotationOffset, Is.EqualTo(part1.RotationOffset), "object1 rotation offset not equal"); | ||
470 | Assert.That( | ||
471 | object1PartLoaded.OffsetPosition, Is.EqualTo(part1.OffsetPosition), "object1 offset position not equal"); | ||
472 | Assert.That(object1PartLoaded.SitTargetOrientation, Is.EqualTo(part1.SitTargetOrientation)); | ||
473 | Assert.That(object1PartLoaded.SitTargetPosition, Is.EqualTo(part1.SitTargetPosition)); | ||
474 | 425 | ||
475 | TaskInventoryItem loadedSoundItem = object1PartLoaded.Inventory.GetInventoryItems(soundItemName)[0]; | 426 | SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, ownerId, "obj1-", 0x11); |
476 | Assert.That(loadedSoundItem, Is.Not.Null, "loaded sound item was null"); | 427 | SceneObjectPart sop2 |
477 | AssetBase loadedSoundAsset = m_scene.AssetService.Get(loadedSoundItem.AssetID.ToString()); | 428 | = SceneHelpers.CreateSceneObjectPart("obj1-Part2", TestHelpers.ParseTail(0x12), ownerId); |
478 | Assert.That(loadedSoundAsset, Is.Not.Null, "loaded sound asset was null"); | 429 | SceneObjectPart sop3 |
479 | Assert.That(loadedSoundAsset.Data, Is.EqualTo(soundData), "saved and loaded sound data do not match"); | 430 | = SceneHelpers.CreateSceneObjectPart("obj1-Part3", TestHelpers.ParseTail(0x13), ownerId); |
480 | 431 | ||
481 | Assert.Greater(m_scene.LandChannel.AllParcels().Count, 0, "incorrect number of parcels"); | 432 | // Add the parts so they will be written out in reverse order to the oar |
433 | sog1.AddPart(sop3); | ||
434 | sop3.LinkNum = 3; | ||
435 | sog1.AddPart(sop2); | ||
436 | sop2.LinkNum = 2; | ||
437 | |||
438 | tar.WriteFile( | ||
439 | ArchiveConstants.CreateOarObjectPath(sog1.Name, sog1.UUID, sog1.AbsolutePosition), | ||
440 | SceneObjectSerializer.ToXml2Format(sog1)); | ||
441 | |||
442 | tar.Close(); | ||
443 | |||
444 | MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray()); | ||
445 | |||
446 | lock (this) | ||
447 | { | ||
448 | m_scene.EventManager.OnOarFileLoaded += LoadCompleted; | ||
449 | m_archiverModule.DearchiveRegion(archiveReadStream); | ||
450 | } | ||
451 | |||
452 | Assert.That(m_lastErrorMessage, Is.Null); | ||
453 | |||
454 | SceneObjectPart part2 = m_scene.GetSceneObjectPart("obj1-Part2"); | ||
455 | Assert.That(part2.LinkNum, Is.EqualTo(2)); | ||
456 | |||
457 | SceneObjectPart part3 = m_scene.GetSceneObjectPart("obj1-Part3"); | ||
458 | Assert.That(part3.LinkNum, Is.EqualTo(3)); | ||
482 | } | 459 | } |
483 | 460 | ||
484 | /// <summary> | 461 | /// <summary> |
@@ -538,8 +515,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
538 | SerialiserModule serialiserModule = new SerialiserModule(); | 515 | SerialiserModule serialiserModule = new SerialiserModule(); |
539 | TerrainModule terrainModule = new TerrainModule(); | 516 | TerrainModule terrainModule = new TerrainModule(); |
540 | 517 | ||
541 | m_sceneHelpers = new SceneHelpers(); | 518 | SceneHelpers m_sceneHelpers2 = new SceneHelpers(); |
542 | TestScene scene2 = m_sceneHelpers.SetupScene(); | 519 | TestScene scene2 = m_sceneHelpers2.SetupScene(); |
543 | SceneHelpers.SetupSceneModules(scene2, archiverModule, serialiserModule, terrainModule); | 520 | SceneHelpers.SetupSceneModules(scene2, archiverModule, serialiserModule, terrainModule); |
544 | 521 | ||
545 | // Make sure there's a valid owner for the owner we saved (this should have been wiped if the code is | 522 | // Make sure there's a valid owner for the owner we saved (this should have been wiped if the code is |
@@ -563,6 +540,71 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
563 | } | 540 | } |
564 | 541 | ||
565 | /// <summary> | 542 | /// <summary> |
543 | /// Test OAR loading where the land parcel is group deeded. | ||
544 | /// </summary> | ||
545 | /// <remarks> | ||
546 | /// In this situation, the owner ID is set to the group ID. | ||
547 | /// </remarks> | ||
548 | [Test] | ||
549 | public void TestLoadOarDeededLand() | ||
550 | { | ||
551 | TestHelpers.InMethod(); | ||
552 | // TestHelpers.EnableLogging(); | ||
553 | |||
554 | UUID landID = TestHelpers.ParseTail(0x10); | ||
555 | |||
556 | MockGroupsServicesConnector groupsService = new MockGroupsServicesConnector(); | ||
557 | |||
558 | IConfigSource configSource = new IniConfigSource(); | ||
559 | IConfig config = configSource.AddConfig("Groups"); | ||
560 | config.Set("Enabled", true); | ||
561 | config.Set("Module", "GroupsModule"); | ||
562 | config.Set("DebugEnabled", true); | ||
563 | SceneHelpers.SetupSceneModules( | ||
564 | m_scene, configSource, new object[] { new GroupsModule(), groupsService, new LandManagementModule() }); | ||
565 | |||
566 | // Create group in scene for loading | ||
567 | // FIXME: For now we'll put up with the issue that we'll get a group ID that varies across tests. | ||
568 | UUID groupID | ||
569 | = groupsService.CreateGroup(UUID.Zero, "group1", "", true, UUID.Zero, 3, true, true, true, UUID.Zero); | ||
570 | |||
571 | // Construct OAR | ||
572 | MemoryStream oarStream = new MemoryStream(); | ||
573 | TarArchiveWriter tar = new TarArchiveWriter(oarStream); | ||
574 | |||
575 | tar.WriteDir(ArchiveConstants.LANDDATA_PATH); | ||
576 | tar.WriteFile( | ||
577 | ArchiveConstants.CONTROL_FILE_PATH, | ||
578 | new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup())); | ||
579 | |||
580 | LandObject lo = new LandObject(groupID, true, null); | ||
581 | lo.SetLandBitmap(lo.BasicFullRegionLandBitmap()); | ||
582 | LandData ld = lo.LandData; | ||
583 | ld.GlobalID = landID; | ||
584 | |||
585 | string ldPath = ArchiveConstants.CreateOarLandDataPath(ld); | ||
586 | tar.WriteFile(ldPath, LandDataSerializer.Serialize(ld, null)); | ||
587 | tar.Close(); | ||
588 | |||
589 | oarStream = new MemoryStream(oarStream.ToArray()); | ||
590 | |||
591 | // Load OAR | ||
592 | lock (this) | ||
593 | { | ||
594 | m_scene.EventManager.OnOarFileLoaded += LoadCompleted; | ||
595 | m_archiverModule.DearchiveRegion(oarStream); | ||
596 | } | ||
597 | |||
598 | ILandObject rLo = m_scene.LandChannel.GetLandObject(16, 16); | ||
599 | LandData rLd = rLo.LandData; | ||
600 | |||
601 | Assert.That(rLd.GlobalID, Is.EqualTo(landID)); | ||
602 | Assert.That(rLd.OwnerID, Is.EqualTo(groupID)); | ||
603 | Assert.That(rLd.GroupID, Is.EqualTo(groupID)); | ||
604 | Assert.That(rLd.IsGroupOwned, Is.EqualTo(true)); | ||
605 | } | ||
606 | |||
607 | /// <summary> | ||
566 | /// Test loading the region settings of an OpenSim Region Archive. | 608 | /// Test loading the region settings of an OpenSim Region Archive. |
567 | /// </summary> | 609 | /// </summary> |
568 | [Test] | 610 | [Test] |
@@ -781,9 +823,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
781 | } | 823 | } |
782 | } | 824 | } |
783 | 825 | ||
784 | |||
785 | // Save OAR | 826 | // Save OAR |
786 | |||
787 | MemoryStream archiveWriteStream = new MemoryStream(); | 827 | MemoryStream archiveWriteStream = new MemoryStream(); |
788 | m_scene.EventManager.OnOarFileSaved += SaveCompleted; | 828 | m_scene.EventManager.OnOarFileSaved += SaveCompleted; |
789 | 829 | ||
@@ -800,7 +840,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
800 | 840 | ||
801 | 841 | ||
802 | // Check that the OAR contains the expected data | 842 | // Check that the OAR contains the expected data |
803 | |||
804 | Assert.That(m_lastRequestId, Is.EqualTo(requestId)); | 843 | Assert.That(m_lastRequestId, Is.EqualTo(requestId)); |
805 | 844 | ||
806 | byte[] archive = archiveWriteStream.ToArray(); | 845 | byte[] archive = archiveWriteStream.ToArray(); |
@@ -892,7 +931,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
892 | } | 931 | } |
893 | 932 | ||
894 | ArchiveScenesGroup scenesGroup = new ArchiveScenesGroup(); | 933 | ArchiveScenesGroup scenesGroup = new ArchiveScenesGroup(); |
895 | SceneManager.Instance.ForEachScene(delegate(Scene scene) | 934 | m_sceneHelpers.SceneManager.ForEachScene(delegate(Scene scene) |
896 | { | 935 | { |
897 | scenesGroup.AddScene(scene); | 936 | scenesGroup.AddScene(scene); |
898 | }); | 937 | }); |
@@ -950,13 +989,13 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
950 | 989 | ||
951 | // Delete the current objects, to test that they're loaded from the OAR and didn't | 990 | // Delete the current objects, to test that they're loaded from the OAR and didn't |
952 | // just remain in the scene. | 991 | // just remain in the scene. |
953 | SceneManager.Instance.ForEachScene(delegate(Scene scene) | 992 | m_sceneHelpers.SceneManager.ForEachScene(delegate(Scene scene) |
954 | { | 993 | { |
955 | scene.DeleteAllSceneObjects(); | 994 | scene.DeleteAllSceneObjects(); |
956 | }); | 995 | }); |
957 | 996 | ||
958 | // Create a "hole", to test that that the corresponding region isn't loaded from the OAR | 997 | // Create a "hole", to test that that the corresponding region isn't loaded from the OAR |
959 | SceneManager.Instance.CloseScene(SceneManager.Instance.Scenes[1]); | 998 | m_sceneHelpers.SceneManager.CloseScene(SceneManager.Instance.Scenes[1]); |
960 | 999 | ||
961 | 1000 | ||
962 | // Check thay the OAR file contains the expected data | 1001 | // Check thay the OAR file contains the expected data |
@@ -971,10 +1010,32 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
971 | 1010 | ||
972 | Assert.That(m_lastErrorMessage, Is.Null); | 1011 | Assert.That(m_lastErrorMessage, Is.Null); |
973 | 1012 | ||
974 | Assert.AreEqual(3, SceneManager.Instance.Scenes.Count); | 1013 | Assert.AreEqual(3, m_sceneHelpers.SceneManager.Scenes.Count); |
975 | 1014 | ||
976 | TestLoadedRegion(part1, soundItemName, soundData); | 1015 | TestLoadedRegion(part1, soundItemName, soundData); |
977 | } | 1016 | } |
978 | 1017 | ||
1018 | private void TestLoadedRegion(SceneObjectPart part1, string soundItemName, byte[] soundData) | ||
1019 | { | ||
1020 | SceneObjectPart object1PartLoaded = m_scene.GetSceneObjectPart(part1.Name); | ||
1021 | |||
1022 | Assert.That(object1PartLoaded, Is.Not.Null, "object1 was not loaded"); | ||
1023 | Assert.That(object1PartLoaded.Name, Is.EqualTo(part1.Name), "object1 names not identical"); | ||
1024 | Assert.That(object1PartLoaded.GroupPosition, Is.EqualTo(part1.GroupPosition), "object1 group position not equal"); | ||
1025 | Assert.That( | ||
1026 | object1PartLoaded.RotationOffset, Is.EqualTo(part1.RotationOffset), "object1 rotation offset not equal"); | ||
1027 | Assert.That( | ||
1028 | object1PartLoaded.OffsetPosition, Is.EqualTo(part1.OffsetPosition), "object1 offset position not equal"); | ||
1029 | Assert.That(object1PartLoaded.SitTargetOrientation, Is.EqualTo(part1.SitTargetOrientation)); | ||
1030 | Assert.That(object1PartLoaded.SitTargetPosition, Is.EqualTo(part1.SitTargetPosition)); | ||
1031 | |||
1032 | TaskInventoryItem loadedSoundItem = object1PartLoaded.Inventory.GetInventoryItems(soundItemName)[0]; | ||
1033 | Assert.That(loadedSoundItem, Is.Not.Null, "loaded sound item was null"); | ||
1034 | AssetBase loadedSoundAsset = m_scene.AssetService.Get(loadedSoundItem.AssetID.ToString()); | ||
1035 | Assert.That(loadedSoundAsset, Is.Not.Null, "loaded sound asset was null"); | ||
1036 | Assert.That(loadedSoundAsset.Data, Is.EqualTo(soundData), "saved and loaded sound data do not match"); | ||
1037 | |||
1038 | Assert.Greater(m_scene.LandChannel.AllParcels().Count, 0, "incorrect number of parcels"); | ||
1039 | } | ||
979 | } | 1040 | } |
980 | } | 1041 | } \ No newline at end of file |
diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs index dc062b6..267332d 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs | |||
@@ -55,6 +55,11 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
55 | 55 | ||
56 | protected EstateManagementCommands m_commands; | 56 | protected EstateManagementCommands m_commands; |
57 | 57 | ||
58 | /// <summary> | ||
59 | /// If false, region restart requests from the client are blocked even if they are otherwise legitimate. | ||
60 | /// </summary> | ||
61 | public bool AllowRegionRestartFromClient { get; set; } | ||
62 | |||
58 | private EstateTerrainXferHandler TerrainUploader; | 63 | private EstateTerrainXferHandler TerrainUploader; |
59 | public TelehubManager m_Telehub; | 64 | public TelehubManager m_Telehub; |
60 | 65 | ||
@@ -64,6 +69,53 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
64 | 69 | ||
65 | private int m_delayCount = 0; | 70 | private int m_delayCount = 0; |
66 | 71 | ||
72 | #region Region Module interface | ||
73 | |||
74 | public string Name { get { return "EstateManagementModule"; } } | ||
75 | |||
76 | public Type ReplaceableInterface { get { return null; } } | ||
77 | |||
78 | public void Initialise(IConfigSource source) | ||
79 | { | ||
80 | AllowRegionRestartFromClient = true; | ||
81 | |||
82 | IConfig config = source.Configs["EstateManagement"]; | ||
83 | |||
84 | if (config != null) | ||
85 | AllowRegionRestartFromClient = config.GetBoolean("AllowRegionRestartFromClient", true); | ||
86 | } | ||
87 | |||
88 | public void AddRegion(Scene scene) | ||
89 | { | ||
90 | Scene = scene; | ||
91 | Scene.RegisterModuleInterface<IEstateModule>(this); | ||
92 | Scene.EventManager.OnNewClient += EventManager_OnNewClient; | ||
93 | Scene.EventManager.OnRequestChangeWaterHeight += changeWaterHeight; | ||
94 | |||
95 | m_Telehub = new TelehubManager(scene); | ||
96 | |||
97 | m_commands = new EstateManagementCommands(this); | ||
98 | m_commands.Initialise(); | ||
99 | } | ||
100 | |||
101 | public void RemoveRegion(Scene scene) {} | ||
102 | |||
103 | public void RegionLoaded(Scene scene) | ||
104 | { | ||
105 | // Sets up the sun module based no the saved Estate and Region Settings | ||
106 | // DO NOT REMOVE or the sun will stop working | ||
107 | scene.TriggerEstateSunUpdate(); | ||
108 | |||
109 | UserManager = scene.RequestModuleInterface<IUserManagement>(); | ||
110 | } | ||
111 | |||
112 | public void Close() | ||
113 | { | ||
114 | m_commands.Close(); | ||
115 | } | ||
116 | |||
117 | #endregion | ||
118 | |||
67 | #region Packet Data Responders | 119 | #region Packet Data Responders |
68 | 120 | ||
69 | private void clientSendDetailedEstateData(IClientAPI remote_client, UUID invoice) | 121 | private void clientSendDetailedEstateData(IClientAPI remote_client, UUID invoice) |
@@ -197,6 +249,7 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
197 | Scene.RegionInfo.RegionSettings.TerrainTexture4 = texture; | 249 | Scene.RegionInfo.RegionSettings.TerrainTexture4 = texture; |
198 | break; | 250 | break; |
199 | } | 251 | } |
252 | |||
200 | Scene.RegionInfo.RegionSettings.Save(); | 253 | Scene.RegionInfo.RegionSettings.Save(); |
201 | TriggerRegionInfoChange(); | 254 | TriggerRegionInfoChange(); |
202 | sendRegionInfoPacketToAll(); | 255 | sendRegionInfoPacketToAll(); |
@@ -228,6 +281,7 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
228 | Scene.RegionInfo.RegionSettings.Elevation2NE = highValue; | 281 | Scene.RegionInfo.RegionSettings.Elevation2NE = highValue; |
229 | break; | 282 | break; |
230 | } | 283 | } |
284 | |||
231 | Scene.RegionInfo.RegionSettings.Save(); | 285 | Scene.RegionInfo.RegionSettings.Save(); |
232 | TriggerRegionInfoChange(); | 286 | TriggerRegionInfoChange(); |
233 | sendRegionHandshakeToAll(); | 287 | sendRegionHandshakeToAll(); |
@@ -268,6 +322,12 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
268 | 322 | ||
269 | private void handleEstateRestartSimRequest(IClientAPI remoteClient, int timeInSeconds) | 323 | private void handleEstateRestartSimRequest(IClientAPI remoteClient, int timeInSeconds) |
270 | { | 324 | { |
325 | if (!AllowRegionRestartFromClient) | ||
326 | { | ||
327 | remoteClient.SendAlertMessage("Region restart has been disabled on this simulator."); | ||
328 | return; | ||
329 | } | ||
330 | |||
271 | IRestartModule restartModule = Scene.RequestModuleInterface<IRestartModule>(); | 331 | IRestartModule restartModule = Scene.RequestModuleInterface<IRestartModule>(); |
272 | if (restartModule != null) | 332 | if (restartModule != null) |
273 | { | 333 | { |
@@ -352,6 +412,7 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
352 | } | 412 | } |
353 | 413 | ||
354 | } | 414 | } |
415 | |||
355 | if ((estateAccessType & 8) != 0) // User remove | 416 | if ((estateAccessType & 8) != 0) // User remove |
356 | { | 417 | { |
357 | if (Scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true)) | 418 | if (Scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true)) |
@@ -383,6 +444,7 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
383 | remote_client.SendAlertMessage("Method EstateAccessDelta Failed, you don't have permissions"); | 444 | remote_client.SendAlertMessage("Method EstateAccessDelta Failed, you don't have permissions"); |
384 | } | 445 | } |
385 | } | 446 | } |
447 | |||
386 | if ((estateAccessType & 16) != 0) // Group add | 448 | if ((estateAccessType & 16) != 0) // Group add |
387 | { | 449 | { |
388 | if (Scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true)) | 450 | if (Scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true)) |
@@ -650,7 +712,7 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
650 | } | 712 | } |
651 | } | 713 | } |
652 | 714 | ||
653 | public void handleOnEstateManageTelehub (IClientAPI client, UUID invoice, UUID senderID, string cmd, uint param1) | 715 | public void handleOnEstateManageTelehub(IClientAPI client, UUID invoice, UUID senderID, string cmd, uint param1) |
654 | { | 716 | { |
655 | SceneObjectPart part; | 717 | SceneObjectPart part; |
656 | 718 | ||
@@ -1118,49 +1180,6 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
1118 | 1180 | ||
1119 | #endregion | 1181 | #endregion |
1120 | 1182 | ||
1121 | #region Region Module interface | ||
1122 | |||
1123 | public string Name { get { return "EstateManagementModule"; } } | ||
1124 | |||
1125 | public Type ReplaceableInterface { get { return null; } } | ||
1126 | |||
1127 | public void Initialise(IConfigSource source) {} | ||
1128 | |||
1129 | public void AddRegion(Scene scene) | ||
1130 | { | ||
1131 | m_regionChangeTimer.AutoReset = false; | ||
1132 | m_regionChangeTimer.Interval = 2000; | ||
1133 | m_regionChangeTimer.Elapsed += RaiseRegionInfoChange; | ||
1134 | |||
1135 | Scene = scene; | ||
1136 | Scene.RegisterModuleInterface<IEstateModule>(this); | ||
1137 | Scene.EventManager.OnNewClient += EventManager_OnNewClient; | ||
1138 | Scene.EventManager.OnRequestChangeWaterHeight += changeWaterHeight; | ||
1139 | |||
1140 | m_Telehub = new TelehubManager(scene); | ||
1141 | |||
1142 | m_commands = new EstateManagementCommands(this); | ||
1143 | m_commands.Initialise(); | ||
1144 | } | ||
1145 | |||
1146 | public void RemoveRegion(Scene scene) {} | ||
1147 | |||
1148 | public void RegionLoaded(Scene scene) | ||
1149 | { | ||
1150 | // Sets up the sun module based no the saved Estate and Region Settings | ||
1151 | // DO NOT REMOVE or the sun will stop working | ||
1152 | scene.TriggerEstateSunUpdate(); | ||
1153 | |||
1154 | UserManager = scene.RequestModuleInterface<IUserManagement>(); | ||
1155 | } | ||
1156 | |||
1157 | public void Close() | ||
1158 | { | ||
1159 | m_commands.Close(); | ||
1160 | } | ||
1161 | |||
1162 | #endregion | ||
1163 | |||
1164 | #region Other Functions | 1183 | #region Other Functions |
1165 | 1184 | ||
1166 | public void changeWaterHeight(float height) | 1185 | public void changeWaterHeight(float height) |
diff --git a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs index 1193057..281c143 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs | |||
@@ -1384,9 +1384,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1384 | } | 1384 | } |
1385 | 1385 | ||
1386 | for (int i = 0; i < data.Count; i++) | 1386 | for (int i = 0; i < data.Count; i++) |
1387 | { | ||
1388 | IncomingLandObjectFromStorage(data[i]); | 1387 | IncomingLandObjectFromStorage(data[i]); |
1389 | } | ||
1390 | } | 1388 | } |
1391 | 1389 | ||
1392 | public void IncomingLandObjectFromStorage(LandData data) | 1390 | public void IncomingLandObjectFromStorage(LandData data) |
diff --git a/OpenSim/Region/CoreModules/World/Land/LandObject.cs b/OpenSim/Region/CoreModules/World/Land/LandObject.cs index d5b2adb..8ddff99 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandObject.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandObject.cs | |||
@@ -748,9 +748,10 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
748 | int ty = min_y * 4; | 748 | int ty = min_y * 4; |
749 | if (ty > ((int)Constants.RegionSize - 1)) | 749 | if (ty > ((int)Constants.RegionSize - 1)) |
750 | ty = ((int)Constants.RegionSize - 1); | 750 | ty = ((int)Constants.RegionSize - 1); |
751 | |||
751 | LandData.AABBMin = | 752 | LandData.AABBMin = |
752 | new Vector3((float) (min_x * 4), (float) (min_y * 4), | 753 | new Vector3( |
753 | (float) m_scene.Heightmap[tx, ty]); | 754 | (float)(min_x * 4), (float)(min_y * 4), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0); |
754 | 755 | ||
755 | tx = max_x * 4; | 756 | tx = max_x * 4; |
756 | if (tx > ((int)Constants.RegionSize - 1)) | 757 | if (tx > ((int)Constants.RegionSize - 1)) |
@@ -758,9 +759,11 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
758 | ty = max_y * 4; | 759 | ty = max_y * 4; |
759 | if (ty > ((int)Constants.RegionSize - 1)) | 760 | if (ty > ((int)Constants.RegionSize - 1)) |
760 | ty = ((int)Constants.RegionSize - 1); | 761 | ty = ((int)Constants.RegionSize - 1); |
761 | LandData.AABBMax = | 762 | |
762 | new Vector3((float) (max_x * 4), (float) (max_y * 4), | 763 | LandData.AABBMax |
763 | (float) m_scene.Heightmap[tx, ty]); | 764 | = new Vector3( |
765 | (float)(max_x * 4), (float)(max_y * 4), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0); | ||
766 | |||
764 | LandData.Area = tempArea; | 767 | LandData.Area = tempArea; |
765 | } | 768 | } |
766 | 769 | ||
diff --git a/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs b/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs index b5ee4d2..0945b43 100644 --- a/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs +++ b/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs | |||
@@ -41,7 +41,7 @@ using OpenSim.Tests.Common.Mock; | |||
41 | namespace OpenSim.Region.CoreModules.World.Land.Tests | 41 | namespace OpenSim.Region.CoreModules.World.Land.Tests |
42 | { | 42 | { |
43 | [TestFixture] | 43 | [TestFixture] |
44 | public class PrimCountModuleTests | 44 | public class PrimCountModuleTests : OpenSimTestCase |
45 | { | 45 | { |
46 | protected UUID m_userId = new UUID("00000000-0000-0000-0000-100000000000"); | 46 | protected UUID m_userId = new UUID("00000000-0000-0000-0000-100000000000"); |
47 | protected UUID m_groupId = new UUID("00000000-0000-0000-8888-000000000000"); | 47 | protected UUID m_groupId = new UUID("00000000-0000-0000-8888-000000000000"); |
@@ -60,8 +60,10 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests | |||
60 | protected ILandObject m_lo2; | 60 | protected ILandObject m_lo2; |
61 | 61 | ||
62 | [SetUp] | 62 | [SetUp] |
63 | public void SetUp() | 63 | public override void SetUp() |
64 | { | 64 | { |
65 | base.SetUp(); | ||
66 | |||
65 | m_pcm = new PrimCountModule(); | 67 | m_pcm = new PrimCountModule(); |
66 | LandManagementModule lmm = new LandManagementModule(); | 68 | LandManagementModule lmm = new LandManagementModule(); |
67 | m_scene = new SceneHelpers().SetupScene(); | 69 | m_scene = new SceneHelpers().SetupScene(); |
diff --git a/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs b/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs index 396095a..03a96a4 100644 --- a/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs +++ b/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs | |||
@@ -44,14 +44,16 @@ using OpenSim.Tests.Common.Mock; | |||
44 | namespace OpenSim.Region.CoreModules.World.Media.Moap.Tests | 44 | namespace OpenSim.Region.CoreModules.World.Media.Moap.Tests |
45 | { | 45 | { |
46 | [TestFixture] | 46 | [TestFixture] |
47 | public class MoapTests | 47 | public class MoapTests : OpenSimTestCase |
48 | { | 48 | { |
49 | protected TestScene m_scene; | 49 | protected TestScene m_scene; |
50 | protected MoapModule m_module; | 50 | protected MoapModule m_module; |
51 | 51 | ||
52 | [SetUp] | 52 | [SetUp] |
53 | public void SetUp() | 53 | public override void SetUp() |
54 | { | 54 | { |
55 | base.SetUp(); | ||
56 | |||
55 | m_module = new MoapModule(); | 57 | m_module = new MoapModule(); |
56 | m_scene = new SceneHelpers().SetupScene(); | 58 | m_scene = new SceneHelpers().SetupScene(); |
57 | SceneHelpers.SetupSceneModules(m_scene, m_module); | 59 | SceneHelpers.SetupSceneModules(m_scene, m_module); |
diff --git a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs index ab8f143..7b235ae 100644 --- a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs +++ b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs | |||
@@ -365,7 +365,8 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands | |||
365 | 365 | ||
366 | if (mainParams.Count < 4) | 366 | if (mainParams.Count < 4) |
367 | { | 367 | { |
368 | m_console.OutputFormat("Usage: show part id [--full] <UUID-or-localID>"); | 368 | //m_console.OutputFormat("Usage: show part id [--full] <UUID-or-localID>"); |
369 | m_console.OutputFormat("Usage: show part id <UUID-or-localID>"); | ||
369 | return; | 370 | return; |
370 | } | 371 | } |
371 | 372 | ||
@@ -405,6 +406,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands | |||
405 | 406 | ||
406 | if (mainParams.Count < 5) | 407 | if (mainParams.Count < 5) |
407 | { | 408 | { |
409 | //m_console.OutputFormat("Usage: show part pos <start-coord> to <end-coord>"); | ||
408 | m_console.OutputFormat("Usage: show part pos [--full] <start-coord> to <end-coord>"); | 410 | m_console.OutputFormat("Usage: show part pos [--full] <start-coord> to <end-coord>"); |
409 | return; | 411 | return; |
410 | } | 412 | } |
@@ -445,7 +447,8 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands | |||
445 | 447 | ||
446 | if (mainParams.Count < 4) | 448 | if (mainParams.Count < 4) |
447 | { | 449 | { |
448 | m_console.OutputFormat("Usage: show part name [--full] [--regex] <name>"); | 450 | m_console.OutputFormat("Usage: show part name [--regex] <name>"); |
451 | //m_console.OutputFormat("Usage: show part name [--full] [--regex] <name>"); | ||
449 | return; | 452 | return; |
450 | } | 453 | } |
451 | 454 | ||
@@ -577,6 +580,58 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands | |||
577 | cdl.AddRow("Link number", sop.LinkNum); | 580 | cdl.AddRow("Link number", sop.LinkNum); |
578 | cdl.AddRow("Flags", sop.Flags); | 581 | cdl.AddRow("Flags", sop.Flags); |
579 | 582 | ||
583 | if (showFull) | ||
584 | { | ||
585 | PrimitiveBaseShape s = sop.Shape; | ||
586 | cdl.AddRow("FlexiDrag", s.FlexiDrag); | ||
587 | cdl.AddRow("FlexiEntry", s.FlexiEntry); | ||
588 | cdl.AddRow("FlexiForce", string.Format("<{0},{1},{2}>", s.FlexiForceX, s.FlexiForceY, s.FlexiForceZ)); | ||
589 | cdl.AddRow("FlexiGravity", s.FlexiGravity); | ||
590 | cdl.AddRow("FlexiSoftness", s.FlexiSoftness); | ||
591 | cdl.AddRow("HollowShape", s.HollowShape); | ||
592 | cdl.AddRow( | ||
593 | "LightColor", | ||
594 | string.Format("<{0},{1},{2},{3}>", s.LightColorR, s.LightColorB, s.LightColorG, s.LightColorA)); | ||
595 | cdl.AddRow("FlexiDrag", s.LightCutoff); | ||
596 | cdl.AddRow("FlexiDrag", s.LightEntry); | ||
597 | cdl.AddRow("FlexiDrag", s.LightFalloff); | ||
598 | cdl.AddRow("FlexiDrag", s.LightIntensity); | ||
599 | cdl.AddRow("FlexiDrag", s.LightRadius); | ||
600 | cdl.AddRow("Media", string.Format("{0} entries", s.Media != null ? s.Media.Count.ToString() : "n/a")); | ||
601 | cdl.AddRow("PathBegin", s.PathBegin); | ||
602 | cdl.AddRow("PathEnd", s.PathEnd); | ||
603 | cdl.AddRow("PathCurve", s.PathCurve); | ||
604 | cdl.AddRow("PathRadiusOffset", s.PathRadiusOffset); | ||
605 | cdl.AddRow("PathRevolutions", s.PathRevolutions); | ||
606 | cdl.AddRow("PathScale", string.Format("<{0},{1}>", s.PathScaleX, s.PathScaleY)); | ||
607 | cdl.AddRow("PathSkew", string.Format("<{0},{1}>", s.PathShearX, s.PathShearY)); | ||
608 | cdl.AddRow("FlexiDrag", s.PathSkew); | ||
609 | cdl.AddRow("PathTaper", string.Format("<{0},{1}>", s.PathTaperX, s.PathTaperY)); | ||
610 | cdl.AddRow("PathTwist", s.PathTwist); | ||
611 | cdl.AddRow("PathTwistBegin", s.PathTwistBegin); | ||
612 | cdl.AddRow("PCode", s.PCode); | ||
613 | cdl.AddRow("ProfileBegin", s.ProfileBegin); | ||
614 | cdl.AddRow("ProfileEnd", s.ProfileEnd); | ||
615 | cdl.AddRow("ProfileHollow", s.ProfileHollow); | ||
616 | cdl.AddRow("ProfileShape", s.ProfileShape); | ||
617 | cdl.AddRow("ProjectionAmbiance", s.ProjectionAmbiance); | ||
618 | cdl.AddRow("ProjectionEntry", s.ProjectionEntry); | ||
619 | cdl.AddRow("ProjectionFocus", s.ProjectionFocus); | ||
620 | cdl.AddRow("ProjectionFOV", s.ProjectionFOV); | ||
621 | cdl.AddRow("ProjectionTextureUUID", s.ProjectionTextureUUID); | ||
622 | cdl.AddRow("Scale", s.Scale); | ||
623 | cdl.AddRow( | ||
624 | "SculptData", | ||
625 | string.Format("{0} bytes", s.SculptData != null ? s.SculptData.Length.ToString() : "n/a")); | ||
626 | cdl.AddRow("SculptEntry", s.SculptEntry); | ||
627 | cdl.AddRow("SculptTexture", s.SculptTexture); | ||
628 | cdl.AddRow("SculptType", s.SculptType); | ||
629 | cdl.AddRow("State", s.State); | ||
630 | |||
631 | // TODO, unpack and display texture entries | ||
632 | //cdl.AddRow("Textures", string.Format("{0} entries", s.Textures. | ||
633 | } | ||
634 | |||
580 | object itemsOutput; | 635 | object itemsOutput; |
581 | if (showFull) | 636 | if (showFull) |
582 | { | 637 | { |
@@ -588,7 +643,6 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands | |||
588 | itemsOutput = sop.Inventory.Count; | 643 | itemsOutput = sop.Inventory.Count; |
589 | } | 644 | } |
590 | 645 | ||
591 | |||
592 | cdl.AddRow("Items", itemsOutput); | 646 | cdl.AddRow("Items", itemsOutput); |
593 | 647 | ||
594 | return sb.Append(cdl.ToString()); | 648 | return sb.Append(cdl.ToString()); |
diff --git a/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs b/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs index 7825e3e..bcb8e2f 100644 --- a/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs +++ b/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs | |||
@@ -39,7 +39,7 @@ using OpenSim.Tests.Common; | |||
39 | namespace OpenSim.Region.CoreModules.World.Serialiser.Tests | 39 | namespace OpenSim.Region.CoreModules.World.Serialiser.Tests |
40 | { | 40 | { |
41 | [TestFixture] | 41 | [TestFixture] |
42 | public class SerialiserTests | 42 | public class SerialiserTests : OpenSimTestCase |
43 | { | 43 | { |
44 | private string xml = @" | 44 | private string xml = @" |
45 | <SceneObjectGroup> | 45 | <SceneObjectGroup> |
diff --git a/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs b/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs index 513a8f5..883045a 100644 --- a/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs +++ b/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs | |||
@@ -43,8 +43,8 @@ namespace OpenSim.Region.CoreModules.World.Sound | |||
43 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SoundModule")] | 43 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SoundModule")] |
44 | public class SoundModule : INonSharedRegionModule, ISoundModule | 44 | public class SoundModule : INonSharedRegionModule, ISoundModule |
45 | { | 45 | { |
46 | private static readonly ILog m_log = LogManager.GetLogger( | 46 | // private static readonly ILog m_log = LogManager.GetLogger( |
47 | MethodBase.GetCurrentMethod().DeclaringType); | 47 | // MethodBase.GetCurrentMethod().DeclaringType); |
48 | 48 | ||
49 | private Scene m_scene; | 49 | private Scene m_scene; |
50 | 50 | ||
@@ -76,7 +76,7 @@ namespace OpenSim.Region.CoreModules.World.Sound | |||
76 | 76 | ||
77 | public void RemoveRegion(Scene scene) | 77 | public void RemoveRegion(Scene scene) |
78 | { | 78 | { |
79 | m_scene.EventManager.OnClientLogin -= OnNewClient; | 79 | m_scene.EventManager.OnNewClient -= OnNewClient; |
80 | } | 80 | } |
81 | 81 | ||
82 | public void RegionLoaded(Scene scene) | 82 | public void RegionLoaded(Scene scene) |
@@ -85,7 +85,7 @@ namespace OpenSim.Region.CoreModules.World.Sound | |||
85 | return; | 85 | return; |
86 | 86 | ||
87 | m_scene = scene; | 87 | m_scene = scene; |
88 | m_scene.EventManager.OnClientLogin += OnNewClient; | 88 | m_scene.EventManager.OnNewClient += OnNewClient; |
89 | 89 | ||
90 | m_scene.RegisterModuleInterface<ISoundModule>(this); | 90 | m_scene.RegisterModuleInterface<ISoundModule>(this); |
91 | } | 91 | } |
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs b/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs index 3d4f762..be719ea 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs | |||
@@ -30,11 +30,12 @@ using NUnit.Framework; | |||
30 | using OpenSim.Framework; | 30 | using OpenSim.Framework; |
31 | using OpenSim.Region.CoreModules.World.Terrain.PaintBrushes; | 31 | using OpenSim.Region.CoreModules.World.Terrain.PaintBrushes; |
32 | using OpenSim.Region.Framework.Scenes; | 32 | using OpenSim.Region.Framework.Scenes; |
33 | using OpenSim.Tests.Common; | ||
33 | 34 | ||
34 | namespace OpenSim.Region.CoreModules.World.Terrain.Tests | 35 | namespace OpenSim.Region.CoreModules.World.Terrain.Tests |
35 | { | 36 | { |
36 | [TestFixture] | 37 | [TestFixture] |
37 | public class TerrainTest | 38 | public class TerrainTest : OpenSimTestCase |
38 | { | 39 | { |
39 | [Test] | 40 | [Test] |
40 | public void BrushTest() | 41 | public void BrushTest() |
diff --git a/OpenSim/Region/CoreModules/World/Wind/WindModule.cs b/OpenSim/Region/CoreModules/World/Wind/WindModule.cs index fd8e2b4..9de588c 100644 --- a/OpenSim/Region/CoreModules/World/Wind/WindModule.cs +++ b/OpenSim/Region/CoreModules/World/Wind/WindModule.cs | |||
@@ -66,7 +66,7 @@ namespace OpenSim.Region.CoreModules | |||
66 | public void Initialise(IConfigSource config) | 66 | public void Initialise(IConfigSource config) |
67 | { | 67 | { |
68 | m_windConfig = config.Configs["Wind"]; | 68 | m_windConfig = config.Configs["Wind"]; |
69 | string desiredWindPlugin = m_dWindPluginName; | 69 | // string desiredWindPlugin = m_dWindPluginName; |
70 | 70 | ||
71 | if (m_windConfig != null) | 71 | if (m_windConfig != null) |
72 | { | 72 | { |
diff --git a/OpenSim/Region/Framework/Interfaces/IXmlRpcRouter.cs b/OpenSim/Region/Framework/Interfaces/IXmlRpcRouter.cs index 6db6674..093d3f0 100644 --- a/OpenSim/Region/Framework/Interfaces/IXmlRpcRouter.cs +++ b/OpenSim/Region/Framework/Interfaces/IXmlRpcRouter.cs | |||
@@ -34,5 +34,6 @@ namespace OpenSim.Region.Framework.Interfaces | |||
34 | void RegisterNewReceiver(IScriptModule scriptEngine, UUID channelID, UUID objectID, UUID itemID, string url); | 34 | void RegisterNewReceiver(IScriptModule scriptEngine, UUID channelID, UUID objectID, UUID itemID, string url); |
35 | void ScriptRemoved(UUID itemID); | 35 | void ScriptRemoved(UUID itemID); |
36 | void ObjectRemoved(UUID objectID); | 36 | void ObjectRemoved(UUID objectID); |
37 | void UnRegisterReceiver(string channelID, UUID itemID); | ||
37 | } | 38 | } |
38 | } | 39 | } |
diff --git a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs index 9458079..d18571c 100644 --- a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs +++ b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs | |||
@@ -26,9 +26,10 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Threading; | ||
30 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Linq; | ||
31 | using System.Reflection; | 31 | using System.Reflection; |
32 | using System.Threading; | ||
32 | using log4net; | 33 | using log4net; |
33 | using OpenMetaverse; | 34 | using OpenMetaverse; |
34 | using OpenSim.Framework; | 35 | using OpenSim.Framework; |
@@ -113,6 +114,8 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
113 | if (m_scenePresence.IsChildAgent) | 114 | if (m_scenePresence.IsChildAgent) |
114 | return; | 115 | return; |
115 | 116 | ||
117 | // m_log.DebugFormat("[SCENE PRESENCE ANIMATOR]: Removing animation {0} for {1}", animID, m_scenePresence.Name); | ||
118 | |||
116 | if (m_animations.Remove(animID)) | 119 | if (m_animations.Remove(animID)) |
117 | SendAnimPack(); | 120 | SendAnimPack(); |
118 | } | 121 | } |
@@ -519,6 +522,12 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
519 | if (m_scenePresence.IsChildAgent) | 522 | if (m_scenePresence.IsChildAgent) |
520 | return; | 523 | return; |
521 | 524 | ||
525 | // m_log.DebugFormat( | ||
526 | // "[SCENE PRESENCE ANIMATOR]: Sending anim pack with animations '{0}', sequence '{1}', uuids '{2}'", | ||
527 | // string.Join(",", Array.ConvertAll<UUID, string>(animations, a => a.ToString())), | ||
528 | // string.Join(",", Array.ConvertAll<int, string>(seqs, s => s.ToString())), | ||
529 | // string.Join(",", Array.ConvertAll<UUID, string>(objectIDs, o => o.ToString()))); | ||
530 | |||
522 | m_scenePresence.Scene.ForEachClient( | 531 | m_scenePresence.Scene.ForEachClient( |
523 | delegate(IClientAPI client) | 532 | delegate(IClientAPI client) |
524 | { | 533 | { |
diff --git a/OpenSim/Region/Framework/Scenes/EntityManager.cs b/OpenSim/Region/Framework/Scenes/EntityManager.cs index b788a3c..7181313 100644 --- a/OpenSim/Region/Framework/Scenes/EntityManager.cs +++ b/OpenSim/Region/Framework/Scenes/EntityManager.cs | |||
@@ -31,6 +31,7 @@ using System.Collections.Generic; | |||
31 | using System.Reflection; | 31 | using System.Reflection; |
32 | using log4net; | 32 | using log4net; |
33 | using OpenMetaverse; | 33 | using OpenMetaverse; |
34 | using OpenSim.Framework; | ||
34 | 35 | ||
35 | namespace OpenSim.Region.Framework.Scenes | 36 | namespace OpenSim.Region.Framework.Scenes |
36 | { | 37 | { |
@@ -38,7 +39,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
38 | { | 39 | { |
39 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 40 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
40 | 41 | ||
41 | private readonly DoubleDictionary<UUID, uint, EntityBase> m_entities = new DoubleDictionary<UUID, uint, EntityBase>(); | 42 | private readonly DoubleDictionaryThreadAbortSafe<UUID, uint, EntityBase> m_entities |
43 | = new DoubleDictionaryThreadAbortSafe<UUID, uint, EntityBase>(); | ||
42 | 44 | ||
43 | public int Count | 45 | public int Count |
44 | { | 46 | { |
diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index c9d1205..65c50bf 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs | |||
@@ -683,12 +683,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
683 | itemCopy.SalePrice = item.SalePrice; | 683 | itemCopy.SalePrice = item.SalePrice; |
684 | itemCopy.SaleType = item.SaleType; | 684 | itemCopy.SaleType = item.SaleType; |
685 | 685 | ||
686 | if (AddInventoryItem(itemCopy)) | 686 | IInventoryAccessModule invAccess = RequestModuleInterface<IInventoryAccessModule>(); |
687 | { | 687 | if (invAccess != null) |
688 | IInventoryAccessModule invAccess = RequestModuleInterface<IInventoryAccessModule>(); | 688 | invAccess.TransferInventoryAssets(itemCopy, senderId, recipient); |
689 | if (invAccess != null) | 689 | AddInventoryItem(itemCopy); |
690 | Util.FireAndForget(delegate { invAccess.TransferInventoryAssets(itemCopy, senderId, recipient); }); | ||
691 | } | ||
692 | 690 | ||
693 | if (!Permissions.BypassPermissions()) | 691 | if (!Permissions.BypassPermissions()) |
694 | { | 692 | { |
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index c99e37e..2a1949d 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs | |||
@@ -762,7 +762,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
762 | // | 762 | // |
763 | // Out of memory | 763 | // Out of memory |
764 | // Operating system has killed the plugin | 764 | // Operating system has killed the plugin |
765 | m_sceneGraph.UnRecoverableError += RestartNow; | 765 | m_sceneGraph.UnRecoverableError |
766 | += () => | ||
767 | { | ||
768 | m_log.ErrorFormat("[SCENE]: Restarting region {0} due to unrecoverable physics crash", Name); | ||
769 | RestartNow(); | ||
770 | }; | ||
766 | 771 | ||
767 | RegisterDefaultSceneEvents(); | 772 | RegisterDefaultSceneEvents(); |
768 | 773 | ||
@@ -6036,10 +6041,17 @@ Environment.Exit(1); | |||
6036 | GC.Collect(); | 6041 | GC.Collect(); |
6037 | } | 6042 | } |
6038 | 6043 | ||
6039 | // Wrappers to get physics modules retrieve assets. Has to be done this way | 6044 | /// <summary> |
6040 | // because we can't assign the asset service to physics directly - at the | 6045 | /// Wrappers to get physics modules retrieve assets. |
6041 | // time physics are instantiated it's not registered but it will be by | 6046 | /// </summary> |
6042 | // the time the first prim exists. | 6047 | /// <remarks> |
6048 | /// Has to be done this way | ||
6049 | /// because we can't assign the asset service to physics directly - at the | ||
6050 | /// time physics are instantiated it's not registered but it will be by | ||
6051 | /// the time the first prim exists. | ||
6052 | /// </remarks> | ||
6053 | /// <param name="assetID"></param> | ||
6054 | /// <param name="callback"></param> | ||
6043 | public void PhysicsRequestAsset(UUID assetID, AssetReceivedDelegate callback) | 6055 | public void PhysicsRequestAsset(UUID assetID, AssetReceivedDelegate callback) |
6044 | { | 6056 | { |
6045 | AssetService.Get(assetID.ToString(), callback, PhysicsAssetReceived); | 6057 | AssetService.Get(assetID.ToString(), callback, PhysicsAssetReceived); |
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 4ad8b11..2051a53 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | |||
@@ -505,11 +505,19 @@ namespace OpenSim.Region.Framework.Scenes | |||
505 | 505 | ||
506 | if (Scene != null) | 506 | if (Scene != null) |
507 | { | 507 | { |
508 | // if ((Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W) | 508 | if ( |
509 | // || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S)) | 509 | // (Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) |
510 | // && !IsAttachmentCheckFull() && (!Scene.LoadingPrims)) | 510 | // || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W) |
511 | if ((Scene.TestBorderCross(val, Cardinals.E) || Scene.TestBorderCross(val, Cardinals.W) | 511 | // || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) |
512 | || Scene.TestBorderCross(val, Cardinals.N) || Scene.TestBorderCross(val, Cardinals.S)) | 512 | // || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S)) |
513 | // Experimental change for better border crossings. | ||
514 | // The commented out original lines above would, it seems, trigger | ||
515 | // a border crossing a little early or late depending on which | ||
516 | // direction the object was moving. | ||
517 | (Scene.TestBorderCross(val, Cardinals.E) | ||
518 | || Scene.TestBorderCross(val, Cardinals.W) | ||
519 | || Scene.TestBorderCross(val, Cardinals.N) | ||
520 | || Scene.TestBorderCross(val, Cardinals.S)) | ||
513 | && !IsAttachmentCheckFull() && (!Scene.LoadingPrims)) | 521 | && !IsAttachmentCheckFull() && (!Scene.LoadingPrims)) |
514 | { | 522 | { |
515 | IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>(); | 523 | IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>(); |
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 2191cfa..c746690 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | |||
@@ -2895,11 +2895,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
2895 | 2895 | ||
2896 | public void PhysicsOutOfBounds(Vector3 pos) | 2896 | public void PhysicsOutOfBounds(Vector3 pos) |
2897 | { | 2897 | { |
2898 | m_log.Error("[PHYSICS]: Physical Object went out of bounds."); | 2898 | // Note: This is only being called on the root prim at this time. |
2899 | |||
2900 | m_log.ErrorFormat( | ||
2901 | "[SCENE OBJECT PART]: Physical object {0}, localID {1} went out of bounds at {2} in {3}. Stopping at {4} and making non-physical.", | ||
2902 | Name, LocalId, pos, ParentGroup.Scene.Name, AbsolutePosition); | ||
2899 | 2903 | ||
2900 | RemFlag(PrimFlags.Physics); | 2904 | RemFlag(PrimFlags.Physics); |
2901 | DoPhysicsPropertyUpdate(false, true); | 2905 | DoPhysicsPropertyUpdate(false, true); |
2902 | //ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor); | ||
2903 | } | 2906 | } |
2904 | 2907 | ||
2905 | public void PhysicsRequestingTerseUpdate() | 2908 | public void PhysicsRequestingTerseUpdate() |
@@ -4549,7 +4552,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
4549 | if (ParentGroup.RootPart == this) | 4552 | if (ParentGroup.RootPart == this) |
4550 | AngularVelocity = new Vector3(0, 0, 0); | 4553 | AngularVelocity = new Vector3(0, 0, 0); |
4551 | } | 4554 | } |
4552 | else | 4555 | else if (SetVD != wasVD) |
4553 | { | 4556 | { |
4554 | if (ParentGroup.Scene.CollidablePrims) | 4557 | if (ParentGroup.Scene.CollidablePrims) |
4555 | { | 4558 | { |
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 7ff163b..041eac2 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs | |||
@@ -216,8 +216,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
216 | 216 | ||
217 | private Quaternion m_headrotation = Quaternion.Identity; | 217 | private Quaternion m_headrotation = Quaternion.Identity; |
218 | 218 | ||
219 | private string m_nextSitAnimation = String.Empty; | ||
220 | |||
221 | //PauPaw:Proper PID Controler for autopilot************ | 219 | //PauPaw:Proper PID Controler for autopilot************ |
222 | public bool MovingToTarget { get; private set; } | 220 | public bool MovingToTarget { get; private set; } |
223 | public Vector3 MoveToPositionTarget { get; private set; } | 221 | public Vector3 MoveToPositionTarget { get; private set; } |
@@ -2174,25 +2172,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
2174 | StandUp(); | 2172 | StandUp(); |
2175 | } | 2173 | } |
2176 | 2174 | ||
2177 | // if (!String.IsNullOrEmpty(sitAnimation)) | ||
2178 | // { | ||
2179 | // m_nextSitAnimation = sitAnimation; | ||
2180 | // } | ||
2181 | // else | ||
2182 | // { | ||
2183 | m_nextSitAnimation = "SIT"; | ||
2184 | // } | ||
2185 | |||
2186 | //SceneObjectPart part = m_scene.GetSceneObjectPart(targetID); | ||
2187 | SceneObjectPart part = FindNextAvailableSitTarget(targetID); | 2175 | SceneObjectPart part = FindNextAvailableSitTarget(targetID); |
2188 | 2176 | ||
2189 | if (part != null) | 2177 | if (part != null) |
2190 | { | 2178 | { |
2191 | if (!String.IsNullOrEmpty(part.SitAnimation)) | ||
2192 | { | ||
2193 | m_nextSitAnimation = part.SitAnimation; | ||
2194 | } | ||
2195 | |||
2196 | m_requestedSitTargetID = part.LocalId; | 2179 | m_requestedSitTargetID = part.LocalId; |
2197 | m_requestedSitTargetUUID = targetID; | 2180 | m_requestedSitTargetUUID = targetID; |
2198 | 2181 | ||
@@ -2264,18 +2247,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
2264 | 2247 | ||
2265 | public void HandleAgentSit(IClientAPI remoteClient, UUID agentID) | 2248 | public void HandleAgentSit(IClientAPI remoteClient, UUID agentID) |
2266 | { | 2249 | { |
2267 | if (!String.IsNullOrEmpty(m_nextSitAnimation)) | ||
2268 | { | ||
2269 | HandleAgentSit(remoteClient, agentID, m_nextSitAnimation); | ||
2270 | } | ||
2271 | else | ||
2272 | { | ||
2273 | HandleAgentSit(remoteClient, agentID, "SIT"); | ||
2274 | } | ||
2275 | } | ||
2276 | |||
2277 | public void HandleAgentSit(IClientAPI remoteClient, UUID agentID, string sitAnimation) | ||
2278 | { | ||
2279 | SceneObjectPart part = m_scene.GetSceneObjectPart(m_requestedSitTargetID); | 2250 | SceneObjectPart part = m_scene.GetSceneObjectPart(m_requestedSitTargetID); |
2280 | 2251 | ||
2281 | if (part != null) | 2252 | if (part != null) |
@@ -2347,7 +2318,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
2347 | 2318 | ||
2348 | Velocity = Vector3.Zero; | 2319 | Velocity = Vector3.Zero; |
2349 | RemoveFromPhysicalScene(); | 2320 | RemoveFromPhysicalScene(); |
2350 | 2321 | ||
2322 | String sitAnimation = "SIT"; | ||
2323 | if (!String.IsNullOrEmpty(part.SitAnimation)) | ||
2324 | { | ||
2325 | sitAnimation = part.SitAnimation; | ||
2326 | } | ||
2351 | Animator.TrySetMovementAnimation(sitAnimation); | 2327 | Animator.TrySetMovementAnimation(sitAnimation); |
2352 | SendAvatarDataToAllAgents(); | 2328 | SendAvatarDataToAllAgents(); |
2353 | } | 2329 | } |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/BorderTests.cs b/OpenSim/Region/Framework/Scenes/Tests/BorderTests.cs index 4a21dc9..e209221 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/BorderTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/BorderTests.cs | |||
@@ -37,7 +37,7 @@ using OpenSim.Tests.Common; | |||
37 | namespace OpenSim.Region.Framework.Scenes.Tests | 37 | namespace OpenSim.Region.Framework.Scenes.Tests |
38 | { | 38 | { |
39 | [TestFixture] | 39 | [TestFixture] |
40 | public class BorderTests | 40 | public class BorderTests : OpenSimTestCase |
41 | { | 41 | { |
42 | [Test] | 42 | [Test] |
43 | public void TestCross() | 43 | public void TestCross() |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/EntityManagerTests.cs b/OpenSim/Region/Framework/Scenes/Tests/EntityManagerTests.cs index ea9fc93..766ce83 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/EntityManagerTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/EntityManagerTests.cs | |||
@@ -41,7 +41,7 @@ using OpenSim.Tests.Common; | |||
41 | namespace OpenSim.Region.Framework.Scenes.Tests | 41 | namespace OpenSim.Region.Framework.Scenes.Tests |
42 | { | 42 | { |
43 | [TestFixture, LongRunning] | 43 | [TestFixture, LongRunning] |
44 | public class EntityManagerTests | 44 | public class EntityManagerTests : OpenSimTestCase |
45 | { | 45 | { |
46 | static public Random random; | 46 | static public Random random; |
47 | SceneObjectGroup found; | 47 | SceneObjectGroup found; |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneGraphTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneGraphTests.cs index d23c965..575a081 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneGraphTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneGraphTests.cs | |||
@@ -40,7 +40,7 @@ using OpenSim.Tests.Common.Mock; | |||
40 | namespace OpenSim.Region.Framework.Scenes.Tests | 40 | namespace OpenSim.Region.Framework.Scenes.Tests |
41 | { | 41 | { |
42 | [TestFixture] | 42 | [TestFixture] |
43 | public class SceneGraphTests | 43 | public class SceneGraphTests : OpenSimTestCase |
44 | { | 44 | { |
45 | [Test] | 45 | [Test] |
46 | public void TestDuplicateObject() | 46 | public void TestDuplicateObject() |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneManagerTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneManagerTests.cs index ab56f4e..2d831fa 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneManagerTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneManagerTests.cs | |||
@@ -41,7 +41,7 @@ using OpenSim.Tests.Common.Mock; | |||
41 | namespace OpenSim.Region.Framework.Scenes.Tests | 41 | namespace OpenSim.Region.Framework.Scenes.Tests |
42 | { | 42 | { |
43 | [TestFixture] | 43 | [TestFixture] |
44 | public class SceneManagerTests | 44 | public class SceneManagerTests : OpenSimTestCase |
45 | { | 45 | { |
46 | [Test] | 46 | [Test] |
47 | public void TestClose() | 47 | public void TestClose() |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs index 5b334c6..a07d64c 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs | |||
@@ -29,6 +29,7 @@ using System; | |||
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Reflection; | 30 | using System.Reflection; |
31 | using System.Threading; | 31 | using System.Threading; |
32 | using Nini.Config; | ||
32 | using NUnit.Framework; | 33 | using NUnit.Framework; |
33 | using OpenMetaverse; | 34 | using OpenMetaverse; |
34 | using OpenSim.Framework; | 35 | using OpenSim.Framework; |
@@ -182,6 +183,10 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
182 | /// <summary> | 183 | /// <summary> |
183 | /// Test deleting an object from a scene. | 184 | /// Test deleting an object from a scene. |
184 | /// </summary> | 185 | /// </summary> |
186 | /// <remarks> | ||
187 | /// This is the most basic form of delete. For all more sophisticated forms of derez (done asynchrnously | ||
188 | /// and where object can be taken to user inventory, etc.), see SceneObjectDeRezTests. | ||
189 | /// </remarks> | ||
185 | [Test] | 190 | [Test] |
186 | public void TestDeleteSceneObject() | 191 | public void TestDeleteSceneObject() |
187 | { | 192 | { |
@@ -201,100 +206,6 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
201 | } | 206 | } |
202 | 207 | ||
203 | /// <summary> | 208 | /// <summary> |
204 | /// Test deleting an object asynchronously | ||
205 | /// </summary> | ||
206 | [Test] | ||
207 | public void TestDeleteSceneObjectAsync() | ||
208 | { | ||
209 | TestHelpers.InMethod(); | ||
210 | //log4net.Config.XmlConfigurator.Configure(); | ||
211 | |||
212 | UUID agentId = UUID.Parse("00000000-0000-0000-0000-000000000001"); | ||
213 | |||
214 | TestScene scene = new SceneHelpers().SetupScene(); | ||
215 | |||
216 | // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. | ||
217 | AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter; | ||
218 | sogd.Enabled = false; | ||
219 | |||
220 | SceneObjectGroup so = SceneHelpers.AddSceneObject(scene); | ||
221 | |||
222 | IClientAPI client = SceneHelpers.AddScenePresence(scene, agentId).ControllingClient; | ||
223 | scene.DeRezObjects(client, new System.Collections.Generic.List<uint>() { so.LocalId }, UUID.Zero, DeRezAction.Delete, UUID.Zero); | ||
224 | |||
225 | SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId); | ||
226 | |||
227 | Assert.That(retrievedPart, Is.Not.Null); | ||
228 | |||
229 | Assert.That(so.IsDeleted, Is.False); | ||
230 | |||
231 | sogd.InventoryDeQueueAndDelete(); | ||
232 | |||
233 | Assert.That(so.IsDeleted, Is.True); | ||
234 | |||
235 | SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId); | ||
236 | Assert.That(retrievedPart2, Is.Null); | ||
237 | } | ||
238 | |||
239 | /// <summary> | ||
240 | /// Test deleting an object asynchronously to user inventory. | ||
241 | /// </summary> | ||
242 | // [Test] | ||
243 | public void TestDeleteSceneObjectAsyncToUserInventory() | ||
244 | { | ||
245 | TestHelpers.InMethod(); | ||
246 | TestHelpers.EnableLogging(); | ||
247 | |||
248 | UUID agentId = UUID.Parse("00000000-0000-0000-0000-000000000001"); | ||
249 | string myObjectName = "Fred"; | ||
250 | |||
251 | TestScene scene = new SceneHelpers().SetupScene(); | ||
252 | |||
253 | // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. | ||
254 | AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter; | ||
255 | sogd.Enabled = false; | ||
256 | |||
257 | SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, myObjectName, agentId); | ||
258 | |||
259 | // Assert.That( | ||
260 | // scene.CommsManager.UserAdminService.AddUser( | ||
261 | // "Bob", "Hoskins", "test", "test@test.com", 1000, 1000, agentId), | ||
262 | // Is.EqualTo(agentId)); | ||
263 | |||
264 | UserAccount ua = UserAccountHelpers.CreateUserWithInventory(scene, agentId); | ||
265 | InventoryFolderBase folder1 | ||
266 | = UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, ua.PrincipalID, "folder1"); | ||
267 | |||
268 | IClientAPI client = SceneHelpers.AddScenePresence(scene, agentId).ControllingClient; | ||
269 | scene.DeRezObjects(client, new List<uint>() { so.LocalId }, UUID.Zero, DeRezAction.Take, folder1.ID); | ||
270 | |||
271 | SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId); | ||
272 | |||
273 | Assert.That(retrievedPart, Is.Not.Null); | ||
274 | Assert.That(so.IsDeleted, Is.False); | ||
275 | |||
276 | sogd.InventoryDeQueueAndDelete(); | ||
277 | |||
278 | Assert.That(so.IsDeleted, Is.True); | ||
279 | |||
280 | SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId); | ||
281 | Assert.That(retrievedPart2, Is.Null); | ||
282 | |||
283 | // SceneSetupHelpers.DeleteSceneObjectAsync(scene, part, DeRezAction.Take, userInfo.RootFolder.ID, client); | ||
284 | |||
285 | InventoryItemBase retrievedItem | ||
286 | = UserInventoryHelpers.GetInventoryItem( | ||
287 | scene.InventoryService, ua.PrincipalID, "folder1/" + myObjectName); | ||
288 | |||
289 | // Check that we now have the taken part in our inventory | ||
290 | Assert.That(retrievedItem, Is.Not.Null); | ||
291 | |||
292 | // Check that the taken part has actually disappeared | ||
293 | // SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId); | ||
294 | // Assert.That(retrievedPart, Is.Null); | ||
295 | } | ||
296 | |||
297 | /// <summary> | ||
298 | /// Changing a scene object uuid changes the root part uuid. This is a valid operation if the object is not | 209 | /// Changing a scene object uuid changes the root part uuid. This is a valid operation if the object is not |
299 | /// in a scene and is useful if one wants to supply a UUID directly rather than use the one generated by | 210 | /// in a scene and is useful if one wants to supply a UUID directly rather than use the one generated by |
300 | /// OpenSim. | 211 | /// OpenSim. |
@@ -329,4 +240,4 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
329 | Assert.That(sog.Parts.Length, Is.EqualTo(2)); | 240 | Assert.That(sog.Parts.Length, Is.EqualTo(2)); |
330 | } | 241 | } |
331 | } | 242 | } |
332 | } | 243 | } \ No newline at end of file |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs index 0076f41..c1522e7 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs | |||
@@ -33,22 +33,24 @@ using NUnit.Framework; | |||
33 | using OpenMetaverse; | 33 | using OpenMetaverse; |
34 | using OpenSim.Framework; | 34 | using OpenSim.Framework; |
35 | using OpenSim.Framework.Communications; | 35 | using OpenSim.Framework.Communications; |
36 | using OpenSim.Region.CoreModules.Framework.InventoryAccess; | ||
36 | using OpenSim.Region.CoreModules.World.Permissions; | 37 | using OpenSim.Region.CoreModules.World.Permissions; |
37 | using OpenSim.Region.Framework.Scenes; | 38 | using OpenSim.Region.Framework.Scenes; |
39 | using OpenSim.Services.Interfaces; | ||
38 | using OpenSim.Tests.Common; | 40 | using OpenSim.Tests.Common; |
39 | using OpenSim.Tests.Common.Mock; | 41 | using OpenSim.Tests.Common.Mock; |
40 | 42 | ||
41 | namespace OpenSim.Region.Framework.Scenes.Tests | 43 | namespace OpenSim.Region.Framework.Scenes.Tests |
42 | { | 44 | { |
43 | /// <summary> | 45 | /// <summary> |
44 | /// Tests derez of scene objects by users. | 46 | /// Tests derez of scene objects. |
45 | /// </summary> | 47 | /// </summary> |
46 | /// <remarks> | 48 | /// <remarks> |
47 | /// This is at a level above the SceneObjectBasicTests, which act on the scene directly. | 49 | /// This is at a level above the SceneObjectBasicTests, which act on the scene directly. |
48 | /// TODO: These tests are very incomplete - they only test for a few conditions. | 50 | /// TODO: These tests are incomplete - need to test more kinds of derez (e.g. return object). |
49 | /// </remarks> | 51 | /// </remarks> |
50 | [TestFixture] | 52 | [TestFixture] |
51 | public class SceneObjectDeRezTests | 53 | public class SceneObjectDeRezTests : OpenSimTestCase |
52 | { | 54 | { |
53 | /// <summary> | 55 | /// <summary> |
54 | /// Test deleting an object from a scene. | 56 | /// Test deleting an object from a scene. |
@@ -76,14 +78,20 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
76 | = new SceneObjectPart(userId, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero); | 78 | = new SceneObjectPart(userId, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero); |
77 | part.Name = "obj1"; | 79 | part.Name = "obj1"; |
78 | scene.AddNewSceneObject(new SceneObjectGroup(part), false); | 80 | scene.AddNewSceneObject(new SceneObjectGroup(part), false); |
81 | |||
79 | List<uint> localIds = new List<uint>(); | 82 | List<uint> localIds = new List<uint>(); |
80 | localIds.Add(part.LocalId); | 83 | localIds.Add(part.LocalId); |
81 | |||
82 | scene.DeRezObjects(client, localIds, UUID.Zero, DeRezAction.Delete, UUID.Zero); | 84 | scene.DeRezObjects(client, localIds, UUID.Zero, DeRezAction.Delete, UUID.Zero); |
85 | |||
86 | // Check that object isn't deleted until we crank the sogd handle. | ||
87 | SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId); | ||
88 | Assert.That(retrievedPart, Is.Not.Null); | ||
89 | Assert.That(retrievedPart.ParentGroup.IsDeleted, Is.False); | ||
90 | |||
83 | sogd.InventoryDeQueueAndDelete(); | 91 | sogd.InventoryDeQueueAndDelete(); |
84 | 92 | ||
85 | SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId); | 93 | SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(part.LocalId); |
86 | Assert.That(retrievedPart, Is.Null); | 94 | Assert.That(retrievedPart2, Is.Null); |
87 | } | 95 | } |
88 | 96 | ||
89 | /// <summary> | 97 | /// <summary> |
@@ -124,6 +132,67 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
124 | // Object should still be in the scene. | 132 | // Object should still be in the scene. |
125 | SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId); | 133 | SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId); |
126 | Assert.That(retrievedPart.UUID, Is.EqualTo(part.UUID)); | 134 | Assert.That(retrievedPart.UUID, Is.EqualTo(part.UUID)); |
127 | } | 135 | } |
136 | |||
137 | /// <summary> | ||
138 | /// Test deleting an object asynchronously to user inventory. | ||
139 | /// </summary> | ||
140 | [Test] | ||
141 | public void TestDeleteSceneObjectAsyncToUserInventory() | ||
142 | { | ||
143 | TestHelpers.InMethod(); | ||
144 | // TestHelpers.EnableLogging(); | ||
145 | |||
146 | UUID agentId = UUID.Parse("00000000-0000-0000-0000-000000000001"); | ||
147 | string myObjectName = "Fred"; | ||
148 | |||
149 | TestScene scene = new SceneHelpers().SetupScene(); | ||
150 | |||
151 | IConfigSource configSource = new IniConfigSource(); | ||
152 | IConfig config = configSource.AddConfig("Modules"); | ||
153 | config.Set("InventoryAccessModule", "BasicInventoryAccessModule"); | ||
154 | SceneHelpers.SetupSceneModules( | ||
155 | scene, configSource, new object[] { new BasicInventoryAccessModule() }); | ||
156 | |||
157 | SceneHelpers.SetupSceneModules(scene, new object[] { }); | ||
158 | |||
159 | // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. | ||
160 | AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter; | ||
161 | sogd.Enabled = false; | ||
162 | |||
163 | SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, myObjectName, agentId); | ||
164 | |||
165 | UserAccount ua = UserAccountHelpers.CreateUserWithInventory(scene, agentId); | ||
166 | InventoryFolderBase folder1 | ||
167 | = UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, ua.PrincipalID, "folder1"); | ||
168 | |||
169 | IClientAPI client = SceneHelpers.AddScenePresence(scene, agentId).ControllingClient; | ||
170 | scene.DeRezObjects(client, new List<uint>() { so.LocalId }, UUID.Zero, DeRezAction.Take, folder1.ID); | ||
171 | |||
172 | SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId); | ||
173 | |||
174 | Assert.That(retrievedPart, Is.Not.Null); | ||
175 | Assert.That(so.IsDeleted, Is.False); | ||
176 | |||
177 | sogd.InventoryDeQueueAndDelete(); | ||
178 | |||
179 | Assert.That(so.IsDeleted, Is.True); | ||
180 | |||
181 | SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId); | ||
182 | Assert.That(retrievedPart2, Is.Null); | ||
183 | |||
184 | // SceneSetupHelpers.DeleteSceneObjectAsync(scene, part, DeRezAction.Take, userInfo.RootFolder.ID, client); | ||
185 | |||
186 | InventoryItemBase retrievedItem | ||
187 | = UserInventoryHelpers.GetInventoryItem( | ||
188 | scene.InventoryService, ua.PrincipalID, "folder1/" + myObjectName); | ||
189 | |||
190 | // Check that we now have the taken part in our inventory | ||
191 | Assert.That(retrievedItem, Is.Not.Null); | ||
192 | |||
193 | // Check that the taken part has actually disappeared | ||
194 | // SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId); | ||
195 | // Assert.That(retrievedPart, Is.Null); | ||
196 | } | ||
128 | } | 197 | } |
129 | } \ No newline at end of file | 198 | } \ No newline at end of file |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs index 0e525c9..9378e20 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs | |||
@@ -40,7 +40,7 @@ using log4net; | |||
40 | namespace OpenSim.Region.Framework.Scenes.Tests | 40 | namespace OpenSim.Region.Framework.Scenes.Tests |
41 | { | 41 | { |
42 | [TestFixture] | 42 | [TestFixture] |
43 | public class SceneObjectLinkingTests | 43 | public class SceneObjectLinkingTests : OpenSimTestCase |
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 | ||
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectResizeTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectResizeTests.cs index e931859..1182c96 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectResizeTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectResizeTests.cs | |||
@@ -41,7 +41,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
41 | /// Basic scene object resize tests | 41 | /// Basic scene object resize tests |
42 | /// </summary> | 42 | /// </summary> |
43 | [TestFixture] | 43 | [TestFixture] |
44 | public class SceneObjectResizeTests | 44 | public class SceneObjectResizeTests : OpenSimTestCase |
45 | { | 45 | { |
46 | /// <summary> | 46 | /// <summary> |
47 | /// Test resizing an object | 47 | /// Test resizing an object |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectScriptTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectScriptTests.cs index d2361f8..a58e735 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectScriptTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectScriptTests.cs | |||
@@ -40,7 +40,7 @@ using OpenSim.Tests.Common.Mock; | |||
40 | namespace OpenSim.Region.Framework.Scenes.Tests | 40 | namespace OpenSim.Region.Framework.Scenes.Tests |
41 | { | 41 | { |
42 | [TestFixture] | 42 | [TestFixture] |
43 | public class SceneObjectScriptTests | 43 | public class SceneObjectScriptTests : OpenSimTestCase |
44 | { | 44 | { |
45 | [Test] | 45 | [Test] |
46 | public void TestAddScript() | 46 | public void TestAddScript() |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectSpatialTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectSpatialTests.cs index 6d255aa..abaa1d1 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectSpatialTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectSpatialTests.cs | |||
@@ -42,14 +42,16 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
42 | /// Spatial scene object tests (will eventually cover root and child part position, rotation properties, etc.) | 42 | /// Spatial scene object tests (will eventually cover root and child part position, rotation properties, etc.) |
43 | /// </summary> | 43 | /// </summary> |
44 | [TestFixture] | 44 | [TestFixture] |
45 | public class SceneObjectSpatialTests | 45 | public class SceneObjectSpatialTests : OpenSimTestCase |
46 | { | 46 | { |
47 | TestScene m_scene; | 47 | TestScene m_scene; |
48 | UUID m_ownerId = TestHelpers.ParseTail(0x1); | 48 | UUID m_ownerId = TestHelpers.ParseTail(0x1); |
49 | 49 | ||
50 | [SetUp] | 50 | [SetUp] |
51 | public void SetUp() | 51 | public override void SetUp() |
52 | { | 52 | { |
53 | base.SetUp(); | ||
54 | |||
53 | m_scene = new SceneHelpers().SetupScene(); | 55 | m_scene = new SceneHelpers().SetupScene(); |
54 | } | 56 | } |
55 | 57 | ||
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs index 742c769..8eb3191 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs | |||
@@ -42,7 +42,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
42 | /// Basic scene object status tests | 42 | /// Basic scene object status tests |
43 | /// </summary> | 43 | /// </summary> |
44 | [TestFixture] | 44 | [TestFixture] |
45 | public class SceneObjectStatusTests | 45 | public class SceneObjectStatusTests : OpenSimTestCase |
46 | { | 46 | { |
47 | private TestScene m_scene; | 47 | private TestScene m_scene; |
48 | private UUID m_ownerId = TestHelpers.ParseTail(0x1); | 48 | private UUID m_ownerId = TestHelpers.ParseTail(0x1); |
@@ -78,6 +78,26 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
78 | } | 78 | } |
79 | 79 | ||
80 | [Test] | 80 | [Test] |
81 | public void TestSetNonPhysicsVolumeDetectSinglePrim() | ||
82 | { | ||
83 | TestHelpers.InMethod(); | ||
84 | |||
85 | m_scene.AddSceneObject(m_so1); | ||
86 | |||
87 | SceneObjectPart rootPart = m_so1.RootPart; | ||
88 | Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); | ||
89 | |||
90 | m_so1.ScriptSetVolumeDetect(true); | ||
91 | |||
92 | // Console.WriteLine("so.RootPart.Flags [{0}]", so.RootPart.Flags); | ||
93 | Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Phantom)); | ||
94 | |||
95 | m_so1.ScriptSetVolumeDetect(false); | ||
96 | |||
97 | Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); | ||
98 | } | ||
99 | |||
100 | [Test] | ||
81 | public void TestSetPhysicsSinglePrim() | 101 | public void TestSetPhysicsSinglePrim() |
82 | { | 102 | { |
83 | TestHelpers.InMethod(); | 103 | TestHelpers.InMethod(); |
@@ -89,13 +109,32 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
89 | 109 | ||
90 | m_so1.ScriptSetPhysicsStatus(true); | 110 | m_so1.ScriptSetPhysicsStatus(true); |
91 | 111 | ||
92 | // Console.WriteLine("so.RootPart.Flags [{0}]", so.RootPart.Flags); | ||
93 | Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Physics)); | 112 | Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Physics)); |
94 | 113 | ||
95 | m_so1.ScriptSetPhysicsStatus(false); | 114 | m_so1.ScriptSetPhysicsStatus(false); |
96 | 115 | ||
97 | Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); | 116 | Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); |
98 | } | 117 | } |
118 | |||
119 | [Test] | ||
120 | public void TestSetPhysicsVolumeDetectSinglePrim() | ||
121 | { | ||
122 | TestHelpers.InMethod(); | ||
123 | |||
124 | m_scene.AddSceneObject(m_so1); | ||
125 | |||
126 | SceneObjectPart rootPart = m_so1.RootPart; | ||
127 | Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); | ||
128 | |||
129 | m_so1.ScriptSetPhysicsStatus(true); | ||
130 | m_so1.ScriptSetVolumeDetect(true); | ||
131 | |||
132 | Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Phantom | PrimFlags.Physics)); | ||
133 | |||
134 | m_so1.ScriptSetVolumeDetect(false); | ||
135 | |||
136 | Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Physics)); | ||
137 | } | ||
99 | 138 | ||
100 | [Test] | 139 | [Test] |
101 | public void TestSetPhysicsLinkset() | 140 | public void TestSetPhysicsLinkset() |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAnimationTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAnimationTests.cs index 646e5fa..1cd8ae9 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAnimationTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAnimationTests.cs | |||
@@ -51,7 +51,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
51 | /// Scene presence animation tests | 51 | /// Scene presence animation tests |
52 | /// </summary> | 52 | /// </summary> |
53 | [TestFixture] | 53 | [TestFixture] |
54 | public class ScenePresenceAnimationTests | 54 | public class ScenePresenceAnimationTests : OpenSimTestCase |
55 | { | 55 | { |
56 | [Test] | 56 | [Test] |
57 | public void TestFlyingAnimation() | 57 | public void TestFlyingAnimation() |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs index 1d1ff88..d80afd3 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs | |||
@@ -42,7 +42,7 @@ using OpenSim.Tests.Common.Mock; | |||
42 | namespace OpenSim.Region.Framework.Scenes.Tests | 42 | namespace OpenSim.Region.Framework.Scenes.Tests |
43 | { | 43 | { |
44 | [TestFixture] | 44 | [TestFixture] |
45 | public class ScenePresenceAutopilotTests | 45 | public class ScenePresenceAutopilotTests : OpenSimTestCase |
46 | { | 46 | { |
47 | private TestScene m_scene; | 47 | private TestScene m_scene; |
48 | 48 | ||
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceSitTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceSitTests.cs index 493ab70..acaeb90 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceSitTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceSitTests.cs | |||
@@ -43,7 +43,7 @@ using System.Threading; | |||
43 | namespace OpenSim.Region.Framework.Scenes.Tests | 43 | namespace OpenSim.Region.Framework.Scenes.Tests |
44 | { | 44 | { |
45 | [TestFixture] | 45 | [TestFixture] |
46 | public class ScenePresenceSitTests | 46 | public class ScenePresenceSitTests : OpenSimTestCase |
47 | { | 47 | { |
48 | private TestScene m_scene; | 48 | private TestScene m_scene; |
49 | private ScenePresence m_sp; | 49 | private ScenePresence m_sp; |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs index 37b5184..8dd1f3d 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs | |||
@@ -49,7 +49,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
49 | /// Teleport tests in a standalone OpenSim | 49 | /// Teleport tests in a standalone OpenSim |
50 | /// </summary> | 50 | /// </summary> |
51 | [TestFixture] | 51 | [TestFixture] |
52 | public class ScenePresenceTeleportTests | 52 | public class ScenePresenceTeleportTests : OpenSimTestCase |
53 | { | 53 | { |
54 | [TestFixtureSetUp] | 54 | [TestFixtureSetUp] |
55 | public void FixtureInit() | 55 | public void FixtureInit() |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs index ac3da1e..9d8eb0b 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs | |||
@@ -50,7 +50,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
50 | /// Scene presence tests | 50 | /// Scene presence tests |
51 | /// </summary> | 51 | /// </summary> |
52 | [TestFixture] | 52 | [TestFixture] |
53 | public class SceneTests | 53 | public class SceneTests : OpenSimTestCase |
54 | { | 54 | { |
55 | /// <summary> | 55 | /// <summary> |
56 | /// Very basic scene update test. Should become more elaborate with time. | 56 | /// Very basic scene update test. Should become more elaborate with time. |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs b/OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs index a51e4e3..0b461f5 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs | |||
@@ -50,7 +50,7 @@ using OpenSim.Tests.Common.Mock; | |||
50 | namespace OpenSim.Region.Framework.Tests | 50 | namespace OpenSim.Region.Framework.Tests |
51 | { | 51 | { |
52 | [TestFixture] | 52 | [TestFixture] |
53 | public class TaskInventoryTests | 53 | public class TaskInventoryTests : OpenSimTestCase |
54 | { | 54 | { |
55 | [Test] | 55 | [Test] |
56 | public void TestAddTaskInventoryItem() | 56 | public void TestAddTaskInventoryItem() |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs b/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs index 198e487..dd27294 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs | |||
@@ -38,7 +38,7 @@ using OpenSim.Tests.Common.Mock; | |||
38 | namespace OpenSim.Region.Framework.Scenes.Tests | 38 | namespace OpenSim.Region.Framework.Scenes.Tests |
39 | { | 39 | { |
40 | [TestFixture] | 40 | [TestFixture] |
41 | public class UuidGathererTests | 41 | public class UuidGathererTests : OpenSimTestCase |
42 | { | 42 | { |
43 | protected IAssetService m_assetService; | 43 | protected IAssetService m_assetService; |
44 | protected UuidGatherer m_uuidGatherer; | 44 | protected UuidGatherer m_uuidGatherer; |
diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/IGroupsServicesConnector.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/IGroupsServicesConnector.cs index 6d26075..6b5b40a 100644 --- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/IGroupsServicesConnector.cs +++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/IGroupsServicesConnector.cs | |||
@@ -36,7 +36,22 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups | |||
36 | { | 36 | { |
37 | UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish, UUID founderID); | 37 | UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish, UUID founderID); |
38 | void UpdateGroup(UUID RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish); | 38 | void UpdateGroup(UUID RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish); |
39 | |||
40 | /// <summary> | ||
41 | /// Get the group record. | ||
42 | /// </summary> | ||
43 | /// <returns></returns> | ||
44 | /// <param name='RequestingAgentID'>The UUID of the user making the request.</param> | ||
45 | /// <param name='GroupID'> | ||
46 | /// The ID of the record to retrieve. | ||
47 | /// GroupName may be specified instead, in which case this parameter will be UUID.Zero | ||
48 | /// </param> | ||
49 | /// <param name='GroupName'> | ||
50 | /// The name of the group to retrieve. | ||
51 | /// GroupID may be specified instead, in which case this parmeter will be null. | ||
52 | /// </param> | ||
39 | GroupRecord GetGroupRecord(UUID RequestingAgentID, UUID GroupID, string GroupName); | 53 | GroupRecord GetGroupRecord(UUID RequestingAgentID, UUID GroupID, string GroupName); |
54 | |||
40 | List<DirGroupsReplyData> FindGroups(UUID RequestingAgentID, string search); | 55 | List<DirGroupsReplyData> FindGroups(UUID RequestingAgentID, string search); |
41 | List<GroupMembersData> GetGroupMembers(UUID RequestingAgentID, UUID GroupID); | 56 | List<GroupMembersData> GetGroupMembers(UUID RequestingAgentID, UUID GroupID); |
42 | 57 | ||
diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs index ac638f1..c1bdacb 100644 --- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs +++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs | |||
@@ -42,7 +42,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups.Tests | |||
42 | /// Basic groups module tests | 42 | /// Basic groups module tests |
43 | /// </summary> | 43 | /// </summary> |
44 | [TestFixture] | 44 | [TestFixture] |
45 | public class GroupsModuleTests | 45 | public class GroupsModuleTests : OpenSimTestCase |
46 | { | 46 | { |
47 | [Test] | 47 | [Test] |
48 | public void TestBasic() | 48 | public void TestBasic() |
diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs index d0c3ea5..1101851 100644 --- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs | |||
@@ -54,13 +54,62 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups | |||
54 | 54 | ||
55 | private bool m_debugEnabled = false; | 55 | private bool m_debugEnabled = false; |
56 | 56 | ||
57 | public const GroupPowers m_DefaultEveryonePowers = GroupPowers.AllowSetHome | | 57 | public const GroupPowers DefaultEveryonePowers |
58 | GroupPowers.Accountable | | 58 | = GroupPowers.AllowSetHome |
59 | GroupPowers.JoinChat | | 59 | | GroupPowers.Accountable |
60 | GroupPowers.AllowVoiceChat | | 60 | | GroupPowers.JoinChat |
61 | GroupPowers.ReceiveNotices | | 61 | | GroupPowers.AllowVoiceChat |
62 | GroupPowers.StartProposal | | 62 | | GroupPowers.ReceiveNotices |
63 | GroupPowers.VoteOnProposal; | 63 | | GroupPowers.StartProposal |
64 | | GroupPowers.VoteOnProposal; | ||
65 | |||
66 | // Would this be cleaner as (GroupPowers)ulong.MaxValue? | ||
67 | public const GroupPowers DefaultOwnerPowers | ||
68 | = GroupPowers.Accountable | ||
69 | | GroupPowers.AllowEditLand | ||
70 | | GroupPowers.AllowFly | ||
71 | | GroupPowers.AllowLandmark | ||
72 | | GroupPowers.AllowRez | ||
73 | | GroupPowers.AllowSetHome | ||
74 | | GroupPowers.AllowVoiceChat | ||
75 | | GroupPowers.AssignMember | ||
76 | | GroupPowers.AssignMemberLimited | ||
77 | | GroupPowers.ChangeActions | ||
78 | | GroupPowers.ChangeIdentity | ||
79 | | GroupPowers.ChangeMedia | ||
80 | | GroupPowers.ChangeOptions | ||
81 | | GroupPowers.CreateRole | ||
82 | | GroupPowers.DeedObject | ||
83 | | GroupPowers.DeleteRole | ||
84 | | GroupPowers.Eject | ||
85 | | GroupPowers.FindPlaces | ||
86 | | GroupPowers.Invite | ||
87 | | GroupPowers.JoinChat | ||
88 | | GroupPowers.LandChangeIdentity | ||
89 | | GroupPowers.LandDeed | ||
90 | | GroupPowers.LandDivideJoin | ||
91 | | GroupPowers.LandEdit | ||
92 | | GroupPowers.LandEjectAndFreeze | ||
93 | | GroupPowers.LandGardening | ||
94 | | GroupPowers.LandManageAllowed | ||
95 | | GroupPowers.LandManageBanned | ||
96 | | GroupPowers.LandManagePasses | ||
97 | | GroupPowers.LandOptions | ||
98 | | GroupPowers.LandRelease | ||
99 | | GroupPowers.LandSetSale | ||
100 | | GroupPowers.ModerateChat | ||
101 | | GroupPowers.ObjectManipulate | ||
102 | | GroupPowers.ObjectSetForSale | ||
103 | | GroupPowers.ReceiveNotices | ||
104 | | GroupPowers.RemoveMember | ||
105 | | GroupPowers.ReturnGroupOwned | ||
106 | | GroupPowers.ReturnGroupSet | ||
107 | | GroupPowers.ReturnNonGroup | ||
108 | | GroupPowers.RoleProperties | ||
109 | | GroupPowers.SendNotices | ||
110 | | GroupPowers.SetLandingPoint | ||
111 | | GroupPowers.StartProposal | ||
112 | | GroupPowers.VoteOnProposal; | ||
64 | 113 | ||
65 | private bool m_connectorEnabled = false; | 114 | private bool m_connectorEnabled = false; |
66 | 115 | ||
@@ -219,59 +268,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups | |||
219 | param["AllowPublish"] = allowPublish == true ? 1 : 0; | 268 | param["AllowPublish"] = allowPublish == true ? 1 : 0; |
220 | param["MaturePublish"] = maturePublish == true ? 1 : 0; | 269 | param["MaturePublish"] = maturePublish == true ? 1 : 0; |
221 | param["FounderID"] = founderID.ToString(); | 270 | param["FounderID"] = founderID.ToString(); |
222 | param["EveryonePowers"] = ((ulong)m_DefaultEveryonePowers).ToString(); | 271 | param["EveryonePowers"] = ((ulong)DefaultEveryonePowers).ToString(); |
223 | param["OwnerRoleID"] = OwnerRoleID.ToString(); | 272 | param["OwnerRoleID"] = OwnerRoleID.ToString(); |
224 | 273 | param["OwnersPowers"] = ((ulong)DefaultOwnerPowers).ToString(); | |
225 | // Would this be cleaner as (GroupPowers)ulong.MaxValue; | ||
226 | GroupPowers OwnerPowers = GroupPowers.Accountable | ||
227 | | GroupPowers.AllowEditLand | ||
228 | | GroupPowers.AllowFly | ||
229 | | GroupPowers.AllowLandmark | ||
230 | | GroupPowers.AllowRez | ||
231 | | GroupPowers.AllowSetHome | ||
232 | | GroupPowers.AllowVoiceChat | ||
233 | | GroupPowers.AssignMember | ||
234 | | GroupPowers.AssignMemberLimited | ||
235 | | GroupPowers.ChangeActions | ||
236 | | GroupPowers.ChangeIdentity | ||
237 | | GroupPowers.ChangeMedia | ||
238 | | GroupPowers.ChangeOptions | ||
239 | | GroupPowers.CreateRole | ||
240 | | GroupPowers.DeedObject | ||
241 | | GroupPowers.DeleteRole | ||
242 | | GroupPowers.Eject | ||
243 | | GroupPowers.FindPlaces | ||
244 | | GroupPowers.Invite | ||
245 | | GroupPowers.JoinChat | ||
246 | | GroupPowers.LandChangeIdentity | ||
247 | | GroupPowers.LandDeed | ||
248 | | GroupPowers.LandDivideJoin | ||
249 | | GroupPowers.LandEdit | ||
250 | | GroupPowers.LandEjectAndFreeze | ||
251 | | GroupPowers.LandGardening | ||
252 | | GroupPowers.LandManageAllowed | ||
253 | | GroupPowers.LandManageBanned | ||
254 | | GroupPowers.LandManagePasses | ||
255 | | GroupPowers.LandOptions | ||
256 | | GroupPowers.LandRelease | ||
257 | | GroupPowers.LandSetSale | ||
258 | | GroupPowers.ModerateChat | ||
259 | | GroupPowers.ObjectManipulate | ||
260 | | GroupPowers.ObjectSetForSale | ||
261 | | GroupPowers.ReceiveNotices | ||
262 | | GroupPowers.RemoveMember | ||
263 | | GroupPowers.ReturnGroupOwned | ||
264 | | GroupPowers.ReturnGroupSet | ||
265 | | GroupPowers.ReturnNonGroup | ||
266 | | GroupPowers.RoleProperties | ||
267 | | GroupPowers.SendNotices | ||
268 | | GroupPowers.SetLandingPoint | ||
269 | | GroupPowers.StartProposal | ||
270 | | GroupPowers.VoteOnProposal; | ||
271 | param["OwnersPowers"] = ((ulong)OwnerPowers).ToString(); | ||
272 | |||
273 | |||
274 | |||
275 | 274 | ||
276 | Hashtable respData = XmlRpcCall(requestingAgentID, "groups.createGroup", param); | 275 | Hashtable respData = XmlRpcCall(requestingAgentID, "groups.createGroup", param); |
277 | 276 | ||
@@ -612,8 +611,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups | |||
612 | } | 611 | } |
613 | 612 | ||
614 | return Roles; | 613 | return Roles; |
615 | |||
616 | |||
617 | } | 614 | } |
618 | 615 | ||
619 | public List<GroupRolesData> GetGroupRoles(UUID requestingAgentID, UUID GroupID) | 616 | public List<GroupRolesData> GetGroupRoles(UUID requestingAgentID, UUID GroupID) |
@@ -676,7 +673,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups | |||
676 | } | 673 | } |
677 | 674 | ||
678 | return members; | 675 | return members; |
679 | |||
680 | } | 676 | } |
681 | 677 | ||
682 | public List<GroupRoleMembersData> GetGroupRoleMembers(UUID requestingAgentID, UUID GroupID) | 678 | public List<GroupRoleMembersData> GetGroupRoleMembers(UUID requestingAgentID, UUID GroupID) |
@@ -727,9 +723,10 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups | |||
727 | values.Add(data); | 723 | values.Add(data); |
728 | } | 724 | } |
729 | } | 725 | } |
730 | return values; | ||
731 | 726 | ||
727 | return values; | ||
732 | } | 728 | } |
729 | |||
733 | public GroupNoticeInfo GetGroupNotice(UUID requestingAgentID, UUID noticeID) | 730 | public GroupNoticeInfo GetGroupNotice(UUID requestingAgentID, UUID noticeID) |
734 | { | 731 | { |
735 | Hashtable param = new Hashtable(); | 732 | Hashtable param = new Hashtable(); |
@@ -737,7 +734,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups | |||
737 | 734 | ||
738 | Hashtable respData = XmlRpcCall(requestingAgentID, "groups.getGroupNotice", param); | 735 | Hashtable respData = XmlRpcCall(requestingAgentID, "groups.getGroupNotice", param); |
739 | 736 | ||
740 | |||
741 | if (respData.Contains("error")) | 737 | if (respData.Contains("error")) |
742 | { | 738 | { |
743 | return null; | 739 | return null; |
@@ -761,6 +757,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups | |||
761 | 757 | ||
762 | return data; | 758 | return data; |
763 | } | 759 | } |
760 | |||
764 | public void AddGroupNotice(UUID requestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message, byte[] binaryBucket) | 761 | public void AddGroupNotice(UUID requestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message, byte[] binaryBucket) |
765 | { | 762 | { |
766 | string binBucket = OpenMetaverse.Utils.BytesToHexString(binaryBucket, ""); | 763 | string binBucket = OpenMetaverse.Utils.BytesToHexString(binaryBucket, ""); |
@@ -777,8 +774,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups | |||
777 | XmlRpcCall(requestingAgentID, "groups.addGroupNotice", param); | 774 | XmlRpcCall(requestingAgentID, "groups.addGroupNotice", param); |
778 | } | 775 | } |
779 | 776 | ||
780 | |||
781 | |||
782 | #endregion | 777 | #endregion |
783 | 778 | ||
784 | #region GroupSessionTracking | 779 | #region GroupSessionTracking |
diff --git a/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcGridRouterModule.cs b/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcGridRouterModule.cs index 6120a81..709d389 100644 --- a/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcGridRouterModule.cs +++ b/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcGridRouterModule.cs | |||
@@ -46,6 +46,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcGridRouterModule | |||
46 | { | 46 | { |
47 | public class XmlRpcInfo | 47 | public class XmlRpcInfo |
48 | { | 48 | { |
49 | public UUID item; | ||
49 | public UUID channel; | 50 | public UUID channel; |
50 | public string uri; | 51 | public string uri; |
51 | } | 52 | } |
@@ -88,6 +89,14 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcGridRouterModule | |||
88 | return; | 89 | return; |
89 | 90 | ||
90 | scene.RegisterModuleInterface<IXmlRpcRouter>(this); | 91 | scene.RegisterModuleInterface<IXmlRpcRouter>(this); |
92 | |||
93 | IScriptModule scriptEngine = scene.RequestModuleInterface<IScriptModule>(); | ||
94 | if ( scriptEngine != null ) | ||
95 | { | ||
96 | scriptEngine.OnScriptRemoved += this.ScriptRemoved; | ||
97 | scriptEngine.OnObjectRemoved += this.ObjectRemoved; | ||
98 | |||
99 | } | ||
91 | } | 100 | } |
92 | 101 | ||
93 | public void RegionLoaded(Scene scene) | 102 | public void RegionLoaded(Scene scene) |
@@ -120,22 +129,36 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcGridRouterModule | |||
120 | 129 | ||
121 | public void RegisterNewReceiver(IScriptModule scriptEngine, UUID channel, UUID objectID, UUID itemID, string uri) | 130 | public void RegisterNewReceiver(IScriptModule scriptEngine, UUID channel, UUID objectID, UUID itemID, string uri) |
122 | { | 131 | { |
123 | if (!m_Channels.ContainsKey(itemID)) | 132 | if (!m_Enabled) |
124 | { | 133 | return; |
125 | XmlRpcInfo info = new XmlRpcInfo(); | ||
126 | info.channel = channel; | ||
127 | info.uri = uri; | ||
128 | 134 | ||
129 | bool success = SynchronousRestObjectRequester.MakeRequest<XmlRpcInfo, bool>( | 135 | m_log.InfoFormat("[XMLRPC GRID ROUTER]: New receiver Obj: {0} Ch: {1} ID: {2} URI: {3}", |
130 | "POST", m_ServerURI+"/RegisterChannel/", info); | 136 | objectID.ToString(), channel.ToString(), itemID.ToString(), uri); |
131 | 137 | ||
132 | if (!success) | 138 | XmlRpcInfo info = new XmlRpcInfo(); |
133 | { | 139 | info.channel = channel; |
134 | m_log.Error("[XMLRPC GRID ROUTER] Error contacting server"); | 140 | info.uri = uri; |
135 | } | 141 | info.item = itemID; |
142 | |||
143 | bool success = SynchronousRestObjectRequester.MakeRequest<XmlRpcInfo, bool>( | ||
144 | "POST", m_ServerURI+"/RegisterChannel/", info); | ||
136 | 145 | ||
137 | m_Channels[itemID] = channel; | 146 | if (!success) |
147 | { | ||
148 | m_log.Error("[XMLRPC GRID ROUTER] Error contacting server"); | ||
138 | } | 149 | } |
150 | |||
151 | m_Channels[itemID] = channel; | ||
152 | |||
153 | } | ||
154 | |||
155 | public void UnRegisterReceiver(string channelID, UUID itemID) | ||
156 | { | ||
157 | if (!m_Enabled) | ||
158 | return; | ||
159 | |||
160 | RemoveChannel(itemID); | ||
161 | |||
139 | } | 162 | } |
140 | 163 | ||
141 | public void ScriptRemoved(UUID itemID) | 164 | public void ScriptRemoved(UUID itemID) |
@@ -143,10 +166,33 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcGridRouterModule | |||
143 | if (!m_Enabled) | 166 | if (!m_Enabled) |
144 | return; | 167 | return; |
145 | 168 | ||
146 | if (m_Channels.ContainsKey(itemID)) | 169 | RemoveChannel(itemID); |
170 | |||
171 | } | ||
172 | |||
173 | public void ObjectRemoved(UUID objectID) | ||
174 | { | ||
175 | // m_log.InfoFormat("[XMLRPC GRID ROUTER]: Object Removed {0}",objectID.ToString()); | ||
176 | } | ||
177 | |||
178 | private bool RemoveChannel(UUID itemID) | ||
179 | { | ||
180 | if(!m_Channels.ContainsKey(itemID)) | ||
181 | { | ||
182 | m_log.InfoFormat("[XMLRPC GRID ROUTER]: Attempted to unregister non-existing Item: {0}", itemID.ToString()); | ||
183 | return false; | ||
184 | } | ||
185 | |||
186 | XmlRpcInfo info = new XmlRpcInfo(); | ||
187 | |||
188 | info.channel = m_Channels[itemID]; | ||
189 | info.item = itemID; | ||
190 | info.uri = "http://0.0.0.0:00"; | ||
191 | |||
192 | if (info != null) | ||
147 | { | 193 | { |
148 | bool success = SynchronousRestObjectRequester.MakeRequest<UUID, bool>( | 194 | bool success = SynchronousRestObjectRequester.MakeRequest<XmlRpcInfo, bool>( |
149 | "POST", m_ServerURI+"/RemoveChannel/", m_Channels[itemID]); | 195 | "POST", m_ServerURI+"/RemoveChannel/", info); |
150 | 196 | ||
151 | if (!success) | 197 | if (!success) |
152 | { | 198 | { |
@@ -154,11 +200,9 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcGridRouterModule | |||
154 | } | 200 | } |
155 | 201 | ||
156 | m_Channels.Remove(itemID); | 202 | m_Channels.Remove(itemID); |
203 | return true; | ||
157 | } | 204 | } |
158 | } | 205 | return false; |
159 | |||
160 | public void ObjectRemoved(UUID objectID) | ||
161 | { | ||
162 | } | 206 | } |
163 | } | 207 | } |
164 | } | 208 | } |
diff --git a/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcRouterModule.cs b/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcRouterModule.cs index 4bde52a..9d373ef 100644 --- a/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcRouterModule.cs +++ b/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcRouterModule.cs | |||
@@ -104,12 +104,18 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcRouterModule | |||
104 | } | 104 | } |
105 | } | 105 | } |
106 | 106 | ||
107 | public void UnRegisterReceiver(string channelID, UUID itemID) | ||
108 | { | ||
109 | } | ||
110 | |||
107 | public void ScriptRemoved(UUID itemID) | 111 | public void ScriptRemoved(UUID itemID) |
108 | { | 112 | { |
113 | System.Console.WriteLine("TEST Script Removed!"); | ||
109 | } | 114 | } |
110 | 115 | ||
111 | public void ObjectRemoved(UUID objectID) | 116 | public void ObjectRemoved(UUID objectID) |
112 | { | 117 | { |
118 | System.Console.WriteLine("TEST Obj Removed!"); | ||
113 | } | 119 | } |
114 | } | 120 | } |
115 | } | 121 | } |
diff --git a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs index 52ed846..a522277 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs | |||
@@ -48,7 +48,7 @@ using OpenSim.Tests.Common.Mock; | |||
48 | namespace OpenSim.Region.OptionalModules.World.NPC.Tests | 48 | namespace OpenSim.Region.OptionalModules.World.NPC.Tests |
49 | { | 49 | { |
50 | [TestFixture] | 50 | [TestFixture] |
51 | public class NPCModuleTests | 51 | public class NPCModuleTests : OpenSimTestCase |
52 | { | 52 | { |
53 | private TestScene m_scene; | 53 | private TestScene m_scene; |
54 | private AvatarFactoryModule m_afMod; | 54 | private AvatarFactoryModule m_afMod; |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 4c195e1..4dd6264 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs | |||
@@ -105,12 +105,12 @@ public sealed class BSCharacter : BSPhysObject | |||
105 | DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", | 105 | DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", |
106 | LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); | 106 | LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); |
107 | 107 | ||
108 | // do actual create at taint time | 108 | // do actual creation in taint time |
109 | PhysicsScene.TaintedObject("BSCharacter.create", delegate() | 109 | PhysicsScene.TaintedObject("BSCharacter.create", delegate() |
110 | { | 110 | { |
111 | DetailLog("{0},BSCharacter.create,taint", LocalID); | 111 | DetailLog("{0},BSCharacter.create,taint", LocalID); |
112 | // New body and shape into PhysBody and PhysShape | 112 | // New body and shape into PhysBody and PhysShape |
113 | PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this, null, null); | 113 | PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this); |
114 | 114 | ||
115 | SetPhysicalProperties(); | 115 | SetPhysicalProperties(); |
116 | }); | 116 | }); |
@@ -124,7 +124,9 @@ public sealed class BSCharacter : BSPhysObject | |||
124 | PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() | 124 | PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() |
125 | { | 125 | { |
126 | PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); | 126 | PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); |
127 | PhysBody.Clear(); | ||
127 | PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); | 128 | PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); |
129 | PhysShape.Clear(); | ||
128 | }); | 130 | }); |
129 | } | 131 | } |
130 | 132 | ||
@@ -165,9 +167,8 @@ public sealed class BSCharacter : BSPhysObject | |||
165 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); | 167 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); |
166 | 168 | ||
167 | // Do this after the object has been added to the world | 169 | // Do this after the object has been added to the world |
168 | BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr, | 170 | PhysBody.collisionType = CollisionType.Avatar; |
169 | (uint)CollisionFilterGroups.AvatarFilter, | 171 | PhysBody.ApplyCollisionMask(); |
170 | (uint)CollisionFilterGroups.AvatarMask); | ||
171 | } | 172 | } |
172 | 173 | ||
173 | public override void RequestPhysicsterseUpdate() | 174 | public override void RequestPhysicsterseUpdate() |
@@ -187,6 +188,11 @@ public sealed class BSCharacter : BSPhysObject | |||
187 | set { | 188 | set { |
188 | // When an avatar's size is set, only the height is changed. | 189 | // When an avatar's size is set, only the height is changed. |
189 | _size = value; | 190 | _size = value; |
191 | // Old versions of ScenePresence passed only the height. If width and/or depth are zero, | ||
192 | // replace with the default values. | ||
193 | if (_size.X == 0f) _size.X = PhysicsScene.Params.avatarCapsuleDepth; | ||
194 | if (_size.Y == 0f) _size.Y = PhysicsScene.Params.avatarCapsuleWidth; | ||
195 | |||
190 | ComputeAvatarScale(_size); | 196 | ComputeAvatarScale(_size); |
191 | ComputeAvatarVolumeAndMass(); | 197 | ComputeAvatarVolumeAndMass(); |
192 | DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", | 198 | DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", |
@@ -194,15 +200,18 @@ public sealed class BSCharacter : BSPhysObject | |||
194 | 200 | ||
195 | PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() | 201 | PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() |
196 | { | 202 | { |
197 | BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale); | 203 | if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape) |
198 | UpdatePhysicalMassProperties(RawMass); | 204 | { |
205 | BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale); | ||
206 | UpdatePhysicalMassProperties(RawMass); | ||
207 | // Make sure this change appears as a property update event | ||
208 | BulletSimAPI.PushUpdate2(PhysBody.ptr); | ||
209 | } | ||
199 | }); | 210 | }); |
200 | 211 | ||
201 | } | 212 | } |
202 | } | 213 | } |
203 | 214 | ||
204 | public override OMV.Vector3 Scale { get; set; } | ||
205 | |||
206 | public override PrimitiveBaseShape Shape | 215 | public override PrimitiveBaseShape Shape |
207 | { | 216 | { |
208 | set { BaseShape = value; } | 217 | set { BaseShape = value; } |
@@ -236,7 +245,8 @@ public sealed class BSCharacter : BSPhysObject | |||
236 | // Zero some other properties directly into the physics engine | 245 | // Zero some other properties directly into the physics engine |
237 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() | 246 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() |
238 | { | 247 | { |
239 | BulletSimAPI.ClearAllForces2(PhysBody.ptr); | 248 | if (PhysBody.HasPhysicalBody) |
249 | BulletSimAPI.ClearAllForces2(PhysBody.ptr); | ||
240 | }); | 250 | }); |
241 | } | 251 | } |
242 | public override void ZeroAngularMotion(bool inTaintTime) | 252 | public override void ZeroAngularMotion(bool inTaintTime) |
@@ -245,10 +255,13 @@ public sealed class BSCharacter : BSPhysObject | |||
245 | 255 | ||
246 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() | 256 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() |
247 | { | 257 | { |
248 | BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); | 258 | if (PhysBody.HasPhysicalBody) |
249 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); | 259 | { |
250 | // The next also get rid of applied linear force but the linear velocity is untouched. | 260 | BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); |
251 | BulletSimAPI.ClearForces2(PhysBody.ptr); | 261 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); |
262 | // The next also get rid of applied linear force but the linear velocity is untouched. | ||
263 | BulletSimAPI.ClearForces2(PhysBody.ptr); | ||
264 | } | ||
252 | }); | 265 | }); |
253 | } | 266 | } |
254 | 267 | ||
@@ -273,7 +286,8 @@ public sealed class BSCharacter : BSPhysObject | |||
273 | PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() | 286 | PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() |
274 | { | 287 | { |
275 | DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 288 | DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); |
276 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 289 | if (PhysBody.HasPhysicalBody) |
290 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | ||
277 | }); | 291 | }); |
278 | } | 292 | } |
279 | } | 293 | } |
@@ -297,6 +311,15 @@ public sealed class BSCharacter : BSPhysObject | |||
297 | { | 311 | { |
298 | bool ret = false; | 312 | bool ret = false; |
299 | 313 | ||
314 | // TODO: check for out of bounds | ||
315 | if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position)) | ||
316 | { | ||
317 | // The character is out of the known/simulated area. | ||
318 | // Upper levels of code will handle the transition to other areas so, for | ||
319 | // the time, we just ignore the position. | ||
320 | return ret; | ||
321 | } | ||
322 | |||
300 | // If below the ground, move the avatar up | 323 | // If below the ground, move the avatar up |
301 | float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); | 324 | float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); |
302 | if (Position.Z < terrainHeight) | 325 | if (Position.Z < terrainHeight) |
@@ -307,7 +330,7 @@ public sealed class BSCharacter : BSPhysObject | |||
307 | } | 330 | } |
308 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) | 331 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) |
309 | { | 332 | { |
310 | float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); | 333 | float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); |
311 | if (Position.Z < waterHeight) | 334 | if (Position.Z < waterHeight) |
312 | { | 335 | { |
313 | _position.Z = waterHeight; | 336 | _position.Z = waterHeight; |
@@ -315,7 +338,6 @@ public sealed class BSCharacter : BSPhysObject | |||
315 | } | 338 | } |
316 | } | 339 | } |
317 | 340 | ||
318 | // TODO: check for out of bounds | ||
319 | return ret; | 341 | return ret; |
320 | } | 342 | } |
321 | 343 | ||
@@ -332,7 +354,8 @@ public sealed class BSCharacter : BSPhysObject | |||
332 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() | 354 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() |
333 | { | 355 | { |
334 | DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 356 | DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); |
335 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 357 | if (PhysBody.HasPhysicalBody) |
358 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | ||
336 | }); | 359 | }); |
337 | ret = true; | 360 | ret = true; |
338 | } | 361 | } |
@@ -359,7 +382,8 @@ public sealed class BSCharacter : BSPhysObject | |||
359 | PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() | 382 | PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() |
360 | { | 383 | { |
361 | DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); | 384 | DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); |
362 | BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); | 385 | if (PhysBody.HasPhysicalBody) |
386 | BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); | ||
363 | }); | 387 | }); |
364 | } | 388 | } |
365 | } | 389 | } |
@@ -398,7 +422,8 @@ public sealed class BSCharacter : BSPhysObject | |||
398 | if (_currentFriction != PhysicsScene.Params.avatarStandingFriction) | 422 | if (_currentFriction != PhysicsScene.Params.avatarStandingFriction) |
399 | { | 423 | { |
400 | _currentFriction = PhysicsScene.Params.avatarStandingFriction; | 424 | _currentFriction = PhysicsScene.Params.avatarStandingFriction; |
401 | BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); | 425 | if (PhysBody.HasPhysicalBody) |
426 | BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); | ||
402 | } | 427 | } |
403 | } | 428 | } |
404 | else | 429 | else |
@@ -406,7 +431,8 @@ public sealed class BSCharacter : BSPhysObject | |||
406 | if (_currentFriction != PhysicsScene.Params.avatarFriction) | 431 | if (_currentFriction != PhysicsScene.Params.avatarFriction) |
407 | { | 432 | { |
408 | _currentFriction = PhysicsScene.Params.avatarFriction; | 433 | _currentFriction = PhysicsScene.Params.avatarFriction; |
409 | BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); | 434 | if (PhysBody.HasPhysicalBody) |
435 | BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); | ||
410 | } | 436 | } |
411 | } | 437 | } |
412 | _velocity = value; | 438 | _velocity = value; |
@@ -443,8 +469,11 @@ public sealed class BSCharacter : BSPhysObject | |||
443 | // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation); | 469 | // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation); |
444 | PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() | 470 | PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() |
445 | { | 471 | { |
446 | // _position = BulletSimAPI.GetPosition2(BSBody.ptr); | 472 | if (PhysBody.HasPhysicalBody) |
447 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 473 | { |
474 | // _position = BulletSimAPI.GetPosition2(BSBody.ptr); | ||
475 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | ||
476 | } | ||
448 | }); | 477 | }); |
449 | } | 478 | } |
450 | } | 479 | } |
@@ -517,10 +546,13 @@ public sealed class BSCharacter : BSPhysObject | |||
517 | _floatOnWater = value; | 546 | _floatOnWater = value; |
518 | PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() | 547 | PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() |
519 | { | 548 | { |
520 | if (_floatOnWater) | 549 | if (PhysBody.HasPhysicalBody) |
521 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); | 550 | { |
522 | else | 551 | if (_floatOnWater) |
523 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); | 552 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); |
553 | else | ||
554 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); | ||
555 | } | ||
524 | }); | 556 | }); |
525 | } | 557 | } |
526 | } | 558 | } |
@@ -553,7 +585,8 @@ public sealed class BSCharacter : BSPhysObject | |||
553 | DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | 585 | DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); |
554 | // Buoyancy is faked by changing the gravity applied to the object | 586 | // Buoyancy is faked by changing the gravity applied to the object |
555 | float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); | 587 | float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); |
556 | BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); | 588 | if (PhysBody.HasPhysicalBody) |
589 | BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); | ||
557 | } | 590 | } |
558 | } | 591 | } |
559 | 592 | ||
@@ -599,7 +632,8 @@ public sealed class BSCharacter : BSPhysObject | |||
599 | PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate() | 632 | PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate() |
600 | { | 633 | { |
601 | DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force); | 634 | DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force); |
602 | BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); | 635 | if (PhysBody.HasPhysicalBody) |
636 | BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); | ||
603 | }); | 637 | }); |
604 | } | 638 | } |
605 | else | 639 | else |
@@ -616,9 +650,6 @@ public sealed class BSCharacter : BSPhysObject | |||
616 | 650 | ||
617 | private void ComputeAvatarScale(OMV.Vector3 size) | 651 | private void ComputeAvatarScale(OMV.Vector3 size) |
618 | { | 652 | { |
619 | // The 'size' given by the simulator is the mid-point of the avatar | ||
620 | // and X and Y are unspecified. | ||
621 | |||
622 | OMV.Vector3 newScale = size; | 653 | OMV.Vector3 newScale = size; |
623 | // newScale.X = PhysicsScene.Params.avatarCapsuleWidth; | 654 | // newScale.X = PhysicsScene.Params.avatarCapsuleWidth; |
624 | // newScale.Y = PhysicsScene.Params.avatarCapsuleDepth; | 655 | // newScale.Y = PhysicsScene.Params.avatarCapsuleDepth; |
@@ -677,7 +708,7 @@ public sealed class BSCharacter : BSPhysObject | |||
677 | } | 708 | } |
678 | 709 | ||
679 | // Tell the linkset about value changes | 710 | // Tell the linkset about value changes |
680 | Linkset.UpdateProperties(this); | 711 | Linkset.UpdateProperties(this, true); |
681 | 712 | ||
682 | // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. | 713 | // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. |
683 | // base.RequestPhysicsterseUpdate(); | 714 | // base.RequestPhysicsterseUpdate(); |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs index 65fac00..6b1e304 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs | |||
@@ -57,7 +57,7 @@ public abstract class BSConstraint : IDisposable | |||
57 | if (m_enabled) | 57 | if (m_enabled) |
58 | { | 58 | { |
59 | m_enabled = false; | 59 | m_enabled = false; |
60 | if (m_constraint.ptr != IntPtr.Zero) | 60 | if (m_constraint.HasPhysicalConstraint) |
61 | { | 61 | { |
62 | bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr); | 62 | bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr); |
63 | m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}", | 63 | m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}", |
@@ -65,7 +65,7 @@ public abstract class BSConstraint : IDisposable | |||
65 | m_body1.ID, m_body1.ptr.ToString("X"), | 65 | m_body1.ID, m_body1.ptr.ToString("X"), |
66 | m_body2.ID, m_body2.ptr.ToString("X"), | 66 | m_body2.ID, m_body2.ptr.ToString("X"), |
67 | success); | 67 | success); |
68 | m_constraint.ptr = System.IntPtr.Zero; | 68 | m_constraint.Clear(); |
69 | } | 69 | } |
70 | } | 70 | } |
71 | } | 71 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs index 23ef052..b073555 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs | |||
@@ -65,7 +65,7 @@ public sealed class BSConstraint6Dof : BSConstraint | |||
65 | m_world = world; | 65 | m_world = world; |
66 | m_body1 = obj1; | 66 | m_body1 = obj1; |
67 | m_body2 = obj2; | 67 | m_body2 = obj2; |
68 | if (obj1.ptr == IntPtr.Zero || obj2.ptr == IntPtr.Zero) | 68 | if (!obj1.HasPhysicalBody || !obj2.HasPhysicalBody) |
69 | { | 69 | { |
70 | world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", | 70 | world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", |
71 | BSScene.DetailLogZero, world.worldID, | 71 | BSScene.DetailLogZero, world.worldID, |
@@ -83,7 +83,7 @@ public sealed class BSConstraint6Dof : BSConstraint | |||
83 | world.physicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}", | 83 | world.physicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}", |
84 | BSScene.DetailLogZero, world.worldID, m_constraint.ptr.ToString("X"), | 84 | BSScene.DetailLogZero, world.worldID, m_constraint.ptr.ToString("X"), |
85 | obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); | 85 | obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); |
86 | if (m_constraint.ptr == IntPtr.Zero) | 86 | if (!m_constraint.HasPhysicalConstraint) |
87 | { | 87 | { |
88 | world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}", | 88 | world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}", |
89 | LogHeader, obj1.ID, obj2.ID); | 89 | LogHeader, obj1.ID, obj2.ID); |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index dbc9039..5887249 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | |||
@@ -24,30 +24,17 @@ | |||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 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. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | * | 26 | * |
27 | 27 | * The quotations from http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial | |
28 | /* RA: June 14, 2011. Copied from ODEDynamics.cs and converted to | 28 | * are Copyright (c) 2009 Linden Research, Inc and are used under their license |
29 | * call the BulletSim system. | 29 | * of Creative Commons Attribution-Share Alike 3.0 |
30 | */ | 30 | * (http://creativecommons.org/licenses/by-sa/3.0/). |
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 | */ | 31 | */ |
43 | 32 | ||
44 | using System; | 33 | using System; |
45 | using System.Collections.Generic; | 34 | using System.Collections.Generic; |
46 | using System.Reflection; | 35 | using System.Reflection; |
47 | using System.Runtime.InteropServices; | 36 | using System.Runtime.InteropServices; |
48 | using log4net; | ||
49 | using OpenMetaverse; | 37 | using OpenMetaverse; |
50 | using OpenSim.Framework; | ||
51 | using OpenSim.Region.Physics.Manager; | 38 | using OpenSim.Region.Physics.Manager; |
52 | 39 | ||
53 | namespace OpenSim.Region.Physics.BulletSPlugin | 40 | namespace OpenSim.Region.Physics.BulletSPlugin |
@@ -80,10 +67,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
80 | private Quaternion m_referenceFrame = Quaternion.Identity; | 67 | private Quaternion m_referenceFrame = Quaternion.Identity; |
81 | 68 | ||
82 | // Linear properties | 69 | // Linear properties |
70 | private BSVMotor m_linearMotor = new BSVMotor("LinearMotor"); | ||
83 | private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time | 71 | private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time |
84 | private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center | 72 | private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center |
85 | private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL | 73 | private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL |
86 | private Vector3 m_newVelocity = Vector3.Zero; // velocity computed to be applied to body | ||
87 | private Vector3 m_linearFrictionTimescale = Vector3.Zero; | 74 | private Vector3 m_linearFrictionTimescale = Vector3.Zero; |
88 | private float m_linearMotorDecayTimescale = 0; | 75 | private float m_linearMotorDecayTimescale = 0; |
89 | private float m_linearMotorTimescale = 0; | 76 | private float m_linearMotorTimescale = 0; |
@@ -93,13 +80,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
93 | // private Vector3 m_linearMotorOffset = Vector3.Zero; | 80 | // private Vector3 m_linearMotorOffset = Vector3.Zero; |
94 | 81 | ||
95 | //Angular properties | 82 | //Angular properties |
83 | private BSVMotor m_angularMotor = new BSVMotor("AngularMotor"); | ||
96 | private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor | 84 | private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor |
97 | // private int m_angularMotorApply = 0; // application frame counter | 85 | // private int m_angularMotorApply = 0; // application frame counter |
98 | private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity | 86 | private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity |
99 | private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate | 87 | private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate |
100 | private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate | 88 | private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate |
101 | private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate | 89 | private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate |
102 | private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body | 90 | private Vector3 m_lastAngularVelocity = Vector3.Zero; |
103 | private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body | 91 | private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body |
104 | 92 | ||
105 | //Deflection properties | 93 | //Deflection properties |
@@ -124,8 +112,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
124 | // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity. | 112 | // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity. |
125 | 113 | ||
126 | //Attractor properties | 114 | //Attractor properties |
127 | private float m_verticalAttractionEfficiency = 1.0f; // damped | 115 | private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction"); |
128 | private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor. | 116 | private float m_verticalAttractionEfficiency = 1.0f; // damped |
117 | private float m_verticalAttractionCutoff = 500f; // per the documentation | ||
118 | // Timescale > cutoff means no vert attractor. | ||
119 | private float m_verticalAttractionTimescale = 510f; | ||
129 | 120 | ||
130 | public BSDynamics(BSScene myScene, BSPrim myPrim) | 121 | public BSDynamics(BSScene myScene, BSPrim myPrim) |
131 | { | 122 | { |
@@ -137,7 +128,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
137 | // Return 'true' if this vehicle is doing vehicle things | 128 | // Return 'true' if this vehicle is doing vehicle things |
138 | public bool IsActive | 129 | public bool IsActive |
139 | { | 130 | { |
140 | get { return Type != Vehicle.TYPE_NONE; } | 131 | get { return Type != Vehicle.TYPE_NONE && Prim.IsPhysical; } |
141 | } | 132 | } |
142 | 133 | ||
143 | internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue) | 134 | internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue) |
@@ -152,13 +143,15 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
152 | m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); | 143 | m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); |
153 | break; | 144 | break; |
154 | case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: | 145 | case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: |
155 | m_angularMotorDecayTimescale = Math.Max(pValue, 0.01f); | 146 | m_angularMotorDecayTimescale = ClampInRange(0.01f, pValue, 120); |
147 | m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale; | ||
156 | break; | 148 | break; |
157 | case Vehicle.ANGULAR_MOTOR_TIMESCALE: | 149 | case Vehicle.ANGULAR_MOTOR_TIMESCALE: |
158 | m_angularMotorTimescale = Math.Max(pValue, 0.01f); | 150 | m_angularMotorTimescale = Math.Max(pValue, 0.01f); |
151 | m_angularMotor.TimeScale = m_angularMotorTimescale; | ||
159 | break; | 152 | break; |
160 | case Vehicle.BANKING_EFFICIENCY: | 153 | case Vehicle.BANKING_EFFICIENCY: |
161 | m_bankingEfficiency = Math.Max(-1f, Math.Min(pValue, 1f)); | 154 | m_bankingEfficiency = ClampInRange(-1f, pValue, 1f); |
162 | break; | 155 | break; |
163 | case Vehicle.BANKING_MIX: | 156 | case Vehicle.BANKING_MIX: |
164 | m_bankingMix = Math.Max(pValue, 0.01f); | 157 | m_bankingMix = Math.Max(pValue, 0.01f); |
@@ -167,10 +160,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
167 | m_bankingTimescale = Math.Max(pValue, 0.01f); | 160 | m_bankingTimescale = Math.Max(pValue, 0.01f); |
168 | break; | 161 | break; |
169 | case Vehicle.BUOYANCY: | 162 | case Vehicle.BUOYANCY: |
170 | m_VehicleBuoyancy = Math.Max(-1f, Math.Min(pValue, 1f)); | 163 | m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f); |
171 | break; | 164 | break; |
172 | case Vehicle.HOVER_EFFICIENCY: | 165 | case Vehicle.HOVER_EFFICIENCY: |
173 | m_VhoverEfficiency = Math.Max(0f, Math.Min(pValue, 1f)); | 166 | m_VhoverEfficiency = ClampInRange(0f, pValue, 1f); |
174 | break; | 167 | break; |
175 | case Vehicle.HOVER_HEIGHT: | 168 | case Vehicle.HOVER_HEIGHT: |
176 | m_VhoverHeight = pValue; | 169 | m_VhoverHeight = pValue; |
@@ -185,33 +178,40 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
185 | m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); | 178 | m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); |
186 | break; | 179 | break; |
187 | case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: | 180 | case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: |
188 | m_linearMotorDecayTimescale = Math.Max(pValue, 0.01f); | 181 | m_linearMotorDecayTimescale = ClampInRange(0.01f, pValue, 120); |
182 | m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale; | ||
189 | break; | 183 | break; |
190 | case Vehicle.LINEAR_MOTOR_TIMESCALE: | 184 | case Vehicle.LINEAR_MOTOR_TIMESCALE: |
191 | m_linearMotorTimescale = Math.Max(pValue, 0.01f); | 185 | m_linearMotorTimescale = Math.Max(pValue, 0.01f); |
186 | m_linearMotor.TimeScale = m_linearMotorTimescale; | ||
192 | break; | 187 | break; |
193 | case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: | 188 | case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: |
194 | m_verticalAttractionEfficiency = Math.Max(0.1f, Math.Min(pValue, 1f)); | 189 | m_verticalAttractionEfficiency = ClampInRange(0.1f, pValue, 1f); |
190 | m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency; | ||
195 | break; | 191 | break; |
196 | case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: | 192 | case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: |
197 | m_verticalAttractionTimescale = Math.Max(pValue, 0.01f); | 193 | m_verticalAttractionTimescale = Math.Max(pValue, 0.01f); |
194 | m_verticalAttractionMotor.TimeScale = m_verticalAttractionTimescale; | ||
198 | break; | 195 | break; |
199 | 196 | ||
200 | // These are vector properties but the engine lets you use a single float value to | 197 | // These are vector properties but the engine lets you use a single float value to |
201 | // set all of the components to the same value | 198 | // set all of the components to the same value |
202 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: | 199 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: |
203 | m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); | 200 | m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); |
201 | m_angularMotor.FrictionTimescale = m_angularFrictionTimescale; | ||
204 | break; | 202 | break; |
205 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | 203 | case Vehicle.ANGULAR_MOTOR_DIRECTION: |
206 | m_angularMotorDirection = new Vector3(pValue, pValue, pValue); | 204 | m_angularMotorDirection = new Vector3(pValue, pValue, pValue); |
207 | // m_angularMotorApply = 100; | 205 | m_angularMotor.SetTarget(m_angularMotorDirection); |
208 | break; | 206 | break; |
209 | case Vehicle.LINEAR_FRICTION_TIMESCALE: | 207 | case Vehicle.LINEAR_FRICTION_TIMESCALE: |
210 | m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); | 208 | m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); |
209 | m_linearMotor.FrictionTimescale = m_linearFrictionTimescale; | ||
211 | break; | 210 | break; |
212 | case Vehicle.LINEAR_MOTOR_DIRECTION: | 211 | case Vehicle.LINEAR_MOTOR_DIRECTION: |
213 | m_linearMotorDirection = new Vector3(pValue, pValue, pValue); | 212 | m_linearMotorDirection = new Vector3(pValue, pValue, pValue); |
214 | m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); | 213 | m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); |
214 | m_linearMotor.SetTarget(m_linearMotorDirection); | ||
215 | break; | 215 | break; |
216 | case Vehicle.LINEAR_MOTOR_OFFSET: | 216 | case Vehicle.LINEAR_MOTOR_OFFSET: |
217 | m_linearMotorOffset = new Vector3(pValue, pValue, pValue); | 217 | m_linearMotorOffset = new Vector3(pValue, pValue, pValue); |
@@ -227,21 +227,24 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
227 | { | 227 | { |
228 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: | 228 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: |
229 | m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | 229 | m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); |
230 | m_angularMotor.FrictionTimescale = m_angularFrictionTimescale; | ||
230 | break; | 231 | break; |
231 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | 232 | case Vehicle.ANGULAR_MOTOR_DIRECTION: |
232 | // Limit requested angular speed to 2 rps= 4 pi rads/sec | 233 | // Limit requested angular speed to 2 rps= 4 pi rads/sec |
233 | pValue.X = Math.Max(-12.56f, Math.Min(pValue.X, 12.56f)); | 234 | pValue.X = ClampInRange(-12.56f, pValue.X, 12.56f); |
234 | pValue.Y = Math.Max(-12.56f, Math.Min(pValue.Y, 12.56f)); | 235 | pValue.Y = ClampInRange(-12.56f, pValue.Y, 12.56f); |
235 | pValue.Z = Math.Max(-12.56f, Math.Min(pValue.Z, 12.56f)); | 236 | pValue.Z = ClampInRange(-12.56f, pValue.Z, 12.56f); |
236 | m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); | 237 | m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); |
237 | // m_angularMotorApply = 100; | 238 | m_angularMotor.SetTarget(m_angularMotorDirection); |
238 | break; | 239 | break; |
239 | case Vehicle.LINEAR_FRICTION_TIMESCALE: | 240 | case Vehicle.LINEAR_FRICTION_TIMESCALE: |
240 | m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | 241 | m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); |
242 | m_linearMotor.FrictionTimescale = m_linearFrictionTimescale; | ||
241 | break; | 243 | break; |
242 | case Vehicle.LINEAR_MOTOR_DIRECTION: | 244 | case Vehicle.LINEAR_MOTOR_DIRECTION: |
243 | m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); | 245 | m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); |
244 | m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); | 246 | m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); |
247 | m_linearMotor.SetTarget(m_linearMotorDirection); | ||
245 | break; | 248 | break; |
246 | case Vehicle.LINEAR_MOTOR_OFFSET: | 249 | case Vehicle.LINEAR_MOTOR_OFFSET: |
247 | m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); | 250 | m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); |
@@ -303,7 +306,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
303 | m_VhoverEfficiency = 0; | 306 | m_VhoverEfficiency = 0; |
304 | m_VhoverTimescale = 0; | 307 | m_VhoverTimescale = 0; |
305 | m_VehicleBuoyancy = 0; | 308 | m_VehicleBuoyancy = 0; |
306 | 309 | ||
307 | m_linearDeflectionEfficiency = 1; | 310 | m_linearDeflectionEfficiency = 1; |
308 | m_linearDeflectionTimescale = 1; | 311 | m_linearDeflectionTimescale = 1; |
309 | 312 | ||
@@ -319,6 +322,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
319 | 322 | ||
320 | m_referenceFrame = Quaternion.Identity; | 323 | m_referenceFrame = Quaternion.Identity; |
321 | m_flags = (VehicleFlag)0; | 324 | m_flags = (VehicleFlag)0; |
325 | |||
322 | break; | 326 | break; |
323 | 327 | ||
324 | case Vehicle.TYPE_SLED: | 328 | case Vehicle.TYPE_SLED: |
@@ -351,10 +355,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
351 | m_bankingMix = 1; | 355 | m_bankingMix = 1; |
352 | 356 | ||
353 | m_referenceFrame = Quaternion.Identity; | 357 | m_referenceFrame = Quaternion.Identity; |
354 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP); | 358 | m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY |
355 | m_flags &= | 359 | | VehicleFlag.HOVER_TERRAIN_ONLY |
356 | ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | | 360 | | VehicleFlag.HOVER_GLOBAL_HEIGHT |
357 | VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); | 361 | | VehicleFlag.HOVER_UP_ONLY); |
362 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | ||
363 | | VehicleFlag.LIMIT_ROLL_ONLY | ||
364 | | VehicleFlag.LIMIT_MOTOR_UP); | ||
365 | |||
358 | break; | 366 | break; |
359 | case Vehicle.TYPE_CAR: | 367 | case Vehicle.TYPE_CAR: |
360 | m_linearMotorDirection = Vector3.Zero; | 368 | m_linearMotorDirection = Vector3.Zero; |
@@ -498,6 +506,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
498 | m_bankingEfficiency = 0; | 506 | m_bankingEfficiency = 0; |
499 | m_bankingMix = 0.7f; | 507 | m_bankingMix = 0.7f; |
500 | m_bankingTimescale = 5; | 508 | m_bankingTimescale = 5; |
509 | |||
501 | m_referenceFrame = Quaternion.Identity; | 510 | m_referenceFrame = Quaternion.Identity; |
502 | 511 | ||
503 | m_referenceFrame = Quaternion.Identity; | 512 | m_referenceFrame = Quaternion.Identity; |
@@ -510,6 +519,26 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
510 | | VehicleFlag.HOVER_GLOBAL_HEIGHT); | 519 | | VehicleFlag.HOVER_GLOBAL_HEIGHT); |
511 | break; | 520 | break; |
512 | } | 521 | } |
522 | |||
523 | // Update any physical parameters based on this type. | ||
524 | Refresh(); | ||
525 | |||
526 | m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale, | ||
527 | m_linearMotorDecayTimescale, m_linearFrictionTimescale, | ||
528 | 1f); | ||
529 | m_linearMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) | ||
530 | |||
531 | m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, | ||
532 | m_angularMotorDecayTimescale, m_angularFrictionTimescale, | ||
533 | 1f); | ||
534 | m_angularMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) | ||
535 | |||
536 | m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale, | ||
537 | BSMotor.Infinite, BSMotor.InfiniteVector, | ||
538 | m_verticalAttractionEfficiency); | ||
539 | // Z goes away and we keep X and Y | ||
540 | m_verticalAttractionMotor.FrictionTimescale = new Vector3(BSMotor.Infinite, BSMotor.Infinite, 0.1f); | ||
541 | m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) | ||
513 | } | 542 | } |
514 | 543 | ||
515 | // Some of the properties of this prim may have changed. | 544 | // Some of the properties of this prim may have changed. |
@@ -518,13 +547,35 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
518 | { | 547 | { |
519 | if (IsActive) | 548 | if (IsActive) |
520 | { | 549 | { |
521 | // Friction effects are handled by this vehicle code | 550 | // Remember the mass so we don't have to fetch it every step |
522 | BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, 0f); | 551 | m_vehicleMass = Prim.Linkset.LinksetMass; |
523 | BulletSimAPI.SetHitFraction2(Prim.PhysBody.ptr, 0f); | 552 | |
524 | 553 | // Friction affects are handled by this vehicle code | |
525 | // BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, 0.8f); | 554 | float friction = 0f; |
526 | 555 | BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, friction); | |
527 | VDetailLog("{0},BSDynamics.Refresh,zeroingFriction and adding damping", Prim.LocalID); | 556 | |
557 | // Moderate angular movement introduced by Bullet. | ||
558 | // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle. | ||
559 | // Maybe compute linear and angular factor and damping from params. | ||
560 | float angularDamping = PhysicsScene.Params.vehicleAngularDamping; | ||
561 | BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, angularDamping); | ||
562 | |||
563 | // Vehicles report collision events so we know when it's on the ground | ||
564 | BulletSimAPI.AddToCollisionFlags2(Prim.PhysBody.ptr, CollisionFlags.BS_VEHICLE_COLLISIONS); | ||
565 | |||
566 | // DEBUG DEBUG DEBUG: use uniform inertia to smooth movement added by Bullet | ||
567 | // Vector3 localInertia = new Vector3(1f, 1f, 1f); | ||
568 | // Vector3 localInertia = new Vector3(m_vehicleMass, m_vehicleMass, m_vehicleMass); | ||
569 | Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(Prim.PhysShape.ptr, m_vehicleMass); | ||
570 | BulletSimAPI.SetMassProps2(Prim.PhysBody.ptr, m_vehicleMass, localInertia); | ||
571 | BulletSimAPI.UpdateInertiaTensor2(Prim.PhysBody.ptr); | ||
572 | |||
573 | VDetailLog("{0},BSDynamics.Refresh,mass={1},frict={2},inert={3},aDamp={4}", | ||
574 | Prim.LocalID, m_vehicleMass, friction, localInertia, angularDamping); | ||
575 | } | ||
576 | else | ||
577 | { | ||
578 | BulletSimAPI.RemoveFromCollisionFlags2(Prim.PhysBody.ptr, CollisionFlags.BS_VEHICLE_COLLISIONS); | ||
528 | } | 579 | } |
529 | } | 580 | } |
530 | 581 | ||
@@ -546,116 +597,294 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
546 | Refresh(); | 597 | Refresh(); |
547 | } | 598 | } |
548 | 599 | ||
600 | #region Known vehicle value functions | ||
601 | // Vehicle physical parameters that we buffer from constant getting and setting. | ||
602 | // The "m_known*" variables are initialized to 'null', fetched only if referenced | ||
603 | // and stored back into the physics engine only if updated. | ||
604 | // This does two things: 1) saves continuious calls into unmanaged code, and | ||
605 | // 2) signals when a physics property update must happen back to the simulator | ||
606 | // to update values modified for the vehicle. | ||
607 | private int m_knownChanged; | ||
608 | private float? m_knownTerrainHeight; | ||
609 | private float? m_knownWaterLevel; | ||
610 | private Vector3? m_knownPosition; | ||
611 | private Vector3? m_knownVelocity; | ||
612 | private Vector3 m_knownForce; | ||
613 | private Quaternion? m_knownOrientation; | ||
614 | private Vector3? m_knownRotationalVelocity; | ||
615 | private Vector3 m_knownRotationalForce; | ||
616 | private float? m_knownForwardSpeed; | ||
617 | |||
618 | private const int m_knownChangedPosition = 1 << 0; | ||
619 | private const int m_knownChangedVelocity = 1 << 1; | ||
620 | private const int m_knownChangedForce = 1 << 2; | ||
621 | private const int m_knownChangedOrientation = 1 << 3; | ||
622 | private const int m_knownChangedRotationalVelocity = 1 << 4; | ||
623 | private const int m_knownChangedRotationalForce = 1 << 5; | ||
624 | |||
625 | private void ForgetKnownVehicleProperties() | ||
626 | { | ||
627 | m_knownTerrainHeight = null; | ||
628 | m_knownWaterLevel = null; | ||
629 | m_knownPosition = null; | ||
630 | m_knownVelocity = null; | ||
631 | m_knownForce = Vector3.Zero; | ||
632 | m_knownOrientation = null; | ||
633 | m_knownRotationalVelocity = null; | ||
634 | m_knownRotationalForce = Vector3.Zero; | ||
635 | m_knownForwardSpeed = null; | ||
636 | m_knownChanged = 0; | ||
637 | } | ||
638 | private void PushKnownChanged() | ||
639 | { | ||
640 | if (m_knownChanged != 0) | ||
641 | { | ||
642 | if ((m_knownChanged & m_knownChangedPosition) != 0) | ||
643 | Prim.ForcePosition = VehiclePosition; | ||
644 | if ((m_knownChanged & m_knownChangedOrientation) != 0) | ||
645 | Prim.ForceOrientation = VehicleOrientation; | ||
646 | if ((m_knownChanged & m_knownChangedVelocity) != 0) | ||
647 | { | ||
648 | Prim.ForceVelocity = VehicleVelocity; | ||
649 | BulletSimAPI.SetInterpolationLinearVelocity2(Prim.PhysBody.ptr, VehicleVelocity); | ||
650 | } | ||
651 | if ((m_knownChanged & m_knownChangedForce) != 0) | ||
652 | Prim.AddForce((Vector3)m_knownForce, false, true); | ||
653 | |||
654 | if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0) | ||
655 | { | ||
656 | Prim.ForceRotationalVelocity = VehicleRotationalVelocity; | ||
657 | // Fake out Bullet by making it think the velocity is the same as last time. | ||
658 | BulletSimAPI.SetInterpolationAngularVelocity2(Prim.PhysBody.ptr, VehicleRotationalVelocity); | ||
659 | } | ||
660 | if ((m_knownChanged & m_knownChangedRotationalForce) != 0) | ||
661 | Prim.AddAngularForce((Vector3)m_knownRotationalForce, false, true); | ||
662 | |||
663 | // If we set one of the values (ie, the physics engine didn't do it) we must force | ||
664 | // an UpdateProperties event to send the changes up to the simulator. | ||
665 | BulletSimAPI.PushUpdate2(Prim.PhysBody.ptr); | ||
666 | } | ||
667 | m_knownChanged = 0; | ||
668 | } | ||
669 | |||
670 | // Since the computation of terrain height can be a little involved, this routine | ||
671 | // is used ot fetch the height only once for each vehicle simulation step. | ||
672 | private float GetTerrainHeight(Vector3 pos) | ||
673 | { | ||
674 | if (m_knownTerrainHeight == null) | ||
675 | m_knownTerrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); | ||
676 | return (float)m_knownTerrainHeight; | ||
677 | } | ||
678 | |||
679 | // Since the computation of water level can be a little involved, this routine | ||
680 | // is used ot fetch the level only once for each vehicle simulation step. | ||
681 | private float GetWaterLevel(Vector3 pos) | ||
682 | { | ||
683 | if (m_knownWaterLevel == null) | ||
684 | m_knownWaterLevel = Prim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos); | ||
685 | return (float)m_knownWaterLevel; | ||
686 | } | ||
687 | |||
688 | private Vector3 VehiclePosition | ||
689 | { | ||
690 | get | ||
691 | { | ||
692 | if (m_knownPosition == null) | ||
693 | m_knownPosition = Prim.ForcePosition; | ||
694 | return (Vector3)m_knownPosition; | ||
695 | } | ||
696 | set | ||
697 | { | ||
698 | m_knownPosition = value; | ||
699 | m_knownChanged |= m_knownChangedPosition; | ||
700 | } | ||
701 | } | ||
702 | |||
703 | private Quaternion VehicleOrientation | ||
704 | { | ||
705 | get | ||
706 | { | ||
707 | if (m_knownOrientation == null) | ||
708 | m_knownOrientation = Prim.ForceOrientation; | ||
709 | return (Quaternion)m_knownOrientation; | ||
710 | } | ||
711 | set | ||
712 | { | ||
713 | m_knownOrientation = value; | ||
714 | m_knownChanged |= m_knownChangedOrientation; | ||
715 | } | ||
716 | } | ||
717 | |||
718 | private Vector3 VehicleVelocity | ||
719 | { | ||
720 | get | ||
721 | { | ||
722 | if (m_knownVelocity == null) | ||
723 | m_knownVelocity = Prim.ForceVelocity; | ||
724 | return (Vector3)m_knownVelocity; | ||
725 | } | ||
726 | set | ||
727 | { | ||
728 | m_knownVelocity = value; | ||
729 | m_knownChanged |= m_knownChangedVelocity; | ||
730 | } | ||
731 | } | ||
732 | |||
733 | private void VehicleAddForce(Vector3 aForce) | ||
734 | { | ||
735 | m_knownForce += aForce; | ||
736 | m_knownChanged |= m_knownChangedForce; | ||
737 | } | ||
738 | |||
739 | private Vector3 VehicleRotationalVelocity | ||
740 | { | ||
741 | get | ||
742 | { | ||
743 | if (m_knownRotationalVelocity == null) | ||
744 | m_knownRotationalVelocity = Prim.ForceRotationalVelocity; | ||
745 | return (Vector3)m_knownRotationalVelocity; | ||
746 | } | ||
747 | set | ||
748 | { | ||
749 | m_knownRotationalVelocity = value; | ||
750 | m_knownChanged |= m_knownChangedRotationalVelocity; | ||
751 | } | ||
752 | } | ||
753 | private void VehicleAddAngularForce(Vector3 aForce) | ||
754 | { | ||
755 | m_knownRotationalForce += aForce; | ||
756 | m_knownChanged |= m_knownChangedRotationalForce; | ||
757 | } | ||
758 | private float VehicleForwardSpeed | ||
759 | { | ||
760 | get | ||
761 | { | ||
762 | if (m_knownForwardSpeed == null) | ||
763 | m_knownForwardSpeed = (VehicleVelocity * Quaternion.Inverse(VehicleOrientation)).X; | ||
764 | return (float)m_knownForwardSpeed; | ||
765 | } | ||
766 | } | ||
767 | |||
768 | #endregion // Known vehicle value functions | ||
769 | |||
549 | // One step of the vehicle properties for the next 'pTimestep' seconds. | 770 | // One step of the vehicle properties for the next 'pTimestep' seconds. |
550 | internal void Step(float pTimestep) | 771 | internal void Step(float pTimestep) |
551 | { | 772 | { |
552 | if (!IsActive) return; | 773 | if (!IsActive) return; |
553 | 774 | ||
554 | // DEBUG | 775 | ForgetKnownVehicleProperties(); |
555 | // Because Bullet does apply forces to the vehicle, our last computed | ||
556 | // linear and angular velocities are not what is happening now. | ||
557 | // Vector3 externalAngularVelocity = Prim.ForceRotationalVelocity - m_lastAngularVelocity; | ||
558 | // m_lastAngularVelocity += (externalAngularVelocity * 0.5f) * pTimestep; | ||
559 | // m_lastAngularVelocity = Prim.ForceRotationalVelocity; // DEBUG: account for what Bullet did last time | ||
560 | // m_lastLinearVelocityVector = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG: | ||
561 | // END DEBUG | ||
562 | |||
563 | m_vehicleMass = Prim.Linkset.LinksetMass; | ||
564 | 776 | ||
565 | MoveLinear(pTimestep); | 777 | MoveLinear(pTimestep); |
566 | // Commented out for debug | ||
567 | MoveAngular(pTimestep); | 778 | MoveAngular(pTimestep); |
568 | // Prim.ApplyTorqueImpulse(-Prim.RotationalVelocity * m_vehicleMass, false); // DEBUG DEBUG | ||
569 | // Prim.ForceRotationalVelocity = -Prim.RotationalVelocity; // DEBUG DEBUG | ||
570 | 779 | ||
571 | LimitRotation(pTimestep); | 780 | LimitRotation(pTimestep); |
572 | 781 | ||
573 | // remember the position so next step we can limit absolute movement effects | 782 | // remember the position so next step we can limit absolute movement effects |
574 | m_lastPositionVector = Prim.ForcePosition; | 783 | m_lastPositionVector = VehiclePosition; |
575 | 784 | ||
576 | VDetailLog("{0},BSDynamics.Step,frict={1},grav={2},inertia={3},mass={4}", // DEBUG DEBUG | 785 | // If we forced the changing of some vehicle parameters, update the values and |
577 | Prim.LocalID, | 786 | // for the physics engine to note the changes so an UpdateProperties event will happen. |
578 | BulletSimAPI.GetFriction2(Prim.PhysBody.ptr), | 787 | PushKnownChanged(); |
579 | BulletSimAPI.GetGravity2(Prim.PhysBody.ptr), | 788 | |
580 | Prim.Inertia, | ||
581 | m_vehicleMass | ||
582 | ); | ||
583 | VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", | 789 | VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", |
584 | Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity); | 790 | Prim.LocalID, VehiclePosition, Prim.Force, VehicleVelocity, VehicleRotationalVelocity); |
585 | }// end Step | 791 | } |
586 | 792 | ||
587 | // Apply the effect of the linear motor. | 793 | // Apply the effect of the linear motor and other linear motions (like hover and float). |
588 | // Also does hover and float. | ||
589 | private void MoveLinear(float pTimestep) | 794 | private void MoveLinear(float pTimestep) |
590 | { | 795 | { |
591 | // m_linearMotorDirection is the target direction we are moving relative to the vehicle coordinates | 796 | Vector3 linearMotorContribution = m_linearMotor.Step(pTimestep); |
592 | // m_lastLinearVelocityVector is the current speed we are moving in that direction | ||
593 | if (m_linearMotorDirection.LengthSquared() > 0.001f) | ||
594 | { | ||
595 | Vector3 origDir = m_linearMotorDirection; // DEBUG | ||
596 | Vector3 origVel = m_lastLinearVelocityVector; // DEBUG | ||
597 | // DEBUG: the vehicle velocity rotated to be relative to vehicle coordinates for comparison | ||
598 | Vector3 vehicleVelocity = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG | ||
599 | 797 | ||
600 | // Add (desiredVelocity - lastAppliedVelocity) / howLongItShouldTakeToComplete | 798 | // The movement computed in the linear motor is relative to the vehicle |
601 | Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/(m_linearMotorTimescale) * pTimestep; | 799 | // coordinates. Rotate the movement to world coordinates. |
602 | m_lastLinearVelocityVector += addAmount; | 800 | linearMotorContribution *= VehicleOrientation; |
603 | 801 | ||
604 | float decayFactor = (1.0f / m_linearMotorDecayTimescale) * pTimestep; | 802 | // ================================================================== |
605 | m_linearMotorDirection *= (1f - decayFactor); | 803 | // Buoyancy: force to overcome gravity. |
804 | // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; | ||
805 | // So, if zero, don't change anything (let gravity happen). If one, negate the effect of gravity. | ||
806 | Vector3 buoyancyContribution = Prim.PhysicsScene.DefaultGravity * m_VehicleBuoyancy; | ||
606 | 807 | ||
607 | // Rotate new object velocity from vehicle relative to world coordinates | 808 | Vector3 terrainHeightContribution = ComputeLinearTerrainHeightCorrection(pTimestep); |
608 | m_newVelocity = m_lastLinearVelocityVector * Prim.ForceOrientation; | ||
609 | 809 | ||
610 | // Apply friction for next time | 810 | Vector3 hoverContribution = ComputeLinearHover(pTimestep); |
611 | Vector3 frictionFactor = (Vector3.One / m_linearFrictionTimescale) * pTimestep; | ||
612 | m_lastLinearVelocityVector *= (Vector3.One - frictionFactor); | ||
613 | 811 | ||
614 | VDetailLog("{0},MoveLinear,nonZero,origlmDir={1},origlvVel={2},vehVel={3},add={4},decay={5},frict={6},lmDir={7},lvVec={8},newVel={9}", | 812 | ComputeLinearBlockingEndPoint(pTimestep); |
615 | Prim.LocalID, origDir, origVel, vehicleVelocity, addAmount, decayFactor, frictionFactor, | ||
616 | m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity); | ||
617 | } | ||
618 | else | ||
619 | { | ||
620 | // if what remains of direction is very small, zero it. | ||
621 | m_linearMotorDirection = Vector3.Zero; | ||
622 | m_lastLinearVelocityVector = Vector3.Zero; | ||
623 | m_newVelocity = Vector3.Zero; | ||
624 | 813 | ||
625 | VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID); | 814 | Vector3 limitMotorUpContribution = ComputeLinearMotorUp(pTimestep); |
626 | } | ||
627 | 815 | ||
628 | // m_newVelocity is velocity computed from linear motor in world coordinates | 816 | // ================================================================== |
817 | Vector3 newVelocity = linearMotorContribution | ||
818 | + terrainHeightContribution | ||
819 | + hoverContribution | ||
820 | + limitMotorUpContribution; | ||
629 | 821 | ||
630 | // Gravity and Buoyancy | 822 | Vector3 newForce = buoyancyContribution; |
631 | // There is some gravity, make a gravity force vector that is applied after object velocity. | 823 | |
632 | // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; | 824 | // If not changing some axis, reduce out velocity |
633 | Vector3 grav = Prim.PhysicsScene.DefaultGravity * (1f - m_VehicleBuoyancy); | 825 | if ((m_flags & (VehicleFlag.NO_X)) != 0) |
826 | newVelocity.X = 0; | ||
827 | if ((m_flags & (VehicleFlag.NO_Y)) != 0) | ||
828 | newVelocity.Y = 0; | ||
829 | if ((m_flags & (VehicleFlag.NO_Z)) != 0) | ||
830 | newVelocity.Z = 0; | ||
634 | 831 | ||
635 | /* | 832 | // ================================================================== |
636 | * RA: Not sure why one would do this unless we are hoping external forces are doing gravity, ... | 833 | // Clamp high or low velocities |
637 | // Preserve the current Z velocity | 834 | float newVelocityLengthSq = newVelocity.LengthSquared(); |
638 | Vector3 vel_now = m_prim.Velocity; | 835 | // if (newVelocityLengthSq > 1e6f) |
639 | m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity | 836 | if (newVelocityLengthSq > 1000f) |
640 | */ | 837 | { |
838 | newVelocity /= newVelocity.Length(); | ||
839 | newVelocity *= 1000f; | ||
840 | } | ||
841 | // else if (newVelocityLengthSq < 1e-6f) | ||
842 | else if (newVelocityLengthSq < 0.001f) | ||
843 | newVelocity = Vector3.Zero; | ||
844 | |||
845 | // ================================================================== | ||
846 | // Stuff new linear velocity into the vehicle. | ||
847 | // Since the velocity is just being set, it is not scaled by pTimeStep. Bullet will do that for us. | ||
848 | VehicleVelocity = newVelocity; | ||
849 | |||
850 | // Other linear forces are applied as forces. | ||
851 | Vector3 totalDownForce = newForce * m_vehicleMass; | ||
852 | if (!totalDownForce.ApproxEquals(Vector3.Zero, 0.01f)) | ||
853 | { | ||
854 | VehicleAddForce(totalDownForce); | ||
855 | } | ||
856 | |||
857 | VDetailLog("{0}, MoveLinear,done,newVel={1},totDown={2},IsColliding={3}", | ||
858 | Prim.LocalID, newVelocity, totalDownForce, Prim.IsColliding); | ||
859 | VDetailLog("{0}, MoveLinear,done,linContrib={1},terrContrib={2},hoverContrib={3},limitContrib={4},buoyContrib={5}", | ||
860 | Prim.LocalID, | ||
861 | linearMotorContribution, terrainHeightContribution, hoverContribution, | ||
862 | limitMotorUpContribution, buoyancyContribution | ||
863 | ); | ||
641 | 864 | ||
642 | Vector3 pos = Prim.ForcePosition; | 865 | } // end MoveLinear() |
643 | // 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); | ||
644 | 866 | ||
867 | public Vector3 ComputeLinearTerrainHeightCorrection(float pTimestep) | ||
868 | { | ||
869 | Vector3 ret = Vector3.Zero; | ||
645 | // If below the terrain, move us above the ground a little. | 870 | // If below the terrain, move us above the ground a little. |
646 | float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); | 871 | // TODO: Consider taking the rotated size of the object or possibly casting a ray. |
647 | // Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset. | 872 | if (VehiclePosition.Z < GetTerrainHeight(VehiclePosition)) |
648 | // TODO: Add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass. | ||
649 | // Vector3 rotatedSize = m_prim.Size * m_prim.ForceOrientation; | ||
650 | // if (rotatedSize.Z < terrainHeight) | ||
651 | if (pos.Z < terrainHeight) | ||
652 | { | 873 | { |
653 | pos.Z = terrainHeight + 2; | 874 | // TODO: correct position by applying force rather than forcing position. |
654 | Prim.ForcePosition = pos; | 875 | Vector3 newPosition = VehiclePosition; |
655 | VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos); | 876 | newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f; |
877 | VehiclePosition = newPosition; | ||
878 | VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}", | ||
879 | Prim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition); | ||
656 | } | 880 | } |
881 | return ret; | ||
882 | } | ||
883 | |||
884 | public Vector3 ComputeLinearHover(float pTimestep) | ||
885 | { | ||
886 | Vector3 ret = Vector3.Zero; | ||
657 | 887 | ||
658 | // Check if hovering | ||
659 | // m_VhoverEfficiency: 0=bouncy, 1=totally damped | 888 | // m_VhoverEfficiency: 0=bouncy, 1=totally damped |
660 | // m_VhoverTimescale: time to achieve height | 889 | // m_VhoverTimescale: time to achieve height |
661 | if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) | 890 | if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) |
@@ -663,11 +892,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
663 | // We should hover, get the target height | 892 | // We should hover, get the target height |
664 | if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0) | 893 | if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0) |
665 | { | 894 | { |
666 | m_VhoverTargetHeight = Prim.PhysicsScene.GetWaterLevelAtXYZ(pos) + m_VhoverHeight; | 895 | m_VhoverTargetHeight = GetWaterLevel(VehiclePosition) + m_VhoverHeight; |
667 | } | 896 | } |
668 | if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) | 897 | if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) |
669 | { | 898 | { |
670 | m_VhoverTargetHeight = terrainHeight + m_VhoverHeight; | 899 | m_VhoverTargetHeight = GetTerrainHeight(VehiclePosition) + m_VhoverHeight; |
671 | } | 900 | } |
672 | if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) | 901 | if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) |
673 | { | 902 | { |
@@ -677,45 +906,47 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
677 | if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0) | 906 | if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0) |
678 | { | 907 | { |
679 | // If body is already heigher, use its height as target height | 908 | // If body is already heigher, use its height as target height |
680 | if (pos.Z > m_VhoverTargetHeight) | 909 | if (VehiclePosition.Z > m_VhoverTargetHeight) |
681 | m_VhoverTargetHeight = pos.Z; | 910 | m_VhoverTargetHeight = VehiclePosition.Z; |
682 | } | 911 | } |
912 | |||
683 | if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) | 913 | if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) |
684 | { | 914 | { |
685 | if (Math.Abs(pos.Z - m_VhoverTargetHeight) > 0.2f) | 915 | if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f) |
686 | { | 916 | { |
917 | Vector3 pos = VehiclePosition; | ||
687 | pos.Z = m_VhoverTargetHeight; | 918 | pos.Z = m_VhoverTargetHeight; |
688 | Prim.ForcePosition = pos; | 919 | VehiclePosition = pos; |
689 | } | 920 | } |
690 | } | 921 | } |
691 | else | 922 | else |
692 | { | 923 | { |
693 | float verticalError = pos.Z - m_VhoverTargetHeight; | 924 | // Error is positive if below the target and negative if above. |
694 | // RA: where does the 50 come from? | 925 | float verticalError = m_VhoverTargetHeight - VehiclePosition.Z; |
695 | float verticalCorrectionVelocity = pTimestep * ((verticalError * 50.0f) / m_VhoverTimescale); | 926 | float verticalCorrectionVelocity = verticalError / m_VhoverTimescale; |
696 | // Replace Vertical speed with correction figure if significant | 927 | |
697 | if (Math.Abs(verticalError) > 0.01f) | 928 | // TODO: implement m_VhoverEfficiency correctly |
698 | { | 929 | if (Math.Abs(verticalError) > m_VhoverEfficiency) |
699 | m_newVelocity.Z += verticalCorrectionVelocity; | ||
700 | //KF: m_VhoverEfficiency is not yet implemented | ||
701 | } | ||
702 | else if (verticalError < -0.01) | ||
703 | { | ||
704 | m_newVelocity.Z -= verticalCorrectionVelocity; | ||
705 | } | ||
706 | else | ||
707 | { | 930 | { |
708 | m_newVelocity.Z = 0f; | 931 | ret = new Vector3(0f, 0f, verticalCorrectionVelocity); |
709 | } | 932 | } |
710 | } | 933 | } |
711 | 934 | ||
712 | VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", Prim.LocalID, pos, m_newVelocity, m_VhoverHeight, m_VhoverTargetHeight); | 935 | VDetailLog("{0}, MoveLinear,hover,pos={1},ret={2},hoverTS={3},height={4},target={5}", |
936 | Prim.LocalID, VehiclePosition, ret, m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight); | ||
713 | } | 937 | } |
714 | 938 | ||
939 | return ret; | ||
940 | } | ||
941 | |||
942 | public bool ComputeLinearBlockingEndPoint(float pTimestep) | ||
943 | { | ||
944 | bool changed = false; | ||
945 | |||
946 | Vector3 pos = VehiclePosition; | ||
715 | Vector3 posChange = pos - m_lastPositionVector; | 947 | Vector3 posChange = pos - m_lastPositionVector; |
716 | if (m_BlockingEndPoint != Vector3.Zero) | 948 | if (m_BlockingEndPoint != Vector3.Zero) |
717 | { | 949 | { |
718 | bool changed = false; | ||
719 | if (pos.X >= (m_BlockingEndPoint.X - (float)1)) | 950 | if (pos.X >= (m_BlockingEndPoint.X - (float)1)) |
720 | { | 951 | { |
721 | pos.X -= posChange.X + 1; | 952 | pos.X -= posChange.X + 1; |
@@ -743,233 +974,110 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
743 | } | 974 | } |
744 | if (changed) | 975 | if (changed) |
745 | { | 976 | { |
746 | Prim.ForcePosition = pos; | 977 | VehiclePosition = pos; |
747 | VDetailLog("{0},MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", | 978 | VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", |
748 | Prim.LocalID, m_BlockingEndPoint, posChange, pos); | 979 | Prim.LocalID, m_BlockingEndPoint, posChange, pos); |
749 | } | 980 | } |
750 | } | 981 | } |
982 | return changed; | ||
983 | } | ||
751 | 984 | ||
752 | #region downForce | 985 | // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags : |
753 | Vector3 downForce = Vector3.Zero; | 986 | // Prevent ground vehicles from motoring into the sky. This flag has a subtle effect when |
987 | // used with conjunction with banking: the strength of the banking will decay when the | ||
988 | // vehicle no longer experiences collisions. The decay timescale is the same as | ||
989 | // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering | ||
990 | // when they are in mid jump. | ||
991 | // TODO: this code is wrong. Also, what should it do for boats (height from water)? | ||
992 | // This is just using the ground and a general collision check. Should really be using | ||
993 | // a downward raycast to find what is below. | ||
994 | public Vector3 ComputeLinearMotorUp(float pTimestep) | ||
995 | { | ||
996 | Vector3 ret = Vector3.Zero; | ||
997 | float distanceAboveGround = 0f; | ||
754 | 998 | ||
755 | if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) | 999 | if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) |
756 | { | 1000 | { |
757 | // If the vehicle is motoring into the sky, get it going back down. | 1001 | float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition); |
758 | // Is this an angular force or both linear and angular?? | 1002 | distanceAboveGround = VehiclePosition.Z - targetHeight; |
759 | float distanceAboveGround = pos.Z - terrainHeight; | 1003 | // Not colliding if the vehicle is off the ground |
760 | if (distanceAboveGround > 2f) | 1004 | if (!Prim.IsColliding) |
761 | { | 1005 | { |
762 | // downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep); | 1006 | // downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep); |
763 | // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); | 1007 | // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); |
764 | downForce = new Vector3(0, 0, -distanceAboveGround); | 1008 | ret = new Vector3(0, 0, -distanceAboveGround); |
765 | } | 1009 | } |
766 | // TODO: this calculation is all wrong. From the description at | 1010 | // TODO: this calculation is wrong. From the description at |
767 | // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce | 1011 | // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce |
768 | // has a decay factor. This says this force should | 1012 | // has a decay factor. This says this force should |
769 | // be computed with a motor. | 1013 | // be computed with a motor. |
770 | VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}", | 1014 | // TODO: add interaction with banking. |
771 | Prim.LocalID, distanceAboveGround, downForce); | ||
772 | } | ||
773 | #endregion // downForce | ||
774 | |||
775 | // If not changing some axis, reduce out velocity | ||
776 | if ((m_flags & (VehicleFlag.NO_X)) != 0) | ||
777 | m_newVelocity.X = 0; | ||
778 | if ((m_flags & (VehicleFlag.NO_Y)) != 0) | ||
779 | m_newVelocity.Y = 0; | ||
780 | if ((m_flags & (VehicleFlag.NO_Z)) != 0) | ||
781 | m_newVelocity.Z = 0; | ||
782 | |||
783 | // Clamp REALLY high or low velocities | ||
784 | if (m_newVelocity.LengthSquared() > 1e6f) | ||
785 | { | ||
786 | m_newVelocity /= m_newVelocity.Length(); | ||
787 | m_newVelocity *= 1000f; | ||
788 | } | 1015 | } |
789 | else if (m_newVelocity.LengthSquared() < 1e-6f) | 1016 | VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}", |
790 | m_newVelocity = Vector3.Zero; | 1017 | Prim.LocalID, distanceAboveGround, Prim.IsColliding, ret); |
791 | 1018 | return ret; | |
792 | // Stuff new linear velocity into the vehicle | 1019 | } |
793 | Prim.ForceVelocity = m_newVelocity; | ||
794 | // Prim.ApplyForceImpulse((m_newVelocity - Prim.Velocity) * m_vehicleMass, false); // DEBUG DEBUG | ||
795 | |||
796 | Vector3 totalDownForce = downForce + grav; | ||
797 | if (totalDownForce != Vector3.Zero) | ||
798 | { | ||
799 | Prim.AddForce(totalDownForce * m_vehicleMass, false); | ||
800 | // Prim.ApplyForceImpulse(totalDownForce * m_vehicleMass, false); | ||
801 | } | ||
802 | |||
803 | VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},primVel={4},totalDown={5}", | ||
804 | Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, Prim.Velocity, totalDownForce); | ||
805 | |||
806 | } // end MoveLinear() | ||
807 | 1020 | ||
808 | // ======================================================================= | 1021 | // ======================================================================= |
1022 | // ======================================================================= | ||
809 | // Apply the effect of the angular motor. | 1023 | // Apply the effect of the angular motor. |
1024 | // The 'contribution' is how much angular correction velocity each function wants. | ||
1025 | // All the contributions are added together and the resulting velocity is | ||
1026 | // set directly on the vehicle. | ||
810 | private void MoveAngular(float pTimestep) | 1027 | private void MoveAngular(float pTimestep) |
811 | { | 1028 | { |
812 | // m_angularMotorDirection // angular velocity requested by LSL motor | 1029 | // The user wants how many radians per second angular change? |
813 | // m_angularMotorApply // application frame counter | 1030 | Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep); |
814 | // m_angularMotorVelocity // current angular motor velocity (ramps up and down) | 1031 | |
815 | // m_angularMotorTimescale // motor angular velocity ramp up rate | 1032 | // ================================================================== |
816 | // m_angularMotorDecayTimescale // motor angular velocity decay rate | 1033 | // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags : |
817 | // m_angularFrictionTimescale // body angular velocity decay rate | 1034 | // This flag prevents linear deflection parallel to world z-axis. This is useful |
818 | // m_lastAngularVelocity // what was last applied to body | 1035 | // for preventing ground vehicles with large linear deflection, like bumper cars, |
819 | 1036 | // from climbing their linear deflection into the sky. | |
820 | if (m_angularMotorDirection.LengthSquared() > 0.0001) | 1037 | // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement |
821 | { | 1038 | if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) |
822 | Vector3 origVel = m_angularMotorVelocity; | ||
823 | Vector3 origDir = m_angularMotorDirection; | ||
824 | |||
825 | // new velocity += error / ( time to get there / step interval) | ||
826 | // requested direction - current vehicle direction | ||
827 | m_angularMotorVelocity += (m_angularMotorDirection - m_angularMotorVelocity) / (m_angularMotorTimescale / pTimestep); | ||
828 | // decay requested direction | ||
829 | m_angularMotorDirection *= (1.0f - (pTimestep * 1.0f/m_angularMotorDecayTimescale)); | ||
830 | |||
831 | VDetailLog("{0},MoveAngular,angularMotorApply,angTScale={1},timeStep={2},origvel={3},origDir={4},vel={5}", | ||
832 | Prim.LocalID, m_angularMotorTimescale, pTimestep, origVel, origDir, m_angularMotorVelocity); | ||
833 | } | ||
834 | else | ||
835 | { | 1039 | { |
836 | m_angularMotorVelocity = Vector3.Zero; | 1040 | angularMotorContribution.X = 0f; |
1041 | angularMotorContribution.Y = 0f; | ||
1042 | VDetailLog("{0}, MoveAngular,noDeflectionUp,angularMotorContrib={1}", Prim.LocalID, angularMotorContribution); | ||
837 | } | 1043 | } |
838 | 1044 | ||
839 | #region Vertical attactor | 1045 | Vector3 verticalAttractionContribution = ComputeAngularVerticalAttraction(); |
840 | |||
841 | Vector3 vertattr = Vector3.Zero; | ||
842 | Vector3 deflection = Vector3.Zero; | ||
843 | Vector3 banking = Vector3.Zero; | ||
844 | |||
845 | // If vertical attaction timescale is reasonable and we applied an angular force last time... | ||
846 | if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero) | ||
847 | { | ||
848 | float VAservo = pTimestep * 0.2f / m_verticalAttractionTimescale; | ||
849 | if (Prim.IsColliding) | ||
850 | VAservo = pTimestep * 0.05f / (m_verticalAttractionTimescale); | ||
851 | |||
852 | VAservo *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); | ||
853 | |||
854 | // Create a vector of the vehicle "up" in world coordinates | ||
855 | Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation; | ||
856 | // verticalError.X and .Y are the World error amounts. They are 0 when there is no | ||
857 | // error (Vehicle Body is 'vertical'), and .Z will be 1. As the body leans to its | ||
858 | // side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall | ||
859 | // and .Z will go // negative. Similar for tilt and |.Y|. .X and .Y must be | ||
860 | // modulated to prevent a stable inverted body. | ||
861 | |||
862 | // Error is 0 (no error) to +/- 2 (max error) | ||
863 | if (verticalError.Z < 0.0f) | ||
864 | { | ||
865 | verticalError.X = 2.0f - verticalError.X; | ||
866 | verticalError.Y = 2.0f - verticalError.Y; | ||
867 | } | ||
868 | // scale it by VAservo (timestep and timescale) | ||
869 | verticalError = verticalError * VAservo; | ||
870 | |||
871 | // As the body rotates around the X axis, then verticalError.Y increases; Rotated around Y | ||
872 | // then .X increases, so change Body angular velocity X based on Y, and Y based on X. | ||
873 | // Z is not changed. | ||
874 | vertattr.X = verticalError.Y; | ||
875 | vertattr.Y = - verticalError.X; | ||
876 | vertattr.Z = 0f; | ||
877 | 1046 | ||
878 | // scaling appears better usingsquare-law | 1047 | Vector3 deflectionContribution = ComputeAngularDeflection(); |
879 | Vector3 angularVelocity = Prim.ForceRotationalVelocity; | ||
880 | float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); | ||
881 | vertattr.X += bounce * angularVelocity.X; | ||
882 | vertattr.Y += bounce * angularVelocity.Y; | ||
883 | 1048 | ||
884 | VDetailLog("{0},MoveAngular,verticalAttraction,VAservo={1},effic={2},verticalError={3},bounce={4},vertattr={5}", | 1049 | Vector3 bankingContribution = ComputeAngularBanking(); |
885 | Prim.LocalID, VAservo, m_verticalAttractionEfficiency, verticalError, bounce, vertattr); | ||
886 | 1050 | ||
887 | } | 1051 | // ================================================================== |
888 | #endregion // Vertical attactor | 1052 | m_lastVertAttractor = verticalAttractionContribution; |
889 | 1053 | ||
890 | #region Deflection | 1054 | m_lastAngularVelocity = angularMotorContribution |
1055 | + verticalAttractionContribution | ||
1056 | + deflectionContribution | ||
1057 | + bankingContribution; | ||
891 | 1058 | ||
892 | if (m_angularDeflectionEfficiency != 0) | 1059 | // ================================================================== |
1060 | // Apply the correction velocity. | ||
1061 | // TODO: Should this be applied as an angular force (torque)? | ||
1062 | if (!m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) | ||
893 | { | 1063 | { |
894 | // Compute a scaled vector that points in the preferred axis (X direction) | 1064 | VehicleRotationalVelocity = m_lastAngularVelocity; |
895 | Vector3 scaledDefaultDirection = | ||
896 | new Vector3((pTimestep * 10 * (m_angularDeflectionEfficiency / m_angularDeflectionTimescale)), 0, 0); | ||
897 | // Adding the current vehicle orientation and reference frame displaces the orientation to the frame. | ||
898 | // Rotate the scaled default axix relative to the actual vehicle direction giving where it should point. | ||
899 | Vector3 preferredAxisOfMotion = scaledDefaultDirection * Quaternion.Add(Prim.ForceOrientation, m_referenceFrame); | ||
900 | |||
901 | // Scale by efficiency and timescale | ||
902 | deflection = (preferredAxisOfMotion * (m_angularDeflectionEfficiency) / m_angularDeflectionTimescale) * pTimestep; | ||
903 | |||
904 | VDetailLog("{0},MoveAngular,Deflection,perfAxis={1},deflection={2}", | ||
905 | Prim.LocalID, preferredAxisOfMotion, deflection); | ||
906 | // This deflection computation is not correct. | ||
907 | deflection = Vector3.Zero; | ||
908 | } | ||
909 | |||
910 | #endregion | ||
911 | |||
912 | #region Banking | ||
913 | 1065 | ||
914 | if (m_bankingEfficiency != 0) | 1066 | VDetailLog("{0}, MoveAngular,done,nonZero,angMotorContrib={1},vertAttrContrib={2},bankContrib={3},deflectContrib={4},totalContrib={5}", |
1067 | Prim.LocalID, | ||
1068 | angularMotorContribution, verticalAttractionContribution, | ||
1069 | bankingContribution, deflectionContribution, | ||
1070 | m_lastAngularVelocity | ||
1071 | ); | ||
1072 | } | ||
1073 | else | ||
915 | { | 1074 | { |
916 | Vector3 dir = Vector3.One * Prim.ForceOrientation; | 1075 | // The vehicle is not adding anything angular wise. |
917 | float mult = (m_bankingMix*m_bankingMix)*-1*(m_bankingMix < 0 ? -1 : 1); | 1076 | VehicleRotationalVelocity = Vector3.Zero; |
918 | //Changes which way it banks in and out of turns | 1077 | VDetailLog("{0}, MoveAngular,done,zero", Prim.LocalID); |
919 | |||
920 | //Use the square of the efficiency, as it looks much more how SL banking works | ||
921 | float effSquared = (m_bankingEfficiency*m_bankingEfficiency); | ||
922 | if (m_bankingEfficiency < 0) | ||
923 | effSquared *= -1; //Keep the negative! | ||
924 | |||
925 | float mix = Math.Abs(m_bankingMix); | ||
926 | if (m_angularMotorVelocity.X == 0) | ||
927 | { | ||
928 | /*if (!parent.Orientation.ApproxEquals(this.m_referenceFrame, 0.25f)) | ||
929 | { | ||
930 | Vector3 axisAngle; | ||
931 | float angle; | ||
932 | parent.Orientation.GetAxisAngle(out axisAngle, out angle); | ||
933 | Vector3 rotatedVel = parent.Velocity * parent.Orientation; | ||
934 | if ((rotatedVel.X < 0 && axisAngle.Y > 0) || (rotatedVel.X > 0 && axisAngle.Y < 0)) | ||
935 | m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (1f) * 10; | ||
936 | else | ||
937 | m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (-1f) * 10; | ||
938 | }*/ | ||
939 | } | ||
940 | else | ||
941 | banking.Z += (effSquared*(mult*mix))*(m_angularMotorVelocity.X) * 4; | ||
942 | if (!Prim.IsColliding && Math.Abs(m_angularMotorVelocity.X) > mix) | ||
943 | //If they are colliding, we probably shouldn't shove the prim around... probably | ||
944 | { | ||
945 | float angVelZ = m_angularMotorVelocity.X*-1; | ||
946 | /*if(angVelZ > mix) | ||
947 | angVelZ = mix; | ||
948 | else if(angVelZ < -mix) | ||
949 | angVelZ = -mix;*/ | ||
950 | //This controls how fast and how far the banking occurs | ||
951 | Vector3 bankingRot = new Vector3(angVelZ*(effSquared*mult), 0, 0); | ||
952 | if (bankingRot.X > 3) | ||
953 | bankingRot.X = 3; | ||
954 | else if (bankingRot.X < -3) | ||
955 | bankingRot.X = -3; | ||
956 | bankingRot *= Prim.ForceOrientation; | ||
957 | banking += bankingRot; | ||
958 | } | ||
959 | m_angularMotorVelocity.X *= m_bankingEfficiency == 1 ? 0.0f : 1 - m_bankingEfficiency; | ||
960 | VDetailLog("{0},MoveAngular,Banking,bEff={1},angMotVel={2},banking={3}", | ||
961 | Prim.LocalID, m_bankingEfficiency, m_angularMotorVelocity, banking); | ||
962 | } | 1078 | } |
963 | 1079 | ||
964 | #endregion | 1080 | // ================================================================== |
965 | |||
966 | m_lastVertAttractor = vertattr; | ||
967 | |||
968 | // Sum velocities | ||
969 | m_lastAngularVelocity = m_angularMotorVelocity + vertattr + banking + deflection; | ||
970 | |||
971 | #region Linear Motor Offset | ||
972 | |||
973 | //Offset section | 1081 | //Offset section |
974 | if (m_linearMotorOffset != Vector3.Zero) | 1082 | if (m_linearMotorOffset != Vector3.Zero) |
975 | { | 1083 | { |
@@ -985,8 +1093,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
985 | // | 1093 | // |
986 | // The torque created is the linear velocity crossed with the offset | 1094 | // The torque created is the linear velocity crossed with the offset |
987 | 1095 | ||
988 | // NOTE: this computation does should be in the linear section | 1096 | // TODO: this computation should be in the linear section |
989 | // because there we know the impulse being applied. | 1097 | // because that is where we know the impulse being applied. |
990 | Vector3 torqueFromOffset = Vector3.Zero; | 1098 | Vector3 torqueFromOffset = Vector3.Zero; |
991 | // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse); | 1099 | // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse); |
992 | if (float.IsNaN(torqueFromOffset.X)) | 1100 | if (float.IsNaN(torqueFromOffset.X)) |
@@ -995,47 +1103,175 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
995 | torqueFromOffset.Y = 0; | 1103 | torqueFromOffset.Y = 0; |
996 | if (float.IsNaN(torqueFromOffset.Z)) | 1104 | if (float.IsNaN(torqueFromOffset.Z)) |
997 | torqueFromOffset.Z = 0; | 1105 | torqueFromOffset.Z = 0; |
998 | torqueFromOffset *= m_vehicleMass; | 1106 | |
999 | Prim.ApplyTorqueImpulse(torqueFromOffset, true); | 1107 | VehicleAddAngularForce(torqueFromOffset * m_vehicleMass); |
1000 | VDetailLog("{0},BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset); | 1108 | VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset); |
1001 | } | 1109 | } |
1002 | 1110 | ||
1003 | #endregion | 1111 | } |
1112 | // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: | ||
1113 | // Some vehicles, like boats, should always keep their up-side up. This can be done by | ||
1114 | // enabling the "vertical attractor" behavior that springs the vehicle's local z-axis to | ||
1115 | // the world z-axis (a.k.a. "up"). To take advantage of this feature you would set the | ||
1116 | // VEHICLE_VERTICAL_ATTRACTION_TIMESCALE to control the period of the spring frequency, | ||
1117 | // and then set the VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY to control the damping. An | ||
1118 | // efficiency of 0.0 will cause the spring to wobble around its equilibrium, while an | ||
1119 | // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay. | ||
1120 | public Vector3 ComputeAngularVerticalAttraction() | ||
1121 | { | ||
1122 | Vector3 ret = Vector3.Zero; | ||
1004 | 1123 | ||
1005 | if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) | 1124 | // If vertical attaction timescale is reasonable |
1125 | if (m_verticalAttractionTimescale < m_verticalAttractionCutoff) | ||
1006 | { | 1126 | { |
1007 | m_lastAngularVelocity.X = 0; | 1127 | // Take a vector pointing up and convert it from world to vehicle relative coords. |
1008 | m_lastAngularVelocity.Y = 0; | 1128 | Vector3 verticalError = Vector3.UnitZ * VehicleOrientation; |
1009 | VDetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity); | 1129 | |
1130 | // If vertical attraction correction is needed, the vector that was pointing up (UnitZ) | ||
1131 | // is now: | ||
1132 | // leaning to one side: rotated around the X axis with the Y value going | ||
1133 | // from zero (nearly straight up) to one (completely to the side)) or | ||
1134 | // leaning front-to-back: rotated around the Y axis with the value of X being between | ||
1135 | // zero and one. | ||
1136 | // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees. | ||
1137 | |||
1138 | // If verticalError.Z is negative, the vehicle is upside down. Add additional push. | ||
1139 | if (verticalError.Z < 0f) | ||
1140 | { | ||
1141 | verticalError.X = 2f - verticalError.X; | ||
1142 | verticalError.Y = 2f - verticalError.Y; | ||
1143 | } | ||
1144 | |||
1145 | // Y error means needed rotation around X axis and visa versa. | ||
1146 | ret.X = verticalError.Y; | ||
1147 | ret.Y = - verticalError.X; | ||
1148 | ret.Z = 0f; | ||
1149 | |||
1150 | // Scale the correction force by how far we're off from vertical. | ||
1151 | // Z error of one says little error. As Z gets smaller, the vehicle is leaning farther over. | ||
1152 | float clampedSqrZError = ClampInRange(0.01f, verticalError.Z * verticalError.Z, 1f); | ||
1153 | float vertForce = 1f / clampedSqrZError; | ||
1154 | |||
1155 | ret *= vertForce; | ||
1156 | |||
1157 | // Correction happens over a number of seconds. | ||
1158 | Vector3 unscaledContrib = ret; | ||
1159 | ret /= m_verticalAttractionTimescale; | ||
1160 | |||
1161 | VDetailLog("{0}, MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},vertForce={3},eff={4},vertAttr={5}", | ||
1162 | Prim.LocalID, verticalError, unscaledContrib, vertForce, m_verticalAttractionEfficiency, ret); | ||
1010 | } | 1163 | } |
1164 | return ret; | ||
1165 | } | ||
1166 | |||
1167 | // Return the angular correction to correct the direction the vehicle is pointing to be | ||
1168 | // the direction is should want to be pointing. | ||
1169 | // The vehicle is moving in some direction and correct its orientation to it is pointing | ||
1170 | // in that direction. | ||
1171 | // TODO: implement reference frame. | ||
1172 | public Vector3 ComputeAngularDeflection() | ||
1173 | { | ||
1174 | Vector3 ret = Vector3.Zero; | ||
1175 | return ret; // DEBUG DEBUG DEBUG debug one force at a time | ||
1011 | 1176 | ||
1012 | if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) | 1177 | if (m_angularDeflectionEfficiency != 0) |
1013 | { | 1178 | { |
1014 | m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. | 1179 | // The direction the vehicle is moving |
1015 | Prim.ZeroAngularMotion(true); | 1180 | Vector3 movingDirection = VehicleVelocity; |
1016 | VDetailLog("{0},MoveAngular,zeroAngularMotion,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity); | 1181 | movingDirection.Normalize(); |
1182 | |||
1183 | // The direction the vehicle is pointing | ||
1184 | Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation; | ||
1185 | pointingDirection.Normalize(); | ||
1186 | |||
1187 | // The difference between what is and what should be | ||
1188 | Vector3 deflectionError = movingDirection - pointingDirection; | ||
1189 | |||
1190 | // Scale the correction by recovery timescale and efficiency | ||
1191 | ret = (-deflectionError * VehicleForwardSpeed) * m_angularDeflectionEfficiency; | ||
1192 | ret /= m_angularDeflectionTimescale; | ||
1193 | |||
1194 | VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}", | ||
1195 | Prim.LocalID, movingDirection, pointingDirection, deflectionError, ret); | ||
1017 | } | 1196 | } |
1018 | else | 1197 | return ret; |
1198 | } | ||
1199 | |||
1200 | // Return an angular change to rotate the vehicle around the Z axis when the vehicle | ||
1201 | // is tipped around the X axis. | ||
1202 | // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: | ||
1203 | // The vertical attractor feature must be enabled in order for the banking behavior to | ||
1204 | // function. The way banking works is this: a rotation around the vehicle's roll-axis will | ||
1205 | // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude | ||
1206 | // of the yaw effect will be proportional to the | ||
1207 | // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's | ||
1208 | // velocity along its preferred axis of motion. | ||
1209 | // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any | ||
1210 | // positive rotation (by the right-hand rule) about the roll-axis will effect a | ||
1211 | // (negative) torque around the yaw-axis, making it turn to the right--that is the | ||
1212 | // vehicle will lean into the turn, which is how real airplanes and motorcycle's work. | ||
1213 | // Negating the banking coefficient will make it so that the vehicle leans to the | ||
1214 | // outside of the turn (not very "physical" but might allow interesting vehicles so why not?). | ||
1215 | // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making | ||
1216 | // banking vehicles do what you want rather than what the laws of physics allow. | ||
1217 | // For example, consider a real motorcycle...it must be moving forward in order for | ||
1218 | // it to turn while banking, however video-game motorcycles are often configured | ||
1219 | // to turn in place when at a dead stop--because they are often easier to control | ||
1220 | // that way using the limited interface of the keyboard or game controller. The | ||
1221 | // VEHICLE_BANKING_MIX enables combinations of both realistic and non-realistic | ||
1222 | // banking by functioning as a slider between a banking that is correspondingly | ||
1223 | // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the | ||
1224 | // banking effect depends only on the vehicle's rotation about its roll-axis compared | ||
1225 | // to "dynamic" where the banking is also proportional to its velocity along its | ||
1226 | // roll-axis. Finding the best value of the "mixture" will probably require trial and error. | ||
1227 | // The time it takes for the banking behavior to defeat a preexisting angular velocity about the | ||
1228 | // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to | ||
1229 | // bank quickly then give it a banking timescale of about a second or less, otherwise you can | ||
1230 | // make a sluggish vehicle by giving it a timescale of several seconds. | ||
1231 | public Vector3 ComputeAngularBanking() | ||
1232 | { | ||
1233 | Vector3 ret = Vector3.Zero; | ||
1234 | |||
1235 | if (m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff) | ||
1019 | { | 1236 | { |
1020 | // Apply to the body. | 1237 | // This works by rotating a unit vector to the orientation of the vehicle. The |
1021 | // The above calculates the absolute angular velocity needed. Angular velocity is massless. | 1238 | // roll (tilt) will be Y component of a tilting Z vector (zero for no tilt |
1022 | // Since we are stuffing the angular velocity directly into the object, the computed | 1239 | // up to one for full over). |
1023 | // velocity needs to be scaled by the timestep. | 1240 | Vector3 rollComponents = Vector3.UnitZ * VehicleOrientation; |
1024 | Vector3 applyAngularForce = ((m_lastAngularVelocity * pTimestep) - Prim.ForceRotationalVelocity); | 1241 | |
1025 | Prim.ForceRotationalVelocity = applyAngularForce; | 1242 | // Figure out the yaw value for this much roll. |
1026 | 1243 | float turnComponent = rollComponents.Y * rollComponents.Y * m_bankingEfficiency; | |
1027 | // Decay the angular movement for next time | 1244 | // Keep the sign |
1028 | Vector3 decayamount = (Vector3.One / m_angularFrictionTimescale) * pTimestep; | 1245 | if (rollComponents.Y < 0f) |
1029 | m_lastAngularVelocity *= Vector3.One - decayamount; | 1246 | turnComponent = -turnComponent; |
1030 | 1247 | ||
1031 | VDetailLog("{0},MoveAngular,done,newRotVel={1},decay={2},lastAngular={3}", | 1248 | // TODO: there must be a better computation of the banking force. |
1032 | Prim.LocalID, applyAngularForce, decayamount, m_lastAngularVelocity); | 1249 | float bankingTurnForce = turnComponent; |
1250 | |||
1251 | // actual error = static turn error + dynamic turn error | ||
1252 | float mixedBankingError = bankingTurnForce * (1f - m_bankingMix) + bankingTurnForce * m_bankingMix * VehicleForwardSpeed; | ||
1253 | // TODO: the banking effect should not go to infinity but what to limit it to? | ||
1254 | mixedBankingError = ClampInRange(-20f, mixedBankingError, 20f); | ||
1255 | |||
1256 | // Build the force vector to change rotation from what it is to what it should be | ||
1257 | ret.Z = -mixedBankingError; | ||
1258 | |||
1259 | // Don't do it all at once. | ||
1260 | ret /= m_bankingTimescale; | ||
1261 | |||
1262 | VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},turnComp={3},bankErr={4},mixedBankErr={5},ret={6}", | ||
1263 | Prim.LocalID, rollComponents, VehicleForwardSpeed, turnComponent, bankingTurnForce, mixedBankingError, ret); | ||
1033 | } | 1264 | } |
1034 | } //end MoveAngular | 1265 | return ret; |
1266 | } | ||
1035 | 1267 | ||
1268 | // This is from previous instantiations of XXXDynamics.cs. | ||
1269 | // Applies roll reference frame. | ||
1270 | // TODO: is this the right way to separate the code to do this operation? | ||
1271 | // Should this be in MoveAngular()? | ||
1036 | internal void LimitRotation(float timestep) | 1272 | internal void LimitRotation(float timestep) |
1037 | { | 1273 | { |
1038 | Quaternion rotq = Prim.ForceOrientation; | 1274 | Quaternion rotq = VehicleOrientation; |
1039 | Quaternion m_rot = rotq; | 1275 | Quaternion m_rot = rotq; |
1040 | if (m_RollreferenceFrame != Quaternion.Identity) | 1276 | if (m_RollreferenceFrame != Quaternion.Identity) |
1041 | { | 1277 | { |
@@ -1063,12 +1299,17 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1063 | } | 1299 | } |
1064 | if (rotq != m_rot) | 1300 | if (rotq != m_rot) |
1065 | { | 1301 | { |
1066 | Prim.ForceOrientation = m_rot; | 1302 | VehicleOrientation = m_rot; |
1067 | VDetailLog("{0},LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot); | 1303 | VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot); |
1068 | } | 1304 | } |
1069 | 1305 | ||
1070 | } | 1306 | } |
1071 | 1307 | ||
1308 | private float ClampInRange(float low, float val, float high) | ||
1309 | { | ||
1310 | return Math.Max(low, Math.Min(val, high)); | ||
1311 | } | ||
1312 | |||
1072 | // Invoke the detailed logger and output something if it's enabled. | 1313 | // Invoke the detailed logger and output something if it's enabled. |
1073 | private void VDetailLog(string msg, params Object[] args) | 1314 | private void VDetailLog(string msg, params Object[] args) |
1074 | { | 1315 | { |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs index 0df4310..2017fa5 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | |||
@@ -32,6 +32,15 @@ using OMV = OpenMetaverse; | |||
32 | 32 | ||
33 | namespace OpenSim.Region.Physics.BulletSPlugin | 33 | namespace OpenSim.Region.Physics.BulletSPlugin |
34 | { | 34 | { |
35 | |||
36 | // A BSPrim can get individual information about its linkedness attached | ||
37 | // to it through an instance of a subclass of LinksetInfo. | ||
38 | // Each type of linkset will define the information needed for its type. | ||
39 | public abstract class BSLinksetInfo | ||
40 | { | ||
41 | public virtual void Clear() { } | ||
42 | } | ||
43 | |||
35 | public abstract class BSLinkset | 44 | public abstract class BSLinkset |
36 | { | 45 | { |
37 | // private static string LogHeader = "[BULLETSIM LINKSET]"; | 46 | // private static string LogHeader = "[BULLETSIM LINKSET]"; |
@@ -87,13 +96,6 @@ public abstract class BSLinkset | |||
87 | return BSPhysicsShapeType.SHAPE_UNKNOWN; | 96 | return BSPhysicsShapeType.SHAPE_UNKNOWN; |
88 | } | 97 | } |
89 | 98 | ||
90 | // Linksets move around the children so the linkset might need to compute the child position | ||
91 | public virtual OMV.Vector3 Position(BSPhysObject member) | ||
92 | { return member.RawPosition; } | ||
93 | public virtual OMV.Quaternion Orientation(BSPhysObject member) | ||
94 | { return member.RawOrientation; } | ||
95 | // TODO: does this need to be done for Velocity and RotationalVelocityy? | ||
96 | |||
97 | // We keep the prim's mass in the linkset structure since it could be dependent on other prims | 99 | // We keep the prim's mass in the linkset structure since it could be dependent on other prims |
98 | protected float m_mass; | 100 | protected float m_mass; |
99 | public float LinksetMass | 101 | public float LinksetMass |
@@ -116,7 +118,7 @@ public abstract class BSLinkset | |||
116 | get { return ComputeLinksetGeometricCenter(); } | 118 | get { return ComputeLinksetGeometricCenter(); } |
117 | } | 119 | } |
118 | 120 | ||
119 | protected void Initialize(BSScene scene, BSPhysObject parent) | 121 | protected BSLinkset(BSScene scene, BSPhysObject parent) |
120 | { | 122 | { |
121 | // A simple linkset of one (no children) | 123 | // A simple linkset of one (no children) |
122 | LinksetID = m_nextLinksetID++; | 124 | LinksetID = m_nextLinksetID++; |
@@ -127,6 +129,7 @@ public abstract class BSLinkset | |||
127 | LinksetRoot = parent; | 129 | LinksetRoot = parent; |
128 | m_children = new HashSet<BSPhysObject>(); | 130 | m_children = new HashSet<BSPhysObject>(); |
129 | m_mass = parent.RawMass; | 131 | m_mass = parent.RawMass; |
132 | Rebuilding = false; | ||
130 | } | 133 | } |
131 | 134 | ||
132 | // Link to a linkset where the child knows the parent. | 135 | // Link to a linkset where the child knows the parent. |
@@ -219,7 +222,7 @@ public abstract class BSLinkset | |||
219 | // I am the root of a linkset and a new child is being added | 222 | // I am the root of a linkset and a new child is being added |
220 | // Called while LinkActivity is locked. | 223 | // Called while LinkActivity is locked. |
221 | protected abstract void AddChildToLinkset(BSPhysObject child); | 224 | protected abstract void AddChildToLinkset(BSPhysObject child); |
222 | 225 | ||
223 | // I am the root of a linkset and one of my children is being removed. | 226 | // I am the root of a linkset and one of my children is being removed. |
224 | // Safe to call even if the child is not really in my linkset. | 227 | // Safe to call even if the child is not really in my linkset. |
225 | protected abstract void RemoveChildFromLinkset(BSPhysObject child); | 228 | protected abstract void RemoveChildFromLinkset(BSPhysObject child); |
@@ -229,6 +232,10 @@ public abstract class BSLinkset | |||
229 | // May be called at runtime or taint-time. | 232 | // May be called at runtime or taint-time. |
230 | public abstract void Refresh(BSPhysObject requestor); | 233 | public abstract void Refresh(BSPhysObject requestor); |
231 | 234 | ||
235 | // Flag denoting the linkset is in the process of being rebuilt. | ||
236 | // Used to know not the schedule a rebuild in the middle of a rebuild. | ||
237 | protected bool Rebuilding { get; set; } | ||
238 | |||
232 | // The object is going dynamic (physical). Do any setup necessary | 239 | // The object is going dynamic (physical). Do any setup necessary |
233 | // for a dynamic linkset. | 240 | // for a dynamic linkset. |
234 | // Only the state of the passed object can be modified. The rest of the linkset | 241 | // Only the state of the passed object can be modified. The rest of the linkset |
@@ -245,8 +252,9 @@ public abstract class BSLinkset | |||
245 | 252 | ||
246 | // Called when a parameter update comes from the physics engine for any object | 253 | // Called when a parameter update comes from the physics engine for any object |
247 | // of the linkset is received. | 254 | // of the linkset is received. |
255 | // Passed flag is update came from physics engine (true) or the user (false). | ||
248 | // Called at taint-time!! | 256 | // Called at taint-time!! |
249 | public abstract void UpdateProperties(BSPhysObject physObject); | 257 | public abstract void UpdateProperties(BSPhysObject physObject, bool physicalUpdate); |
250 | 258 | ||
251 | // Routine used when rebuilding the body of the root of the linkset | 259 | // Routine used when rebuilding the body of the root of the linkset |
252 | // Destroy all the constraints have have been made to root. | 260 | // Destroy all the constraints have have been made to root. |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index b9c2cf9..2a7b72c 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs | |||
@@ -28,22 +28,54 @@ using System; | |||
28 | using System.Collections.Generic; | 28 | using System.Collections.Generic; |
29 | using System.Text; | 29 | using System.Text; |
30 | 30 | ||
31 | using OpenSim.Framework; | ||
32 | |||
31 | using OMV = OpenMetaverse; | 33 | using OMV = OpenMetaverse; |
32 | 34 | ||
33 | namespace OpenSim.Region.Physics.BulletSPlugin | 35 | namespace OpenSim.Region.Physics.BulletSPlugin |
34 | { | 36 | { |
37 | |||
38 | // When a child is linked, the relationship position of the child to the parent | ||
39 | // is remembered so the child's world position can be recomputed when it is | ||
40 | // removed from the linkset. | ||
41 | sealed class BSLinksetCompoundInfo : BSLinksetInfo | ||
42 | { | ||
43 | public OMV.Vector3 OffsetPos; | ||
44 | public OMV.Quaternion OffsetRot; | ||
45 | public BSLinksetCompoundInfo(OMV.Vector3 p, OMV.Quaternion r) | ||
46 | { | ||
47 | OffsetPos = p; | ||
48 | OffsetRot = r; | ||
49 | } | ||
50 | public override void Clear() | ||
51 | { | ||
52 | OffsetPos = OMV.Vector3.Zero; | ||
53 | OffsetRot = OMV.Quaternion.Identity; | ||
54 | } | ||
55 | public override string ToString() | ||
56 | { | ||
57 | StringBuilder buff = new StringBuilder(); | ||
58 | buff.Append("<p="); | ||
59 | buff.Append(OffsetPos.ToString()); | ||
60 | buff.Append(",r="); | ||
61 | buff.Append(OffsetRot.ToString()); | ||
62 | buff.Append(">"); | ||
63 | return buff.ToString(); | ||
64 | } | ||
65 | }; | ||
66 | |||
35 | public sealed class BSLinksetCompound : BSLinkset | 67 | public sealed class BSLinksetCompound : BSLinkset |
36 | { | 68 | { |
37 | private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; | 69 | private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; |
38 | 70 | ||
39 | public BSLinksetCompound(BSScene scene, BSPhysObject parent) | 71 | public BSLinksetCompound(BSScene scene, BSPhysObject parent) : base(scene, parent) |
40 | { | 72 | { |
41 | base.Initialize(scene, parent); | ||
42 | } | 73 | } |
43 | 74 | ||
44 | // For compound implimented linksets, if there are children, use compound shape for the root. | 75 | // For compound implimented linksets, if there are children, use compound shape for the root. |
45 | public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) | 76 | public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) |
46 | { | 77 | { |
78 | // Returning 'unknown' means we don't have a preference. | ||
47 | BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | 79 | BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; |
48 | if (IsRoot(requestor) && HasAnyChildren) | 80 | if (IsRoot(requestor) && HasAnyChildren) |
49 | { | 81 | { |
@@ -55,23 +87,27 @@ public sealed class BSLinksetCompound : BSLinkset | |||
55 | 87 | ||
56 | // When physical properties are changed the linkset needs to recalculate | 88 | // When physical properties are changed the linkset needs to recalculate |
57 | // its internal properties. | 89 | // its internal properties. |
58 | // This is queued in the 'post taint' queue so the | ||
59 | // refresh will happen once after all the other taints are applied. | ||
60 | public override void Refresh(BSPhysObject requestor) | 90 | public override void Refresh(BSPhysObject requestor) |
61 | { | 91 | { |
62 | // External request for Refresh (from BSPrim) is not necessary | 92 | // Something changed so do the rebuilding thing |
63 | // InternalRefresh(requestor); | 93 | // ScheduleRebuild(); |
64 | } | 94 | } |
65 | 95 | ||
66 | private void InternalRefresh(BSPhysObject requestor) | 96 | // Schedule a refresh to happen after all the other taint processing. |
97 | private void ScheduleRebuild(BSPhysObject requestor) | ||
67 | { | 98 | { |
68 | DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,requestor={1}", LinksetRoot.LocalID, requestor.LocalID); | 99 | DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,rebuilding={1}", |
69 | // Queue to happen after all the other taint processing | 100 | requestor.LocalID, Rebuilding); |
70 | PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", requestor.LocalID, delegate() | 101 | // When rebuilding, it is possible to set properties that would normally require a rebuild. |
102 | // If already rebuilding, don't request another rebuild. | ||
103 | if (!Rebuilding) | ||
71 | { | 104 | { |
72 | if (IsRoot(requestor) && HasAnyChildren) | 105 | PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", LinksetRoot.LocalID, delegate() |
73 | RecomputeLinksetCompound(); | 106 | { |
74 | }); | 107 | if (HasAnyChildren) |
108 | RecomputeLinksetCompound(); | ||
109 | }); | ||
110 | } | ||
75 | } | 111 | } |
76 | 112 | ||
77 | // The object is going dynamic (physical). Do any setup necessary | 113 | // The object is going dynamic (physical). Do any setup necessary |
@@ -84,12 +120,23 @@ public sealed class BSLinksetCompound : BSLinkset | |||
84 | { | 120 | { |
85 | bool ret = false; | 121 | bool ret = false; |
86 | DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); | 122 | DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); |
87 | if (!IsRoot(child)) | 123 | if (IsRoot(child)) |
124 | { | ||
125 | // The root is going dynamic. Make sure mass is properly set. | ||
126 | m_mass = ComputeLinksetMass(); | ||
127 | ScheduleRebuild(LinksetRoot); | ||
128 | } | ||
129 | else | ||
88 | { | 130 | { |
89 | // Physical children are removed from the world as the shape ofthe root compound | 131 | // The origional prims are removed from the world as the shape of the root compound |
90 | // shape takes over. | 132 | // shape takes over. |
91 | BulletSimAPI.AddToCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | 133 | BulletSimAPI.AddToCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); |
92 | BulletSimAPI.ForceActivationState2(child.PhysBody.ptr, ActivationState.DISABLE_SIMULATION); | 134 | BulletSimAPI.ForceActivationState2(child.PhysBody.ptr, ActivationState.DISABLE_SIMULATION); |
135 | // We don't want collisions from the old linkset children. | ||
136 | BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
137 | |||
138 | child.PhysBody.collisionType = CollisionType.LinksetChild; | ||
139 | |||
93 | ret = true; | 140 | ret = true; |
94 | } | 141 | } |
95 | return ret; | 142 | return ret; |
@@ -104,33 +151,39 @@ public sealed class BSLinksetCompound : BSLinkset | |||
104 | { | 151 | { |
105 | bool ret = false; | 152 | bool ret = false; |
106 | DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); | 153 | DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); |
107 | if (!IsRoot(child)) | 154 | if (IsRoot(child)) |
155 | { | ||
156 | ScheduleRebuild(LinksetRoot); | ||
157 | } | ||
158 | else | ||
108 | { | 159 | { |
109 | // The non-physical children can come back to life. | 160 | // The non-physical children can come back to life. |
110 | BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | 161 | BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); |
111 | // Don't force activation so setting of DISABLE_SIMULATION can stay. | 162 | |
163 | child.PhysBody.collisionType = CollisionType.LinksetChild; | ||
164 | |||
165 | // Don't force activation so setting of DISABLE_SIMULATION can stay if used. | ||
112 | BulletSimAPI.Activate2(child.PhysBody.ptr, false); | 166 | BulletSimAPI.Activate2(child.PhysBody.ptr, false); |
113 | ret = true; | 167 | ret = true; |
114 | } | 168 | } |
115 | return ret; | 169 | return ret; |
116 | } | 170 | } |
117 | 171 | ||
118 | // Called at taint-time!! | 172 | public override void UpdateProperties(BSPhysObject updated, bool physicalUpdate) |
119 | public override void UpdateProperties(BSPhysObject updated) | ||
120 | { | 173 | { |
121 | // Nothing to do for constraints on property updates | 174 | // The user moving a child around requires the rebuilding of the linkset compound shape |
122 | } | 175 | // One problem is this happens when a border is crossed -- the simulator implementation |
123 | 176 | // is to store the position into the group which causes the move of the object | |
124 | // The children move around in relationship to the root. | 177 | // but it also means all the child positions get updated. |
125 | // Just grab the current values of wherever it is right now. | 178 | // What would cause an unnecessary rebuild so we make sure the linkset is in a |
126 | public override OMV.Vector3 Position(BSPhysObject member) | 179 | // region before bothering to do a rebuild. |
127 | { | 180 | if (!IsRoot(updated) |
128 | return BulletSimAPI.GetPosition2(member.PhysBody.ptr); | 181 | && !physicalUpdate |
129 | } | 182 | && PhysicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition)) |
130 | 183 | { | |
131 | public override OMV.Quaternion Orientation(BSPhysObject member) | 184 | updated.LinksetInfo = null; |
132 | { | 185 | ScheduleRebuild(updated); |
133 | return BulletSimAPI.GetOrientation2(member.PhysBody.ptr); | 186 | } |
134 | } | 187 | } |
135 | 188 | ||
136 | // Routine called when rebuilding the body of some member of the linkset. | 189 | // Routine called when rebuilding the body of some member of the linkset. |
@@ -146,20 +199,58 @@ public sealed class BSLinksetCompound : BSLinkset | |||
146 | 199 | ||
147 | if (!IsRoot(child)) | 200 | if (!IsRoot(child)) |
148 | { | 201 | { |
149 | // Cause the current shape to be freed and the new one to be built. | 202 | // Because it is a convenient time, recompute child world position and rotation based on |
150 | InternalRefresh(LinksetRoot); | 203 | // its position in the linkset. |
151 | ret = true; | 204 | RecomputeChildWorldPosition(child, true); |
152 | } | 205 | } |
153 | 206 | ||
207 | // Cannot schedule a refresh/rebuild here because this routine is called when | ||
208 | // the linkset is being rebuilt. | ||
209 | // InternalRefresh(LinksetRoot); | ||
210 | |||
154 | return ret; | 211 | return ret; |
155 | } | 212 | } |
156 | 213 | ||
157 | // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', | 214 | // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', |
158 | // this routine will restore the removed constraints. | 215 | // this routine will restore the removed constraints. |
159 | // Called at taint-time!! | 216 | // Called at taint-time!! |
160 | public override void RestoreBodyDependencies(BSPrim child) | 217 | public override void RestoreBodyDependencies(BSPrim child) |
161 | { | 218 | { |
162 | // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints. | 219 | } |
220 | |||
221 | // When the linkset is built, the child shape is added to the compound shape relative to the | ||
222 | // root shape. The linkset then moves around but this does not move the actual child | ||
223 | // prim. The child prim's location must be recomputed based on the location of the root shape. | ||
224 | private void RecomputeChildWorldPosition(BSPhysObject child, bool inTaintTime) | ||
225 | { | ||
226 | BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo; | ||
227 | if (lci != null) | ||
228 | { | ||
229 | if (inTaintTime) | ||
230 | { | ||
231 | OMV.Vector3 oldPos = child.RawPosition; | ||
232 | child.ForcePosition = LinksetRoot.RawPosition + lci.OffsetPos; | ||
233 | child.ForceOrientation = LinksetRoot.RawOrientation * lci.OffsetRot; | ||
234 | DetailLog("{0},BSLinksetCompound.RecomputeChildWorldPosition,oldPos={1},lci={2},newPos={3}", | ||
235 | child.LocalID, oldPos, lci, child.RawPosition); | ||
236 | } | ||
237 | else | ||
238 | { | ||
239 | // TaintedObject is not used here so the raw position is set now and not at taint-time. | ||
240 | child.Position = LinksetRoot.RawPosition + lci.OffsetPos; | ||
241 | child.Orientation = LinksetRoot.RawOrientation * lci.OffsetRot; | ||
242 | } | ||
243 | } | ||
244 | else | ||
245 | { | ||
246 | // This happens when children have been added to the linkset but the linkset | ||
247 | // has not been constructed yet. So like, at taint time, adding children to a linkset | ||
248 | // and then changing properties of the children (makePhysical, for instance) | ||
249 | // but the post-print action of actually rebuilding the linkset has not yet happened. | ||
250 | // PhysicsScene.Logger.WarnFormat("{0} Restoring linkset child position failed because of no relative position computed. ID={1}", | ||
251 | // LogHeader, child.LocalID); | ||
252 | DetailLog("{0},BSLinksetCompound.recomputeChildWorldPosition,noRelativePositonInfo", child.LocalID); | ||
253 | } | ||
163 | } | 254 | } |
164 | 255 | ||
165 | // ================================================================ | 256 | // ================================================================ |
@@ -174,14 +265,14 @@ public sealed class BSLinksetCompound : BSLinkset | |||
174 | 265 | ||
175 | DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); | 266 | DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); |
176 | 267 | ||
177 | // Cause constraints and assorted properties to be recomputed before the next simulation step. | 268 | // Rebuild the compound shape with the new child shape included |
178 | InternalRefresh(LinksetRoot); | 269 | ScheduleRebuild(child); |
179 | } | 270 | } |
180 | return; | 271 | return; |
181 | } | 272 | } |
182 | 273 | ||
183 | // Remove the specified child from the linkset. | 274 | // Remove the specified child from the linkset. |
184 | // Safe to call even if the child is not really in my linkset. | 275 | // Safe to call even if the child is not really in the linkset. |
185 | protected override void RemoveChildFromLinkset(BSPhysObject child) | 276 | protected override void RemoveChildFromLinkset(BSPhysObject child) |
186 | { | 277 | { |
187 | if (m_children.Remove(child)) | 278 | if (m_children.Remove(child)) |
@@ -192,6 +283,7 @@ public sealed class BSLinksetCompound : BSLinkset | |||
192 | child.LocalID, child.PhysBody.ptr.ToString("X")); | 283 | child.LocalID, child.PhysBody.ptr.ToString("X")); |
193 | 284 | ||
194 | // Cause the child's body to be rebuilt and thus restored to normal operation | 285 | // Cause the child's body to be rebuilt and thus restored to normal operation |
286 | RecomputeChildWorldPosition(child, false); | ||
195 | child.ForceBodyShapeRebuild(false); | 287 | child.ForceBodyShapeRebuild(false); |
196 | 288 | ||
197 | if (!HasAnyChildren) | 289 | if (!HasAnyChildren) |
@@ -201,8 +293,8 @@ public sealed class BSLinksetCompound : BSLinkset | |||
201 | } | 293 | } |
202 | else | 294 | else |
203 | { | 295 | { |
204 | // Schedule a rebuild of the linkset before the next simulation tick. | 296 | // Rebuild the compound shape with the child removed |
205 | InternalRefresh(LinksetRoot); | 297 | ScheduleRebuild(child); |
206 | } | 298 | } |
207 | } | 299 | } |
208 | return; | 300 | return; |
@@ -215,54 +307,83 @@ public sealed class BSLinksetCompound : BSLinkset | |||
215 | // Called at taint time!! | 307 | // Called at taint time!! |
216 | private void RecomputeLinksetCompound() | 308 | private void RecomputeLinksetCompound() |
217 | { | 309 | { |
218 | // Cause the root shape to be rebuilt as a compound object with just the root in it | 310 | try |
219 | LinksetRoot.ForceBodyShapeRebuild(true); | 311 | { |
312 | // Suppress rebuilding while rebuilding | ||
313 | Rebuilding = true; | ||
220 | 314 | ||
221 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}", | 315 | // Cause the root shape to be rebuilt as a compound object with just the root in it |
222 | LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren); | 316 | LinksetRoot.ForceBodyShapeRebuild(true); |
223 | 317 | ||
224 | // Add a shape for each of the other children in the linkset | 318 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}", |
225 | ForEachMember(delegate(BSPhysObject cPrim) | 319 | LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren); |
226 | { | 320 | |
227 | if (!IsRoot(cPrim)) | 321 | // Add a shape for each of the other children in the linkset |
322 | ForEachMember(delegate(BSPhysObject cPrim) | ||
228 | { | 323 | { |
229 | // Each child position and rotation is given relative to the root. | 324 | if (!IsRoot(cPrim)) |
230 | OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation); | 325 | { |
231 | OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation; | 326 | // Compute the displacement of the child from the root of the linkset. |
232 | OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation; | 327 | // This info is saved in the child prim so the relationship does not |
328 | // change over time and the new child position can be computed | ||
329 | // when the linkset is being disassembled (the linkset may have moved). | ||
330 | BSLinksetCompoundInfo lci = cPrim.LinksetInfo as BSLinksetCompoundInfo; | ||
331 | if (lci == null) | ||
332 | { | ||
333 | // Each child position and rotation is given relative to the root. | ||
334 | OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation); | ||
335 | OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation; | ||
336 | OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation; | ||
337 | |||
338 | // Save relative position for recomputing child's world position after moving linkset. | ||
339 | lci = new BSLinksetCompoundInfo(displacementPos, displacementRot); | ||
340 | cPrim.LinksetInfo = lci; | ||
341 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,creatingRelPos,lci={1}", cPrim.LocalID, lci); | ||
342 | } | ||
233 | 343 | ||
234 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}", | 344 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}", |
235 | LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, displacementPos, displacementRot); | 345 | LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, lci.OffsetPos, lci.OffsetRot); |
236 | 346 | ||
237 | if (cPrim.PhysShape.isNativeShape) | 347 | if (cPrim.PhysShape.isNativeShape) |
238 | { | 348 | { |
239 | // Native shapes are not shared so we need to create a new one. | 349 | // A native shape is turning into a hull collision shape because native |
240 | // A mesh or hull is created because scale is not available on a native shape. | 350 | // shapes are not shared so we have to hullify it so it will be tracked |
241 | // (TODO: Bullet does have a btScaledCollisionShape. Can that be used?) | 351 | // and freed at the correct time. This also solves the scaling problem |
242 | BulletShape saveShape = cPrim.PhysShape; | 352 | // (native shapes scaled but hull/meshes are assumed to not be). |
243 | cPrim.PhysShape.ptr = IntPtr.Zero; // Don't let the create free the child's shape | 353 | // TODO: decide of the native shape can just be used in the compound shape. |
244 | PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null); | 354 | // Use call to CreateGeomNonSpecial(). |
245 | BulletShape newShape = cPrim.PhysShape; | 355 | BulletShape saveShape = cPrim.PhysShape; |
246 | cPrim.PhysShape = saveShape; | 356 | cPrim.PhysShape.Clear(); // Don't let the create free the child's shape |
247 | BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot); | 357 | // PhysicsScene.Shapes.CreateGeomNonSpecial(true, cPrim, null); |
248 | } | 358 | PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null); |
249 | else | 359 | BulletShape newShape = cPrim.PhysShape; |
250 | { | 360 | cPrim.PhysShape = saveShape; |
251 | // For the shared shapes (meshes and hulls), just use the shape in the child. | 361 | BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, lci.OffsetPos, lci.OffsetRot); |
252 | if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape)) | 362 | } |
363 | else | ||
253 | { | 364 | { |
254 | PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}", | 365 | // For the shared shapes (meshes and hulls), just use the shape in the child. |
255 | LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape); | 366 | // The reference count added here will be decremented when the compound shape |
367 | // is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced). | ||
368 | if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape)) | ||
369 | { | ||
370 | PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}", | ||
371 | LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape); | ||
372 | } | ||
373 | BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, lci.OffsetPos, lci.OffsetRot); | ||
256 | } | 374 | } |
257 | BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, displacementPos, displacementRot); | ||
258 | } | 375 | } |
259 | } | 376 | return false; // 'false' says to move onto the next child in the list |
260 | return false; // 'false' says to move onto the next child in the list | 377 | }); |
261 | }); | ||
262 | 378 | ||
263 | // With all of the linkset packed into the root prim, it has the mass of everyone. | 379 | // With all of the linkset packed into the root prim, it has the mass of everyone. |
264 | float linksetMass = LinksetMass; | 380 | float linksetMass = LinksetMass; |
265 | LinksetRoot.UpdatePhysicalMassProperties(linksetMass); | 381 | LinksetRoot.UpdatePhysicalMassProperties(linksetMass); |
382 | } | ||
383 | finally | ||
384 | { | ||
385 | Rebuilding = false; | ||
386 | } | ||
266 | 387 | ||
267 | BulletSimAPI.RecalculateCompoundShapeLocalAabb2(LinksetRoot.PhysShape.ptr); | 388 | BulletSimAPI.RecalculateCompoundShapeLocalAabb2(LinksetRoot.PhysShape.ptr); |
268 | 389 | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs index c855fda..8c36c31 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs | |||
@@ -36,9 +36,8 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
36 | { | 36 | { |
37 | // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]"; | 37 | // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]"; |
38 | 38 | ||
39 | public BSLinksetConstraints(BSScene scene, BSPhysObject parent) | 39 | public BSLinksetConstraints(BSScene scene, BSPhysObject parent) : base(scene, parent) |
40 | { | 40 | { |
41 | base.Initialize(scene, parent); | ||
42 | } | 41 | } |
43 | 42 | ||
44 | // When physical properties are changed the linkset needs to recalculate | 43 | // When physical properties are changed the linkset needs to recalculate |
@@ -79,23 +78,11 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
79 | } | 78 | } |
80 | 79 | ||
81 | // Called at taint-time!! | 80 | // Called at taint-time!! |
82 | public override void UpdateProperties(BSPhysObject updated) | 81 | public override void UpdateProperties(BSPhysObject updated, bool inTaintTime) |
83 | { | 82 | { |
84 | // Nothing to do for constraints on property updates | 83 | // Nothing to do for constraints on property updates |
85 | } | 84 | } |
86 | 85 | ||
87 | // The children of the linkset are moved around by the constraints. | ||
88 | // Just grab the current values of wherever it is right now. | ||
89 | public override OMV.Vector3 Position(BSPhysObject member) | ||
90 | { | ||
91 | return BulletSimAPI.GetPosition2(member.PhysBody.ptr); | ||
92 | } | ||
93 | |||
94 | public override OMV.Quaternion Orientation(BSPhysObject member) | ||
95 | { | ||
96 | return BulletSimAPI.GetOrientation2(member.PhysBody.ptr); | ||
97 | } | ||
98 | |||
99 | // Routine called when rebuilding the body of some member of the linkset. | 86 | // Routine called when rebuilding the body of some member of the linkset. |
100 | // Destroy all the constraints have have been made to root and set | 87 | // Destroy all the constraints have have been made to root and set |
101 | // up to rebuild the constraints before the next simulation step. | 88 | // up to rebuild the constraints before the next simulation step. |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs new file mode 100755 index 0000000..c113a43 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs | |||
@@ -0,0 +1,200 @@ | |||
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.Text; | ||
30 | using System.Reflection; | ||
31 | using Nini.Config; | ||
32 | |||
33 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
34 | { | ||
35 | |||
36 | public struct MaterialAttributes | ||
37 | { | ||
38 | // Material type values that correspond with definitions for LSL | ||
39 | public enum Material : int | ||
40 | { | ||
41 | Stone = 0, | ||
42 | Metal, | ||
43 | Glass, | ||
44 | Wood, | ||
45 | Flesh, | ||
46 | Plastic, | ||
47 | Rubber, | ||
48 | Light, | ||
49 | // Hereafter are BulletSim additions | ||
50 | Avatar, | ||
51 | NumberOfTypes // the count of types in the enum. | ||
52 | } | ||
53 | |||
54 | // Names must be in the order of the above enum. | ||
55 | // These names must coorespond to the lower case field names in the MaterialAttributes | ||
56 | // structure as reflection is used to select the field to put the value in. | ||
57 | public static readonly string[] MaterialAttribs = { "Density", "Friction", "Restitution"}; | ||
58 | |||
59 | public MaterialAttributes(string t, float d, float f, float r) | ||
60 | { | ||
61 | type = t; | ||
62 | density = d; | ||
63 | friction = f; | ||
64 | restitution = r; | ||
65 | } | ||
66 | public string type; | ||
67 | public float density; | ||
68 | public float friction; | ||
69 | public float restitution; | ||
70 | } | ||
71 | |||
72 | public static class BSMaterials | ||
73 | { | ||
74 | // Attributes for each material type | ||
75 | private static readonly MaterialAttributes[] Attributes; | ||
76 | |||
77 | // Map of material name to material type code | ||
78 | public static readonly Dictionary<string, MaterialAttributes.Material> MaterialMap; | ||
79 | |||
80 | static BSMaterials() | ||
81 | { | ||
82 | // Attribute sets for both the non-physical and physical instances of materials. | ||
83 | Attributes = new MaterialAttributes[(int)MaterialAttributes.Material.NumberOfTypes * 2]; | ||
84 | |||
85 | // Map of name to type code. | ||
86 | MaterialMap = new Dictionary<string, MaterialAttributes.Material>(); | ||
87 | MaterialMap.Add("Stone", MaterialAttributes.Material.Stone); | ||
88 | MaterialMap.Add("Metal", MaterialAttributes.Material.Metal); | ||
89 | MaterialMap.Add("Glass", MaterialAttributes.Material.Glass); | ||
90 | MaterialMap.Add("Wood", MaterialAttributes.Material.Wood); | ||
91 | MaterialMap.Add("Flesh", MaterialAttributes.Material.Flesh); | ||
92 | MaterialMap.Add("Plastic", MaterialAttributes.Material.Plastic); | ||
93 | MaterialMap.Add("Rubber", MaterialAttributes.Material.Rubber); | ||
94 | MaterialMap.Add("Light", MaterialAttributes.Material.Light); | ||
95 | MaterialMap.Add("Avatar", MaterialAttributes.Material.Avatar); | ||
96 | } | ||
97 | |||
98 | // This is where all the default material attributes are defined. | ||
99 | public static void InitializeFromDefaults(ConfigurationParameters parms) | ||
100 | { | ||
101 | // Values from http://wiki.secondlife.com/wiki/PRIM_MATERIAL | ||
102 | float dDensity = parms.defaultDensity; | ||
103 | float dFriction = parms.defaultFriction; | ||
104 | float dRestitution = parms.defaultRestitution; | ||
105 | Attributes[(int)MaterialAttributes.Material.Stone] = | ||
106 | new MaterialAttributes("stone",dDensity, 0.8f, 0.4f); | ||
107 | Attributes[(int)MaterialAttributes.Material.Metal] = | ||
108 | new MaterialAttributes("metal",dDensity, 0.3f, 0.4f); | ||
109 | Attributes[(int)MaterialAttributes.Material.Glass] = | ||
110 | new MaterialAttributes("glass",dDensity, 0.2f, 0.7f); | ||
111 | Attributes[(int)MaterialAttributes.Material.Wood] = | ||
112 | new MaterialAttributes("wood",dDensity, 0.6f, 0.5f); | ||
113 | Attributes[(int)MaterialAttributes.Material.Flesh] = | ||
114 | new MaterialAttributes("flesh",dDensity, 0.9f, 0.3f); | ||
115 | Attributes[(int)MaterialAttributes.Material.Plastic] = | ||
116 | new MaterialAttributes("plastic",dDensity, 0.4f, 0.7f); | ||
117 | Attributes[(int)MaterialAttributes.Material.Rubber] = | ||
118 | new MaterialAttributes("rubber",dDensity, 0.9f, 0.9f); | ||
119 | Attributes[(int)MaterialAttributes.Material.Light] = | ||
120 | new MaterialAttributes("light",dDensity, dFriction, dRestitution); | ||
121 | Attributes[(int)MaterialAttributes.Material.Avatar] = | ||
122 | new MaterialAttributes("avatar",60f, 0.2f, 0f); | ||
123 | |||
124 | Attributes[(int)MaterialAttributes.Material.Stone + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
125 | new MaterialAttributes("stonePhysical",dDensity, 0.8f, 0.4f); | ||
126 | Attributes[(int)MaterialAttributes.Material.Metal + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
127 | new MaterialAttributes("metalPhysical",dDensity, 0.8f, 0.4f); | ||
128 | Attributes[(int)MaterialAttributes.Material.Glass + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
129 | new MaterialAttributes("glassPhysical",dDensity, 0.8f, 0.7f); | ||
130 | Attributes[(int)MaterialAttributes.Material.Wood + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
131 | new MaterialAttributes("woodPhysical",dDensity, 0.8f, 0.5f); | ||
132 | Attributes[(int)MaterialAttributes.Material.Flesh + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
133 | new MaterialAttributes("fleshPhysical",dDensity, 0.8f, 0.3f); | ||
134 | Attributes[(int)MaterialAttributes.Material.Plastic + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
135 | new MaterialAttributes("plasticPhysical",dDensity, 0.8f, 0.7f); | ||
136 | Attributes[(int)MaterialAttributes.Material.Rubber + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
137 | new MaterialAttributes("rubberPhysical",dDensity, 0.8f, 0.9f); | ||
138 | Attributes[(int)MaterialAttributes.Material.Light + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
139 | new MaterialAttributes("lightPhysical",dDensity, dFriction, dRestitution); | ||
140 | Attributes[(int)MaterialAttributes.Material.Avatar + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
141 | new MaterialAttributes("avatarPhysical",60f, 0.2f, 0f); | ||
142 | } | ||
143 | |||
144 | // Under the [BulletSim] section, one can change the individual material | ||
145 | // attribute values. The format of the configuration parameter is: | ||
146 | // <materialName><Attribute>["Physical"] = floatValue | ||
147 | // For instance: | ||
148 | // [BulletSim] | ||
149 | // StoneFriction = 0.2 | ||
150 | // FleshRestitutionPhysical = 0.8 | ||
151 | // Materials can have different parameters for their static and | ||
152 | // physical instantiations. When setting the non-physical value, | ||
153 | // both values are changed. Setting the physical value only changes | ||
154 | // the physical value. | ||
155 | public static void InitializefromParameters(IConfig pConfig) | ||
156 | { | ||
157 | foreach (KeyValuePair<string, MaterialAttributes.Material> kvp in MaterialMap) | ||
158 | { | ||
159 | string matName = kvp.Key; | ||
160 | foreach (string attribName in MaterialAttributes.MaterialAttribs) | ||
161 | { | ||
162 | string paramName = matName + attribName; | ||
163 | if (pConfig.Contains(paramName)) | ||
164 | { | ||
165 | float paramValue = pConfig.GetFloat(paramName); | ||
166 | SetAttributeValue((int)kvp.Value, attribName, paramValue); | ||
167 | // set the physical value also | ||
168 | SetAttributeValue((int)kvp.Value + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue); | ||
169 | } | ||
170 | paramName += "Physical"; | ||
171 | if (pConfig.Contains(paramName)) | ||
172 | { | ||
173 | float paramValue = pConfig.GetFloat(paramName); | ||
174 | SetAttributeValue((int)kvp.Value + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue); | ||
175 | } | ||
176 | } | ||
177 | } | ||
178 | } | ||
179 | |||
180 | // Use reflection to set the value in the attribute structure. | ||
181 | private static void SetAttributeValue(int matType, string attribName, float val) | ||
182 | { | ||
183 | MaterialAttributes thisAttrib = Attributes[matType]; | ||
184 | FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName.ToLower()); | ||
185 | if (fieldInfo != null) | ||
186 | { | ||
187 | fieldInfo.SetValue(thisAttrib, val); | ||
188 | Attributes[matType] = thisAttrib; | ||
189 | } | ||
190 | } | ||
191 | |||
192 | // Given a material type, return a structure of attributes. | ||
193 | public static MaterialAttributes GetAttributes(MaterialAttributes.Material type, bool isPhysical) | ||
194 | { | ||
195 | int ind = (int)type; | ||
196 | if (isPhysical) ind += (int)MaterialAttributes.Material.NumberOfTypes; | ||
197 | return Attributes[ind]; | ||
198 | } | ||
199 | } | ||
200 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs index bc6e4c4..e0faf4e 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs | |||
@@ -1,104 +1,220 @@ | |||
1 | using System; | 1 | /* |
2 | using System.Collections.Generic; | 2 | * Copyright (c) Contributors, http://opensimulator.org/ |
3 | using System.Text; | 3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. |
4 | using OpenMetaverse; | 4 | * |
5 | 5 | * Redistribution and use in source and binary forms, with or without | |
6 | namespace OpenSim.Region.Physics.BulletSPlugin | 6 | * modification, are permitted provided that the following conditions are met: |
7 | { | 7 | * * Redistributions of source code must retain the above copyright |
8 | public abstract class BSMotor | 8 | * notice, this list of conditions and the following disclaimer. |
9 | { | 9 | * * Redistributions in binary form must reproduce the above copyright |
10 | public virtual void Reset() { } | 10 | * notice, this list of conditions and the following disclaimer in the |
11 | public virtual void Zero() { } | 11 | * documentation and/or other materials provided with the distribution. |
12 | } | 12 | * * Neither the name of the OpenSimulator Project nor the |
13 | // Can all the incremental stepping be replaced with motor classes? | 13 | * names of its contributors may be used to endorse or promote products |
14 | public class BSVMotor : BSMotor | 14 | * derived from this software without specific prior written permission. |
15 | { | 15 | * |
16 | public Vector3 FrameOfReference { get; set; } | 16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY |
17 | public Vector3 Offset { get; set; } | 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
19 | public float TimeScale { get; set; } | 19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY |
20 | public float TargetValueDecayTimeScale { get; set; } | 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
21 | public Vector3 CurrentValueReductionTimescale { get; set; } | 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | public float Efficiency { get; set; } | 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
23 | 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
24 | public Vector3 TargetValue { get; private set; } | 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
25 | public Vector3 CurrentValue { get; private set; } | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | 26 | * | |
27 | 27 | */ | |
28 | 28 | using System; | |
29 | BSVMotor(float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency) | 29 | using System.Collections.Generic; |
30 | { | 30 | using System.Text; |
31 | TimeScale = timeScale; | 31 | using OpenMetaverse; |
32 | TargetValueDecayTimeScale = decayTimeScale; | 32 | |
33 | CurrentValueReductionTimescale = frictionTimeScale; | 33 | namespace OpenSim.Region.Physics.BulletSPlugin |
34 | Efficiency = efficiency; | 34 | { |
35 | } | 35 | public abstract class BSMotor |
36 | public void SetCurrent(Vector3 current) | 36 | { |
37 | { | 37 | // Timescales and other things can be turned off by setting them to 'infinite'. |
38 | CurrentValue = current; | 38 | public const float Infinite = 12345f; |
39 | } | 39 | public readonly static Vector3 InfiniteVector = new Vector3(BSMotor.Infinite, BSMotor.Infinite, BSMotor.Infinite); |
40 | public void SetTarget(Vector3 target) | 40 | |
41 | { | 41 | public BSMotor(string useName) |
42 | TargetValue = target; | 42 | { |
43 | } | 43 | UseName = useName; |
44 | public Vector3 Step(float timeStep) | 44 | PhysicsScene = null; |
45 | { | 45 | } |
46 | if (CurrentValue.LengthSquared() > 0.001f) | 46 | public virtual void Reset() { } |
47 | { | 47 | public virtual void Zero() { } |
48 | // Vector3 origDir = Target; // DEBUG | 48 | |
49 | // Vector3 origVel = CurrentValue; // DEBUG | 49 | // A name passed at motor creation for easily identifyable debugging messages. |
50 | 50 | public string UseName { get; private set; } | |
51 | // Add (desiredVelocity - currentAppliedVelocity) / howLongItShouldTakeToComplete | 51 | |
52 | Vector3 addAmount = (TargetValue - CurrentValue)/(TargetValue) * timeStep; | 52 | // Used only for outputting debug information. Might not be set so check for null. |
53 | CurrentValue += addAmount; | 53 | public BSScene PhysicsScene { get; set; } |
54 | 54 | protected void MDetailLog(string msg, params Object[] parms) | |
55 | float decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; | 55 | { |
56 | TargetValue *= (1f - decayFactor); | 56 | if (PhysicsScene != null) |
57 | 57 | { | |
58 | Vector3 frictionFactor = (Vector3.One / CurrentValueReductionTimescale) * timeStep; | 58 | if (PhysicsScene.VehicleLoggingEnabled) |
59 | CurrentValue *= (Vector3.One - frictionFactor); | 59 | { |
60 | } | 60 | PhysicsScene.DetailLog(msg, parms); |
61 | else | 61 | } |
62 | { | 62 | } |
63 | // if what remains of direction is very small, zero it. | 63 | } |
64 | TargetValue = Vector3.Zero; | 64 | } |
65 | CurrentValue = Vector3.Zero; | 65 | // Can all the incremental stepping be replaced with motor classes? |
66 | 66 | ||
67 | // VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID); | 67 | // Motor which moves CurrentValue to TargetValue over TimeScale seconds. |
68 | } | 68 | // The TargetValue decays in TargetValueDecayTimeScale and |
69 | return CurrentValue; | 69 | // the CurrentValue will be held back by FrictionTimeScale. |
70 | } | 70 | // TimeScale and TargetDelayTimeScale may be 'infinite' which means go decay. |
71 | } | 71 | |
72 | 72 | // For instance, if something is moving at speed X and the desired speed is Y, | |
73 | public class BSFMotor : BSMotor | 73 | // CurrentValue is X and TargetValue is Y. As the motor is stepped, new |
74 | { | 74 | // values of CurrentValue are returned that approach the TargetValue. |
75 | public float TimeScale { get; set; } | 75 | // The feature of decaying TargetValue is so vehicles will eventually |
76 | public float DecayTimeScale { get; set; } | 76 | // come to a stop rather than run forever. This can be disabled by |
77 | public float Friction { get; set; } | 77 | // setting TargetValueDecayTimescale to 'infinite'. |
78 | public float Efficiency { get; set; } | 78 | // The change from CurrentValue to TargetValue is linear over TimeScale seconds. |
79 | 79 | public class BSVMotor : BSMotor | |
80 | public float Target { get; private set; } | 80 | { |
81 | public float CurrentValue { get; private set; } | 81 | // public Vector3 FrameOfReference { get; set; } |
82 | 82 | // public Vector3 Offset { get; set; } | |
83 | BSFMotor(float timeScale, float decayTimescale, float friction, float efficiency) | 83 | |
84 | { | 84 | public float TimeScale { get; set; } |
85 | } | 85 | public float TargetValueDecayTimeScale { get; set; } |
86 | public void SetCurrent(float target) | 86 | public Vector3 FrictionTimescale { get; set; } |
87 | { | 87 | public float Efficiency { get; set; } |
88 | } | 88 | |
89 | public void SetTarget(float target) | 89 | public Vector3 TargetValue { get; private set; } |
90 | { | 90 | public Vector3 CurrentValue { get; private set; } |
91 | } | 91 | |
92 | public float Step(float timeStep) | 92 | public BSVMotor(string useName) |
93 | { | 93 | : base(useName) |
94 | return 0f; | 94 | { |
95 | } | 95 | TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite; |
96 | } | 96 | Efficiency = 1f; |
97 | public class BSPIDMotor : BSMotor | 97 | FrictionTimescale = BSMotor.InfiniteVector; |
98 | { | 98 | CurrentValue = TargetValue = Vector3.Zero; |
99 | // TODO: write and use this one | 99 | } |
100 | BSPIDMotor() | 100 | public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency) |
101 | { | 101 | : this(useName) |
102 | } | 102 | { |
103 | } | 103 | TimeScale = timeScale; |
104 | } | 104 | TargetValueDecayTimeScale = decayTimeScale; |
105 | FrictionTimescale = frictionTimeScale; | ||
106 | Efficiency = efficiency; | ||
107 | CurrentValue = TargetValue = Vector3.Zero; | ||
108 | } | ||
109 | public void SetCurrent(Vector3 current) | ||
110 | { | ||
111 | CurrentValue = current; | ||
112 | } | ||
113 | public void SetTarget(Vector3 target) | ||
114 | { | ||
115 | TargetValue = target; | ||
116 | } | ||
117 | |||
118 | // A form of stepping that does not take the time quantum into account. | ||
119 | // The caller must do the right thing later. | ||
120 | public Vector3 Step() | ||
121 | { | ||
122 | return Step(1f); | ||
123 | } | ||
124 | |||
125 | public Vector3 Step(float timeStep) | ||
126 | { | ||
127 | Vector3 returnCurrent = Vector3.Zero; | ||
128 | if (!CurrentValue.ApproxEquals(TargetValue, 0.01f)) | ||
129 | { | ||
130 | Vector3 origTarget = TargetValue; // DEBUG | ||
131 | Vector3 origCurrVal = CurrentValue; // DEBUG | ||
132 | |||
133 | // Addition = (desiredVector - currentAppliedVector) / secondsItShouldTakeToComplete | ||
134 | Vector3 addAmount = (TargetValue - CurrentValue)/TimeScale * timeStep; | ||
135 | CurrentValue += addAmount; | ||
136 | |||
137 | // The desired value reduces to zero which also reduces the difference with current. | ||
138 | // If the decay time is infinite, don't decay at all. | ||
139 | float decayFactor = 0f; | ||
140 | if (TargetValueDecayTimeScale != BSMotor.Infinite) | ||
141 | { | ||
142 | decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; | ||
143 | TargetValue *= (1f - decayFactor); | ||
144 | } | ||
145 | |||
146 | Vector3 frictionFactor = Vector3.Zero; | ||
147 | if (FrictionTimescale != BSMotor.InfiniteVector) | ||
148 | { | ||
149 | // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep; | ||
150 | // Individual friction components can be 'infinite' so compute each separately. | ||
151 | frictionFactor.X = FrictionTimescale.X == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.X) * timeStep; | ||
152 | frictionFactor.Y = FrictionTimescale.Y == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.Y) * timeStep; | ||
153 | frictionFactor.Z = FrictionTimescale.Z == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.Z) * timeStep; | ||
154 | CurrentValue *= (Vector3.One - frictionFactor); | ||
155 | } | ||
156 | |||
157 | returnCurrent = CurrentValue; | ||
158 | |||
159 | MDetailLog("{0}, BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},timeScale={5},addAmnt={6},targetDecay={7},decayFact={8},fricTS={9},frictFact={10}", | ||
160 | BSScene.DetailLogZero, UseName, origCurrVal, origTarget, | ||
161 | timeStep, TimeScale, addAmount, | ||
162 | TargetValueDecayTimeScale, decayFactor, | ||
163 | FrictionTimescale, frictionFactor); | ||
164 | MDetailLog("{0}, BSVMotor.Step,nonZero,{1},curr={2},target={3},add={4},decay={5},frict={6},ret={7}", | ||
165 | BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, | ||
166 | addAmount, decayFactor, frictionFactor, returnCurrent); | ||
167 | } | ||
168 | else | ||
169 | { | ||
170 | // Difference between what we have and target is small. Motor is done. | ||
171 | CurrentValue = Vector3.Zero; | ||
172 | TargetValue = Vector3.Zero; | ||
173 | |||
174 | MDetailLog("{0}, BSVMotor.Step,zero,{1},curr={2},target={3},ret={4}", | ||
175 | BSScene.DetailLogZero, UseName, TargetValue, CurrentValue, returnCurrent); | ||
176 | |||
177 | } | ||
178 | return returnCurrent; | ||
179 | } | ||
180 | public override string ToString() | ||
181 | { | ||
182 | return String.Format("<{0},curr={1},targ={2},decayTS={3},frictTS={4}>", | ||
183 | UseName, CurrentValue, TargetValue, TargetValueDecayTimeScale, FrictionTimescale); | ||
184 | } | ||
185 | } | ||
186 | |||
187 | public class BSFMotor : BSMotor | ||
188 | { | ||
189 | public float TimeScale { get; set; } | ||
190 | public float DecayTimeScale { get; set; } | ||
191 | public float Friction { get; set; } | ||
192 | public float Efficiency { get; set; } | ||
193 | |||
194 | public float Target { get; private set; } | ||
195 | public float CurrentValue { get; private set; } | ||
196 | |||
197 | public BSFMotor(string useName, float timeScale, float decayTimescale, float friction, float efficiency) | ||
198 | : base(useName) | ||
199 | { | ||
200 | } | ||
201 | public void SetCurrent(float target) | ||
202 | { | ||
203 | } | ||
204 | public void SetTarget(float target) | ||
205 | { | ||
206 | } | ||
207 | public float Step(float timeStep) | ||
208 | { | ||
209 | return 0f; | ||
210 | } | ||
211 | } | ||
212 | public class BSPIDMotor : BSMotor | ||
213 | { | ||
214 | // TODO: write and use this one | ||
215 | public BSPIDMotor(string useName) | ||
216 | : base(useName) | ||
217 | { | ||
218 | } | ||
219 | } | ||
220 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index f6a890e..92a5f2f 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs | |||
@@ -60,6 +60,9 @@ public abstract class BSPhysObject : PhysicsActor | |||
60 | Linkset = BSLinkset.Factory(PhysicsScene, this); | 60 | Linkset = BSLinkset.Factory(PhysicsScene, this); |
61 | LastAssetBuildFailed = false; | 61 | LastAssetBuildFailed = false; |
62 | 62 | ||
63 | // Default material type | ||
64 | Material = MaterialAttributes.Material.Wood; | ||
65 | |||
63 | CollisionCollection = new CollisionEventUpdate(); | 66 | CollisionCollection = new CollisionEventUpdate(); |
64 | SubscribedEventsMs = 0; | 67 | SubscribedEventsMs = 0; |
65 | CollidingStep = 0; | 68 | CollidingStep = 0; |
@@ -72,6 +75,7 @@ public abstract class BSPhysObject : PhysicsActor | |||
72 | public string TypeName { get; protected set; } | 75 | public string TypeName { get; protected set; } |
73 | 76 | ||
74 | public BSLinkset Linkset { get; set; } | 77 | public BSLinkset Linkset { get; set; } |
78 | public BSLinksetInfo LinksetInfo { get; set; } | ||
75 | 79 | ||
76 | // Return the object mass without calculating it or having side effects | 80 | // Return the object mass without calculating it or having side effects |
77 | public abstract float RawMass { get; } | 81 | public abstract float RawMass { get; } |
@@ -105,10 +109,17 @@ public abstract class BSPhysObject : PhysicsActor | |||
105 | public EntityProperties CurrentEntityProperties { get; set; } | 109 | public EntityProperties CurrentEntityProperties { get; set; } |
106 | public EntityProperties LastEntityProperties { get; set; } | 110 | public EntityProperties LastEntityProperties { get; set; } |
107 | 111 | ||
108 | public abstract OMV.Vector3 Scale { get; set; } | 112 | public virtual OMV.Vector3 Scale { get; set; } |
109 | public abstract bool IsSolid { get; } | 113 | public abstract bool IsSolid { get; } |
110 | public abstract bool IsStatic { get; } | 114 | public abstract bool IsStatic { get; } |
111 | 115 | ||
116 | // Materialness | ||
117 | public MaterialAttributes.Material Material { get; private set; } | ||
118 | public override void SetMaterial(int material) | ||
119 | { | ||
120 | Material = (MaterialAttributes.Material)material; | ||
121 | } | ||
122 | |||
112 | // Stop all physical motion. | 123 | // Stop all physical motion. |
113 | public abstract void ZeroMotion(bool inTaintTime); | 124 | public abstract void ZeroMotion(bool inTaintTime); |
114 | public abstract void ZeroAngularMotion(bool inTaintTime); | 125 | public abstract void ZeroAngularMotion(bool inTaintTime); |
@@ -128,6 +139,17 @@ public abstract class BSPhysObject : PhysicsActor | |||
128 | public abstract OMV.Quaternion RawOrientation { get; set; } | 139 | public abstract OMV.Quaternion RawOrientation { get; set; } |
129 | public abstract OMV.Quaternion ForceOrientation { get; set; } | 140 | public abstract OMV.Quaternion ForceOrientation { get; set; } |
130 | 141 | ||
142 | // The system is telling us the velocity it wants to move at. | ||
143 | protected OMV.Vector3 m_targetVelocity; | ||
144 | public override OMV.Vector3 TargetVelocity | ||
145 | { | ||
146 | get { return m_targetVelocity; } | ||
147 | set | ||
148 | { | ||
149 | m_targetVelocity = value; | ||
150 | Velocity = value; | ||
151 | } | ||
152 | } | ||
131 | public abstract OMV.Vector3 ForceVelocity { get; set; } | 153 | public abstract OMV.Vector3 ForceVelocity { get; set; } |
132 | 154 | ||
133 | public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } | 155 | public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } |
@@ -192,7 +214,7 @@ public abstract class BSPhysObject : PhysicsActor | |||
192 | { | 214 | { |
193 | bool ret = true; | 215 | bool ret = true; |
194 | // If the 'no collision' call, force it to happen right now so quick collision_end | 216 | // If the 'no collision' call, force it to happen right now so quick collision_end |
195 | bool force = CollisionCollection.Count == 0; | 217 | bool force = (CollisionCollection.Count == 0); |
196 | 218 | ||
197 | // throttle the collisions to the number of milliseconds specified in the subscription | 219 | // throttle the collisions to the number of milliseconds specified in the subscription |
198 | if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime)) | 220 | if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime)) |
@@ -210,8 +232,10 @@ public abstract class BSPhysObject : PhysicsActor | |||
210 | // DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count); | 232 | // DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count); |
211 | base.SendCollisionUpdate(CollisionCollection); | 233 | base.SendCollisionUpdate(CollisionCollection); |
212 | 234 | ||
213 | // The collisionCollection structure is passed around in the simulator. | 235 | // The CollisionCollection instance is passed around in the simulator. |
214 | // Make sure we don't have a handle to that one and that a new one is used for next time. | 236 | // Make sure we don't have a handle to that one and that a new one is used for next time. |
237 | // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here, | ||
238 | // a race condition is created for the other users of this instance. | ||
215 | CollisionCollection = new CollisionEventUpdate(); | 239 | CollisionCollection = new CollisionEventUpdate(); |
216 | } | 240 | } |
217 | return ret; | 241 | return ret; |
@@ -229,7 +253,8 @@ public abstract class BSPhysObject : PhysicsActor | |||
229 | 253 | ||
230 | PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate() | 254 | PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate() |
231 | { | 255 | { |
232 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | 256 | if (PhysBody.HasPhysicalBody) |
257 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
233 | }); | 258 | }); |
234 | } | 259 | } |
235 | else | 260 | else |
@@ -243,7 +268,9 @@ public abstract class BSPhysObject : PhysicsActor | |||
243 | SubscribedEventsMs = 0; | 268 | SubscribedEventsMs = 0; |
244 | PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() | 269 | PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() |
245 | { | 270 | { |
246 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | 271 | // Make sure there is a body there because sometimes destruction happens in an un-ideal order. |
272 | if (PhysBody.HasPhysicalBody) | ||
273 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
247 | }); | 274 | }); |
248 | } | 275 | } |
249 | // Return 'true' if the simulator wants collision events | 276 | // Return 'true' if the simulator wants collision events |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 2b3fa25..758d92b 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | |||
@@ -45,7 +45,6 @@ public sealed class BSPrim : BSPhysObject | |||
45 | private static readonly string LogHeader = "[BULLETS PRIM]"; | 45 | private static readonly string LogHeader = "[BULLETS PRIM]"; |
46 | 46 | ||
47 | // _size is what the user passed. Scale is what we pass to the physics engine with the mesh. | 47 | // _size is what the user passed. Scale is what we pass to the physics engine with the mesh. |
48 | // Often Scale is unity because the meshmerizer will apply _size when creating the mesh. | ||
49 | private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user | 48 | private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user |
50 | 49 | ||
51 | private bool _grabbed; | 50 | private bool _grabbed; |
@@ -93,7 +92,7 @@ public sealed class BSPrim : BSPhysObject | |||
93 | _physicsActorType = (int)ActorTypes.Prim; | 92 | _physicsActorType = (int)ActorTypes.Prim; |
94 | _position = pos; | 93 | _position = pos; |
95 | _size = size; | 94 | _size = size; |
96 | Scale = size; // the scale will be set by CreateGeom depending on object type | 95 | Scale = size; // prims are the size the user wants them to be (different for BSCharactes). |
97 | _orientation = rotation; | 96 | _orientation = rotation; |
98 | _buoyancy = 1f; | 97 | _buoyancy = 1f; |
99 | _velocity = OMV.Vector3.Zero; | 98 | _velocity = OMV.Vector3.Zero; |
@@ -108,8 +107,8 @@ public sealed class BSPrim : BSPhysObject | |||
108 | _mass = CalculateMass(); | 107 | _mass = CalculateMass(); |
109 | 108 | ||
110 | // No body or shape yet | 109 | // No body or shape yet |
111 | PhysBody = new BulletBody(LocalID, IntPtr.Zero); | 110 | PhysBody = new BulletBody(LocalID); |
112 | PhysShape = new BulletShape(IntPtr.Zero); | 111 | PhysShape = new BulletShape(); |
113 | 112 | ||
114 | DetailLog("{0},BSPrim.constructor,call", LocalID); | 113 | DetailLog("{0},BSPrim.constructor,call", LocalID); |
115 | // do the actual object creation at taint time | 114 | // do the actual object creation at taint time |
@@ -143,7 +142,9 @@ public sealed class BSPrim : BSPhysObject | |||
143 | DetailLog("{0},BSPrim.Destroy,taint,", LocalID); | 142 | DetailLog("{0},BSPrim.Destroy,taint,", LocalID); |
144 | // If there are physical body and shape, release my use of same. | 143 | // If there are physical body and shape, release my use of same. |
145 | PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); | 144 | PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); |
145 | PhysBody.Clear(); | ||
146 | PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); | 146 | PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); |
147 | PhysShape.Clear(); | ||
147 | }); | 148 | }); |
148 | } | 149 | } |
149 | 150 | ||
@@ -157,12 +158,10 @@ public sealed class BSPrim : BSPhysObject | |||
157 | // We presume the scale and size are the same. If scale must be changed for | 158 | // We presume the scale and size are the same. If scale must be changed for |
158 | // the physical shape, that is done when the geometry is built. | 159 | // the physical shape, that is done when the geometry is built. |
159 | _size = value; | 160 | _size = value; |
161 | Scale = _size; | ||
160 | ForceBodyShapeRebuild(false); | 162 | ForceBodyShapeRebuild(false); |
161 | } | 163 | } |
162 | } | 164 | } |
163 | // Scale is what we set in the physics engine. It is different than 'size' in that | ||
164 | // 'size' can be encorporated into the mesh. In that case, the scale is <1,1,1>. | ||
165 | public override OMV.Vector3 Scale { get; set; } | ||
166 | 165 | ||
167 | public override PrimitiveBaseShape Shape { | 166 | public override PrimitiveBaseShape Shape { |
168 | set { | 167 | set { |
@@ -189,13 +188,17 @@ public sealed class BSPrim : BSPhysObject | |||
189 | } | 188 | } |
190 | } | 189 | } |
191 | public override bool Selected { | 190 | public override bool Selected { |
192 | set { | 191 | set |
193 | _isSelected = value; | 192 | { |
194 | PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() | 193 | if (value != _isSelected) |
195 | { | 194 | { |
196 | DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); | 195 | _isSelected = value; |
197 | SetObjectDynamic(false); | 196 | PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() |
198 | }); | 197 | { |
198 | DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); | ||
199 | SetObjectDynamic(false); | ||
200 | }); | ||
201 | } | ||
199 | } | 202 | } |
200 | } | 203 | } |
201 | public override void CrossingFailure() { return; } | 204 | public override void CrossingFailure() { return; } |
@@ -244,7 +247,8 @@ public sealed class BSPrim : BSPhysObject | |||
244 | // Zero some other properties in the physics engine | 247 | // Zero some other properties in the physics engine |
245 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() | 248 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() |
246 | { | 249 | { |
247 | BulletSimAPI.ClearAllForces2(PhysBody.ptr); | 250 | if (PhysBody.HasPhysicalBody) |
251 | BulletSimAPI.ClearAllForces2(PhysBody.ptr); | ||
248 | }); | 252 | }); |
249 | } | 253 | } |
250 | public override void ZeroAngularMotion(bool inTaintTime) | 254 | public override void ZeroAngularMotion(bool inTaintTime) |
@@ -253,8 +257,12 @@ public sealed class BSPrim : BSPhysObject | |||
253 | // Zero some other properties in the physics engine | 257 | // Zero some other properties in the physics engine |
254 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() | 258 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() |
255 | { | 259 | { |
256 | BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); | 260 | // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity); |
257 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); | 261 | if (PhysBody.HasPhysicalBody) |
262 | { | ||
263 | BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, _rotationalVelocity); | ||
264 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); | ||
265 | } | ||
258 | }); | 266 | }); |
259 | } | 267 | } |
260 | 268 | ||
@@ -271,9 +279,12 @@ public sealed class BSPrim : BSPhysObject | |||
271 | } | 279 | } |
272 | public override OMV.Vector3 Position { | 280 | public override OMV.Vector3 Position { |
273 | get { | 281 | get { |
282 | /* NOTE: this refetch is not necessary. The simulator knows about linkset children | ||
283 | * and does not fetch this position info for children. Thus this is commented out. | ||
274 | // child prims move around based on their parent. Need to get the latest location | 284 | // child prims move around based on their parent. Need to get the latest location |
275 | if (!Linkset.IsRoot(this)) | 285 | if (!Linkset.IsRoot(this)) |
276 | _position = Linkset.Position(this); | 286 | _position = Linkset.PositionGet(this); |
287 | */ | ||
277 | 288 | ||
278 | // don't do the GetObjectPosition for root elements because this function is called a zillion times. | 289 | // don't do the GetObjectPosition for root elements because this function is called a zillion times. |
279 | // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); | 290 | // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); |
@@ -281,18 +292,22 @@ public sealed class BSPrim : BSPhysObject | |||
281 | } | 292 | } |
282 | set { | 293 | set { |
283 | // If the position must be forced into the physics engine, use ForcePosition. | 294 | // If the position must be forced into the physics engine, use ForcePosition. |
295 | // All positions are given in world positions. | ||
284 | if (_position == value) | 296 | if (_position == value) |
285 | { | 297 | { |
298 | DetailLog("{0},BSPrim.setPosition,taint,positionNotChanging,pos={1},orient={2}", LocalID, _position, _orientation); | ||
286 | return; | 299 | return; |
287 | } | 300 | } |
288 | _position = value; | 301 | _position = value; |
289 | // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint? | ||
290 | PositionSanityCheck(false); | 302 | PositionSanityCheck(false); |
303 | |||
304 | // A linkset might need to know if a component information changed. | ||
305 | Linkset.UpdateProperties(this, false); | ||
306 | |||
291 | PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() | 307 | PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() |
292 | { | 308 | { |
293 | // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 309 | DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); |
294 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 310 | ForcePosition = _position; |
295 | ActivateIfPhysical(false); | ||
296 | }); | 311 | }); |
297 | } | 312 | } |
298 | } | 313 | } |
@@ -303,9 +318,11 @@ public sealed class BSPrim : BSPhysObject | |||
303 | } | 318 | } |
304 | set { | 319 | set { |
305 | _position = value; | 320 | _position = value; |
306 | // PositionSanityCheck(); // Don't do this! Causes a loop and caller should know better. | 321 | if (PhysBody.HasPhysicalBody) |
307 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 322 | { |
308 | ActivateIfPhysical(false); | 323 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); |
324 | ActivateIfPhysical(false); | ||
325 | } | ||
309 | } | 326 | } |
310 | } | 327 | } |
311 | 328 | ||
@@ -316,39 +333,46 @@ public sealed class BSPrim : BSPhysObject | |||
316 | { | 333 | { |
317 | bool ret = false; | 334 | bool ret = false; |
318 | 335 | ||
336 | if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position)) | ||
337 | { | ||
338 | // The physical object is out of the known/simulated area. | ||
339 | // Upper levels of code will handle the transition to other areas so, for | ||
340 | // the time, we just ignore the position. | ||
341 | return ret; | ||
342 | } | ||
343 | |||
319 | float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); | 344 | float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); |
320 | OMV.Vector3 upForce = OMV.Vector3.Zero; | 345 | OMV.Vector3 upForce = OMV.Vector3.Zero; |
321 | if (Position.Z < terrainHeight) | 346 | if (RawPosition.Z < terrainHeight) |
322 | { | 347 | { |
323 | DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); | 348 | DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); |
324 | float targetHeight = terrainHeight + (Size.Z / 2f); | 349 | float targetHeight = terrainHeight + (Size.Z / 2f); |
325 | // Upforce proportional to the distance away from the terrain. Correct the error in 1 sec. | 350 | // Upforce proportional to the distance away from the terrain. Correct the error in 1 sec. |
326 | upForce.Z = (terrainHeight - Position.Z) * 1f; | 351 | upForce.Z = (terrainHeight - RawPosition.Z) * 1f; |
327 | ret = true; | 352 | ret = true; |
328 | } | 353 | } |
329 | 354 | ||
330 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) | 355 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) |
331 | { | 356 | { |
332 | float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); | 357 | float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); |
333 | // TODO: a floating motor so object will bob in the water | 358 | // TODO: a floating motor so object will bob in the water |
334 | if (Math.Abs(Position.Z - waterHeight) > 0.1f) | 359 | if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f) |
335 | { | 360 | { |
336 | // Upforce proportional to the distance away from the water. Correct the error in 1 sec. | 361 | // Upforce proportional to the distance away from the water. Correct the error in 1 sec. |
337 | upForce.Z = (waterHeight - Position.Z) * 1f; | 362 | upForce.Z = (waterHeight - RawPosition.Z) * 1f; |
338 | ret = true; | 363 | ret = true; |
339 | } | 364 | } |
340 | } | 365 | } |
341 | 366 | ||
342 | // TODO: check for out of bounds | ||
343 | |||
344 | // The above code computes a force to apply to correct any out-of-bounds problems. Apply same. | 367 | // The above code computes a force to apply to correct any out-of-bounds problems. Apply same. |
368 | // TODO: This should be intergrated with a geneal physics action mechanism. | ||
369 | // TODO: This should be moderated with PID'ness. | ||
345 | if (ret) | 370 | if (ret) |
346 | { | 371 | { |
347 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.PositionSanityCheck:belowTerrain", delegate() | 372 | // Apply upforce and overcome gravity. |
348 | { | 373 | OMV.Vector3 correctionForce = upForce - PhysicsScene.DefaultGravity; |
349 | // Apply upforce and overcome gravity. | 374 | DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce); |
350 | ForceVelocity = ForceVelocity + upForce - PhysicsScene.DefaultGravity; | 375 | AddForce(correctionForce, false, inTaintTime); |
351 | }); | ||
352 | } | 376 | } |
353 | return ret; | 377 | return ret; |
354 | } | 378 | } |
@@ -408,7 +432,8 @@ public sealed class BSPrim : BSPhysObject | |||
408 | PhysicsScene.TaintedObject("BSPrim.setForce", delegate() | 432 | PhysicsScene.TaintedObject("BSPrim.setForce", delegate() |
409 | { | 433 | { |
410 | // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force); | 434 | // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force); |
411 | BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); | 435 | if (PhysBody.HasPhysicalBody) |
436 | BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); | ||
412 | }); | 437 | }); |
413 | } | 438 | } |
414 | } | 439 | } |
@@ -502,7 +527,8 @@ public sealed class BSPrim : BSPhysObject | |||
502 | PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() | 527 | PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() |
503 | { | 528 | { |
504 | // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); | 529 | // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); |
505 | BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); | 530 | if (PhysBody.HasPhysicalBody) |
531 | BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); | ||
506 | }); | 532 | }); |
507 | } | 533 | } |
508 | } | 534 | } |
@@ -537,23 +563,32 @@ public sealed class BSPrim : BSPhysObject | |||
537 | } | 563 | } |
538 | public override OMV.Quaternion Orientation { | 564 | public override OMV.Quaternion Orientation { |
539 | get { | 565 | get { |
566 | /* NOTE: this refetch is not necessary. The simulator knows about linkset children | ||
567 | * and does not fetch this position info for children. Thus this is commented out. | ||
540 | // Children move around because tied to parent. Get a fresh value. | 568 | // Children move around because tied to parent. Get a fresh value. |
541 | if (!Linkset.IsRoot(this)) | 569 | if (!Linkset.IsRoot(this)) |
542 | { | 570 | { |
543 | _orientation = Linkset.Orientation(this); | 571 | _orientation = Linkset.OrientationGet(this); |
544 | } | 572 | } |
573 | */ | ||
545 | return _orientation; | 574 | return _orientation; |
546 | } | 575 | } |
547 | set { | 576 | set { |
548 | if (_orientation == value) | 577 | if (_orientation == value) |
549 | return; | 578 | return; |
550 | _orientation = value; | 579 | _orientation = value; |
551 | // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint? | 580 | |
581 | // A linkset might need to know if a component information changed. | ||
582 | Linkset.UpdateProperties(this, false); | ||
583 | |||
552 | PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() | 584 | PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() |
553 | { | 585 | { |
554 | // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); | 586 | if (PhysBody.HasPhysicalBody) |
555 | // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 587 | { |
556 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 588 | // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); |
589 | // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation); | ||
590 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | ||
591 | } | ||
557 | }); | 592 | }); |
558 | } | 593 | } |
559 | } | 594 | } |
@@ -644,10 +679,7 @@ public sealed class BSPrim : BSPhysObject | |||
644 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); | 679 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); |
645 | 680 | ||
646 | // Collision filter can be set only when the object is in the world | 681 | // Collision filter can be set only when the object is in the world |
647 | if (PhysBody.collisionFilter != 0 || PhysBody.collisionMask != 0) | 682 | PhysBody.ApplyCollisionMask(); |
648 | { | ||
649 | BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr, (uint)PhysBody.collisionFilter, (uint)PhysBody.collisionMask); | ||
650 | } | ||
651 | 683 | ||
652 | // Recompute any linkset parameters. | 684 | // Recompute any linkset parameters. |
653 | // When going from non-physical to physical, this re-enables the constraints that | 685 | // When going from non-physical to physical, this re-enables the constraints that |
@@ -672,8 +704,12 @@ public sealed class BSPrim : BSPhysObject | |||
672 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); | 704 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); |
673 | // Stop all movement | 705 | // Stop all movement |
674 | ZeroMotion(true); | 706 | ZeroMotion(true); |
675 | // Center of mass is at the center of the object | 707 | |
676 | // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation); | 708 | // Set various physical properties so other object interact properly |
709 | MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false); | ||
710 | BulletSimAPI.SetFriction2(PhysBody.ptr, matAttrib.friction); | ||
711 | BulletSimAPI.SetRestitution2(PhysBody.ptr, matAttrib.restitution); | ||
712 | |||
677 | // Mass is zero which disables a bunch of physics stuff in Bullet | 713 | // Mass is zero which disables a bunch of physics stuff in Bullet |
678 | UpdatePhysicalMassProperties(0f); | 714 | UpdatePhysicalMassProperties(0f); |
679 | // Set collision detection parameters | 715 | // Set collision detection parameters |
@@ -682,24 +718,27 @@ public sealed class BSPrim : BSPhysObject | |||
682 | BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); | 718 | BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); |
683 | BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); | 719 | BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); |
684 | } | 720 | } |
685 | // There can be special things needed for implementing linksets | 721 | |
686 | Linkset.MakeStatic(this); | ||
687 | // The activation state is 'disabled' so Bullet will not try to act on it. | 722 | // The activation state is 'disabled' so Bullet will not try to act on it. |
688 | BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_SIMULATION); | 723 | // BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_SIMULATION); |
689 | // Start it out sleeping and physical actions could wake it up. | 724 | // Start it out sleeping and physical actions could wake it up. |
690 | // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING); | 725 | BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ISLAND_SLEEPING); |
726 | |||
727 | // This collides like a static object | ||
728 | PhysBody.collisionType = CollisionType.Static; | ||
691 | 729 | ||
692 | PhysBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter; | 730 | // There can be special things needed for implementing linksets |
693 | PhysBody.collisionMask = CollisionFilterGroups.StaticObjectMask; | 731 | Linkset.MakeStatic(this); |
694 | } | 732 | } |
695 | else | 733 | else |
696 | { | 734 | { |
697 | // Not a Bullet static object | 735 | // Not a Bullet static object |
698 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); | 736 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); |
699 | 737 | ||
700 | // Set various physical properties so internal dynamic properties will get computed correctly as they are set | 738 | // Set various physical properties so other object interact properly |
701 | BulletSimAPI.SetFriction2(PhysBody.ptr, PhysicsScene.Params.defaultFriction); | 739 | MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, true); |
702 | BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.defaultRestitution); | 740 | BulletSimAPI.SetFriction2(PhysBody.ptr, matAttrib.friction); |
741 | BulletSimAPI.SetRestitution2(PhysBody.ptr, matAttrib.restitution); | ||
703 | 742 | ||
704 | // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 | 743 | // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 |
705 | // Since this can be called multiple times, only zero forces when becoming physical | 744 | // Since this can be called multiple times, only zero forces when becoming physical |
@@ -727,16 +766,15 @@ public sealed class BSPrim : BSPhysObject | |||
727 | BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); | 766 | BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); |
728 | BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold); | 767 | BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold); |
729 | 768 | ||
730 | // There might be special things needed for implementing linksets. | 769 | // This collides like an object. |
731 | Linkset.MakeDynamic(this); | 770 | PhysBody.collisionType = CollisionType.Dynamic; |
732 | 771 | ||
733 | // Force activation of the object so Bullet will act on it. | 772 | // Force activation of the object so Bullet will act on it. |
734 | // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. | 773 | // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. |
735 | BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG); | 774 | BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG); |
736 | // BulletSimAPI.Activate2(BSBody.ptr, true); | ||
737 | 775 | ||
738 | PhysBody.collisionFilter = CollisionFilterGroups.ObjectFilter; | 776 | // There might be special things needed for implementing linksets. |
739 | PhysBody.collisionMask = CollisionFilterGroups.ObjectMask; | 777 | Linkset.MakeDynamic(this); |
740 | } | 778 | } |
741 | } | 779 | } |
742 | 780 | ||
@@ -763,8 +801,9 @@ public sealed class BSPrim : BSPhysObject | |||
763 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); | 801 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); |
764 | } | 802 | } |
765 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | 803 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); |
766 | PhysBody.collisionFilter = CollisionFilterGroups.VolumeDetectFilter; | 804 | |
767 | PhysBody.collisionMask = CollisionFilterGroups.VolumeDetectMask; | 805 | // Change collision info from a static object to a ghosty collision object |
806 | PhysBody.collisionType = CollisionType.VolumeDetect; | ||
768 | } | 807 | } |
769 | } | 808 | } |
770 | 809 | ||
@@ -839,15 +878,6 @@ public sealed class BSPrim : BSPhysObject | |||
839 | } | 878 | } |
840 | public override OMV.Vector3 RotationalVelocity { | 879 | public override OMV.Vector3 RotationalVelocity { |
841 | get { | 880 | get { |
842 | /* | ||
843 | OMV.Vector3 pv = OMV.Vector3.Zero; | ||
844 | // if close to zero, report zero | ||
845 | // This is copied from ODE but I'm not sure why it returns zero but doesn't | ||
846 | // zero the property in the physics engine. | ||
847 | if (_rotationalVelocity.ApproxEquals(pv, 0.2f)) | ||
848 | return pv; | ||
849 | */ | ||
850 | |||
851 | return _rotationalVelocity; | 881 | return _rotationalVelocity; |
852 | } | 882 | } |
853 | set { | 883 | set { |
@@ -856,7 +886,8 @@ public sealed class BSPrim : BSPhysObject | |||
856 | PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() | 886 | PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() |
857 | { | 887 | { |
858 | DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); | 888 | DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); |
859 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); | 889 | if (PhysBody.HasPhysicalBody) |
890 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); | ||
860 | }); | 891 | }); |
861 | } | 892 | } |
862 | } | 893 | } |
@@ -891,8 +922,11 @@ public sealed class BSPrim : BSPhysObject | |||
891 | _buoyancy = value; | 922 | _buoyancy = value; |
892 | // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | 923 | // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); |
893 | // Buoyancy is faked by changing the gravity applied to the object | 924 | // Buoyancy is faked by changing the gravity applied to the object |
894 | float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); | 925 | if (PhysBody.HasPhysicalBody) |
895 | BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); | 926 | { |
927 | float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); | ||
928 | BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); | ||
929 | } | ||
896 | } | 930 | } |
897 | } | 931 | } |
898 | 932 | ||
@@ -960,7 +994,8 @@ public sealed class BSPrim : BSPhysObject | |||
960 | } | 994 | } |
961 | DetailLog("{0},BSPrim.AddForce,taint,force={1}", LocalID, fSum); | 995 | DetailLog("{0},BSPrim.AddForce,taint,force={1}", LocalID, fSum); |
962 | if (fSum != OMV.Vector3.Zero) | 996 | if (fSum != OMV.Vector3.Zero) |
963 | BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, fSum); | 997 | if (PhysBody.HasPhysicalBody) |
998 | BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, fSum); | ||
964 | }); | 999 | }); |
965 | } | 1000 | } |
966 | 1001 | ||
@@ -971,7 +1006,8 @@ public sealed class BSPrim : BSPhysObject | |||
971 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyForceImpulse", delegate() | 1006 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyForceImpulse", delegate() |
972 | { | 1007 | { |
973 | DetailLog("{0},BSPrim.ApplyForceImpulse,taint,tImpulse={1}", LocalID, applyImpulse); | 1008 | DetailLog("{0},BSPrim.ApplyForceImpulse,taint,tImpulse={1}", LocalID, applyImpulse); |
974 | BulletSimAPI.ApplyCentralImpulse2(PhysBody.ptr, applyImpulse); | 1009 | if (PhysBody.HasPhysicalBody) |
1010 | BulletSimAPI.ApplyCentralImpulse2(PhysBody.ptr, applyImpulse); | ||
975 | }); | 1011 | }); |
976 | } | 1012 | } |
977 | 1013 | ||
@@ -1007,18 +1043,23 @@ public sealed class BSPrim : BSPhysObject | |||
1007 | DetailLog("{0},BSPrim.AddAngularForce,taint,aForce={1}", LocalID, fSum); | 1043 | DetailLog("{0},BSPrim.AddAngularForce,taint,aForce={1}", LocalID, fSum); |
1008 | if (fSum != OMV.Vector3.Zero) | 1044 | if (fSum != OMV.Vector3.Zero) |
1009 | { | 1045 | { |
1010 | BulletSimAPI.ApplyTorque2(PhysBody.ptr, fSum); | 1046 | if (PhysBody.HasPhysicalBody) |
1047 | BulletSimAPI.ApplyTorque2(PhysBody.ptr, fSum); | ||
1011 | _torque = fSum; | 1048 | _torque = fSum; |
1012 | } | 1049 | } |
1013 | }); | 1050 | }); |
1014 | } | 1051 | } |
1015 | // A torque impulse. | 1052 | // A torque impulse. |
1053 | // ApplyTorqueImpulse adds torque directly to the angularVelocity. | ||
1054 | // AddAngularForce accumulates the force and applied it to the angular velocity all at once. | ||
1055 | // Computed as: angularVelocity += impulse * inertia; | ||
1016 | public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) | 1056 | public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) |
1017 | { | 1057 | { |
1018 | OMV.Vector3 applyImpulse = impulse; | 1058 | OMV.Vector3 applyImpulse = impulse; |
1019 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() | 1059 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() |
1020 | { | 1060 | { |
1021 | BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse); | 1061 | if (PhysBody.HasPhysicalBody) |
1062 | BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse); | ||
1022 | }); | 1063 | }); |
1023 | } | 1064 | } |
1024 | 1065 | ||
@@ -1326,7 +1367,7 @@ public sealed class BSPrim : BSPhysObject | |||
1326 | // Rebuild the geometry and object. | 1367 | // Rebuild the geometry and object. |
1327 | // This is called when the shape changes so we need to recreate the mesh/hull. | 1368 | // This is called when the shape changes so we need to recreate the mesh/hull. |
1328 | // Called at taint-time!!! | 1369 | // Called at taint-time!!! |
1329 | private void CreateGeomAndObject(bool forceRebuild) | 1370 | public void CreateGeomAndObject(bool forceRebuild) |
1330 | { | 1371 | { |
1331 | // If this prim is part of a linkset, we must remove and restore the physical | 1372 | // If this prim is part of a linkset, we must remove and restore the physical |
1332 | // links if the body is rebuilt. | 1373 | // links if the body is rebuilt. |
@@ -1336,12 +1377,11 @@ public sealed class BSPrim : BSPhysObject | |||
1336 | // Create the correct physical representation for this type of object. | 1377 | // Create the correct physical representation for this type of object. |
1337 | // Updates PhysBody and PhysShape with the new information. | 1378 | // Updates PhysBody and PhysShape with the new information. |
1338 | // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. | 1379 | // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. |
1339 | // Returns 'true' if either the body or the shape was changed. | ||
1340 | PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody) | 1380 | PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody) |
1341 | { | 1381 | { |
1342 | // Called if the current prim body is about to be destroyed. | 1382 | // Called if the current prim body is about to be destroyed. |
1343 | // Remove all the physical dependencies on the old body. | 1383 | // Remove all the physical dependencies on the old body. |
1344 | // (Maybe someday make the changing of BSShape an event handled by BSLinkset.) | 1384 | // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...) |
1345 | needToRestoreLinkset = Linkset.RemoveBodyDependencies(this); | 1385 | needToRestoreLinkset = Linkset.RemoveBodyDependencies(this); |
1346 | needToRestoreVehicle = _vehicle.RemoveBodyDependencies(this); | 1386 | needToRestoreVehicle = _vehicle.RemoveBodyDependencies(this); |
1347 | }); | 1387 | }); |
@@ -1381,54 +1421,16 @@ public sealed class BSPrim : BSPhysObject | |||
1381 | 1421 | ||
1382 | public override void UpdateProperties(EntityProperties entprop) | 1422 | public override void UpdateProperties(EntityProperties entprop) |
1383 | { | 1423 | { |
1384 | /* | 1424 | // Updates only for individual prims and for the root object of a linkset. |
1385 | UpdatedProperties changed = 0; | 1425 | if (Linkset.IsRoot(this)) |
1386 | // assign to the local variables so the normal set action does not happen | ||
1387 | // if (_position != entprop.Position) | ||
1388 | if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE)) | ||
1389 | { | ||
1390 | _position = entprop.Position; | ||
1391 | changed |= UpdatedProperties.Position; | ||
1392 | } | ||
1393 | // if (_orientation != entprop.Rotation) | ||
1394 | if (!_orientation.ApproxEquals(entprop.Rotation, ROTATION_TOLERANCE)) | ||
1395 | { | ||
1396 | _orientation = entprop.Rotation; | ||
1397 | changed |= UpdatedProperties.Rotation; | ||
1398 | } | ||
1399 | // if (_velocity != entprop.Velocity) | ||
1400 | if (!_velocity.ApproxEquals(entprop.Velocity, VELOCITY_TOLERANCE)) | ||
1401 | { | ||
1402 | _velocity = entprop.Velocity; | ||
1403 | changed |= UpdatedProperties.Velocity; | ||
1404 | } | ||
1405 | // if (_acceleration != entprop.Acceleration) | ||
1406 | if (!_acceleration.ApproxEquals(entprop.Acceleration, ACCELERATION_TOLERANCE)) | ||
1407 | { | ||
1408 | _acceleration = entprop.Acceleration; | ||
1409 | changed |= UpdatedProperties.Acceleration; | ||
1410 | } | ||
1411 | // if (_rotationalVelocity != entprop.RotationalVelocity) | ||
1412 | if (!_rotationalVelocity.ApproxEquals(entprop.RotationalVelocity, ROTATIONAL_VELOCITY_TOLERANCE)) | ||
1413 | { | ||
1414 | _rotationalVelocity = entprop.RotationalVelocity; | ||
1415 | changed |= UpdatedProperties.RotationalVel; | ||
1416 | } | ||
1417 | if (changed != 0) | ||
1418 | { | 1426 | { |
1419 | // Only update the position of single objects and linkset roots | 1427 | // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet |
1420 | if (Linkset.IsRoot(this)) | 1428 | // TODO: handle physics introduced by Bullet with computed vehicle physics. |
1429 | if (_vehicle.IsActive) | ||
1421 | { | 1430 | { |
1422 | base.RequestPhysicsterseUpdate(); | 1431 | entprop.RotationalVelocity = OMV.Vector3.Zero; |
1423 | } | 1432 | } |
1424 | } | ||
1425 | */ | ||
1426 | |||
1427 | // Don't check for damping here -- it's done in BulletSim and SceneObjectPart. | ||
1428 | 1433 | ||
1429 | // Updates only for individual prims and for the root object of a linkset. | ||
1430 | if (Linkset.IsRoot(this)) | ||
1431 | { | ||
1432 | // Assign directly to the local variables so the normal set action does not happen | 1434 | // Assign directly to the local variables so the normal set action does not happen |
1433 | _position = entprop.Position; | 1435 | _position = entprop.Position; |
1434 | _orientation = entprop.Rotation; | 1436 | _orientation = entprop.Rotation; |
@@ -1437,21 +1439,19 @@ public sealed class BSPrim : BSPhysObject | |||
1437 | _rotationalVelocity = entprop.RotationalVelocity; | 1439 | _rotationalVelocity = entprop.RotationalVelocity; |
1438 | 1440 | ||
1439 | // The sanity check can change the velocity and/or position. | 1441 | // The sanity check can change the velocity and/or position. |
1440 | if (PositionSanityCheck(true)) | 1442 | if (IsPhysical && PositionSanityCheck(true)) |
1441 | { | 1443 | { |
1442 | entprop.Position = _position; | 1444 | entprop.Position = _position; |
1443 | entprop.Velocity = _velocity; | 1445 | entprop.Velocity = _velocity; |
1444 | } | 1446 | } |
1445 | 1447 | ||
1446 | // remember the current and last set values | 1448 | OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; // DEBUG DEBUG DEBUG |
1447 | LastEntityProperties = CurrentEntityProperties; | ||
1448 | CurrentEntityProperties = entprop; | ||
1449 | |||
1450 | OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; | ||
1451 | DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}", | 1449 | DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}", |
1452 | LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity); | 1450 | LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity); |
1453 | 1451 | ||
1454 | // BulletSimAPI.DumpRigidBody2(PhysicsScene.World.ptr, BSBody.ptr); // DEBUG DEBUG DEBUG | 1452 | // remember the current and last set values |
1453 | LastEntityProperties = CurrentEntityProperties; | ||
1454 | CurrentEntityProperties = entprop; | ||
1455 | 1455 | ||
1456 | base.RequestPhysicsterseUpdate(); | 1456 | base.RequestPhysicsterseUpdate(); |
1457 | } | 1457 | } |
@@ -1466,7 +1466,7 @@ public sealed class BSPrim : BSPhysObject | |||
1466 | */ | 1466 | */ |
1467 | 1467 | ||
1468 | // The linkset implimentation might want to know about this. | 1468 | // The linkset implimentation might want to know about this. |
1469 | Linkset.UpdateProperties(this); | 1469 | Linkset.UpdateProperties(this, true); |
1470 | } | 1470 | } |
1471 | } | 1471 | } |
1472 | } | 1472 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 27a78d1..069cb0d 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | |||
@@ -39,23 +39,10 @@ using log4net; | |||
39 | using OpenMetaverse; | 39 | using OpenMetaverse; |
40 | 40 | ||
41 | // TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) | 41 | // TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) |
42 | // Test sculpties (verified that they don't work) | ||
43 | // Compute physics FPS reasonably | ||
44 | // Based on material, set density and friction | 42 | // Based on material, set density and friction |
45 | // Don't use constraints in linksets of non-physical objects. Means having to move children manually. | ||
46 | // Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly? | ||
47 | // In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground) | ||
48 | // At the moment, physical and phantom causes object to drop through the terrain | ||
49 | // Physical phantom objects and related typing (collision options ) | ||
50 | // Check out llVolumeDetect. Must do something for that. | ||
51 | // Use collision masks for collision with terrain and phantom objects | ||
52 | // More efficient memory usage when passing hull information from BSPrim to BulletSim | 43 | // More efficient memory usage when passing hull information from BSPrim to BulletSim |
53 | // Should prim.link() and prim.delink() membership checking happen at taint time? | ||
54 | // Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once. | ||
55 | // Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect | 44 | // Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect |
56 | // Implement LockAngularMotion | 45 | // Implement LockAngularMotion |
57 | // Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation) | ||
58 | // Remove mesh and Hull stuff. Use mesh passed to bullet and use convexdecom from bullet. | ||
59 | // Add PID movement operations. What does ScenePresence.MoveToTarget do? | 46 | // Add PID movement operations. What does ScenePresence.MoveToTarget do? |
60 | // Check terrain size. 128 or 127? | 47 | // Check terrain size. 128 or 127? |
61 | // Raycast | 48 | // Raycast |
@@ -109,6 +96,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
109 | public long SimulationStep { get { return m_simulationStep; } } | 96 | public long SimulationStep { get { return m_simulationStep; } } |
110 | private int m_taintsToProcessPerStep; | 97 | private int m_taintsToProcessPerStep; |
111 | 98 | ||
99 | public delegate void PreStepAction(float timeStep); | ||
100 | public event PreStepAction BeforeStep; | ||
101 | |||
112 | // A value of the time now so all the collision and update routines do not have to get their own | 102 | // A value of the time now so all the collision and update routines do not have to get their own |
113 | // Set to 'now' just before all the prims and actors are called for collisions and updates | 103 | // Set to 'now' just before all the prims and actors are called for collisions and updates |
114 | public int SimulationNowTime { get; private set; } | 104 | public int SimulationNowTime { get; private set; } |
@@ -140,7 +130,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
140 | public const uint GROUNDPLANE_ID = 1; | 130 | public const uint GROUNDPLANE_ID = 1; |
141 | public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here | 131 | public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here |
142 | 132 | ||
143 | private float m_waterLevel; | 133 | public float SimpleWaterLevel { get; set; } |
144 | public BSTerrainManager TerrainManager { get; private set; } | 134 | public BSTerrainManager TerrainManager { get; private set; } |
145 | 135 | ||
146 | public ConfigurationParameters Params | 136 | public ConfigurationParameters Params |
@@ -195,8 +185,10 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
195 | private string m_physicsLoggingDir; | 185 | private string m_physicsLoggingDir; |
196 | private string m_physicsLoggingPrefix; | 186 | private string m_physicsLoggingPrefix; |
197 | private int m_physicsLoggingFileMinutes; | 187 | private int m_physicsLoggingFileMinutes; |
188 | private bool m_physicsLoggingDoFlush; | ||
198 | // 'true' of the vehicle code is to log lots of details | 189 | // 'true' of the vehicle code is to log lots of details |
199 | public bool VehicleLoggingEnabled { get; private set; } | 190 | public bool VehicleLoggingEnabled { get; private set; } |
191 | public bool VehiclePhysicalLoggingEnabled { get; private set; } | ||
200 | 192 | ||
201 | #region Construction and Initialization | 193 | #region Construction and Initialization |
202 | public BSScene(string identifier) | 194 | public BSScene(string identifier) |
@@ -234,6 +226,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
234 | if (m_physicsLoggingEnabled) | 226 | if (m_physicsLoggingEnabled) |
235 | { | 227 | { |
236 | PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); | 228 | PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); |
229 | PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output error messages. | ||
237 | } | 230 | } |
238 | else | 231 | else |
239 | { | 232 | { |
@@ -302,12 +295,22 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
302 | m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); | 295 | m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); |
303 | m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-"); | 296 | m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-"); |
304 | m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); | 297 | m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); |
298 | m_physicsLoggingDoFlush = pConfig.GetBoolean("PhysicsLoggingDoFlush", false); | ||
305 | // Very detailed logging for vehicle debugging | 299 | // Very detailed logging for vehicle debugging |
306 | VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); | 300 | VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); |
301 | VehiclePhysicalLoggingEnabled = pConfig.GetBoolean("VehiclePhysicalLoggingEnabled", false); | ||
307 | 302 | ||
308 | // Do any replacements in the parameters | 303 | // Do any replacements in the parameters |
309 | m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); | 304 | m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); |
310 | } | 305 | } |
306 | |||
307 | // The material characteristics. | ||
308 | BSMaterials.InitializeFromDefaults(Params); | ||
309 | if (pConfig != null) | ||
310 | { | ||
311 | // Let the user add new and interesting material property values. | ||
312 | BSMaterials.InitializefromParameters(pConfig); | ||
313 | } | ||
311 | } | 314 | } |
312 | } | 315 | } |
313 | 316 | ||
@@ -345,8 +348,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
345 | // make sure no stepping happens while we're deleting stuff | 348 | // make sure no stepping happens while we're deleting stuff |
346 | m_initialized = false; | 349 | m_initialized = false; |
347 | 350 | ||
348 | TerrainManager.ReleaseGroundPlaneAndTerrain(); | ||
349 | |||
350 | foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects) | 351 | foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects) |
351 | { | 352 | { |
352 | kvp.Value.Destroy(); | 353 | kvp.Value.Destroy(); |
@@ -366,6 +367,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
366 | Shapes = null; | 367 | Shapes = null; |
367 | } | 368 | } |
368 | 369 | ||
370 | if (TerrainManager != null) | ||
371 | { | ||
372 | TerrainManager.ReleaseGroundPlaneAndTerrain(); | ||
373 | TerrainManager.Dispose(); | ||
374 | TerrainManager = null; | ||
375 | } | ||
376 | |||
369 | // Anything left in the unmanaged code should be cleaned out | 377 | // Anything left in the unmanaged code should be cleaned out |
370 | BulletSimAPI.Shutdown2(World.ptr); | 378 | BulletSimAPI.Shutdown2(World.ptr); |
371 | 379 | ||
@@ -490,8 +498,10 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
490 | ProcessTaints(); | 498 | ProcessTaints(); |
491 | 499 | ||
492 | // Some of the prims operate with special vehicle properties | 500 | // Some of the prims operate with special vehicle properties |
493 | ProcessVehicles(timeStep); | 501 | DoPreStepActions(timeStep); |
494 | ProcessTaints(); // the vehicles might have added taints | 502 | |
503 | // the prestep actions might have added taints | ||
504 | ProcessTaints(); | ||
495 | 505 | ||
496 | // step the physical world one interval | 506 | // step the physical world one interval |
497 | m_simulationStep++; | 507 | m_simulationStep++; |
@@ -499,16 +509,17 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
499 | 509 | ||
500 | try | 510 | try |
501 | { | 511 | { |
502 | if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG | 512 | if (VehiclePhysicalLoggingEnabled) DumpVehicles(); // DEBUG |
503 | if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); | 513 | if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); |
504 | 514 | ||
505 | numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep, | 515 | numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep, |
506 | out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr); | 516 | out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr); |
507 | 517 | ||
508 | if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime); | 518 | if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime); |
509 | DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}", | 519 | DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}", |
510 | DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount); | 520 | DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, |
511 | if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG | 521 | updatedEntityCount, collidersCount, ObjectsWithCollisions.Count); |
522 | if (VehiclePhysicalLoggingEnabled) DumpVehicles(); // DEBUG | ||
512 | } | 523 | } |
513 | catch (Exception e) | 524 | catch (Exception e) |
514 | { | 525 | { |
@@ -520,9 +531,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
520 | collidersCount = 0; | 531 | collidersCount = 0; |
521 | } | 532 | } |
522 | 533 | ||
523 | // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in | 534 | // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in. |
524 | 535 | ||
525 | // Get a value for 'now' so all the collision and update routines don't have to get their own | 536 | // Get a value for 'now' so all the collision and update routines don't have to get their own. |
526 | SimulationNowTime = Util.EnvironmentTickCount(); | 537 | SimulationNowTime = Util.EnvironmentTickCount(); |
527 | 538 | ||
528 | // If there were collisions, process them by sending the event to the prim. | 539 | // If there were collisions, process them by sending the event to the prim. |
@@ -562,12 +573,16 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
562 | 573 | ||
563 | // Objects that are done colliding are removed from the ObjectsWithCollisions list. | 574 | // Objects that are done colliding are removed from the ObjectsWithCollisions list. |
564 | // Not done above because it is inside an iteration of ObjectWithCollisions. | 575 | // Not done above because it is inside an iteration of ObjectWithCollisions. |
576 | // This complex collision processing is required to create an empty collision | ||
577 | // event call after all collisions have happened on an object. This enables | ||
578 | // the simulator to generate the 'collision end' event. | ||
565 | if (ObjectsWithNoMoreCollisions.Count > 0) | 579 | if (ObjectsWithNoMoreCollisions.Count > 0) |
566 | { | 580 | { |
567 | foreach (BSPhysObject po in ObjectsWithNoMoreCollisions) | 581 | foreach (BSPhysObject po in ObjectsWithNoMoreCollisions) |
568 | ObjectsWithCollisions.Remove(po); | 582 | ObjectsWithCollisions.Remove(po); |
569 | ObjectsWithNoMoreCollisions.Clear(); | 583 | ObjectsWithNoMoreCollisions.Clear(); |
570 | } | 584 | } |
585 | // Done with collisions. | ||
571 | 586 | ||
572 | // If any of the objects had updated properties, tell the object it has been changed by the physics engine | 587 | // If any of the objects had updated properties, tell the object it has been changed by the physics engine |
573 | if (updatedEntityCount > 0) | 588 | if (updatedEntityCount > 0) |
@@ -585,15 +600,14 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
585 | 600 | ||
586 | ProcessPostStepTaints(); | 601 | ProcessPostStepTaints(); |
587 | 602 | ||
588 | // This causes the unmanaged code to output ALL the values found in ALL the objects in the world. | 603 | // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. |
589 | // Only enable this in a limited test world with few objects. | 604 | // Only enable this in a limited test world with few objects. |
590 | // BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG | 605 | // BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG |
591 | 606 | ||
592 | // The physics engine returns the number of milliseconds it simulated this call. | 607 | // The physics engine returns the number of milliseconds it simulated this call. |
593 | // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. | 608 | // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. |
594 | // We multiply by 55 to give a recognizable running rate (55 or less). | 609 | // Multiply by 55 to give a nominal frame rate of 55. |
595 | return numSubSteps * m_fixedTimeStep * 1000 * 55; | 610 | return (float)numSubSteps * m_fixedTimeStep * 1000f * 55f; |
596 | // return timeStep * 1000 * 55; | ||
597 | } | 611 | } |
598 | 612 | ||
599 | // Something has collided | 613 | // Something has collided |
@@ -639,12 +653,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
639 | 653 | ||
640 | public override void SetWaterLevel(float baseheight) | 654 | public override void SetWaterLevel(float baseheight) |
641 | { | 655 | { |
642 | m_waterLevel = baseheight; | 656 | SimpleWaterLevel = baseheight; |
643 | } | ||
644 | // Someday.... | ||
645 | public float GetWaterLevelAtXYZ(Vector3 loc) | ||
646 | { | ||
647 | return m_waterLevel; | ||
648 | } | 657 | } |
649 | 658 | ||
650 | public override void DeleteTerrain() | 659 | public override void DeleteTerrain() |
@@ -915,6 +924,16 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
915 | } | 924 | } |
916 | } | 925 | } |
917 | 926 | ||
927 | private void DoPreStepActions(float timeStep) | ||
928 | { | ||
929 | ProcessVehicles(timeStep); | ||
930 | |||
931 | PreStepAction actions = BeforeStep; | ||
932 | if (actions != null) | ||
933 | actions(timeStep); | ||
934 | |||
935 | } | ||
936 | |||
918 | // Some prims have extra vehicle actions | 937 | // Some prims have extra vehicle actions |
919 | // Called at taint time! | 938 | // Called at taint time! |
920 | private void ProcessVehicles(float timeStep) | 939 | private void ProcessVehicles(float timeStep) |
@@ -979,6 +998,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
979 | // Should handle fetching the right type from the ini file and converting it. | 998 | // Should handle fetching the right type from the ini file and converting it. |
980 | // -- a delegate for getting the value as a float | 999 | // -- a delegate for getting the value as a float |
981 | // -- a delegate for setting the value from a float | 1000 | // -- a delegate for setting the value from a float |
1001 | // -- an optional delegate to update the value in the world. Most often used to | ||
1002 | // push the new value to an in-world object. | ||
982 | // | 1003 | // |
983 | // The single letter parameters for the delegates are: | 1004 | // The single letter parameters for the delegates are: |
984 | // s = BSScene | 1005 | // s = BSScene |
@@ -1069,7 +1090,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1069 | (s,p,l,v) => { s.PID_P = v; } ), | 1090 | (s,p,l,v) => { s.PID_P = v; } ), |
1070 | 1091 | ||
1071 | new ParameterDefn("DefaultFriction", "Friction factor used on new objects", | 1092 | new ParameterDefn("DefaultFriction", "Friction factor used on new objects", |
1072 | 0.5f, | 1093 | 0.2f, |
1073 | (s,cf,p,v) => { s.m_params[0].defaultFriction = cf.GetFloat(p, v); }, | 1094 | (s,cf,p,v) => { s.m_params[0].defaultFriction = cf.GetFloat(p, v); }, |
1074 | (s) => { return s.m_params[0].defaultFriction; }, | 1095 | (s) => { return s.m_params[0].defaultFriction; }, |
1075 | (s,p,l,v) => { s.m_params[0].defaultFriction = v; } ), | 1096 | (s,p,l,v) => { s.m_params[0].defaultFriction = v; } ), |
@@ -1084,7 +1105,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1084 | (s) => { return s.m_params[0].defaultRestitution; }, | 1105 | (s) => { return s.m_params[0].defaultRestitution; }, |
1085 | (s,p,l,v) => { s.m_params[0].defaultRestitution = v; } ), | 1106 | (s,p,l,v) => { s.m_params[0].defaultRestitution = v; } ), |
1086 | new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)", | 1107 | new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)", |
1087 | 0f, | 1108 | 0.04f, |
1088 | (s,cf,p,v) => { s.m_params[0].collisionMargin = cf.GetFloat(p, v); }, | 1109 | (s,cf,p,v) => { s.m_params[0].collisionMargin = cf.GetFloat(p, v); }, |
1089 | (s) => { return s.m_params[0].collisionMargin; }, | 1110 | (s) => { return s.m_params[0].collisionMargin; }, |
1090 | (s,p,l,v) => { s.m_params[0].collisionMargin = v; } ), | 1111 | (s,p,l,v) => { s.m_params[0].collisionMargin = v; } ), |
@@ -1151,7 +1172,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1151 | (s) => { return s.m_params[0].terrainImplementation; }, | 1172 | (s) => { return s.m_params[0].terrainImplementation; }, |
1152 | (s,p,l,v) => { s.m_params[0].terrainImplementation = v; } ), | 1173 | (s,p,l,v) => { s.m_params[0].terrainImplementation = v; } ), |
1153 | new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , | 1174 | new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , |
1154 | 0.5f, | 1175 | 0.3f, |
1155 | (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); }, | 1176 | (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); }, |
1156 | (s) => { return s.m_params[0].terrainFriction; }, | 1177 | (s) => { return s.m_params[0].terrainFriction; }, |
1157 | (s,p,l,v) => { s.m_params[0].terrainFriction = v; /* TODO: set on real terrain */} ), | 1178 | (s,p,l,v) => { s.m_params[0].terrainFriction = v; /* TODO: set on real terrain */} ), |
@@ -1165,13 +1186,19 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1165 | (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); }, | 1186 | (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); }, |
1166 | (s) => { return s.m_params[0].terrainRestitution; }, | 1187 | (s) => { return s.m_params[0].terrainRestitution; }, |
1167 | (s,p,l,v) => { s.m_params[0].terrainRestitution = v; /* TODO: set on real terrain */ } ), | 1188 | (s,p,l,v) => { s.m_params[0].terrainRestitution = v; /* TODO: set on real terrain */ } ), |
1189 | new ParameterDefn("TerrainCollisionMargin", "Margin where collision checking starts" , | ||
1190 | 0.04f, | ||
1191 | (s,cf,p,v) => { s.m_params[0].terrainCollisionMargin = cf.GetFloat(p, v); }, | ||
1192 | (s) => { return s.m_params[0].terrainCollisionMargin; }, | ||
1193 | (s,p,l,v) => { s.m_params[0].terrainCollisionMargin = v; /* TODO: set on real terrain */ } ), | ||
1194 | |||
1168 | new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", | 1195 | new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", |
1169 | 0.2f, | 1196 | 0.2f, |
1170 | (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); }, | 1197 | (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); }, |
1171 | (s) => { return s.m_params[0].avatarFriction; }, | 1198 | (s) => { return s.m_params[0].avatarFriction; }, |
1172 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ), | 1199 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ), |
1173 | new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", | 1200 | new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", |
1174 | 10f, | 1201 | 10.0f, |
1175 | (s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); }, | 1202 | (s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); }, |
1176 | (s) => { return s.m_params[0].avatarStandingFriction; }, | 1203 | (s) => { return s.m_params[0].avatarStandingFriction; }, |
1177 | (s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ), | 1204 | (s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ), |
@@ -1206,6 +1233,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1206 | (s) => { return s.m_params[0].avatarContactProcessingThreshold; }, | 1233 | (s) => { return s.m_params[0].avatarContactProcessingThreshold; }, |
1207 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ), | 1234 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ), |
1208 | 1235 | ||
1236 | new ParameterDefn("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)", | ||
1237 | 0.95f, | ||
1238 | (s,cf,p,v) => { s.m_params[0].vehicleAngularDamping = cf.GetFloat(p, v); }, | ||
1239 | (s) => { return s.m_params[0].vehicleAngularDamping; }, | ||
1240 | (s,p,l,v) => { s.m_params[0].vehicleAngularDamping = v; } ), | ||
1209 | 1241 | ||
1210 | new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", | 1242 | new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", |
1211 | 0f, | 1243 | 0f, |
@@ -1487,7 +1519,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1487 | { | 1519 | { |
1488 | PhysicsLogging.Write(msg, args); | 1520 | PhysicsLogging.Write(msg, args); |
1489 | // Add the Flush() if debugging crashes. Gets all the messages written out. | 1521 | // Add the Flush() if debugging crashes. Gets all the messages written out. |
1490 | // PhysicsLogging.Flush(); | 1522 | if (m_physicsLoggingDoFlush) PhysicsLogging.Flush(); |
1491 | } | 1523 | } |
1492 | // Used to fill in the LocalID when there isn't one. It's the correct number of characters. | 1524 | // Used to fill in the LocalID when there isn't one. It's the correct number of characters. |
1493 | public const string DetailLogZero = "0000000000"; | 1525 | public const string DetailLogZero = "0000000000"; |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs index 892c34b..d6e2fe9 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs | |||
@@ -65,9 +65,16 @@ public sealed class BSShapeCollection : IDisposable | |||
65 | private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>(); | 65 | private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>(); |
66 | private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>(); | 66 | private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>(); |
67 | 67 | ||
68 | private bool DDetail = false; | ||
69 | |||
68 | public BSShapeCollection(BSScene physScene) | 70 | public BSShapeCollection(BSScene physScene) |
69 | { | 71 | { |
70 | PhysicsScene = physScene; | 72 | PhysicsScene = physScene; |
73 | // Set the next to 'true' for very detailed shape update detailed logging (detailed details?) | ||
74 | // While detailed debugging is still active, this is better than commenting out all the | ||
75 | // DetailLog statements. When debugging slows down, this and the protected logging | ||
76 | // statements can be commented/removed. | ||
77 | DDetail = true; | ||
71 | } | 78 | } |
72 | 79 | ||
73 | public void Dispose() | 80 | public void Dispose() |
@@ -119,6 +126,11 @@ public sealed class BSShapeCollection : IDisposable | |||
119 | return ret; | 126 | return ret; |
120 | } | 127 | } |
121 | 128 | ||
129 | public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim) | ||
130 | { | ||
131 | return GetBodyAndShape(forceRebuild, sim, prim, null, null); | ||
132 | } | ||
133 | |||
122 | // Track another user of a body. | 134 | // Track another user of a body. |
123 | // We presume the caller has allocated the body. | 135 | // We presume the caller has allocated the body. |
124 | // Bodies only have one user so the body is just put into the world if not already there. | 136 | // Bodies only have one user so the body is just put into the world if not already there. |
@@ -126,13 +138,13 @@ public sealed class BSShapeCollection : IDisposable | |||
126 | { | 138 | { |
127 | lock (m_collectionActivityLock) | 139 | lock (m_collectionActivityLock) |
128 | { | 140 | { |
129 | DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body); | 141 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body); |
130 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate() | 142 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate() |
131 | { | 143 | { |
132 | if (!BulletSimAPI.IsInWorld2(body.ptr)) | 144 | if (!BulletSimAPI.IsInWorld2(body.ptr)) |
133 | { | 145 | { |
134 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr); | 146 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr); |
135 | DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); | 147 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); |
136 | } | 148 | } |
137 | }); | 149 | }); |
138 | } | 150 | } |
@@ -142,14 +154,14 @@ public sealed class BSShapeCollection : IDisposable | |||
142 | // Called when releasing use of a BSBody. BSShape is handled separately. | 154 | // Called when releasing use of a BSBody. BSShape is handled separately. |
143 | public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback ) | 155 | public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback ) |
144 | { | 156 | { |
145 | if (body.ptr == IntPtr.Zero) | 157 | if (!body.HasPhysicalBody) |
146 | return; | 158 | return; |
147 | 159 | ||
148 | lock (m_collectionActivityLock) | 160 | lock (m_collectionActivityLock) |
149 | { | 161 | { |
150 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate() | 162 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate() |
151 | { | 163 | { |
152 | DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}", | 164 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}", |
153 | body.ID, body, inTaintTime); | 165 | body.ID, body, inTaintTime); |
154 | // If the caller needs to know the old body is going away, pass the event up. | 166 | // If the caller needs to know the old body is going away, pass the event up. |
155 | if (bodyCallback != null) bodyCallback(body); | 167 | if (bodyCallback != null) bodyCallback(body); |
@@ -157,7 +169,7 @@ public sealed class BSShapeCollection : IDisposable | |||
157 | if (BulletSimAPI.IsInWorld2(body.ptr)) | 169 | if (BulletSimAPI.IsInWorld2(body.ptr)) |
158 | { | 170 | { |
159 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr); | 171 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr); |
160 | DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body); | 172 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body); |
161 | } | 173 | } |
162 | 174 | ||
163 | // Zero any reference to the shape so it is not freed when the body is deleted. | 175 | // Zero any reference to the shape so it is not freed when the body is deleted. |
@@ -184,7 +196,7 @@ public sealed class BSShapeCollection : IDisposable | |||
184 | { | 196 | { |
185 | // There is an existing instance of this mesh. | 197 | // There is an existing instance of this mesh. |
186 | meshDesc.referenceCount++; | 198 | meshDesc.referenceCount++; |
187 | DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}", | 199 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}", |
188 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); | 200 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); |
189 | } | 201 | } |
190 | else | 202 | else |
@@ -194,7 +206,7 @@ public sealed class BSShapeCollection : IDisposable | |||
194 | meshDesc.shapeKey = shape.shapeKey; | 206 | meshDesc.shapeKey = shape.shapeKey; |
195 | // We keep a reference to the underlying IMesh data so a hull can be built | 207 | // We keep a reference to the underlying IMesh data so a hull can be built |
196 | meshDesc.referenceCount = 1; | 208 | meshDesc.referenceCount = 1; |
197 | DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}", | 209 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}", |
198 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); | 210 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); |
199 | ret = true; | 211 | ret = true; |
200 | } | 212 | } |
@@ -207,7 +219,7 @@ public sealed class BSShapeCollection : IDisposable | |||
207 | { | 219 | { |
208 | // There is an existing instance of this hull. | 220 | // There is an existing instance of this hull. |
209 | hullDesc.referenceCount++; | 221 | hullDesc.referenceCount++; |
210 | DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}", | 222 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}", |
211 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); | 223 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); |
212 | } | 224 | } |
213 | else | 225 | else |
@@ -216,7 +228,7 @@ public sealed class BSShapeCollection : IDisposable | |||
216 | hullDesc.ptr = shape.ptr; | 228 | hullDesc.ptr = shape.ptr; |
217 | hullDesc.shapeKey = shape.shapeKey; | 229 | hullDesc.shapeKey = shape.shapeKey; |
218 | hullDesc.referenceCount = 1; | 230 | hullDesc.referenceCount = 1; |
219 | DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}", | 231 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}", |
220 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); | 232 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); |
221 | ret = true; | 233 | ret = true; |
222 | 234 | ||
@@ -236,17 +248,17 @@ public sealed class BSShapeCollection : IDisposable | |||
236 | // Release the usage of a shape. | 248 | // Release the usage of a shape. |
237 | public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback) | 249 | public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback) |
238 | { | 250 | { |
239 | if (shape.ptr == IntPtr.Zero) | 251 | if (!shape.HasPhysicalShape) |
240 | return; | 252 | return; |
241 | 253 | ||
242 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate() | 254 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate() |
243 | { | 255 | { |
244 | if (shape.ptr != IntPtr.Zero) | 256 | if (shape.HasPhysicalShape) |
245 | { | 257 | { |
246 | if (shape.isNativeShape) | 258 | if (shape.isNativeShape) |
247 | { | 259 | { |
248 | // Native shapes are not tracked and are released immediately | 260 | // Native shapes are not tracked and are released immediately |
249 | DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}", | 261 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}", |
250 | BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime); | 262 | BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime); |
251 | if (shapeCallback != null) shapeCallback(shape); | 263 | if (shapeCallback != null) shapeCallback(shape); |
252 | BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); | 264 | BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); |
@@ -286,7 +298,7 @@ public sealed class BSShapeCollection : IDisposable | |||
286 | if (shapeCallback != null) shapeCallback(shape); | 298 | if (shapeCallback != null) shapeCallback(shape); |
287 | meshDesc.lastReferenced = System.DateTime.Now; | 299 | meshDesc.lastReferenced = System.DateTime.Now; |
288 | Meshes[shape.shapeKey] = meshDesc; | 300 | Meshes[shape.shapeKey] = meshDesc; |
289 | DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}", | 301 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}", |
290 | BSScene.DetailLogZero, shape, meshDesc.referenceCount); | 302 | BSScene.DetailLogZero, shape, meshDesc.referenceCount); |
291 | 303 | ||
292 | } | 304 | } |
@@ -307,7 +319,7 @@ public sealed class BSShapeCollection : IDisposable | |||
307 | 319 | ||
308 | hullDesc.lastReferenced = System.DateTime.Now; | 320 | hullDesc.lastReferenced = System.DateTime.Now; |
309 | Hulls[shape.shapeKey] = hullDesc; | 321 | Hulls[shape.shapeKey] = hullDesc; |
310 | DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}", | 322 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}", |
311 | BSScene.DetailLogZero, shape, hullDesc.referenceCount); | 323 | BSScene.DetailLogZero, shape, hullDesc.referenceCount); |
312 | } | 324 | } |
313 | } | 325 | } |
@@ -325,13 +337,13 @@ public sealed class BSShapeCollection : IDisposable | |||
325 | // Failed the sanity check!! | 337 | // Failed the sanity check!! |
326 | PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", | 338 | PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", |
327 | LogHeader, shape.type, shape.ptr.ToString("X")); | 339 | LogHeader, shape.type, shape.ptr.ToString("X")); |
328 | DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", | 340 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", |
329 | BSScene.DetailLogZero, shape.type, shape.ptr.ToString("X")); | 341 | BSScene.DetailLogZero, shape.type, shape.ptr.ToString("X")); |
330 | return; | 342 | return; |
331 | } | 343 | } |
332 | 344 | ||
333 | int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr); | 345 | int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr); |
334 | DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren); | 346 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren); |
335 | 347 | ||
336 | for (int ii = numChildren - 1; ii >= 0; ii--) | 348 | for (int ii = numChildren - 1; ii >= 0; ii--) |
337 | { | 349 | { |
@@ -379,7 +391,7 @@ public sealed class BSShapeCollection : IDisposable | |||
379 | } | 391 | } |
380 | } | 392 | } |
381 | 393 | ||
382 | DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo); | 394 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo); |
383 | 395 | ||
384 | if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN) | 396 | if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN) |
385 | { | 397 | { |
@@ -408,19 +420,19 @@ public sealed class BSShapeCollection : IDisposable | |||
408 | if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) | 420 | if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) |
409 | { | 421 | { |
410 | // an avatar capsule is close to a native shape (it is not shared) | 422 | // an avatar capsule is close to a native shape (it is not shared) |
411 | ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, | 423 | GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, |
412 | FixedShapeKey.KEY_CAPSULE, shapeCallback); | 424 | FixedShapeKey.KEY_CAPSULE, shapeCallback); |
413 | DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape); | 425 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape); |
414 | ret = true; | 426 | ret = true; |
415 | haveShape = true; | 427 | haveShape = true; |
416 | } | 428 | } |
417 | 429 | ||
418 | // Compound shapes are handled special as they are rebuilt from scratch. | 430 | // Compound shapes are handled special as they are rebuilt from scratch. |
419 | // This isn't too great a hardship since most of the child shapes will already been created. | 431 | // This isn't too great a hardship since most of the child shapes will have already been created. |
420 | if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) | 432 | if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) |
421 | { | 433 | { |
422 | ret = GetReferenceToCompoundShape(prim, shapeCallback); | 434 | ret = GetReferenceToCompoundShape(prim, shapeCallback); |
423 | DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape); | 435 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape); |
424 | haveShape = true; | 436 | haveShape = true; |
425 | } | 437 | } |
426 | 438 | ||
@@ -433,7 +445,7 @@ public sealed class BSShapeCollection : IDisposable | |||
433 | } | 445 | } |
434 | 446 | ||
435 | // Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'. | 447 | // Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'. |
436 | private bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) | 448 | public bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) |
437 | { | 449 | { |
438 | bool ret = false; | 450 | bool ret = false; |
439 | bool haveShape = false; | 451 | bool haveShape = false; |
@@ -453,19 +465,27 @@ public sealed class BSShapeCollection : IDisposable | |||
453 | && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 | 465 | && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 |
454 | && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) | 466 | && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) |
455 | { | 467 | { |
468 | // Get the scale of any existing shape so we can see if the new shape is same native type and same size. | ||
469 | OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero; | ||
470 | if (prim.PhysShape.HasPhysicalShape) | ||
471 | scaleOfExistingShape = BulletSimAPI.GetLocalScaling2(prim.PhysShape.ptr); | ||
472 | |||
473 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}", | ||
474 | prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.type); | ||
475 | |||
456 | // It doesn't look like Bullet scales spheres so make sure the scales are all equal | 476 | // It doesn't look like Bullet scales spheres so make sure the scales are all equal |
457 | if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) | 477 | if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) |
458 | && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) | 478 | && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) |
459 | { | 479 | { |
460 | haveShape = true; | 480 | haveShape = true; |
461 | if (forceRebuild | 481 | if (forceRebuild |
462 | || prim.Scale != prim.Size | 482 | || prim.Scale != scaleOfExistingShape |
463 | || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE | 483 | || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE |
464 | ) | 484 | ) |
465 | { | 485 | { |
466 | ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE, | 486 | ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE, |
467 | FixedShapeKey.KEY_SPHERE, shapeCallback); | 487 | FixedShapeKey.KEY_SPHERE, shapeCallback); |
468 | DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}", | 488 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}", |
469 | prim.LocalID, forceRebuild, prim.PhysShape); | 489 | prim.LocalID, forceRebuild, prim.PhysShape); |
470 | } | 490 | } |
471 | } | 491 | } |
@@ -473,13 +493,13 @@ public sealed class BSShapeCollection : IDisposable | |||
473 | { | 493 | { |
474 | haveShape = true; | 494 | haveShape = true; |
475 | if (forceRebuild | 495 | if (forceRebuild |
476 | || prim.Scale != prim.Size | 496 | || prim.Scale != scaleOfExistingShape |
477 | || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX | 497 | || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX |
478 | ) | 498 | ) |
479 | { | 499 | { |
480 | ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX, | 500 | ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX, |
481 | FixedShapeKey.KEY_BOX, shapeCallback); | 501 | FixedShapeKey.KEY_BOX, shapeCallback); |
482 | DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}", | 502 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}", |
483 | prim.LocalID, forceRebuild, prim.PhysShape); | 503 | prim.LocalID, forceRebuild, prim.PhysShape); |
484 | } | 504 | } |
485 | } | 505 | } |
@@ -504,13 +524,13 @@ public sealed class BSShapeCollection : IDisposable | |||
504 | { | 524 | { |
505 | // Update prim.BSShape to reference a hull of this shape. | 525 | // Update prim.BSShape to reference a hull of this shape. |
506 | ret = GetReferenceToHull(prim,shapeCallback); | 526 | ret = GetReferenceToHull(prim,shapeCallback); |
507 | DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", | 527 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", |
508 | prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); | 528 | prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); |
509 | } | 529 | } |
510 | else | 530 | else |
511 | { | 531 | { |
512 | ret = GetReferenceToMesh(prim, shapeCallback); | 532 | ret = GetReferenceToMesh(prim, shapeCallback); |
513 | DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}", | 533 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}", |
514 | prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); | 534 | prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); |
515 | } | 535 | } |
516 | return ret; | 536 | return ret; |
@@ -528,9 +548,10 @@ public sealed class BSShapeCollection : IDisposable | |||
528 | BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey); | 548 | BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey); |
529 | 549 | ||
530 | // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. | 550 | // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. |
531 | DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", | 551 | if (DDetail) DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", |
532 | prim.LocalID, newShape, prim.Scale); | 552 | prim.LocalID, newShape, prim.Scale); |
533 | 553 | ||
554 | // native shapes are scaled by Bullet | ||
534 | prim.PhysShape = newShape; | 555 | prim.PhysShape = newShape; |
535 | return true; | 556 | return true; |
536 | } | 557 | } |
@@ -554,16 +575,14 @@ public sealed class BSShapeCollection : IDisposable | |||
554 | newShape = new BulletShape( | 575 | newShape = new BulletShape( |
555 | BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale) | 576 | BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale) |
556 | , shapeType); | 577 | , shapeType); |
557 | DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); | 578 | if (DDetail) DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); |
558 | } | 579 | } |
559 | else | 580 | else |
560 | { | 581 | { |
561 | // Native shapes are scaled in Bullet so set the scaling to the size | 582 | // Native shapes are scaled in Bullet so set the scaling to the size |
562 | prim.Scale = prim.Size; | ||
563 | nativeShapeData.Scale = prim.Scale; | ||
564 | newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType); | 583 | newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType); |
565 | } | 584 | } |
566 | if (newShape.ptr == IntPtr.Zero) | 585 | if (!newShape.HasPhysicalShape) |
567 | { | 586 | { |
568 | PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", | 587 | PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", |
569 | LogHeader, prim.LocalID, shapeType); | 588 | LogHeader, prim.LocalID, shapeType); |
@@ -580,7 +599,7 @@ public sealed class BSShapeCollection : IDisposable | |||
580 | // Called at taint-time! | 599 | // Called at taint-time! |
581 | private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback) | 600 | private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback) |
582 | { | 601 | { |
583 | BulletShape newShape = new BulletShape(IntPtr.Zero); | 602 | BulletShape newShape = new BulletShape(); |
584 | 603 | ||
585 | float lod; | 604 | float lod; |
586 | System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); | 605 | System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); |
@@ -589,7 +608,7 @@ public sealed class BSShapeCollection : IDisposable | |||
589 | if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH) | 608 | if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH) |
590 | return false; | 609 | return false; |
591 | 610 | ||
592 | DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}", | 611 | if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}", |
593 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X")); | 612 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X")); |
594 | 613 | ||
595 | // Since we're recreating new, get rid of the reference to the previous shape | 614 | // Since we're recreating new, get rid of the reference to the previous shape |
@@ -601,8 +620,6 @@ public sealed class BSShapeCollection : IDisposable | |||
601 | 620 | ||
602 | ReferenceShape(newShape); | 621 | ReferenceShape(newShape); |
603 | 622 | ||
604 | // meshes are already scaled by the meshmerizer | ||
605 | prim.Scale = new OMV.Vector3(1f, 1f, 1f); | ||
606 | prim.PhysShape = newShape; | 623 | prim.PhysShape = newShape; |
607 | 624 | ||
608 | return true; // 'true' means a new shape has been added to this prim | 625 | return true; // 'true' means a new shape has been added to this prim |
@@ -620,8 +637,7 @@ public sealed class BSShapeCollection : IDisposable | |||
620 | } | 637 | } |
621 | else | 638 | else |
622 | { | 639 | { |
623 | // Pass false for physicalness as this creates some sort of bounding box which we don't need | 640 | meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false, false, false); |
624 | meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); | ||
625 | 641 | ||
626 | if (meshData != null) | 642 | if (meshData != null) |
627 | { | 643 | { |
@@ -663,7 +679,7 @@ public sealed class BSShapeCollection : IDisposable | |||
663 | if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL) | 679 | if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL) |
664 | return false; | 680 | return false; |
665 | 681 | ||
666 | DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}", | 682 | if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}", |
667 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X")); | 683 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X")); |
668 | 684 | ||
669 | // Remove usage of the previous shape. | 685 | // Remove usage of the previous shape. |
@@ -674,8 +690,6 @@ public sealed class BSShapeCollection : IDisposable | |||
674 | 690 | ||
675 | ReferenceShape(newShape); | 691 | ReferenceShape(newShape); |
676 | 692 | ||
677 | // hulls are already scaled by the meshmerizer | ||
678 | prim.Scale = new OMV.Vector3(1f, 1f, 1f); | ||
679 | prim.PhysShape = newShape; | 693 | prim.PhysShape = newShape; |
680 | return true; // 'true' means a new shape has been added to this prim | 694 | return true; // 'true' means a new shape has been added to this prim |
681 | } | 695 | } |
@@ -694,8 +708,8 @@ public sealed class BSShapeCollection : IDisposable | |||
694 | else | 708 | else |
695 | { | 709 | { |
696 | // Build a new hull in the physical world | 710 | // Build a new hull in the physical world |
697 | // Pass false for physicalness as this creates some sort of bounding box which we don't need | 711 | // Pass true for physicalness as this creates some sort of bounding box which we don't need |
698 | IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); | 712 | IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false, false, false); |
699 | if (meshData != null) | 713 | if (meshData != null) |
700 | { | 714 | { |
701 | 715 | ||
@@ -784,7 +798,7 @@ public sealed class BSShapeCollection : IDisposable | |||
784 | BulletShape newShape = new BulletShape(hullPtr, BSPhysicsShapeType.SHAPE_HULL); | 798 | BulletShape newShape = new BulletShape(hullPtr, BSPhysicsShapeType.SHAPE_HULL); |
785 | newShape.shapeKey = newHullKey; | 799 | newShape.shapeKey = newHullKey; |
786 | 800 | ||
787 | return newShape; // 'true' means a new shape has been added to this prim | 801 | return newShape; |
788 | } | 802 | } |
789 | 803 | ||
790 | // Callback from convex hull creater with a newly created hull. | 804 | // Callback from convex hull creater with a newly created hull. |
@@ -809,7 +823,7 @@ public sealed class BSShapeCollection : IDisposable | |||
809 | // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape. | 823 | // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape. |
810 | CreateGeomMeshOrHull(prim, shapeCallback); | 824 | CreateGeomMeshOrHull(prim, shapeCallback); |
811 | BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity); | 825 | BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity); |
812 | DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}", | 826 | if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}", |
813 | prim.LocalID, cShape, prim.PhysShape); | 827 | prim.LocalID, cShape, prim.PhysShape); |
814 | 828 | ||
815 | prim.PhysShape = cShape; | 829 | prim.PhysShape = cShape; |
@@ -851,7 +865,7 @@ public sealed class BSShapeCollection : IDisposable | |||
851 | private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim) | 865 | private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim) |
852 | { | 866 | { |
853 | // If the shape was successfully created, nothing more to do | 867 | // If the shape was successfully created, nothing more to do |
854 | if (newShape.ptr != IntPtr.Zero) | 868 | if (newShape.HasPhysicalShape) |
855 | return newShape; | 869 | return newShape; |
856 | 870 | ||
857 | // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset | 871 | // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset |
@@ -910,7 +924,7 @@ public sealed class BSShapeCollection : IDisposable | |||
910 | bool ret = false; | 924 | bool ret = false; |
911 | 925 | ||
912 | // the mesh, hull or native shape must have already been created in Bullet | 926 | // the mesh, hull or native shape must have already been created in Bullet |
913 | bool mustRebuild = (prim.PhysBody.ptr == IntPtr.Zero); | 927 | bool mustRebuild = !prim.PhysBody.HasPhysicalBody; |
914 | 928 | ||
915 | // If there is an existing body, verify it's of an acceptable type. | 929 | // If there is an existing body, verify it's of an acceptable type. |
916 | // If not a solid object, body is a GhostObject. Otherwise a RigidBody. | 930 | // If not a solid object, body is a GhostObject. Otherwise a RigidBody. |
@@ -936,13 +950,13 @@ public sealed class BSShapeCollection : IDisposable | |||
936 | { | 950 | { |
937 | bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr, | 951 | bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr, |
938 | prim.LocalID, prim.RawPosition, prim.RawOrientation); | 952 | prim.LocalID, prim.RawPosition, prim.RawOrientation); |
939 | DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); | 953 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); |
940 | } | 954 | } |
941 | else | 955 | else |
942 | { | 956 | { |
943 | bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, | 957 | bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, |
944 | prim.LocalID, prim.RawPosition, prim.RawOrientation); | 958 | prim.LocalID, prim.RawPosition, prim.RawOrientation); |
945 | DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); | 959 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); |
946 | } | 960 | } |
947 | aBody = new BulletBody(prim.LocalID, bodyPtr); | 961 | aBody = new BulletBody(prim.LocalID, bodyPtr); |
948 | 962 | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs index 3ca756c..2b120d6 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs | |||
@@ -93,7 +93,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
93 | { | 93 | { |
94 | m_mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, m_mapInfo.ID, | 94 | m_mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, m_mapInfo.ID, |
95 | m_mapInfo.minCoords, m_mapInfo.maxCoords, | 95 | m_mapInfo.minCoords, m_mapInfo.maxCoords, |
96 | m_mapInfo.heightMap, BSTerrainManager.TERRAIN_COLLISION_MARGIN); | 96 | m_mapInfo.heightMap, PhysicsScene.Params.terrainCollisionMargin); |
97 | 97 | ||
98 | // Create the terrain shape from the mapInfo | 98 | // Create the terrain shape from the mapInfo |
99 | m_mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(m_mapInfo.Ptr), | 99 | m_mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(m_mapInfo.Ptr), |
@@ -121,9 +121,8 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
121 | // redo its bounding box now that it is in the world | 121 | // redo its bounding box now that it is in the world |
122 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); | 122 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); |
123 | 123 | ||
124 | BulletSimAPI.SetCollisionFilterMask2(m_mapInfo.terrainBody.ptr, | 124 | m_mapInfo.terrainBody.collisionType = CollisionType.Terrain; |
125 | (uint)CollisionFilterGroups.TerrainFilter, | 125 | m_mapInfo.terrainBody.ApplyCollisionMask(); |
126 | (uint)CollisionFilterGroups.TerrainMask); | ||
127 | 126 | ||
128 | // Make it so the terrain will not move or be considered for movement. | 127 | // Make it so the terrain will not move or be considered for movement. |
129 | BulletSimAPI.ForceActivationState2(m_mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION); | 128 | BulletSimAPI.ForceActivationState2(m_mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION); |
@@ -136,7 +135,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
136 | { | 135 | { |
137 | if (m_mapInfo != null) | 136 | if (m_mapInfo != null) |
138 | { | 137 | { |
139 | if (m_mapInfo.terrainBody.ptr != IntPtr.Zero) | 138 | if (m_mapInfo.terrainBody.HasPhysicalBody) |
140 | { | 139 | { |
141 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); | 140 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); |
142 | // Frees both the body and the shape. | 141 | // Frees both the body and the shape. |
@@ -148,7 +147,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
148 | } | 147 | } |
149 | 148 | ||
150 | // The passed position is relative to the base of the region. | 149 | // The passed position is relative to the base of the region. |
151 | public override float GetHeightAtXYZ(Vector3 pos) | 150 | public override float GetTerrainHeightAtXYZ(Vector3 pos) |
152 | { | 151 | { |
153 | float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; | 152 | float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; |
154 | 153 | ||
@@ -166,5 +165,11 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
166 | } | 165 | } |
167 | return ret; | 166 | return ret; |
168 | } | 167 | } |
168 | |||
169 | // The passed position is relative to the base of the region. | ||
170 | public override float GetWaterLevelAtXYZ(Vector3 pos) | ||
171 | { | ||
172 | return PhysicsScene.SimpleWaterLevel; | ||
173 | } | ||
169 | } | 174 | } |
170 | } | 175 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs index 23fcfd3..3428b9c 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs | |||
@@ -62,11 +62,12 @@ public abstract class BSTerrainPhys : IDisposable | |||
62 | ID = id; | 62 | ID = id; |
63 | } | 63 | } |
64 | public abstract void Dispose(); | 64 | public abstract void Dispose(); |
65 | public abstract float GetHeightAtXYZ(Vector3 pos); | 65 | public abstract float GetTerrainHeightAtXYZ(Vector3 pos); |
66 | public abstract float GetWaterLevelAtXYZ(Vector3 pos); | ||
66 | } | 67 | } |
67 | 68 | ||
68 | // ========================================================================================== | 69 | // ========================================================================================== |
69 | public sealed class BSTerrainManager | 70 | public sealed class BSTerrainManager : IDisposable |
70 | { | 71 | { |
71 | static string LogHeader = "[BULLETSIM TERRAIN MANAGER]"; | 72 | static string LogHeader = "[BULLETSIM TERRAIN MANAGER]"; |
72 | 73 | ||
@@ -75,13 +76,12 @@ public sealed class BSTerrainManager | |||
75 | public const float HEIGHT_INITIALIZATION = 24.987f; | 76 | public const float HEIGHT_INITIALIZATION = 24.987f; |
76 | public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f; | 77 | public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f; |
77 | public const float HEIGHT_GETHEIGHT_RET = 24.765f; | 78 | public const float HEIGHT_GETHEIGHT_RET = 24.765f; |
79 | public const float WATER_HEIGHT_GETHEIGHT_RET = 19.998f; | ||
78 | 80 | ||
79 | // If the min and max height are equal, we reduce the min by this | 81 | // If the min and max height are equal, we reduce the min by this |
80 | // amount to make sure that a bounding box is built for the terrain. | 82 | // amount to make sure that a bounding box is built for the terrain. |
81 | public const float HEIGHT_EQUAL_FUDGE = 0.2f; | 83 | public const float HEIGHT_EQUAL_FUDGE = 0.2f; |
82 | 84 | ||
83 | public const float TERRAIN_COLLISION_MARGIN = 0.0f; | ||
84 | |||
85 | // Until the whole simulator is changed to pass us the region size, we rely on constants. | 85 | // Until the whole simulator is changed to pass us the region size, we rely on constants. |
86 | public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); | 86 | public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); |
87 | 87 | ||
@@ -122,6 +122,11 @@ public sealed class BSTerrainManager | |||
122 | MegaRegionParentPhysicsScene = null; | 122 | MegaRegionParentPhysicsScene = null; |
123 | } | 123 | } |
124 | 124 | ||
125 | public void Dispose() | ||
126 | { | ||
127 | ReleaseGroundPlaneAndTerrain(); | ||
128 | } | ||
129 | |||
125 | // Create the initial instance of terrain and the underlying ground plane. | 130 | // Create the initial instance of terrain and the underlying ground plane. |
126 | // This is called from the initialization routine so we presume it is | 131 | // This is called from the initialization routine so we presume it is |
127 | // safe to call Bullet in real time. We hope no one is moving prims around yet. | 132 | // safe to call Bullet in real time. We hope no one is moving prims around yet. |
@@ -129,7 +134,8 @@ public sealed class BSTerrainManager | |||
129 | { | 134 | { |
130 | // The ground plane is here to catch things that are trying to drop to negative infinity | 135 | // The ground plane is here to catch things that are trying to drop to negative infinity |
131 | BulletShape groundPlaneShape = new BulletShape( | 136 | BulletShape groundPlaneShape = new BulletShape( |
132 | BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, TERRAIN_COLLISION_MARGIN), | 137 | BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, |
138 | PhysicsScene.Params.terrainCollisionMargin), | ||
133 | BSPhysicsShapeType.SHAPE_GROUNDPLANE); | 139 | BSPhysicsShapeType.SHAPE_GROUNDPLANE); |
134 | m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID, | 140 | m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID, |
135 | BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID, | 141 | BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID, |
@@ -139,8 +145,8 @@ public sealed class BSTerrainManager | |||
139 | // Ground plane does not move | 145 | // Ground plane does not move |
140 | BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION); | 146 | BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION); |
141 | // Everything collides with the ground plane. | 147 | // Everything collides with the ground plane. |
142 | BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr, | 148 | m_groundPlane.collisionType = CollisionType.Groundplane; |
143 | (uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask); | 149 | m_groundPlane.ApplyCollisionMask(); |
144 | 150 | ||
145 | // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. | 151 | // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. |
146 | BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); | 152 | BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); |
@@ -150,13 +156,13 @@ public sealed class BSTerrainManager | |||
150 | // Release all the terrain structures we might have allocated | 156 | // Release all the terrain structures we might have allocated |
151 | public void ReleaseGroundPlaneAndTerrain() | 157 | public void ReleaseGroundPlaneAndTerrain() |
152 | { | 158 | { |
153 | if (m_groundPlane.ptr != IntPtr.Zero) | 159 | if (m_groundPlane.HasPhysicalBody) |
154 | { | 160 | { |
155 | if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr)) | 161 | if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr)) |
156 | { | 162 | { |
157 | BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_groundPlane.ptr); | 163 | BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_groundPlane.ptr); |
158 | } | 164 | } |
159 | m_groundPlane.ptr = IntPtr.Zero; | 165 | m_groundPlane.Clear(); |
160 | } | 166 | } |
161 | 167 | ||
162 | ReleaseTerrain(); | 168 | ReleaseTerrain(); |
@@ -165,17 +171,22 @@ public sealed class BSTerrainManager | |||
165 | // Release all the terrain we have allocated | 171 | // Release all the terrain we have allocated |
166 | public void ReleaseTerrain() | 172 | public void ReleaseTerrain() |
167 | { | 173 | { |
168 | foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains) | 174 | lock (m_terrains) |
169 | { | 175 | { |
170 | kvp.Value.Dispose(); | 176 | foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains) |
177 | { | ||
178 | kvp.Value.Dispose(); | ||
179 | } | ||
180 | m_terrains.Clear(); | ||
171 | } | 181 | } |
172 | m_terrains.Clear(); | ||
173 | } | 182 | } |
174 | 183 | ||
175 | // The simulator wants to set a new heightmap for the terrain. | 184 | // The simulator wants to set a new heightmap for the terrain. |
176 | public void SetTerrain(float[] heightMap) { | 185 | public void SetTerrain(float[] heightMap) { |
177 | float[] localHeightMap = heightMap; | 186 | float[] localHeightMap = heightMap; |
178 | PhysicsScene.TaintedObject("TerrainManager.SetTerrain", delegate() | 187 | // If there are multiple requests for changes to the same terrain between ticks, |
188 | // only do that last one. | ||
189 | PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate() | ||
179 | { | 190 | { |
180 | if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) | 191 | if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) |
181 | { | 192 | { |
@@ -211,6 +222,7 @@ public sealed class BSTerrainManager | |||
211 | // terrain shape is created and added to the body. | 222 | // terrain shape is created and added to the body. |
212 | // This call is most often used to update the heightMap and parameters of the terrain. | 223 | // This call is most often used to update the heightMap and parameters of the terrain. |
213 | // (The above does suggest that some simplification/refactoring is in order.) | 224 | // (The above does suggest that some simplification/refactoring is in order.) |
225 | // Called during taint-time. | ||
214 | private void UpdateTerrain(uint id, float[] heightMap, | 226 | private void UpdateTerrain(uint id, float[] heightMap, |
215 | Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) | 227 | Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) |
216 | { | 228 | { |
@@ -220,7 +232,7 @@ public sealed class BSTerrainManager | |||
220 | // Find high and low points of passed heightmap. | 232 | // Find high and low points of passed heightmap. |
221 | // The min and max passed in is usually the area objects can be in (maximum | 233 | // The min and max passed in is usually the area objects can be in (maximum |
222 | // object height, for instance). The terrain wants the bounding box for the | 234 | // object height, for instance). The terrain wants the bounding box for the |
223 | // terrain so we replace passed min and max Z with the actual terrain min/max Z. | 235 | // terrain so replace passed min and max Z with the actual terrain min/max Z. |
224 | float minZ = float.MaxValue; | 236 | float minZ = float.MaxValue; |
225 | float maxZ = float.MinValue; | 237 | float maxZ = float.MinValue; |
226 | foreach (float height in heightMap) | 238 | foreach (float height in heightMap) |
@@ -238,15 +250,15 @@ public sealed class BSTerrainManager | |||
238 | 250 | ||
239 | Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f); | 251 | Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f); |
240 | 252 | ||
241 | BSTerrainPhys terrainPhys; | 253 | lock (m_terrains) |
242 | if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys)) | ||
243 | { | 254 | { |
244 | // There is already a terrain in this spot. Free the old and build the new. | 255 | BSTerrainPhys terrainPhys; |
245 | DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", | 256 | if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys)) |
246 | BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords); | ||
247 | |||
248 | PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:UpdateExisting", delegate() | ||
249 | { | 257 | { |
258 | // There is already a terrain in this spot. Free the old and build the new. | ||
259 | DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", | ||
260 | BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords); | ||
261 | |||
250 | // Remove old terrain from the collection | 262 | // Remove old terrain from the collection |
251 | m_terrains.Remove(terrainRegionBase); | 263 | m_terrains.Remove(terrainRegionBase); |
252 | // Release any physical memory it may be using. | 264 | // Release any physical memory it may be using. |
@@ -271,35 +283,24 @@ public sealed class BSTerrainManager | |||
271 | // I hate doing this, but just bail | 283 | // I hate doing this, but just bail |
272 | return; | 284 | return; |
273 | } | 285 | } |
274 | }); | 286 | } |
275 | } | 287 | else |
276 | else | 288 | { |
277 | { | 289 | // We don't know about this terrain so either we are creating a new terrain or |
278 | // We don't know about this terrain so either we are creating a new terrain or | 290 | // our mega-prim child is giving us a new terrain to add to the phys world |
279 | // our mega-prim child is giving us a new terrain to add to the phys world | ||
280 | |||
281 | // if this is a child terrain, calculate a unique terrain id | ||
282 | uint newTerrainID = id; | ||
283 | if (newTerrainID >= BSScene.CHILDTERRAIN_ID) | ||
284 | newTerrainID = ++m_terrainCount; | ||
285 | |||
286 | float[] heightMapX = heightMap; | ||
287 | Vector3 minCoordsX = minCoords; | ||
288 | Vector3 maxCoordsX = maxCoords; | ||
289 | 291 | ||
290 | DetailLog("{0},UpdateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}", | 292 | // if this is a child terrain, calculate a unique terrain id |
291 | BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); | 293 | uint newTerrainID = id; |
294 | if (newTerrainID >= BSScene.CHILDTERRAIN_ID) | ||
295 | newTerrainID = ++m_terrainCount; | ||
292 | 296 | ||
293 | // Code that must happen at taint-time | 297 | DetailLog("{0},UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}", |
294 | PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:NewTerrain", delegate() | 298 | BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); |
295 | { | ||
296 | DetailLog("{0},UpdateTerrain:NewTerrain,taint,baseX={1},baseY={2}", | ||
297 | BSScene.DetailLogZero, minCoordsX.X, minCoordsX.Y); | ||
298 | BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); | 299 | BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); |
299 | m_terrains.Add(terrainRegionBase, newTerrainPhys); | 300 | m_terrains.Add(terrainRegionBase, newTerrainPhys); |
300 | 301 | ||
301 | m_terrainModified = true; | 302 | m_terrainModified = true; |
302 | }); | 303 | } |
303 | } | 304 | } |
304 | } | 305 | } |
305 | 306 | ||
@@ -331,6 +332,13 @@ public sealed class BSTerrainManager | |||
331 | return newTerrainPhys; | 332 | return newTerrainPhys; |
332 | } | 333 | } |
333 | 334 | ||
335 | // Return 'true' of this position is somewhere in known physical terrain space | ||
336 | public bool IsWithinKnownTerrain(Vector3 pos) | ||
337 | { | ||
338 | Vector3 terrainBaseXYZ; | ||
339 | BSTerrainPhys physTerrain; | ||
340 | return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ); | ||
341 | } | ||
334 | 342 | ||
335 | // Given an X and Y, find the height of the terrain. | 343 | // Given an X and Y, find the height of the terrain. |
336 | // Since we could be handling multiple terrains for a mega-region, | 344 | // Since we could be handling multiple terrains for a mega-region, |
@@ -341,40 +349,74 @@ public sealed class BSTerrainManager | |||
341 | private float lastHeightTX = 999999f; | 349 | private float lastHeightTX = 999999f; |
342 | private float lastHeightTY = 999999f; | 350 | private float lastHeightTY = 999999f; |
343 | private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT; | 351 | private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT; |
344 | public float GetTerrainHeightAtXYZ(Vector3 loc) | 352 | public float GetTerrainHeightAtXYZ(Vector3 pos) |
345 | { | 353 | { |
346 | float tX = loc.X; | 354 | float tX = pos.X; |
347 | float tY = loc.Y; | 355 | float tY = pos.Y; |
348 | // You'd be surprized at the number of times this routine is called | 356 | // You'd be surprized at the number of times this routine is called |
349 | // with the same parameters as last time. | 357 | // with the same parameters as last time. |
350 | if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY) | 358 | if (!m_terrainModified && (lastHeightTX == tX) && (lastHeightTY == tY)) |
351 | return lastHeight; | 359 | return lastHeight; |
360 | m_terrainModified = false; | ||
352 | 361 | ||
353 | lastHeightTX = tX; | 362 | lastHeightTX = tX; |
354 | lastHeightTY = tY; | 363 | lastHeightTY = tY; |
355 | float ret = HEIGHT_GETHEIGHT_RET; | 364 | float ret = HEIGHT_GETHEIGHT_RET; |
356 | 365 | ||
357 | int offsetX = ((int)(tX / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; | 366 | Vector3 terrainBaseXYZ; |
358 | int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; | ||
359 | Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f); | ||
360 | |||
361 | BSTerrainPhys physTerrain; | 367 | BSTerrainPhys physTerrain; |
362 | if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain)) | 368 | if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ)) |
363 | { | 369 | { |
364 | ret = physTerrain.GetHeightAtXYZ(loc - terrainBaseXYZ); | 370 | ret = physTerrain.GetTerrainHeightAtXYZ(pos - terrainBaseXYZ); |
365 | DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,loc={1},base={2},height={3}", | ||
366 | BSScene.DetailLogZero, loc, terrainBaseXYZ, ret); | ||
367 | } | 371 | } |
368 | else | 372 | else |
369 | { | 373 | { |
370 | PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", | 374 | PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", |
371 | LogHeader, PhysicsScene.RegionName, tX, tY); | 375 | LogHeader, PhysicsScene.RegionName, tX, tY); |
376 | DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}", | ||
377 | BSScene.DetailLogZero, pos, terrainBaseXYZ); | ||
372 | } | 378 | } |
373 | m_terrainModified = false; | 379 | |
374 | lastHeight = ret; | 380 | lastHeight = ret; |
375 | return ret; | 381 | return ret; |
376 | } | 382 | } |
377 | 383 | ||
384 | public float GetWaterLevelAtXYZ(Vector3 pos) | ||
385 | { | ||
386 | float ret = WATER_HEIGHT_GETHEIGHT_RET; | ||
387 | |||
388 | Vector3 terrainBaseXYZ; | ||
389 | BSTerrainPhys physTerrain; | ||
390 | if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ)) | ||
391 | { | ||
392 | ret = physTerrain.GetWaterLevelAtXYZ(pos); | ||
393 | } | ||
394 | else | ||
395 | { | ||
396 | PhysicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}", | ||
397 | LogHeader, PhysicsScene.RegionName, pos, terrainBaseXYZ, ret); | ||
398 | } | ||
399 | return ret; | ||
400 | } | ||
401 | |||
402 | // Given an address, return 'true' of there is a description of that terrain and output | ||
403 | // the descriptor class and the 'base' fo the addresses therein. | ||
404 | private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase) | ||
405 | { | ||
406 | int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; | ||
407 | int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; | ||
408 | Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f); | ||
409 | |||
410 | BSTerrainPhys physTerrain = null; | ||
411 | lock (m_terrains) | ||
412 | { | ||
413 | m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain); | ||
414 | } | ||
415 | outTerrainBase = terrainBaseXYZ; | ||
416 | outPhysTerrain = physTerrain; | ||
417 | return (physTerrain != null); | ||
418 | } | ||
419 | |||
378 | // Although no one seems to check this, I do support combining. | 420 | // Although no one seems to check this, I do support combining. |
379 | public bool SupportsCombining() | 421 | public bool SupportsCombining() |
380 | { | 422 | { |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs index dca7150..6dc0d92 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs | |||
@@ -88,11 +88,13 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
88 | // Something is very messed up and a crash is in our future. | 88 | // Something is very messed up and a crash is in our future. |
89 | return; | 89 | return; |
90 | } | 90 | } |
91 | PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,indices={1},indSz={2},vertices={3},vertSz={4}", | ||
92 | ID, indicesCount, indices.Length, verticesCount, vertices.Length); | ||
91 | 93 | ||
92 | m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, | 94 | m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, |
93 | indicesCount, indices, verticesCount, vertices), | 95 | indicesCount, indices, verticesCount, vertices), |
94 | BSPhysicsShapeType.SHAPE_MESH); | 96 | BSPhysicsShapeType.SHAPE_MESH); |
95 | if (m_terrainShape.ptr == IntPtr.Zero) | 97 | if (!m_terrainShape.HasPhysicalShape) |
96 | { | 98 | { |
97 | // DISASTER!! | 99 | // DISASTER!! |
98 | PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID); | 100 | PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID); |
@@ -105,7 +107,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
105 | Quaternion rot = Quaternion.Identity; | 107 | Quaternion rot = Quaternion.Identity; |
106 | 108 | ||
107 | m_terrainBody = new BulletBody(id, BulletSimAPI.CreateBodyWithDefaultMotionState2( m_terrainShape.ptr, ID, pos, rot)); | 109 | m_terrainBody = new BulletBody(id, BulletSimAPI.CreateBodyWithDefaultMotionState2( m_terrainShape.ptr, ID, pos, rot)); |
108 | if (m_terrainBody.ptr == IntPtr.Zero) | 110 | if (!m_terrainBody.HasPhysicalBody) |
109 | { | 111 | { |
110 | // DISASTER!! | 112 | // DISASTER!! |
111 | physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase); | 113 | physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase); |
@@ -122,15 +124,14 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
122 | // Static objects are not very massive. | 124 | // Static objects are not very massive. |
123 | BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero); | 125 | BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero); |
124 | 126 | ||
125 | // Return the new terrain to the world of physical objects | 127 | // Put the new terrain to the world of physical objects |
126 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr); | 128 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr); |
127 | 129 | ||
128 | // redo its bounding box now that it is in the world | 130 | // Redo its bounding box now that it is in the world |
129 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr); | 131 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr); |
130 | 132 | ||
131 | BulletSimAPI.SetCollisionFilterMask2(m_terrainBody.ptr, | 133 | m_terrainBody.collisionType = CollisionType.Terrain; |
132 | (uint)CollisionFilterGroups.TerrainFilter, | 134 | m_terrainBody.ApplyCollisionMask(); |
133 | (uint)CollisionFilterGroups.TerrainMask); | ||
134 | 135 | ||
135 | // Make it so the terrain will not move or be considered for movement. | 136 | // Make it so the terrain will not move or be considered for movement. |
136 | BulletSimAPI.ForceActivationState2(m_terrainBody.ptr, ActivationState.DISABLE_SIMULATION); | 137 | BulletSimAPI.ForceActivationState2(m_terrainBody.ptr, ActivationState.DISABLE_SIMULATION); |
@@ -138,7 +139,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
138 | 139 | ||
139 | public override void Dispose() | 140 | public override void Dispose() |
140 | { | 141 | { |
141 | if (m_terrainBody.ptr != IntPtr.Zero) | 142 | if (m_terrainBody.HasPhysicalBody) |
142 | { | 143 | { |
143 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr); | 144 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr); |
144 | // Frees both the body and the shape. | 145 | // Frees both the body and the shape. |
@@ -146,7 +147,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
146 | } | 147 | } |
147 | } | 148 | } |
148 | 149 | ||
149 | public override float GetHeightAtXYZ(Vector3 pos) | 150 | public override float GetTerrainHeightAtXYZ(Vector3 pos) |
150 | { | 151 | { |
151 | // For the moment use the saved heightmap to get the terrain height. | 152 | // For the moment use the saved heightmap to get the terrain height. |
152 | // TODO: raycast downward to find the true terrain below the position. | 153 | // TODO: raycast downward to find the true terrain below the position. |
@@ -167,6 +168,12 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
167 | return ret; | 168 | return ret; |
168 | } | 169 | } |
169 | 170 | ||
171 | // The passed position is relative to the base of the region. | ||
172 | public override float GetWaterLevelAtXYZ(Vector3 pos) | ||
173 | { | ||
174 | return PhysicsScene.SimpleWaterLevel; | ||
175 | } | ||
176 | |||
170 | // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). | 177 | // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). |
171 | // Return 'true' if successfully created. | 178 | // Return 'true' if successfully created. |
172 | public static bool ConvertHeightmapToMesh( | 179 | public static bool ConvertHeightmapToMesh( |
@@ -188,6 +195,11 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
188 | // Simple mesh creation which assumes magnification == 1. | 195 | // Simple mesh creation which assumes magnification == 1. |
189 | // TODO: do a more general solution that scales, adds new vertices and smoothes the result. | 196 | // TODO: do a more general solution that scales, adds new vertices and smoothes the result. |
190 | 197 | ||
198 | // Create an array of vertices that is sizeX+1 by sizeY+1 (note the loop | ||
199 | // from zero to <= sizeX). The triangle indices are then generated as two triangles | ||
200 | // per heightmap point. There are sizeX by sizeY of these squares. The extra row and | ||
201 | // column of vertices are used to complete the triangles of the last row and column | ||
202 | // of the heightmap. | ||
191 | try | 203 | try |
192 | { | 204 | { |
193 | // One vertice per heightmap value plus the vertices off the top and bottom edge. | 205 | // One vertice per heightmap value plus the vertices off the top and bottom edge. |
@@ -200,16 +212,18 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
200 | float magY = (float)sizeY / extentY; | 212 | float magY = (float)sizeY / extentY; |
201 | physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}", | 213 | physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}", |
202 | BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY); | 214 | BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY); |
215 | float minHeight = float.MaxValue; | ||
203 | // Note that sizeX+1 vertices are created since there is land between this and the next region. | 216 | // Note that sizeX+1 vertices are created since there is land between this and the next region. |
204 | for (int yy = 0; yy <= sizeY; yy++) | 217 | for (int yy = 0; yy <= sizeY; yy++) |
205 | { | 218 | { |
206 | for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we got through sizeX + 1 times | 219 | for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we go around sizeX + 1 times |
207 | { | 220 | { |
208 | int offset = yy * sizeX + xx; | 221 | int offset = yy * sizeX + xx; |
209 | // Extend the height from the height from the last row or column | 222 | // Extend the height with the height from the last row or column |
210 | if (yy == sizeY) offset -= sizeX; | 223 | if (yy == sizeY) offset -= sizeX; |
211 | if (xx == sizeX) offset -= 1; | 224 | if (xx == sizeX) offset -= 1; |
212 | float height = heightMap[offset]; | 225 | float height = heightMap[offset]; |
226 | minHeight = Math.Min(minHeight, height); | ||
213 | vertices[verticesCount + 0] = (float)xx * magX + extentBase.X; | 227 | vertices[verticesCount + 0] = (float)xx * magX + extentBase.X; |
214 | vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y; | 228 | vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y; |
215 | vertices[verticesCount + 2] = height + extentBase.Z; | 229 | vertices[verticesCount + 2] = height + extentBase.Z; |
@@ -217,14 +231,12 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
217 | } | 231 | } |
218 | } | 232 | } |
219 | verticesCount = verticesCount / 3; | 233 | verticesCount = verticesCount / 3; |
220 | physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeVerts,verCount={1}", | ||
221 | BSScene.DetailLogZero, verticesCount); | ||
222 | 234 | ||
223 | for (int yy = 0; yy < sizeY; yy++) | 235 | for (int yy = 0; yy < sizeY; yy++) |
224 | { | 236 | { |
225 | for (int xx = 0; xx < sizeX; xx++) | 237 | for (int xx = 0; xx < sizeX; xx++) |
226 | { | 238 | { |
227 | int offset = yy * sizeX + xx; | 239 | int offset = yy * (sizeX + 1) + xx; |
228 | // Each vertices is presumed to be the upper left corner of a box of two triangles | 240 | // Each vertices is presumed to be the upper left corner of a box of two triangles |
229 | indices[indicesCount + 0] = offset; | 241 | indices[indicesCount + 0] = offset; |
230 | indices[indicesCount + 1] = offset + 1; | 242 | indices[indicesCount + 1] = offset + 1; |
@@ -235,8 +247,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
235 | indicesCount += 6; | 247 | indicesCount += 6; |
236 | } | 248 | } |
237 | } | 249 | } |
238 | physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeIndices,indCount={1}", // DEEBUG DEBUG DEBUG | 250 | |
239 | LogHeader, indicesCount); // DEBUG | ||
240 | ret = true; | 251 | ret = true; |
241 | } | 252 | } |
242 | catch (Exception e) | 253 | catch (Exception e) |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs index e60a760..962b540 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.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 | using System; | 27 | using System; |
28 | using System.Collections.Generic; | ||
28 | using System.Runtime.InteropServices; | 29 | using System.Runtime.InteropServices; |
29 | using System.Security; | 30 | using System.Security; |
30 | using System.Text; | 31 | using System.Text; |
@@ -32,93 +33,6 @@ using OpenMetaverse; | |||
32 | 33 | ||
33 | namespace OpenSim.Region.Physics.BulletSPlugin { | 34 | namespace OpenSim.Region.Physics.BulletSPlugin { |
34 | 35 | ||
35 | // Classes to allow some type checking for the API | ||
36 | // These hold pointers to allocated objects in the unmanaged space. | ||
37 | |||
38 | // The physics engine controller class created at initialization | ||
39 | public struct BulletSim | ||
40 | { | ||
41 | public BulletSim(uint worldId, BSScene bss, IntPtr xx) | ||
42 | { | ||
43 | ptr = xx; | ||
44 | worldID = worldId; | ||
45 | physicsScene = bss; | ||
46 | } | ||
47 | public IntPtr ptr; | ||
48 | public uint worldID; | ||
49 | // The scene is only in here so very low level routines have a handle to print debug/error messages | ||
50 | public BSScene physicsScene; | ||
51 | } | ||
52 | |||
53 | // An allocated Bullet btRigidBody | ||
54 | public struct BulletBody | ||
55 | { | ||
56 | public BulletBody(uint id, IntPtr xx) | ||
57 | { | ||
58 | ID = id; | ||
59 | ptr = xx; | ||
60 | collisionFilter = 0; | ||
61 | collisionMask = 0; | ||
62 | } | ||
63 | public IntPtr ptr; | ||
64 | public uint ID; | ||
65 | public CollisionFilterGroups collisionFilter; | ||
66 | public CollisionFilterGroups collisionMask; | ||
67 | public override string ToString() | ||
68 | { | ||
69 | StringBuilder buff = new StringBuilder(); | ||
70 | buff.Append("<id="); | ||
71 | buff.Append(ID.ToString()); | ||
72 | buff.Append(",p="); | ||
73 | buff.Append(ptr.ToString("X")); | ||
74 | if (collisionFilter != 0 || collisionMask != 0) | ||
75 | { | ||
76 | buff.Append(",f="); | ||
77 | buff.Append(collisionFilter.ToString("X")); | ||
78 | buff.Append(",m="); | ||
79 | buff.Append(collisionMask.ToString("X")); | ||
80 | } | ||
81 | buff.Append(">"); | ||
82 | return buff.ToString(); | ||
83 | } | ||
84 | } | ||
85 | |||
86 | public struct BulletShape | ||
87 | { | ||
88 | public BulletShape(IntPtr xx) | ||
89 | { | ||
90 | ptr = xx; | ||
91 | type=BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
92 | shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE; | ||
93 | isNativeShape = false; | ||
94 | } | ||
95 | public BulletShape(IntPtr xx, BSPhysicsShapeType typ) | ||
96 | { | ||
97 | ptr = xx; | ||
98 | type = typ; | ||
99 | shapeKey = 0; | ||
100 | isNativeShape = false; | ||
101 | } | ||
102 | public IntPtr ptr; | ||
103 | public BSPhysicsShapeType type; | ||
104 | public System.UInt64 shapeKey; | ||
105 | public bool isNativeShape; | ||
106 | public override string ToString() | ||
107 | { | ||
108 | StringBuilder buff = new StringBuilder(); | ||
109 | buff.Append("<p="); | ||
110 | buff.Append(ptr.ToString("X")); | ||
111 | buff.Append(",s="); | ||
112 | buff.Append(type.ToString()); | ||
113 | buff.Append(",k="); | ||
114 | buff.Append(shapeKey.ToString("X")); | ||
115 | buff.Append(",n="); | ||
116 | buff.Append(isNativeShape.ToString()); | ||
117 | buff.Append(">"); | ||
118 | return buff.ToString(); | ||
119 | } | ||
120 | } | ||
121 | |||
122 | // Constraint type values as defined by Bullet | 36 | // Constraint type values as defined by Bullet |
123 | public enum ConstraintType : int | 37 | public enum ConstraintType : int |
124 | { | 38 | { |
@@ -132,44 +46,6 @@ public enum ConstraintType : int | |||
132 | MAX_CONSTRAINT_TYPE | 46 | MAX_CONSTRAINT_TYPE |
133 | } | 47 | } |
134 | 48 | ||
135 | // An allocated Bullet btConstraint | ||
136 | public struct BulletConstraint | ||
137 | { | ||
138 | public BulletConstraint(IntPtr xx) | ||
139 | { | ||
140 | ptr = xx; | ||
141 | } | ||
142 | public IntPtr ptr; | ||
143 | } | ||
144 | |||
145 | // An allocated HeightMapThing which holds various heightmap info. | ||
146 | // Made a class rather than a struct so there would be only one | ||
147 | // instance of this and C# will pass around pointers rather | ||
148 | // than making copies. | ||
149 | public class BulletHeightMapInfo | ||
150 | { | ||
151 | public BulletHeightMapInfo(uint id, float[] hm, IntPtr xx) { | ||
152 | ID = id; | ||
153 | Ptr = xx; | ||
154 | heightMap = hm; | ||
155 | terrainRegionBase = Vector3.Zero; | ||
156 | minCoords = new Vector3(100f, 100f, 25f); | ||
157 | maxCoords = new Vector3(101f, 101f, 26f); | ||
158 | minZ = maxZ = 0f; | ||
159 | sizeX = sizeY = 256f; | ||
160 | } | ||
161 | public uint ID; | ||
162 | public IntPtr Ptr; | ||
163 | public float[] heightMap; | ||
164 | public Vector3 terrainRegionBase; | ||
165 | public Vector3 minCoords; | ||
166 | public Vector3 maxCoords; | ||
167 | public float sizeX, sizeY; | ||
168 | public float minZ, maxZ; | ||
169 | public BulletShape terrainShape; | ||
170 | public BulletBody terrainBody; | ||
171 | } | ||
172 | |||
173 | // =============================================================================== | 49 | // =============================================================================== |
174 | [StructLayout(LayoutKind.Sequential)] | 50 | [StructLayout(LayoutKind.Sequential)] |
175 | public struct ConvexHull | 51 | public struct ConvexHull |
@@ -287,6 +163,8 @@ public struct ConfigurationParameters | |||
287 | public float terrainFriction; | 163 | public float terrainFriction; |
288 | public float terrainHitFraction; | 164 | public float terrainHitFraction; |
289 | public float terrainRestitution; | 165 | public float terrainRestitution; |
166 | public float terrainCollisionMargin; | ||
167 | |||
290 | public float avatarFriction; | 168 | public float avatarFriction; |
291 | public float avatarStandingFriction; | 169 | public float avatarStandingFriction; |
292 | public float avatarDensity; | 170 | public float avatarDensity; |
@@ -296,6 +174,8 @@ public struct ConfigurationParameters | |||
296 | public float avatarCapsuleHeight; | 174 | public float avatarCapsuleHeight; |
297 | public float avatarContactProcessingThreshold; | 175 | public float avatarContactProcessingThreshold; |
298 | 176 | ||
177 | public float vehicleAngularDamping; | ||
178 | |||
299 | public float maxPersistantManifoldPoolSize; | 179 | public float maxPersistantManifoldPoolSize; |
300 | public float maxCollisionAlgorithmPoolSize; | 180 | public float maxCollisionAlgorithmPoolSize; |
301 | public float shouldDisableContactPoolDynamicAllocation; | 181 | public float shouldDisableContactPoolDynamicAllocation; |
@@ -353,56 +233,35 @@ public enum CollisionFlags : uint | |||
353 | CF_CHARACTER_OBJECT = 1 << 4, | 233 | CF_CHARACTER_OBJECT = 1 << 4, |
354 | CF_DISABLE_VISUALIZE_OBJECT = 1 << 5, | 234 | CF_DISABLE_VISUALIZE_OBJECT = 1 << 5, |
355 | CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, | 235 | CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, |
356 | // Following used by BulletSim to control collisions | 236 | // Following used by BulletSim to control collisions and updates |
357 | BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, | 237 | BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, |
358 | BS_FLOATS_ON_WATER = 1 << 11, | 238 | BS_FLOATS_ON_WATER = 1 << 11, |
239 | BS_VEHICLE_COLLISIONS = 1 << 12, | ||
359 | BS_NONE = 0, | 240 | BS_NONE = 0, |
360 | BS_ALL = 0xFFFFFFFF, | 241 | BS_ALL = 0xFFFFFFFF |
361 | |||
362 | // These are the collision flags switched depending on physical state. | ||
363 | // The other flags are used for other things and should not be fooled with. | ||
364 | BS_ACTIVE = CF_STATIC_OBJECT | ||
365 | | CF_KINEMATIC_OBJECT | ||
366 | | CF_NO_CONTACT_RESPONSE | ||
367 | }; | 242 | }; |
368 | 243 | ||
369 | // Values for collisions groups and masks | 244 | // Values f collisions groups and masks |
370 | public enum CollisionFilterGroups : uint | 245 | public enum CollisionFilterGroups : uint |
371 | { | 246 | { |
372 | // Don't use the bit definitions!! Define the use in a | 247 | // Don't use the bit definitions!! Define the use in a |
373 | // filter/mask definition below. This way collision interactions | 248 | // filter/mask definition below. This way collision interactions |
374 | // are more easily debugged. | 249 | // are more easily found and debugged. |
375 | BNoneFilter = 0, | 250 | BNoneGroup = 0, |
376 | BDefaultFilter = 1 << 0, | 251 | BDefaultGroup = 1 << 0, |
377 | BStaticFilter = 1 << 1, | 252 | BStaticGroup = 1 << 1, |
378 | BKinematicFilter = 1 << 2, | 253 | BKinematicGroup = 1 << 2, |
379 | BDebrisFilter = 1 << 3, | 254 | BDebrisGroup = 1 << 3, |
380 | BSensorTrigger = 1 << 4, | 255 | BSensorTrigger = 1 << 4, |
381 | BCharacterFilter = 1 << 5, | 256 | BCharacterGroup = 1 << 5, |
382 | BAllFilter = 0xFFFFFFFF, | 257 | BAllGroup = 0xFFFFFFFF, |
383 | // Filter groups defined by BulletSim | 258 | // Filter groups defined by BulletSim |
384 | BGroundPlaneFilter = 1 << 10, | 259 | BGroundPlaneGroup = 1 << 10, |
385 | BTerrainFilter = 1 << 11, | 260 | BTerrainGroup = 1 << 11, |
386 | BRaycastFilter = 1 << 12, | 261 | BRaycastGroup = 1 << 12, |
387 | BSolidFilter = 1 << 13, | 262 | BSolidGroup = 1 << 13, |
388 | BLinksetFilter = 1 << 14, | 263 | // BLinksetGroup = xx // a linkset proper is either static or dynamic |
389 | 264 | BLinksetChildGroup = 1 << 14, | |
390 | // The collsion filters and masked are defined in one place -- don't want them scattered | ||
391 | AvatarFilter = BCharacterFilter, | ||
392 | AvatarMask = BAllFilter, | ||
393 | ObjectFilter = BSolidFilter, | ||
394 | ObjectMask = BAllFilter, | ||
395 | StaticObjectFilter = BStaticFilter, | ||
396 | StaticObjectMask = BAllFilter & ~BStaticFilter, // static objects don't collide with each other | ||
397 | LinksetFilter = BLinksetFilter, | ||
398 | LinksetMask = BAllFilter & ~BLinksetFilter, // linkset objects don't collide with each other | ||
399 | VolumeDetectFilter = BSensorTrigger, | ||
400 | VolumeDetectMask = ~BSensorTrigger, | ||
401 | TerrainFilter = BTerrainFilter, | ||
402 | TerrainMask = BAllFilter & ~BStaticFilter, // static objects on the ground don't collide | ||
403 | GroundPlaneFilter = BGroundPlaneFilter, | ||
404 | GroundPlaneMask = BAllFilter | ||
405 | |||
406 | }; | 265 | }; |
407 | 266 | ||
408 | // CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0 | 267 | // CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0 |
@@ -429,7 +288,7 @@ public enum ConstraintParamAxis : int | |||
429 | 288 | ||
430 | // =============================================================================== | 289 | // =============================================================================== |
431 | static class BulletSimAPI { | 290 | static class BulletSimAPI { |
432 | 291 | // =============================================================================== | |
433 | // Link back to the managed code for outputting log messages | 292 | // Link back to the managed code for outputting log messages |
434 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] | 293 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] |
435 | public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg); | 294 | public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg); |
@@ -482,6 +341,9 @@ public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData) | |||
482 | public static extern bool IsNativeShape2(IntPtr shape); | 341 | public static extern bool IsNativeShape2(IntPtr shape); |
483 | 342 | ||
484 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 343 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
344 | public static extern void SetShapeCollisionMargin(IntPtr shape, float margin); | ||
345 | |||
346 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
485 | public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale); | 347 | public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale); |
486 | 348 | ||
487 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 349 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
@@ -938,7 +800,7 @@ public static extern IntPtr GetConstraintRef2(IntPtr obj, int index); | |||
938 | public static extern int GetNumConstraintRefs2(IntPtr obj); | 800 | public static extern int GetNumConstraintRefs2(IntPtr obj); |
939 | 801 | ||
940 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 802 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
941 | public static extern void SetCollisionFilterMask2(IntPtr body, uint filter, uint mask); | 803 | public static extern bool SetCollisionGroupMask2(IntPtr body, uint filter, uint mask); |
942 | 804 | ||
943 | // ===================================================================================== | 805 | // ===================================================================================== |
944 | // btCollisionShape entries | 806 | // btCollisionShape entries |
@@ -1000,13 +862,16 @@ public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject); | |||
1000 | public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape); | 862 | public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape); |
1001 | 863 | ||
1002 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 864 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
865 | public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo); | ||
866 | |||
867 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1003 | public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain); | 868 | public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain); |
1004 | 869 | ||
1005 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 870 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1006 | public static extern void DumpAllInfo2(IntPtr sim); | 871 | public static extern void DumpActivationInfo2(IntPtr sim); |
1007 | 872 | ||
1008 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 873 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1009 | public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo); | 874 | public static extern void DumpAllInfo2(IntPtr sim); |
1010 | 875 | ||
1011 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 876 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1012 | public static extern void DumpPhysicsStatistics2(IntPtr sim); | 877 | public static extern void DumpPhysicsStatistics2(IntPtr sim); |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs new file mode 100755 index 0000000..662177f --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs | |||
@@ -0,0 +1,278 @@ | |||
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.Text; | ||
30 | using OMV = OpenMetaverse; | ||
31 | |||
32 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
33 | { | ||
34 | // Classes to allow some type checking for the API | ||
35 | // These hold pointers to allocated objects in the unmanaged space. | ||
36 | |||
37 | // The physics engine controller class created at initialization | ||
38 | public struct BulletSim | ||
39 | { | ||
40 | public BulletSim(uint worldId, BSScene bss, IntPtr xx) | ||
41 | { | ||
42 | ptr = xx; | ||
43 | worldID = worldId; | ||
44 | physicsScene = bss; | ||
45 | } | ||
46 | public IntPtr ptr; | ||
47 | public uint worldID; | ||
48 | // The scene is only in here so very low level routines have a handle to print debug/error messages | ||
49 | public BSScene physicsScene; | ||
50 | } | ||
51 | |||
52 | // An allocated Bullet btRigidBody | ||
53 | public struct BulletBody | ||
54 | { | ||
55 | public BulletBody(uint id) : this(id, IntPtr.Zero) | ||
56 | { | ||
57 | } | ||
58 | public BulletBody(uint id, IntPtr xx) | ||
59 | { | ||
60 | ID = id; | ||
61 | ptr = xx; | ||
62 | collisionType = CollisionType.Static; | ||
63 | } | ||
64 | public IntPtr ptr; | ||
65 | public uint ID; | ||
66 | public CollisionType collisionType; | ||
67 | |||
68 | public void Clear() | ||
69 | { | ||
70 | ptr = IntPtr.Zero; | ||
71 | } | ||
72 | public bool HasPhysicalBody { get { return ptr != IntPtr.Zero; } } | ||
73 | |||
74 | // Apply the specificed collision mask into the physical world | ||
75 | public void ApplyCollisionMask() | ||
76 | { | ||
77 | // Should assert the body has been added to the physical world. | ||
78 | // (The collision masks are stored in the collision proxy cache which only exists for | ||
79 | // a collision body that is in the world.) | ||
80 | BulletSimAPI.SetCollisionGroupMask2(ptr, | ||
81 | BulletSimData.CollisionTypeMasks[collisionType].group, | ||
82 | BulletSimData.CollisionTypeMasks[collisionType].mask); | ||
83 | } | ||
84 | |||
85 | public override string ToString() | ||
86 | { | ||
87 | StringBuilder buff = new StringBuilder(); | ||
88 | buff.Append("<id="); | ||
89 | buff.Append(ID.ToString()); | ||
90 | buff.Append(",p="); | ||
91 | buff.Append(ptr.ToString("X")); | ||
92 | buff.Append(",c="); | ||
93 | buff.Append(collisionType); | ||
94 | buff.Append(">"); | ||
95 | return buff.ToString(); | ||
96 | } | ||
97 | } | ||
98 | |||
99 | public struct BulletShape | ||
100 | { | ||
101 | public BulletShape(IntPtr xx) : this(xx, BSPhysicsShapeType.SHAPE_UNKNOWN) | ||
102 | { | ||
103 | } | ||
104 | public BulletShape(IntPtr xx, BSPhysicsShapeType typ) | ||
105 | { | ||
106 | ptr = xx; | ||
107 | type = typ; | ||
108 | shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE; | ||
109 | isNativeShape = false; | ||
110 | } | ||
111 | public IntPtr ptr; | ||
112 | public BSPhysicsShapeType type; | ||
113 | public System.UInt64 shapeKey; | ||
114 | public bool isNativeShape; | ||
115 | |||
116 | public void Clear() | ||
117 | { | ||
118 | ptr = IntPtr.Zero; | ||
119 | } | ||
120 | public bool HasPhysicalShape { get { return ptr != IntPtr.Zero; } } | ||
121 | |||
122 | public override string ToString() | ||
123 | { | ||
124 | StringBuilder buff = new StringBuilder(); | ||
125 | buff.Append("<p="); | ||
126 | buff.Append(ptr.ToString("X")); | ||
127 | buff.Append(",s="); | ||
128 | buff.Append(type.ToString()); | ||
129 | buff.Append(",k="); | ||
130 | buff.Append(shapeKey.ToString("X")); | ||
131 | buff.Append(",n="); | ||
132 | buff.Append(isNativeShape.ToString()); | ||
133 | buff.Append(">"); | ||
134 | return buff.ToString(); | ||
135 | } | ||
136 | } | ||
137 | |||
138 | // An allocated Bullet btConstraint | ||
139 | public struct BulletConstraint | ||
140 | { | ||
141 | public BulletConstraint(IntPtr xx) | ||
142 | { | ||
143 | ptr = xx; | ||
144 | } | ||
145 | public IntPtr ptr; | ||
146 | |||
147 | public void Clear() | ||
148 | { | ||
149 | ptr = IntPtr.Zero; | ||
150 | } | ||
151 | public bool HasPhysicalConstraint { get { return ptr != IntPtr.Zero; } } | ||
152 | } | ||
153 | |||
154 | // An allocated HeightMapThing which holds various heightmap info. | ||
155 | // Made a class rather than a struct so there would be only one | ||
156 | // instance of this and C# will pass around pointers rather | ||
157 | // than making copies. | ||
158 | public class BulletHeightMapInfo | ||
159 | { | ||
160 | public BulletHeightMapInfo(uint id, float[] hm, IntPtr xx) { | ||
161 | ID = id; | ||
162 | Ptr = xx; | ||
163 | heightMap = hm; | ||
164 | terrainRegionBase = OMV.Vector3.Zero; | ||
165 | minCoords = new OMV.Vector3(100f, 100f, 25f); | ||
166 | maxCoords = new OMV.Vector3(101f, 101f, 26f); | ||
167 | minZ = maxZ = 0f; | ||
168 | sizeX = sizeY = 256f; | ||
169 | } | ||
170 | public uint ID; | ||
171 | public IntPtr Ptr; | ||
172 | public float[] heightMap; | ||
173 | public OMV.Vector3 terrainRegionBase; | ||
174 | public OMV.Vector3 minCoords; | ||
175 | public OMV.Vector3 maxCoords; | ||
176 | public float sizeX, sizeY; | ||
177 | public float minZ, maxZ; | ||
178 | public BulletShape terrainShape; | ||
179 | public BulletBody terrainBody; | ||
180 | } | ||
181 | |||
182 | // The general class of collsion object. | ||
183 | public enum CollisionType | ||
184 | { | ||
185 | Avatar, | ||
186 | Groundplane, | ||
187 | Terrain, | ||
188 | Static, | ||
189 | Dynamic, | ||
190 | VolumeDetect, | ||
191 | // Linkset, // A linkset should be either Static or Dynamic | ||
192 | LinksetChild, | ||
193 | Unknown | ||
194 | }; | ||
195 | |||
196 | // Hold specification of group and mask collision flags for a CollisionType | ||
197 | public struct CollisionTypeFilterGroup | ||
198 | { | ||
199 | public CollisionTypeFilterGroup(CollisionType t, uint g, uint m) | ||
200 | { | ||
201 | type = t; | ||
202 | group = g; | ||
203 | mask = m; | ||
204 | } | ||
205 | public CollisionType type; | ||
206 | public uint group; | ||
207 | public uint mask; | ||
208 | }; | ||
209 | |||
210 | /* NOTE: old definitions kept for reference. Delete when things are working. | ||
211 | // The collsion filters and masked are defined in one place -- don't want them scattered | ||
212 | AvatarGroup = BCharacterGroup, | ||
213 | AvatarMask = BAllGroup, | ||
214 | ObjectGroup = BSolidGroup, | ||
215 | ObjectMask = BAllGroup, | ||
216 | StaticObjectGroup = BStaticGroup, | ||
217 | StaticObjectMask = AvatarGroup | ObjectGroup, // static things don't interact with much | ||
218 | LinksetGroup = BLinksetGroup, | ||
219 | LinksetMask = BAllGroup, | ||
220 | LinksetChildGroup = BLinksetChildGroup, | ||
221 | LinksetChildMask = BNoneGroup, // Linkset children disappear from the world | ||
222 | VolumeDetectGroup = BSensorTrigger, | ||
223 | VolumeDetectMask = ~BSensorTrigger, | ||
224 | TerrainGroup = BTerrainGroup, | ||
225 | TerrainMask = BAllGroup & ~BStaticGroup, // static objects on the ground don't collide | ||
226 | GroundPlaneGroup = BGroundPlaneGroup, | ||
227 | GroundPlaneMask = BAllGroup | ||
228 | */ | ||
229 | |||
230 | public static class BulletSimData | ||
231 | { | ||
232 | |||
233 | // Map of collisionTypes to flags for collision groups and masks. | ||
234 | // As mentioned above, don't use the CollisionFilterGroups definitions directly in the code | ||
235 | // but, instead, use references to this dictionary. Finding and debugging | ||
236 | // collision flag problems will be made easier. | ||
237 | public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks | ||
238 | = new Dictionary<CollisionType, CollisionTypeFilterGroup>() | ||
239 | { | ||
240 | { CollisionType.Avatar, | ||
241 | new CollisionTypeFilterGroup(CollisionType.Avatar, | ||
242 | (uint)CollisionFilterGroups.BCharacterGroup, | ||
243 | (uint)CollisionFilterGroups.BAllGroup) | ||
244 | }, | ||
245 | { CollisionType.Groundplane, | ||
246 | new CollisionTypeFilterGroup(CollisionType.Groundplane, | ||
247 | (uint)CollisionFilterGroups.BGroundPlaneGroup, | ||
248 | (uint)CollisionFilterGroups.BAllGroup) | ||
249 | }, | ||
250 | { CollisionType.Terrain, | ||
251 | new CollisionTypeFilterGroup(CollisionType.Terrain, | ||
252 | (uint)CollisionFilterGroups.BTerrainGroup, | ||
253 | (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup)) | ||
254 | }, | ||
255 | { CollisionType.Static, | ||
256 | new CollisionTypeFilterGroup(CollisionType.Static, | ||
257 | (uint)CollisionFilterGroups.BStaticGroup, | ||
258 | (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) | ||
259 | }, | ||
260 | { CollisionType.Dynamic, | ||
261 | new CollisionTypeFilterGroup(CollisionType.Dynamic, | ||
262 | (uint)CollisionFilterGroups.BSolidGroup, | ||
263 | (uint)(CollisionFilterGroups.BAllGroup)) | ||
264 | }, | ||
265 | { CollisionType.VolumeDetect, | ||
266 | new CollisionTypeFilterGroup(CollisionType.VolumeDetect, | ||
267 | (uint)CollisionFilterGroups.BSensorTrigger, | ||
268 | (uint)(~CollisionFilterGroups.BSensorTrigger)) | ||
269 | }, | ||
270 | { CollisionType.LinksetChild, | ||
271 | new CollisionTypeFilterGroup(CollisionType.LinksetChild, | ||
272 | (uint)CollisionFilterGroups.BTerrainGroup, | ||
273 | (uint)(CollisionFilterGroups.BNoneGroup)) | ||
274 | }, | ||
275 | }; | ||
276 | |||
277 | } | ||
278 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt new file mode 100755 index 0000000..0d9a156 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt | |||
@@ -0,0 +1,204 @@ | |||
1 | CURRENT PRIORITIES | ||
2 | ================================================= | ||
3 | Eliminate all crashes (DONEish) | ||
4 | Editing/deleting physical linkset (DONE) | ||
5 | Border crossing of physical linkset (DONE) | ||
6 | Enable vehicle border crossings (at least as poorly as ODE) | ||
7 | Avatar created in previous region and not new region when crossing border | ||
8 | Vehicle recreated in new sim at small Z value (offset from root value?) (DONE) | ||
9 | Calibrate turning radius | ||
10 | limitMotorUp calibration (more down?) | ||
11 | study PID motors (include 'efficiency' implementation | ||
12 | Add to avatar movement | ||
13 | |||
14 | CRASHES | ||
15 | ================================================= | ||
16 | 20121129.1411: editting/moving phys object across region boundries causes crash | ||
17 | getPos-> btRigidBody::upcast -> getBodyType -> BOOM | ||
18 | 20121128.1600: mesh object not rezzing (no physics mesh). | ||
19 | Causes many errors. Doesn't stop after first error with box shape. | ||
20 | Eventually crashes when deleting the object. | ||
21 | 20121206.1434: rez Sam-pan into OSGrid BulletSim11 region | ||
22 | Immediate simulator crash. Mono does not output any stacktrace and | ||
23 | log just stops after reporting taint-time linking of the linkset. | ||
24 | |||
25 | VEHICLES TODO LIST: | ||
26 | ================================================= | ||
27 | Border crossing with linked vehicle causes crash | ||
28 | Neb vehicle taking > 25ms of physics time!! | ||
29 | Vehicles (Move smoothly) | ||
30 | Add vehicle collisions so IsColliding is properly reported. | ||
31 | Needed for banking, limitMotorUp, movementLimiting, ... | ||
32 | Some vehicles should not be able to turn if no speed or off ground. | ||
33 | Cannot edit/move a vehicle being ridden: it jumps back to the origional position. | ||
34 | Neb car jiggling left and right | ||
35 | Happens on terrain and any other mesh object. Flat cubes are much smoother. | ||
36 | This has been reduced but not eliminated. | ||
37 | Light cycle falling over when driving | ||
38 | Implement referenceFrame for all the motion routines. | ||
39 | Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE. | ||
40 | Verify that angular motion specified around Z moves in the vehicle coordinates. | ||
41 | Verify llGetVel() is returning a smooth and good value for vehicle movement. | ||
42 | llGetVel() should return the root's velocity if requested in a child prim. | ||
43 | Implement function efficiency for lineaar and angular motion. | ||
44 | Should vehicle angular/linear movement friction happen after all the components | ||
45 | or does it only apply to the basic movement? | ||
46 | After getting off a vehicle, the root prim is phantom (can be walked through) | ||
47 | Need to force a position update for the root prim after compound shape destruction | ||
48 | Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint) | ||
49 | For limitMotorUp, use raycast down to find if vehicle is in the air. | ||
50 | Remove vehicle angular velocity zeroing in BSPrim.UpdateProperties(). | ||
51 | A kludge that isn't fixing the real problem of Bullet adding extra motion. | ||
52 | |||
53 | BULLETSIM TODO LIST: | ||
54 | ================================================= | ||
55 | Revisit CollisionMargin. Builders notice the 0.04 spacing between prims. | ||
56 | Avatar height off after unsitting (floats off ground) | ||
57 | Editting appearance then moving restores. | ||
58 | Must not be initializing height when recreating capsule after unsit. | ||
59 | Duplicating a physical prim causes old prim to jump away | ||
60 | Dup a phys prim and the original become unselected and thus interacts w/ selected prim. | ||
61 | Scenes with hundred of thousands of static objects take a lot of physics CPU time. | ||
62 | BSPrim.Force should set a continious force on the prim. The force should be | ||
63 | applied each tick. Some limits? | ||
64 | Gun sending shooter flying. | ||
65 | Collision margin (gap between physical objects lying on each other) | ||
66 | Boundry checking (crashes related to crossing boundry) | ||
67 | Add check for border edge position for avatars and objects. | ||
68 | Verify the events are created for border crossings. | ||
69 | Avatar rotation (check out changes to ScenePresence for physical rotation) | ||
70 | Avatar running (what does phys engine need to do?) | ||
71 | Small physical objects do not interact correctly | ||
72 | Create chain of .5x.5x.1 torui and make all but top physical so to hang. | ||
73 | The chain will fall apart and pairs will dance around on ground | ||
74 | Chains of 1x1x.2 will stay connected but will dance. | ||
75 | Chains above 2x2x.4 are move stable and get stablier as torui get larger. | ||
76 | Add PID motor for avatar movement (slow to stop, ...) | ||
77 | setForce should set a constant force. Different than AddImpulse. | ||
78 | Implement raycast. | ||
79 | Implement ShapeCollection.Dispose() | ||
80 | Implement water as a plain so raycasting and collisions can happen with same. | ||
81 | Add osGetPhysicsEngineName() so scripters can tell whether BulletSim or ODE | ||
82 | Also osGetPhysicsEngineVerion() maybe. | ||
83 | Linkset.Position and Linkset.Orientation requre rewrite to properly return | ||
84 | child position. LinksetConstraint acts like it's at taint time!! | ||
85 | |||
86 | LINKSETS | ||
87 | ====================================================== | ||
88 | Linksets should allow collisions to individual children | ||
89 | Add LocalID to children shapes in LinksetCompound and create events for individuals | ||
90 | LinksetCompound: when one of the children changes orientation (like tires | ||
91 | turning on a vehicle, the whole compound object is rebuilt. Optimize this | ||
92 | so orientation/position of individual children can change without a rebuild. | ||
93 | Verify/think through scripts in children of linksets. What do they reference | ||
94 | and return when getting position, velocity, ... | ||
95 | Confirm constraint linksets still work after making all the changes for compound linksets. | ||
96 | Add 'changed' flag or similar to reduce the number of times a linkset is rebuilt. | ||
97 | For compound linksets, add ability to remove or reposition individual child shapes. | ||
98 | Disable activity of passive linkset children. | ||
99 | Since the linkset is a compound object, the old prims are left lying | ||
100 | around and need to be phantomized so they don't collide, ... | ||
101 | Speed up creation of large physical linksets | ||
102 | For instance, sitting in Neb's car (130 prims) takes several seconds to become physical | ||
103 | Eliminate collisions between objects in a linkset. (LinksetConstraint) | ||
104 | Have UserPointer point to struct with localID and linksetID? | ||
105 | Objects in original linkset still collide with each other? | ||
106 | |||
107 | MORE | ||
108 | ====================================================== | ||
109 | Find/remove avatar collision with ID=0. | ||
110 | Test avatar walking up stairs. How does compare with SL. | ||
111 | Radius of the capsule affects ability to climb edges. | ||
112 | Tune terrain/object friction to be closer to SL. | ||
113 | Debounce avatar contact so legs don't keep folding up when standing. | ||
114 | Implement LSL physics controls. Like STATUS_ROTATE_X. | ||
115 | Add border extensions to terrain to help region crossings and objects leaving region. | ||
116 | |||
117 | Performance test with lots of avatars. Can BulletSim support a thousand? | ||
118 | Optimize collisions in C++: only send up to the object subscribed to collisions. | ||
119 | Use collision subscription and remove the collsion(A,B) and collision(B,A) | ||
120 | Check whether SimMotionState needs large if statement (see TODO). | ||
121 | |||
122 | Implement 'top colliders' info. | ||
123 | Avatar jump | ||
124 | Performance measurement and changes to make quicker. | ||
125 | Implement detailed physics stats (GetStats()). | ||
126 | |||
127 | Measure performance improvement from hulls | ||
128 | Test not using ghost objects for volume detect implementation. | ||
129 | Performance of closures and delegates for taint processing | ||
130 | Are there faster ways? | ||
131 | Is any slowdown introduced by the existing implementation significant? | ||
132 | Is there are more efficient method of implementing pre and post step actions? | ||
133 | See http://www.codeproject.com/Articles/29922/Weak-Events-in-C | ||
134 | |||
135 | Physics Arena central pyramid: why is one side permiable? | ||
136 | |||
137 | INTERNAL IMPROVEMENT/CLEANUP | ||
138 | ================================================= | ||
139 | Consider moving prim/character body and shape destruction in destroy() | ||
140 | to postTimeTime rather than protecting all the potential sets that | ||
141 | might have been queued up. | ||
142 | Remove unused fields from ShapeData (not used in API2) | ||
143 | Breakout code for mesh/hull/compound/native into separate BSShape* classes | ||
144 | Standardize access to building and reference code. | ||
145 | The skeleton classes are in the sources but are not complete or linked in. | ||
146 | Make BSBody and BSShape real classes to centralize creation/changin/destruction | ||
147 | Convert state and parameter calls from BulletSimAPI direct calls to | ||
148 | calls on BSBody and BSShape | ||
149 | Generalize Dynamics and PID with standardized motors. | ||
150 | Generalize Linkset and vehicles into PropertyManagers | ||
151 | Methods for Refresh, RemoveBodyDependencies, RestoreBodyDependencies | ||
152 | Potentially add events for shape destruction, etc. | ||
153 | Complete implemention of preStepActions | ||
154 | Replace vehicle step call with prestep event. | ||
155 | Is there a need for postStepActions? postStepTaints? | ||
156 | Implement linkset by setting position of children when root updated. (LinksetManual) | ||
157 | Linkset implementation using manual prim movement. | ||
158 | LinkablePrim class? Would that simplify/centralize the linkset logic? | ||
159 | BSScene.UpdateParameterSet() is broken. How to set params on objects? | ||
160 | Remove HeightmapInfo from terrain specification | ||
161 | Since C++ code does not need terrain height, this structure et al are not needed. | ||
162 | Add floating motor for BS_FLOATS_ON_WATER so prim and avatar will | ||
163 | bob at the water level. BSPrim.PositionSanityCheck(). | ||
164 | Should taints check for existance or activeness of target? | ||
165 | When destroying linksets/etc, taints can be generated for objects that are | ||
166 | actually gone when the taint happens. Crashes don't happen because the taint closure | ||
167 | keeps the object from being freed, but that is just an accident. | ||
168 | Possibly have and 'active' flag that is checked by the taint processor? | ||
169 | |||
170 | THREADING | ||
171 | ================================================= | ||
172 | Do taint action immediately if not actually executing Bullet. | ||
173 | Add lock around Bullet execution and just do taint actions if simulation is not happening. | ||
174 | |||
175 | DONE DONE DONE DONE | ||
176 | ================================================= | ||
177 | Cleanup code in BSDynamics by using motors. (Resolution: started) | ||
178 | Consider implementing terrain with a mesh rather than heightmap. (Resolution: done) | ||
179 | Would have better and adjustable resolution. | ||
180 | Build terrain mesh so heighmap is height of the center of the square meter. | ||
181 | Resolution: NOT DONE: SL and ODE define meter square as being at one corner with one diagional. | ||
182 | Terrain as mesh. (Resolution: done) | ||
183 | How are static linksets seen by the physics engine? | ||
184 | Resolution: they are not linked in physics. When moved, all the children are repositioned. | ||
185 | Convert BSCharacter to use all API2 (Resolution: done) | ||
186 | Avatar pushing difficult (too heavy?) | ||
187 | Use asset service passed to BulletSim to get sculptie bodies, etc. (Resolution: done) | ||
188 | Remove old code in DLL (all non-API2 stuff). (Resolution: done) | ||
189 | Measurements of mega-physical prim performance (with graph) (Resolution: done, email) | ||
190 | Debug Bullet internal stats output (why is timing all wrong?) | ||
191 | Resolution: Bullet stats logging only works with a single instance of Bullet (one region). | ||
192 | Implement meshes or just verify that they work. (Resolution: they do!) | ||
193 | Do prim hash codes work for sculpties and meshes? (Resolution: yes) | ||
194 | Linkset implementation using compound shapes. (Resolution: implemented LinksetCompound) | ||
195 | Compound shapes will need the LocalID in the shapes and collision | ||
196 | processing to get it from there. | ||
197 | Light cycle not banking (Resolution: It doesn't. Banking is roll adding yaw.) | ||
198 | Package Bullet source mods for Bullet internal stats output | ||
199 | (Resolution: move code into WorldData.h rather than relying on patches) | ||
200 | Single prim vehicles don't seem to properly vehiclize. | ||
201 | (Resolution: mass was not getting set properly for single prim linksets) | ||
202 | Add material type linkage and input all the material property definitions. | ||
203 | Skeleton classes and table are in the sources but are not filled or used. | ||
204 | (Resolution: | ||
diff --git a/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs index 8de70ef..ba24aa7 100644 --- a/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs | |||
@@ -2190,7 +2190,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
2190 | convex = false; | 2190 | convex = false; |
2191 | try | 2191 | try |
2192 | { | 2192 | { |
2193 | _mesh = _parent_scene.mesher.CreateMesh(m_primName, _pbs, _size, (int)LevelOfDetail.High, true,convex,false); | 2193 | _mesh = _parent_scene.mesher.CreateMesh(m_primName, _pbs, _size, (int)LevelOfDetail.High, true,false,convex,false); |
2194 | } | 2194 | } |
2195 | catch | 2195 | catch |
2196 | { | 2196 | { |
@@ -2557,7 +2557,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
2557 | 2557 | ||
2558 | try | 2558 | try |
2559 | { | 2559 | { |
2560 | mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, (int)LevelOfDetail.High, true, convex,false); | 2560 | mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, (int)LevelOfDetail.High, true, false,convex,false); |
2561 | } | 2561 | } |
2562 | catch | 2562 | catch |
2563 | { | 2563 | { |
diff --git a/OpenSim/Region/Physics/Manager/IMesher.cs b/OpenSim/Region/Physics/Manager/IMesher.cs index ecc2918..df980ab 100644 --- a/OpenSim/Region/Physics/Manager/IMesher.cs +++ b/OpenSim/Region/Physics/Manager/IMesher.cs | |||
@@ -37,7 +37,7 @@ namespace OpenSim.Region.Physics.Manager | |||
37 | { | 37 | { |
38 | IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod); | 38 | IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod); |
39 | IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical); | 39 | IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical); |
40 | IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex, bool forOde); | 40 | IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache, bool convex, bool forOde); |
41 | IMesh GetMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex); | 41 | IMesh GetMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex); |
42 | void ReleaseMesh(IMesh mesh); | 42 | void ReleaseMesh(IMesh mesh); |
43 | void ExpireReleaseMeshs(); | 43 | void ExpireReleaseMeshs(); |
diff --git a/OpenSim/Region/Physics/Manager/PhysicsActor.cs b/OpenSim/Region/Physics/Manager/PhysicsActor.cs index 9338130..e2789d6 100644 --- a/OpenSim/Region/Physics/Manager/PhysicsActor.cs +++ b/OpenSim/Region/Physics/Manager/PhysicsActor.cs | |||
@@ -349,17 +349,20 @@ namespace OpenSim.Region.Physics.Manager | |||
349 | } | 349 | } |
350 | 350 | ||
351 | /// <summary> | 351 | /// <summary> |
352 | /// Velocity of this actor. | 352 | /// The desired velocity of this actor. |
353 | /// </summary> | 353 | /// </summary> |
354 | /// <remarks> | 354 | /// <remarks> |
355 | /// Setting this provides a target velocity for physics scene updates. | 355 | /// Setting this provides a target velocity for physics scene updates. |
356 | /// Getting this returns the velocity calculated by physics scene updates, using factors such as target velocity, | 356 | /// Getting this returns the last set target. Fetch Velocity to get the current velocity. |
357 | /// time to accelerate and collisions. | ||
358 | /// </remarks> | 357 | /// </remarks> |
358 | protected Vector3 m_targetVelocity; | ||
359 | public virtual Vector3 TargetVelocity | 359 | public virtual Vector3 TargetVelocity |
360 | { | 360 | { |
361 | get { return Velocity; } | 361 | get { return m_targetVelocity; } |
362 | set { Velocity = value; } | 362 | set { |
363 | m_targetVelocity = value; | ||
364 | Velocity = m_targetVelocity; | ||
365 | } | ||
363 | } | 366 | } |
364 | 367 | ||
365 | public abstract Vector3 Velocity { get; set; } | 368 | public abstract Vector3 Velocity { get; set; } |
diff --git a/OpenSim/Region/Physics/Manager/ZeroMesher.cs b/OpenSim/Region/Physics/Manager/ZeroMesher.cs index 16846e6..80ecf66 100644 --- a/OpenSim/Region/Physics/Manager/ZeroMesher.cs +++ b/OpenSim/Region/Physics/Manager/ZeroMesher.cs | |||
@@ -64,16 +64,21 @@ namespace OpenSim.Region.Physics.Manager | |||
64 | { | 64 | { |
65 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) | 65 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) |
66 | { | 66 | { |
67 | return CreateMesh(primName, primShape, size, lod, false); | 67 | return CreateMesh(primName, primShape, size, lod, false, false); |
68 | } | 68 | } |
69 | 69 | ||
70 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex,bool forOde) | 70 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache, bool convex,bool forOde) |
71 | { | 71 | { |
72 | return CreateMesh(primName, primShape, size, lod, false); | 72 | return CreateMesh(primName, primShape, size, lod, false); |
73 | } | 73 | } |
74 | 74 | ||
75 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) | 75 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) |
76 | { | 76 | { |
77 | return CreateMesh(primName, primShape, size, lod, false, false); | ||
78 | } | ||
79 | |||
80 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache) | ||
81 | { | ||
77 | // Remove the reference to the encoded JPEG2000 data so it can be GCed | 82 | // Remove the reference to the encoded JPEG2000 data so it can be GCed |
78 | primShape.SculptData = OpenMetaverse.Utils.EmptyBytes; | 83 | primShape.SculptData = OpenMetaverse.Utils.EmptyBytes; |
79 | 84 | ||
diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs index f629c4d..d181b78 100644 --- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs | |||
@@ -321,6 +321,9 @@ namespace OpenSim.Region.Physics.Meshing | |||
321 | 321 | ||
322 | if (primShape.SculptData.Length <= 0) | 322 | if (primShape.SculptData.Length <= 0) |
323 | { | 323 | { |
324 | // XXX: At the moment we can not log here since ODEPrim, for instance, ends up triggering this | ||
325 | // method twice - once before it has loaded sculpt data from the asset service and once afterwards. | ||
326 | // The first time will always call with unloaded SculptData if this needs to be uploaded. | ||
324 | // m_log.ErrorFormat("[MESH]: asset data for {0} is zero length", primName); | 327 | // m_log.ErrorFormat("[MESH]: asset data for {0} is zero length", primName); |
325 | return false; | 328 | return false; |
326 | } | 329 | } |
@@ -699,16 +702,21 @@ namespace OpenSim.Region.Physics.Meshing | |||
699 | 702 | ||
700 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) | 703 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) |
701 | { | 704 | { |
702 | return CreateMesh(primName, primShape, size, lod, false); | 705 | return CreateMesh(primName, primShape, size, lod, false, true); |
703 | } | 706 | } |
704 | 707 | ||
705 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex, bool forOde) | 708 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache, bool convex, bool forOde) |
706 | { | 709 | { |
707 | return CreateMesh(primName, primShape, size, lod, false); | 710 | return CreateMesh(primName, primShape, size, lod, false); |
708 | } | 711 | } |
709 | 712 | ||
710 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) | 713 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) |
711 | { | 714 | { |
715 | return CreateMesh(primName, primShape, size, lod, isPhysical, true); | ||
716 | } | ||
717 | |||
718 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache) | ||
719 | { | ||
712 | #if SPAM | 720 | #if SPAM |
713 | m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName); | 721 | m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName); |
714 | #endif | 722 | #endif |
@@ -718,9 +726,12 @@ namespace OpenSim.Region.Physics.Meshing | |||
718 | 726 | ||
719 | // If this mesh has been created already, return it instead of creating another copy | 727 | // If this mesh has been created already, return it instead of creating another copy |
720 | // For large regions with 100k+ prims and hundreds of copies of each, this can save a GB or more of memory | 728 | // For large regions with 100k+ prims and hundreds of copies of each, this can save a GB or more of memory |
721 | key = primShape.GetMeshKey(size, lod); | 729 | if (shouldCache) |
722 | if (m_uniqueMeshes.TryGetValue(key, out mesh)) | 730 | { |
723 | return mesh; | 731 | key = primShape.GetMeshKey(size, lod); |
732 | if (m_uniqueMeshes.TryGetValue(key, out mesh)) | ||
733 | return mesh; | ||
734 | } | ||
724 | 735 | ||
725 | if (size.X < 0.01f) size.X = 0.01f; | 736 | if (size.X < 0.01f) size.X = 0.01f; |
726 | if (size.Y < 0.01f) size.Y = 0.01f; | 737 | if (size.Y < 0.01f) size.Y = 0.01f; |
@@ -743,7 +754,10 @@ namespace OpenSim.Region.Physics.Meshing | |||
743 | // trim the vertex and triangle lists to free up memory | 754 | // trim the vertex and triangle lists to free up memory |
744 | mesh.TrimExcess(); | 755 | mesh.TrimExcess(); |
745 | 756 | ||
746 | m_uniqueMeshes.Add(key, mesh); | 757 | if (shouldCache) |
758 | { | ||
759 | m_uniqueMeshes.Add(key, mesh); | ||
760 | } | ||
747 | } | 761 | } |
748 | 762 | ||
749 | return mesh; | 763 | return mesh; |
diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs index a59f63f..d09aa62 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs | |||
@@ -3367,6 +3367,11 @@ Console.WriteLine(" JointCreateFixed"); | |||
3367 | _pbs.SculptData = new byte[asset.Data.Length]; | 3367 | _pbs.SculptData = new byte[asset.Data.Length]; |
3368 | asset.Data.CopyTo(_pbs.SculptData, 0); | 3368 | asset.Data.CopyTo(_pbs.SculptData, 0); |
3369 | // m_assetFailed = false; | 3369 | // m_assetFailed = false; |
3370 | |||
3371 | // m_log.DebugFormat( | ||
3372 | // "[ODE PRIM]: Received mesh/sculpt data asset {0} with {1} bytes for {2} at {3} in {4}", | ||
3373 | // _pbs.SculptTexture, _pbs.SculptData.Length, Name, _position, _parent_scene.Name); | ||
3374 | |||
3370 | m_taintshape = true; | 3375 | m_taintshape = true; |
3371 | _parent_scene.AddPhysicsActorTaint(this); | 3376 | _parent_scene.AddPhysicsActorTaint(this); |
3372 | } | 3377 | } |
diff --git a/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs b/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs index cbc6b95..16404c6 100644 --- a/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs +++ b/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs | |||
@@ -32,13 +32,14 @@ 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 OpenSim.Region.Physics.OdePlugin; |
35 | using OpenSim.Tests.Common; | ||
35 | using log4net; | 36 | using log4net; |
36 | using System.Reflection; | 37 | using System.Reflection; |
37 | 38 | ||
38 | namespace OpenSim.Region.Physics.OdePlugin.Tests | 39 | namespace OpenSim.Region.Physics.OdePlugin.Tests |
39 | { | 40 | { |
40 | [TestFixture] | 41 | [TestFixture] |
41 | public class ODETestClass | 42 | public class ODETestClass : OpenSimTestCase |
42 | { | 43 | { |
43 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 44 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
44 | 45 | ||
diff --git a/OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs b/OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs index 6e1a105..00cbfbd 100644 --- a/OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs | |||
@@ -1031,12 +1031,12 @@ namespace OpenSim.Region.Physics.Meshing | |||
1031 | 1031 | ||
1032 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) | 1032 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) |
1033 | { | 1033 | { |
1034 | return CreateMesh(primName, primShape, size, lod, false,false,false); | 1034 | return CreateMesh(primName, primShape, size, lod, false,false,false,false); |
1035 | } | 1035 | } |
1036 | 1036 | ||
1037 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) | 1037 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) |
1038 | { | 1038 | { |
1039 | return CreateMesh(primName, primShape, size, lod, false,false,false); | 1039 | return CreateMesh(primName, primShape, size, lod, false,false,false,false); |
1040 | } | 1040 | } |
1041 | 1041 | ||
1042 | public IMesh GetMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex) | 1042 | public IMesh GetMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex) |
@@ -1080,7 +1080,7 @@ namespace OpenSim.Region.Physics.Meshing | |||
1080 | 1080 | ||
1081 | private static Vector3 m_MeshUnitSize = new Vector3(1.0f, 1.0f, 1.0f); | 1081 | private static Vector3 m_MeshUnitSize = new Vector3(1.0f, 1.0f, 1.0f); |
1082 | 1082 | ||
1083 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex, bool forOde) | 1083 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache, bool convex, bool forOde) |
1084 | { | 1084 | { |
1085 | #if SPAM | 1085 | #if SPAM |
1086 | m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName); | 1086 | m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName); |
diff --git a/OpenSim/Region/Physics/UbitOdePlugin/ODEMeshWorker.cs b/OpenSim/Region/Physics/UbitOdePlugin/ODEMeshWorker.cs index 5030cec..0df71eb 100644 --- a/OpenSim/Region/Physics/UbitOdePlugin/ODEMeshWorker.cs +++ b/OpenSim/Region/Physics/UbitOdePlugin/ODEMeshWorker.cs | |||
@@ -448,7 +448,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
448 | else | 448 | else |
449 | { | 449 | { |
450 | repData.meshState = MeshState.needMesh; | 450 | repData.meshState = MeshState.needMesh; |
451 | mesh = m_mesher.CreateMesh(actor.Name, pbs, size, clod, true, convex, true); | 451 | mesh = m_mesher.CreateMesh(actor.Name, pbs, size, clod, true, false, convex, true); |
452 | if (mesh == null) | 452 | if (mesh == null) |
453 | { | 453 | { |
454 | repData.meshState = MeshState.MeshFailed; | 454 | repData.meshState = MeshState.MeshFailed; |
@@ -513,7 +513,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
513 | clod = (int)LevelOfDetail.Low; | 513 | clod = (int)LevelOfDetail.Low; |
514 | } | 514 | } |
515 | 515 | ||
516 | mesh = m_mesher.CreateMesh(actor.Name, pbs, size, clod, true, convex, true); | 516 | mesh = m_mesher.CreateMesh(actor.Name, pbs, size, clod, true, false, convex, true); |
517 | 517 | ||
518 | if (mesh == null) | 518 | if (mesh == null) |
519 | { | 519 | { |
@@ -929,4 +929,4 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
929 | repData.actor.Name); | 929 | repData.actor.Name); |
930 | } | 930 | } |
931 | } | 931 | } |
932 | } \ No newline at end of file | 932 | } |
diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs index b04f6b6..2f5b526 100644 --- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs | |||
@@ -59,6 +59,18 @@ namespace OpenSim.Region.ScriptEngine.Interfaces | |||
59 | public interface IScriptInstance | 59 | public interface IScriptInstance |
60 | { | 60 | { |
61 | /// <summary> | 61 | /// <summary> |
62 | /// Debug level for this script instance. | ||
63 | /// </summary> | ||
64 | /// <remarks> | ||
65 | /// Level == 0, no extra data is logged. | ||
66 | /// Level >= 1, state changes are logged. | ||
67 | /// Level >= 2, event firing is logged. | ||
68 | /// <value> | ||
69 | /// The debug level. | ||
70 | /// </value> | ||
71 | int DebugLevel { get; set; } | ||
72 | |||
73 | /// <summary> | ||
62 | /// Is the script currently running? | 74 | /// Is the script currently running? |
63 | /// </summary> | 75 | /// </summary> |
64 | bool Running { get; set; } | 76 | bool Running { get; set; } |
@@ -114,6 +126,16 @@ namespace OpenSim.Region.ScriptEngine.Interfaces | |||
114 | UUID AssetID { get; } | 126 | UUID AssetID { get; } |
115 | Queue EventQueue { get; } | 127 | Queue EventQueue { get; } |
116 | 128 | ||
129 | /// <summary> | ||
130 | /// Number of events queued for processing. | ||
131 | /// </summary> | ||
132 | long EventsQueued { get; } | ||
133 | |||
134 | /// <summary> | ||
135 | /// Number of events processed by this script instance. | ||
136 | /// </summary> | ||
137 | long EventsProcessed { get; } | ||
138 | |||
117 | void ClearQueue(); | 139 | void ClearQueue(); |
118 | int StartParam { get; set; } | 140 | int StartParam { get; set; } |
119 | 141 | ||
@@ -125,7 +147,13 @@ namespace OpenSim.Region.ScriptEngine.Interfaces | |||
125 | /// <summary> | 147 | /// <summary> |
126 | /// Stop the script instance. | 148 | /// Stop the script instance. |
127 | /// </summary> | 149 | /// </summary> |
150 | /// <remarks> | ||
151 | /// This must not be called by a thread that is in the process of handling an event for this script. Otherwise | ||
152 | /// there is a danger that it will self-abort and not complete the reset. | ||
153 | /// </remarks> | ||
128 | /// <param name="timeout"></param> | 154 | /// <param name="timeout"></param> |
155 | /// How many milliseconds we will wait for an existing script event to finish before | ||
156 | /// forcibly aborting that event. | ||
129 | /// <returns>true if the script was successfully stopped, false otherwise</returns> | 157 | /// <returns>true if the script was successfully stopped, false otherwise</returns> |
130 | bool Stop(int timeout); | 158 | bool Stop(int timeout); |
131 | 159 | ||
@@ -147,8 +175,31 @@ namespace OpenSim.Region.ScriptEngine.Interfaces | |||
147 | object EventProcessor(); | 175 | object EventProcessor(); |
148 | 176 | ||
149 | int EventTime(); | 177 | int EventTime(); |
150 | void ResetScript(); | 178 | |
179 | /// <summary> | ||
180 | /// Reset the script. | ||
181 | /// </summary> | ||
182 | /// <remarks> | ||
183 | /// This must not be called by a thread that is in the process of handling an event for this script. Otherwise | ||
184 | /// there is a danger that it will self-abort and not complete the reset. Such a thread must call | ||
185 | /// ApiResetScript() instead. | ||
186 | /// </remarks> | ||
187 | /// <param name='timeout'> | ||
188 | /// How many milliseconds we will wait for an existing script event to finish before | ||
189 | /// forcibly aborting that event prior to script reset. | ||
190 | /// </param> | ||
191 | void ResetScript(int timeout); | ||
192 | |||
193 | /// <summary> | ||
194 | /// Reset the script. | ||
195 | /// </summary> | ||
196 | /// <remarks> | ||
197 | /// This must not be called by any thread other than the one executing the scripts current event. This is | ||
198 | /// because there is no wait or abort logic if another thread is in the middle of processing a script event. | ||
199 | /// Such an external thread should use ResetScript() instead. | ||
200 | /// </remarks> | ||
151 | void ApiResetScript(); | 201 | void ApiResetScript(); |
202 | |||
152 | Dictionary<string, object> GetVars(); | 203 | Dictionary<string, object> GetVars(); |
153 | void SetVars(Dictionary<string, object> vars); | 204 | void SetVars(Dictionary<string, object> vars); |
154 | DetectParams GetDetectParams(int idx); | 205 | DetectParams GetDetectParams(int idx); |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 7ff30ca..3a9d0ff 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | |||
@@ -7334,6 +7334,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
7334 | public void llCloseRemoteDataChannel(string channel) | 7334 | public void llCloseRemoteDataChannel(string channel) |
7335 | { | 7335 | { |
7336 | m_host.AddScriptLPS(1); | 7336 | m_host.AddScriptLPS(1); |
7337 | |||
7338 | IXmlRpcRouter xmlRpcRouter = m_ScriptEngine.World.RequestModuleInterface<IXmlRpcRouter>(); | ||
7339 | if (xmlRpcRouter != null) | ||
7340 | { | ||
7341 | xmlRpcRouter.UnRegisterReceiver(channel, m_item.ItemID); | ||
7342 | } | ||
7343 | |||
7337 | IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>(); | 7344 | IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>(); |
7338 | xmlrpcMod.CloseXMLRPCChannel((UUID)channel); | 7345 | xmlrpcMod.CloseXMLRPCChannel((UUID)channel); |
7339 | ScriptSleep(1000); | 7346 | ScriptSleep(1000); |
diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CSCodeGeneratorTest.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CSCodeGeneratorTest.cs index 7763619..77e087c 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CSCodeGeneratorTest.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CSCodeGeneratorTest.cs | |||
@@ -39,7 +39,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools.Tests | |||
39 | /// The generated C# code is compared against the expected C# code. | 39 | /// The generated C# code is compared against the expected C# code. |
40 | /// </summary> | 40 | /// </summary> |
41 | [TestFixture] | 41 | [TestFixture] |
42 | public class CSCodeGeneratorTest | 42 | public class CSCodeGeneratorTest : OpenSimTestCase |
43 | { | 43 | { |
44 | [Test] | 44 | [Test] |
45 | public void TestDefaultState() | 45 | public void TestDefaultState() |
diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CompilerTest.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CompilerTest.cs index 1fa6954..05a8756 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CompilerTest.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CompilerTest.cs | |||
@@ -41,7 +41,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools.Tests | |||
41 | /// the LSL source. | 41 | /// the LSL source. |
42 | /// </summary> | 42 | /// </summary> |
43 | [TestFixture] | 43 | [TestFixture] |
44 | public class CompilerTest | 44 | public class CompilerTest : OpenSimTestCase |
45 | { | 45 | { |
46 | private string m_testDir; | 46 | private string m_testDir; |
47 | private CSharpCodeProvider m_CSCodeProvider; | 47 | private CSharpCodeProvider m_CSCodeProvider; |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index 771db0c..ff4d130 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs | |||
@@ -94,6 +94,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
94 | private UUID m_CurrentStateHash; | 94 | private UUID m_CurrentStateHash; |
95 | private UUID m_RegionID; | 95 | private UUID m_RegionID; |
96 | 96 | ||
97 | public int DebugLevel { get; set; } | ||
98 | |||
97 | public Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> LineMap { get; set; } | 99 | public Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> LineMap { get; set; } |
98 | 100 | ||
99 | private Dictionary<string,IScriptApi> m_Apis = new Dictionary<string,IScriptApi>(); | 101 | private Dictionary<string,IScriptApi> m_Apis = new Dictionary<string,IScriptApi>(); |
@@ -174,6 +176,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
174 | 176 | ||
175 | public Queue EventQueue { get; private set; } | 177 | public Queue EventQueue { get; private set; } |
176 | 178 | ||
179 | public long EventsQueued | ||
180 | { | ||
181 | get | ||
182 | { | ||
183 | lock (EventQueue) | ||
184 | return EventQueue.Count; | ||
185 | } | ||
186 | } | ||
187 | |||
188 | public long EventsProcessed { get; private set; } | ||
189 | |||
177 | public int StartParam { get; set; } | 190 | public int StartParam { get; set; } |
178 | 191 | ||
179 | public TaskInventoryItem ScriptTask { get; private set; } | 192 | public TaskInventoryItem ScriptTask { get; private set; } |
@@ -538,9 +551,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
538 | // forcibly abort the work item (this aborts the underlying thread). | 551 | // forcibly abort the work item (this aborts the underlying thread). |
539 | if (!m_InSelfDelete) | 552 | if (!m_InSelfDelete) |
540 | { | 553 | { |
541 | // m_log.ErrorFormat( | 554 | m_log.DebugFormat( |
542 | // "[SCRIPT INSTANCE]: Aborting script {0} {1} in prim {2} {3} {4} {5}", | 555 | "[SCRIPT INSTANCE]: Aborting unstopped script {0} {1} in prim {2}, localID {3}, timeout was {4} ms", |
543 | // ScriptName, ItemID, PrimName, ObjectID, m_InSelfDelete, DateTime.Now.Ticks); | 556 | ScriptName, ItemID, PrimName, LocalID, timeout); |
544 | 557 | ||
545 | workItem.Abort(); | 558 | workItem.Abort(); |
546 | } | 559 | } |
@@ -696,19 +709,41 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
696 | { | 709 | { |
697 | 710 | ||
698 | // m_log.DebugFormat("[XEngine]: Processing event {0} for {1}", data.EventName, this); | 711 | // m_log.DebugFormat("[XEngine]: Processing event {0} for {1}", data.EventName, this); |
712 | SceneObjectPart part = Engine.World.GetSceneObjectPart(LocalID); | ||
713 | |||
714 | if (DebugLevel >= 2) | ||
715 | m_log.DebugFormat( | ||
716 | "[SCRIPT INSTANCE]: Processing event {0} for {1}/{2}({3})/{4}({5}) @ {6}/{7}", | ||
717 | data.EventName, | ||
718 | ScriptName, | ||
719 | part.Name, | ||
720 | part.LocalId, | ||
721 | part.ParentGroup.Name, | ||
722 | part.ParentGroup.UUID, | ||
723 | part.AbsolutePosition, | ||
724 | part.ParentGroup.Scene.Name); | ||
699 | 725 | ||
700 | m_DetectParams = data.DetectParams; | 726 | m_DetectParams = data.DetectParams; |
701 | 727 | ||
702 | if (data.EventName == "state") // Hardcoded state change | 728 | if (data.EventName == "state") // Hardcoded state change |
703 | { | 729 | { |
704 | // m_log.DebugFormat("[Script] Script {0}.{1} state set to {2}", | ||
705 | // PrimName, ScriptName, data.Params[0].ToString()); | ||
706 | State = data.Params[0].ToString(); | 730 | State = data.Params[0].ToString(); |
731 | |||
732 | if (DebugLevel >= 1) | ||
733 | m_log.DebugFormat( | ||
734 | "[SCRIPT INSTANCE]: Changing state to {0} for {1}/{2}({3})/{4}({5}) @ {6}/{7}", | ||
735 | State, | ||
736 | ScriptName, | ||
737 | part.Name, | ||
738 | part.LocalId, | ||
739 | part.ParentGroup.Name, | ||
740 | part.ParentGroup.UUID, | ||
741 | part.AbsolutePosition, | ||
742 | part.ParentGroup.Scene.Name); | ||
743 | |||
707 | AsyncCommandManager.RemoveScript(Engine, | 744 | AsyncCommandManager.RemoveScript(Engine, |
708 | LocalID, ItemID); | 745 | LocalID, ItemID); |
709 | 746 | ||
710 | SceneObjectPart part = Engine.World.GetSceneObjectPart( | ||
711 | LocalID); | ||
712 | if (part != null) | 747 | if (part != null) |
713 | { | 748 | { |
714 | part.SetScriptEvents(ItemID, | 749 | part.SetScriptEvents(ItemID, |
@@ -720,8 +755,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
720 | if (Engine.World.PipeEventsForScript(LocalID) || | 755 | if (Engine.World.PipeEventsForScript(LocalID) || |
721 | data.EventName == "control") // Don't freeze avies! | 756 | data.EventName == "control") // Don't freeze avies! |
722 | { | 757 | { |
723 | SceneObjectPart part = Engine.World.GetSceneObjectPart( | ||
724 | LocalID); | ||
725 | // m_log.DebugFormat("[Script] Delivered event {2} in state {3} to {0}.{1}", | 758 | // m_log.DebugFormat("[Script] Delivered event {2} in state {3} to {0}.{1}", |
726 | // PrimName, ScriptName, data.EventName, State); | 759 | // PrimName, ScriptName, data.EventName, State); |
727 | 760 | ||
@@ -776,6 +809,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
776 | ChatTypeEnum.DebugChannel, 2147483647, | 809 | ChatTypeEnum.DebugChannel, 2147483647, |
777 | part.AbsolutePosition, | 810 | part.AbsolutePosition, |
778 | part.Name, part.UUID, false); | 811 | part.Name, part.UUID, false); |
812 | |||
813 | |||
814 | m_log.DebugFormat( | ||
815 | "[SCRIPT INSTANCE]: Runtime error in script {0}, part {1} {2} at {3} in {4}, displayed error {5}, actual exception {6}", | ||
816 | ScriptName, | ||
817 | PrimName, | ||
818 | part.UUID, | ||
819 | part.AbsolutePosition, | ||
820 | part.ParentGroup.Scene.Name, | ||
821 | text.Replace("\n", "\\n"), | ||
822 | e.InnerException); | ||
779 | } | 823 | } |
780 | catch (Exception) | 824 | catch (Exception) |
781 | { | 825 | { |
@@ -810,6 +854,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
810 | // script engine to run the next event. | 854 | // script engine to run the next event. |
811 | lock (EventQueue) | 855 | lock (EventQueue) |
812 | { | 856 | { |
857 | EventsProcessed++; | ||
858 | |||
813 | if (EventQueue.Count > 0 && Running && !ShuttingDown) | 859 | if (EventQueue.Count > 0 && Running && !ShuttingDown) |
814 | { | 860 | { |
815 | m_CurrentWorkItem = Engine.QueueEventHandler(this); | 861 | m_CurrentWorkItem = Engine.QueueEventHandler(this); |
@@ -834,7 +880,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
834 | return (DateTime.Now - m_EventStart).Seconds; | 880 | return (DateTime.Now - m_EventStart).Seconds; |
835 | } | 881 | } |
836 | 882 | ||
837 | public void ResetScript() | 883 | public void ResetScript(int timeout) |
838 | { | 884 | { |
839 | if (m_Script == null) | 885 | if (m_Script == null) |
840 | return; | 886 | return; |
@@ -844,7 +890,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
844 | RemoveState(); | 890 | RemoveState(); |
845 | ReleaseControls(); | 891 | ReleaseControls(); |
846 | 892 | ||
847 | Stop(0); | 893 | Stop(timeout); |
848 | SceneObjectPart part = Engine.World.GetSceneObjectPart(LocalID); | 894 | SceneObjectPart part = Engine.World.GetSceneObjectPart(LocalID); |
849 | part.Inventory.GetInventoryItem(ItemID).PermsMask = 0; | 895 | part.Inventory.GetInventoryItem(ItemID).PermsMask = 0; |
850 | part.Inventory.GetInventoryItem(ItemID).PermsGranter = UUID.Zero; | 896 | part.Inventory.GetInventoryItem(ItemID).PermsGranter = UUID.Zero; |
@@ -1015,7 +1061,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
1015 | "({0}): {1}", scriptLine - 1, | 1061 | "({0}): {1}", scriptLine - 1, |
1016 | e.InnerException.Message); | 1062 | e.InnerException.Message); |
1017 | 1063 | ||
1018 | System.Console.WriteLine(e.ToString()+"\n"); | ||
1019 | return message; | 1064 | return message; |
1020 | } | 1065 | } |
1021 | } | 1066 | } |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs index c73e22f..cb7291a 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs | |||
@@ -51,14 +51,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests | |||
51 | /// Tests for inventory functions in LSL | 51 | /// Tests for inventory functions in LSL |
52 | /// </summary> | 52 | /// </summary> |
53 | [TestFixture] | 53 | [TestFixture] |
54 | public class LSL_ApiInventoryTests | 54 | public class LSL_ApiInventoryTests : OpenSimTestCase |
55 | { | 55 | { |
56 | protected Scene m_scene; | 56 | protected Scene m_scene; |
57 | protected XEngine.XEngine m_engine; | 57 | protected XEngine.XEngine m_engine; |
58 | 58 | ||
59 | [SetUp] | 59 | [SetUp] |
60 | public void SetUp() | 60 | public override void SetUp() |
61 | { | 61 | { |
62 | base.SetUp(); | ||
63 | |||
62 | IConfigSource initConfigSource = new IniConfigSource(); | 64 | IConfigSource initConfigSource = new IniConfigSource(); |
63 | IConfig config = initConfigSource.AddConfig("XEngine"); | 65 | IConfig config = initConfigSource.AddConfig("XEngine"); |
64 | config.Set("Enabled", "true"); | 66 | config.Set("Enabled", "true"); |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs index 2565ae7..d9b17d7 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs | |||
@@ -56,14 +56,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests | |||
56 | /// OpenSim.Region.Framework.Scenes.Tests.SceneObjectLinkingTests. | 56 | /// OpenSim.Region.Framework.Scenes.Tests.SceneObjectLinkingTests. |
57 | /// </remarks> | 57 | /// </remarks> |
58 | [TestFixture] | 58 | [TestFixture] |
59 | public class LSL_ApiLinkingTests | 59 | public class LSL_ApiLinkingTests : OpenSimTestCase |
60 | { | 60 | { |
61 | protected Scene m_scene; | 61 | protected Scene m_scene; |
62 | protected XEngine.XEngine m_engine; | 62 | protected XEngine.XEngine m_engine; |
63 | 63 | ||
64 | [SetUp] | 64 | [SetUp] |
65 | public void SetUp() | 65 | public override void SetUp() |
66 | { | 66 | { |
67 | base.SetUp(); | ||
68 | |||
67 | IConfigSource initConfigSource = new IniConfigSource(); | 69 | IConfigSource initConfigSource = new IniConfigSource(); |
68 | IConfig config = initConfigSource.AddConfig("XEngine"); | 70 | IConfig config = initConfigSource.AddConfig("XEngine"); |
69 | config.Set("Enabled", "true"); | 71 | config.Set("Enabled", "true"); |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs index dd23be8..98017d8 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs | |||
@@ -46,13 +46,15 @@ using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; | |||
46 | namespace OpenSim.Region.ScriptEngine.Shared.Tests | 46 | namespace OpenSim.Region.ScriptEngine.Shared.Tests |
47 | { | 47 | { |
48 | [TestFixture] | 48 | [TestFixture] |
49 | public class LSL_ApiListTests | 49 | public class LSL_ApiListTests : OpenSimTestCase |
50 | { | 50 | { |
51 | private LSL_Api m_lslApi; | 51 | private LSL_Api m_lslApi; |
52 | 52 | ||
53 | [SetUp] | 53 | [SetUp] |
54 | public void SetUp() | 54 | public override void SetUp() |
55 | { | 55 | { |
56 | base.SetUp(); | ||
57 | |||
56 | IConfigSource initConfigSource = new IniConfigSource(); | 58 | IConfigSource initConfigSource = new IniConfigSource(); |
57 | IConfig config = initConfigSource.AddConfig("XEngine"); | 59 | IConfig config = initConfigSource.AddConfig("XEngine"); |
58 | config.Set("Enabled", "true"); | 60 | config.Set("Enabled", "true"); |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLFloat.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLFloat.cs index 3ed2562..c8c7f82 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLFloat.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLFloat.cs | |||
@@ -33,7 +33,7 @@ using OpenSim.Region.ScriptEngine.Shared; | |||
33 | namespace OpenSim.Region.ScriptEngine.Shared.Tests | 33 | namespace OpenSim.Region.ScriptEngine.Shared.Tests |
34 | { | 34 | { |
35 | [TestFixture] | 35 | [TestFixture] |
36 | public class LSL_TypesTestLSLFloat | 36 | public class LSL_TypesTestLSLFloat : OpenSimTestCase |
37 | { | 37 | { |
38 | // Used for testing equality of two floats. | 38 | // Used for testing equality of two floats. |
39 | private double _lowPrecisionTolerance = 0.000001; | 39 | private double _lowPrecisionTolerance = 0.000001; |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLInteger.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLInteger.cs index 8d1169a..c664108 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLInteger.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLInteger.cs | |||
@@ -33,7 +33,7 @@ using OpenSim.Region.ScriptEngine.Shared; | |||
33 | namespace OpenSim.Region.ScriptEngine.Shared.Tests | 33 | namespace OpenSim.Region.ScriptEngine.Shared.Tests |
34 | { | 34 | { |
35 | [TestFixture] | 35 | [TestFixture] |
36 | public class LSL_TypesTestLSLInteger | 36 | public class LSL_TypesTestLSLInteger : OpenSimTestCase |
37 | { | 37 | { |
38 | private Dictionary<double, int> m_doubleIntSet; | 38 | private Dictionary<double, int> m_doubleIntSet; |
39 | private Dictionary<string, int> m_stringIntSet; | 39 | private Dictionary<string, int> m_stringIntSet; |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLString.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLString.cs index c4ca1a8..8550f2d 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLString.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLString.cs | |||
@@ -33,7 +33,7 @@ using OpenSim.Region.ScriptEngine.Shared; | |||
33 | namespace OpenSim.Region.ScriptEngine.Shared.Tests | 33 | namespace OpenSim.Region.ScriptEngine.Shared.Tests |
34 | { | 34 | { |
35 | [TestFixture] | 35 | [TestFixture] |
36 | public class LSL_TypesTestLSLString | 36 | public class LSL_TypesTestLSLString : OpenSimTestCase |
37 | { | 37 | { |
38 | private Dictionary<double, string> m_doubleStringSet; | 38 | private Dictionary<double, string> m_doubleStringSet; |
39 | 39 | ||
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestList.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestList.cs index b81225f..71b88bc 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestList.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestList.cs | |||
@@ -36,7 +36,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests | |||
36 | /// Tests the LSL_Types.list class. | 36 | /// Tests the LSL_Types.list class. |
37 | /// </summary> | 37 | /// </summary> |
38 | [TestFixture] | 38 | [TestFixture] |
39 | public class LSL_TypesTestList | 39 | public class LSL_TypesTestList : OpenSimTestCase |
40 | { | 40 | { |
41 | /// <summary> | 41 | /// <summary> |
42 | /// Tests concatenating a string to a list. | 42 | /// Tests concatenating a string to a list. |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestVector3.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestVector3.cs index ebf8001..0c838af 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestVector3.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestVector3.cs | |||
@@ -36,7 +36,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests | |||
36 | /// Tests for Vector3 | 36 | /// Tests for Vector3 |
37 | /// </summary> | 37 | /// </summary> |
38 | [TestFixture] | 38 | [TestFixture] |
39 | public class LSL_TypesTestVector3 | 39 | public class LSL_TypesTestVector3 : OpenSimTestCase |
40 | { | 40 | { |
41 | [Test] | 41 | [Test] |
42 | public void TestDotProduct() | 42 | public void TestDotProduct() |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs index c401794..1381d2b 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs | |||
@@ -51,14 +51,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests | |||
51 | /// Tests for OSSL_Api | 51 | /// Tests for OSSL_Api |
52 | /// </summary> | 52 | /// </summary> |
53 | [TestFixture] | 53 | [TestFixture] |
54 | public class OSSL_ApiAppearanceTest | 54 | public class OSSL_ApiAppearanceTest : OpenSimTestCase |
55 | { | 55 | { |
56 | protected Scene m_scene; | 56 | protected Scene m_scene; |
57 | protected XEngine.XEngine m_engine; | 57 | protected XEngine.XEngine m_engine; |
58 | 58 | ||
59 | [SetUp] | 59 | [SetUp] |
60 | public void SetUp() | 60 | public override void SetUp() |
61 | { | 61 | { |
62 | base.SetUp(); | ||
63 | |||
62 | IConfigSource initConfigSource = new IniConfigSource(); | 64 | IConfigSource initConfigSource = new IniConfigSource(); |
63 | IConfig config = initConfigSource.AddConfig("XEngine"); | 65 | IConfig config = initConfigSource.AddConfig("XEngine"); |
64 | config.Set("Enabled", "true"); | 66 | config.Set("Enabled", "true"); |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs index b49bcc2..d6c82f1 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs | |||
@@ -127,12 +127,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests | |||
127 | OSSL_Api osslApi = new OSSL_Api(); | 127 | OSSL_Api osslApi = new OSSL_Api(); |
128 | osslApi.Initialize(m_engine, so.RootPart, null); | 128 | osslApi.Initialize(m_engine, so.RootPart, null); |
129 | 129 | ||
130 | string npcRaw; | ||
131 | bool gotExpectedException = false; | 130 | bool gotExpectedException = false; |
132 | try | 131 | try |
133 | { | 132 | { |
134 | npcRaw | 133 | osslApi.osNpcCreate("Jane", "Doe", new LSL_Types.Vector3(128, 128, 128), "not existing notecard name"); |
135 | = osslApi.osNpcCreate("Jane", "Doe", new LSL_Types.Vector3(128, 128, 128), "not existing notecard name"); | ||
136 | } | 134 | } |
137 | catch (ScriptException) | 135 | catch (ScriptException) |
138 | { | 136 | { |
diff --git a/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineTest.cs b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineTest.cs index f331658..5abfe9a 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineTest.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineTest.cs | |||
@@ -44,7 +44,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine.Tests | |||
44 | /// XEngine tests. | 44 | /// XEngine tests. |
45 | /// </summary> | 45 | /// </summary> |
46 | [TestFixture] | 46 | [TestFixture] |
47 | public class XEngineTest | 47 | public class XEngineTest : OpenSimTestCase |
48 | { | 48 | { |
49 | private TestScene m_scene; | 49 | private TestScene m_scene; |
50 | private XEngine m_xEngine; | 50 | private XEngine m_xEngine; |
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index 9f05666..0bd9a06 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs | |||
@@ -31,6 +31,7 @@ using System.Collections.Generic; | |||
31 | using System.Diagnostics; //for [DebuggerNonUserCode] | 31 | using System.Diagnostics; //for [DebuggerNonUserCode] |
32 | using System.Globalization; | 32 | using System.Globalization; |
33 | using System.IO; | 33 | using System.IO; |
34 | using System.Linq; | ||
34 | using System.Reflection; | 35 | using System.Reflection; |
35 | using System.Security; | 36 | using System.Security; |
36 | using System.Security.Policy; | 37 | using System.Security.Policy; |
@@ -107,6 +108,24 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
107 | private IXmlRpcRouter m_XmlRpcRouter; | 108 | private IXmlRpcRouter m_XmlRpcRouter; |
108 | private int m_EventLimit; | 109 | private int m_EventLimit; |
109 | private bool m_KillTimedOutScripts; | 110 | private bool m_KillTimedOutScripts; |
111 | |||
112 | /// <summary> | ||
113 | /// Number of milliseconds we will wait for a script event to complete on script stop before we forcibly abort | ||
114 | /// its thread. | ||
115 | /// </summary> | ||
116 | /// <remarks> | ||
117 | /// It appears that if a script thread is aborted whilst it is holding ReaderWriterLockSlim (possibly the write | ||
118 | /// lock) then the lock is not properly released. This causes mono 2.6, 2.10 and possibly | ||
119 | /// later to crash, sometimes with symptoms such as a leap to 100% script usage and a vm thead dump showing | ||
120 | /// all threads waiting on release of ReaderWriterLockSlim write thread which none of the threads listed | ||
121 | /// actually hold. | ||
122 | /// | ||
123 | /// Pausing for event completion reduces the risk of this happening. However, it may be that aborting threads | ||
124 | /// is not a mono issue per se but rather a risky activity in itself in an AppDomain that is not immediately | ||
125 | /// shutting down. | ||
126 | /// </remarks> | ||
127 | private int m_WaitForEventCompletionOnScriptStop = 1000; | ||
128 | |||
110 | private string m_ScriptEnginesPath = null; | 129 | private string m_ScriptEnginesPath = null; |
111 | 130 | ||
112 | private ExpiringCache<UUID, bool> m_runFlags = new ExpiringCache<UUID, bool>(); | 131 | private ExpiringCache<UUID, bool> m_runFlags = new ExpiringCache<UUID, bool>(); |
@@ -316,6 +335,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
316 | m_EventLimit = m_ScriptConfig.GetInt("EventLimit", 30); | 335 | m_EventLimit = m_ScriptConfig.GetInt("EventLimit", 30); |
317 | m_KillTimedOutScripts = m_ScriptConfig.GetBoolean("KillTimedOutScripts", false); | 336 | m_KillTimedOutScripts = m_ScriptConfig.GetBoolean("KillTimedOutScripts", false); |
318 | m_SaveTime = m_ScriptConfig.GetInt("SaveInterval", 120) * 1000; | 337 | m_SaveTime = m_ScriptConfig.GetInt("SaveInterval", 120) * 1000; |
338 | m_WaitForEventCompletionOnScriptStop | ||
339 | = m_ScriptConfig.GetInt("WaitForEventCompletionOnScriptStop", m_WaitForEventCompletionOnScriptStop); | ||
340 | |||
319 | m_ScriptEnginesPath = m_ScriptConfig.GetString("ScriptEnginesPath", "ScriptEngines"); | 341 | m_ScriptEnginesPath = m_ScriptConfig.GetString("ScriptEnginesPath", "ScriptEngines"); |
320 | 342 | ||
321 | m_Prio = ThreadPriority.BelowNormal; | 343 | m_Prio = ThreadPriority.BelowNormal; |
@@ -371,7 +393,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
371 | 393 | ||
372 | MainConsole.Instance.Commands.AddCommand( | 394 | MainConsole.Instance.Commands.AddCommand( |
373 | "Scripts", false, "scripts show", "scripts show [<script-item-uuid>]", "Show script information", | 395 | "Scripts", false, "scripts show", "scripts show [<script-item-uuid>]", "Show script information", |
374 | "Show information on all scripts known to the script engine." | 396 | "Show information on all scripts known to the script engine.\n" |
375 | + "If a <script-item-uuid> is given then only information on that script will be shown.", | 397 | + "If a <script-item-uuid> is given then only information on that script will be shown.", |
376 | HandleShowScripts); | 398 | HandleShowScripts); |
377 | 399 | ||
@@ -390,22 +412,30 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
390 | MainConsole.Instance.Commands.AddCommand( | 412 | MainConsole.Instance.Commands.AddCommand( |
391 | "Scripts", false, "scripts resume", "scripts resume [<script-item-uuid>]", "Resumes all suspended scripts", | 413 | "Scripts", false, "scripts resume", "scripts resume [<script-item-uuid>]", "Resumes all suspended scripts", |
392 | "Resumes all currently suspended scripts.\n" | 414 | "Resumes all currently suspended scripts.\n" |
393 | + "Resumed scripts will process all events accumulated whilst suspended." | 415 | + "Resumed scripts will process all events accumulated whilst suspended.\n" |
394 | + "If a <script-item-uuid> is given then only that script will be resumed. Otherwise, all suitable scripts are resumed.", | 416 | + "If a <script-item-uuid> is given then only that script will be resumed. Otherwise, all suitable scripts are resumed.", |
395 | (module, cmdparams) => HandleScriptsAction(cmdparams, HandleResumeScript)); | 417 | (module, cmdparams) => HandleScriptsAction(cmdparams, HandleResumeScript)); |
396 | 418 | ||
397 | MainConsole.Instance.Commands.AddCommand( | 419 | MainConsole.Instance.Commands.AddCommand( |
398 | "Scripts", false, "scripts stop", "scripts stop [<script-item-uuid>]", "Stops all running scripts", | 420 | "Scripts", false, "scripts stop", "scripts stop [<script-item-uuid>]", "Stops all running scripts", |
399 | "Stops all running scripts." | 421 | "Stops all running scripts.\n" |
400 | + "If a <script-item-uuid> is given then only that script will be stopped. Otherwise, all suitable scripts are stopped.", | 422 | + "If a <script-item-uuid> is given then only that script will be stopped. Otherwise, all suitable scripts are stopped.", |
401 | (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStopScript)); | 423 | (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStopScript)); |
402 | 424 | ||
403 | MainConsole.Instance.Commands.AddCommand( | 425 | MainConsole.Instance.Commands.AddCommand( |
404 | "Scripts", false, "scripts start", "scripts start [<script-item-uuid>]", "Starts all stopped scripts", | 426 | "Scripts", false, "scripts start", "scripts start [<script-item-uuid>]", "Starts all stopped scripts", |
405 | "Starts all stopped scripts." | 427 | "Starts all stopped scripts.\n" |
406 | + "If a <script-item-uuid> is given then only that script will be started. Otherwise, all suitable scripts are started.", | 428 | + "If a <script-item-uuid> is given then only that script will be started. Otherwise, all suitable scripts are started.", |
407 | (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStartScript)); | 429 | (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStartScript)); |
408 | 430 | ||
431 | MainConsole.Instance.Commands.AddCommand( | ||
432 | "Scripts", false, "debug script log", "debug scripts log <item-id> <log-level>", "Extra debug logging for a script", | ||
433 | "Activates or deactivates extra debug logging for the given script.\n" | ||
434 | + "Level == 0, deactivate extra debug logging.\n" | ||
435 | + "Level >= 1, log state changes.\n" | ||
436 | + "Level >= 2, log event invocations.\n", | ||
437 | HandleDebugScriptLogCommand); | ||
438 | |||
409 | // MainConsole.Instance.Commands.AddCommand( | 439 | // MainConsole.Instance.Commands.AddCommand( |
410 | // "Debug", false, "debug xengine", "debug xengine [<level>]", | 440 | // "Debug", false, "debug xengine", "debug xengine [<level>]", |
411 | // "Turn on detailed xengine debugging.", | 441 | // "Turn on detailed xengine debugging.", |
@@ -414,6 +444,41 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
414 | // HandleDebugLevelCommand); | 444 | // HandleDebugLevelCommand); |
415 | } | 445 | } |
416 | 446 | ||
447 | private void HandleDebugScriptLogCommand(string module, string[] args) | ||
448 | { | ||
449 | if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene)) | ||
450 | return; | ||
451 | |||
452 | if (args.Length != 5) | ||
453 | { | ||
454 | MainConsole.Instance.Output("Usage: debug script log <item-id> <log-level>"); | ||
455 | return; | ||
456 | } | ||
457 | |||
458 | UUID itemId; | ||
459 | |||
460 | if (!ConsoleUtil.TryParseConsoleUuid(MainConsole.Instance, args[3], out itemId)) | ||
461 | return; | ||
462 | |||
463 | int newLevel; | ||
464 | |||
465 | if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[4], out newLevel)) | ||
466 | return; | ||
467 | |||
468 | IScriptInstance si; | ||
469 | |||
470 | lock (m_Scripts) | ||
471 | { | ||
472 | // XXX: We can't give the user feedback on a bad item id because this may apply to a different script | ||
473 | // engine | ||
474 | if (!m_Scripts.TryGetValue(itemId, out si)) | ||
475 | return; | ||
476 | } | ||
477 | |||
478 | si.DebugLevel = newLevel; | ||
479 | MainConsole.Instance.OutputFormat("Set debug level of {0} {1} to {2}", si.ScriptName, si.ItemID, newLevel); | ||
480 | } | ||
481 | |||
417 | /// <summary> | 482 | /// <summary> |
418 | /// Change debug level | 483 | /// Change debug level |
419 | /// </summary> | 484 | /// </summary> |
@@ -445,9 +510,21 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
445 | /// </summary> | 510 | /// </summary> |
446 | /// <param name="cmdparams"></param> | 511 | /// <param name="cmdparams"></param> |
447 | /// <param name="instance"></param> | 512 | /// <param name="instance"></param> |
448 | /// <returns>true if we're okay to proceed, false if not.</returns> | 513 | /// <param name="comparer">Basis on which to sort output. Can be null if no sort needs to take place</param> |
449 | private void HandleScriptsAction(string[] cmdparams, Action<IScriptInstance> action) | 514 | private void HandleScriptsAction(string[] cmdparams, Action<IScriptInstance> action) |
450 | { | 515 | { |
516 | HandleScriptsAction<object>(cmdparams, action, null); | ||
517 | } | ||
518 | |||
519 | /// <summary> | ||
520 | /// Parse the raw item id into a script instance from the command params if it's present. | ||
521 | /// </summary> | ||
522 | /// <param name="cmdparams"></param> | ||
523 | /// <param name="instance"></param> | ||
524 | /// <param name="keySelector">Basis on which to sort output. Can be null if no sort needs to take place</param> | ||
525 | private void HandleScriptsAction<TKey>( | ||
526 | string[] cmdparams, Action<IScriptInstance> action, Func<IScriptInstance, TKey> keySelector) | ||
527 | { | ||
451 | if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene)) | 528 | if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene)) |
452 | return; | 529 | return; |
453 | 530 | ||
@@ -458,7 +535,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
458 | 535 | ||
459 | if (cmdparams.Length == 2) | 536 | if (cmdparams.Length == 2) |
460 | { | 537 | { |
461 | foreach (IScriptInstance instance in m_Scripts.Values) | 538 | IEnumerable<IScriptInstance> scripts = m_Scripts.Values; |
539 | |||
540 | if (keySelector != null) | ||
541 | scripts = scripts.OrderBy<IScriptInstance, TKey>(keySelector); | ||
542 | |||
543 | foreach (IScriptInstance instance in scripts) | ||
462 | action(instance); | 544 | action(instance); |
463 | 545 | ||
464 | return; | 546 | return; |
@@ -468,7 +550,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
468 | 550 | ||
469 | if (!UUID.TryParse(rawItemId, out itemId)) | 551 | if (!UUID.TryParse(rawItemId, out itemId)) |
470 | { | 552 | { |
471 | MainConsole.Instance.OutputFormat("Error - {0} is not a valid UUID", rawItemId); | 553 | MainConsole.Instance.OutputFormat("ERROR: {0} is not a valid UUID", rawItemId); |
472 | return; | 554 | return; |
473 | } | 555 | } |
474 | 556 | ||
@@ -505,9 +587,20 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
505 | StringBuilder sb = new StringBuilder(); | 587 | StringBuilder sb = new StringBuilder(); |
506 | sb.AppendFormat("Status of XEngine instance for {0}\n", m_Scene.RegionInfo.RegionName); | 588 | sb.AppendFormat("Status of XEngine instance for {0}\n", m_Scene.RegionInfo.RegionName); |
507 | 589 | ||
590 | long scriptsLoaded, eventsQueued = 0, eventsProcessed = 0; | ||
591 | |||
508 | lock (m_Scripts) | 592 | lock (m_Scripts) |
509 | sb.AppendFormat("Scripts loaded : {0}\n", m_Scripts.Count); | 593 | { |
594 | scriptsLoaded = m_Scripts.Count; | ||
595 | |||
596 | foreach (IScriptInstance si in m_Scripts.Values) | ||
597 | { | ||
598 | eventsQueued += si.EventsQueued; | ||
599 | eventsProcessed += si.EventsProcessed; | ||
600 | } | ||
601 | } | ||
510 | 602 | ||
603 | sb.AppendFormat("Scripts loaded : {0}\n", scriptsLoaded); | ||
511 | sb.AppendFormat("Unique scripts : {0}\n", m_uniqueScripts.Count); | 604 | sb.AppendFormat("Unique scripts : {0}\n", m_uniqueScripts.Count); |
512 | sb.AppendFormat("Scripts waiting for load : {0}\n", m_CompileQueue.Count); | 605 | sb.AppendFormat("Scripts waiting for load : {0}\n", m_CompileQueue.Count); |
513 | sb.AppendFormat("Max threads : {0}\n", m_ThreadPool.MaxThreads); | 606 | sb.AppendFormat("Max threads : {0}\n", m_ThreadPool.MaxThreads); |
@@ -516,6 +609,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
516 | sb.AppendFormat("In use threads : {0}\n", m_ThreadPool.InUseThreads); | 609 | sb.AppendFormat("In use threads : {0}\n", m_ThreadPool.InUseThreads); |
517 | sb.AppendFormat("Work items waiting : {0}\n", m_ThreadPool.WaitingCallbacks); | 610 | sb.AppendFormat("Work items waiting : {0}\n", m_ThreadPool.WaitingCallbacks); |
518 | // sb.AppendFormat("Assemblies loaded : {0}\n", m_Assemblies.Count); | 611 | // sb.AppendFormat("Assemblies loaded : {0}\n", m_Assemblies.Count); |
612 | sb.AppendFormat("Events queued : {0}\n", eventsQueued); | ||
613 | sb.AppendFormat("Events processed : {0}\n", eventsProcessed); | ||
519 | 614 | ||
520 | SensorRepeat sr = AsyncCommandManager.GetSensorRepeatPlugin(this); | 615 | SensorRepeat sr = AsyncCommandManager.GetSensorRepeatPlugin(this); |
521 | sb.AppendFormat("Sensors : {0}\n", sr != null ? sr.SensorsCount : 0); | 616 | sb.AppendFormat("Sensors : {0}\n", sr != null ? sr.SensorsCount : 0); |
@@ -546,7 +641,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
546 | } | 641 | } |
547 | } | 642 | } |
548 | 643 | ||
549 | HandleScriptsAction(cmdparams, HandleShowScript); | 644 | HandleScriptsAction<long>(cmdparams, HandleShowScript, si => si.EventsProcessed); |
550 | } | 645 | } |
551 | 646 | ||
552 | private void HandleShowScript(IScriptInstance instance) | 647 | private void HandleShowScript(IScriptInstance instance) |
@@ -576,11 +671,10 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
576 | 671 | ||
577 | sb.AppendFormat("Script name : {0}\n", instance.ScriptName); | 672 | sb.AppendFormat("Script name : {0}\n", instance.ScriptName); |
578 | sb.AppendFormat("Status : {0}\n", status); | 673 | sb.AppendFormat("Status : {0}\n", status); |
579 | 674 | sb.AppendFormat("Queued events : {0}\n", instance.EventsQueued); | |
580 | lock (eq) | 675 | sb.AppendFormat("Processed events : {0}\n", instance.EventsProcessed); |
581 | sb.AppendFormat("Queued events : {0}\n", eq.Count); | ||
582 | |||
583 | sb.AppendFormat("Item UUID : {0}\n", instance.ItemID); | 676 | sb.AppendFormat("Item UUID : {0}\n", instance.ItemID); |
677 | sb.AppendFormat("Asset UUID : {0}\n", instance.AssetID); | ||
584 | sb.AppendFormat("Containing part name: {0}\n", instance.PrimName); | 678 | sb.AppendFormat("Containing part name: {0}\n", instance.PrimName); |
585 | sb.AppendFormat("Containing part UUID: {0}\n", instance.ObjectID); | 679 | sb.AppendFormat("Containing part UUID: {0}\n", instance.ObjectID); |
586 | sb.AppendFormat("Position : {0}\n", sop.AbsolutePosition); | 680 | sb.AppendFormat("Position : {0}\n", sop.AbsolutePosition); |
@@ -1089,8 +1183,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1089 | 1183 | ||
1090 | string assembly = ""; | 1184 | string assembly = ""; |
1091 | 1185 | ||
1092 | CultureInfo USCulture = new CultureInfo("en-US"); | 1186 | Culture.SetCurrentCulture(); |
1093 | Thread.CurrentThread.CurrentCulture = USCulture; | ||
1094 | 1187 | ||
1095 | Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> linemap; | 1188 | Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> linemap; |
1096 | 1189 | ||
@@ -1347,9 +1440,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1347 | lockScriptsForWrite(false); | 1440 | lockScriptsForWrite(false); |
1348 | instance.ClearQueue(); | 1441 | instance.ClearQueue(); |
1349 | 1442 | ||
1350 | // Give the script some time to finish processing its last event. Simply aborting the script thread can | 1443 | instance.Stop(m_WaitForEventCompletionOnScriptStop); |
1351 | // cause issues on mono 2.6, 2.10 and possibly later where locks are not released properly on abort. | ||
1352 | instance.Stop(1000); | ||
1353 | 1444 | ||
1354 | // bool objectRemoved = false; | 1445 | // bool objectRemoved = false; |
1355 | 1446 | ||
@@ -1504,8 +1595,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1504 | /// <returns></returns> | 1595 | /// <returns></returns> |
1505 | private object ProcessEventHandler(object parms) | 1596 | private object ProcessEventHandler(object parms) |
1506 | { | 1597 | { |
1507 | CultureInfo USCulture = new CultureInfo("en-US"); | 1598 | Culture.SetCurrentCulture(); |
1508 | Thread.CurrentThread.CurrentCulture = USCulture; | ||
1509 | 1599 | ||
1510 | IScriptInstance instance = (ScriptInstance) parms; | 1600 | IScriptInstance instance = (ScriptInstance) parms; |
1511 | 1601 | ||
@@ -1693,7 +1783,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1693 | { | 1783 | { |
1694 | IScriptInstance instance = GetInstance(itemID); | 1784 | IScriptInstance instance = GetInstance(itemID); |
1695 | if (instance != null) | 1785 | if (instance != null) |
1696 | instance.ResetScript(); | 1786 | instance.ResetScript(m_WaitForEventCompletionOnScriptStop); |
1697 | } | 1787 | } |
1698 | 1788 | ||
1699 | public void StartScript(UUID itemID) | 1789 | public void StartScript(UUID itemID) |
@@ -1708,16 +1798,11 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1708 | public void StopScript(UUID itemID) | 1798 | public void StopScript(UUID itemID) |
1709 | { | 1799 | { |
1710 | IScriptInstance instance = GetInstance(itemID); | 1800 | IScriptInstance instance = GetInstance(itemID); |
1801 | |||
1711 | if (instance != null) | 1802 | if (instance != null) |
1712 | { | 1803 | instance.Stop(m_WaitForEventCompletionOnScriptStop); |
1713 | // Give the script some time to finish processing its last event. Simply aborting the script thread can | ||
1714 | // cause issues on mono 2.6, 2.10 and possibly later where locks are not released properly on abort. | ||
1715 | instance.Stop(1000); | ||
1716 | } | ||
1717 | else | 1804 | else |
1718 | { | ||
1719 | m_runFlags.AddOrUpdate(itemID, false, 240); | 1805 | m_runFlags.AddOrUpdate(itemID, false, 240); |
1720 | } | ||
1721 | } | 1806 | } |
1722 | 1807 | ||
1723 | public DetectParams GetDetectParams(UUID itemID, int idx) | 1808 | public DetectParams GetDetectParams(UUID itemID, int idx) |
diff --git a/OpenSim/Region/UserStatistics/WebStatsModule.cs b/OpenSim/Region/UserStatistics/WebStatsModule.cs index b08233c..64cb577 100644 --- a/OpenSim/Region/UserStatistics/WebStatsModule.cs +++ b/OpenSim/Region/UserStatistics/WebStatsModule.cs | |||
@@ -94,8 +94,6 @@ namespace OpenSim.Region.UserStatistics | |||
94 | if (!enabled) | 94 | if (!enabled) |
95 | return; | 95 | return; |
96 | 96 | ||
97 | AddEventHandlers(); | ||
98 | |||
99 | if (Util.IsWindows()) | 97 | if (Util.IsWindows()) |
100 | Util.LoadArchSpecificWindowsDll("sqlite3.dll"); | 98 | Util.LoadArchSpecificWindowsDll("sqlite3.dll"); |
101 | 99 | ||
@@ -143,10 +141,14 @@ namespace OpenSim.Region.UserStatistics | |||
143 | lock (m_scenes) | 141 | lock (m_scenes) |
144 | { | 142 | { |
145 | m_scenes.Add(scene); | 143 | m_scenes.Add(scene); |
146 | if (m_simstatsCounters.ContainsKey(scene.RegionInfo.RegionID)) | 144 | updateLogMod = m_scenes.Count * 2; |
147 | m_simstatsCounters.Remove(scene.RegionInfo.RegionID); | ||
148 | 145 | ||
149 | m_simstatsCounters.Add(scene.RegionInfo.RegionID, new USimStatsData(scene.RegionInfo.RegionID)); | 146 | m_simstatsCounters.Add(scene.RegionInfo.RegionID, new USimStatsData(scene.RegionInfo.RegionID)); |
147 | |||
148 | scene.EventManager.OnRegisterCaps += OnRegisterCaps; | ||
149 | scene.EventManager.OnDeregisterCaps += OnDeRegisterCaps; | ||
150 | scene.EventManager.OnClientClosed += OnClientClosed; | ||
151 | scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; | ||
150 | scene.StatsReporter.OnSendStatsResult += ReceiveClassicSimStatsPacket; | 152 | scene.StatsReporter.OnSendStatsResult += ReceiveClassicSimStatsPacket; |
151 | } | 153 | } |
152 | } | 154 | } |
@@ -157,6 +159,15 @@ namespace OpenSim.Region.UserStatistics | |||
157 | 159 | ||
158 | public void RemoveRegion(Scene scene) | 160 | public void RemoveRegion(Scene scene) |
159 | { | 161 | { |
162 | if (!enabled) | ||
163 | return; | ||
164 | |||
165 | lock (m_scenes) | ||
166 | { | ||
167 | m_scenes.Remove(scene); | ||
168 | updateLogMod = m_scenes.Count * 2; | ||
169 | m_simstatsCounters.Remove(scene.RegionInfo.RegionID); | ||
170 | } | ||
160 | } | 171 | } |
161 | 172 | ||
162 | public virtual void Close() | 173 | public virtual void Close() |
@@ -187,9 +198,7 @@ namespace OpenSim.Region.UserStatistics | |||
187 | private void ReceiveClassicSimStatsPacket(SimStats stats) | 198 | private void ReceiveClassicSimStatsPacket(SimStats stats) |
188 | { | 199 | { |
189 | if (!enabled) | 200 | if (!enabled) |
190 | { | ||
191 | return; | 201 | return; |
192 | } | ||
193 | 202 | ||
194 | try | 203 | try |
195 | { | 204 | { |
@@ -198,17 +207,25 @@ namespace OpenSim.Region.UserStatistics | |||
198 | if (concurrencyCounter > 0 || System.Environment.TickCount - lastHit > 30000) | 207 | if (concurrencyCounter > 0 || System.Environment.TickCount - lastHit > 30000) |
199 | return; | 208 | return; |
200 | 209 | ||
201 | if ((updateLogCounter++ % updateLogMod) == 0) | 210 | // We will conduct this under lock so that fields such as updateLogCounter do not potentially get |
211 | // confused if a scene is removed. | ||
212 | // XXX: Possibly the scope of this lock could be reduced though it's not critical. | ||
213 | lock (m_scenes) | ||
202 | { | 214 | { |
203 | m_loglines = readLogLines(10); | 215 | if (updateLogMod != 0 && updateLogCounter++ % updateLogMod == 0) |
204 | if (updateLogCounter > 10000) updateLogCounter = 1; | 216 | { |
205 | } | 217 | m_loglines = readLogLines(10); |
206 | 218 | ||
207 | USimStatsData ss = m_simstatsCounters[stats.RegionUUID]; | 219 | if (updateLogCounter > 10000) |
220 | updateLogCounter = 1; | ||
221 | } | ||
208 | 222 | ||
209 | if ((++ss.StatsCounter % updateStatsMod) == 0) | 223 | USimStatsData ss = m_simstatsCounters[stats.RegionUUID]; |
210 | { | 224 | |
211 | ss.ConsumeSimStats(stats); | 225 | if ((++ss.StatsCounter % updateStatsMod) == 0) |
226 | { | ||
227 | ss.ConsumeSimStats(stats); | ||
228 | } | ||
212 | } | 229 | } |
213 | } | 230 | } |
214 | catch (KeyNotFoundException) | 231 | catch (KeyNotFoundException) |