aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region
diff options
context:
space:
mode:
authorDan Lake2011-07-11 12:23:20 -0700
committerDan Lake2011-07-11 12:23:20 -0700
commitb9cbe92f30c97d6b402be73c8c6fd8e6894ef05a (patch)
tree8fd2fa4567e2882e7f5dafdb8cf1de571917f23a /OpenSim/Region
parentCheckin 32 bit bulletsim shared library for Linux. (diff)
parentminor Tack the prim name on the end of the "experimental mesh proxy generatio... (diff)
downloadopensim-SC-b9cbe92f30c97d6b402be73c8c6fd8e6894ef05a.zip
opensim-SC-b9cbe92f30c97d6b402be73c8c6fd8e6894ef05a.tar.gz
opensim-SC-b9cbe92f30c97d6b402be73c8c6fd8e6894ef05a.tar.bz2
opensim-SC-b9cbe92f30c97d6b402be73c8c6fd8e6894ef05a.tar.xz
Merge branch 'master' into bulletsim
Diffstat (limited to 'OpenSim/Region')
-rw-r--r--OpenSim/Region/Application/ConfigurationLoader.cs2
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs212
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs149
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs4
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs7
-rw-r--r--OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs337
-rw-r--r--OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs127
-rw-r--r--OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs28
-rw-r--r--OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs69
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs58
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs6
-rw-r--r--OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs6
-rw-r--r--OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs3
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs6
-rw-r--r--OpenSim/Region/CoreModules/World/Land/LandObject.cs8
-rw-r--r--OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs4
-rw-r--r--OpenSim/Region/Framework/Interfaces/IAvatarFactory.cs2
-rw-r--r--OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs10
-rw-r--r--OpenSim/Region/Framework/Interfaces/INPCModule.cs (renamed from OpenSim/Region/CoreModules/Avatar/NPC/INPCModule.cs)2
-rw-r--r--OpenSim/Region/Framework/Scenes/AsyncInventorySender.cs156
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.Inventory.cs23
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs25
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs13
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneGraph.cs17
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs49
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPart.cs117
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs6
-rw-r--r--OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/AttachmentTests.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs4
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneObjectUserGroupTests.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTests.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/StandaloneTeleportTests.cs2
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs2
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs8
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsMessagingModule.cs2
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/SimianGroupsServicesConnectorModule.cs2
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs2
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/Minimodule/SOPObject.cs2
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs2
-rw-r--r--OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs125
-rw-r--r--OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs71
-rw-r--r--OpenSim/Region/Physics/Manager/PhysicsScene.cs5
-rw-r--r--OpenSim/Region/Physics/Meshing/Meshmerizer.cs115
-rw-r--r--OpenSim/Region/Physics/OdePlugin/ODEPrim.cs109
-rw-r--r--OpenSim/Region/Physics/OdePlugin/OdePlugin.cs3827
-rw-r--r--OpenSim/Region/Physics/OdePlugin/OdeScene.cs3865
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs50
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs5
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs38
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs6
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs21
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs19
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs31
57 files changed, 5402 insertions, 4371 deletions
diff --git a/OpenSim/Region/Application/ConfigurationLoader.cs b/OpenSim/Region/Application/ConfigurationLoader.cs
index 2d81ea8..d19852b 100644
--- a/OpenSim/Region/Application/ConfigurationLoader.cs
+++ b/OpenSim/Region/Application/ConfigurationLoader.cs
@@ -328,7 +328,7 @@ namespace OpenSim
328 config.Set("meshing", "Meshmerizer"); 328 config.Set("meshing", "Meshmerizer");
329 config.Set("physical_prim", true); 329 config.Set("physical_prim", true);
330 config.Set("see_into_this_sim_from_neighbor", true); 330 config.Set("see_into_this_sim_from_neighbor", true);
331 config.Set("serverside_object_permissions", false); 331 config.Set("serverside_object_permissions", true);
332 config.Set("storage_plugin", "OpenSim.Data.SQLite.dll"); 332 config.Set("storage_plugin", "OpenSim.Data.SQLite.dll");
333 config.Set("storage_connection_string", "URI=file:OpenSim.db,version=3"); 333 config.Set("storage_connection_string", "URI=file:OpenSim.db,version=3");
334 config.Set("storage_prim_inventories", true); 334 config.Set("storage_prim_inventories", true);
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
index 95713e9..d3bb0bc 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
@@ -1,10 +1,39 @@
1using System; 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
2using System.Collections; 29using System.Collections;
3using System.Collections.Generic; 30using System.Collections.Generic;
4using System.IO; 31using System.IO;
5using System.Reflection; 32using System.Reflection;
33using System.Text;
6 34
7using OpenMetaverse; 35using OpenMetaverse;
36using OpenMetaverse.StructuredData;
8using Nini.Config; 37using Nini.Config;
9using log4net; 38using log4net;
10 39
@@ -12,11 +41,14 @@ using OpenSim.Framework;
12using OpenSim.Framework.Capabilities; 41using OpenSim.Framework.Capabilities;
13using OpenSim.Region.Framework; 42using OpenSim.Region.Framework;
14using OpenSim.Region.Framework.Scenes; 43using OpenSim.Region.Framework.Scenes;
44using OpenSim.Region.Framework.Scenes.Serialization;
15using OpenSim.Framework.Servers; 45using OpenSim.Framework.Servers;
16using OpenSim.Framework.Servers.HttpServer; 46using OpenSim.Framework.Servers.HttpServer;
17using OpenSim.Services.Interfaces; 47using OpenSim.Services.Interfaces;
18 48
19using Caps = OpenSim.Framework.Capabilities.Caps; 49using Caps = OpenSim.Framework.Capabilities.Caps;
50using OSDArray = OpenMetaverse.StructuredData.OSDArray;
51using OSDMap = OpenMetaverse.StructuredData.OSDMap;
20 52
21namespace OpenSim.Region.ClientStack.Linden 53namespace OpenSim.Region.ClientStack.Linden
22{ 54{
@@ -79,7 +111,7 @@ namespace OpenSim.Region.ClientStack.Linden
79 111
80 private bool m_persistBakedTextures = false; 112 private bool m_persistBakedTextures = false;
81 private IAssetService m_assetService; 113 private IAssetService m_assetService;
82 private bool m_dumpAssetsToFile; 114 private bool m_dumpAssetsToFile = false;
83 private string m_regionName; 115 private string m_regionName;
84 116
85 public BunchOfCaps(Scene scene, Caps caps) 117 public BunchOfCaps(Scene scene, Caps caps)
@@ -439,7 +471,7 @@ namespace OpenSim.Region.ClientStack.Linden
439 } 471 }
440 472
441 /// <summary> 473 /// <summary>
442 /// 474 /// Convert raw uploaded data into the appropriate asset and item.
443 /// </summary> 475 /// </summary>
444 /// <param name="assetID"></param> 476 /// <param name="assetID"></param>
445 /// <param name="inventoryItem"></param> 477 /// <param name="inventoryItem"></param>
@@ -448,6 +480,10 @@ namespace OpenSim.Region.ClientStack.Linden
448 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType, 480 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType,
449 string assetType) 481 string assetType)
450 { 482 {
483 m_log.DebugFormat(
484 "Uploaded asset {0} for inventory item {1}, inv type {2}, asset type {3}",
485 assetID, inventoryItem, inventoryType, assetType);
486
451 sbyte assType = 0; 487 sbyte assType = 0;
452 sbyte inType = 0; 488 sbyte inType = 0;
453 489
@@ -474,6 +510,160 @@ namespace OpenSim.Region.ClientStack.Linden
474 break; 510 break;
475 } 511 }
476 } 512 }
513 else if (inventoryType == "object")
514 {
515 inType = (sbyte)InventoryType.Object;
516 assType = (sbyte)AssetType.Object;
517
518 List<Vector3> positions = new List<Vector3>();
519 List<Quaternion> rotations = new List<Quaternion>();
520 OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data);
521 OSDArray instance_list = (OSDArray)request["instance_list"];
522 OSDArray mesh_list = (OSDArray)request["mesh_list"];
523 OSDArray texture_list = (OSDArray)request["texture_list"];
524 SceneObjectGroup grp = null;
525
526 List<UUID> textures = new List<UUID>();
527 for (int i = 0; i < texture_list.Count; i++)
528 {
529 AssetBase textureAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Texture, "");
530 textureAsset.Data = texture_list[i].AsBinary();
531 m_assetService.Store(textureAsset);
532 textures.Add(textureAsset.FullID);
533 }
534
535 for (int i = 0; i < mesh_list.Count; i++)
536 {
537 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox();
538
539 Primitive.TextureEntry textureEntry
540 = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE);
541 OSDMap inner_instance_list = (OSDMap)instance_list[i];
542
543 OSDArray face_list = (OSDArray)inner_instance_list["face_list"];
544 for (uint face = 0; face < face_list.Count; face++)
545 {
546 OSDMap faceMap = (OSDMap)face_list[(int)face];
547 Primitive.TextureEntryFace f = pbs.Textures.CreateFace(face);
548 if(faceMap.ContainsKey("fullbright"))
549 f.Fullbright = faceMap["fullbright"].AsBoolean();
550 if (faceMap.ContainsKey ("diffuse_color"))
551 f.RGBA = faceMap["diffuse_color"].AsColor4();
552
553 int textureNum = faceMap["image"].AsInteger();
554 float imagerot = faceMap["imagerot"].AsInteger();
555 float offsets = (float)faceMap["offsets"].AsReal();
556 float offsett = (float)faceMap["offsett"].AsReal();
557 float scales = (float)faceMap["scales"].AsReal();
558 float scalet = (float)faceMap["scalet"].AsReal();
559
560 if(imagerot != 0)
561 f.Rotation = imagerot;
562
563 if(offsets != 0)
564 f.OffsetU = offsets;
565
566 if (offsett != 0)
567 f.OffsetV = offsett;
568
569 if (scales != 0)
570 f.RepeatU = scales;
571
572 if (scalet != 0)
573 f.RepeatV = scalet;
574
575 if (textures.Count > textureNum)
576 f.TextureID = textures[textureNum];
577 else
578 f.TextureID = Primitive.TextureEntry.WHITE_TEXTURE;
579
580 textureEntry.FaceTextures[face] = f;
581 }
582
583 pbs.TextureEntry = textureEntry.GetBytes();
584
585 AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, "");
586 meshAsset.Data = mesh_list[i].AsBinary();
587 m_assetService.Store(meshAsset);
588
589 pbs.SculptEntry = true;
590 pbs.SculptTexture = meshAsset.FullID;
591 pbs.SculptType = (byte)SculptType.Mesh;
592 pbs.SculptData = meshAsset.Data;
593
594 Vector3 position = inner_instance_list["position"].AsVector3();
595 Vector3 scale = inner_instance_list["scale"].AsVector3();
596 Quaternion rotation = inner_instance_list["rotation"].AsQuaternion();
597
598// no longer used - begin ------------------------
599// int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger();
600// int material = inner_instance_list["material"].AsInteger();
601// int mesh = inner_instance_list["mesh"].AsInteger();
602
603// OSDMap permissions = (OSDMap)inner_instance_list["permissions"];
604// int base_mask = permissions["base_mask"].AsInteger();
605// int everyone_mask = permissions["everyone_mask"].AsInteger();
606// UUID creator_id = permissions["creator_id"].AsUUID();
607// UUID group_id = permissions["group_id"].AsUUID();
608// int group_mask = permissions["group_mask"].AsInteger();
609// bool is_owner_group = permissions["is_owner_group"].AsBoolean();
610// UUID last_owner_id = permissions["last_owner_id"].AsUUID();
611// int next_owner_mask = permissions["next_owner_mask"].AsInteger();
612// UUID owner_id = permissions["owner_id"].AsUUID();
613// int owner_mask = permissions["owner_mask"].AsInteger();
614// no longer used - end ------------------------
615
616 UUID owner_id = m_HostCapsObj.AgentID;
617
618 SceneObjectPart prim
619 = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero);
620
621 prim.Scale = scale;
622 prim.OffsetPosition = position;
623 rotations.Add(rotation);
624 positions.Add(position);
625 prim.UUID = UUID.Random();
626 prim.CreatorID = owner_id;
627 prim.OwnerID = owner_id;
628 prim.GroupID = UUID.Zero;
629 prim.LastOwnerID = prim.OwnerID;
630 prim.CreationDate = Util.UnixTimeSinceEpoch();
631 prim.Name = assetName;
632 prim.Description = "";
633
634// prim.BaseMask = (uint)base_mask;
635// prim.EveryoneMask = (uint)everyone_mask;
636// prim.GroupMask = (uint)group_mask;
637// prim.NextOwnerMask = (uint)next_owner_mask;
638// prim.OwnerMask = (uint)owner_mask;
639
640 if (grp == null)
641 grp = new SceneObjectGroup(prim);
642 else
643 grp.AddPart(prim);
644 }
645
646 // Fix first link number
647 if (grp.Parts.Length > 1)
648 grp.RootPart.LinkNum++;
649
650 Vector3 rootPos = positions[0];
651 grp.AbsolutePosition = rootPos;
652 for (int i = 0; i < positions.Count; i++)
653 {
654 Vector3 offset = positions[i] - rootPos;
655 grp.Parts[i].OffsetPosition = offset;
656 }
657
658 for (int i = 0; i < rotations.Count; i++)
659 {
660 if (i != 0)
661 grp.Parts[i].RotationOffset = rotations[i];
662 }
663
664 grp.UpdateGroupRotationR(rotations[0]);
665 data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp));
666 }
477 667
478 AssetBase asset; 668 AssetBase asset;
479 asset = new AssetBase(assetID, assetName, assType, m_HostCapsObj.AgentID.ToString()); 669 asset = new AssetBase(assetID, assetName, assType, m_HostCapsObj.AgentID.ToString());
@@ -506,8 +696,6 @@ namespace OpenSim.Region.ClientStack.Linden
506 } 696 }
507 } 697 }
508 698
509
510
511 /// <summary> 699 /// <summary>
512 /// 700 ///
513 /// </summary> 701 /// </summary>
@@ -632,7 +820,7 @@ namespace OpenSim.Region.ClientStack.Linden
632 } 820 }
633 821
634 /// <summary> 822 /// <summary>
635 /// 823 /// Handle raw asset upload data via the capability.
636 /// </summary> 824 /// </summary>
637 /// <param name="data"></param> 825 /// <param name="data"></param>
638 /// <param name="path"></param> 826 /// <param name="path"></param>
@@ -670,6 +858,7 @@ namespace OpenSim.Region.ClientStack.Linden
670 858
671 return res; 859 return res;
672 } 860 }
861
673 ///Left this in and commented in case there are unforseen issues 862 ///Left this in and commented in case there are unforseen issues
674 //private void SaveAssetToFile(string filename, byte[] data) 863 //private void SaveAssetToFile(string filename, byte[] data)
675 //{ 864 //{
@@ -679,6 +868,7 @@ namespace OpenSim.Region.ClientStack.Linden
679 // bw.Close(); 868 // bw.Close();
680 // fs.Close(); 869 // fs.Close();
681 //} 870 //}
871
682 private static void SaveAssetToFile(string filename, byte[] data) 872 private static void SaveAssetToFile(string filename, byte[] data)
683 { 873 {
684 string assetPath = "UserAssets"; 874 string assetPath = "UserAssets";
@@ -719,7 +909,7 @@ namespace OpenSim.Region.ClientStack.Linden
719 } 909 }
720 910
721 /// <summary> 911 /// <summary>
722 /// 912 /// Handle raw uploaded asset data.
723 /// </summary> 913 /// </summary>
724 /// <param name="data"></param> 914 /// <param name="data"></param>
725 /// <param name="path"></param> 915 /// <param name="path"></param>
@@ -752,6 +942,7 @@ namespace OpenSim.Region.ClientStack.Linden
752 942
753 return res; 943 return res;
754 } 944 }
945
755 ///Left this in and commented in case there are unforseen issues 946 ///Left this in and commented in case there are unforseen issues
756 //private void SaveAssetToFile(string filename, byte[] data) 947 //private void SaveAssetToFile(string filename, byte[] data)
757 //{ 948 //{
@@ -761,6 +952,7 @@ namespace OpenSim.Region.ClientStack.Linden
761 // bw.Close(); 952 // bw.Close();
762 // fs.Close(); 953 // fs.Close();
763 //} 954 //}
955
764 private static void SaveAssetToFile(string filename, byte[] data) 956 private static void SaveAssetToFile(string filename, byte[] data)
765 { 957 {
766 string assetPath = "UserAssets"; 958 string assetPath = "UserAssets";
@@ -839,7 +1031,7 @@ namespace OpenSim.Region.ClientStack.Linden
839 uploadComplete.new_asset = inventoryItemID; 1031 uploadComplete.new_asset = inventoryItemID;
840 uploadComplete.compiled = errors.Count > 0 ? false : true; 1032 uploadComplete.compiled = errors.Count > 0 ? false : true;
841 uploadComplete.state = "complete"; 1033 uploadComplete.state = "complete";
842 uploadComplete.errors = new OSDArray(); 1034 uploadComplete.errors = new OpenSim.Framework.Capabilities.OSDArray();
843 uploadComplete.errors.Array = errors; 1035 uploadComplete.errors.Array = errors;
844 1036
845 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); 1037 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
@@ -905,7 +1097,7 @@ namespace OpenSim.Region.ClientStack.Linden
905 } 1097 }
906 1098
907 /// <summary> 1099 /// <summary>
908 /// 1100 /// Handle raw uploaded baked texture data.
909 /// </summary> 1101 /// </summary>
910 /// <param name="data"></param> 1102 /// <param name="data"></param>
911 /// <param name="path"></param> 1103 /// <param name="path"></param>
@@ -935,4 +1127,4 @@ namespace OpenSim.Region.ClientStack.Linden
935 } 1127 }
936 } 1128 }
937 1129
938} 1130} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs
new file mode 100644
index 0000000..c9d7ae1
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs
@@ -0,0 +1,149 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Reflection;
31using log4net;
32using Nini.Config;
33using Mono.Addins;
34using OpenMetaverse;
35using OpenMetaverse.StructuredData;
36using OpenSim.Framework;
37using OpenSim.Framework.Servers.HttpServer;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Services.Interfaces;
41using Caps = OpenSim.Framework.Capabilities.Caps;
42
43namespace OpenSim.Region.ClientStack.Linden
44{
45 /// <summary>
46 /// MeshUploadFlag capability. This is required for uploading Mesh.
47 /// </summary>
48 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
49 public class MeshUploadFlagModule : INonSharedRegionModule
50 {
51 private static readonly ILog m_log =
52 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
53
54 /// <summary>
55 /// Is this module enabled?
56 /// </summary>
57 public bool Enabled { get; private set; }
58
59 private Scene m_scene;
60 private UUID m_agentID;
61
62 #region ISharedRegionModule Members
63
64 public MeshUploadFlagModule()
65 {
66 Enabled = true;
67 }
68
69 public void Initialise(IConfigSource source)
70 {
71 IConfig config = source.Configs["Mesh"];
72 if (config == null)
73 {
74 return;
75 }
76 else
77 {
78 Enabled = config.GetBoolean("AllowMeshUpload", Enabled);
79 }
80 }
81
82 public void AddRegion(Scene s)
83 {
84 if (!Enabled)
85 return;
86
87 m_scene = s;
88 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
89 }
90
91 public void RemoveRegion(Scene s)
92 {
93 if (!Enabled)
94 return;
95
96 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
97 }
98
99 public void RegionLoaded(Scene s)
100 {
101 }
102
103 public void PostInitialise()
104 {
105 }
106
107 public void Close() { }
108
109 public string Name { get { return "MeshUploadFlagModule"; } }
110
111 public Type ReplaceableInterface
112 {
113 get { return null; }
114 }
115
116 #endregion
117
118 public void RegisterCaps(UUID agentID, Caps caps)
119 {
120 IRequestHandler reqHandler = new RestHTTPHandler("GET", "/CAPS/" + UUID.Random(), MeshUploadFlag);
121 caps.RegisterHandler("MeshUploadFlag", reqHandler);
122 m_agentID = agentID;
123 }
124
125 private Hashtable MeshUploadFlag(Hashtable mDhttpMethod)
126 {
127 m_log.DebugFormat("[SIMULATOR FEATURES MODULE]: MeshUploadFlag request");
128
129 OSDMap data = new OSDMap();
130 ScenePresence sp = m_scene.GetScenePresence(m_agentID);
131 data["username"] = sp.Firstname + "." + sp.Lastname;
132 data["display_name_next_update"] = new OSDDate(DateTime.Now);
133 data["legacy_first_name"] = sp.Firstname;
134 data["mesh_upload_status"] = "valid";
135 data["display_name"] = sp.Firstname + " " + sp.Lastname;
136 data["legacy_last_name"] = sp.Lastname;
137 data["id"] = m_agentID;
138 data["is_display_name_default"] = true;
139
140 //Send back data
141 Hashtable responsedata = new Hashtable();
142 responsedata["int_response_code"] = 200;
143 responsedata["content_type"] = "text/plain";
144 responsedata["keepalive"] = false;
145 responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(data);
146 return responsedata;
147 }
148 }
149} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs
index 3809f84..15ed3b3 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs
@@ -250,11 +250,9 @@ namespace OpenSim.Region.ClientStack.Linden
250 case 0x40: 250 case 0x40:
251 pbs.ReadProjectionData(extraParam.ExtraParamData, 0); 251 pbs.ReadProjectionData(extraParam.ExtraParamData, 0);
252 break; 252 break;
253
254 } 253 }
255
256
257 } 254 }
255
258 pbs.PathBegin = (ushort) obj.PathBegin; 256 pbs.PathBegin = (ushort) obj.PathBegin;
259 pbs.PathCurve = (byte) obj.PathCurve; 257 pbs.PathCurve = (byte) obj.PathCurve;
260 pbs.PathEnd = (ushort) obj.PathEnd; 258 pbs.PathEnd = (ushort) obj.PathEnd;
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index f53e236..c176c2b 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -7548,13 +7548,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7548 IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); 7548 IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>();
7549 if (invAccess != null) 7549 if (invAccess != null)
7550 { 7550 {
7551 if (!invAccess.GetAgentInventoryItem(this, itemID, requestID)) 7551 if (!invAccess.CanGetAgentInventoryItem(this, itemID, requestID))
7552 return false; 7552 return false;
7553
7554 } 7553 }
7555 else 7554 else
7555 {
7556 return false; 7556 return false;
7557 7557 }
7558 } 7558 }
7559 } 7559 }
7560 } 7560 }
@@ -7568,7 +7568,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7568 { 7568 {
7569 AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack; 7569 AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack;
7570 7570
7571
7572 // m_log.Debug("upload request " + request.ToString()); 7571 // m_log.Debug("upload request " + request.ToString());
7573 // m_log.Debug("upload request was for assetid: " + request.AssetBlock.TransactionID.Combine(this.SecureSessionId).ToString()); 7572 // m_log.Debug("upload request was for assetid: " + request.AssetBlock.TransactionID.Combine(this.SecureSessionId).ToString());
7574 UUID temp = UUID.Combine(request.AssetBlock.TransactionID, SecureSessionId); 7573 UUID temp = UUID.Combine(request.AssetBlock.TransactionID, SecureSessionId);
diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
index 48ee277..2b3f7f5 100644
--- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
+++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
@@ -86,6 +86,8 @@ namespace Flotsam.RegionModules.AssetCache
86 private List<string> m_CurrentlyWriting = new List<string>(); 86 private List<string> m_CurrentlyWriting = new List<string>();
87#endif 87#endif
88 88
89 private bool m_FileCacheEnabled = true;
90
89 private ExpiringCache<string, AssetBase> m_MemoryCache; 91 private ExpiringCache<string, AssetBase> m_MemoryCache;
90 private bool m_MemoryCacheEnabled = false; 92 private bool m_MemoryCacheEnabled = false;
91 93
@@ -146,6 +148,7 @@ namespace Flotsam.RegionModules.AssetCache
146 } 148 }
147 else 149 else
148 { 150 {
151 m_FileCacheEnabled = assetConfig.GetBoolean("FileCacheEnabled", m_FileCacheEnabled);
149 m_CacheDirectory = assetConfig.GetString("CacheDirectory", m_DefaultCacheDirectory); 152 m_CacheDirectory = assetConfig.GetString("CacheDirectory", m_DefaultCacheDirectory);
150 153
151 m_MemoryCacheEnabled = assetConfig.GetBoolean("MemoryCacheEnabled", m_MemoryCacheEnabled); 154 m_MemoryCacheEnabled = assetConfig.GetBoolean("MemoryCacheEnabled", m_MemoryCacheEnabled);
@@ -173,7 +176,7 @@ namespace Flotsam.RegionModules.AssetCache
173 176
174 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Cache Directory {0}", m_CacheDirectory); 177 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Cache Directory {0}", m_CacheDirectory);
175 178
176 if ((m_FileExpiration > TimeSpan.Zero) && (m_FileExpirationCleanupTimer > TimeSpan.Zero)) 179 if (m_FileCacheEnabled && (m_FileExpiration > TimeSpan.Zero) && (m_FileExpirationCleanupTimer > TimeSpan.Zero))
177 { 180 {
178 m_CacheCleanTimer = new System.Timers.Timer(m_FileExpirationCleanupTimer.TotalMilliseconds); 181 m_CacheCleanTimer = new System.Timers.Timer(m_FileExpirationCleanupTimer.TotalMilliseconds);
179 m_CacheCleanTimer.AutoReset = true; 182 m_CacheCleanTimer.AutoReset = true;
@@ -226,7 +229,6 @@ namespace Flotsam.RegionModules.AssetCache
226 if (m_AssetService == null) 229 if (m_AssetService == null)
227 { 230 {
228 m_AssetService = scene.RequestModuleInterface<IAssetService>(); 231 m_AssetService = scene.RequestModuleInterface<IAssetService>();
229
230 } 232 }
231 } 233 }
232 } 234 }
@@ -250,138 +252,171 @@ namespace Flotsam.RegionModules.AssetCache
250 252
251 private void UpdateMemoryCache(string key, AssetBase asset) 253 private void UpdateMemoryCache(string key, AssetBase asset)
252 { 254 {
253 if (m_MemoryCacheEnabled) 255 m_MemoryCache.AddOrUpdate(key, asset, m_MemoryExpiration);
254 m_MemoryCache.AddOrUpdate(key, asset, m_MemoryExpiration);
255 } 256 }
256 257
257 public void Cache(AssetBase asset) 258 private void UpdateFileCache(string key, AssetBase asset)
258 { 259 {
259 // TODO: Spawn this off to some seperate thread to do the actual writing 260 string filename = GetFileName(asset.ID);
260 if (asset != null)
261 {
262 UpdateMemoryCache(asset.ID, asset);
263
264 string filename = GetFileName(asset.ID);
265 261
266 try 262 try
263 {
264 // If the file is already cached, don't cache it, just touch it so access time is updated
265 if (File.Exists(filename))
267 { 266 {
268 // If the file is already cached, don't cache it, just touch it so access time is updated 267 File.SetLastAccessTime(filename, DateTime.Now);
269 if (File.Exists(filename)) 268 }
269 else
270 {
271 // Once we start writing, make sure we flag that we're writing
272 // that object to the cache so that we don't try to write the
273 // same file multiple times.
274 lock (m_CurrentlyWriting)
270 { 275 {
271 File.SetLastAccessTime(filename, DateTime.Now);
272 } else {
273
274 // Once we start writing, make sure we flag that we're writing
275 // that object to the cache so that we don't try to write the
276 // same file multiple times.
277 lock (m_CurrentlyWriting)
278 {
279#if WAIT_ON_INPROGRESS_REQUESTS 276#if WAIT_ON_INPROGRESS_REQUESTS
280 if (m_CurrentlyWriting.ContainsKey(filename)) 277 if (m_CurrentlyWriting.ContainsKey(filename))
281 { 278 {
282 return; 279 return;
283 } 280 }
284 else 281 else
285 { 282 {
286 m_CurrentlyWriting.Add(filename, new ManualResetEvent(false)); 283 m_CurrentlyWriting.Add(filename, new ManualResetEvent(false));
287 } 284 }
288 285
289#else 286#else
290 if (m_CurrentlyWriting.Contains(filename)) 287 if (m_CurrentlyWriting.Contains(filename))
291 { 288 {
292 return; 289 return;
293 }
294 else
295 {
296 m_CurrentlyWriting.Add(filename);
297 }
298#endif
299
300 } 290 }
301 291 else
302 Util.FireAndForget( 292 {
303 delegate { WriteFileCache(filename, asset); }); 293 m_CurrentlyWriting.Add(filename);
294 }
295#endif
304 } 296 }
305 } 297
306 catch (Exception e) 298 Util.FireAndForget(
307 { 299 delegate { WriteFileCache(filename, asset); });
308 LogException(e);
309 } 300 }
310 } 301 }
302 catch (Exception e)
303 {
304 LogException(e);
305 }
311 } 306 }
312 307
313 public AssetBase Get(string id) 308 public void Cache(AssetBase asset)
314 { 309 {
315 m_Requests++; 310 // TODO: Spawn this off to some seperate thread to do the actual writing
311 if (asset != null)
312 {
313 //m_log.DebugFormat("[FLOTSAM ASSET CACHE]: Caching asset with id {0}", asset.ID);
314
315 if (m_MemoryCacheEnabled)
316 UpdateMemoryCache(asset.ID, asset);
317
318 if (m_FileCacheEnabled)
319 UpdateFileCache(asset.ID, asset);
320 }
321 }
316 322
323 /// <summary>
324 /// Try to get an asset from the in-memory cache.
325 /// </summary>
326 /// <param name="id"></param>
327 /// <returns></returns>
328 private AssetBase GetFromMemoryCache(string id)
329 {
317 AssetBase asset = null; 330 AssetBase asset = null;
318 331
319 if (m_MemoryCacheEnabled && m_MemoryCache.TryGetValue(id, out asset)) 332 if (m_MemoryCache.TryGetValue(id, out asset))
320 {
321 m_MemoryHits++; 333 m_MemoryHits++;
322 } 334
323 else 335 return asset;
336 }
337
338 /// <summary>
339 /// Try to get an asset from the file cache.
340 /// </summary>
341 /// <param name="id"></param>
342 /// <returns></returns>
343 private AssetBase GetFromFileCache(string id)
344 {
345 AssetBase asset = null;
346
347 string filename = GetFileName(id);
348 if (File.Exists(filename))
324 { 349 {
325 string filename = GetFileName(id); 350 FileStream stream = null;
326 if (File.Exists(filename)) 351 try
327 { 352 {
328 FileStream stream = null; 353 stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
329 try 354 BinaryFormatter bformatter = new BinaryFormatter();
330 {
331 stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
332 BinaryFormatter bformatter = new BinaryFormatter();
333 355
334 asset = (AssetBase)bformatter.Deserialize(stream); 356 asset = (AssetBase)bformatter.Deserialize(stream);
335 357
336 UpdateMemoryCache(id, asset); 358 UpdateMemoryCache(id, asset);
337 359
338 m_DiskHits++; 360 m_DiskHits++;
339 } 361 }
340 catch (System.Runtime.Serialization.SerializationException e) 362 catch (System.Runtime.Serialization.SerializationException e)
341 { 363 {
342 LogException(e); 364 LogException(e);
343 365
344 // If there was a problem deserializing the asset, the asset may 366 // If there was a problem deserializing the asset, the asset may
345 // either be corrupted OR was serialized under an old format 367 // either be corrupted OR was serialized under an old format
346 // {different version of AssetBase} -- we should attempt to 368 // {different version of AssetBase} -- we should attempt to
347 // delete it and re-cache 369 // delete it and re-cache
348 File.Delete(filename); 370 File.Delete(filename);
349 } 371 }
350 catch (Exception e) 372 catch (Exception e)
351 { 373 {
352 LogException(e); 374 LogException(e);
353 } 375 }
354 finally 376 finally
355 { 377 {
356 if (stream != null) 378 if (stream != null)
357 stream.Close(); 379 stream.Close();
358 }
359 } 380 }
381 }
360 382
361 383
362#if WAIT_ON_INPROGRESS_REQUESTS 384#if WAIT_ON_INPROGRESS_REQUESTS
363 // Check if we're already downloading this asset. If so, try to wait for it to 385 // Check if we're already downloading this asset. If so, try to wait for it to
364 // download. 386 // download.
365 if (m_WaitOnInprogressTimeout > 0) 387 if (m_WaitOnInprogressTimeout > 0)
366 { 388 {
367 m_RequestsForInprogress++; 389 m_RequestsForInprogress++;
368 390
369 ManualResetEvent waitEvent; 391 ManualResetEvent waitEvent;
370 if (m_CurrentlyWriting.TryGetValue(filename, out waitEvent)) 392 if (m_CurrentlyWriting.TryGetValue(filename, out waitEvent))
371 {
372 waitEvent.WaitOne(m_WaitOnInprogressTimeout);
373 return Get(id);
374 }
375 }
376#else
377 // Track how often we have the problem that an asset is requested while
378 // it is still being downloaded by a previous request.
379 if (m_CurrentlyWriting.Contains(filename))
380 { 393 {
381 m_RequestsForInprogress++; 394 waitEvent.WaitOne(m_WaitOnInprogressTimeout);
395 return Get(id);
382 } 396 }
383#endif
384 } 397 }
398#else
399 // Track how often we have the problem that an asset is requested while
400 // it is still being downloaded by a previous request.
401 if (m_CurrentlyWriting.Contains(filename))
402 {
403 m_RequestsForInprogress++;
404 }
405#endif
406
407 return asset;
408 }
409
410 public AssetBase Get(string id)
411 {
412 m_Requests++;
413
414 AssetBase asset = null;
415
416 if (m_MemoryCacheEnabled)
417 asset = GetFromMemoryCache(id);
418 else if (m_FileCacheEnabled)
419 asset = GetFromFileCache(id);
385 420
386 if (((m_LogLevel >= 1)) && (m_HitRateDisplay != 0) && (m_Requests % m_HitRateDisplay == 0)) 421 if (((m_LogLevel >= 1)) && (m_HitRateDisplay != 0) && (m_Requests % m_HitRateDisplay == 0))
387 { 422 {
@@ -415,10 +450,13 @@ namespace Flotsam.RegionModules.AssetCache
415 450
416 try 451 try
417 { 452 {
418 string filename = GetFileName(id); 453 if (m_FileCacheEnabled)
419 if (File.Exists(filename))
420 { 454 {
421 File.Delete(filename); 455 string filename = GetFileName(id);
456 if (File.Exists(filename))
457 {
458 File.Delete(filename);
459 }
422 } 460 }
423 461
424 if (m_MemoryCacheEnabled) 462 if (m_MemoryCacheEnabled)
@@ -433,11 +471,14 @@ namespace Flotsam.RegionModules.AssetCache
433 public void Clear() 471 public void Clear()
434 { 472 {
435 if (m_LogLevel >= 2) 473 if (m_LogLevel >= 2)
436 m_log.Debug("[FLOTSAM ASSET CACHE]: Clearing Cache."); 474 m_log.Debug("[FLOTSAM ASSET CACHE]: Clearing caches.");
437 475
438 foreach (string dir in Directory.GetDirectories(m_CacheDirectory)) 476 if (m_FileCacheEnabled)
439 { 477 {
440 Directory.Delete(dir); 478 foreach (string dir in Directory.GetDirectories(m_CacheDirectory))
479 {
480 Directory.Delete(dir);
481 }
441 } 482 }
442 483
443 if (m_MemoryCacheEnabled) 484 if (m_MemoryCacheEnabled)
@@ -472,9 +513,9 @@ namespace Flotsam.RegionModules.AssetCache
472 /// removes empty tier directories. 513 /// removes empty tier directories.
473 /// </summary> 514 /// </summary>
474 /// <param name="dir"></param> 515 /// <param name="dir"></param>
516 /// <param name="purgeLine"></param>
475 private void CleanExpiredFiles(string dir, DateTime purgeLine) 517 private void CleanExpiredFiles(string dir, DateTime purgeLine)
476 { 518 {
477
478 foreach (string file in Directory.GetFiles(dir)) 519 foreach (string file in Directory.GetFiles(dir))
479 { 520 {
480 if (File.GetLastAccessTime(file) < purgeLine) 521 if (File.GetLastAccessTime(file) < purgeLine)
@@ -712,18 +753,28 @@ namespace Flotsam.RegionModules.AssetCache
712 switch (cmd) 753 switch (cmd)
713 { 754 {
714 case "status": 755 case "status":
715 m_log.InfoFormat("[FLOTSAM ASSET CACHE] Memory Cache : {0} assets", m_MemoryCache.Count); 756 if (m_MemoryCacheEnabled)
716 757 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Memory Cache : {0} assets", m_MemoryCache.Count);
717 int fileCount = GetFileCacheCount(m_CacheDirectory); 758 else
718 m_log.InfoFormat("[FLOTSAM ASSET CACHE] File Cache : {0} assets", fileCount); 759 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Memory cache disabled");
719 760
720 foreach (string s in Directory.GetFiles(m_CacheDirectory, "*.fac")) 761 if (m_FileCacheEnabled)
721 { 762 {
722 m_log.Info("[FLOTSAM ASSET CACHE] Deep Scans were performed on the following regions:"); 763 int fileCount = GetFileCacheCount(m_CacheDirectory);
723 764 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: File Cache : {0} assets", fileCount);
724 string RegionID = s.Remove(0,s.IndexOf("_")).Replace(".fac",""); 765
725 DateTime RegionDeepScanTMStamp = File.GetLastWriteTime(s); 766 foreach (string s in Directory.GetFiles(m_CacheDirectory, "*.fac"))
726 m_log.InfoFormat("[FLOTSAM ASSET CACHE] Region: {0}, {1}", RegionID, RegionDeepScanTMStamp.ToString("MM/dd/yyyy hh:mm:ss")); 767 {
768 m_log.Info("[FLOTSAM ASSET CACHE]: Deep Scans were performed on the following regions:");
769
770 string RegionID = s.Remove(0,s.IndexOf("_")).Replace(".fac","");
771 DateTime RegionDeepScanTMStamp = File.GetLastWriteTime(s);
772 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Region: {0}, {1}", RegionID, RegionDeepScanTMStamp.ToString("MM/dd/yyyy hh:mm:ss"));
773 }
774 }
775 else
776 {
777 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: File cache disabled");
727 } 778 }
728 779
729 break; 780 break;
@@ -731,7 +782,7 @@ namespace Flotsam.RegionModules.AssetCache
731 case "clear": 782 case "clear":
732 if (cmdparams.Length < 2) 783 if (cmdparams.Length < 2)
733 { 784 {
734 m_log.Warn("[FLOTSAM ASSET CACHE] Usage is fcache clear [file] [memory]"); 785 m_log.Warn("[FLOTSAM ASSET CACHE]: Usage is fcache clear [file] [memory]");
735 break; 786 break;
736 } 787 }
737 788
@@ -752,36 +803,48 @@ namespace Flotsam.RegionModules.AssetCache
752 803
753 if (clearMemory) 804 if (clearMemory)
754 { 805 {
755 m_MemoryCache.Clear(); 806 if (m_MemoryCacheEnabled)
756 m_log.Info("[FLOTSAM ASSET CACHE] Memory cache cleared."); 807 {
808 m_MemoryCache.Clear();
809 m_log.Info("[FLOTSAM ASSET CACHE]: Memory cache cleared.");
810 }
811 else
812 {
813 m_log.Info("[FLOTSAM ASSET CACHE]: Memory cache not enabled.");
814 }
757 } 815 }
758 816
759 if (clearFile) 817 if (clearFile)
760 { 818 {
761 ClearFileCache(); 819 if (m_FileCacheEnabled)
762 m_log.Info("[FLOTSAM ASSET CACHE] File cache cleared."); 820 {
821 ClearFileCache();
822 m_log.Info("[FLOTSAM ASSET CACHE]: File cache cleared.");
823 }
824 else
825 {
826 m_log.Info("[FLOTSAM ASSET CACHE]: File cache not enabled.");
827 }
763 } 828 }
764 829
765 break; 830 break;
766 831
767 832
768 case "assets": 833 case "assets":
769 m_log.Info("[FLOTSAM ASSET CACHE] Caching all assets, in all scenes."); 834 m_log.Info("[FLOTSAM ASSET CACHE]: Caching all assets, in all scenes.");
770 835
771 Util.FireAndForget(delegate { 836 Util.FireAndForget(delegate {
772 int assetsCached = CacheScenes(); 837 int assetsCached = CacheScenes();
773 m_log.InfoFormat("[FLOTSAM ASSET CACHE] Completed Scene Caching, {0} assets found.", assetsCached); 838 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Completed Scene Caching, {0} assets found.", assetsCached);
774 839
775 }); 840 });
776 841
777 break; 842 break;
778 843
779 case "expire": 844 case "expire":
780
781
782 if (cmdparams.Length < 3) 845 if (cmdparams.Length < 3)
783 { 846 {
784 m_log.InfoFormat("[FLOTSAM ASSET CACHE] Invalid parameters for Expire, please specify a valid date & time", cmd); 847 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Invalid parameters for Expire, please specify a valid date & time", cmd);
785 break; 848 break;
786 } 849 }
787 850
@@ -799,26 +862,28 @@ namespace Flotsam.RegionModules.AssetCache
799 862
800 if (!DateTime.TryParse(s_expirationDate, out expirationDate)) 863 if (!DateTime.TryParse(s_expirationDate, out expirationDate))
801 { 864 {
802 m_log.InfoFormat("[FLOTSAM ASSET CACHE] {0} is not a valid date & time", cmd); 865 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: {0} is not a valid date & time", cmd);
803 break; 866 break;
804 } 867 }
805 868
806 CleanExpiredFiles(m_CacheDirectory, expirationDate); 869 if (m_FileCacheEnabled)
870 CleanExpiredFiles(m_CacheDirectory, expirationDate);
871 else
872 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: File cache not active, not clearing.");
807 873
808 break; 874 break;
809 default: 875 default:
810 m_log.InfoFormat("[FLOTSAM ASSET CACHE] Unknown command {0}", cmd); 876 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Unknown command {0}", cmd);
811 break; 877 break;
812 } 878 }
813 } 879 }
814 else if (cmdparams.Length == 1) 880 else if (cmdparams.Length == 1)
815 { 881 {
816 m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache status - Display cache status"); 882 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: fcache status - Display cache status");
817 m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache clearmem - Remove all assets cached in memory"); 883 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: fcache clearmem - Remove all assets cached in memory");
818 m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache clearfile - Remove all assets cached on disk"); 884 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: fcache clearfile - Remove all assets cached on disk");
819 m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache cachescenes - Attempt a deep cache of all assets in all scenes"); 885 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: fcache cachescenes - Attempt a deep cache of all assets in all scenes");
820 m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache <datetime> - Purge assets older then the specified date & time"); 886 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: fcache <datetime> - Purge assets older then the specified date & time");
821
822 } 887 }
823 } 888 }
824 889
diff --git a/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs b/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs
new file mode 100644
index 0000000..63b0c31
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs
@@ -0,0 +1,127 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Reflection;
32using System.Threading;
33using log4net.Config;
34using Nini.Config;
35using NUnit.Framework;
36using OpenMetaverse;
37using OpenMetaverse.Assets;
38using Flotsam.RegionModules.AssetCache;
39using OpenSim.Framework;
40using OpenSim.Region.Framework.Scenes;
41using OpenSim.Region.Framework.Scenes.Serialization;
42using OpenSim.Tests.Common;
43using OpenSim.Tests.Common.Mock;
44
45namespace OpenSim.Region.CoreModules.Asset.Tests
46{
47 /// <summary>
48 /// At the moment we're only test the in-memory part of the FlotsamAssetCache. This is a considerable weakness.
49 /// </summary>
50 [TestFixture]
51 public class FlotsamAssetCacheTests
52 {
53 protected TestScene m_scene;
54 protected FlotsamAssetCache m_cache;
55
56 [SetUp]
57 public void SetUp()
58 {
59 IConfigSource config = new IniConfigSource();
60
61 config.AddConfig("Modules");
62 config.Configs["Modules"].Set("AssetCaching", "FlotsamAssetCache");
63 config.AddConfig("AssetCache");
64 config.Configs["AssetCache"].Set("FileCacheEnabled", "false");
65 config.Configs["AssetCache"].Set("MemoryCacheEnabled", "true");
66
67 m_cache = new FlotsamAssetCache();
68 m_scene = SceneSetupHelpers.SetupScene();
69 SceneSetupHelpers.SetupSceneModules(m_scene, config, m_cache);
70 }
71
72 [Test]
73 public void TestCacheAsset()
74 {
75 TestHelper.InMethod();
76// log4net.Config.XmlConfigurator.Configure();
77
78 AssetBase asset = AssetHelpers.CreateAsset();
79 asset.ID = TestHelper.ParseTail(0x1).ToString();
80
81 // Check we don't get anything before the asset is put in the cache
82 AssetBase retrievedAsset = m_cache.Get(asset.ID.ToString());
83 Assert.That(retrievedAsset, Is.Null);
84
85 m_cache.Store(asset);
86
87 // Check that asset is now in cache
88 retrievedAsset = m_cache.Get(asset.ID.ToString());
89 Assert.That(retrievedAsset, Is.Not.Null);
90 Assert.That(retrievedAsset.ID, Is.EqualTo(asset.ID));
91 }
92
93 [Test]
94 public void TestExpireAsset()
95 {
96 TestHelper.InMethod();
97// log4net.Config.XmlConfigurator.Configure();
98
99 AssetBase asset = AssetHelpers.CreateAsset();
100 asset.ID = TestHelper.ParseTail(0x2).ToString();
101
102 m_cache.Store(asset);
103
104 m_cache.Expire(asset.ID);
105
106 AssetBase retrievedAsset = m_cache.Get(asset.ID.ToString());
107 Assert.That(retrievedAsset, Is.Null);
108 }
109
110 [Test]
111 public void TestClearCache()
112 {
113 TestHelper.InMethod();
114// log4net.Config.XmlConfigurator.Configure();
115
116 AssetBase asset = AssetHelpers.CreateAsset();
117 asset.ID = TestHelper.ParseTail(0x2).ToString();
118
119 m_cache.Store(asset);
120
121 m_cache.Clear();
122
123 AssetBase retrievedAsset = m_cache.Get(asset.ID.ToString());
124 Assert.That(retrievedAsset, Is.Null);
125 }
126 }
127} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
index e92f072..1955e5b 100644
--- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
@@ -116,16 +116,20 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
116 #endregion 116 #endregion
117 117
118 /// <summary> 118 /// <summary>
119 /// Check for the existence of the baked texture assets. Request a rebake 119 /// Check for the existence of the baked texture assets.
120 /// unless checkonly is true.
121 /// </summary> 120 /// </summary>
122 /// <param name="client"></param> 121 /// <param name="client"></param>
123 /// <param name="checkonly"></param>
124 public bool ValidateBakedTextureCache(IClientAPI client) 122 public bool ValidateBakedTextureCache(IClientAPI client)
125 { 123 {
126 return ValidateBakedTextureCache(client, true); 124 return ValidateBakedTextureCache(client, true);
127 } 125 }
128 126
127 /// <summary>
128 /// Check for the existence of the baked texture assets. Request a rebake
129 /// unless checkonly is true.
130 /// </summary>
131 /// <param name="client"></param>
132 /// <param name="checkonly"></param>
129 private bool ValidateBakedTextureCache(IClientAPI client, bool checkonly) 133 private bool ValidateBakedTextureCache(IClientAPI client, bool checkonly)
130 { 134 {
131 ScenePresence sp = m_scene.GetScenePresence(client.AgentId); 135 ScenePresence sp = m_scene.GetScenePresence(client.AgentId);
@@ -156,18 +160,20 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
156 160
157 defonly = false; // found a non-default texture reference 161 defonly = false; // found a non-default texture reference
158 162
159 if (! CheckBakedTextureAsset(client,face.TextureID,idx)) 163 if (!CheckBakedTextureAsset(client, face.TextureID, idx))
160 { 164 {
161 // the asset didn't exist if we are only checking, then we found a bad 165 // the asset didn't exist if we are only checking, then we found a bad
162 // one and we're done otherwise, ask for a rebake 166 // one and we're done otherwise, ask for a rebake
163 if (checkonly) return false; 167 if (checkonly)
168 return false;
164 169
165 m_log.InfoFormat("[AVFACTORY]: missing baked texture {0}, requesting rebake",face.TextureID); 170 m_log.InfoFormat("[AVFACTORY]: missing baked texture {0}, requesting rebake", face.TextureID);
171
166 client.SendRebakeAvatarTextures(face.TextureID); 172 client.SendRebakeAvatarTextures(face.TextureID);
167 } 173 }
168 } 174 }
169 175
170 m_log.DebugFormat("[AVFACTORY]: completed texture check for {0}", client.AgentId); 176 m_log.DebugFormat("[AVFACTORY]: Completed texture check for {0}", client.AgentId);
171 177
172 // If we only found default textures, then the appearance is not cached 178 // If we only found default textures, then the appearance is not cached
173 return (defonly ? false : true); 179 return (defonly ? false : true);
@@ -183,7 +189,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
183 ScenePresence sp = m_scene.GetScenePresence(client.AgentId); 189 ScenePresence sp = m_scene.GetScenePresence(client.AgentId);
184 if (sp == null) 190 if (sp == null)
185 { 191 {
186 m_log.WarnFormat("[AVFACTORY]: SetAppearance unable to find presence for {0}",client.AgentId); 192 m_log.WarnFormat("[AVFACTORY]: SetAppearance unable to find presence for {0}", client.AgentId);
187 return; 193 return;
188 } 194 }
189 195
@@ -211,7 +217,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
211 changed = sp.Appearance.SetTextureEntries(textureEntry) || changed; 217 changed = sp.Appearance.SetTextureEntries(textureEntry) || changed;
212 218
213 m_log.InfoFormat("[AVFACTORY]: received texture update for {0}", client.AgentId); 219 m_log.InfoFormat("[AVFACTORY]: received texture update for {0}", client.AgentId);
214 Util.FireAndForget(delegate(object o) { ValidateBakedTextureCache(client,false); }); 220 Util.FireAndForget(delegate(object o) { ValidateBakedTextureCache(client, false); });
215 221
216 // This appears to be set only in the final stage of the appearance 222 // This appears to be set only in the final stage of the appearance
217 // update transaction. In theory, we should be able to do an immediate 223 // update transaction. In theory, we should be able to do an immediate
@@ -220,9 +226,9 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
220 // save only if there were changes, send no matter what (doesn't hurt to send twice) 226 // save only if there were changes, send no matter what (doesn't hurt to send twice)
221 if (changed) 227 if (changed)
222 QueueAppearanceSave(client.AgentId); 228 QueueAppearanceSave(client.AgentId);
229
223 QueueAppearanceSend(client.AgentId); 230 QueueAppearanceSend(client.AgentId);
224 } 231 }
225
226 } 232 }
227 233
228 // m_log.WarnFormat("[AVFACTORY]: complete SetAppearance for {0}:\n{1}",client.AgentId,sp.Appearance.ToString()); 234 // m_log.WarnFormat("[AVFACTORY]: complete SetAppearance for {0}:\n{1}",client.AgentId,sp.Appearance.ToString());
diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs
new file mode 100644
index 0000000..07de908
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs
@@ -0,0 +1,69 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using NUnit.Framework;
30using OpenMetaverse;
31using OpenSim.Framework;
32using OpenSim.Region.Framework.Scenes;
33using OpenSim.Tests.Common;
34using OpenSim.Tests.Common.Mock;
35
36namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
37{
38 [TestFixture]
39 public class AvatarFactoryModuleTests
40 {
41 /// <summary>
42 /// Only partial right now since we don't yet test that it's ended up in the avatar appearance service.
43 /// </summary>
44 [Test]
45 public void TestSetAppearance()
46 {
47 TestHelper.InMethod();
48// log4net.Config.XmlConfigurator.Configure();
49
50 UUID userId = TestHelper.ParseTail(0x1);
51
52 AvatarFactoryModule afm = new AvatarFactoryModule();
53 TestScene scene = SceneSetupHelpers.SetupScene();
54 SceneSetupHelpers.SetupSceneModules(scene, afm);
55 TestClient tc = SceneSetupHelpers.AddClient(scene, userId);
56
57 byte[] visualParams = new byte[AvatarAppearance.VISUALPARAM_COUNT];
58 for (byte i = 0; i < visualParams.Length; i++)
59 visualParams[i] = i;
60
61 afm.SetAppearance(tc, new Primitive.TextureEntry(TestHelper.ParseTail(0x10)), visualParams);
62
63 ScenePresence sp = scene.GetScenePresence(userId);
64
65 // TODO: Check baked texture
66 Assert.AreEqual(visualParams, sp.Appearance.VisualParams);
67 }
68 }
69} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
index daee4ca..3a7178c 100644
--- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
@@ -830,7 +830,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
830 830
831 public bool LocalStatusNotification(UUID userID, UUID friendID, bool online) 831 public bool LocalStatusNotification(UUID userID, UUID friendID, bool online)
832 { 832 {
833 m_log.DebugFormat("[FRIENDS]: Local Status Notify {0} that user {1} is {2}", friendID, userID, online); 833// m_log.DebugFormat("[FRIENDS]: Local Status Notify {0} that user {1} is {2}", friendID, userID, online);
834 IClientAPI friendClient = LocateClientObject(friendID); 834 IClientAPI friendClient = LocateClientObject(friendID);
835 if (friendClient != null) 835 if (friendClient != null)
836 { 836 {
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
index 1341533..457ee33 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
@@ -50,6 +50,17 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
50 { 50 {
51 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 51 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
52 52
53 /// <summary>
54 /// The maximum distance, in standard region units (256m) that an agent is allowed to transfer.
55 /// </summary>
56 private int m_MaxTransferDistance = 4095;
57 public int MaxTransferDistance
58 {
59 get { return m_MaxTransferDistance; }
60 set { m_MaxTransferDistance = value; }
61 }
62
63
53 protected bool m_Enabled = false; 64 protected bool m_Enabled = false;
54 protected Scene m_aScene; 65 protected Scene m_aScene;
55 protected List<Scene> m_Scenes = new List<Scene>(); 66 protected List<Scene> m_Scenes = new List<Scene>();
@@ -78,13 +89,26 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
78 string name = moduleConfig.GetString("EntityTransferModule", ""); 89 string name = moduleConfig.GetString("EntityTransferModule", "");
79 if (name == Name) 90 if (name == Name)
80 { 91 {
81 m_agentsInTransit = new List<UUID>(); 92 InitialiseCommon(source);
82 m_Enabled = true; 93 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: {0} enabled.", Name);
83 m_log.InfoFormat("[ENTITY TRANSFER MODULE]: {0} enabled.", Name);
84 } 94 }
85 } 95 }
86 } 96 }
87 97
98 /// <summary>
99 /// Initialize config common for this module and any descendents.
100 /// </summary>
101 /// <param name="source"></param>
102 protected virtual void InitialiseCommon(IConfigSource source)
103 {
104 IConfig transferConfig = source.Configs["EntityTransfer"];
105 if (transferConfig != null)
106 MaxTransferDistance = transferConfig.GetInt("max_distance", 4095);
107
108 m_agentsInTransit = new List<UUID>();
109 m_Enabled = true;
110 }
111
88 public virtual void PostInitialise() 112 public virtual void PostInitialise()
89 { 113 {
90 } 114 }
@@ -114,7 +138,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
114 return; 138 return;
115 } 139 }
116 140
117
118 public virtual void RemoveRegion(Scene scene) 141 public virtual void RemoveRegion(Scene scene)
119 { 142 {
120 if (!m_Enabled) 143 if (!m_Enabled)
@@ -129,7 +152,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
129 { 152 {
130 if (!m_Enabled) 153 if (!m_Enabled)
131 return; 154 return;
132
133 } 155 }
134 156
135 #endregion 157 #endregion
@@ -204,8 +226,18 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
204 sp.ControllingClient.SendTeleportFailed("Problem at destination"); 226 sp.ControllingClient.SendTeleportFailed("Problem at destination");
205 return; 227 return;
206 } 228 }
207 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Final destination is x={0} y={1} {2}@{3}", 229
208 finalDestination.RegionLocX / Constants.RegionSize, finalDestination.RegionLocY / Constants.RegionSize, finalDestination.RegionID, finalDestination.ServerURI); 230 uint curX = 0, curY = 0;
231 Utils.LongToUInts(sp.Scene.RegionInfo.RegionHandle, out curX, out curY);
232 int curCellX = (int)(curX / Constants.RegionSize);
233 int curCellY = (int)(curY / Constants.RegionSize);
234 int destCellX = (int)(finalDestination.RegionLocX / Constants.RegionSize);
235 int destCellY = (int)(finalDestination.RegionLocY / Constants.RegionSize);
236
237// m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Source co-ords are x={0} y={1}", curRegionX, curRegionY);
238//
239// m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Final dest is x={0} y={1} {2}@{3}",
240// destRegionX, destRegionY, finalDestination.RegionID, finalDestination.ServerURI);
209 241
210 // Check that these are not the same coordinates 242 // Check that these are not the same coordinates
211 if (finalDestination.RegionLocX == sp.Scene.RegionInfo.RegionLocX && 243 if (finalDestination.RegionLocX == sp.Scene.RegionInfo.RegionLocX &&
@@ -216,6 +248,18 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
216 return; 248 return;
217 } 249 }
218 250
251 if (Math.Abs(curCellX - destCellX) > MaxTransferDistance || Math.Abs(curCellY - destCellY) > MaxTransferDistance)
252 {
253 sp.ControllingClient.SendTeleportFailed(
254 string.Format(
255 "Can't teleport to {0} ({1},{2}) from {3} ({4},{5}), destination is more than {6} regions way",
256 finalDestination.RegionName, destCellX, destCellY,
257 sp.Scene.RegionInfo.RegionName, curCellX, curCellY,
258 MaxTransferDistance));
259
260 return;
261 }
262
219 // 263 //
220 // This is it 264 // This is it
221 // 265 //
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
index 4d77ef4..a87279a 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
@@ -67,10 +67,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
67 string name = moduleConfig.GetString("EntityTransferModule", ""); 67 string name = moduleConfig.GetString("EntityTransferModule", "");
68 if (name == Name) 68 if (name == Name)
69 { 69 {
70 m_agentsInTransit = new List<UUID>(); 70 InitialiseCommon(source);
71 71 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: {0} enabled.", Name);
72 m_Enabled = true;
73 m_log.InfoFormat("[HG ENTITY TRANSFER MODULE]: {0} enabled.", Name);
74 } 72 }
75 } 73 }
76 } 74 }
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
index 2930303..66fbcb9 100644
--- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
@@ -978,7 +978,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
978 { 978 {
979 } 979 }
980 980
981 public virtual bool GetAgentInventoryItem(IClientAPI remoteClient, UUID itemID, UUID requestID) 981 public virtual bool CanGetAgentInventoryItem(IClientAPI remoteClient, UUID itemID, UUID requestID)
982 { 982 {
983 InventoryItemBase assetRequestItem = GetItem(remoteClient.AgentId, itemID); 983 InventoryItemBase assetRequestItem = GetItem(remoteClient.AgentId, itemID);
984 if (assetRequestItem == null) 984 if (assetRequestItem == null)
@@ -1057,7 +1057,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
1057 InventoryItemBase item = new InventoryItemBase(itemID, agentID); 1057 InventoryItemBase item = new InventoryItemBase(itemID, agentID);
1058 item = invService.GetItem(item); 1058 item = invService.GetItem(item);
1059 1059
1060 if (item.CreatorData != null && item.CreatorData != string.Empty) 1060 if (item != null && item.CreatorData != null && item.CreatorData != string.Empty)
1061 UserManagementModule.AddUser(item.CreatorIdAsUuid, item.CreatorData); 1061 UserManagementModule.AddUser(item.CreatorIdAsUuid, item.CreatorData);
1062 1062
1063 return item; 1063 return item;
@@ -1065,4 +1065,4 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
1065 1065
1066 #endregion 1066 #endregion
1067 } 1067 }
1068} 1068} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs
index accd094..a4861ec 100644
--- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs
@@ -297,9 +297,10 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
297 if (m_UserCache.ContainsKey(id)) 297 if (m_UserCache.ContainsKey(id))
298 return; 298 return;
299 299
300// m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, craetorData {1}", id, creatorData);
301
300 UserData user = new UserData(); 302 UserData user = new UserData();
301 user.Id = id; 303 user.Id = id;
302
303 UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, id); 304 UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, id);
304 305
305 if (account != null) 306 if (account != null)
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs
index 6dd871f..0c57618 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs
@@ -284,9 +284,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
284 284
285 item = m_InventoryService.GetItem(item); 285 item = m_InventoryService.GetItem(item);
286 286
287 if (null == item) 287// if (null == item)
288 m_log.ErrorFormat( 288// m_log.ErrorFormat(
289 "[LOCAL INVENTORY SERVICES CONNECTOR]: Could not find item with id {0}", requestedItemId); 289// "[LOCAL INVENTORY SERVICES CONNECTOR]: Could not find item with id {0}", requestedItemId);
290 290
291 return item; 291 return item;
292 } 292 }
diff --git a/OpenSim/Region/CoreModules/World/Land/LandObject.cs b/OpenSim/Region/CoreModules/World/Land/LandObject.cs
index 560b862..8c40171 100644
--- a/OpenSim/Region/CoreModules/World/Land/LandObject.cs
+++ b/OpenSim/Region/CoreModules/World/Land/LandObject.cs
@@ -418,7 +418,7 @@ namespace OpenSim.Region.CoreModules.World.Land
418 418
419 public bool IsBannedFromLand(UUID avatar) 419 public bool IsBannedFromLand(UUID avatar)
420 { 420 {
421 if (m_scene.Permissions.IsAdministrator(avatar)) 421 if (m_scene.Permissions.CanEditParcelProperties(avatar, this, 0))
422 return false; 422 return false;
423 423
424 if ((LandData.Flags & (uint) ParcelFlags.UseBanList) > 0) 424 if ((LandData.Flags & (uint) ParcelFlags.UseBanList) > 0)
@@ -429,7 +429,7 @@ namespace OpenSim.Region.CoreModules.World.Land
429 if (e.AgentID == avatar && e.Flags == AccessList.Ban) 429 if (e.AgentID == avatar && e.Flags == AccessList.Ban)
430 return true; 430 return true;
431 return false; 431 return false;
432 }) != -1 && LandData.OwnerID != avatar) 432 }) != -1)
433 { 433 {
434 return true; 434 return true;
435 } 435 }
@@ -439,7 +439,7 @@ namespace OpenSim.Region.CoreModules.World.Land
439 439
440 public bool IsRestrictedFromLand(UUID avatar) 440 public bool IsRestrictedFromLand(UUID avatar)
441 { 441 {
442 if (m_scene.Permissions.IsAdministrator(avatar)) 442 if (m_scene.Permissions.CanEditParcelProperties(avatar, this, 0))
443 return false; 443 return false;
444 444
445 if ((LandData.Flags & (uint) ParcelFlags.UseAccessList) > 0) 445 if ((LandData.Flags & (uint) ParcelFlags.UseAccessList) > 0)
@@ -450,7 +450,7 @@ namespace OpenSim.Region.CoreModules.World.Land
450 if (e.AgentID == avatar && e.Flags == AccessList.Access) 450 if (e.AgentID == avatar && e.Flags == AccessList.Access)
451 return true; 451 return true;
452 return false; 452 return false;
453 }) == -1 && LandData.OwnerID != avatar) 453 }) == -1)
454 { 454 {
455 return true; 455 return true;
456 } 456 }
diff --git a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
index d7324c6..a40517c 100644
--- a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
+++ b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
@@ -134,7 +134,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions
134 return; 134 return;
135 135
136 m_allowGridGods = myConfig.GetBoolean("allow_grid_gods", false); 136 m_allowGridGods = myConfig.GetBoolean("allow_grid_gods", false);
137 m_bypassPermissions = !myConfig.GetBoolean("serverside_object_permissions", false); 137 m_bypassPermissions = !myConfig.GetBoolean("serverside_object_permissions", true);
138 m_propagatePermissions = myConfig.GetBoolean("propagate_permissions", true); 138 m_propagatePermissions = myConfig.GetBoolean("propagate_permissions", true);
139 m_RegionOwnerIsGod = myConfig.GetBoolean("region_owner_is_god", true); 139 m_RegionOwnerIsGod = myConfig.GetBoolean("region_owner_is_god", true);
140 m_RegionManagerIsGod = myConfig.GetBoolean("region_manager_is_god", false); 140 m_RegionManagerIsGod = myConfig.GetBoolean("region_manager_is_god", false);
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs
index 00959b0..2e3b21f 100644
--- a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs
+++ b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs
@@ -91,6 +91,8 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
91 remoteClient.SendAlertMessage("Use a search string with at least 3 characters"); 91 remoteClient.SendAlertMessage("Use a search string with at least 3 characters");
92 return; 92 return;
93 } 93 }
94
95m_log.DebugFormat("MAP NAME=({0})", mapName);
94 96
95 // try to fetch from GridServer 97 // try to fetch from GridServer
96 List<GridRegion> regionInfos = m_scene.GridService.GetRegionsByName(m_scene.RegionInfo.ScopeID, mapName, 20); 98 List<GridRegion> regionInfos = m_scene.GridService.GetRegionsByName(m_scene.RegionInfo.ScopeID, mapName, 20);
@@ -103,7 +105,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
103 if (info != null) 105 if (info != null)
104 regionInfos.Add(info); 106 regionInfos.Add(info);
105 } 107 }
106 else if (regionInfos.Count == 0 && mapName.StartsWith("http://")) 108 else if (regionInfos.Count == 0)
107 remoteClient.SendAlertMessage("Hyperlink could not be established."); 109 remoteClient.SendAlertMessage("Hyperlink could not be established.");
108 110
109 m_log.DebugFormat("[MAPSEARCHMODULE]: search {0} returned {1} regions. Flags={2}", mapName, regionInfos.Count, flags); 111 m_log.DebugFormat("[MAPSEARCHMODULE]: search {0} returned {1} regions. Flags={2}", mapName, regionInfos.Count, flags);
diff --git a/OpenSim/Region/Framework/Interfaces/IAvatarFactory.cs b/OpenSim/Region/Framework/Interfaces/IAvatarFactory.cs
index 22795fc..d0e5609 100644
--- a/OpenSim/Region/Framework/Interfaces/IAvatarFactory.cs
+++ b/OpenSim/Region/Framework/Interfaces/IAvatarFactory.cs
@@ -36,4 +36,4 @@ namespace OpenSim.Region.Framework.Interfaces
36 void QueueAppearanceSend(UUID agentid); 36 void QueueAppearanceSend(UUID agentid);
37 void QueueAppearanceSave(UUID agentid); 37 void QueueAppearanceSave(UUID agentid);
38 } 38 }
39} 39} \ No newline at end of file
diff --git a/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs b/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs
index 305975e..da11e61 100644
--- a/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs
@@ -59,7 +59,15 @@ namespace OpenSim.Region.Framework.Interfaces
59 UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, 59 UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection,
60 bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment); 60 bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment);
61 void TransferInventoryAssets(InventoryItemBase item, UUID sender, UUID receiver); 61 void TransferInventoryAssets(InventoryItemBase item, UUID sender, UUID receiver);
62 bool GetAgentInventoryItem(IClientAPI remoteClient, UUID itemID, UUID requestID); 62
63 /// <summary>
64 /// Does the client have sufficient permissions to retrieve the inventory item?
65 /// </summary>
66 /// <param name="remoteClient"></param>
67 /// <param name="itemID"></param>
68 /// <param name="requestID"></param>
69 /// <returns></returns>
70 bool CanGetAgentInventoryItem(IClientAPI remoteClient, UUID itemID, UUID requestID);
63 71
64 // Must be here because of textures in user's inventory 72 // Must be here because of textures in user's inventory
65 bool IsForeignUser(UUID userID, out string assetServerURL); 73 bool IsForeignUser(UUID userID, out string assetServerURL);
diff --git a/OpenSim/Region/CoreModules/Avatar/NPC/INPCModule.cs b/OpenSim/Region/Framework/Interfaces/INPCModule.cs
index cd2fe4f..21a755f 100644
--- a/OpenSim/Region/CoreModules/Avatar/NPC/INPCModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/INPCModule.cs
@@ -28,7 +28,7 @@
28using OpenMetaverse; 28using OpenMetaverse;
29using OpenSim.Region.Framework.Scenes; 29using OpenSim.Region.Framework.Scenes;
30 30
31namespace OpenSim.Region.CoreModules.Avatar.NPC 31namespace OpenSim.Region.Framework.Interfaces
32{ 32{
33 public interface INPCModule 33 public interface INPCModule
34 { 34 {
diff --git a/OpenSim/Region/Framework/Scenes/AsyncInventorySender.cs b/OpenSim/Region/Framework/Scenes/AsyncInventorySender.cs
new file mode 100644
index 0000000..9cb5674
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/AsyncInventorySender.cs
@@ -0,0 +1,156 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Threading;
32using log4net;
33using OpenMetaverse;
34using OpenSim.Framework;
35using OpenSim.Region.Framework.Interfaces;
36
37namespace OpenSim.Region.Framework.Scenes
38{
39 class FetchHolder
40 {
41 public IClientAPI Client { get; private set; }
42 public UUID ItemID { get; private set; }
43
44 public FetchHolder(IClientAPI client, UUID itemID)
45 {
46 Client = client;
47 ItemID = itemID;
48 }
49 }
50
51 /// <summary>
52 /// Send FetchInventoryReply information to clients asynchronously on a single thread rather than asynchronously via
53 /// multiple threads.
54 /// </summary>
55 /// <remarks>
56 /// If the main root inventory is right-clicked on a version 1 viewer for a user with a large inventory, a very
57 /// very large number of FetchInventory requests are sent to the simulator. Each is handled on a separate thread
58 /// by the IClientAPI, but the sheer number of requests overwhelms the number of threads available and ends up
59 /// freezing the inbound packet handling.
60 ///
61 /// This class makes the first FetchInventory packet thread process the queue. If new requests come
62 /// in while it is processing, then the subsequent threads just add the requests and leave it to the original
63 /// thread to process them.
64 ///
65 /// This might slow down outbound packets but these are limited by the IClientAPI outbound queues
66 /// anyway.
67 ///
68 /// It might be possible to ignore FetchInventory requests altogether, particularly as they are redundant wrt to
69 /// FetchInventoryDescendents requests, but this would require more investigation.
70 /// </remarks>
71 public class AsyncInventorySender
72 {
73// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
74
75 protected Scene m_scene;
76
77 /// <summary>
78 /// Queues fetch requests
79 /// </summary>
80 Queue<FetchHolder> m_fetchHolder = new Queue<FetchHolder>();
81
82 /// <summary>
83 /// Signal whether a queue is currently being processed or not.
84 /// </summary>
85 protected volatile bool m_processing;
86
87 public AsyncInventorySender(Scene scene)
88 {
89 m_processing = false;
90 m_scene = scene;
91 }
92
93 /// <summary>
94 /// Handle a fetch inventory request from the client
95 /// </summary>
96 /// <param name="remoteClient"></param>
97 /// <param name="itemID"></param>
98 /// <param name="ownerID"></param>
99 public void HandleFetchInventory(IClientAPI remoteClient, UUID itemID, UUID ownerID)
100 {
101 lock (m_fetchHolder)
102 {
103// m_log.DebugFormat(
104// "[ASYNC INVENTORY SENDER]: Putting request from {0} for {1} on queue", remoteClient.Name, itemID);
105
106 m_fetchHolder.Enqueue(new FetchHolder(remoteClient, itemID));
107 }
108
109 if (!m_processing)
110 {
111 m_processing = true;
112 ProcessQueue();
113 }
114 }
115
116 /// <summary>
117 /// Process the queue of fetches
118 /// </summary>
119 protected void ProcessQueue()
120 {
121 FetchHolder fh = null;
122
123 while (true)
124 {
125 lock (m_fetchHolder)
126 {
127// m_log.DebugFormat("[ASYNC INVENTORY SENDER]: {0} items left to process", m_fetchHolder.Count);
128
129 if (m_fetchHolder.Count == 0)
130 {
131 m_processing = false;
132 return;
133 }
134 else
135 {
136 fh = m_fetchHolder.Dequeue();
137 }
138 }
139
140 if (fh.Client.IsLoggingOut)
141 continue;
142
143// m_log.DebugFormat(
144// "[ASYNC INVENTORY SENDER]: Handling request from {0} for {1} on queue", fh.Client.Name, fh.ItemID);
145
146 InventoryItemBase item = new InventoryItemBase(fh.ItemID, fh.Client.AgentId);
147 item = m_scene.InventoryService.GetItem(item);
148
149 if (item != null)
150 fh.Client.SendInventoryItemDetails(item.Owner, item);
151
152 // TODO: Possibly log any failure
153 }
154 }
155 }
156} \ No newline at end of file
diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
index f37f94a..30421d4 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
@@ -52,6 +52,11 @@ namespace OpenSim.Region.Framework.Scenes
52 protected AsyncSceneObjectGroupDeleter m_asyncSceneObjectDeleter; 52 protected AsyncSceneObjectGroupDeleter m_asyncSceneObjectDeleter;
53 53
54 /// <summary> 54 /// <summary>
55 /// Allows inventory details to be sent to clients asynchronously
56 /// </summary>
57 protected AsyncInventorySender m_asyncInventorySender;
58
59 /// <summary>
55 /// Start all the scripts in the scene which should be started. 60 /// Start all the scripts in the scene which should be started.
56 /// </summary> 61 /// </summary>
57 public void CreateScriptInstances() 62 public void CreateScriptInstances()
@@ -1328,7 +1333,7 @@ namespace OpenSim.Region.Framework.Scenes
1328// m_log.DebugFormat("[AGENT INVENTORY]: Sending inventory folder contents ({0} nodes) for \"{1}\" to {2} {3}", 1333// m_log.DebugFormat("[AGENT INVENTORY]: Sending inventory folder contents ({0} nodes) for \"{1}\" to {2} {3}",
1329// contents.Folders.Count + contents.Items.Count, containingFolder.Name, client.FirstName, client.LastName); 1334// contents.Folders.Count + contents.Items.Count, containingFolder.Name, client.FirstName, client.LastName);
1330 1335
1331 if (containingFolder != null && containingFolder != null) 1336 if (containingFolder != null)
1332 { 1337 {
1333 // If the folder requested contains links, then we need to send those folders first, otherwise the links 1338 // If the folder requested contains links, then we need to send those folders first, otherwise the links
1334 // will be broken in the viewer. 1339 // will be broken in the viewer.
@@ -1340,15 +1345,25 @@ namespace OpenSim.Region.Framework.Scenes
1340 InventoryItemBase linkedItem = InventoryService.GetItem(new InventoryItemBase(item.AssetID)); 1345 InventoryItemBase linkedItem = InventoryService.GetItem(new InventoryItemBase(item.AssetID));
1341 1346
1342 // Take care of genuinely broken links where the target doesn't exist 1347 // Take care of genuinely broken links where the target doesn't exist
1343 if (linkedItem != null) 1348 // HACK: Also, don't follow up links that just point to other links. In theory this is legitimate,
1344 linkedItemFolderIdsToSend.Add(linkedItem.Folder); 1349 // but no viewer has been observed to set these up and this is the lazy way of avoiding cycles
1350 // rather than having to keep track of every folder requested in the recursion.
1351 if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link)
1352 {
1353 // We don't need to send the folder if source and destination of the link are in the same
1354 // folder.
1355 if (linkedItem.Folder != containingFolder.ID)
1356 linkedItemFolderIdsToSend.Add(linkedItem.Folder);
1357 }
1345 } 1358 }
1346 } 1359 }
1347 1360
1348 foreach (UUID linkedItemFolderId in linkedItemFolderIdsToSend) 1361 foreach (UUID linkedItemFolderId in linkedItemFolderIdsToSend)
1349 SendInventoryUpdate(client, new InventoryFolderBase(linkedItemFolderId), false, true); 1362 SendInventoryUpdate(client, new InventoryFolderBase(linkedItemFolderId), false, true);
1350 1363
1351 client.SendInventoryFolderDetails(client.AgentId, folder.ID, contents.Items, contents.Folders, containingFolder.Version, fetchFolders, fetchItems); 1364 client.SendInventoryFolderDetails(
1365 client.AgentId, folder.ID, contents.Items, contents.Folders,
1366 containingFolder.Version, fetchFolders, fetchItems);
1352 } 1367 }
1353 } 1368 }
1354 1369
diff --git a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs
index e2d7208..44472b2 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs
@@ -461,31 +461,6 @@ namespace OpenSim.Region.Framework.Scenes
461 } 461 }
462 ); 462 );
463 } 463 }
464
465
466 /// <summary>
467 /// Handle a fetch inventory request from the client
468 /// </summary>
469 /// <param name="remoteClient"></param>
470 /// <param name="itemID"></param>
471 /// <param name="ownerID"></param>
472 public void HandleFetchInventory(IClientAPI remoteClient, UUID itemID, UUID ownerID)
473 {
474 if (LibraryService != null && LibraryService.LibraryRootFolder != null && ownerID == LibraryService.LibraryRootFolder.Owner)
475 {
476 //m_log.Debug("request info for library item");
477 return;
478 }
479
480 InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId);
481 item = InventoryService.GetItem(item);
482
483 if (item != null)
484 {
485 remoteClient.SendInventoryItemDetails(ownerID, item);
486 }
487 // else shouldn't we send an alert message?
488 }
489 464
490 /// <summary> 465 /// <summary>
491 /// Tell the client about the various child items and folders contained in the requested folder. 466 /// Tell the client about the various child items and folders contained in the requested folder.
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index bdf3d1d..8195a0d 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -583,6 +583,8 @@ namespace OpenSim.Region.Framework.Scenes
583 m_asyncSceneObjectDeleter = new AsyncSceneObjectGroupDeleter(this); 583 m_asyncSceneObjectDeleter = new AsyncSceneObjectGroupDeleter(this);
584 m_asyncSceneObjectDeleter.Enabled = true; 584 m_asyncSceneObjectDeleter.Enabled = true;
585 585
586 m_asyncInventorySender = new AsyncInventorySender(this);
587
586 #region Region Settings 588 #region Region Settings
587 589
588 // Load region settings 590 // Load region settings
@@ -1724,6 +1726,7 @@ namespace OpenSim.Region.Framework.Scenes
1724 /// <summary> 1726 /// <summary>
1725 /// Loads the World's objects 1727 /// Loads the World's objects
1726 /// </summary> 1728 /// </summary>
1729 /// <param name="regionID"></param>
1727 public virtual void LoadPrimsFromStorage(UUID regionID) 1730 public virtual void LoadPrimsFromStorage(UUID regionID)
1728 { 1731 {
1729 LoadingPrims = true; 1732 LoadingPrims = true;
@@ -2593,8 +2596,10 @@ namespace OpenSim.Region.Framework.Scenes
2593 { 2596 {
2594 string homeURL = string.Empty; 2597 string homeURL = string.Empty;
2595 string first = aCircuit.firstname, last = aCircuit.lastname; 2598 string first = aCircuit.firstname, last = aCircuit.lastname;
2599
2596 if (aCircuit.ServiceURLs.ContainsKey("HomeURI")) 2600 if (aCircuit.ServiceURLs.ContainsKey("HomeURI"))
2597 homeURL = aCircuit.ServiceURLs["HomeURI"].ToString(); 2601 homeURL = aCircuit.ServiceURLs["HomeURI"].ToString();
2602
2598 if (aCircuit.lastname.StartsWith("@")) 2603 if (aCircuit.lastname.StartsWith("@"))
2599 { 2604 {
2600 string[] parts = aCircuit.firstname.Split('.'); 2605 string[] parts = aCircuit.firstname.Split('.');
@@ -2604,6 +2609,7 @@ namespace OpenSim.Region.Framework.Scenes
2604 last = parts[1]; 2609 last = parts[1];
2605 } 2610 }
2606 } 2611 }
2612
2607 uMan.AddUser(aCircuit.AgentID, first, last, homeURL); 2613 uMan.AddUser(aCircuit.AgentID, first, last, homeURL);
2608 } 2614 }
2609 } 2615 }
@@ -2757,14 +2763,13 @@ namespace OpenSim.Region.Framework.Scenes
2757 2763
2758 public virtual void SubscribeToClientInventoryEvents(IClientAPI client) 2764 public virtual void SubscribeToClientInventoryEvents(IClientAPI client)
2759 { 2765 {
2760
2761 client.OnLinkInventoryItem += HandleLinkInventoryItem; 2766 client.OnLinkInventoryItem += HandleLinkInventoryItem;
2762 client.OnCreateNewInventoryFolder += HandleCreateInventoryFolder; 2767 client.OnCreateNewInventoryFolder += HandleCreateInventoryFolder;
2763 client.OnUpdateInventoryFolder += HandleUpdateInventoryFolder; 2768 client.OnUpdateInventoryFolder += HandleUpdateInventoryFolder;
2764 client.OnMoveInventoryFolder += HandleMoveInventoryFolder; // 2; //!! 2769 client.OnMoveInventoryFolder += HandleMoveInventoryFolder; // 2; //!!
2765 client.OnFetchInventoryDescendents += HandleFetchInventoryDescendents; 2770 client.OnFetchInventoryDescendents += HandleFetchInventoryDescendents;
2766 client.OnPurgeInventoryDescendents += HandlePurgeInventoryDescendents; // 2; //!! 2771 client.OnPurgeInventoryDescendents += HandlePurgeInventoryDescendents; // 2; //!!
2767 client.OnFetchInventory += HandleFetchInventory; 2772 client.OnFetchInventory += m_asyncInventorySender.HandleFetchInventory;
2768 client.OnUpdateInventoryItem += UpdateInventoryItemAsset; 2773 client.OnUpdateInventoryItem += UpdateInventoryItemAsset;
2769 client.OnCopyInventoryItem += CopyInventoryItem; 2774 client.OnCopyInventoryItem += CopyInventoryItem;
2770 client.OnMoveInventoryItem += MoveInventoryItem; 2775 client.OnMoveInventoryItem += MoveInventoryItem;
@@ -2883,13 +2888,12 @@ namespace OpenSim.Region.Framework.Scenes
2883 2888
2884 public virtual void UnSubscribeToClientInventoryEvents(IClientAPI client) 2889 public virtual void UnSubscribeToClientInventoryEvents(IClientAPI client)
2885 { 2890 {
2886
2887 client.OnCreateNewInventoryFolder -= HandleCreateInventoryFolder; 2891 client.OnCreateNewInventoryFolder -= HandleCreateInventoryFolder;
2888 client.OnUpdateInventoryFolder -= HandleUpdateInventoryFolder; 2892 client.OnUpdateInventoryFolder -= HandleUpdateInventoryFolder;
2889 client.OnMoveInventoryFolder -= HandleMoveInventoryFolder; // 2; //!! 2893 client.OnMoveInventoryFolder -= HandleMoveInventoryFolder; // 2; //!!
2890 client.OnFetchInventoryDescendents -= HandleFetchInventoryDescendents; 2894 client.OnFetchInventoryDescendents -= HandleFetchInventoryDescendents;
2891 client.OnPurgeInventoryDescendents -= HandlePurgeInventoryDescendents; // 2; //!! 2895 client.OnPurgeInventoryDescendents -= HandlePurgeInventoryDescendents; // 2; //!!
2892 client.OnFetchInventory -= HandleFetchInventory; 2896 client.OnFetchInventory -= m_asyncInventorySender.HandleFetchInventory;
2893 client.OnUpdateInventoryItem -= UpdateInventoryItemAsset; 2897 client.OnUpdateInventoryItem -= UpdateInventoryItemAsset;
2894 client.OnCopyInventoryItem -= CopyInventoryItem; 2898 client.OnCopyInventoryItem -= CopyInventoryItem;
2895 client.OnMoveInventoryItem -= MoveInventoryItem; 2899 client.OnMoveInventoryItem -= MoveInventoryItem;
@@ -3389,7 +3393,6 @@ namespace OpenSim.Region.Framework.Scenes
3389 } 3393 }
3390 } 3394 }
3391 3395
3392
3393 // In all cases, add or update the circuit data with the new agent circuit data and teleport flags 3396 // In all cases, add or update the circuit data with the new agent circuit data and teleport flags
3394 agent.teleportFlags = teleportFlags; 3397 agent.teleportFlags = teleportFlags;
3395 m_authenticateHandler.AddNewCircuit(agent.circuitcode, agent); 3398 m_authenticateHandler.AddNewCircuit(agent.circuitcode, agent);
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
index a078291..7ec7ea3 100644
--- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
@@ -1401,21 +1401,26 @@ namespace OpenSim.Region.Framework.Scenes
1401 } 1401 }
1402 1402
1403 /// <summary> 1403 /// <summary>
1404 /// 1404 /// Update the flags on a scene object. This covers properties such as phantom, physics and temporary.
1405 /// </summary> 1405 /// </summary>
1406 /// <remarks>
1407 /// This is currently handling the incoming call from the client stack (e.g. LLClientView).
1408 /// </remarks>
1406 /// <param name="localID"></param> 1409 /// <param name="localID"></param>
1407 /// <param name="packet"></param> 1410 /// <param name="UsePhysics"></param>
1411 /// <param name="SetTemporary"></param>
1412 /// <param name="SetPhantom"></param>
1408 /// <param name="remoteClient"></param> 1413 /// <param name="remoteClient"></param>
1409 /// This routine seems to get called when a user changes object settings in the viewer. 1414 protected internal void UpdatePrimFlags(
1410 /// If some one can confirm that, please change the comment according. 1415 uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, IClientAPI remoteClient)
1411 protected internal void UpdatePrimFlags(uint localID, bool UsePhysics, bool IsTemporary, bool IsPhantom, IClientAPI remoteClient)
1412 { 1416 {
1413 SceneObjectGroup group = GetGroupByPrim(localID); 1417 SceneObjectGroup group = GetGroupByPrim(localID);
1414 if (group != null) 1418 if (group != null)
1415 { 1419 {
1416 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId)) 1420 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1417 { 1421 {
1418 group.UpdatePrimFlags(localID, UsePhysics, IsTemporary, IsPhantom, false); // VolumeDetect can't be set via UI and will always be off when a change is made there 1422 // VolumeDetect can't be set via UI and will always be off when a change is made there
1423 group.UpdatePrimFlags(localID, UsePhysics, SetTemporary, SetPhantom, false);
1419 } 1424 }
1420 } 1425 }
1421 } 1426 }
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 42ac9aa..fa23fcd 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -2513,14 +2513,15 @@ namespace OpenSim.Region.Framework.Scenes
2513 /// Update prim flags for this group. 2513 /// Update prim flags for this group.
2514 /// </summary> 2514 /// </summary>
2515 /// <param name="localID"></param> 2515 /// <param name="localID"></param>
2516 /// <param name="type"></param> 2516 /// <param name="UsePhysics"></param>
2517 /// <param name="inUse"></param> 2517 /// <param name="SetTemporary"></param>
2518 /// <param name="data"></param> 2518 /// <param name="SetPhantom"></param>
2519 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool IsTemporary, bool IsPhantom, bool IsVolumeDetect) 2519 /// <param name="SetVolumeDetect"></param>
2520 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect)
2520 { 2521 {
2521 SceneObjectPart selectionPart = GetChildPart(localID); 2522 SceneObjectPart selectionPart = GetChildPart(localID);
2522 2523
2523 if (IsTemporary) 2524 if (SetTemporary)
2524 { 2525 {
2525 DetachFromBackup(); 2526 DetachFromBackup();
2526 // Remove from database and parcel prim count 2527 // Remove from database and parcel prim count
@@ -2545,7 +2546,7 @@ namespace OpenSim.Region.Framework.Scenes
2545 } 2546 }
2546 2547
2547 for (int i = 0; i < parts.Length; i++) 2548 for (int i = 0; i < parts.Length; i++)
2548 parts[i].UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2549 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect);
2549 } 2550 }
2550 } 2551 }
2551 2552
@@ -3287,34 +3288,36 @@ namespace OpenSim.Region.Framework.Scenes
3287 3288
3288 return retmass; 3289 return retmass;
3289 } 3290 }
3290 3291
3292 /// <summary>
3293 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that
3294 /// the physics engine can use it.
3295 /// </summary>
3296 /// <remarks>
3297 /// When the physics engine has finished with it, the sculpt data is discarded to save memory.
3298 /// </remarks>
3291 public void CheckSculptAndLoad() 3299 public void CheckSculptAndLoad()
3292 { 3300 {
3293 if (IsDeleted) 3301 if (IsDeleted)
3294 return; 3302 return;
3303
3295 if ((RootPart.GetEffectiveObjectFlags() & (uint)PrimFlags.Phantom) != 0) 3304 if ((RootPart.GetEffectiveObjectFlags() & (uint)PrimFlags.Phantom) != 0)
3296 return; 3305 return;
3297 3306
3307// m_log.Debug("Processing CheckSculptAndLoad for {0} {1}", Name, LocalId);
3308
3298 SceneObjectPart[] parts = m_parts.GetArray(); 3309 SceneObjectPart[] parts = m_parts.GetArray();
3310
3299 for (int i = 0; i < parts.Length; i++) 3311 for (int i = 0; i < parts.Length; i++)
3300 { 3312 parts[i].CheckSculptAndLoad();
3301 SceneObjectPart part = parts[i];
3302 if (part.Shape.SculptEntry && part.Shape.SculptTexture != UUID.Zero)
3303 {
3304 // check if a previously decoded sculpt map has been cached
3305 if (File.Exists(System.IO.Path.Combine("j2kDecodeCache", "smap_" + part.Shape.SculptTexture.ToString())))
3306 {
3307 part.SculptTextureCallback(part.Shape.SculptTexture, null);
3308 }
3309 else
3310 {
3311 m_scene.AssetService.Get(
3312 part.Shape.SculptTexture.ToString(), part, AssetReceived);
3313 }
3314 }
3315 }
3316 } 3313 }
3317 3314
3315 /// <summary>
3316 /// Handle an asset received asynchronously from the asset service.
3317 /// </summary>
3318 /// <param name="id"></param>
3319 /// <param name="sender"></param>
3320 /// <param name="asset"></param>
3318 protected void AssetReceived(string id, Object sender, AssetBase asset) 3321 protected void AssetReceived(string id, Object sender, AssetBase asset)
3319 { 3322 {
3320 SceneObjectPart sop = (SceneObjectPart)sender; 3323 SceneObjectPart sop = (SceneObjectPart)sender;
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
index c6d8c73..2026c53 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
@@ -28,6 +28,7 @@
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Drawing; 30using System.Drawing;
31using System.IO;
31using System.Reflection; 32using System.Reflection;
32using System.Runtime.Serialization; 33using System.Runtime.Serialization;
33using System.Security.Permissions; 34using System.Security.Permissions;
@@ -800,7 +801,8 @@ namespace OpenSim.Region.Framework.Scenes
800 actor.Orientation = GetWorldRotation(); 801 actor.Orientation = GetWorldRotation();
801 802
802 // Tell the physics engines that this prim changed. 803 // Tell the physics engines that this prim changed.
803 m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor); 804 if (m_parentGroup.Scene != null)
805 m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor);
804 } 806 }
805 } 807 }
806 } 808 }
@@ -1067,7 +1069,6 @@ namespace OpenSim.Region.Framework.Scenes
1067 } 1069 }
1068 } 1070 }
1069 1071
1070
1071 public bool CreateSelected 1072 public bool CreateSelected
1072 { 1073 {
1073 get { return m_createSelected; } 1074 get { return m_createSelected; }
@@ -1085,11 +1086,13 @@ namespace OpenSim.Region.Framework.Scenes
1085 1086
1086 public Vector3 AbsolutePosition 1087 public Vector3 AbsolutePosition
1087 { 1088 {
1088 get { 1089 get
1090 {
1089 if (IsAttachment) 1091 if (IsAttachment)
1090 return GroupPosition; 1092 return GroupPosition;
1091 1093
1092 return m_offsetPosition + m_groupPosition; } 1094 return m_offsetPosition + m_groupPosition;
1095 }
1093 } 1096 }
1094 1097
1095 public SceneObjectGroup ParentGroup 1098 public SceneObjectGroup ParentGroup
@@ -1238,7 +1241,9 @@ namespace OpenSim.Region.Framework.Scenes
1238 /// <summary> 1241 /// <summary>
1239 /// Property flags. See OpenMetaverse.PrimFlags 1242 /// Property flags. See OpenMetaverse.PrimFlags
1240 /// </summary> 1243 /// </summary>
1244 /// <remarks>
1241 /// Example properties are PrimFlags.Phantom and PrimFlags.DieAtEdge 1245 /// Example properties are PrimFlags.Phantom and PrimFlags.DieAtEdge
1246 /// </remarks>
1242 public PrimFlags Flags 1247 public PrimFlags Flags
1243 { 1248 {
1244 get { return _flags; } 1249 get { return _flags; }
@@ -1561,6 +1566,8 @@ namespace OpenSim.Region.Framework.Scenes
1561 /// <param name="m_physicalPrim"></param> 1566 /// <param name="m_physicalPrim"></param>
1562 public void ApplyPhysics(uint rootObjectFlags, bool VolumeDetectActive, bool m_physicalPrim) 1567 public void ApplyPhysics(uint rootObjectFlags, bool VolumeDetectActive, bool m_physicalPrim)
1563 { 1568 {
1569// m_log.DebugFormat("[SCENE OBJECT PART]: Applying physics to {0} {1} {2}", Name, LocalId, UUID);
1570
1564 bool isPhysical = (((rootObjectFlags & (uint) PrimFlags.Physics) != 0) && m_physicalPrim); 1571 bool isPhysical = (((rootObjectFlags & (uint) PrimFlags.Physics) != 0) && m_physicalPrim);
1565 bool isPhantom = ((rootObjectFlags & (uint) PrimFlags.Phantom) != 0); 1572 bool isPhantom = ((rootObjectFlags & (uint) PrimFlags.Phantom) != 0);
1566 1573
@@ -1581,6 +1588,8 @@ namespace OpenSim.Region.Framework.Scenes
1581 // or flexible 1588 // or flexible
1582 if (!isPhantom && !IsAttachment && !(Shape.PathCurve == (byte) Extrusion.Flexible)) 1589 if (!isPhantom && !IsAttachment && !(Shape.PathCurve == (byte) Extrusion.Flexible))
1583 { 1590 {
1591// m_log.DebugFormat("[SCENE OBJECT PART]: Creating PhysActor for {0} {1} {2}", Name, LocalId, UUID);
1592
1584 PhysActor = m_parentGroup.Scene.PhysicsScene.AddPrimShape( 1593 PhysActor = m_parentGroup.Scene.PhysicsScene.AddPrimShape(
1585 LocalId, 1594 LocalId,
1586 string.Format("{0}/{1}", Name, UUID), 1595 string.Format("{0}/{1}", Name, UUID),
@@ -1802,7 +1811,6 @@ namespace OpenSim.Region.Framework.Scenes
1802 { 1811 {
1803 ParentGroup.Scene.jointErrorMessage(joint, "warning: tracked body name not found! joint location will not be updated properly. joint: " + Name); 1812 ParentGroup.Scene.jointErrorMessage(joint, "warning: tracked body name not found! joint location will not be updated properly. joint: " + Name);
1804 } 1813 }
1805
1806 } 1814 }
1807 else 1815 else
1808 { 1816 {
@@ -1864,7 +1872,6 @@ namespace OpenSim.Region.Framework.Scenes
1864 1872
1865 PhysActor.IsPhysical = UsePhysics; 1873 PhysActor.IsPhysical = UsePhysics;
1866 1874
1867
1868 // If we're not what we're supposed to be in the physics scene, recreate ourselves. 1875 // If we're not what we're supposed to be in the physics scene, recreate ourselves.
1869 //m_parentGroup.Scene.PhysicsScene.RemovePrim(PhysActor); 1876 //m_parentGroup.Scene.PhysicsScene.RemovePrim(PhysActor);
1870 /// that's not wholesome. Had to make Scene public 1877 /// that's not wholesome. Had to make Scene public
@@ -1888,6 +1895,7 @@ namespace OpenSim.Region.Framework.Scenes
1888 } 1895 }
1889 } 1896 }
1890 } 1897 }
1898
1891 m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor); 1899 m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor);
1892 } 1900 }
1893 } 1901 }
@@ -2823,6 +2831,12 @@ namespace OpenSim.Region.Framework.Scenes
2823 StoreUndoState(); 2831 StoreUndoState();
2824 m_shape.Scale = scale; 2832 m_shape.Scale = scale;
2825 2833
2834 // If we're a mesh/sculpt, then we need to tell the physics engine about our new size. To do this, we
2835 // need to reinsert the sculpt data into the shape, since the physics engine deletes it when done to
2836 // save memory
2837 if (PhysActor != null)
2838 CheckSculptAndLoad();
2839
2826 ParentGroup.HasGroupChanged = true; 2840 ParentGroup.HasGroupChanged = true;
2827 ScheduleFullUpdate(); 2841 ScheduleFullUpdate();
2828 } 2842 }
@@ -2951,7 +2965,6 @@ namespace OpenSim.Region.Framework.Scenes
2951 } 2965 }
2952 } 2966 }
2953 2967
2954
2955 public void SculptTextureCallback(UUID textureID, AssetBase texture) 2968 public void SculptTextureCallback(UUID textureID, AssetBase texture)
2956 { 2969 {
2957 if (m_shape.SculptEntry) 2970 if (m_shape.SculptEntry)
@@ -2960,14 +2973,17 @@ namespace OpenSim.Region.Framework.Scenes
2960 //if (texture != null) 2973 //if (texture != null)
2961 { 2974 {
2962 if (texture != null) 2975 if (texture != null)
2976 {
2977// m_log.DebugFormat(
2978// "[SCENE OBJECT PART]: Setting sculpt data for {0} on SculptTextureCallback()", Name);
2979
2963 m_shape.SculptData = texture.Data; 2980 m_shape.SculptData = texture.Data;
2981 }
2964 2982
2965 if (PhysActor != null) 2983 if (PhysActor != null)
2966 { 2984 {
2967 // Tricks physics engine into thinking we've changed the part shape. 2985 // Update the physics actor with the new loaded sculpt data and set the taint signal.
2968 PrimitiveBaseShape m_newshape = m_shape.Copy(); 2986 PhysActor.Shape = m_shape;
2969 PhysActor.Shape = m_newshape;
2970 m_shape = m_newshape;
2971 2987
2972 m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor); 2988 m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor);
2973 } 2989 }
@@ -3263,11 +3279,14 @@ namespace OpenSim.Region.Framework.Scenes
3263 { 3279 {
3264 m_parentGroup.SetAxisRotation(axis, rotate); 3280 m_parentGroup.SetAxisRotation(axis, rotate);
3265 } 3281 }
3282
3266 //Cannot use ScriptBaseClass constants as no referance to it currently. 3283 //Cannot use ScriptBaseClass constants as no referance to it currently.
3267 if (axis == 2)//STATUS_ROTATE_X 3284 if (axis == 2)//STATUS_ROTATE_X
3268 STATUS_ROTATE_X = rotate; 3285 STATUS_ROTATE_X = rotate;
3286
3269 if (axis == 4)//STATUS_ROTATE_Y 3287 if (axis == 4)//STATUS_ROTATE_Y
3270 STATUS_ROTATE_Y = rotate; 3288 STATUS_ROTATE_Y = rotate;
3289
3271 if (axis == 8)//STATUS_ROTATE_Z 3290 if (axis == 8)//STATUS_ROTATE_Z
3272 STATUS_ROTATE_Z = rotate; 3291 STATUS_ROTATE_Z = rotate;
3273 } 3292 }
@@ -4318,14 +4337,21 @@ namespace OpenSim.Region.Framework.Scenes
4318 } 4337 }
4319 } 4338 }
4320 4339
4321 public void UpdatePrimFlags(bool UsePhysics, bool IsTemporary, bool IsPhantom, bool IsVD) 4340 /// <summary>
4341 /// Update the flags on this prim. This covers properties such as phantom, physics and temporary.
4342 /// </summary>
4343 /// <param name="UsePhysics"></param>
4344 /// <param name="SetTemporary"></param>
4345 /// <param name="SetPhantom"></param>
4346 /// <param name="SetVD"></param>
4347 public void UpdatePrimFlags(bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVD)
4322 { 4348 {
4323 bool wasUsingPhysics = ((Flags & PrimFlags.Physics) != 0); 4349 bool wasUsingPhysics = ((Flags & PrimFlags.Physics) != 0);
4324 bool wasTemporary = ((Flags & PrimFlags.TemporaryOnRez) != 0); 4350 bool wasTemporary = ((Flags & PrimFlags.TemporaryOnRez) != 0);
4325 bool wasPhantom = ((Flags & PrimFlags.Phantom) != 0); 4351 bool wasPhantom = ((Flags & PrimFlags.Phantom) != 0);
4326 bool wasVD = VolumeDetectActive; 4352 bool wasVD = VolumeDetectActive;
4327 4353
4328 if ((UsePhysics == wasUsingPhysics) && (wasTemporary == IsTemporary) && (wasPhantom == IsPhantom) && (IsVD==wasVD)) 4354 if ((UsePhysics == wasUsingPhysics) && (wasTemporary == SetTemporary) && (wasPhantom == SetPhantom) && (SetVD == wasVD))
4329 { 4355 {
4330 return; 4356 return;
4331 } 4357 }
@@ -4335,32 +4361,31 @@ namespace OpenSim.Region.Framework.Scenes
4335 // that... 4361 // that...
4336 // ... if VD is changed, all others are not. 4362 // ... if VD is changed, all others are not.
4337 // ... if one of the others is changed, VD is not. 4363 // ... if one of the others is changed, VD is not.
4338 if (IsVD) // VD is active, special logic applies 4364 if (SetVD) // VD is active, special logic applies
4339 { 4365 {
4340 // State machine logic for VolumeDetect 4366 // State machine logic for VolumeDetect
4341 // More logic below 4367 // More logic below
4342 bool phanReset = (IsPhantom != wasPhantom) && !IsPhantom; 4368 bool phanReset = (SetPhantom != wasPhantom) && !SetPhantom;
4343 4369
4344 if (phanReset) // Phantom changes from on to off switch VD off too 4370 if (phanReset) // Phantom changes from on to off switch VD off too
4345 { 4371 {
4346 IsVD = false; // Switch it of for the course of this routine 4372 SetVD = false; // Switch it of for the course of this routine
4347 VolumeDetectActive = false; // and also permanently 4373 VolumeDetectActive = false; // and also permanently
4348 if (PhysActor != null) 4374 if (PhysActor != null)
4349 PhysActor.SetVolumeDetect(0); // Let physics know about it too 4375 PhysActor.SetVolumeDetect(0); // Let physics know about it too
4350 } 4376 }
4351 else 4377 else
4352 { 4378 {
4353 IsPhantom = false;
4354 // If volumedetect is active we don't want phantom to be applied. 4379 // If volumedetect is active we don't want phantom to be applied.
4355 // If this is a new call to VD out of the state "phantom" 4380 // If this is a new call to VD out of the state "phantom"
4356 // this will also cause the prim to be visible to physics 4381 // this will also cause the prim to be visible to physics
4382 SetPhantom = false;
4357 } 4383 }
4358
4359 } 4384 }
4360 4385
4361 if (UsePhysics && IsJoint()) 4386 if (UsePhysics && IsJoint())
4362 { 4387 {
4363 IsPhantom = true; 4388 SetPhantom = true;
4364 } 4389 }
4365 4390
4366 if (UsePhysics) 4391 if (UsePhysics)
@@ -4390,8 +4415,7 @@ namespace OpenSim.Region.Framework.Scenes
4390 } 4415 }
4391 } 4416 }
4392 4417
4393 4418 if (SetPhantom || IsAttachment || (Shape.PathCurve == (byte)Extrusion.Flexible)) // note: this may have been changed above in the case of joints
4394 if (IsPhantom || IsAttachment || (Shape.PathCurve == (byte)Extrusion.Flexible)) // note: this may have been changed above in the case of joints
4395 { 4419 {
4396 AddFlag(PrimFlags.Phantom); 4420 AddFlag(PrimFlags.Phantom);
4397 if (PhysActor != null) 4421 if (PhysActor != null)
@@ -4406,6 +4430,7 @@ namespace OpenSim.Region.Framework.Scenes
4406 RemFlag(PrimFlags.Phantom); 4430 RemFlag(PrimFlags.Phantom);
4407 4431
4408 PhysicsActor pa = PhysActor; 4432 PhysicsActor pa = PhysActor;
4433
4409 if (pa == null) 4434 if (pa == null)
4410 { 4435 {
4411 // It's not phantom anymore. So make sure the physics engine get's knowledge of it 4436 // It's not phantom anymore. So make sure the physics engine get's knowledge of it
@@ -4422,6 +4447,7 @@ namespace OpenSim.Region.Framework.Scenes
4422 if (pa != null) 4447 if (pa != null)
4423 { 4448 {
4424 DoPhysicsPropertyUpdate(UsePhysics, true); 4449 DoPhysicsPropertyUpdate(UsePhysics, true);
4450
4425 if (m_parentGroup != null) 4451 if (m_parentGroup != null)
4426 { 4452 {
4427 if (!m_parentGroup.IsDeleted) 4453 if (!m_parentGroup.IsDeleted)
@@ -4432,6 +4458,7 @@ namespace OpenSim.Region.Framework.Scenes
4432 } 4458 }
4433 } 4459 }
4434 } 4460 }
4461
4435 if ( 4462 if (
4436 ((AggregateScriptEvents & scriptEvents.collision) != 0) || 4463 ((AggregateScriptEvents & scriptEvents.collision) != 0) ||
4437 ((AggregateScriptEvents & scriptEvents.collision_end) != 0) || 4464 ((AggregateScriptEvents & scriptEvents.collision_end) != 0) ||
@@ -4442,8 +4469,8 @@ namespace OpenSim.Region.Framework.Scenes
4442 (CollisionSound != UUID.Zero) 4469 (CollisionSound != UUID.Zero)
4443 ) 4470 )
4444 { 4471 {
4445 PhysActor.OnCollisionUpdate += PhysicsCollision; 4472 PhysActor.OnCollisionUpdate += PhysicsCollision;
4446 PhysActor.SubscribeEvents(1000); 4473 PhysActor.SubscribeEvents(1000);
4447 } 4474 }
4448 } 4475 }
4449 } 4476 }
@@ -4465,7 +4492,7 @@ namespace OpenSim.Region.Framework.Scenes
4465 } 4492 }
4466 } 4493 }
4467 4494
4468 if (IsVD) 4495 if (SetVD)
4469 { 4496 {
4470 // If the above logic worked (this is urgent candidate to unit tests!) 4497 // If the above logic worked (this is urgent candidate to unit tests!)
4471 // we now have a physicsactor. 4498 // we now have a physicsactor.
@@ -4480,18 +4507,19 @@ namespace OpenSim.Region.Framework.Scenes
4480 } 4507 }
4481 } 4508 }
4482 else 4509 else
4483 { // Remove VolumeDetect in any case. Note, it's safe to call SetVolumeDetect as often as you like 4510 {
4511 // Remove VolumeDetect in any case. Note, it's safe to call SetVolumeDetect as often as you like
4484 // (mumbles, well, at least if you have infinte CPU powers :-)) 4512 // (mumbles, well, at least if you have infinte CPU powers :-))
4485 PhysicsActor pa = this.PhysActor; 4513 PhysicsActor pa = this.PhysActor;
4486 if (pa != null) 4514 if (pa != null)
4487 { 4515 {
4488 PhysActor.SetVolumeDetect(0); 4516 PhysActor.SetVolumeDetect(0);
4489 } 4517 }
4518
4490 this.VolumeDetectActive = false; 4519 this.VolumeDetectActive = false;
4491 } 4520 }
4492 4521
4493 4522 if (SetTemporary)
4494 if (IsTemporary)
4495 { 4523 {
4496 AddFlag(PrimFlags.TemporaryOnRez); 4524 AddFlag(PrimFlags.TemporaryOnRez);
4497 } 4525 }
@@ -4542,6 +4570,7 @@ namespace OpenSim.Region.Framework.Scenes
4542 m_shape.PathTaperY = shapeBlock.PathTaperY; 4570 m_shape.PathTaperY = shapeBlock.PathTaperY;
4543 m_shape.PathTwist = shapeBlock.PathTwist; 4571 m_shape.PathTwist = shapeBlock.PathTwist;
4544 m_shape.PathTwistBegin = shapeBlock.PathTwistBegin; 4572 m_shape.PathTwistBegin = shapeBlock.PathTwistBegin;
4573
4545 if (PhysActor != null) 4574 if (PhysActor != null)
4546 { 4575 {
4547 PhysActor.Shape = m_shape; 4576 PhysActor.Shape = m_shape;
@@ -4563,11 +4592,44 @@ namespace OpenSim.Region.Framework.Scenes
4563 } 4592 }
4564 4593
4565 /// <summary> 4594 /// <summary>
4595 /// If the part is a sculpt/mesh, retrieve the mesh data and reinsert it into the shape so that the physics
4596 /// engine can use it.
4597 /// </summary>
4598 /// <remarks>
4599 /// When the physics engine has finished with it, the sculpt data is discarded to save memory.
4600 /// </remarks>
4601 public void CheckSculptAndLoad()
4602 {
4603// m_log.Debug("Processing CheckSculptAndLoad for {0} {1}", Name, LocalId);
4604
4605 if (ParentGroup.IsDeleted)
4606 return;
4607
4608 if ((ParentGroup.RootPart.GetEffectiveObjectFlags() & (uint)PrimFlags.Phantom) != 0)
4609 return;
4610
4611 if (Shape.SculptEntry && Shape.SculptTexture != UUID.Zero)
4612 {
4613 // check if a previously decoded sculpt map has been cached
4614 if (File.Exists(System.IO.Path.Combine("j2kDecodeCache", "smap_" + Shape.SculptTexture.ToString())))
4615 {
4616 SculptTextureCallback(Shape.SculptTexture, null);
4617 }
4618 else
4619 {
4620 ParentGroup.Scene.AssetService.Get(Shape.SculptTexture.ToString(), this, AssetReceived);
4621 }
4622 }
4623 }
4624
4625 /// <summary>
4566 /// Update the textures on the part. 4626 /// Update the textures on the part.
4567 /// </summary> 4627 /// </summary>
4628 /// <remarks>
4568 /// Added to handle bug in libsecondlife's TextureEntry.ToBytes() 4629 /// Added to handle bug in libsecondlife's TextureEntry.ToBytes()
4569 /// not handling RGBA properly. Cycles through, and "fixes" the color 4630 /// not handling RGBA properly. Cycles through, and "fixes" the color
4570 /// info 4631 /// info
4632 /// </remarks>
4571 /// <param name="tex"></param> 4633 /// <param name="tex"></param>
4572 public void UpdateTexture(Primitive.TextureEntry tex) 4634 public void UpdateTexture(Primitive.TextureEntry tex)
4573 { 4635 {
@@ -4798,6 +4860,7 @@ namespace OpenSim.Region.Framework.Scenes
4798 4860
4799 Inventory.ApplyNextOwnerPermissions(); 4861 Inventory.ApplyNextOwnerPermissions();
4800 } 4862 }
4863
4801 public void UpdateLookAt() 4864 public void UpdateLookAt()
4802 { 4865 {
4803 try 4866 try
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index 80aafd0..83b761c 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -1944,10 +1944,9 @@ namespace OpenSim.Region.Framework.Scenes
1944 m_log.Warn("Sit requested on unknown object: " + targetID.ToString()); 1944 m_log.Warn("Sit requested on unknown object: " + targetID.ToString());
1945 } 1945 }
1946 1946
1947
1948
1949 SendSitResponse(remoteClient, targetID, offset, Quaternion.Identity); 1947 SendSitResponse(remoteClient, targetID, offset, Quaternion.Identity);
1950 } 1948 }
1949
1951 /* 1950 /*
1952 public void SitRayCastAvatarPosition(SceneObjectPart part) 1951 public void SitRayCastAvatarPosition(SceneObjectPart part)
1953 { 1952 {
@@ -2380,7 +2379,6 @@ namespace OpenSim.Region.Framework.Scenes
2380 /// <param name="remoteClient"></param> 2379 /// <param name="remoteClient"></param>
2381 public void SendTerseUpdateToClient(IClientAPI remoteClient) 2380 public void SendTerseUpdateToClient(IClientAPI remoteClient)
2382 { 2381 {
2383
2384 // If the client is inactive, it's getting its updates from another 2382 // If the client is inactive, it's getting its updates from another
2385 // server. 2383 // server.
2386 if (remoteClient.IsActive) 2384 if (remoteClient.IsActive)
@@ -2495,7 +2493,7 @@ namespace OpenSim.Region.Framework.Scenes
2495 } 2493 }
2496 2494
2497 // If we aren't using a cached appearance, then clear out the baked textures 2495 // If we aren't using a cached appearance, then clear out the baked textures
2498 if (! cachedappearance) 2496 if (!cachedappearance)
2499 { 2497 {
2500 m_appearance.ResetAppearance(); 2498 m_appearance.ResetAppearance();
2501 if (m_scene.AvatarFactory != null) 2499 if (m_scene.AvatarFactory != null)
diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
index fcf7e0c..c18c93a 100644
--- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
+++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
@@ -1001,6 +1001,8 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
1001 1001
1002 private static void ProcessShpSculptData(PrimitiveBaseShape shp, XmlTextReader reader) 1002 private static void ProcessShpSculptData(PrimitiveBaseShape shp, XmlTextReader reader)
1003 { 1003 {
1004// m_log.DebugFormat("[SCENE OBJECT SERIALIZER]: Setting sculpt data length {0}", shp.SculptData.Length);
1005
1004 shp.SculptData = Convert.FromBase64String(reader.ReadElementString("SculptData")); 1006 shp.SculptData = Convert.FromBase64String(reader.ReadElementString("SculptData"));
1005 } 1007 }
1006 1008
diff --git a/OpenSim/Region/Framework/Scenes/Tests/AttachmentTests.cs b/OpenSim/Region/Framework/Scenes/Tests/AttachmentTests.cs
index cff649b..5586c65 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/AttachmentTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/AttachmentTests.cs
@@ -83,7 +83,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
83 region1 = scene.RegionInfo.RegionHandle; 83 region1 = scene.RegionInfo.RegionHandle;
84 region2 = scene2.RegionInfo.RegionHandle; 84 region2 = scene2.RegionInfo.RegionHandle;
85 85
86 SceneSetupHelpers.AddRootAgent(scene, agent1); 86 SceneSetupHelpers.AddClient(scene, agent1);
87 } 87 }
88 88
89 [Test] 89 [Test]
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs
index 0a82c4f..260d1c0 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs
@@ -139,7 +139,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
139 139
140 SceneObjectPart part = SceneSetupHelpers.AddSceneObject(scene); 140 SceneObjectPart part = SceneSetupHelpers.AddSceneObject(scene);
141 141
142 IClientAPI client = SceneSetupHelpers.AddRootAgent(scene, agentId); 142 IClientAPI client = SceneSetupHelpers.AddClient(scene, agentId);
143 scene.DeRezObjects(client, new System.Collections.Generic.List<uint>() { part.LocalId }, UUID.Zero, DeRezAction.Delete, UUID.Zero); 143 scene.DeRezObjects(client, new System.Collections.Generic.List<uint>() { part.LocalId }, UUID.Zero, DeRezAction.Delete, UUID.Zero);
144 144
145 SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId); 145 SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId);
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs
index 5357a06..1b8c100 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs
@@ -66,7 +66,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
66 IConfig config = configSource.AddConfig("Startup"); 66 IConfig config = configSource.AddConfig("Startup");
67 config.Set("serverside_object_permissions", true); 67 config.Set("serverside_object_permissions", true);
68 SceneSetupHelpers.SetupSceneModules(scene, configSource, new object[] { new PermissionsModule() }); 68 SceneSetupHelpers.SetupSceneModules(scene, configSource, new object[] { new PermissionsModule() });
69 TestClient client = SceneSetupHelpers.AddRootAgent(scene, userId); 69 TestClient client = SceneSetupHelpers.AddClient(scene, userId);
70 70
71 // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. 71 // Turn off the timer on the async sog deleter - we'll crank it by hand for this test.
72 AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter; 72 AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter;
@@ -105,7 +105,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
105 IConfig config = configSource.AddConfig("Startup"); 105 IConfig config = configSource.AddConfig("Startup");
106 config.Set("serverside_object_permissions", true); 106 config.Set("serverside_object_permissions", true);
107 SceneSetupHelpers.SetupSceneModules(scene, configSource, new object[] { new PermissionsModule() }); 107 SceneSetupHelpers.SetupSceneModules(scene, configSource, new object[] { new PermissionsModule() });
108 TestClient client = SceneSetupHelpers.AddRootAgent(scene, userId); 108 TestClient client = SceneSetupHelpers.AddClient(scene, userId);
109 109
110 // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. 110 // Turn off the timer on the async sog deleter - we'll crank it by hand for this test.
111 AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter; 111 AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter;
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectUserGroupTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectUserGroupTests.cs
index 77bd4c2..8425d37 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectUserGroupTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectUserGroupTests.cs
@@ -75,7 +75,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
75 new GroupsModule(), 75 new GroupsModule(),
76 new MockGroupsServicesConnector() }); 76 new MockGroupsServicesConnector() });
77 77
78 TestClient client = SceneSetupHelpers.AddRootAgent(scene, userId); 78 TestClient client = SceneSetupHelpers.AddClient(scene, userId);
79 79
80 IGroupsModule groupsModule = scene.RequestModuleInterface<IGroupsModule>(); 80 IGroupsModule groupsModule = scene.RequestModuleInterface<IGroupsModule>();
81 81
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTests.cs
index 03ac252..a37b338 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTests.cs
@@ -212,7 +212,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
212 212
213 SceneSetupHelpers.SetupSceneModules(myScene1, configSource, etm); 213 SceneSetupHelpers.SetupSceneModules(myScene1, configSource, etm);
214 214
215 SceneSetupHelpers.AddRootAgent(myScene1, agent1Id); 215 SceneSetupHelpers.AddClient(myScene1, agent1Id);
216 ScenePresence childPresence = myScene2.GetScenePresence(agent1); 216 ScenePresence childPresence = myScene2.GetScenePresence(agent1);
217 217
218 // TODO: Need to do a fair amount of work to allow synchronous establishment of child agents 218 // TODO: Need to do a fair amount of work to allow synchronous establishment of child agents
diff --git a/OpenSim/Region/Framework/Scenes/Tests/StandaloneTeleportTests.cs b/OpenSim/Region/Framework/Scenes/Tests/StandaloneTeleportTests.cs
index 1b5a54e..4074f5d 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/StandaloneTeleportTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/StandaloneTeleportTests.cs
@@ -125,7 +125,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
125 sceneA.RegisterRegionWithGrid(); 125 sceneA.RegisterRegionWithGrid();
126 126
127 UUID agentId = UUID.Parse("00000000-0000-0000-0000-000000000041"); 127 UUID agentId = UUID.Parse("00000000-0000-0000-0000-000000000041");
128 TestClient client = SceneSetupHelpers.AddRootAgent(sceneA, agentId); 128 TestClient client = SceneSetupHelpers.AddClient(sceneA, agentId);
129 129
130 ICapabilitiesModule sceneACapsModule = sceneA.RequestModuleInterface<ICapabilitiesModule>(); 130 ICapabilitiesModule sceneACapsModule = sceneA.RequestModuleInterface<ICapabilitiesModule>();
131 131
diff --git a/OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs b/OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs
index 7304145..77e7acf 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs
@@ -113,7 +113,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
113 { 113 {
114 bool bakedTextureValid = scene.AvatarFactory.ValidateBakedTextureCache(client); 114 bool bakedTextureValid = scene.AvatarFactory.ValidateBakedTextureCache(client);
115 MainConsole.Instance.OutputFormat( 115 MainConsole.Instance.OutputFormat(
116 "{0} baked apperance texture is {1}", client.Name, bakedTextureValid ? "OK" : "corrupt"); 116 "{0} baked appearance texture is {1}", client.Name, bakedTextureValid ? "OK" : "corrupt");
117 } 117 }
118 }); 118 });
119 } 119 }
diff --git a/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs b/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs
index 42efd67..a5bba4f 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs
@@ -417,9 +417,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
417 public string ParcelVoiceInfoRequest(Scene scene, string request, string path, string param, 417 public string ParcelVoiceInfoRequest(Scene scene, string request, string path, string param,
418 UUID agentID, Caps caps) 418 UUID agentID, Caps caps)
419 { 419 {
420// m_log.DebugFormat( 420 m_log.DebugFormat(
421// "[FreeSwitchVoice][PARCELVOICE]: ParcelVoiceInfoRequest() on {0} for {1}", 421 "[FreeSwitchVoice][PARCELVOICE]: ParcelVoiceInfoRequest() on {0} for {1}",
422// scene.RegionInfo.RegionName, agentID); 422 scene.RegionInfo.RegionName, agentID);
423 423
424 ScenePresence avatar = scene.GetScenePresence(agentID); 424 ScenePresence avatar = scene.GetScenePresence(agentID);
425 string avatarName = avatar.Name; 425 string avatarName = avatar.Name;
@@ -885,4 +885,4 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
885 885
886 #endregion 886 #endregion
887 } 887 }
888} \ No newline at end of file 888}
diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsMessagingModule.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsMessagingModule.cs
index 2bf8489..0800e98 100644
--- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsMessagingModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsMessagingModule.cs
@@ -70,7 +70,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
70 // if groups aren't enabled, we're not needed. 70 // if groups aren't enabled, we're not needed.
71 // if we're not specified as the connector to use, then we're not wanted 71 // if we're not specified as the connector to use, then we're not wanted
72 if ((groupsConfig.GetBoolean("Enabled", false) == false) 72 if ((groupsConfig.GetBoolean("Enabled", false) == false)
73 || (groupsConfig.GetString("MessagingModule", "Default") != Name)) 73 || (groupsConfig.GetString("MessagingModule", "GroupsMessagingModule") != Name))
74 { 74 {
75 m_groupMessagingEnabled = false; 75 m_groupMessagingEnabled = false;
76 return; 76 return;
diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/SimianGroupsServicesConnectorModule.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/SimianGroupsServicesConnectorModule.cs
index 02751ea..42008da 100644
--- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/SimianGroupsServicesConnectorModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/SimianGroupsServicesConnectorModule.cs
@@ -200,7 +200,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
200 // if groups aren't enabled, we're not needed. 200 // if groups aren't enabled, we're not needed.
201 // if we're not specified as the connector to use, then we're not wanted 201 // if we're not specified as the connector to use, then we're not wanted
202 if ((groupsConfig.GetBoolean("Enabled", false) == false) 202 if ((groupsConfig.GetBoolean("Enabled", false) == false)
203 || (groupsConfig.GetString("ServicesConnectorModule", "Default") != Name)) 203 || (groupsConfig.GetString("ServicesConnectorModule", "XmlRpcGroupsServicesConnector") != Name))
204 { 204 {
205 m_connectorEnabled = false; 205 m_connectorEnabled = false;
206 return; 206 return;
diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs
index 2631ac1..a08bcd0 100644
--- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs
@@ -109,7 +109,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
109 // if groups aren't enabled, we're not needed. 109 // if groups aren't enabled, we're not needed.
110 // if we're not specified as the connector to use, then we're not wanted 110 // if we're not specified as the connector to use, then we're not wanted
111 if ((groupsConfig.GetBoolean("Enabled", false) == false) 111 if ((groupsConfig.GetBoolean("Enabled", false) == false)
112 || (groupsConfig.GetString("ServicesConnectorModule", "Default") != Name)) 112 || (groupsConfig.GetString("ServicesConnectorModule", "XmlRpcGroupsServicesConnector") != Name))
113 { 113 {
114 m_connectorEnabled = false; 114 m_connectorEnabled = false;
115 return; 115 return;
diff --git a/OpenSim/Region/OptionalModules/Scripting/Minimodule/SOPObject.cs b/OpenSim/Region/OptionalModules/Scripting/Minimodule/SOPObject.cs
index faed522..aa23fee 100644
--- a/OpenSim/Region/OptionalModules/Scripting/Minimodule/SOPObject.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/Minimodule/SOPObject.cs
@@ -801,7 +801,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.Minimodule
801 // retain pathcurve 801 // retain pathcurve
802 shapeBlock.PathCurve = part.Shape.PathCurve; 802 shapeBlock.PathCurve = part.Shape.PathCurve;
803 803
804 part.Shape.SetSculptData((byte)type, sculptId); 804 part.Shape.SetSculptProperties((byte)type, sculptId);
805 part.Shape.SculptEntry = true; 805 part.Shape.SculptEntry = true;
806 part.UpdateShape(shapeBlock); 806 part.UpdateShape(shapeBlock);
807 } 807 }
diff --git a/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs b/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs
index eed6450..05c729a 100644
--- a/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs
@@ -36,6 +36,7 @@ using log4net;
36using Nini.Config; 36using Nini.Config;
37using OpenMetaverse; 37using OpenMetaverse;
38using OpenMetaverse.StructuredData; 38using OpenMetaverse.StructuredData;
39using OpenSim.Services.Interfaces;
39 40
40using OpenSim.Framework; 41using OpenSim.Framework;
41using OpenSim.Region.Framework.Interfaces; 42using OpenSim.Region.Framework.Interfaces;
@@ -175,6 +176,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.RegionReady
175 176
176 m_scene.EventManager.TriggerOnChatBroadcast(this, c); 177 m_scene.EventManager.TriggerOnChatBroadcast(this, c);
177 m_scene.EventManager.TriggerLoginsEnabled(m_scene.RegionInfo.RegionName); 178 m_scene.EventManager.TriggerLoginsEnabled(m_scene.RegionInfo.RegionName);
179 m_scene.SceneGridService.InformNeighborsThatRegionisUp(m_scene.RequestModuleInterface<INeighbourService>(), m_scene.RegionInfo);
178 } 180 }
179 } 181 }
180 182
diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs
index c471636..3cdd06d 100644
--- a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs
+++ b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs
@@ -25,13 +25,15 @@
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
28using System;
28using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Reflection;
29using System.Threading; 31using System.Threading;
30using OpenMetaverse; 32using log4net;
31using Nini.Config; 33using Nini.Config;
34using OpenMetaverse;
32using OpenSim.Region.Framework.Interfaces; 35using OpenSim.Region.Framework.Interfaces;
33using OpenSim.Region.Framework.Scenes; 36using OpenSim.Region.Framework.Scenes;
34using OpenSim.Region.CoreModules.Avatar.NPC;
35using OpenSim.Framework; 37using OpenSim.Framework;
36using Timer=System.Timers.Timer; 38using Timer=System.Timers.Timer;
37using OpenSim.Services.Interfaces; 39using OpenSim.Services.Interfaces;
@@ -40,24 +42,17 @@ namespace OpenSim.Region.OptionalModules.World.NPC
40{ 42{
41 public class NPCModule : IRegionModule, INPCModule 43 public class NPCModule : IRegionModule, INPCModule
42 { 44 {
43 // private const bool m_enabled = false; 45 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
44 46
45 private Mutex m_createMutex; 47 // private const bool m_enabled = false;
46 private Timer m_timer;
47 48
48 private Dictionary<UUID,NPCAvatar> m_avatars = new Dictionary<UUID, NPCAvatar>(); 49 private Dictionary<UUID,NPCAvatar> m_avatars = new Dictionary<UUID, NPCAvatar>();
49 private Dictionary<UUID,AvatarAppearance> m_appearanceCache = new Dictionary<UUID, AvatarAppearance>(); 50 private Dictionary<UUID,AvatarAppearance> m_appearanceCache = new Dictionary<UUID, AvatarAppearance>();
50 51
51 // Timer vars. 52 public void Initialise(Scene scene, IConfigSource source)
52 private bool p_inUse = false; 53 {
53 private readonly object p_lock = new object(); 54 scene.RegisterModuleInterface<INPCModule>(this);
54 // Private Temporary Variables. 55 }
55 private string p_firstname;
56 private string p_lastname;
57 private Vector3 p_position;
58 private Scene p_scene;
59 private UUID p_cloneAppearanceFrom;
60 private UUID p_returnUuid;
61 56
62 private AvatarAppearance GetAppearance(UUID target, Scene scene) 57 private AvatarAppearance GetAppearance(UUID target, Scene scene)
63 { 58 {
@@ -74,31 +69,53 @@ namespace OpenSim.Region.OptionalModules.World.NPC
74 return new AvatarAppearance(); 69 return new AvatarAppearance();
75 } 70 }
76 71
77 public UUID CreateNPC(string firstname, string lastname,Vector3 position, Scene scene, UUID cloneAppearanceFrom) 72 public UUID CreateNPC(string firstname, string lastname, Vector3 position, Scene scene, UUID cloneAppearanceFrom)
78 { 73 {
79 // Block. 74 NPCAvatar npcAvatar = new NPCAvatar(firstname, lastname, position, scene);
80 m_createMutex.WaitOne(); 75 npcAvatar.CircuitCode = (uint)Util.RandomClass.Next(0, int.MaxValue);
76
77 m_log.DebugFormat(
78 "[NPC MODULE]: Creating NPC {0} {1} {2} at {3} in {4}",
79 firstname, lastname, npcAvatar.AgentId, position, scene.RegionInfo.RegionName);
80
81 AgentCircuitData acd = new AgentCircuitData();
82 acd.AgentID = npcAvatar.AgentId;
83 acd.firstname = firstname;
84 acd.lastname = lastname;
85 acd.ServiceURLs = new Dictionary<string, object>();
81 86
82 // Copy Temp Variables for Timer to pick up. 87 AvatarAppearance originalAppearance = GetAppearance(cloneAppearanceFrom, scene);
83 lock (p_lock) 88 AvatarAppearance npcAppearance = new AvatarAppearance(originalAppearance, true);
89 acd.Appearance = npcAppearance;
90
91 scene.AuthenticateHandler.AddNewCircuit(npcAvatar.CircuitCode, acd);
92 scene.AddNewClient(npcAvatar);
93
94 ScenePresence sp;
95 if (scene.TryGetScenePresence(npcAvatar.AgentId, out sp))
84 { 96 {
85 p_firstname = firstname; 97 m_log.DebugFormat(
86 p_lastname = lastname; 98 "[NPC MODULE]: Successfully retrieved scene presence for NPC {0} {1}", sp.Name, sp.UUID);
87 p_position = position;
88 p_scene = scene;
89 p_cloneAppearanceFrom = cloneAppearanceFrom;
90 p_inUse = true;
91 p_returnUuid = UUID.Zero;
92 }
93 99
94 while (p_returnUuid == UUID.Zero) 100 // Shouldn't call this - temporary.
101 sp.CompleteMovement(npcAvatar);
102
103// sp.SendAppearanceToAllOtherAgents();
104//
105// // Send animations back to the avatar as well
106// sp.Animator.SendAnimPack();
107 }
108 else
95 { 109 {
96 Thread.Sleep(250); 110 m_log.WarnFormat("[NPC MODULE]: Could not find scene presence for NPC {0} {1}", sp.Name, sp.UUID);
97 } 111 }
98 112
99 m_createMutex.ReleaseMutex(); 113 lock (m_avatars)
114 m_avatars.Add(npcAvatar.AgentId, npcAvatar);
115
116 m_log.DebugFormat("[NPC MODULE]: Created NPC with id {0}", npcAvatar.AgentId);
100 117
101 return p_returnUuid; 118 return npcAvatar.AgentId;
102 } 119 }
103 120
104 public void Autopilot(UUID agentID, Scene scene, Vector3 pos) 121 public void Autopilot(UUID agentID, Scene scene, Vector3 pos)
@@ -137,48 +154,6 @@ namespace OpenSim.Region.OptionalModules.World.NPC
137 } 154 }
138 } 155 }
139 156
140
141 public void Initialise(Scene scene, IConfigSource source)
142 {
143 m_createMutex = new Mutex(false);
144
145 m_timer = new Timer(500);
146 m_timer.Elapsed += m_timer_Elapsed;
147 m_timer.Start();
148
149 scene.RegisterModuleInterface<INPCModule>(this);
150 }
151
152 void m_timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
153 {
154 lock (p_lock)
155 {
156 if (p_inUse)
157 {
158 p_inUse = false;
159
160 NPCAvatar npcAvatar = new NPCAvatar(p_firstname, p_lastname, p_position, p_scene);
161 npcAvatar.CircuitCode = (uint) Util.RandomClass.Next(0, int.MaxValue);
162
163 p_scene.AddNewClient(npcAvatar);
164
165 ScenePresence sp;
166 if (p_scene.TryGetScenePresence(npcAvatar.AgentId, out sp))
167 {
168 AvatarAppearance x = GetAppearance(p_cloneAppearanceFrom, p_scene);
169
170 sp.Appearance.SetTextureEntries(x.Texture);
171 sp.Appearance.SetVisualParams((byte[])x.VisualParams.Clone());
172 sp.SendAppearanceToAllOtherAgents();
173 }
174
175 m_avatars.Add(npcAvatar.AgentId, npcAvatar);
176
177 p_returnUuid = npcAvatar.AgentId;
178 }
179 }
180 }
181
182 public void PostInitialise() 157 public void PostInitialise()
183 { 158 {
184 } 159 }
@@ -197,4 +172,4 @@ namespace OpenSim.Region.OptionalModules.World.NPC
197 get { return true; } 172 get { return true; }
198 } 173 }
199 } 174 }
200} 175} \ No newline at end of file
diff --git a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs
new file mode 100644
index 0000000..899e721
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs
@@ -0,0 +1,71 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Reflection;
30using Nini.Config;
31using NUnit.Framework;
32using OpenMetaverse;
33using OpenSim.Framework;
34using OpenSim.Framework.Communications;
35using OpenSim.Region.CoreModules.ServiceConnectorsOut.Avatar;
36using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes;
38using OpenSim.Services.AvatarService;
39using OpenSim.Tests.Common;
40using OpenSim.Tests.Common.Mock;
41
42namespace OpenSim.Region.OptionalModules.World.NPC.Tests
43{
44 [TestFixture]
45 public class NPCModuleTests
46 {
47 [Test]
48 public void TestCreate()
49 {
50 TestHelper.InMethod();
51// log4net.Config.XmlConfigurator.Configure();
52
53 IConfigSource config = new IniConfigSource();
54
55 config.AddConfig("Modules");
56 config.Configs["Modules"].Set("AvatarServices", "LocalAvatarServicesConnector");
57 config.AddConfig("AvatarService");
58 config.Configs["AvatarService"].Set("LocalServiceModule", "OpenSim.Services.AvatarService.dll:AvatarService");
59 config.Configs["AvatarService"].Set("StorageProvider", "OpenSim.Data.Null.dll");
60
61 TestScene scene = SceneSetupHelpers.SetupScene();
62 SceneSetupHelpers.SetupSceneModules(scene, config, new NPCModule(), new LocalAvatarServicesConnector());
63
64 INPCModule npcModule = scene.RequestModuleInterface<INPCModule>();
65 UUID npcId = npcModule.CreateNPC("John", "Smith", new Vector3(128, 128, 30), scene, UUID.Zero);
66
67 ScenePresence npc = scene.GetScenePresence(npcId);
68 Assert.That(npc, Is.Not.Null);
69 }
70 }
71} \ No newline at end of file
diff --git a/OpenSim/Region/Physics/Manager/PhysicsScene.cs b/OpenSim/Region/Physics/Manager/PhysicsScene.cs
index 54c50f8..13ea084 100644
--- a/OpenSim/Region/Physics/Manager/PhysicsScene.cs
+++ b/OpenSim/Region/Physics/Manager/PhysicsScene.cs
@@ -86,7 +86,10 @@ namespace OpenSim.Region.Physics.Manager
86 Vector3 size, Quaternion rotation, bool isPhysical) 86 Vector3 size, Quaternion rotation, bool isPhysical)
87 { 87 {
88 PhysicsActor ret = AddPrimShape(primName, pbs, position, size, rotation, isPhysical); 88 PhysicsActor ret = AddPrimShape(primName, pbs, position, size, rotation, isPhysical);
89 if (ret != null) ret.LocalID = localID; 89
90 if (ret != null)
91 ret.LocalID = localID;
92
90 return ret; 93 return ret;
91 } 94 }
92 95
diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
index 99b2d84..5ca5f20 100644
--- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
+++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
@@ -100,7 +100,6 @@ namespace OpenSim.Region.Physics.Meshing
100 { 100 {
101 m_log.WarnFormat("[SCULPT]: Unable to create {0} directory: ", decodedSculptMapPath, e.Message); 101 m_log.WarnFormat("[SCULPT]: Unable to create {0} directory: ", decodedSculptMapPath, e.Message);
102 } 102 }
103
104 } 103 }
105 104
106 /// <summary> 105 /// <summary>
@@ -156,7 +155,6 @@ namespace OpenSim.Region.Physics.Meshing
156 return box; 155 return box;
157 } 156 }
158 157
159
160 /// <summary> 158 /// <summary>
161 /// Creates a simple bounding box mesh for a complex input mesh 159 /// Creates a simple bounding box mesh for a complex input mesh
162 /// </summary> 160 /// </summary>
@@ -193,7 +191,6 @@ namespace OpenSim.Region.Physics.Meshing
193 m_log.Error(message); 191 m_log.Error(message);
194 m_log.Error("\nPrim Name: " + primName); 192 m_log.Error("\nPrim Name: " + primName);
195 m_log.Error("****** PrimMesh Parameters ******\n" + primMesh.ParamsToDisplayString()); 193 m_log.Error("****** PrimMesh Parameters ******\n" + primMesh.ParamsToDisplayString());
196
197 } 194 }
198 195
199 private ulong GetMeshKey(PrimitiveBaseShape pbs, Vector3 size, float lod) 196 private ulong GetMeshKey(PrimitiveBaseShape pbs, Vector3 size, float lod)
@@ -257,6 +254,52 @@ namespace OpenSim.Region.Physics.Meshing
257 return ((hash << 5) + hash) + (ulong)(c >> 8); 254 return ((hash << 5) + hash) + (ulong)(c >> 8);
258 } 255 }
259 256
257 /// <summary>
258 /// Add a submesh to an existing list of coords and faces.
259 /// </summary>
260 /// <param name="subMeshData"></param>
261 /// <param name="size">Size of entire object</param>
262 /// <param name="coords"></param>
263 /// <param name="faces"></param>
264 private void AddSubMesh(OSDMap subMeshData, Vector3 size, List<Coord> coords, List<Face> faces)
265 {
266 // Console.WriteLine("subMeshMap for {0} - {1}", primName, Util.GetFormattedXml((OSD)subMeshMap));
267
268 // As per http://wiki.secondlife.com/wiki/Mesh/Mesh_Asset_Format, some Mesh Level
269 // of Detail Blocks (maps) contain just a NoGeometry key to signal there is no
270 // geometry for this submesh.
271 if (subMeshData.ContainsKey("NoGeometry") && ((OSDBoolean)subMeshData["NoGeometry"]))
272 return;
273
274 OpenMetaverse.Vector3 posMax = ((OSDMap)subMeshData["PositionDomain"])["Max"].AsVector3();
275 OpenMetaverse.Vector3 posMin = ((OSDMap)subMeshData["PositionDomain"])["Min"].AsVector3();
276 ushort faceIndexOffset = (ushort)coords.Count;
277
278 byte[] posBytes = subMeshData["Position"].AsBinary();
279 for (int i = 0; i < posBytes.Length; i += 6)
280 {
281 ushort uX = Utils.BytesToUInt16(posBytes, i);
282 ushort uY = Utils.BytesToUInt16(posBytes, i + 2);
283 ushort uZ = Utils.BytesToUInt16(posBytes, i + 4);
284
285 Coord c = new Coord(
286 Utils.UInt16ToFloat(uX, posMin.X, posMax.X) * size.X,
287 Utils.UInt16ToFloat(uY, posMin.Y, posMax.Y) * size.Y,
288 Utils.UInt16ToFloat(uZ, posMin.Z, posMax.Z) * size.Z);
289
290 coords.Add(c);
291 }
292
293 byte[] triangleBytes = subMeshData["TriangleList"].AsBinary();
294 for (int i = 0; i < triangleBytes.Length; i += 6)
295 {
296 ushort v1 = (ushort)(Utils.BytesToUInt16(triangleBytes, i) + faceIndexOffset);
297 ushort v2 = (ushort)(Utils.BytesToUInt16(triangleBytes, i + 2) + faceIndexOffset);
298 ushort v3 = (ushort)(Utils.BytesToUInt16(triangleBytes, i + 4) + faceIndexOffset);
299 Face f = new Face(v1, v2, v3);
300 faces.Add(f);
301 }
302 }
260 303
261 private Mesh CreateMeshFromPrimMesher(string primName, PrimitiveBaseShape primShape, Vector3 size, float lod) 304 private Mesh CreateMeshFromPrimMesher(string primName, PrimitiveBaseShape primShape, Vector3 size, float lod)
262 { 305 {
@@ -276,7 +319,7 @@ namespace OpenSim.Region.Physics.Meshing
276 if (!useMeshiesPhysicsMesh) 319 if (!useMeshiesPhysicsMesh)
277 return null; 320 return null;
278 321
279 m_log.Debug("[MESH]: experimental mesh proxy generation"); 322 m_log.DebugFormat("[MESH]: experimental mesh proxy generation for {0}", primName);
280 323
281 OSD meshOsd = null; 324 OSD meshOsd = null;
282 325
@@ -291,23 +334,38 @@ namespace OpenSim.Region.Physics.Meshing
291 { 334 {
292 try 335 try
293 { 336 {
294 meshOsd = (OSDMap)OSDParser.DeserializeLLSDBinary(data); 337 OSD osd = OSDParser.DeserializeLLSDBinary(data);
338 if (osd is OSDMap)
339 meshOsd = (OSDMap)osd;
340 else
341 {
342 m_log.Warn("[Mesh}: unable to cast mesh asset to OSDMap");
343 return null;
344 }
295 } 345 }
296 catch (Exception e) 346 catch (Exception e)
297 { 347 {
298 m_log.Error("[MESH]: Exception deserializing mesh asset header:" + e.ToString()); 348 m_log.Error("[MESH]: Exception deserializing mesh asset header:" + e.ToString());
299 } 349 }
350
300 start = data.Position; 351 start = data.Position;
301 } 352 }
302 353
303 if (meshOsd is OSDMap) 354 if (meshOsd is OSDMap)
304 { 355 {
356 OSDMap physicsParms = null;
305 OSDMap map = (OSDMap)meshOsd; 357 OSDMap map = (OSDMap)meshOsd;
306 OSDMap physicsParms = (OSDMap)map["physics_shape"]; // old asset format 358 if (map.ContainsKey("physics_shape"))
307 359 physicsParms = (OSDMap)map["physics_shape"]; // old asset format
308 if (physicsParms.Count == 0) 360 else if (map.ContainsKey("physics_mesh"))
309 physicsParms = (OSDMap)map["physics_mesh"]; // new asset format 361 physicsParms = (OSDMap)map["physics_mesh"]; // new asset format
310 362
363 if (physicsParms == null)
364 {
365 m_log.Warn("[MESH]: no recognized physics mesh found in mesh asset");
366 return null;
367 }
368
311 int physOffset = physicsParms["offset"].AsInteger() + (int)start; 369 int physOffset = physicsParms["offset"].AsInteger() + (int)start;
312 int physSize = physicsParms["size"].AsInteger(); 370 int physSize = physicsParms["size"].AsInteger();
313 371
@@ -353,42 +411,13 @@ namespace OpenSim.Region.Physics.Meshing
353 // physics_shape is an array of OSDMaps, one for each submesh 411 // physics_shape is an array of OSDMaps, one for each submesh
354 if (decodedMeshOsd is OSDArray) 412 if (decodedMeshOsd is OSDArray)
355 { 413 {
414// Console.WriteLine("decodedMeshOsd for {0} - {1}", primName, Util.GetFormattedXml(decodedMeshOsd));
415
356 decodedMeshOsdArray = (OSDArray)decodedMeshOsd; 416 decodedMeshOsdArray = (OSDArray)decodedMeshOsd;
357 foreach (OSD subMeshOsd in decodedMeshOsdArray) 417 foreach (OSD subMeshOsd in decodedMeshOsdArray)
358 { 418 {
359 if (subMeshOsd is OSDMap) 419 if (subMeshOsd is OSDMap)
360 { 420 AddSubMesh(subMeshOsd as OSDMap, size, coords, faces);
361 OSDMap subMeshMap = (OSDMap)subMeshOsd;
362
363 OpenMetaverse.Vector3 posMax = ((OSDMap)subMeshMap["PositionDomain"])["Max"].AsVector3();
364 OpenMetaverse.Vector3 posMin = ((OSDMap)subMeshMap["PositionDomain"])["Min"].AsVector3();
365 ushort faceIndexOffset = (ushort)coords.Count;
366
367 byte[] posBytes = subMeshMap["Position"].AsBinary();
368 for (int i = 0; i < posBytes.Length; i += 6)
369 {
370 ushort uX = Utils.BytesToUInt16(posBytes, i);
371 ushort uY = Utils.BytesToUInt16(posBytes, i + 2);
372 ushort uZ = Utils.BytesToUInt16(posBytes, i + 4);
373
374 Coord c = new Coord(
375 Utils.UInt16ToFloat(uX, posMin.X, posMax.X) * size.X,
376 Utils.UInt16ToFloat(uY, posMin.Y, posMax.Y) * size.Y,
377 Utils.UInt16ToFloat(uZ, posMin.Z, posMax.Z) * size.Z);
378
379 coords.Add(c);
380 }
381
382 byte[] triangleBytes = subMeshMap["TriangleList"].AsBinary();
383 for (int i = 0; i < triangleBytes.Length; i += 6)
384 {
385 ushort v1 = (ushort)(Utils.BytesToUInt16(triangleBytes, i) + faceIndexOffset);
386 ushort v2 = (ushort)(Utils.BytesToUInt16(triangleBytes, i + 2) + faceIndexOffset);
387 ushort v3 = (ushort)(Utils.BytesToUInt16(triangleBytes, i + 4) + faceIndexOffset);
388 Face f = new Face(v1, v2, v3);
389 faces.Add(f);
390 }
391 }
392 } 421 }
393 } 422 }
394 } 423 }
@@ -511,7 +540,6 @@ namespace OpenSim.Region.Physics.Meshing
511 540
512 profileBegin = 0.5f * profileBegin + 0.5f; 541 profileBegin = 0.5f * profileBegin + 0.5f;
513 profileEnd = 0.5f * profileEnd + 0.5f; 542 profileEnd = 0.5f * profileEnd + 0.5f;
514
515 } 543 }
516 544
517 int hollowSides = sides; 545 int hollowSides = sides;
@@ -620,6 +648,7 @@ namespace OpenSim.Region.Physics.Meshing
620 Face f = faces[i]; 648 Face f = faces[i];
621 mesh.Add(new Triangle(vertices[f.v1], vertices[f.v2], vertices[f.v3])); 649 mesh.Add(new Triangle(vertices[f.v1], vertices[f.v2], vertices[f.v3]));
622 } 650 }
651
623 return mesh; 652 return mesh;
624 } 653 }
625 654
@@ -630,6 +659,10 @@ namespace OpenSim.Region.Physics.Meshing
630 659
631 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) 660 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical)
632 { 661 {
662#if SPAM
663 m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName);
664#endif
665
633 Mesh mesh = null; 666 Mesh mesh = null;
634 ulong key = 0; 667 ulong key = 0;
635 668
diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
index c91658e..123c8ff 100644
--- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
+++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
@@ -38,6 +38,9 @@
38 * switch between 'VEHICLE' parameter use and general dynamics 38 * switch between 'VEHICLE' parameter use and general dynamics
39 * settings use. 39 * settings use.
40 */ 40 */
41
42//#define SPAM
43
41using System; 44using System;
42using System.Collections.Generic; 45using System.Collections.Generic;
43using System.Reflection; 46using System.Reflection;
@@ -54,7 +57,6 @@ namespace OpenSim.Region.Physics.OdePlugin
54 /// <summary> 57 /// <summary>
55 /// Various properties that ODE uses for AMotors but isn't exposed in ODE.NET so we must define them ourselves. 58 /// Various properties that ODE uses for AMotors but isn't exposed in ODE.NET so we must define them ourselves.
56 /// </summary> 59 /// </summary>
57
58 public class OdePrim : PhysicsActor 60 public class OdePrim : PhysicsActor
59 { 61 {
60 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 62 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
@@ -279,14 +281,14 @@ namespace OpenSim.Region.Physics.OdePlugin
279 281
280 public override bool Selected 282 public override bool Selected
281 { 283 {
282 set { 284 set
283 285 {
284
285 // This only makes the object not collidable if the object 286 // This only makes the object not collidable if the object
286 // is physical or the object is modified somehow *IN THE FUTURE* 287 // is physical or the object is modified somehow *IN THE FUTURE*
287 // without this, if an avatar selects prim, they can walk right 288 // without this, if an avatar selects prim, they can walk right
288 // through it while it's selected 289 // through it while it's selected
289 m_collisionscore = 0; 290 m_collisionscore = 0;
291
290 if ((m_isphysical && !_zeroFlag) || !value) 292 if ((m_isphysical && !_zeroFlag) || !value)
291 { 293 {
292 m_taintselected = value; 294 m_taintselected = value;
@@ -297,7 +299,9 @@ namespace OpenSim.Region.Physics.OdePlugin
297 m_taintselected = value; 299 m_taintselected = value;
298 m_isSelected = value; 300 m_isSelected = value;
299 } 301 }
300 if (m_isSelected) disableBodySoft(); 302
303 if (m_isSelected)
304 disableBodySoft();
301 } 305 }
302 } 306 }
303 307
@@ -324,8 +328,6 @@ namespace OpenSim.Region.Physics.OdePlugin
324 //m_log.Warn("Setting Geom to: " + prim_geom); 328 //m_log.Warn("Setting Geom to: " + prim_geom);
325 } 329 }
326 330
327
328
329 public void enableBodySoft() 331 public void enableBodySoft()
330 { 332 {
331 if (!childPrim) 333 if (!childPrim)
@@ -626,8 +628,6 @@ namespace OpenSim.Region.Physics.OdePlugin
626 break; 628 break;
627 } 629 }
628 630
629
630
631 float taperX1; 631 float taperX1;
632 float taperY1; 632 float taperY1;
633 float taperX; 633 float taperX;
@@ -682,9 +682,6 @@ namespace OpenSim.Region.Physics.OdePlugin
682// else if (returnMass > _parent_scene.maximumMassObject) 682// else if (returnMass > _parent_scene.maximumMassObject)
683// returnMass = _parent_scene.maximumMassObject; 683// returnMass = _parent_scene.maximumMassObject;
684 684
685
686
687
688 // Recursively calculate mass 685 // Recursively calculate mass
689 bool HasChildPrim = false; 686 bool HasChildPrim = false;
690 lock (childrenPrim) 687 lock (childrenPrim)
@@ -693,8 +690,8 @@ namespace OpenSim.Region.Physics.OdePlugin
693 { 690 {
694 HasChildPrim = true; 691 HasChildPrim = true;
695 } 692 }
696
697 } 693 }
694
698 if (HasChildPrim) 695 if (HasChildPrim)
699 { 696 {
700 OdePrim[] childPrimArr = new OdePrim[0]; 697 OdePrim[] childPrimArr = new OdePrim[0];
@@ -711,10 +708,12 @@ namespace OpenSim.Region.Physics.OdePlugin
711 break; 708 break;
712 } 709 }
713 } 710 }
711
714 if (returnMass > _parent_scene.maximumMassObject) 712 if (returnMass > _parent_scene.maximumMassObject)
715 returnMass = _parent_scene.maximumMassObject; 713 returnMass = _parent_scene.maximumMassObject;
714
716 return returnMass; 715 return returnMass;
717 }// end CalculateMass 716 }
718 717
719 #endregion 718 #endregion
720 719
@@ -750,7 +749,6 @@ namespace OpenSim.Region.Physics.OdePlugin
750 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); 749 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
751 } 750 }
752 751
753
754 d.BodyDestroy(Body); 752 d.BodyDestroy(Body);
755 lock (childrenPrim) 753 lock (childrenPrim)
756 { 754 {
@@ -779,7 +777,6 @@ namespace OpenSim.Region.Physics.OdePlugin
779 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); 777 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
780 } 778 }
781 779
782
783 Body = IntPtr.Zero; 780 Body = IntPtr.Zero;
784 } 781 }
785 } 782 }
@@ -791,6 +788,8 @@ namespace OpenSim.Region.Physics.OdePlugin
791 788
792 public void setMesh(OdeScene parent_scene, IMesh mesh) 789 public void setMesh(OdeScene parent_scene, IMesh mesh)
793 { 790 {
791// m_log.DebugFormat("[ODE PRIM]: Setting mesh on {0} to {1}", Name, mesh);
792
794 // This sleeper is there to moderate how long it takes between 793 // This sleeper is there to moderate how long it takes between
795 // setting up the mesh and pre-processing it when we get rapid fire mesh requests on a single object 794 // setting up the mesh and pre-processing it when we get rapid fire mesh requests on a single object
796 795
@@ -869,7 +868,7 @@ namespace OpenSim.Region.Physics.OdePlugin
869 if (prim_geom != IntPtr.Zero) 868 if (prim_geom != IntPtr.Zero)
870 { 869 {
871 if (!_position.ApproxEquals(m_taintposition, 0f)) 870 if (!_position.ApproxEquals(m_taintposition, 0f))
872 changemove(timestep); 871 changemove(timestep);
873 872
874 if (m_taintrot != _orientation) 873 if (m_taintrot != _orientation)
875 { 874 {
@@ -887,19 +886,15 @@ namespace OpenSim.Region.Physics.OdePlugin
887 rotate(timestep); 886 rotate(timestep);
888 } 887 }
889 } 888 }
890 //
891 889
892 if (m_taintPhysics != m_isphysical && !(m_taintparent != _parent)) 890 if (m_taintPhysics != m_isphysical && !(m_taintparent != _parent))
893 changePhysicsStatus(timestep); 891 changePhysicsStatus(timestep);
894 //
895 892
896 if (!_size.ApproxEquals(m_taintsize,0f)) 893 if (!_size.ApproxEquals(m_taintsize, 0f))
897 changesize(timestep); 894 changesize(timestep);
898 //
899 895
900 if (m_taintshape) 896 if (m_taintshape)
901 changeshape(timestep); 897 changeshape(timestep);
902 //
903 898
904 if (m_taintforce) 899 if (m_taintforce)
905 changeAddForce(timestep); 900 changeAddForce(timestep);
@@ -927,7 +922,6 @@ namespace OpenSim.Region.Physics.OdePlugin
927 922
928 if (!m_angularlock.ApproxEquals(m_taintAngularLock,0f)) 923 if (!m_angularlock.ApproxEquals(m_taintAngularLock,0f))
929 changeAngularLock(timestep); 924 changeAngularLock(timestep);
930
931 } 925 }
932 else 926 else
933 { 927 {
@@ -935,7 +929,6 @@ namespace OpenSim.Region.Physics.OdePlugin
935 } 929 }
936 } 930 }
937 931
938
939 private void changeAngularLock(float timestep) 932 private void changeAngularLock(float timestep)
940 { 933 {
941 // do we have a Physical object? 934 // do we have a Physical object?
@@ -963,7 +956,6 @@ namespace OpenSim.Region.Physics.OdePlugin
963 } 956 }
964 // Store this for later in case we get turned into a separate body 957 // Store this for later in case we get turned into a separate body
965 m_angularlock = m_taintAngularLock; 958 m_angularlock = m_taintAngularLock;
966
967 } 959 }
968 960
969 private void changelink(float timestep) 961 private void changelink(float timestep)
@@ -1102,7 +1094,6 @@ namespace OpenSim.Region.Physics.OdePlugin
1102 m_log.DebugFormat("[PHYSICS]: {0} ain't got no boooooooooddy, no body", Name); 1094 m_log.DebugFormat("[PHYSICS]: {0} ain't got no boooooooooddy, no body", Name);
1103 } 1095 }
1104 1096
1105
1106 prm.m_interpenetrationcount = 0; 1097 prm.m_interpenetrationcount = 0;
1107 prm.m_collisionscore = 0; 1098 prm.m_collisionscore = 0;
1108 prm.m_disabled = false; 1099 prm.m_disabled = false;
@@ -1162,7 +1153,6 @@ namespace OpenSim.Region.Physics.OdePlugin
1162 } 1153 }
1163 } 1154 }
1164 } 1155 }
1165
1166 } 1156 }
1167 1157
1168 private void ChildSetGeom(OdePrim odePrim) 1158 private void ChildSetGeom(OdePrim odePrim)
@@ -1223,17 +1213,12 @@ namespace OpenSim.Region.Physics.OdePlugin
1223 //Console.WriteLine("childrenPrim.Remove " + odePrim); 1213 //Console.WriteLine("childrenPrim.Remove " + odePrim);
1224 childrenPrim.Remove(odePrim); 1214 childrenPrim.Remove(odePrim);
1225 } 1215 }
1226
1227
1228
1229 1216
1230 if (Body != IntPtr.Zero) 1217 if (Body != IntPtr.Zero)
1231 { 1218 {
1232 _parent_scene.remActivePrim(this); 1219 _parent_scene.remActivePrim(this);
1233 } 1220 }
1234 1221
1235
1236
1237 lock (childrenPrim) 1222 lock (childrenPrim)
1238 { 1223 {
1239 foreach (OdePrim prm in childrenPrim) 1224 foreach (OdePrim prm in childrenPrim)
@@ -1242,8 +1227,6 @@ namespace OpenSim.Region.Physics.OdePlugin
1242 ParentPrim(prm); 1227 ParentPrim(prm);
1243 } 1228 }
1244 } 1229 }
1245
1246
1247 } 1230 }
1248 1231
1249 private void changeSelectedStatus(float timestep) 1232 private void changeSelectedStatus(float timestep)
@@ -1398,7 +1381,6 @@ namespace OpenSim.Region.Physics.OdePlugin
1398 } 1381 }
1399 } 1382 }
1400 } 1383 }
1401
1402 else 1384 else
1403 { 1385 {
1404 _parent_scene.waitForSpaceUnlock(m_targetSpace); 1386 _parent_scene.waitForSpaceUnlock(m_targetSpace);
@@ -1438,10 +1420,11 @@ namespace OpenSim.Region.Physics.OdePlugin
1438 } 1420 }
1439 } 1421 }
1440 1422
1441
1442 lock (_parent_scene.OdeLock) 1423 lock (_parent_scene.OdeLock)
1443 { 1424 {
1444//Console.WriteLine("changeadd 1"); 1425#if SPAM
1426Console.WriteLine("changeadd 1");
1427#endif
1445 CreateGeom(m_targetSpace, _mesh); 1428 CreateGeom(m_targetSpace, _mesh);
1446 1429
1447 if (prim_geom != IntPtr.Zero) 1430 if (prim_geom != IntPtr.Zero)
@@ -1684,13 +1667,11 @@ Console.WriteLine(" JointCreateFixed");
1684 { 1667 {
1685 PID_G = m_PIDTau + 1; 1668 PID_G = m_PIDTau + 1;
1686 } 1669 }
1687
1688 1670
1689 // Where are we, and where are we headed? 1671 // Where are we, and where are we headed?
1690 d.Vector3 pos = d.BodyGetPosition(Body); 1672 d.Vector3 pos = d.BodyGetPosition(Body);
1691 d.Vector3 vel = d.BodyGetLinearVel(Body); 1673 d.Vector3 vel = d.BodyGetLinearVel(Body);
1692 1674
1693
1694 // Non-Vehicles have a limited set of Hover options. 1675 // Non-Vehicles have a limited set of Hover options.
1695 // determine what our target height really is based on HoverType 1676 // determine what our target height really is based on HoverType
1696 switch (m_PIDHoverType) 1677 switch (m_PIDHoverType)
@@ -1796,8 +1777,6 @@ Console.WriteLine(" JointCreateFixed");
1796 } 1777 }
1797 } 1778 }
1798 1779
1799
1800
1801 public void rotate(float timestep) 1780 public void rotate(float timestep)
1802 { 1781 {
1803 d.Quaternion myrot = new d.Quaternion(); 1782 d.Quaternion myrot = new d.Quaternion();
@@ -1908,7 +1887,10 @@ Console.WriteLine(" JointCreateFixed");
1908 1887
1909 public void changesize(float timestamp) 1888 public void changesize(float timestamp)
1910 { 1889 {
1911 1890#if SPAM
1891 m_log.DebugFormat("[ODE PRIM]: Called changesize");
1892#endif
1893
1912 string oldname = _parent_scene.geom_name_map[prim_geom]; 1894 string oldname = _parent_scene.geom_name_map[prim_geom];
1913 1895
1914 if (_size.X <= 0) _size.X = 0.01f; 1896 if (_size.X <= 0) _size.X = 0.01f;
@@ -1918,8 +1900,9 @@ Console.WriteLine(" JointCreateFixed");
1918 // Cleanup of old prim geometry 1900 // Cleanup of old prim geometry
1919 if (_mesh != null) 1901 if (_mesh != null)
1920 { 1902 {
1921 // Cleanup meshing here 1903 // TODO: Cleanup meshing here
1922 } 1904 }
1905
1923 //kill body to rebuild 1906 //kill body to rebuild
1924 if (IsPhysical && Body != IntPtr.Zero) 1907 if (IsPhysical && Body != IntPtr.Zero)
1925 { 1908 {
@@ -1936,11 +1919,13 @@ Console.WriteLine(" JointCreateFixed");
1936 disableBody(); 1919 disableBody();
1937 } 1920 }
1938 } 1921 }
1922
1939 if (d.SpaceQuery(m_targetSpace, prim_geom)) 1923 if (d.SpaceQuery(m_targetSpace, prim_geom))
1940 { 1924 {
1941 _parent_scene.waitForSpaceUnlock(m_targetSpace); 1925 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1942 d.SpaceRemove(m_targetSpace, prim_geom); 1926 d.SpaceRemove(m_targetSpace, prim_geom);
1943 } 1927 }
1928
1944 d.GeomDestroy(prim_geom); 1929 d.GeomDestroy(prim_geom);
1945 prim_geom = IntPtr.Zero; 1930 prim_geom = IntPtr.Zero;
1946 // we don't need to do space calculation because the client sends a position update also. 1931 // we don't need to do space calculation because the client sends a position update also.
@@ -1960,15 +1945,19 @@ Console.WriteLine(" JointCreateFixed");
1960 mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, meshlod, IsPhysical); 1945 mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, meshlod, IsPhysical);
1961 1946
1962 //IMesh mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, meshlod, IsPhysical); 1947 //IMesh mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, meshlod, IsPhysical);
1963//Console.WriteLine("changesize 1"); 1948#if SPAM
1949Console.WriteLine("changesize 1");
1950#endif
1964 CreateGeom(m_targetSpace, mesh); 1951 CreateGeom(m_targetSpace, mesh);
1965
1966
1967 } 1952 }
1968 else 1953 else
1969 { 1954 {
1970 _mesh = null; 1955 _mesh = null;
1971//Console.WriteLine("changesize 2"); 1956
1957#if SPAM
1958Console.WriteLine("changesize 2");
1959#endif
1960
1972 CreateGeom(m_targetSpace, _mesh); 1961 CreateGeom(m_targetSpace, _mesh);
1973 } 1962 }
1974 1963
@@ -2004,8 +1993,6 @@ Console.WriteLine(" JointCreateFixed");
2004 m_taintsize = _size; 1993 m_taintsize = _size;
2005 } 1994 }
2006 1995
2007
2008
2009 public void changefloatonwater(float timestep) 1996 public void changefloatonwater(float timestep)
2010 { 1997 {
2011 m_collidesWater = m_taintCollidesWater; 1998 m_collidesWater = m_taintCollidesWater;
@@ -2053,6 +2040,7 @@ Console.WriteLine(" JointCreateFixed");
2053 prim_geom = IntPtr.Zero; 2040 prim_geom = IntPtr.Zero;
2054 m_log.ErrorFormat("[PHYSICS]: PrimGeom dead for {0}", Name); 2041 m_log.ErrorFormat("[PHYSICS]: PrimGeom dead for {0}", Name);
2055 } 2042 }
2043
2056 prim_geom = IntPtr.Zero; 2044 prim_geom = IntPtr.Zero;
2057 // we don't need to do space calculation because the client sends a position update also. 2045 // we don't need to do space calculation because the client sends a position update also.
2058 if (_size.X <= 0) _size.X = 0.01f; 2046 if (_size.X <= 0) _size.X = 0.01f;
@@ -2062,7 +2050,7 @@ Console.WriteLine(" JointCreateFixed");
2062 2050
2063 if (_parent_scene.needsMeshing(_pbs)) 2051 if (_parent_scene.needsMeshing(_pbs))
2064 { 2052 {
2065 // Don't need to re-enable body.. it's done in SetMesh 2053 // Don't need to re-enable body.. it's done in CreateMesh
2066 float meshlod = _parent_scene.meshSculptLOD; 2054 float meshlod = _parent_scene.meshSculptLOD;
2067 2055
2068 if (IsPhysical) 2056 if (IsPhysical)
@@ -2070,12 +2058,18 @@ Console.WriteLine(" JointCreateFixed");
2070 2058
2071 IMesh mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, meshlod, IsPhysical); 2059 IMesh mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, meshlod, IsPhysical);
2072 // createmesh returns null when it doesn't mesh. 2060 // createmesh returns null when it doesn't mesh.
2061#if SPAM
2062Console.WriteLine("changeshape needed meshing");
2063#endif
2073 CreateGeom(m_targetSpace, mesh); 2064 CreateGeom(m_targetSpace, mesh);
2074 } 2065 }
2075 else 2066 else
2076 { 2067 {
2077 _mesh = null; 2068 _mesh = null;
2078//Console.WriteLine("changeshape"); 2069
2070#if SPAM
2071Console.WriteLine("changeshape not need meshing");
2072#endif
2079 CreateGeom(m_targetSpace, null); 2073 CreateGeom(m_targetSpace, null);
2080 } 2074 }
2081 2075
@@ -2110,6 +2104,7 @@ Console.WriteLine(" JointCreateFixed");
2110 parent.ChildSetGeom(this); 2104 parent.ChildSetGeom(this);
2111 } 2105 }
2112 } 2106 }
2107
2113 resetCollisionAccounting(); 2108 resetCollisionAccounting();
2114 m_taintshape = false; 2109 m_taintshape = false;
2115 } 2110 }
@@ -2160,11 +2155,8 @@ Console.WriteLine(" JointCreateFixed");
2160 } 2155 }
2161 2156
2162 m_taintforce = false; 2157 m_taintforce = false;
2163
2164 } 2158 }
2165 2159
2166
2167
2168 public void changeSetTorque(float timestamp) 2160 public void changeSetTorque(float timestamp)
2169 { 2161 {
2170 if (!m_isSelected) 2162 if (!m_isSelected)
@@ -2352,7 +2344,7 @@ Console.WriteLine(" JointCreateFixed");
2352 { 2344 {
2353 lock (_parent_scene.OdeLock) 2345 lock (_parent_scene.OdeLock)
2354 { 2346 {
2355 m_isVolumeDetect = (param!=0); 2347 m_isVolumeDetect = (param != 0);
2356 } 2348 }
2357 } 2349 }
2358 2350
@@ -2833,7 +2825,6 @@ Console.WriteLine(" JointCreateFixed");
2833 2825
2834 public override float APIDDamping{ set { return; } } 2826 public override float APIDDamping{ set { return; } }
2835 2827
2836
2837 private void createAMotor(Vector3 axis) 2828 private void createAMotor(Vector3 axis)
2838 { 2829 {
2839 if (Body == IntPtr.Zero) 2830 if (Body == IntPtr.Zero)
@@ -2953,7 +2944,6 @@ Console.WriteLine(" JointCreateFixed");
2953 //d.JointSetAMotorParam(Amotor, (int) dParam.Vel, 9000f); 2944 //d.JointSetAMotorParam(Amotor, (int) dParam.Vel, 9000f);
2954 d.JointSetAMotorParam(Amotor, (int)dParam.FudgeFactor, 0f); 2945 d.JointSetAMotorParam(Amotor, (int)dParam.FudgeFactor, 0f);
2955 d.JointSetAMotorParam(Amotor, (int)dParam.FMax, Mass * 50f);// 2946 d.JointSetAMotorParam(Amotor, (int)dParam.FMax, Mass * 50f);//
2956
2957 } 2947 }
2958 2948
2959 public Matrix4 FromDMass(d.Mass pMass) 2949 public Matrix4 FromDMass(d.Mass pMass)
@@ -3038,8 +3028,6 @@ Console.WriteLine(" JointCreateFixed");
3038 return Matrix4.Identity; // should probably throw an error. singluar matrix inverse not possible 3028 return Matrix4.Identity; // should probably throw an error. singluar matrix inverse not possible
3039 } 3029 }
3040 3030
3041
3042
3043 return (Adjoint(pMat) / determinant3x3(pMat)); 3031 return (Adjoint(pMat) / determinant3x3(pMat));
3044 } 3032 }
3045 3033
@@ -3076,6 +3064,7 @@ Console.WriteLine(" JointCreateFixed");
3076 } 3064 }
3077 m++; 3065 m++;
3078 } 3066 }
3067
3079 return minor; 3068 return minor;
3080 } 3069 }
3081 3070
@@ -3178,7 +3167,6 @@ Console.WriteLine(" JointCreateFixed");
3178 3167
3179 det = diag1 + diag2 + diag3 - (diag4 + diag5 + diag6); 3168 det = diag1 + diag2 + diag3 - (diag4 + diag5 + diag6);
3180 return det; 3169 return det;
3181
3182 } 3170 }
3183 3171
3184 private static void DMassCopy(ref d.Mass src, ref d.Mass dst) 3172 private static void DMassCopy(ref d.Mass src, ref d.Mass dst)
@@ -3203,6 +3191,5 @@ Console.WriteLine(" JointCreateFixed");
3203 { 3191 {
3204 m_material = pMaterial; 3192 m_material = pMaterial;
3205 } 3193 }
3206
3207 } 3194 }
3208} 3195}
diff --git a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs
index a0101af..ebd46ab 100644
--- a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs
+++ b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs
@@ -25,8 +25,6 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28//#define USE_DRAWSTUFF
29
30using System; 28using System;
31using System.Collections.Generic; 29using System.Collections.Generic;
32using System.Reflection; 30using System.Reflection;
@@ -37,15 +35,10 @@ using System.Diagnostics;
37using log4net; 35using log4net;
38using Nini.Config; 36using Nini.Config;
39using Ode.NET; 37using Ode.NET;
40#if USE_DRAWSTUFF
41using Drawstuff.NET;
42#endif
43using OpenSim.Framework; 38using OpenSim.Framework;
44using OpenSim.Region.Physics.Manager; 39using OpenSim.Region.Physics.Manager;
45using OpenMetaverse; 40using OpenMetaverse;
46 41
47//using OpenSim.Region.Physics.OdePlugin.Meshing;
48
49namespace OpenSim.Region.Physics.OdePlugin 42namespace OpenSim.Region.Physics.OdePlugin
50{ 43{
51 /// <summary> 44 /// <summary>
@@ -55,12 +48,12 @@ namespace OpenSim.Region.Physics.OdePlugin
55 { 48 {
56 //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 49 //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
57 50
58 private CollisionLocker ode; 51 private CollisionLocker m_ode;
59 private OdeScene _mScene; 52 private OdeScene m_scene;
60 53
61 public OdePlugin() 54 public OdePlugin()
62 { 55 {
63 ode = new CollisionLocker(); 56 m_ode = new CollisionLocker();
64 } 57 }
65 58
66 public bool Init() 59 public bool Init()
@@ -70,15 +63,15 @@ namespace OpenSim.Region.Physics.OdePlugin
70 63
71 public PhysicsScene GetScene(String sceneIdentifier) 64 public PhysicsScene GetScene(String sceneIdentifier)
72 { 65 {
73 if (_mScene == null) 66 if (m_scene == null)
74 { 67 {
75 // Initializing ODE only when a scene is created allows alternative ODE plugins to co-habit (according to 68 // Initializing ODE only when a scene is created allows alternative ODE plugins to co-habit (according to
76 // http://opensimulator.org/mantis/view.php?id=2750). 69 // http://opensimulator.org/mantis/view.php?id=2750).
77 d.InitODE(); 70 d.InitODE();
78 71
79 _mScene = new OdeScene(ode, sceneIdentifier); 72 m_scene = new OdeScene(m_ode, sceneIdentifier);
80 } 73 }
81 return (_mScene); 74 return (m_scene);
82 } 75 }
83 76
84 public string GetName() 77 public string GetName()
@@ -90,3810 +83,4 @@ namespace OpenSim.Region.Physics.OdePlugin
90 { 83 {
91 } 84 }
92 } 85 }
93 86} \ No newline at end of file
94 public enum StatusIndicators : int
95 {
96 Generic = 0,
97 Start = 1,
98 End = 2
99 }
100
101 public struct sCollisionData
102 {
103 public uint ColliderLocalId;
104 public uint CollidedWithLocalId;
105 public int NumberOfCollisions;
106 public int CollisionType;
107 public int StatusIndicator;
108 public int lastframe;
109 }
110
111 [Flags]
112 public enum CollisionCategories : int
113 {
114 Disabled = 0,
115 Geom = 0x00000001,
116 Body = 0x00000002,
117 Space = 0x00000004,
118 Character = 0x00000008,
119 Land = 0x00000010,
120 Water = 0x00000020,
121 Wind = 0x00000040,
122 Sensor = 0x00000080,
123 Selected = 0x00000100
124 }
125
126 /// <summary>
127 /// Material type for a primitive
128 /// </summary>
129 public enum Material : int
130 {
131 /// <summary></summary>
132 Stone = 0,
133 /// <summary></summary>
134 Metal = 1,
135 /// <summary></summary>
136 Glass = 2,
137 /// <summary></summary>
138 Wood = 3,
139 /// <summary></summary>
140 Flesh = 4,
141 /// <summary></summary>
142 Plastic = 5,
143 /// <summary></summary>
144 Rubber = 6
145
146 }
147
148 public sealed class OdeScene : PhysicsScene
149 {
150 private readonly ILog m_log;
151 // private Dictionary<string, sCollisionData> m_storedCollisions = new Dictionary<string, sCollisionData>();
152
153 CollisionLocker ode;
154
155 private Random fluidRandomizer = new Random(Environment.TickCount);
156
157 private const uint m_regionWidth = Constants.RegionSize;
158 private const uint m_regionHeight = Constants.RegionSize;
159
160 private float ODE_STEPSIZE = 0.020f;
161 private float metersInSpace = 29.9f;
162 private float m_timeDilation = 1.0f;
163
164 public float gravityx = 0f;
165 public float gravityy = 0f;
166 public float gravityz = -9.8f;
167
168 private float contactsurfacelayer = 0.001f;
169
170 private int worldHashspaceLow = -4;
171 private int worldHashspaceHigh = 128;
172
173 private int smallHashspaceLow = -4;
174 private int smallHashspaceHigh = 66;
175
176 private float waterlevel = 0f;
177 private int framecount = 0;
178 //private int m_returncollisions = 10;
179
180 private readonly IntPtr contactgroup;
181
182 internal IntPtr LandGeom;
183 internal IntPtr WaterGeom;
184
185 private float nmTerrainContactFriction = 255.0f;
186 private float nmTerrainContactBounce = 0.1f;
187 private float nmTerrainContactERP = 0.1025f;
188
189 private float mTerrainContactFriction = 75f;
190 private float mTerrainContactBounce = 0.1f;
191 private float mTerrainContactERP = 0.05025f;
192
193 private float nmAvatarObjectContactFriction = 250f;
194 private float nmAvatarObjectContactBounce = 0.1f;
195
196 private float mAvatarObjectContactFriction = 75f;
197 private float mAvatarObjectContactBounce = 0.1f;
198
199 private float avPIDD = 3200f;
200 private float avPIDP = 1400f;
201 private float avCapRadius = 0.37f;
202 private float avStandupTensor = 2000000f;
203 private bool avCapsuleTilted = true; // true = old compatibility mode with leaning capsule; false = new corrected mode
204 public bool IsAvCapsuleTilted { get { return avCapsuleTilted; } set { avCapsuleTilted = value; } }
205 private float avDensity = 80f;
206 private float avHeightFudgeFactor = 0.52f;
207 private float avMovementDivisorWalk = 1.3f;
208 private float avMovementDivisorRun = 0.8f;
209 private float minimumGroundFlightOffset = 3f;
210 public float maximumMassObject = 10000.01f;
211
212 public bool meshSculptedPrim = true;
213 public bool forceSimplePrimMeshing = false;
214
215 public float meshSculptLOD = 32;
216 public float MeshSculptphysicalLOD = 16;
217
218 public float geomDefaultDensity = 10.000006836f;
219
220 public int geomContactPointsStartthrottle = 3;
221 public int geomUpdatesPerThrottledUpdate = 15;
222
223 public float bodyPIDD = 35f;
224 public float bodyPIDG = 25;
225
226 public int geomCrossingFailuresBeforeOutofbounds = 5;
227
228 public float bodyMotorJointMaxforceTensor = 2;
229
230 public int bodyFramesAutoDisable = 20;
231
232
233
234 private float[] _watermap;
235 private bool m_filterCollisions = true;
236
237 private d.NearCallback nearCallback;
238 public d.TriCallback triCallback;
239 public d.TriArrayCallback triArrayCallback;
240 private readonly HashSet<OdeCharacter> _characters = new HashSet<OdeCharacter>();
241 private readonly HashSet<OdePrim> _prims = new HashSet<OdePrim>();
242 private readonly HashSet<OdePrim> _activeprims = new HashSet<OdePrim>();
243 private readonly HashSet<OdePrim> _taintedPrimH = new HashSet<OdePrim>();
244 private readonly Object _taintedPrimLock = new Object();
245 private readonly List<OdePrim> _taintedPrimL = new List<OdePrim>();
246 private readonly HashSet<OdeCharacter> _taintedActors = new HashSet<OdeCharacter>();
247 private readonly List<d.ContactGeom> _perloopContact = new List<d.ContactGeom>();
248 private readonly List<PhysicsActor> _collisionEventPrim = new List<PhysicsActor>();
249 private readonly HashSet<OdeCharacter> _badCharacter = new HashSet<OdeCharacter>();
250 public Dictionary<IntPtr, String> geom_name_map = new Dictionary<IntPtr, String>();
251 public Dictionary<IntPtr, PhysicsActor> actor_name_map = new Dictionary<IntPtr, PhysicsActor>();
252 private bool m_NINJA_physics_joints_enabled = false;
253 //private Dictionary<String, IntPtr> jointpart_name_map = new Dictionary<String,IntPtr>();
254 private readonly Dictionary<String, List<PhysicsJoint>> joints_connecting_actor = new Dictionary<String, List<PhysicsJoint>>();
255 private d.ContactGeom[] contacts;
256 private readonly List<PhysicsJoint> requestedJointsToBeCreated = new List<PhysicsJoint>(); // lock only briefly. accessed by external code (to request new joints) and by OdeScene.Simulate() to move those joints into pending/active
257 private readonly List<PhysicsJoint> pendingJoints = new List<PhysicsJoint>(); // can lock for longer. accessed only by OdeScene.
258 private readonly List<PhysicsJoint> activeJoints = new List<PhysicsJoint>(); // can lock for longer. accessed only by OdeScene.
259 private readonly List<string> requestedJointsToBeDeleted = new List<string>(); // lock only briefly. accessed by external code (to request deletion of joints) and by OdeScene.Simulate() to move those joints out of pending/active
260 private Object externalJointRequestsLock = new Object();
261 private readonly Dictionary<String, PhysicsJoint> SOPName_to_activeJoint = new Dictionary<String, PhysicsJoint>();
262 private readonly Dictionary<String, PhysicsJoint> SOPName_to_pendingJoint = new Dictionary<String, PhysicsJoint>();
263 private readonly DoubleDictionary<Vector3, IntPtr, IntPtr> RegionTerrain = new DoubleDictionary<Vector3, IntPtr, IntPtr>();
264 private readonly Dictionary<IntPtr,float[]> TerrainHeightFieldHeights = new Dictionary<IntPtr, float[]>();
265
266 private d.Contact contact;
267 private d.Contact TerrainContact;
268 private d.Contact AvatarMovementprimContact;
269 private d.Contact AvatarMovementTerrainContact;
270 private d.Contact WaterContact;
271 private d.Contact[,] m_materialContacts;
272
273//Ckrinke: Comment out until used. We declare it, initialize it, but do not use it
274//Ckrinke private int m_randomizeWater = 200;
275 private int m_physicsiterations = 10;
276 private const float m_SkipFramesAtms = 0.40f; // Drop frames gracefully at a 400 ms lag
277 private readonly PhysicsActor PANull = new NullPhysicsActor();
278 private float step_time = 0.0f;
279//Ckrinke: Comment out until used. We declare it, initialize it, but do not use it
280//Ckrinke private int ms = 0;
281 public IntPtr world;
282 //private bool returncollisions = false;
283 // private uint obj1LocalID = 0;
284 private uint obj2LocalID = 0;
285 //private int ctype = 0;
286 private OdeCharacter cc1;
287 private OdePrim cp1;
288 private OdeCharacter cc2;
289 private OdePrim cp2;
290 private int tickCountFrameRun;
291
292 private int latertickcount=0;
293 //private int cStartStop = 0;
294 //private string cDictKey = "";
295
296 public IntPtr space;
297
298 //private IntPtr tmpSpace;
299 // split static geometry collision handling into spaces of 30 meters
300 public IntPtr[,] staticPrimspace;
301
302 public Object OdeLock;
303
304 public IMesher mesher;
305
306 private IConfigSource m_config;
307
308 public bool physics_logging = false;
309 public int physics_logging_interval = 0;
310 public bool physics_logging_append_existing_logfile = false;
311
312 public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f);
313 public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f);
314
315 // TODO: unused: private uint heightmapWidth = m_regionWidth + 1;
316 // TODO: unused: private uint heightmapHeight = m_regionHeight + 1;
317 // TODO: unused: private uint heightmapWidthSamples;
318 // TODO: unused: private uint heightmapHeightSamples;
319
320 private volatile int m_global_contactcount = 0;
321
322 private Vector3 m_worldOffset = Vector3.Zero;
323 public Vector2 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize);
324 private PhysicsScene m_parentScene = null;
325
326 private ODERayCastRequestManager m_rayCastManager;
327
328 /// <summary>
329 /// Initiailizes the scene
330 /// Sets many properties that ODE requires to be stable
331 /// These settings need to be tweaked 'exactly' right or weird stuff happens.
332 /// </summary>
333 public OdeScene(CollisionLocker dode, string sceneIdentifier)
334 {
335 m_log
336 = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.ToString() + "." + sceneIdentifier);
337
338 OdeLock = new Object();
339 ode = dode;
340 nearCallback = near;
341 triCallback = TriCallback;
342 triArrayCallback = TriArrayCallback;
343 m_rayCastManager = new ODERayCastRequestManager(this);
344 lock (OdeLock)
345 {
346 // Create the world and the first space
347 world = d.WorldCreate();
348 space = d.HashSpaceCreate(IntPtr.Zero);
349
350
351 contactgroup = d.JointGroupCreate(0);
352 //contactgroup
353
354 d.WorldSetAutoDisableFlag(world, false);
355 #if USE_DRAWSTUFF
356
357 Thread viewthread = new Thread(new ParameterizedThreadStart(startvisualization));
358 viewthread.Start();
359 #endif
360 }
361
362
363 _watermap = new float[258 * 258];
364
365 // Zero out the prim spaces array (we split our space into smaller spaces so
366 // we can hit test less.
367 }
368
369#if USE_DRAWSTUFF
370 public void startvisualization(object o)
371 {
372 ds.Functions fn;
373 fn.version = ds.VERSION;
374 fn.start = new ds.CallbackFunction(start);
375 fn.step = new ds.CallbackFunction(step);
376 fn.command = new ds.CallbackFunction(command);
377 fn.stop = null;
378 fn.path_to_textures = "./textures";
379 string[] args = new string[0];
380 ds.SimulationLoop(args.Length, args, 352, 288, ref fn);
381 }
382#endif
383
384 // Initialize the mesh plugin
385 public override void Initialise(IMesher meshmerizer, IConfigSource config)
386 {
387 mesher = meshmerizer;
388 m_config = config;
389 // Defaults
390
391 if (Environment.OSVersion.Platform == PlatformID.Unix)
392 {
393 avPIDD = 3200.0f;
394 avPIDP = 1400.0f;
395 avStandupTensor = 2000000f;
396 }
397 else
398 {
399 avPIDD = 2200.0f;
400 avPIDP = 900.0f;
401 avStandupTensor = 550000f;
402 }
403
404 int contactsPerCollision = 80;
405
406 if (m_config != null)
407 {
408 IConfig physicsconfig = m_config.Configs["ODEPhysicsSettings"];
409 if (physicsconfig != null)
410 {
411 gravityx = physicsconfig.GetFloat("world_gravityx", 0f);
412 gravityy = physicsconfig.GetFloat("world_gravityy", 0f);
413 gravityz = physicsconfig.GetFloat("world_gravityz", -9.8f);
414
415 worldHashspaceLow = physicsconfig.GetInt("world_hashspace_size_low", -4);
416 worldHashspaceHigh = physicsconfig.GetInt("world_hashspace_size_high", 128);
417
418 metersInSpace = physicsconfig.GetFloat("meters_in_small_space", 29.9f);
419 smallHashspaceLow = physicsconfig.GetInt("small_hashspace_size_low", -4);
420 smallHashspaceHigh = physicsconfig.GetInt("small_hashspace_size_high", 66);
421
422 contactsurfacelayer = physicsconfig.GetFloat("world_contact_surface_layer", 0.001f);
423
424 nmTerrainContactFriction = physicsconfig.GetFloat("nm_terraincontact_friction", 255.0f);
425 nmTerrainContactBounce = physicsconfig.GetFloat("nm_terraincontact_bounce", 0.1f);
426 nmTerrainContactERP = physicsconfig.GetFloat("nm_terraincontact_erp", 0.1025f);
427
428 mTerrainContactFriction = physicsconfig.GetFloat("m_terraincontact_friction", 75f);
429 mTerrainContactBounce = physicsconfig.GetFloat("m_terraincontact_bounce", 0.05f);
430 mTerrainContactERP = physicsconfig.GetFloat("m_terraincontact_erp", 0.05025f);
431
432 nmAvatarObjectContactFriction = physicsconfig.GetFloat("objectcontact_friction", 250f);
433 nmAvatarObjectContactBounce = physicsconfig.GetFloat("objectcontact_bounce", 0.2f);
434
435 mAvatarObjectContactFriction = physicsconfig.GetFloat("m_avatarobjectcontact_friction", 75f);
436 mAvatarObjectContactBounce = physicsconfig.GetFloat("m_avatarobjectcontact_bounce", 0.1f);
437
438 ODE_STEPSIZE = physicsconfig.GetFloat("world_stepsize", 0.020f);
439 m_physicsiterations = physicsconfig.GetInt("world_internal_steps_without_collisions", 10);
440
441 avDensity = physicsconfig.GetFloat("av_density", 80f);
442 avHeightFudgeFactor = physicsconfig.GetFloat("av_height_fudge_factor", 0.52f);
443 avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", 1.3f);
444 avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", 0.8f);
445 avCapRadius = physicsconfig.GetFloat("av_capsule_radius", 0.37f);
446 avCapsuleTilted = physicsconfig.GetBoolean("av_capsule_tilted", false);
447
448 contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80);
449
450 geomContactPointsStartthrottle = physicsconfig.GetInt("geom_contactpoints_start_throttling", 3);
451 geomUpdatesPerThrottledUpdate = physicsconfig.GetInt("geom_updates_before_throttled_update", 15);
452 geomCrossingFailuresBeforeOutofbounds = physicsconfig.GetInt("geom_crossing_failures_before_outofbounds", 5);
453
454 geomDefaultDensity = physicsconfig.GetFloat("geometry_default_density", 10.000006836f);
455 bodyFramesAutoDisable = physicsconfig.GetInt("body_frames_auto_disable", 20);
456
457 bodyPIDD = physicsconfig.GetFloat("body_pid_derivative", 35f);
458 bodyPIDG = physicsconfig.GetFloat("body_pid_gain", 25f);
459
460 forceSimplePrimMeshing = physicsconfig.GetBoolean("force_simple_prim_meshing", forceSimplePrimMeshing);
461 meshSculptedPrim = physicsconfig.GetBoolean("mesh_sculpted_prim", true);
462 meshSculptLOD = physicsconfig.GetFloat("mesh_lod", 32f);
463 MeshSculptphysicalLOD = physicsconfig.GetFloat("mesh_physical_lod", 16f);
464 m_filterCollisions = physicsconfig.GetBoolean("filter_collisions", false);
465
466 if (Environment.OSVersion.Platform == PlatformID.Unix)
467 {
468 avPIDD = physicsconfig.GetFloat("av_pid_derivative_linux", 2200.0f);
469 avPIDP = physicsconfig.GetFloat("av_pid_proportional_linux", 900.0f);
470 avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor_linux", 550000f);
471 bodyMotorJointMaxforceTensor = physicsconfig.GetFloat("body_motor_joint_maxforce_tensor_linux", 5f);
472 }
473 else
474 {
475 avPIDD = physicsconfig.GetFloat("av_pid_derivative_win", 2200.0f);
476 avPIDP = physicsconfig.GetFloat("av_pid_proportional_win", 900.0f);
477 avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor_win", 550000f);
478 bodyMotorJointMaxforceTensor = physicsconfig.GetFloat("body_motor_joint_maxforce_tensor_win", 5f);
479 }
480
481 physics_logging = physicsconfig.GetBoolean("physics_logging", false);
482 physics_logging_interval = physicsconfig.GetInt("physics_logging_interval", 0);
483 physics_logging_append_existing_logfile = physicsconfig.GetBoolean("physics_logging_append_existing_logfile", false);
484
485 m_NINJA_physics_joints_enabled = physicsconfig.GetBoolean("use_NINJA_physics_joints", false);
486 minimumGroundFlightOffset = physicsconfig.GetFloat("minimum_ground_flight_offset", 3f);
487 maximumMassObject = physicsconfig.GetFloat("maximum_mass_object", 10000.01f);
488 }
489 }
490
491 contacts = new d.ContactGeom[contactsPerCollision];
492
493 staticPrimspace = new IntPtr[(int)(300 / metersInSpace), (int)(300 / metersInSpace)];
494
495 // Centeral contact friction and bounce
496 // ckrinke 11/10/08 Enabling soft_erp but not soft_cfm until I figure out why
497 // an avatar falls through in Z but not in X or Y when walking on a prim.
498 contact.surface.mode |= d.ContactFlags.SoftERP;
499 contact.surface.mu = nmAvatarObjectContactFriction;
500 contact.surface.bounce = nmAvatarObjectContactBounce;
501 contact.surface.soft_cfm = 0.010f;
502 contact.surface.soft_erp = 0.010f;
503
504 // Terrain contact friction and Bounce
505 // This is the *non* moving version. Use this when an avatar
506 // isn't moving to keep it in place better
507 TerrainContact.surface.mode |= d.ContactFlags.SoftERP;
508 TerrainContact.surface.mu = nmTerrainContactFriction;
509 TerrainContact.surface.bounce = nmTerrainContactBounce;
510 TerrainContact.surface.soft_erp = nmTerrainContactERP;
511
512 WaterContact.surface.mode |= (d.ContactFlags.SoftERP | d.ContactFlags.SoftCFM);
513 WaterContact.surface.mu = 0f; // No friction
514 WaterContact.surface.bounce = 0.0f; // No bounce
515 WaterContact.surface.soft_cfm = 0.010f;
516 WaterContact.surface.soft_erp = 0.010f;
517
518 // Prim contact friction and bounce
519 // THis is the *non* moving version of friction and bounce
520 // Use this when an avatar comes in contact with a prim
521 // and is moving
522 AvatarMovementprimContact.surface.mu = mAvatarObjectContactFriction;
523 AvatarMovementprimContact.surface.bounce = mAvatarObjectContactBounce;
524
525 // Terrain contact friction bounce and various error correcting calculations
526 // Use this when an avatar is in contact with the terrain and moving.
527 AvatarMovementTerrainContact.surface.mode |= d.ContactFlags.SoftERP;
528 AvatarMovementTerrainContact.surface.mu = mTerrainContactFriction;
529 AvatarMovementTerrainContact.surface.bounce = mTerrainContactBounce;
530 AvatarMovementTerrainContact.surface.soft_erp = mTerrainContactERP;
531
532
533 /*
534 <summary></summary>
535 Stone = 0,
536 /// <summary></summary>
537 Metal = 1,
538 /// <summary></summary>
539 Glass = 2,
540 /// <summary></summary>
541 Wood = 3,
542 /// <summary></summary>
543 Flesh = 4,
544 /// <summary></summary>
545 Plastic = 5,
546 /// <summary></summary>
547 Rubber = 6
548 */
549
550 m_materialContacts = new d.Contact[7,2];
551
552 m_materialContacts[(int)Material.Stone, 0] = new d.Contact();
553 m_materialContacts[(int)Material.Stone, 0].surface.mode |= d.ContactFlags.SoftERP;
554 m_materialContacts[(int)Material.Stone, 0].surface.mu = nmAvatarObjectContactFriction;
555 m_materialContacts[(int)Material.Stone, 0].surface.bounce = nmAvatarObjectContactBounce;
556 m_materialContacts[(int)Material.Stone, 0].surface.soft_cfm = 0.010f;
557 m_materialContacts[(int)Material.Stone, 0].surface.soft_erp = 0.010f;
558
559 m_materialContacts[(int)Material.Stone, 1] = new d.Contact();
560 m_materialContacts[(int)Material.Stone, 1].surface.mode |= d.ContactFlags.SoftERP;
561 m_materialContacts[(int)Material.Stone, 1].surface.mu = mAvatarObjectContactFriction;
562 m_materialContacts[(int)Material.Stone, 1].surface.bounce = mAvatarObjectContactBounce;
563 m_materialContacts[(int)Material.Stone, 1].surface.soft_cfm = 0.010f;
564 m_materialContacts[(int)Material.Stone, 1].surface.soft_erp = 0.010f;
565
566 m_materialContacts[(int)Material.Metal, 0] = new d.Contact();
567 m_materialContacts[(int)Material.Metal, 0].surface.mode |= d.ContactFlags.SoftERP;
568 m_materialContacts[(int)Material.Metal, 0].surface.mu = nmAvatarObjectContactFriction;
569 m_materialContacts[(int)Material.Metal, 0].surface.bounce = nmAvatarObjectContactBounce;
570 m_materialContacts[(int)Material.Metal, 0].surface.soft_cfm = 0.010f;
571 m_materialContacts[(int)Material.Metal, 0].surface.soft_erp = 0.010f;
572
573 m_materialContacts[(int)Material.Metal, 1] = new d.Contact();
574 m_materialContacts[(int)Material.Metal, 1].surface.mode |= d.ContactFlags.SoftERP;
575 m_materialContacts[(int)Material.Metal, 1].surface.mu = mAvatarObjectContactFriction;
576 m_materialContacts[(int)Material.Metal, 1].surface.bounce = mAvatarObjectContactBounce;
577 m_materialContacts[(int)Material.Metal, 1].surface.soft_cfm = 0.010f;
578 m_materialContacts[(int)Material.Metal, 1].surface.soft_erp = 0.010f;
579
580 m_materialContacts[(int)Material.Glass, 0] = new d.Contact();
581 m_materialContacts[(int)Material.Glass, 0].surface.mode |= d.ContactFlags.SoftERP;
582 m_materialContacts[(int)Material.Glass, 0].surface.mu = 1f;
583 m_materialContacts[(int)Material.Glass, 0].surface.bounce = 0.5f;
584 m_materialContacts[(int)Material.Glass, 0].surface.soft_cfm = 0.010f;
585 m_materialContacts[(int)Material.Glass, 0].surface.soft_erp = 0.010f;
586
587 /*
588 private float nmAvatarObjectContactFriction = 250f;
589 private float nmAvatarObjectContactBounce = 0.1f;
590
591 private float mAvatarObjectContactFriction = 75f;
592 private float mAvatarObjectContactBounce = 0.1f;
593 */
594 m_materialContacts[(int)Material.Glass, 1] = new d.Contact();
595 m_materialContacts[(int)Material.Glass, 1].surface.mode |= d.ContactFlags.SoftERP;
596 m_materialContacts[(int)Material.Glass, 1].surface.mu = 1f;
597 m_materialContacts[(int)Material.Glass, 1].surface.bounce = 0.5f;
598 m_materialContacts[(int)Material.Glass, 1].surface.soft_cfm = 0.010f;
599 m_materialContacts[(int)Material.Glass, 1].surface.soft_erp = 0.010f;
600
601 m_materialContacts[(int)Material.Wood, 0] = new d.Contact();
602 m_materialContacts[(int)Material.Wood, 0].surface.mode |= d.ContactFlags.SoftERP;
603 m_materialContacts[(int)Material.Wood, 0].surface.mu = nmAvatarObjectContactFriction;
604 m_materialContacts[(int)Material.Wood, 0].surface.bounce = nmAvatarObjectContactBounce;
605 m_materialContacts[(int)Material.Wood, 0].surface.soft_cfm = 0.010f;
606 m_materialContacts[(int)Material.Wood, 0].surface.soft_erp = 0.010f;
607
608 m_materialContacts[(int)Material.Wood, 1] = new d.Contact();
609 m_materialContacts[(int)Material.Wood, 1].surface.mode |= d.ContactFlags.SoftERP;
610 m_materialContacts[(int)Material.Wood, 1].surface.mu = mAvatarObjectContactFriction;
611 m_materialContacts[(int)Material.Wood, 1].surface.bounce = mAvatarObjectContactBounce;
612 m_materialContacts[(int)Material.Wood, 1].surface.soft_cfm = 0.010f;
613 m_materialContacts[(int)Material.Wood, 1].surface.soft_erp = 0.010f;
614
615 m_materialContacts[(int)Material.Flesh, 0] = new d.Contact();
616 m_materialContacts[(int)Material.Flesh, 0].surface.mode |= d.ContactFlags.SoftERP;
617 m_materialContacts[(int)Material.Flesh, 0].surface.mu = nmAvatarObjectContactFriction;
618 m_materialContacts[(int)Material.Flesh, 0].surface.bounce = nmAvatarObjectContactBounce;
619 m_materialContacts[(int)Material.Flesh, 0].surface.soft_cfm = 0.010f;
620 m_materialContacts[(int)Material.Flesh, 0].surface.soft_erp = 0.010f;
621
622 m_materialContacts[(int)Material.Flesh, 1] = new d.Contact();
623 m_materialContacts[(int)Material.Flesh, 1].surface.mode |= d.ContactFlags.SoftERP;
624 m_materialContacts[(int)Material.Flesh, 1].surface.mu = mAvatarObjectContactFriction;
625 m_materialContacts[(int)Material.Flesh, 1].surface.bounce = mAvatarObjectContactBounce;
626 m_materialContacts[(int)Material.Flesh, 1].surface.soft_cfm = 0.010f;
627 m_materialContacts[(int)Material.Flesh, 1].surface.soft_erp = 0.010f;
628
629 m_materialContacts[(int)Material.Plastic, 0] = new d.Contact();
630 m_materialContacts[(int)Material.Plastic, 0].surface.mode |= d.ContactFlags.SoftERP;
631 m_materialContacts[(int)Material.Plastic, 0].surface.mu = nmAvatarObjectContactFriction;
632 m_materialContacts[(int)Material.Plastic, 0].surface.bounce = nmAvatarObjectContactBounce;
633 m_materialContacts[(int)Material.Plastic, 0].surface.soft_cfm = 0.010f;
634 m_materialContacts[(int)Material.Plastic, 0].surface.soft_erp = 0.010f;
635
636 m_materialContacts[(int)Material.Plastic, 1] = new d.Contact();
637 m_materialContacts[(int)Material.Plastic, 1].surface.mode |= d.ContactFlags.SoftERP;
638 m_materialContacts[(int)Material.Plastic, 1].surface.mu = mAvatarObjectContactFriction;
639 m_materialContacts[(int)Material.Plastic, 1].surface.bounce = mAvatarObjectContactBounce;
640 m_materialContacts[(int)Material.Plastic, 1].surface.soft_cfm = 0.010f;
641 m_materialContacts[(int)Material.Plastic, 1].surface.soft_erp = 0.010f;
642
643 m_materialContacts[(int)Material.Rubber, 0] = new d.Contact();
644 m_materialContacts[(int)Material.Rubber, 0].surface.mode |= d.ContactFlags.SoftERP;
645 m_materialContacts[(int)Material.Rubber, 0].surface.mu = nmAvatarObjectContactFriction;
646 m_materialContacts[(int)Material.Rubber, 0].surface.bounce = nmAvatarObjectContactBounce;
647 m_materialContacts[(int)Material.Rubber, 0].surface.soft_cfm = 0.010f;
648 m_materialContacts[(int)Material.Rubber, 0].surface.soft_erp = 0.010f;
649
650 m_materialContacts[(int)Material.Rubber, 1] = new d.Contact();
651 m_materialContacts[(int)Material.Rubber, 1].surface.mode |= d.ContactFlags.SoftERP;
652 m_materialContacts[(int)Material.Rubber, 1].surface.mu = mAvatarObjectContactFriction;
653 m_materialContacts[(int)Material.Rubber, 1].surface.bounce = mAvatarObjectContactBounce;
654 m_materialContacts[(int)Material.Rubber, 1].surface.soft_cfm = 0.010f;
655 m_materialContacts[(int)Material.Rubber, 1].surface.soft_erp = 0.010f;
656
657 d.HashSpaceSetLevels(space, worldHashspaceLow, worldHashspaceHigh);
658
659 // Set the gravity,, don't disable things automatically (we set it explicitly on some things)
660
661 d.WorldSetGravity(world, gravityx, gravityy, gravityz);
662 d.WorldSetContactSurfaceLayer(world, contactsurfacelayer);
663
664 d.WorldSetLinearDamping(world, 256f);
665 d.WorldSetAngularDamping(world, 256f);
666 d.WorldSetAngularDampingThreshold(world, 256f);
667 d.WorldSetLinearDampingThreshold(world, 256f);
668 d.WorldSetMaxAngularSpeed(world, 256f);
669
670 // Set how many steps we go without running collision testing
671 // This is in addition to the step size.
672 // Essentially Steps * m_physicsiterations
673 d.WorldSetQuickStepNumIterations(world, m_physicsiterations);
674 //d.WorldSetContactMaxCorrectingVel(world, 1000.0f);
675
676
677
678 for (int i = 0; i < staticPrimspace.GetLength(0); i++)
679 {
680 for (int j = 0; j < staticPrimspace.GetLength(1); j++)
681 {
682 staticPrimspace[i, j] = IntPtr.Zero;
683 }
684 }
685 }
686
687 internal void waitForSpaceUnlock(IntPtr space)
688 {
689 //if (space != IntPtr.Zero)
690 //while (d.SpaceLockQuery(space)) { } // Wait and do nothing
691 }
692
693 /// <summary>
694 /// Debug space message for printing the space that a prim/avatar is in.
695 /// </summary>
696 /// <param name="pos"></param>
697 /// <returns>Returns which split up space the given position is in.</returns>
698 public string whichspaceamIin(Vector3 pos)
699 {
700 return calculateSpaceForGeom(pos).ToString();
701 }
702
703 #region Collision Detection
704
705 /// <summary>
706 /// This is our near callback. A geometry is near a body
707 /// </summary>
708 /// <param name="space">The space that contains the geoms. Remember, spaces are also geoms</param>
709 /// <param name="g1">a geometry or space</param>
710 /// <param name="g2">another geometry or space</param>
711 private void near(IntPtr space, IntPtr g1, IntPtr g2)
712 {
713 // no lock here! It's invoked from within Simulate(), which is thread-locked
714
715 // Test if we're colliding a geom with a space.
716 // If so we have to drill down into the space recursively
717
718 if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2))
719 {
720 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
721 return;
722
723 // Separating static prim geometry spaces.
724 // We'll be calling near recursivly if one
725 // of them is a space to find all of the
726 // contact points in the space
727 try
728 {
729 d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback);
730 }
731 catch (AccessViolationException)
732 {
733 m_log.Warn("[PHYSICS]: Unable to collide test a space");
734 return;
735 }
736 //Colliding a space or a geom with a space or a geom. so drill down
737
738 //Collide all geoms in each space..
739 //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback);
740 //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback);
741 return;
742 }
743
744 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
745 return;
746
747 IntPtr b1 = d.GeomGetBody(g1);
748 IntPtr b2 = d.GeomGetBody(g2);
749
750 // d.GeomClassID id = d.GeomGetClass(g1);
751
752 String name1 = null;
753 String name2 = null;
754
755 if (!geom_name_map.TryGetValue(g1, out name1))
756 {
757 name1 = "null";
758 }
759 if (!geom_name_map.TryGetValue(g2, out name2))
760 {
761 name2 = "null";
762 }
763
764 //if (id == d.GeomClassId.TriMeshClass)
765 //{
766 // m_log.InfoFormat("near: A collision was detected between {1} and {2}", 0, name1, name2);
767 //m_log.Debug("near: A collision was detected between {1} and {2}", 0, name1, name2);
768 //}
769
770 // Figure out how many contact points we have
771 int count = 0;
772 try
773 {
774 // Colliding Geom To Geom
775 // This portion of the function 'was' blatantly ripped off from BoxStack.cs
776
777 if (g1 == g2)
778 return; // Can't collide with yourself
779
780 if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact))
781 return;
782
783 lock (contacts)
784 {
785 count = d.Collide(g1, g2, contacts.Length, contacts, d.ContactGeom.SizeOf);
786 if (count > contacts.Length)
787 m_log.Error("[PHYSICS]: Got " + count + " contacts when we asked for a maximum of " + contacts.Length);
788 }
789 }
790 catch (SEHException)
791 {
792 m_log.Error("[PHYSICS]: The Operating system shut down ODE because of corrupt memory. This could be a result of really irregular terrain. If this repeats continuously, restart using Basic Physics and terrain fill your terrain. Restarting the sim.");
793 ode.drelease(world);
794 base.TriggerPhysicsBasedRestart();
795 }
796 catch (Exception e)
797 {
798 m_log.WarnFormat("[PHYSICS]: Unable to collide test an object: {0}", e.Message);
799 return;
800 }
801
802 PhysicsActor p1;
803 PhysicsActor p2;
804
805 if (!actor_name_map.TryGetValue(g1, out p1))
806 {
807 p1 = PANull;
808 }
809
810 if (!actor_name_map.TryGetValue(g2, out p2))
811 {
812 p2 = PANull;
813 }
814
815 ContactPoint maxDepthContact = new ContactPoint();
816 if (p1.CollisionScore + count >= float.MaxValue)
817 p1.CollisionScore = 0;
818 p1.CollisionScore += count;
819
820 if (p2.CollisionScore + count >= float.MaxValue)
821 p2.CollisionScore = 0;
822 p2.CollisionScore += count;
823
824 for (int i = 0; i < count; i++)
825 {
826 d.ContactGeom curContact = contacts[i];
827
828 if (curContact.depth > maxDepthContact.PenetrationDepth)
829 {
830 maxDepthContact = new ContactPoint(
831 new Vector3(curContact.pos.X, curContact.pos.Y, curContact.pos.Z),
832 new Vector3(curContact.normal.X, curContact.normal.Y, curContact.normal.Z),
833 curContact.depth
834 );
835 }
836
837 //m_log.Warn("[CCOUNT]: " + count);
838 IntPtr joint;
839 // If we're colliding with terrain, use 'TerrainContact' instead of contact.
840 // allows us to have different settings
841
842 // We only need to test p2 for 'jump crouch purposes'
843 if (p2 is OdeCharacter && p1.PhysicsActorType == (int)ActorTypes.Prim)
844 {
845 // Testing if the collision is at the feet of the avatar
846
847 //m_log.DebugFormat("[PHYSICS]: {0} - {1} - {2} - {3}", curContact.pos.Z, p2.Position.Z, (p2.Position.Z - curContact.pos.Z), (p2.Size.Z * 0.6f));
848 if ((p2.Position.Z - curContact.pos.Z) > (p2.Size.Z * 0.6f))
849 p2.IsColliding = true;
850 }
851 else
852 {
853 p2.IsColliding = true;
854 }
855
856 //if ((framecount % m_returncollisions) == 0)
857
858 switch (p1.PhysicsActorType)
859 {
860 case (int)ActorTypes.Agent:
861 p2.CollidingObj = true;
862 break;
863 case (int)ActorTypes.Prim:
864 if (p2.Velocity.LengthSquared() > 0.0f)
865 p2.CollidingObj = true;
866 break;
867 case (int)ActorTypes.Unknown:
868 p2.CollidingGround = true;
869 break;
870 default:
871 p2.CollidingGround = true;
872 break;
873 }
874
875 // we don't want prim or avatar to explode
876
877 #region InterPenetration Handling - Unintended physics explosions
878# region disabled code1
879
880 if (curContact.depth >= 0.08f)
881 {
882 //This is disabled at the moment only because it needs more tweaking
883 //It will eventually be uncommented
884 /*
885 if (contact.depth >= 1.00f)
886 {
887 //m_log.Debug("[PHYSICS]: " + contact.depth.ToString());
888 }
889
890 //If you interpenetrate a prim with an agent
891 if ((p2.PhysicsActorType == (int) ActorTypes.Agent &&
892 p1.PhysicsActorType == (int) ActorTypes.Prim) ||
893 (p1.PhysicsActorType == (int) ActorTypes.Agent &&
894 p2.PhysicsActorType == (int) ActorTypes.Prim))
895 {
896
897 //contact.depth = contact.depth * 4.15f;
898 /*
899 if (p2.PhysicsActorType == (int) ActorTypes.Agent)
900 {
901 p2.CollidingObj = true;
902 contact.depth = 0.003f;
903 p2.Velocity = p2.Velocity + new PhysicsVector(0, 0, 2.5f);
904 OdeCharacter character = (OdeCharacter) p2;
905 character.SetPidStatus(true);
906 contact.pos = new d.Vector3(contact.pos.X + (p1.Size.X / 2), contact.pos.Y + (p1.Size.Y / 2), contact.pos.Z + (p1.Size.Z / 2));
907
908 }
909 else
910 {
911
912 //contact.depth = 0.0000000f;
913 }
914 if (p1.PhysicsActorType == (int) ActorTypes.Agent)
915 {
916
917 p1.CollidingObj = true;
918 contact.depth = 0.003f;
919 p1.Velocity = p1.Velocity + new PhysicsVector(0, 0, 2.5f);
920 contact.pos = new d.Vector3(contact.pos.X + (p2.Size.X / 2), contact.pos.Y + (p2.Size.Y / 2), contact.pos.Z + (p2.Size.Z / 2));
921 OdeCharacter character = (OdeCharacter)p1;
922 character.SetPidStatus(true);
923 }
924 else
925 {
926
927 //contact.depth = 0.0000000f;
928 }
929
930
931
932 }
933*/
934 // If you interpenetrate a prim with another prim
935 /*
936 if (p1.PhysicsActorType == (int) ActorTypes.Prim && p2.PhysicsActorType == (int) ActorTypes.Prim)
937 {
938 #region disabledcode2
939 //OdePrim op1 = (OdePrim)p1;
940 //OdePrim op2 = (OdePrim)p2;
941 //op1.m_collisionscore++;
942 //op2.m_collisionscore++;
943
944 //if (op1.m_collisionscore > 8000 || op2.m_collisionscore > 8000)
945 //{
946 //op1.m_taintdisable = true;
947 //AddPhysicsActorTaint(p1);
948 //op2.m_taintdisable = true;
949 //AddPhysicsActorTaint(p2);
950 //}
951
952 //if (contact.depth >= 0.25f)
953 //{
954 // Don't collide, one or both prim will expld.
955
956 //op1.m_interpenetrationcount++;
957 //op2.m_interpenetrationcount++;
958 //interpenetrations_before_disable = 200;
959 //if (op1.m_interpenetrationcount >= interpenetrations_before_disable)
960 //{
961 //op1.m_taintdisable = true;
962 //AddPhysicsActorTaint(p1);
963 //}
964 //if (op2.m_interpenetrationcount >= interpenetrations_before_disable)
965 //{
966 // op2.m_taintdisable = true;
967 //AddPhysicsActorTaint(p2);
968 //}
969
970 //contact.depth = contact.depth / 8f;
971 //contact.normal = new d.Vector3(0, 0, 1);
972 //}
973 //if (op1.m_disabled || op2.m_disabled)
974 //{
975 //Manually disabled objects stay disabled
976 //contact.depth = 0f;
977 //}
978 #endregion
979 }
980 */
981#endregion
982 if (curContact.depth >= 1.00f)
983 {
984 //m_log.Info("[P]: " + contact.depth.ToString());
985 if ((p2.PhysicsActorType == (int) ActorTypes.Agent &&
986 p1.PhysicsActorType == (int) ActorTypes.Unknown) ||
987 (p1.PhysicsActorType == (int) ActorTypes.Agent &&
988 p2.PhysicsActorType == (int) ActorTypes.Unknown))
989 {
990 if (p2.PhysicsActorType == (int) ActorTypes.Agent)
991 {
992 if (p2 is OdeCharacter)
993 {
994 OdeCharacter character = (OdeCharacter) p2;
995
996 //p2.CollidingObj = true;
997 curContact.depth = 0.00000003f;
998 p2.Velocity = p2.Velocity + new Vector3(0f, 0f, 0.5f);
999 curContact.pos =
1000 new d.Vector3(curContact.pos.X + (p1.Size.X/2),
1001 curContact.pos.Y + (p1.Size.Y/2),
1002 curContact.pos.Z + (p1.Size.Z/2));
1003 character.SetPidStatus(true);
1004 }
1005 }
1006
1007
1008 if (p1.PhysicsActorType == (int) ActorTypes.Agent)
1009 {
1010 if (p1 is OdeCharacter)
1011 {
1012 OdeCharacter character = (OdeCharacter) p1;
1013
1014 //p2.CollidingObj = true;
1015 curContact.depth = 0.00000003f;
1016 p1.Velocity = p1.Velocity + new Vector3(0f, 0f, 0.5f);
1017 curContact.pos =
1018 new d.Vector3(curContact.pos.X + (p1.Size.X/2),
1019 curContact.pos.Y + (p1.Size.Y/2),
1020 curContact.pos.Z + (p1.Size.Z/2));
1021 character.SetPidStatus(true);
1022 }
1023 }
1024 }
1025 }
1026 }
1027
1028 #endregion
1029
1030 // Logic for collision handling
1031 // Note, that if *all* contacts are skipped (VolumeDetect)
1032 // The prim still detects (and forwards) collision events but
1033 // appears to be phantom for the world
1034 Boolean skipThisContact = false;
1035
1036 if ((p1 is OdePrim) && (((OdePrim)p1).m_isVolumeDetect))
1037 skipThisContact = true; // No collision on volume detect prims
1038
1039 if (!skipThisContact && (p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect))
1040 skipThisContact = true; // No collision on volume detect prims
1041
1042 if (!skipThisContact && curContact.depth < 0f)
1043 skipThisContact = true;
1044
1045 if (!skipThisContact && checkDupe(curContact, p2.PhysicsActorType))
1046 skipThisContact = true;
1047
1048 const int maxContactsbeforedeath = 4000;
1049 joint = IntPtr.Zero;
1050
1051 if (!skipThisContact)
1052 {
1053 // If we're colliding against terrain
1054 if (name1 == "Terrain" || name2 == "Terrain")
1055 {
1056 // If we're moving
1057 if ((p2.PhysicsActorType == (int) ActorTypes.Agent) &&
1058 (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
1059 {
1060 // Use the movement terrain contact
1061 AvatarMovementTerrainContact.geom = curContact;
1062 _perloopContact.Add(curContact);
1063 if (m_global_contactcount < maxContactsbeforedeath)
1064 {
1065 joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementTerrainContact);
1066 m_global_contactcount++;
1067 }
1068 }
1069 else
1070 {
1071 if (p2.PhysicsActorType == (int)ActorTypes.Agent)
1072 {
1073 // Use the non moving terrain contact
1074 TerrainContact.geom = curContact;
1075 _perloopContact.Add(curContact);
1076 if (m_global_contactcount < maxContactsbeforedeath)
1077 {
1078 joint = d.JointCreateContact(world, contactgroup, ref TerrainContact);
1079 m_global_contactcount++;
1080 }
1081 }
1082 else
1083 {
1084 if (p2.PhysicsActorType == (int)ActorTypes.Prim && p1.PhysicsActorType == (int)ActorTypes.Prim)
1085 {
1086 // prim prim contact
1087 // int pj294950 = 0;
1088 int movintYN = 0;
1089 int material = (int) Material.Wood;
1090 // prim terrain contact
1091 if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)
1092 {
1093 movintYN = 1;
1094 }
1095
1096 if (p2 is OdePrim)
1097 material = ((OdePrim)p2).m_material;
1098
1099 //m_log.DebugFormat("Material: {0}", material);
1100 m_materialContacts[material, movintYN].geom = curContact;
1101 _perloopContact.Add(curContact);
1102
1103 if (m_global_contactcount < maxContactsbeforedeath)
1104 {
1105 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]);
1106 m_global_contactcount++;
1107
1108 }
1109
1110 }
1111 else
1112 {
1113
1114 int movintYN = 0;
1115 // prim terrain contact
1116 if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)
1117 {
1118 movintYN = 1;
1119 }
1120
1121 int material = (int)Material.Wood;
1122
1123 if (p2 is OdePrim)
1124 material = ((OdePrim)p2).m_material;
1125 //m_log.DebugFormat("Material: {0}", material);
1126 m_materialContacts[material, movintYN].geom = curContact;
1127 _perloopContact.Add(curContact);
1128
1129 if (m_global_contactcount < maxContactsbeforedeath)
1130 {
1131 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]);
1132 m_global_contactcount++;
1133
1134 }
1135 }
1136 }
1137 }
1138 //if (p2.PhysicsActorType == (int)ActorTypes.Prim)
1139 //{
1140 //m_log.Debug("[PHYSICS]: prim contacting with ground");
1141 //}
1142 }
1143 else if (name1 == "Water" || name2 == "Water")
1144 {
1145 /*
1146 if ((p2.PhysicsActorType == (int) ActorTypes.Prim))
1147 {
1148 }
1149 else
1150 {
1151 }
1152 */
1153 //WaterContact.surface.soft_cfm = 0.0000f;
1154 //WaterContact.surface.soft_erp = 0.00000f;
1155 if (curContact.depth > 0.1f)
1156 {
1157 curContact.depth *= 52;
1158 //contact.normal = new d.Vector3(0, 0, 1);
1159 //contact.pos = new d.Vector3(0, 0, contact.pos.Z - 5f);
1160 }
1161 WaterContact.geom = curContact;
1162 _perloopContact.Add(curContact);
1163 if (m_global_contactcount < maxContactsbeforedeath)
1164 {
1165 joint = d.JointCreateContact(world, contactgroup, ref WaterContact);
1166 m_global_contactcount++;
1167 }
1168 //m_log.Info("[PHYSICS]: Prim Water Contact" + contact.depth);
1169 }
1170 else
1171 {
1172 // we're colliding with prim or avatar
1173 // check if we're moving
1174 if ((p2.PhysicsActorType == (int)ActorTypes.Agent))
1175 {
1176 if ((Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
1177 {
1178 // Use the Movement prim contact
1179 AvatarMovementprimContact.geom = curContact;
1180 _perloopContact.Add(curContact);
1181 if (m_global_contactcount < maxContactsbeforedeath)
1182 {
1183 joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementprimContact);
1184 m_global_contactcount++;
1185 }
1186 }
1187 else
1188 {
1189 // Use the non movement contact
1190 contact.geom = curContact;
1191 _perloopContact.Add(curContact);
1192
1193 if (m_global_contactcount < maxContactsbeforedeath)
1194 {
1195 joint = d.JointCreateContact(world, contactgroup, ref contact);
1196 m_global_contactcount++;
1197 }
1198 }
1199 }
1200 else if (p2.PhysicsActorType == (int)ActorTypes.Prim)
1201 {
1202 //p1.PhysicsActorType
1203 int material = (int)Material.Wood;
1204
1205 if (p2 is OdePrim)
1206 material = ((OdePrim)p2).m_material;
1207
1208 //m_log.DebugFormat("Material: {0}", material);
1209 m_materialContacts[material, 0].geom = curContact;
1210 _perloopContact.Add(curContact);
1211
1212 if (m_global_contactcount < maxContactsbeforedeath)
1213 {
1214 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, 0]);
1215 m_global_contactcount++;
1216
1217 }
1218 }
1219 }
1220
1221 if (m_global_contactcount < maxContactsbeforedeath && joint != IntPtr.Zero) // stack collide!
1222 {
1223 d.JointAttach(joint, b1, b2);
1224 m_global_contactcount++;
1225 }
1226
1227 }
1228 collision_accounting_events(p1, p2, maxDepthContact);
1229 if (count > geomContactPointsStartthrottle)
1230 {
1231 // If there are more then 3 contact points, it's likely
1232 // that we've got a pile of objects, so ...
1233 // We don't want to send out hundreds of terse updates over and over again
1234 // so lets throttle them and send them again after it's somewhat sorted out.
1235 p2.ThrottleUpdates = true;
1236 }
1237 //m_log.Debug(count.ToString());
1238 //m_log.Debug("near: A collision was detected between {1} and {2}", 0, name1, name2);
1239 }
1240 }
1241
1242 private bool checkDupe(d.ContactGeom contactGeom, int atype)
1243 {
1244 bool result = false;
1245 //return result;
1246 if (!m_filterCollisions)
1247 return false;
1248
1249 ActorTypes at = (ActorTypes)atype;
1250 lock (_perloopContact)
1251 {
1252 foreach (d.ContactGeom contact in _perloopContact)
1253 {
1254 //if ((contact.g1 == contactGeom.g1 && contact.g2 == contactGeom.g2))
1255 //{
1256 // || (contact.g2 == contactGeom.g1 && contact.g1 == contactGeom.g2)
1257 if (at == ActorTypes.Agent)
1258 {
1259 if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)) && contactGeom.g1 != LandGeom && contactGeom.g2 != LandGeom)
1260 {
1261
1262 if (Math.Abs(contact.depth - contactGeom.depth) < 0.052f)
1263 {
1264 //contactGeom.depth *= .00005f;
1265 //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
1266 // m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z));
1267 result = true;
1268 break;
1269 }
1270 else
1271 {
1272 //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
1273 }
1274 }
1275 else
1276 {
1277 //m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z));
1278 //int i = 0;
1279 }
1280 }
1281 else if (at == ActorTypes.Prim)
1282 {
1283 //d.AABB aabb1 = new d.AABB();
1284 //d.AABB aabb2 = new d.AABB();
1285
1286 //d.GeomGetAABB(contactGeom.g2, out aabb2);
1287 //d.GeomGetAABB(contactGeom.g1, out aabb1);
1288 //aabb1.
1289 if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)) && contactGeom.g1 != LandGeom && contactGeom.g2 != LandGeom)
1290 {
1291 if (contactGeom.normal.X == contact.normal.X && contactGeom.normal.Y == contact.normal.Y && contactGeom.normal.Z == contact.normal.Z)
1292 {
1293 if (Math.Abs(contact.depth - contactGeom.depth) < 0.272f)
1294 {
1295 result = true;
1296 break;
1297 }
1298 }
1299 //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
1300 //m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z));
1301 }
1302
1303 }
1304
1305 //}
1306
1307 }
1308 }
1309 return result;
1310 }
1311
1312 private void collision_accounting_events(PhysicsActor p1, PhysicsActor p2, ContactPoint contact)
1313 {
1314 // obj1LocalID = 0;
1315 //returncollisions = false;
1316 obj2LocalID = 0;
1317 //ctype = 0;
1318 //cStartStop = 0;
1319 if (!p2.SubscribedEvents() && !p1.SubscribedEvents())
1320 return;
1321
1322 switch ((ActorTypes)p2.PhysicsActorType)
1323 {
1324 case ActorTypes.Agent:
1325 cc2 = (OdeCharacter)p2;
1326
1327 // obj1LocalID = cc2.m_localID;
1328 switch ((ActorTypes)p1.PhysicsActorType)
1329 {
1330 case ActorTypes.Agent:
1331 cc1 = (OdeCharacter)p1;
1332 obj2LocalID = cc1.m_localID;
1333 cc1.AddCollisionEvent(cc2.m_localID, contact);
1334 //ctype = (int)CollisionCategories.Character;
1335
1336 //if (cc1.CollidingObj)
1337 //cStartStop = (int)StatusIndicators.Generic;
1338 //else
1339 //cStartStop = (int)StatusIndicators.Start;
1340
1341 //returncollisions = true;
1342 break;
1343 case ActorTypes.Prim:
1344 if (p1 is OdePrim)
1345 {
1346 cp1 = (OdePrim) p1;
1347 obj2LocalID = cp1.m_localID;
1348 cp1.AddCollisionEvent(cc2.m_localID, contact);
1349 }
1350 //ctype = (int)CollisionCategories.Geom;
1351
1352 //if (cp1.CollidingObj)
1353 //cStartStop = (int)StatusIndicators.Generic;
1354 //else
1355 //cStartStop = (int)StatusIndicators.Start;
1356
1357 //returncollisions = true;
1358 break;
1359
1360 case ActorTypes.Ground:
1361 case ActorTypes.Unknown:
1362 obj2LocalID = 0;
1363 //ctype = (int)CollisionCategories.Land;
1364 //returncollisions = true;
1365 break;
1366 }
1367
1368 cc2.AddCollisionEvent(obj2LocalID, contact);
1369 break;
1370 case ActorTypes.Prim:
1371
1372 if (p2 is OdePrim)
1373 {
1374 cp2 = (OdePrim) p2;
1375
1376 // obj1LocalID = cp2.m_localID;
1377 switch ((ActorTypes) p1.PhysicsActorType)
1378 {
1379 case ActorTypes.Agent:
1380 if (p1 is OdeCharacter)
1381 {
1382 cc1 = (OdeCharacter) p1;
1383 obj2LocalID = cc1.m_localID;
1384 cc1.AddCollisionEvent(cp2.m_localID, contact);
1385 //ctype = (int)CollisionCategories.Character;
1386
1387 //if (cc1.CollidingObj)
1388 //cStartStop = (int)StatusIndicators.Generic;
1389 //else
1390 //cStartStop = (int)StatusIndicators.Start;
1391 //returncollisions = true;
1392 }
1393 break;
1394 case ActorTypes.Prim:
1395
1396 if (p1 is OdePrim)
1397 {
1398 cp1 = (OdePrim) p1;
1399 obj2LocalID = cp1.m_localID;
1400 cp1.AddCollisionEvent(cp2.m_localID, contact);
1401 //ctype = (int)CollisionCategories.Geom;
1402
1403 //if (cp1.CollidingObj)
1404 //cStartStop = (int)StatusIndicators.Generic;
1405 //else
1406 //cStartStop = (int)StatusIndicators.Start;
1407
1408 //returncollisions = true;
1409 }
1410 break;
1411
1412 case ActorTypes.Ground:
1413 case ActorTypes.Unknown:
1414 obj2LocalID = 0;
1415 //ctype = (int)CollisionCategories.Land;
1416
1417 //returncollisions = true;
1418 break;
1419 }
1420
1421 cp2.AddCollisionEvent(obj2LocalID, contact);
1422 }
1423 break;
1424 }
1425 //if (returncollisions)
1426 //{
1427
1428 //lock (m_storedCollisions)
1429 //{
1430 //cDictKey = obj1LocalID.ToString() + obj2LocalID.ToString() + cStartStop.ToString() + ctype.ToString();
1431 //if (m_storedCollisions.ContainsKey(cDictKey))
1432 //{
1433 //sCollisionData objd = m_storedCollisions[cDictKey];
1434 //objd.NumberOfCollisions += 1;
1435 //objd.lastframe = framecount;
1436 //m_storedCollisions[cDictKey] = objd;
1437 //}
1438 //else
1439 //{
1440 //sCollisionData objd = new sCollisionData();
1441 //objd.ColliderLocalId = obj1LocalID;
1442 //objd.CollidedWithLocalId = obj2LocalID;
1443 //objd.CollisionType = ctype;
1444 //objd.NumberOfCollisions = 1;
1445 //objd.lastframe = framecount;
1446 //objd.StatusIndicator = cStartStop;
1447 //m_storedCollisions.Add(cDictKey, objd);
1448 //}
1449 //}
1450 // }
1451 }
1452
1453 public int TriArrayCallback(IntPtr trimesh, IntPtr refObject, int[] triangleIndex, int triCount)
1454 {
1455 /* String name1 = null;
1456 String name2 = null;
1457
1458 if (!geom_name_map.TryGetValue(trimesh, out name1))
1459 {
1460 name1 = "null";
1461 }
1462 if (!geom_name_map.TryGetValue(refObject, out name2))
1463 {
1464 name2 = "null";
1465 }
1466
1467 m_log.InfoFormat("TriArrayCallback: A collision was detected between {1} and {2}", 0, name1, name2);
1468 */
1469 return 1;
1470 }
1471
1472 public int TriCallback(IntPtr trimesh, IntPtr refObject, int triangleIndex)
1473 {
1474 String name1 = null;
1475 String name2 = null;
1476
1477 if (!geom_name_map.TryGetValue(trimesh, out name1))
1478 {
1479 name1 = "null";
1480 }
1481
1482 if (!geom_name_map.TryGetValue(refObject, out name2))
1483 {
1484 name2 = "null";
1485 }
1486
1487 // m_log.InfoFormat("TriCallback: A collision was detected between {1} and {2}. Index was {3}", 0, name1, name2, triangleIndex);
1488
1489 d.Vector3 v0 = new d.Vector3();
1490 d.Vector3 v1 = new d.Vector3();
1491 d.Vector3 v2 = new d.Vector3();
1492
1493 d.GeomTriMeshGetTriangle(trimesh, 0, ref v0, ref v1, ref v2);
1494 // m_log.DebugFormat("Triangle {0} is <{1},{2},{3}>, <{4},{5},{6}>, <{7},{8},{9}>", triangleIndex, v0.X, v0.Y, v0.Z, v1.X, v1.Y, v1.Z, v2.X, v2.Y, v2.Z);
1495
1496 return 1;
1497 }
1498
1499 /// <summary>
1500 /// This is our collision testing routine in ODE
1501 /// </summary>
1502 /// <param name="timeStep"></param>
1503 private void collision_optimized(float timeStep)
1504 {
1505 _perloopContact.Clear();
1506
1507 lock (_characters)
1508 {
1509 foreach (OdeCharacter chr in _characters)
1510 {
1511 // Reset the collision values to false
1512 // since we don't know if we're colliding yet
1513
1514 // For some reason this can happen. Don't ask...
1515 //
1516 if (chr == null)
1517 continue;
1518
1519 if (chr.Shell == IntPtr.Zero || chr.Body == IntPtr.Zero)
1520 continue;
1521
1522 chr.IsColliding = false;
1523 chr.CollidingGround = false;
1524 chr.CollidingObj = false;
1525
1526 // test the avatar's geometry for collision with the space
1527 // This will return near and the space that they are the closest to
1528 // And we'll run this again against the avatar and the space segment
1529 // This will return with a bunch of possible objects in the space segment
1530 // and we'll run it again on all of them.
1531 try
1532 {
1533 d.SpaceCollide2(space, chr.Shell, IntPtr.Zero, nearCallback);
1534 }
1535 catch (AccessViolationException)
1536 {
1537 m_log.Warn("[PHYSICS]: Unable to space collide");
1538 }
1539 //float terrainheight = GetTerrainHeightAtXY(chr.Position.X, chr.Position.Y);
1540 //if (chr.Position.Z + (chr.Velocity.Z * timeStep) < terrainheight + 10)
1541 //{
1542 //chr.Position.Z = terrainheight + 10.0f;
1543 //forcedZ = true;
1544 //}
1545 }
1546 }
1547
1548 lock (_activeprims)
1549 {
1550 List<OdePrim> removeprims = null;
1551 foreach (OdePrim chr in _activeprims)
1552 {
1553 if (chr.Body != IntPtr.Zero && d.BodyIsEnabled(chr.Body) && (!chr.m_disabled))
1554 {
1555 try
1556 {
1557 lock (chr)
1558 {
1559 if (space != IntPtr.Zero && chr.prim_geom != IntPtr.Zero && chr.m_taintremove == false)
1560 {
1561 d.SpaceCollide2(space, chr.prim_geom, IntPtr.Zero, nearCallback);
1562 }
1563 else
1564 {
1565 if (removeprims == null)
1566 {
1567 removeprims = new List<OdePrim>();
1568 }
1569 removeprims.Add(chr);
1570 m_log.Debug("[PHYSICS]: unable to collide test active prim against space. The space was zero, the geom was zero or it was in the process of being removed. Removed it from the active prim list. This needs to be fixed!");
1571 }
1572 }
1573 }
1574 catch (AccessViolationException)
1575 {
1576 m_log.Warn("[PHYSICS]: Unable to space collide");
1577 }
1578 }
1579 }
1580 if (removeprims != null)
1581 {
1582 foreach (OdePrim chr in removeprims)
1583 {
1584 _activeprims.Remove(chr);
1585 }
1586 }
1587 }
1588
1589 _perloopContact.Clear();
1590 }
1591
1592 #endregion
1593
1594 public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
1595 {
1596 m_worldOffset = offset;
1597 WorldExtents = new Vector2(extents.X, extents.Y);
1598 m_parentScene = pScene;
1599
1600 }
1601
1602 // Recovered for use by fly height. Kitto Flora
1603 public float GetTerrainHeightAtXY(float x, float y)
1604 {
1605
1606 int offsetX = ((int)(x / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
1607 int offsetY = ((int)(y / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
1608
1609 IntPtr heightFieldGeom = IntPtr.Zero;
1610
1611 if (RegionTerrain.TryGetValue(new Vector3(offsetX,offsetY,0), out heightFieldGeom))
1612 {
1613 if (heightFieldGeom != IntPtr.Zero)
1614 {
1615 if (TerrainHeightFieldHeights.ContainsKey(heightFieldGeom))
1616 {
1617
1618 int index;
1619
1620
1621 if ((int)x > WorldExtents.X || (int)y > WorldExtents.Y ||
1622 (int)x < 0.001f || (int)y < 0.001f)
1623 return 0;
1624
1625 x = x - offsetX;
1626 y = y - offsetY;
1627
1628 index = (int)((int)x * ((int)Constants.RegionSize + 2) + (int)y);
1629
1630 if (index < TerrainHeightFieldHeights[heightFieldGeom].Length)
1631 {
1632 //m_log.DebugFormat("x{0} y{1} = {2}", x, y, (float)TerrainHeightFieldHeights[heightFieldGeom][index]);
1633 return (float)TerrainHeightFieldHeights[heightFieldGeom][index];
1634 }
1635
1636 else
1637 return 0f;
1638 }
1639 else
1640 {
1641 return 0f;
1642 }
1643
1644 }
1645 else
1646 {
1647 return 0f;
1648 }
1649
1650 }
1651 else
1652 {
1653 return 0f;
1654 }
1655
1656
1657 }
1658// End recovered. Kitto Flora
1659
1660 public void addCollisionEventReporting(PhysicsActor obj)
1661 {
1662 lock (_collisionEventPrim)
1663 {
1664 if (!_collisionEventPrim.Contains(obj))
1665 _collisionEventPrim.Add(obj);
1666 }
1667 }
1668
1669 public void remCollisionEventReporting(PhysicsActor obj)
1670 {
1671 lock (_collisionEventPrim)
1672 {
1673 if (!_collisionEventPrim.Contains(obj))
1674 _collisionEventPrim.Remove(obj);
1675 }
1676 }
1677
1678 #region Add/Remove Entities
1679
1680 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
1681 {
1682 Vector3 pos;
1683 pos.X = position.X;
1684 pos.Y = position.Y;
1685 pos.Z = position.Z;
1686 OdeCharacter newAv = new OdeCharacter(avName, this, pos, ode, size, avPIDD, avPIDP, avCapRadius, avStandupTensor, avDensity, avHeightFudgeFactor, avMovementDivisorWalk, avMovementDivisorRun);
1687 newAv.Flying = isFlying;
1688 newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset;
1689
1690 return newAv;
1691 }
1692
1693 public void AddCharacter(OdeCharacter chr)
1694 {
1695 lock (_characters)
1696 {
1697 if (!_characters.Contains(chr))
1698 {
1699 _characters.Add(chr);
1700 if (chr.bad)
1701 m_log.DebugFormat("[PHYSICS] Added BAD actor {0} to characters list", chr.m_uuid);
1702 }
1703 }
1704 }
1705
1706 public void RemoveCharacter(OdeCharacter chr)
1707 {
1708 lock (_characters)
1709 {
1710 if (_characters.Contains(chr))
1711 {
1712 _characters.Remove(chr);
1713 }
1714 }
1715 }
1716 public void BadCharacter(OdeCharacter chr)
1717 {
1718 lock (_badCharacter)
1719 {
1720 if (!_badCharacter.Contains(chr))
1721 _badCharacter.Add(chr);
1722 }
1723 }
1724
1725 public override void RemoveAvatar(PhysicsActor actor)
1726 {
1727 //m_log.Debug("[PHYSICS]:ODELOCK");
1728 ((OdeCharacter) actor).Destroy();
1729
1730 }
1731
1732 private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation,
1733 IMesh mesh, PrimitiveBaseShape pbs, bool isphysical)
1734 {
1735
1736 Vector3 pos = position;
1737 Vector3 siz = size;
1738 Quaternion rot = rotation;
1739
1740 OdePrim newPrim;
1741 lock (OdeLock)
1742 {
1743 newPrim = new OdePrim(name, this, pos, siz, rot, mesh, pbs, isphysical, ode);
1744
1745 lock (_prims)
1746 _prims.Add(newPrim);
1747 }
1748
1749 return newPrim;
1750 }
1751
1752 public void addActivePrim(OdePrim activatePrim)
1753 {
1754 // adds active prim.. (ones that should be iterated over in collisions_optimized
1755 lock (_activeprims)
1756 {
1757 if (!_activeprims.Contains(activatePrim))
1758 _activeprims.Add(activatePrim);
1759 //else
1760 // m_log.Warn("[PHYSICS]: Double Entry in _activeprims detected, potential crash immenent");
1761 }
1762 }
1763
1764 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
1765 Vector3 size, Quaternion rotation) //To be removed
1766 {
1767 return AddPrimShape(primName, pbs, position, size, rotation, false);
1768 }
1769
1770 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
1771 Vector3 size, Quaternion rotation, bool isPhysical)
1772 {
1773 PhysicsActor result;
1774 IMesh mesh = null;
1775
1776 if (needsMeshing(pbs))
1777 {
1778 try
1779 {
1780 mesh = mesher.CreateMesh(primName, pbs, size, 32f, isPhysical);
1781 }
1782 catch(Exception e)
1783 {
1784 m_log.ErrorFormat("[PHYSICS]: Exception while meshing prim {0}.", primName);
1785 m_log.Debug(e.ToString());
1786 mesh = null;
1787 return null;
1788 }
1789 }
1790
1791 result = AddPrim(primName, position, size, rotation, mesh, pbs, isPhysical);
1792
1793 return result;
1794 }
1795
1796 public override float TimeDilation
1797 {
1798 get { return m_timeDilation; }
1799 }
1800
1801 public override bool SupportsNINJAJoints
1802 {
1803 get { return m_NINJA_physics_joints_enabled; }
1804 }
1805
1806 // internal utility function: must be called within a lock (OdeLock)
1807 private void InternalAddActiveJoint(PhysicsJoint joint)
1808 {
1809 activeJoints.Add(joint);
1810 SOPName_to_activeJoint.Add(joint.ObjectNameInScene, joint);
1811 }
1812
1813 // internal utility function: must be called within a lock (OdeLock)
1814 private void InternalAddPendingJoint(OdePhysicsJoint joint)
1815 {
1816 pendingJoints.Add(joint);
1817 SOPName_to_pendingJoint.Add(joint.ObjectNameInScene, joint);
1818 }
1819
1820 // internal utility function: must be called within a lock (OdeLock)
1821 private void InternalRemovePendingJoint(PhysicsJoint joint)
1822 {
1823 pendingJoints.Remove(joint);
1824 SOPName_to_pendingJoint.Remove(joint.ObjectNameInScene);
1825 }
1826
1827 // internal utility function: must be called within a lock (OdeLock)
1828 private void InternalRemoveActiveJoint(PhysicsJoint joint)
1829 {
1830 activeJoints.Remove(joint);
1831 SOPName_to_activeJoint.Remove(joint.ObjectNameInScene);
1832 }
1833
1834 public override void DumpJointInfo()
1835 {
1836 string hdr = "[NINJA] JOINTINFO: ";
1837 foreach (PhysicsJoint j in pendingJoints)
1838 {
1839 m_log.Debug(hdr + " pending joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1840 }
1841 m_log.Debug(hdr + pendingJoints.Count + " total pending joints");
1842 foreach (string jointName in SOPName_to_pendingJoint.Keys)
1843 {
1844 m_log.Debug(hdr + " pending joints dict contains Name: " + jointName);
1845 }
1846 m_log.Debug(hdr + SOPName_to_pendingJoint.Keys.Count + " total pending joints dict entries");
1847 foreach (PhysicsJoint j in activeJoints)
1848 {
1849 m_log.Debug(hdr + " active joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1850 }
1851 m_log.Debug(hdr + activeJoints.Count + " total active joints");
1852 foreach (string jointName in SOPName_to_activeJoint.Keys)
1853 {
1854 m_log.Debug(hdr + " active joints dict contains Name: " + jointName);
1855 }
1856 m_log.Debug(hdr + SOPName_to_activeJoint.Keys.Count + " total active joints dict entries");
1857
1858 m_log.Debug(hdr + " Per-body joint connectivity information follows.");
1859 m_log.Debug(hdr + joints_connecting_actor.Keys.Count + " bodies are connected by joints.");
1860 foreach (string actorName in joints_connecting_actor.Keys)
1861 {
1862 m_log.Debug(hdr + " Actor " + actorName + " has the following joints connecting it");
1863 foreach (PhysicsJoint j in joints_connecting_actor[actorName])
1864 {
1865 m_log.Debug(hdr + " * joint Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1866 }
1867 m_log.Debug(hdr + joints_connecting_actor[actorName].Count + " connecting joints total for this actor");
1868 }
1869 }
1870
1871 public override void RequestJointDeletion(string ObjectNameInScene)
1872 {
1873 lock (externalJointRequestsLock)
1874 {
1875 if (!requestedJointsToBeDeleted.Contains(ObjectNameInScene)) // forbid same deletion request from entering twice to prevent spurious deletions processed asynchronously
1876 {
1877 requestedJointsToBeDeleted.Add(ObjectNameInScene);
1878 }
1879 }
1880 }
1881
1882 private void DeleteRequestedJoints()
1883 {
1884 List<string> myRequestedJointsToBeDeleted;
1885 lock (externalJointRequestsLock)
1886 {
1887 // make a local copy of the shared list for processing (threading issues)
1888 myRequestedJointsToBeDeleted = new List<string>(requestedJointsToBeDeleted);
1889 }
1890
1891 foreach (string jointName in myRequestedJointsToBeDeleted)
1892 {
1893 lock (OdeLock)
1894 {
1895 //m_log.Debug("[NINJA] trying to deleting requested joint " + jointName);
1896 if (SOPName_to_activeJoint.ContainsKey(jointName) || SOPName_to_pendingJoint.ContainsKey(jointName))
1897 {
1898 OdePhysicsJoint joint = null;
1899 if (SOPName_to_activeJoint.ContainsKey(jointName))
1900 {
1901 joint = SOPName_to_activeJoint[jointName] as OdePhysicsJoint;
1902 InternalRemoveActiveJoint(joint);
1903 }
1904 else if (SOPName_to_pendingJoint.ContainsKey(jointName))
1905 {
1906 joint = SOPName_to_pendingJoint[jointName] as OdePhysicsJoint;
1907 InternalRemovePendingJoint(joint);
1908 }
1909
1910 if (joint != null)
1911 {
1912 //m_log.Debug("joint.BodyNames.Count is " + joint.BodyNames.Count + " and contents " + joint.BodyNames);
1913 for (int iBodyName = 0; iBodyName < 2; iBodyName++)
1914 {
1915 string bodyName = joint.BodyNames[iBodyName];
1916 if (bodyName != "NULL")
1917 {
1918 joints_connecting_actor[bodyName].Remove(joint);
1919 if (joints_connecting_actor[bodyName].Count == 0)
1920 {
1921 joints_connecting_actor.Remove(bodyName);
1922 }
1923 }
1924 }
1925
1926 DoJointDeactivated(joint);
1927 if (joint.jointID != IntPtr.Zero)
1928 {
1929 d.JointDestroy(joint.jointID);
1930 joint.jointID = IntPtr.Zero;
1931 //DoJointErrorMessage(joint, "successfully destroyed joint " + jointName);
1932 }
1933 else
1934 {
1935 //m_log.Warn("[NINJA] Ignoring re-request to destroy joint " + jointName);
1936 }
1937 }
1938 else
1939 {
1940 // DoJointErrorMessage(joint, "coult not find joint to destroy based on name " + jointName);
1941 }
1942 }
1943 else
1944 {
1945 // DoJointErrorMessage(joint, "WARNING - joint removal failed, joint " + jointName);
1946 }
1947 }
1948 }
1949
1950 // remove processed joints from the shared list
1951 lock (externalJointRequestsLock)
1952 {
1953 foreach (string jointName in myRequestedJointsToBeDeleted)
1954 {
1955 requestedJointsToBeDeleted.Remove(jointName);
1956 }
1957 }
1958 }
1959
1960 // for pending joints we don't know if their associated bodies exist yet or not.
1961 // the joint is actually created during processing of the taints
1962 private void CreateRequestedJoints()
1963 {
1964 List<PhysicsJoint> myRequestedJointsToBeCreated;
1965 lock (externalJointRequestsLock)
1966 {
1967 // make a local copy of the shared list for processing (threading issues)
1968 myRequestedJointsToBeCreated = new List<PhysicsJoint>(requestedJointsToBeCreated);
1969 }
1970
1971 foreach (PhysicsJoint joint in myRequestedJointsToBeCreated)
1972 {
1973 lock (OdeLock)
1974 {
1975 if (SOPName_to_pendingJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_pendingJoint[joint.ObjectNameInScene] != null)
1976 {
1977 DoJointErrorMessage(joint, "WARNING: ignoring request to re-add already pending joint Name:" + joint.ObjectNameInScene + " type:" + joint.Type + " parms: " + joint.RawParams + " pos: " + joint.Position + " rot:" + joint.Rotation);
1978 continue;
1979 }
1980 if (SOPName_to_activeJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_activeJoint[joint.ObjectNameInScene] != null)
1981 {
1982 DoJointErrorMessage(joint, "WARNING: ignoring request to re-add already active joint Name:" + joint.ObjectNameInScene + " type:" + joint.Type + " parms: " + joint.RawParams + " pos: " + joint.Position + " rot:" + joint.Rotation);
1983 continue;
1984 }
1985
1986 InternalAddPendingJoint(joint as OdePhysicsJoint);
1987
1988 if (joint.BodyNames.Count >= 2)
1989 {
1990 for (int iBodyName = 0; iBodyName < 2; iBodyName++)
1991 {
1992 string bodyName = joint.BodyNames[iBodyName];
1993 if (bodyName != "NULL")
1994 {
1995 if (!joints_connecting_actor.ContainsKey(bodyName))
1996 {
1997 joints_connecting_actor.Add(bodyName, new List<PhysicsJoint>());
1998 }
1999 joints_connecting_actor[bodyName].Add(joint);
2000 }
2001 }
2002 }
2003 }
2004 }
2005
2006 // remove processed joints from shared list
2007 lock (externalJointRequestsLock)
2008 {
2009 foreach (PhysicsJoint joint in myRequestedJointsToBeCreated)
2010 {
2011 requestedJointsToBeCreated.Remove(joint);
2012 }
2013 }
2014
2015 }
2016
2017 // public function to add an request for joint creation
2018 // this joint will just be added to a waiting list that is NOT processed during the main
2019 // Simulate() loop (to avoid deadlocks). After Simulate() is finished, we handle unprocessed joint requests.
2020
2021 public override PhysicsJoint RequestJointCreation(string objectNameInScene, PhysicsJointType jointType, Vector3 position,
2022 Quaternion rotation, string parms, List<string> bodyNames, string trackedBodyName, Quaternion localRotation)
2023
2024 {
2025
2026 OdePhysicsJoint joint = new OdePhysicsJoint();
2027 joint.ObjectNameInScene = objectNameInScene;
2028 joint.Type = jointType;
2029 joint.Position = position;
2030 joint.Rotation = rotation;
2031 joint.RawParams = parms;
2032 joint.BodyNames = new List<string>(bodyNames);
2033 joint.TrackedBodyName = trackedBodyName;
2034 joint.LocalRotation = localRotation;
2035 joint.jointID = IntPtr.Zero;
2036 joint.ErrorMessageCount = 0;
2037
2038 lock (externalJointRequestsLock)
2039 {
2040 if (!requestedJointsToBeCreated.Contains(joint)) // forbid same creation request from entering twice
2041 {
2042 requestedJointsToBeCreated.Add(joint);
2043 }
2044 }
2045 return joint;
2046 }
2047
2048 private void RemoveAllJointsConnectedToActor(PhysicsActor actor)
2049 {
2050 //m_log.Debug("RemoveAllJointsConnectedToActor: start");
2051 if (actor.SOPName != null && joints_connecting_actor.ContainsKey(actor.SOPName) && joints_connecting_actor[actor.SOPName] != null)
2052 {
2053
2054 List<PhysicsJoint> jointsToRemove = new List<PhysicsJoint>();
2055 //TODO: merge these 2 loops (originally it was needed to avoid altering a list being iterated over, but it is no longer needed due to the joint request queue mechanism)
2056 foreach (PhysicsJoint j in joints_connecting_actor[actor.SOPName])
2057 {
2058 jointsToRemove.Add(j);
2059 }
2060 foreach (PhysicsJoint j in jointsToRemove)
2061 {
2062 //m_log.Debug("RemoveAllJointsConnectedToActor: about to request deletion of " + j.ObjectNameInScene);
2063 RequestJointDeletion(j.ObjectNameInScene);
2064 //m_log.Debug("RemoveAllJointsConnectedToActor: done request deletion of " + j.ObjectNameInScene);
2065 j.TrackedBodyName = null; // *IMMEDIATELY* prevent any further movement of this joint (else a deleted actor might cause spurious tracking motion of the joint for a few frames, leading to the joint proxy object disappearing)
2066 }
2067 }
2068 }
2069
2070 public override void RemoveAllJointsConnectedToActorThreadLocked(PhysicsActor actor)
2071 {
2072 //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: start");
2073 lock (OdeLock)
2074 {
2075 //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: got lock");
2076 RemoveAllJointsConnectedToActor(actor);
2077 }
2078 }
2079
2080 // normally called from within OnJointMoved, which is called from within a lock (OdeLock)
2081 public override Vector3 GetJointAnchor(PhysicsJoint joint)
2082 {
2083 Debug.Assert(joint.IsInPhysicsEngine);
2084 d.Vector3 pos = new d.Vector3();
2085
2086 if (!(joint is OdePhysicsJoint))
2087 {
2088 DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene);
2089 }
2090 else
2091 {
2092 OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint;
2093 switch (odeJoint.Type)
2094 {
2095 case PhysicsJointType.Ball:
2096 d.JointGetBallAnchor(odeJoint.jointID, out pos);
2097 break;
2098 case PhysicsJointType.Hinge:
2099 d.JointGetHingeAnchor(odeJoint.jointID, out pos);
2100 break;
2101 }
2102 }
2103 return new Vector3(pos.X, pos.Y, pos.Z);
2104 }
2105
2106 // normally called from within OnJointMoved, which is called from within a lock (OdeLock)
2107 // WARNING: ODE sometimes returns <0,0,0> as the joint axis! Therefore this function
2108 // appears to be unreliable. Fortunately we can compute the joint axis ourselves by
2109 // keeping track of the joint's original orientation relative to one of the involved bodies.
2110 public override Vector3 GetJointAxis(PhysicsJoint joint)
2111 {
2112 Debug.Assert(joint.IsInPhysicsEngine);
2113 d.Vector3 axis = new d.Vector3();
2114
2115 if (!(joint is OdePhysicsJoint))
2116 {
2117 DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene);
2118 }
2119 else
2120 {
2121 OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint;
2122 switch (odeJoint.Type)
2123 {
2124 case PhysicsJointType.Ball:
2125 DoJointErrorMessage(joint, "warning - axis requested for ball joint: " + joint.ObjectNameInScene);
2126 break;
2127 case PhysicsJointType.Hinge:
2128 d.JointGetHingeAxis(odeJoint.jointID, out axis);
2129 break;
2130 }
2131 }
2132 return new Vector3(axis.X, axis.Y, axis.Z);
2133 }
2134
2135
2136 public void remActivePrim(OdePrim deactivatePrim)
2137 {
2138 lock (_activeprims)
2139 {
2140 _activeprims.Remove(deactivatePrim);
2141 }
2142 }
2143
2144 public override void RemovePrim(PhysicsActor prim)
2145 {
2146 if (prim is OdePrim)
2147 {
2148 lock (OdeLock)
2149 {
2150 OdePrim p = (OdePrim) prim;
2151
2152 p.setPrimForRemoval();
2153 AddPhysicsActorTaint(prim);
2154 //RemovePrimThreadLocked(p);
2155 }
2156 }
2157 }
2158
2159 /// <summary>
2160 /// This is called from within simulate but outside the locked portion
2161 /// We need to do our own locking here
2162 /// Essentially, we need to remove the prim from our space segment, whatever segment it's in.
2163 ///
2164 /// If there are no more prim in the segment, we need to empty (spacedestroy)the segment and reclaim memory
2165 /// that the space was using.
2166 /// </summary>
2167 /// <param name="prim"></param>
2168 public void RemovePrimThreadLocked(OdePrim prim)
2169 {
2170//Console.WriteLine("RemovePrimThreadLocked " + prim.m_primName);
2171 lock (prim)
2172 {
2173 remCollisionEventReporting(prim);
2174 lock (ode)
2175 {
2176 if (prim.prim_geom != IntPtr.Zero)
2177 {
2178 prim.ResetTaints();
2179
2180 if (prim.IsPhysical)
2181 {
2182 prim.disableBody();
2183 if (prim.childPrim)
2184 {
2185 prim.childPrim = false;
2186 prim.Body = IntPtr.Zero;
2187 prim.m_disabled = true;
2188 prim.IsPhysical = false;
2189 }
2190
2191
2192 }
2193 // we don't want to remove the main space
2194
2195 // If the geometry is in the targetspace, remove it from the target space
2196 //m_log.Warn(prim.m_targetSpace);
2197
2198 //if (prim.m_targetSpace != IntPtr.Zero)
2199 //{
2200 //if (d.SpaceQuery(prim.m_targetSpace, prim.prim_geom))
2201 //{
2202
2203 //if (d.GeomIsSpace(prim.m_targetSpace))
2204 //{
2205 //waitForSpaceUnlock(prim.m_targetSpace);
2206 //d.SpaceRemove(prim.m_targetSpace, prim.prim_geom);
2207 prim.m_targetSpace = IntPtr.Zero;
2208 //}
2209 //else
2210 //{
2211 // m_log.Info("[Physics]: Invalid Scene passed to 'removeprim from scene':" +
2212 //((OdePrim)prim).m_targetSpace.ToString());
2213 //}
2214
2215 //}
2216 //}
2217 //m_log.Warn(prim.prim_geom);
2218 try
2219 {
2220 if (prim.prim_geom != IntPtr.Zero)
2221 {
2222 d.GeomDestroy(prim.prim_geom);
2223 prim.prim_geom = IntPtr.Zero;
2224 }
2225 else
2226 {
2227 m_log.Warn("[PHYSICS]: Unable to remove prim from physics scene");
2228 }
2229 }
2230 catch (AccessViolationException)
2231 {
2232 m_log.Info("[PHYSICS]: Couldn't remove prim from physics scene, it was already be removed.");
2233 }
2234 lock (_prims)
2235 _prims.Remove(prim);
2236
2237 //If there are no more geometries in the sub-space, we don't need it in the main space anymore
2238 //if (d.SpaceGetNumGeoms(prim.m_targetSpace) == 0)
2239 //{
2240 //if (prim.m_targetSpace != null)
2241 //{
2242 //if (d.GeomIsSpace(prim.m_targetSpace))
2243 //{
2244 //waitForSpaceUnlock(prim.m_targetSpace);
2245 //d.SpaceRemove(space, prim.m_targetSpace);
2246 // free up memory used by the space.
2247 //d.SpaceDestroy(prim.m_targetSpace);
2248 //int[] xyspace = calculateSpaceArrayItemFromPos(prim.Position);
2249 //resetSpaceArrayItemToZero(xyspace[0], xyspace[1]);
2250 //}
2251 //else
2252 //{
2253 //m_log.Info("[Physics]: Invalid Scene passed to 'removeprim from scene':" +
2254 //((OdePrim) prim).m_targetSpace.ToString());
2255 //}
2256 //}
2257 //}
2258
2259 if (SupportsNINJAJoints)
2260 {
2261 RemoveAllJointsConnectedToActorThreadLocked(prim);
2262 }
2263 }
2264 }
2265 }
2266 }
2267
2268 #endregion
2269
2270 #region Space Separation Calculation
2271
2272 /// <summary>
2273 /// Takes a space pointer and zeros out the array we're using to hold the spaces
2274 /// </summary>
2275 /// <param name="pSpace"></param>
2276 public void resetSpaceArrayItemToZero(IntPtr pSpace)
2277 {
2278 for (int x = 0; x < staticPrimspace.GetLength(0); x++)
2279 {
2280 for (int y = 0; y < staticPrimspace.GetLength(1); y++)
2281 {
2282 if (staticPrimspace[x, y] == pSpace)
2283 staticPrimspace[x, y] = IntPtr.Zero;
2284 }
2285 }
2286 }
2287
2288 public void resetSpaceArrayItemToZero(int arrayitemX, int arrayitemY)
2289 {
2290 staticPrimspace[arrayitemX, arrayitemY] = IntPtr.Zero;
2291 }
2292
2293 /// <summary>
2294 /// Called when a static prim moves. Allocates a space for the prim based on its position
2295 /// </summary>
2296 /// <param name="geom">the pointer to the geom that moved</param>
2297 /// <param name="pos">the position that the geom moved to</param>
2298 /// <param name="currentspace">a pointer to the space it was in before it was moved.</param>
2299 /// <returns>a pointer to the new space it's in</returns>
2300 public IntPtr recalculateSpaceForGeom(IntPtr geom, Vector3 pos, IntPtr currentspace)
2301 {
2302 // Called from setting the Position and Size of an ODEPrim so
2303 // it's already in locked space.
2304
2305 // we don't want to remove the main space
2306 // we don't need to test physical here because this function should
2307 // never be called if the prim is physical(active)
2308
2309 // All physical prim end up in the root space
2310 //Thread.Sleep(20);
2311 if (currentspace != space)
2312 {
2313 //m_log.Info("[SPACE]: C:" + currentspace.ToString() + " g:" + geom.ToString());
2314 //if (currentspace == IntPtr.Zero)
2315 //{
2316 //int adfadf = 0;
2317 //}
2318 if (d.SpaceQuery(currentspace, geom) && currentspace != IntPtr.Zero)
2319 {
2320 if (d.GeomIsSpace(currentspace))
2321 {
2322 waitForSpaceUnlock(currentspace);
2323 d.SpaceRemove(currentspace, geom);
2324 }
2325 else
2326 {
2327 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" + currentspace +
2328 " Geom:" + geom);
2329 }
2330 }
2331 else
2332 {
2333 IntPtr sGeomIsIn = d.GeomGetSpace(geom);
2334 if (sGeomIsIn != IntPtr.Zero)
2335 {
2336 if (d.GeomIsSpace(currentspace))
2337 {
2338 waitForSpaceUnlock(sGeomIsIn);
2339 d.SpaceRemove(sGeomIsIn, geom);
2340 }
2341 else
2342 {
2343 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2344 sGeomIsIn + " Geom:" + geom);
2345 }
2346 }
2347 }
2348
2349 //If there are no more geometries in the sub-space, we don't need it in the main space anymore
2350 if (d.SpaceGetNumGeoms(currentspace) == 0)
2351 {
2352 if (currentspace != IntPtr.Zero)
2353 {
2354 if (d.GeomIsSpace(currentspace))
2355 {
2356 waitForSpaceUnlock(currentspace);
2357 waitForSpaceUnlock(space);
2358 d.SpaceRemove(space, currentspace);
2359 // free up memory used by the space.
2360
2361 //d.SpaceDestroy(currentspace);
2362 resetSpaceArrayItemToZero(currentspace);
2363 }
2364 else
2365 {
2366 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2367 currentspace + " Geom:" + geom);
2368 }
2369 }
2370 }
2371 }
2372 else
2373 {
2374 // this is a physical object that got disabled. ;.;
2375 if (currentspace != IntPtr.Zero && geom != IntPtr.Zero)
2376 {
2377 if (d.SpaceQuery(currentspace, geom))
2378 {
2379 if (d.GeomIsSpace(currentspace))
2380 {
2381 waitForSpaceUnlock(currentspace);
2382 d.SpaceRemove(currentspace, geom);
2383 }
2384 else
2385 {
2386 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2387 currentspace + " Geom:" + geom);
2388 }
2389 }
2390 else
2391 {
2392 IntPtr sGeomIsIn = d.GeomGetSpace(geom);
2393 if (sGeomIsIn != IntPtr.Zero)
2394 {
2395 if (d.GeomIsSpace(sGeomIsIn))
2396 {
2397 waitForSpaceUnlock(sGeomIsIn);
2398 d.SpaceRemove(sGeomIsIn, geom);
2399 }
2400 else
2401 {
2402 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2403 sGeomIsIn + " Geom:" + geom);
2404 }
2405 }
2406 }
2407 }
2408 }
2409
2410 // The routines in the Position and Size sections do the 'inserting' into the space,
2411 // so all we have to do is make sure that the space that we're putting the prim into
2412 // is in the 'main' space.
2413 int[] iprimspaceArrItem = calculateSpaceArrayItemFromPos(pos);
2414 IntPtr newspace = calculateSpaceForGeom(pos);
2415
2416 if (newspace == IntPtr.Zero)
2417 {
2418 newspace = createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]);
2419 d.HashSpaceSetLevels(newspace, smallHashspaceLow, smallHashspaceHigh);
2420 }
2421
2422 return newspace;
2423 }
2424
2425 /// <summary>
2426 /// Creates a new space at X Y
2427 /// </summary>
2428 /// <param name="iprimspaceArrItemX"></param>
2429 /// <param name="iprimspaceArrItemY"></param>
2430 /// <returns>A pointer to the created space</returns>
2431 public IntPtr createprimspace(int iprimspaceArrItemX, int iprimspaceArrItemY)
2432 {
2433 // creating a new space for prim and inserting it into main space.
2434 staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY] = d.HashSpaceCreate(IntPtr.Zero);
2435 d.GeomSetCategoryBits(staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY], (int)CollisionCategories.Space);
2436 waitForSpaceUnlock(space);
2437 d.SpaceSetSublevel(space, 1);
2438 d.SpaceAdd(space, staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY]);
2439 return staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY];
2440 }
2441
2442 /// <summary>
2443 /// Calculates the space the prim should be in by its position
2444 /// </summary>
2445 /// <param name="pos"></param>
2446 /// <returns>a pointer to the space. This could be a new space or reused space.</returns>
2447 public IntPtr calculateSpaceForGeom(Vector3 pos)
2448 {
2449 int[] xyspace = calculateSpaceArrayItemFromPos(pos);
2450 //m_log.Info("[Physics]: Attempting to use arrayItem: " + xyspace[0].ToString() + "," + xyspace[1].ToString());
2451 return staticPrimspace[xyspace[0], xyspace[1]];
2452 }
2453
2454 /// <summary>
2455 /// Holds the space allocation logic
2456 /// </summary>
2457 /// <param name="pos"></param>
2458 /// <returns>an array item based on the position</returns>
2459 public int[] calculateSpaceArrayItemFromPos(Vector3 pos)
2460 {
2461 int[] returnint = new int[2];
2462
2463 returnint[0] = (int) (pos.X/metersInSpace);
2464
2465 if (returnint[0] > ((int) (259f/metersInSpace)))
2466 returnint[0] = ((int) (259f/metersInSpace));
2467 if (returnint[0] < 0)
2468 returnint[0] = 0;
2469
2470 returnint[1] = (int) (pos.Y/metersInSpace);
2471 if (returnint[1] > ((int) (259f/metersInSpace)))
2472 returnint[1] = ((int) (259f/metersInSpace));
2473 if (returnint[1] < 0)
2474 returnint[1] = 0;
2475
2476 return returnint;
2477 }
2478
2479 #endregion
2480
2481 /// <summary>
2482 /// Routine to figure out if we need to mesh this prim with our mesher
2483 /// </summary>
2484 /// <param name="pbs"></param>
2485 /// <returns></returns>
2486 public bool needsMeshing(PrimitiveBaseShape pbs)
2487 {
2488 // most of this is redundant now as the mesher will return null if it cant mesh a prim
2489 // but we still need to check for sculptie meshing being enabled so this is the most
2490 // convenient place to do it for now...
2491
2492 // //if (pbs.PathCurve == (byte)Primitive.PathCurve.Circle && pbs.ProfileCurve == (byte)Primitive.ProfileCurve.Circle && pbs.PathScaleY <= 0.75f)
2493 // //m_log.Debug("needsMeshing: " + " pathCurve: " + pbs.PathCurve.ToString() + " profileCurve: " + pbs.ProfileCurve.ToString() + " pathScaleY: " + Primitive.UnpackPathScale(pbs.PathScaleY).ToString());
2494 int iPropertiesNotSupportedDefault = 0;
2495
2496 if (pbs.SculptEntry && !meshSculptedPrim)
2497 {
2498#if SPAM
2499 m_log.Warn("NonMesh");
2500#endif
2501 return false;
2502 }
2503
2504 // if it's a standard box or sphere with no cuts, hollows, twist or top shear, return false since ODE can use an internal representation for the prim
2505 if (!forceSimplePrimMeshing)
2506 {
2507 if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
2508 || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1
2509 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z))
2510 {
2511
2512 if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
2513 && pbs.ProfileHollow == 0
2514 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
2515 && pbs.PathBegin == 0 && pbs.PathEnd == 0
2516 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
2517 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
2518 && pbs.PathShearX == 0 && pbs.PathShearY == 0)
2519 {
2520#if SPAM
2521 m_log.Warn("NonMesh");
2522#endif
2523 return false;
2524 }
2525 }
2526 }
2527
2528 if (pbs.ProfileHollow != 0)
2529 iPropertiesNotSupportedDefault++;
2530
2531 if ((pbs.PathBegin != 0) || pbs.PathEnd != 0)
2532 iPropertiesNotSupportedDefault++;
2533
2534 if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0))
2535 iPropertiesNotSupportedDefault++;
2536
2537 if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0)
2538 iPropertiesNotSupportedDefault++;
2539
2540 if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100))
2541 iPropertiesNotSupportedDefault++;
2542
2543 if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0))
2544 iPropertiesNotSupportedDefault++;
2545
2546 if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight)
2547 iPropertiesNotSupportedDefault++;
2548
2549 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 && (pbs.Scale.X != pbs.Scale.Y || pbs.Scale.Y != pbs.Scale.Z || pbs.Scale.Z != pbs.Scale.X))
2550 iPropertiesNotSupportedDefault++;
2551
2552 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte) Extrusion.Curve1)
2553 iPropertiesNotSupportedDefault++;
2554
2555 // test for torus
2556 if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square)
2557 {
2558 if (pbs.PathCurve == (byte)Extrusion.Curve1)
2559 {
2560 iPropertiesNotSupportedDefault++;
2561 }
2562 }
2563 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
2564 {
2565 if (pbs.PathCurve == (byte)Extrusion.Straight)
2566 {
2567 iPropertiesNotSupportedDefault++;
2568 }
2569
2570 // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits
2571 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
2572 {
2573 iPropertiesNotSupportedDefault++;
2574 }
2575 }
2576 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
2577 {
2578 if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2)
2579 {
2580 iPropertiesNotSupportedDefault++;
2581 }
2582 }
2583 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
2584 {
2585 if (pbs.PathCurve == (byte)Extrusion.Straight)
2586 {
2587 iPropertiesNotSupportedDefault++;
2588 }
2589 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
2590 {
2591 iPropertiesNotSupportedDefault++;
2592 }
2593 }
2594
2595
2596 if (iPropertiesNotSupportedDefault == 0)
2597 {
2598#if SPAM
2599 m_log.Warn("NonMesh");
2600#endif
2601 return false;
2602 }
2603#if SPAM
2604 m_log.Debug("Mesh");
2605#endif
2606 return true;
2607 }
2608
2609 /// <summary>
2610 /// Called after our prim properties are set Scale, position etc.
2611 /// We use this event queue like method to keep changes to the physical scene occuring in the threadlocked mutex
2612 /// This assures us that we have no race conditions
2613 /// </summary>
2614 /// <param name="prim"></param>
2615 public override void AddPhysicsActorTaint(PhysicsActor prim)
2616 {
2617
2618 if (prim is OdePrim)
2619 {
2620 OdePrim taintedprim = ((OdePrim) prim);
2621 lock (_taintedPrimLock)
2622 {
2623 if (!(_taintedPrimH.Contains(taintedprim)))
2624 {
2625//Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.m_primName);
2626 _taintedPrimH.Add(taintedprim); // HashSet for searching
2627 _taintedPrimL.Add(taintedprim); // List for ordered readout
2628 }
2629 }
2630 return;
2631 }
2632 else if (prim is OdeCharacter)
2633 {
2634 OdeCharacter taintedchar = ((OdeCharacter)prim);
2635 lock (_taintedActors)
2636 {
2637 if (!(_taintedActors.Contains(taintedchar)))
2638 {
2639 _taintedActors.Add(taintedchar);
2640 if (taintedchar.bad)
2641 m_log.DebugFormat("[PHYSICS]: Added BAD actor {0} to tainted actors", taintedchar.m_uuid);
2642 }
2643 }
2644 }
2645 }
2646
2647 /// <summary>
2648 /// This is our main simulate loop
2649 /// It's thread locked by a Mutex in the scene.
2650 /// It holds Collisions, it instructs ODE to step through the physical reactions
2651 /// It moves the objects around in memory
2652 /// It calls the methods that report back to the object owners.. (scenepresence, SceneObjectGroup)
2653 /// </summary>
2654 /// <param name="timeStep"></param>
2655 /// <returns></returns>
2656 public override float Simulate(float timeStep)
2657 {
2658 if (framecount >= int.MaxValue)
2659 framecount = 0;
2660
2661 //if (m_worldOffset != Vector3.Zero)
2662 // return 0;
2663
2664 framecount++;
2665
2666 float fps = 0;
2667 //m_log.Info(timeStep.ToString());
2668 step_time += timeStep;
2669
2670 // If We're loaded down by something else,
2671 // or debugging with the Visual Studio project on pause
2672 // skip a few frames to catch up gracefully.
2673 // without shooting the physicsactors all over the place
2674
2675 if (step_time >= m_SkipFramesAtms)
2676 {
2677 // Instead of trying to catch up, it'll do 5 physics frames only
2678 step_time = ODE_STEPSIZE;
2679 m_physicsiterations = 5;
2680 }
2681 else
2682 {
2683 m_physicsiterations = 10;
2684 }
2685
2686 if (SupportsNINJAJoints)
2687 {
2688 DeleteRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks
2689 CreateRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks
2690 }
2691
2692 lock (OdeLock)
2693 {
2694 // Process 10 frames if the sim is running normal..
2695 // process 5 frames if the sim is running slow
2696 //try
2697 //{
2698 //d.WorldSetQuickStepNumIterations(world, m_physicsiterations);
2699 //}
2700 //catch (StackOverflowException)
2701 //{
2702 // m_log.Error("[PHYSICS]: The operating system wasn't able to allocate enough memory for the simulation. Restarting the sim.");
2703 // ode.drelease(world);
2704 //base.TriggerPhysicsBasedRestart();
2705 //}
2706
2707 int i = 0;
2708
2709 // Figure out the Frames Per Second we're going at.
2710 //(step_time == 0.004f, there's 250 of those per second. Times the step time/step size
2711
2712 fps = (step_time / ODE_STEPSIZE) * 1000;
2713 // HACK: Using a time dilation of 1.0 to debug rubberbanding issues
2714 //m_timeDilation = Math.Min((step_time / ODE_STEPSIZE) / (0.09375f / ODE_STEPSIZE), 1.0f);
2715
2716 step_time = 0.09375f;
2717
2718 while (step_time > 0.0f)
2719 {
2720 //lock (ode)
2721 //{
2722 //if (!ode.lockquery())
2723 //{
2724 // ode.dlock(world);
2725 try
2726 {
2727 // Insert, remove Characters
2728 bool processedtaints = false;
2729
2730 lock (_taintedActors)
2731 {
2732 if (_taintedActors.Count > 0)
2733 {
2734 foreach (OdeCharacter character in _taintedActors)
2735 {
2736
2737 character.ProcessTaints(timeStep);
2738
2739 processedtaints = true;
2740 //character.m_collisionscore = 0;
2741 }
2742
2743 if (processedtaints)
2744 _taintedActors.Clear();
2745 }
2746 }
2747
2748 // Modify other objects in the scene.
2749 processedtaints = false;
2750
2751 lock (_taintedPrimLock)
2752 {
2753 foreach (OdePrim prim in _taintedPrimL)
2754 {
2755 if (prim.m_taintremove)
2756 {
2757 //Console.WriteLine("Simulate calls RemovePrimThreadLocked");
2758 RemovePrimThreadLocked(prim);
2759 }
2760 else
2761 {
2762 //Console.WriteLine("Simulate calls ProcessTaints");
2763 prim.ProcessTaints(timeStep);
2764 }
2765 processedtaints = true;
2766 prim.m_collisionscore = 0;
2767
2768 // This loop can block up the Heartbeat for a very long time on large regions.
2769 // We need to let the Watchdog know that the Heartbeat is not dead
2770 // NOTE: This is currently commented out, but if things like OAR loading are
2771 // timing the heartbeat out we will need to uncomment it
2772 //Watchdog.UpdateThread();
2773 }
2774
2775 if (SupportsNINJAJoints)
2776 {
2777 // Create pending joints, if possible
2778
2779 // joints can only be processed after ALL bodies are processed (and exist in ODE), since creating
2780 // a joint requires specifying the body id of both involved bodies
2781 if (pendingJoints.Count > 0)
2782 {
2783 List<PhysicsJoint> successfullyProcessedPendingJoints = new List<PhysicsJoint>();
2784 //DoJointErrorMessage(joints_connecting_actor, "taint: " + pendingJoints.Count + " pending joints");
2785 foreach (PhysicsJoint joint in pendingJoints)
2786 {
2787 //DoJointErrorMessage(joint, "taint: time to create joint with parms: " + joint.RawParams);
2788 string[] jointParams = joint.RawParams.Split(" ".ToCharArray(), System.StringSplitOptions.RemoveEmptyEntries);
2789 List<IntPtr> jointBodies = new List<IntPtr>();
2790 bool allJointBodiesAreReady = true;
2791 foreach (string jointParam in jointParams)
2792 {
2793 if (jointParam == "NULL")
2794 {
2795 //DoJointErrorMessage(joint, "attaching NULL joint to world");
2796 jointBodies.Add(IntPtr.Zero);
2797 }
2798 else
2799 {
2800 //DoJointErrorMessage(joint, "looking for prim name: " + jointParam);
2801 bool foundPrim = false;
2802 lock (_prims)
2803 {
2804 foreach (OdePrim prim in _prims) // FIXME: inefficient
2805 {
2806 if (prim.SOPName == jointParam)
2807 {
2808 //DoJointErrorMessage(joint, "found for prim name: " + jointParam);
2809 if (prim.IsPhysical && prim.Body != IntPtr.Zero)
2810 {
2811 jointBodies.Add(prim.Body);
2812 foundPrim = true;
2813 break;
2814 }
2815 else
2816 {
2817 DoJointErrorMessage(joint, "prim name " + jointParam +
2818 " exists but is not (yet) physical; deferring joint creation. " +
2819 "IsPhysical property is " + prim.IsPhysical +
2820 " and body is " + prim.Body);
2821 foundPrim = false;
2822 break;
2823 }
2824 }
2825 }
2826 }
2827 if (foundPrim)
2828 {
2829 // all is fine
2830 }
2831 else
2832 {
2833 allJointBodiesAreReady = false;
2834 break;
2835 }
2836 }
2837 }
2838 if (allJointBodiesAreReady)
2839 {
2840 //DoJointErrorMessage(joint, "allJointBodiesAreReady for " + joint.ObjectNameInScene + " with parms " + joint.RawParams);
2841 if (jointBodies[0] == jointBodies[1])
2842 {
2843 DoJointErrorMessage(joint, "ERROR: joint cannot be created; the joint bodies are the same, body1==body2. Raw body is " + jointBodies[0] + ". raw parms: " + joint.RawParams);
2844 }
2845 else
2846 {
2847 switch (joint.Type)
2848 {
2849 case PhysicsJointType.Ball:
2850 {
2851 IntPtr odeJoint;
2852 //DoJointErrorMessage(joint, "ODE creating ball joint ");
2853 odeJoint = d.JointCreateBall(world, IntPtr.Zero);
2854 //DoJointErrorMessage(joint, "ODE attaching ball joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]);
2855 d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]);
2856 //DoJointErrorMessage(joint, "ODE setting ball anchor: " + odeJoint + " to vec:" + joint.Position);
2857 d.JointSetBallAnchor(odeJoint,
2858 joint.Position.X,
2859 joint.Position.Y,
2860 joint.Position.Z);
2861 //DoJointErrorMessage(joint, "ODE joint setting OK");
2862 //DoJointErrorMessage(joint, "The ball joint's bodies are here: b0: ");
2863 //DoJointErrorMessage(joint, "" + (jointBodies[0] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[0]) : "fixed environment"));
2864 //DoJointErrorMessage(joint, "The ball joint's bodies are here: b1: ");
2865 //DoJointErrorMessage(joint, "" + (jointBodies[1] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[1]) : "fixed environment"));
2866
2867 if (joint is OdePhysicsJoint)
2868 {
2869 ((OdePhysicsJoint)joint).jointID = odeJoint;
2870 }
2871 else
2872 {
2873 DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!");
2874 }
2875 }
2876 break;
2877 case PhysicsJointType.Hinge:
2878 {
2879 IntPtr odeJoint;
2880 //DoJointErrorMessage(joint, "ODE creating hinge joint ");
2881 odeJoint = d.JointCreateHinge(world, IntPtr.Zero);
2882 //DoJointErrorMessage(joint, "ODE attaching hinge joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]);
2883 d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]);
2884 //DoJointErrorMessage(joint, "ODE setting hinge anchor: " + odeJoint + " to vec:" + joint.Position);
2885 d.JointSetHingeAnchor(odeJoint,
2886 joint.Position.X,
2887 joint.Position.Y,
2888 joint.Position.Z);
2889 // We use the orientation of the x-axis of the joint's coordinate frame
2890 // as the axis for the hinge.
2891
2892 // Therefore, we must get the joint's coordinate frame based on the
2893 // joint.Rotation field, which originates from the orientation of the
2894 // joint's proxy object in the scene.
2895
2896 // The joint's coordinate frame is defined as the transformation matrix
2897 // that converts a vector from joint-local coordinates into world coordinates.
2898 // World coordinates are defined as the XYZ coordinate system of the sim,
2899 // as shown in the top status-bar of the viewer.
2900
2901 // Once we have the joint's coordinate frame, we extract its X axis (AtAxis)
2902 // and use that as the hinge axis.
2903
2904 //joint.Rotation.Normalize();
2905 Matrix4 proxyFrame = Matrix4.CreateFromQuaternion(joint.Rotation);
2906
2907 // Now extract the X axis of the joint's coordinate frame.
2908
2909 // Do not try to use proxyFrame.AtAxis or you will become mired in the
2910 // tar pit of transposed, inverted, and generally messed-up orientations.
2911 // (In other words, Matrix4.AtAxis() is borked.)
2912 // Vector3 jointAxis = proxyFrame.AtAxis; <--- this path leadeth to madness
2913
2914 // Instead, compute the X axis of the coordinate frame by transforming
2915 // the (1,0,0) vector. At least that works.
2916
2917 //m_log.Debug("PHY: making axis: complete matrix is " + proxyFrame);
2918 Vector3 jointAxis = Vector3.Transform(Vector3.UnitX, proxyFrame);
2919 //m_log.Debug("PHY: making axis: hinge joint axis is " + jointAxis);
2920 //DoJointErrorMessage(joint, "ODE setting hinge axis: " + odeJoint + " to vec:" + jointAxis);
2921 d.JointSetHingeAxis(odeJoint,
2922 jointAxis.X,
2923 jointAxis.Y,
2924 jointAxis.Z);
2925 //d.JointSetHingeParam(odeJoint, (int)dParam.CFM, 0.1f);
2926 if (joint is OdePhysicsJoint)
2927 {
2928 ((OdePhysicsJoint)joint).jointID = odeJoint;
2929 }
2930 else
2931 {
2932 DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!");
2933 }
2934 }
2935 break;
2936 }
2937 successfullyProcessedPendingJoints.Add(joint);
2938 }
2939 }
2940 else
2941 {
2942 DoJointErrorMessage(joint, "joint could not yet be created; still pending");
2943 }
2944 }
2945 foreach (PhysicsJoint successfullyProcessedJoint in successfullyProcessedPendingJoints)
2946 {
2947 //DoJointErrorMessage(successfullyProcessedJoint, "finalizing succesfully procsssed joint " + successfullyProcessedJoint.ObjectNameInScene + " parms " + successfullyProcessedJoint.RawParams);
2948 //DoJointErrorMessage(successfullyProcessedJoint, "removing from pending");
2949 InternalRemovePendingJoint(successfullyProcessedJoint);
2950 //DoJointErrorMessage(successfullyProcessedJoint, "adding to active");
2951 InternalAddActiveJoint(successfullyProcessedJoint);
2952 //DoJointErrorMessage(successfullyProcessedJoint, "done");
2953 }
2954 }
2955 }
2956
2957 if (processedtaints)
2958//Console.WriteLine("Simulate calls Clear of _taintedPrim list");
2959 _taintedPrimH.Clear();
2960 _taintedPrimL.Clear();
2961 }
2962
2963 // Move characters
2964 lock (_characters)
2965 {
2966 List<OdeCharacter> defects = new List<OdeCharacter>();
2967 foreach (OdeCharacter actor in _characters)
2968 {
2969 if (actor != null)
2970 actor.Move(timeStep, defects);
2971 }
2972 if (0 != defects.Count)
2973 {
2974 foreach (OdeCharacter defect in defects)
2975 {
2976 RemoveCharacter(defect);
2977 }
2978 }
2979 }
2980
2981 // Move other active objects
2982 lock (_activeprims)
2983 {
2984 foreach (OdePrim prim in _activeprims)
2985 {
2986 prim.m_collisionscore = 0;
2987 prim.Move(timeStep);
2988 }
2989 }
2990
2991 //if ((framecount % m_randomizeWater) == 0)
2992 // randomizeWater(waterlevel);
2993
2994 //int RayCastTimeMS = m_rayCastManager.ProcessQueuedRequests();
2995 m_rayCastManager.ProcessQueuedRequests();
2996
2997 collision_optimized(timeStep);
2998
2999 lock (_collisionEventPrim)
3000 {
3001 foreach (PhysicsActor obj in _collisionEventPrim)
3002 {
3003 if (obj == null)
3004 continue;
3005
3006 switch ((ActorTypes)obj.PhysicsActorType)
3007 {
3008 case ActorTypes.Agent:
3009 OdeCharacter cobj = (OdeCharacter)obj;
3010 cobj.AddCollisionFrameTime(100);
3011 cobj.SendCollisions();
3012 break;
3013 case ActorTypes.Prim:
3014 OdePrim pobj = (OdePrim)obj;
3015 pobj.SendCollisions();
3016 break;
3017 }
3018 }
3019 }
3020
3021 //if (m_global_contactcount > 5)
3022 //{
3023 // m_log.DebugFormat("[PHYSICS]: Contacts:{0}", m_global_contactcount);
3024 //}
3025
3026 m_global_contactcount = 0;
3027
3028 d.WorldQuickStep(world, ODE_STEPSIZE);
3029 d.JointGroupEmpty(contactgroup);
3030 //ode.dunlock(world);
3031 }
3032 catch (Exception e)
3033 {
3034 m_log.ErrorFormat("[PHYSICS]: {0}, {1}, {2}", e.Message, e.TargetSite, e);
3035 ode.dunlock(world);
3036 }
3037
3038 step_time -= ODE_STEPSIZE;
3039 i++;
3040 //}
3041 //else
3042 //{
3043 //fps = 0;
3044 //}
3045 //}
3046 }
3047
3048 lock (_characters)
3049 {
3050 foreach (OdeCharacter actor in _characters)
3051 {
3052 if (actor != null)
3053 {
3054 if (actor.bad)
3055 m_log.WarnFormat("[PHYSICS]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid);
3056 actor.UpdatePositionAndVelocity();
3057 }
3058 }
3059 }
3060
3061 lock (_badCharacter)
3062 {
3063 if (_badCharacter.Count > 0)
3064 {
3065 foreach (OdeCharacter chr in _badCharacter)
3066 {
3067 RemoveCharacter(chr);
3068 }
3069 _badCharacter.Clear();
3070 }
3071 }
3072
3073 lock (_activeprims)
3074 {
3075 //if (timeStep < 0.2f)
3076 {
3077 foreach (OdePrim actor in _activeprims)
3078 {
3079 if (actor.IsPhysical && (d.BodyIsEnabled(actor.Body) || !actor._zeroFlag))
3080 {
3081 actor.UpdatePositionAndVelocity();
3082
3083 if (SupportsNINJAJoints)
3084 {
3085 // If an actor moved, move its joint proxy objects as well.
3086 // There seems to be an event PhysicsActor.OnPositionUpdate that could be used
3087 // for this purpose but it is never called! So we just do the joint
3088 // movement code here.
3089
3090 if (actor.SOPName != null &&
3091 joints_connecting_actor.ContainsKey(actor.SOPName) &&
3092 joints_connecting_actor[actor.SOPName] != null &&
3093 joints_connecting_actor[actor.SOPName].Count > 0)
3094 {
3095 foreach (PhysicsJoint affectedJoint in joints_connecting_actor[actor.SOPName])
3096 {
3097 if (affectedJoint.IsInPhysicsEngine)
3098 {
3099 DoJointMoved(affectedJoint);
3100 }
3101 else
3102 {
3103 DoJointErrorMessage(affectedJoint, "a body connected to a joint was moved, but the joint doesn't exist yet! this will lead to joint error. joint was: " + affectedJoint.ObjectNameInScene + " parms:" + affectedJoint.RawParams);
3104 }
3105 }
3106 }
3107 }
3108 }
3109 }
3110 }
3111 }
3112
3113 //DumpJointInfo();
3114
3115 // Finished with all sim stepping. If requested, dump world state to file for debugging.
3116 // TODO: This call to the export function is already inside lock (OdeLock) - but is an extra lock needed?
3117 // TODO: This overwrites all dump files in-place. Should this be a growing logfile, or separate snapshots?
3118 if (physics_logging && (physics_logging_interval>0) && (framecount % physics_logging_interval == 0))
3119 {
3120 string fname = "state-" + world.ToString() + ".DIF"; // give each physics world a separate filename
3121 string prefix = "world" + world.ToString(); // prefix for variable names in exported .DIF file
3122
3123 if (physics_logging_append_existing_logfile)
3124 {
3125 string header = "-------------- START OF PHYSICS FRAME " + framecount.ToString() + " --------------";
3126 TextWriter fwriter = File.AppendText(fname);
3127 fwriter.WriteLine(header);
3128 fwriter.Close();
3129 }
3130 d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix);
3131 }
3132 latertickcount = Util.EnvironmentTickCount() - tickCountFrameRun;
3133
3134 // OpenSimulator above does 10 fps. 10 fps = means that the main thread loop and physics
3135 // has a max of 100 ms to run theoretically.
3136 // If the main loop stalls, it calls Simulate later which makes the tick count ms larger.
3137 // If Physics stalls, it takes longer which makes the tick count ms larger.
3138
3139 if (latertickcount < 100)
3140 m_timeDilation = 1.0f;
3141 else
3142 {
3143 m_timeDilation = 100f / latertickcount;
3144 //m_timeDilation = Math.Min((Math.Max(100 - (Util.EnvironmentTickCount() - tickCountFrameRun), 1) / 100f), 1.0f);
3145 }
3146
3147 tickCountFrameRun = Util.EnvironmentTickCount();
3148 }
3149
3150 return fps;
3151 }
3152
3153 public override void GetResults()
3154 {
3155 }
3156
3157 public override bool IsThreaded
3158 {
3159 // for now we won't be multithreaded
3160 get { return (false); }
3161 }
3162
3163 #region ODE Specific Terrain Fixes
3164 public float[] ResizeTerrain512NearestNeighbour(float[] heightMap)
3165 {
3166 float[] returnarr = new float[262144];
3167 float[,] resultarr = new float[(int)WorldExtents.X, (int)WorldExtents.Y];
3168
3169 // Filling out the array into its multi-dimensional components
3170 for (int y = 0; y < WorldExtents.Y; y++)
3171 {
3172 for (int x = 0; x < WorldExtents.X; x++)
3173 {
3174 resultarr[y, x] = heightMap[y * (int)WorldExtents.Y + x];
3175 }
3176 }
3177
3178 // Resize using Nearest Neighbour
3179
3180 // This particular way is quick but it only works on a multiple of the original
3181
3182 // The idea behind this method can be described with the following diagrams
3183 // second pass and third pass happen in the same loop really.. just separated
3184 // them to show what this does.
3185
3186 // First Pass
3187 // ResultArr:
3188 // 1,1,1,1,1,1
3189 // 1,1,1,1,1,1
3190 // 1,1,1,1,1,1
3191 // 1,1,1,1,1,1
3192 // 1,1,1,1,1,1
3193 // 1,1,1,1,1,1
3194
3195 // Second Pass
3196 // ResultArr2:
3197 // 1,,1,,1,,1,,1,,1,
3198 // ,,,,,,,,,,
3199 // 1,,1,,1,,1,,1,,1,
3200 // ,,,,,,,,,,
3201 // 1,,1,,1,,1,,1,,1,
3202 // ,,,,,,,,,,
3203 // 1,,1,,1,,1,,1,,1,
3204 // ,,,,,,,,,,
3205 // 1,,1,,1,,1,,1,,1,
3206 // ,,,,,,,,,,
3207 // 1,,1,,1,,1,,1,,1,
3208
3209 // Third pass fills in the blanks
3210 // ResultArr2:
3211 // 1,1,1,1,1,1,1,1,1,1,1,1
3212 // 1,1,1,1,1,1,1,1,1,1,1,1
3213 // 1,1,1,1,1,1,1,1,1,1,1,1
3214 // 1,1,1,1,1,1,1,1,1,1,1,1
3215 // 1,1,1,1,1,1,1,1,1,1,1,1
3216 // 1,1,1,1,1,1,1,1,1,1,1,1
3217 // 1,1,1,1,1,1,1,1,1,1,1,1
3218 // 1,1,1,1,1,1,1,1,1,1,1,1
3219 // 1,1,1,1,1,1,1,1,1,1,1,1
3220 // 1,1,1,1,1,1,1,1,1,1,1,1
3221 // 1,1,1,1,1,1,1,1,1,1,1,1
3222
3223 // X,Y = .
3224 // X+1,y = ^
3225 // X,Y+1 = *
3226 // X+1,Y+1 = #
3227
3228 // Filling in like this;
3229 // .*
3230 // ^#
3231 // 1st .
3232 // 2nd *
3233 // 3rd ^
3234 // 4th #
3235 // on single loop.
3236
3237 float[,] resultarr2 = new float[512, 512];
3238 for (int y = 0; y < WorldExtents.Y; y++)
3239 {
3240 for (int x = 0; x < WorldExtents.X; x++)
3241 {
3242 resultarr2[y * 2, x * 2] = resultarr[y, x];
3243
3244 if (y < WorldExtents.Y)
3245 {
3246 resultarr2[(y * 2) + 1, x * 2] = resultarr[y, x];
3247 }
3248 if (x < WorldExtents.X)
3249 {
3250 resultarr2[y * 2, (x * 2) + 1] = resultarr[y, x];
3251 }
3252 if (x < WorldExtents.X && y < WorldExtents.Y)
3253 {
3254 resultarr2[(y * 2) + 1, (x * 2) + 1] = resultarr[y, x];
3255 }
3256 }
3257 }
3258
3259 //Flatten out the array
3260 int i = 0;
3261 for (int y = 0; y < 512; y++)
3262 {
3263 for (int x = 0; x < 512; x++)
3264 {
3265 if (resultarr2[y, x] <= 0)
3266 returnarr[i] = 0.0000001f;
3267 else
3268 returnarr[i] = resultarr2[y, x];
3269
3270 i++;
3271 }
3272 }
3273
3274 return returnarr;
3275 }
3276
3277 public float[] ResizeTerrain512Interpolation(float[] heightMap)
3278 {
3279 float[] returnarr = new float[262144];
3280 float[,] resultarr = new float[512,512];
3281
3282 // Filling out the array into its multi-dimensional components
3283 for (int y = 0; y < 256; y++)
3284 {
3285 for (int x = 0; x < 256; x++)
3286 {
3287 resultarr[y, x] = heightMap[y * 256 + x];
3288 }
3289 }
3290
3291 // Resize using interpolation
3292
3293 // This particular way is quick but it only works on a multiple of the original
3294
3295 // The idea behind this method can be described with the following diagrams
3296 // second pass and third pass happen in the same loop really.. just separated
3297 // them to show what this does.
3298
3299 // First Pass
3300 // ResultArr:
3301 // 1,1,1,1,1,1
3302 // 1,1,1,1,1,1
3303 // 1,1,1,1,1,1
3304 // 1,1,1,1,1,1
3305 // 1,1,1,1,1,1
3306 // 1,1,1,1,1,1
3307
3308 // Second Pass
3309 // ResultArr2:
3310 // 1,,1,,1,,1,,1,,1,
3311 // ,,,,,,,,,,
3312 // 1,,1,,1,,1,,1,,1,
3313 // ,,,,,,,,,,
3314 // 1,,1,,1,,1,,1,,1,
3315 // ,,,,,,,,,,
3316 // 1,,1,,1,,1,,1,,1,
3317 // ,,,,,,,,,,
3318 // 1,,1,,1,,1,,1,,1,
3319 // ,,,,,,,,,,
3320 // 1,,1,,1,,1,,1,,1,
3321
3322 // Third pass fills in the blanks
3323 // ResultArr2:
3324 // 1,1,1,1,1,1,1,1,1,1,1,1
3325 // 1,1,1,1,1,1,1,1,1,1,1,1
3326 // 1,1,1,1,1,1,1,1,1,1,1,1
3327 // 1,1,1,1,1,1,1,1,1,1,1,1
3328 // 1,1,1,1,1,1,1,1,1,1,1,1
3329 // 1,1,1,1,1,1,1,1,1,1,1,1
3330 // 1,1,1,1,1,1,1,1,1,1,1,1
3331 // 1,1,1,1,1,1,1,1,1,1,1,1
3332 // 1,1,1,1,1,1,1,1,1,1,1,1
3333 // 1,1,1,1,1,1,1,1,1,1,1,1
3334 // 1,1,1,1,1,1,1,1,1,1,1,1
3335
3336 // X,Y = .
3337 // X+1,y = ^
3338 // X,Y+1 = *
3339 // X+1,Y+1 = #
3340
3341 // Filling in like this;
3342 // .*
3343 // ^#
3344 // 1st .
3345 // 2nd *
3346 // 3rd ^
3347 // 4th #
3348 // on single loop.
3349
3350 float[,] resultarr2 = new float[512,512];
3351 for (int y = 0; y < (int)Constants.RegionSize; y++)
3352 {
3353 for (int x = 0; x < (int)Constants.RegionSize; x++)
3354 {
3355 resultarr2[y*2, x*2] = resultarr[y, x];
3356
3357 if (y < (int)Constants.RegionSize)
3358 {
3359 if (y + 1 < (int)Constants.RegionSize)
3360 {
3361 if (x + 1 < (int)Constants.RegionSize)
3362 {
3363 resultarr2[(y*2) + 1, x*2] = ((resultarr[y, x] + resultarr[y + 1, x] +
3364 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3365 }
3366 else
3367 {
3368 resultarr2[(y*2) + 1, x*2] = ((resultarr[y, x] + resultarr[y + 1, x])/2);
3369 }
3370 }
3371 else
3372 {
3373 resultarr2[(y*2) + 1, x*2] = resultarr[y, x];
3374 }
3375 }
3376 if (x < (int)Constants.RegionSize)
3377 {
3378 if (x + 1 < (int)Constants.RegionSize)
3379 {
3380 if (y + 1 < (int)Constants.RegionSize)
3381 {
3382 resultarr2[y*2, (x*2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] +
3383 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3384 }
3385 else
3386 {
3387 resultarr2[y*2, (x*2) + 1] = ((resultarr[y, x] + resultarr[y, x + 1])/2);
3388 }
3389 }
3390 else
3391 {
3392 resultarr2[y*2, (x*2) + 1] = resultarr[y, x];
3393 }
3394 }
3395 if (x < (int)Constants.RegionSize && y < (int)Constants.RegionSize)
3396 {
3397 if ((x + 1 < (int)Constants.RegionSize) && (y + 1 < (int)Constants.RegionSize))
3398 {
3399 resultarr2[(y*2) + 1, (x*2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] +
3400 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3401 }
3402 else
3403 {
3404 resultarr2[(y*2) + 1, (x*2) + 1] = resultarr[y, x];
3405 }
3406 }
3407 }
3408 }
3409 //Flatten out the array
3410 int i = 0;
3411 for (int y = 0; y < 512; y++)
3412 {
3413 for (int x = 0; x < 512; x++)
3414 {
3415 if (Single.IsNaN(resultarr2[y, x]) || Single.IsInfinity(resultarr2[y, x]))
3416 {
3417 m_log.Warn("[PHYSICS]: Non finite heightfield element detected. Setting it to 0");
3418 resultarr2[y, x] = 0;
3419 }
3420 returnarr[i] = resultarr2[y, x];
3421 i++;
3422 }
3423 }
3424
3425 return returnarr;
3426 }
3427
3428 #endregion
3429
3430 public override void SetTerrain(float[] heightMap)
3431 {
3432 if (m_worldOffset != Vector3.Zero && m_parentScene != null)
3433 {
3434 if (m_parentScene is OdeScene)
3435 {
3436 ((OdeScene)m_parentScene).SetTerrain(heightMap, m_worldOffset);
3437 }
3438 }
3439 else
3440 {
3441 SetTerrain(heightMap, m_worldOffset);
3442 }
3443 }
3444
3445 public void SetTerrain(float[] heightMap, Vector3 pOffset)
3446 {
3447 // this._heightmap[i] = (double)heightMap[i];
3448 // dbm (danx0r) -- creating a buffer zone of one extra sample all around
3449 //_origheightmap = heightMap;
3450
3451 float[] _heightmap;
3452
3453 // zero out a heightmap array float array (single dimension [flattened]))
3454 //if ((int)Constants.RegionSize == 256)
3455 // _heightmap = new float[514 * 514];
3456 //else
3457
3458 _heightmap = new float[(((int)Constants.RegionSize + 2) * ((int)Constants.RegionSize + 2))];
3459
3460 uint heightmapWidth = Constants.RegionSize + 1;
3461 uint heightmapHeight = Constants.RegionSize + 1;
3462
3463 uint heightmapWidthSamples;
3464
3465 uint heightmapHeightSamples;
3466
3467 //if (((int)Constants.RegionSize) == 256)
3468 //{
3469 // heightmapWidthSamples = 2 * (uint)Constants.RegionSize + 2;
3470 // heightmapHeightSamples = 2 * (uint)Constants.RegionSize + 2;
3471 // heightmapWidth++;
3472 // heightmapHeight++;
3473 //}
3474 //else
3475 //{
3476
3477 heightmapWidthSamples = (uint)Constants.RegionSize + 1;
3478 heightmapHeightSamples = (uint)Constants.RegionSize + 1;
3479 //}
3480
3481 const float scale = 1.0f;
3482 const float offset = 0.0f;
3483 const float thickness = 0.2f;
3484 const int wrap = 0;
3485
3486 int regionsize = (int) Constants.RegionSize + 2;
3487 //Double resolution
3488 //if (((int)Constants.RegionSize) == 256)
3489 // heightMap = ResizeTerrain512Interpolation(heightMap);
3490
3491
3492 // if (((int)Constants.RegionSize) == 256 && (int)Constants.RegionSize == 256)
3493 // regionsize = 512;
3494
3495 float hfmin = 2000;
3496 float hfmax = -2000;
3497
3498 for (int x = 0; x < heightmapWidthSamples; x++)
3499 {
3500 for (int y = 0; y < heightmapHeightSamples; y++)
3501 {
3502 int xx = Util.Clip(x - 1, 0, regionsize - 1);
3503 int yy = Util.Clip(y - 1, 0, regionsize - 1);
3504
3505
3506 float val= heightMap[yy * (int)Constants.RegionSize + xx];
3507 _heightmap[x * ((int)Constants.RegionSize + 2) + y] = val;
3508
3509 hfmin = (val < hfmin) ? val : hfmin;
3510 hfmax = (val > hfmax) ? val : hfmax;
3511 }
3512 }
3513
3514
3515
3516
3517 lock (OdeLock)
3518 {
3519 IntPtr GroundGeom = IntPtr.Zero;
3520 if (RegionTerrain.TryGetValue(pOffset, out GroundGeom))
3521 {
3522 RegionTerrain.Remove(pOffset);
3523 if (GroundGeom != IntPtr.Zero)
3524 {
3525 if (TerrainHeightFieldHeights.ContainsKey(GroundGeom))
3526 {
3527 TerrainHeightFieldHeights.Remove(GroundGeom);
3528 }
3529 d.SpaceRemove(space, GroundGeom);
3530 d.GeomDestroy(GroundGeom);
3531 }
3532
3533 }
3534 IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
3535 d.GeomHeightfieldDataBuildSingle(HeightmapData, _heightmap, 0, heightmapWidth + 1, heightmapHeight + 1,
3536 (int)heightmapWidthSamples + 1, (int)heightmapHeightSamples + 1, scale,
3537 offset, thickness, wrap);
3538 d.GeomHeightfieldDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1);
3539 GroundGeom = d.CreateHeightfield(space, HeightmapData, 1);
3540 if (GroundGeom != IntPtr.Zero)
3541 {
3542 d.GeomSetCategoryBits(GroundGeom, (int)(CollisionCategories.Land));
3543 d.GeomSetCollideBits(GroundGeom, (int)(CollisionCategories.Space));
3544
3545 }
3546 geom_name_map[GroundGeom] = "Terrain";
3547
3548 d.Matrix3 R = new d.Matrix3();
3549
3550 Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f);
3551 Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f);
3552 //Axiom.Math.Quaternion q3 = Axiom.Math.Quaternion.FromAngleAxis(3.14f, new Axiom.Math.Vector3(0, 0, 1));
3553
3554 q1 = q1 * q2;
3555 //q1 = q1 * q3;
3556 Vector3 v3;
3557 float angle;
3558 q1.GetAxisAngle(out v3, out angle);
3559
3560 d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle);
3561 d.GeomSetRotation(GroundGeom, ref R);
3562 d.GeomSetPosition(GroundGeom, (pOffset.X + ((int)Constants.RegionSize * 0.5f)) - 1, (pOffset.Y + ((int)Constants.RegionSize * 0.5f)) - 1, 0);
3563 IntPtr testGround = IntPtr.Zero;
3564 if (RegionTerrain.TryGetValue(pOffset, out testGround))
3565 {
3566 RegionTerrain.Remove(pOffset);
3567 }
3568 RegionTerrain.Add(pOffset, GroundGeom, GroundGeom);
3569 TerrainHeightFieldHeights.Add(GroundGeom,_heightmap);
3570
3571 }
3572 }
3573
3574 public override void DeleteTerrain()
3575 {
3576 }
3577
3578 public float GetWaterLevel()
3579 {
3580 return waterlevel;
3581 }
3582
3583 public override bool SupportsCombining()
3584 {
3585 return true;
3586 }
3587
3588 public override void UnCombine(PhysicsScene pScene)
3589 {
3590 IntPtr localGround = IntPtr.Zero;
3591// float[] localHeightfield;
3592 bool proceed = false;
3593 List<IntPtr> geomDestroyList = new List<IntPtr>();
3594
3595 lock (OdeLock)
3596 {
3597 if (RegionTerrain.TryGetValue(Vector3.Zero, out localGround))
3598 {
3599 foreach (IntPtr geom in TerrainHeightFieldHeights.Keys)
3600 {
3601 if (geom == localGround)
3602 {
3603// localHeightfield = TerrainHeightFieldHeights[geom];
3604 proceed = true;
3605 }
3606 else
3607 {
3608 geomDestroyList.Add(geom);
3609 }
3610 }
3611
3612 if (proceed)
3613 {
3614 m_worldOffset = Vector3.Zero;
3615 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize);
3616 m_parentScene = null;
3617
3618 foreach (IntPtr g in geomDestroyList)
3619 {
3620 // removingHeightField needs to be done or the garbage collector will
3621 // collect the terrain data before we tell ODE to destroy it causing
3622 // memory corruption
3623 if (TerrainHeightFieldHeights.ContainsKey(g))
3624 {
3625// float[] removingHeightField = TerrainHeightFieldHeights[g];
3626 TerrainHeightFieldHeights.Remove(g);
3627
3628 if (RegionTerrain.ContainsKey(g))
3629 {
3630 RegionTerrain.Remove(g);
3631 }
3632
3633 d.GeomDestroy(g);
3634 //removingHeightField = new float[0];
3635 }
3636 }
3637
3638 }
3639 else
3640 {
3641 m_log.Warn("[PHYSICS]: Couldn't proceed with UnCombine. Region has inconsistant data.");
3642
3643 }
3644 }
3645 }
3646 }
3647
3648 public override void SetWaterLevel(float baseheight)
3649 {
3650 waterlevel = baseheight;
3651 randomizeWater(waterlevel);
3652 }
3653
3654 public void randomizeWater(float baseheight)
3655 {
3656 const uint heightmapWidth = m_regionWidth + 2;
3657 const uint heightmapHeight = m_regionHeight + 2;
3658 const uint heightmapWidthSamples = m_regionWidth + 2;
3659 const uint heightmapHeightSamples = m_regionHeight + 2;
3660 const float scale = 1.0f;
3661 const float offset = 0.0f;
3662 const float thickness = 2.9f;
3663 const int wrap = 0;
3664
3665 for (int i = 0; i < (258 * 258); i++)
3666 {
3667 _watermap[i] = (baseheight-0.1f) + ((float)fluidRandomizer.Next(1,9) / 10f);
3668 // m_log.Info((baseheight - 0.1f) + ((float)fluidRandomizer.Next(1, 9) / 10f));
3669 }
3670
3671 lock (OdeLock)
3672 {
3673 if (WaterGeom != IntPtr.Zero)
3674 {
3675 d.SpaceRemove(space, WaterGeom);
3676 }
3677 IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
3678 d.GeomHeightfieldDataBuildSingle(HeightmapData, _watermap, 0, heightmapWidth, heightmapHeight,
3679 (int)heightmapWidthSamples, (int)heightmapHeightSamples, scale,
3680 offset, thickness, wrap);
3681 d.GeomHeightfieldDataSetBounds(HeightmapData, m_regionWidth, m_regionHeight);
3682 WaterGeom = d.CreateHeightfield(space, HeightmapData, 1);
3683 if (WaterGeom != IntPtr.Zero)
3684 {
3685 d.GeomSetCategoryBits(WaterGeom, (int)(CollisionCategories.Water));
3686 d.GeomSetCollideBits(WaterGeom, (int)(CollisionCategories.Space));
3687
3688 }
3689 geom_name_map[WaterGeom] = "Water";
3690
3691 d.Matrix3 R = new d.Matrix3();
3692
3693 Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f);
3694 Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f);
3695 //Axiom.Math.Quaternion q3 = Axiom.Math.Quaternion.FromAngleAxis(3.14f, new Axiom.Math.Vector3(0, 0, 1));
3696
3697 q1 = q1 * q2;
3698 //q1 = q1 * q3;
3699 Vector3 v3;
3700 float angle;
3701 q1.GetAxisAngle(out v3, out angle);
3702
3703 d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle);
3704 d.GeomSetRotation(WaterGeom, ref R);
3705 d.GeomSetPosition(WaterGeom, 128, 128, 0);
3706
3707 }
3708
3709 }
3710
3711 public override void Dispose()
3712 {
3713 m_rayCastManager.Dispose();
3714 m_rayCastManager = null;
3715
3716 lock (OdeLock)
3717 {
3718 lock (_prims)
3719 {
3720 foreach (OdePrim prm in _prims)
3721 {
3722 RemovePrim(prm);
3723 }
3724 }
3725
3726 //foreach (OdeCharacter act in _characters)
3727 //{
3728 //RemoveAvatar(act);
3729 //}
3730 d.WorldDestroy(world);
3731 //d.CloseODE();
3732 }
3733 }
3734 public override Dictionary<uint, float> GetTopColliders()
3735 {
3736 Dictionary<uint, float> returncolliders = new Dictionary<uint, float>();
3737 int cnt = 0;
3738 lock (_prims)
3739 {
3740 foreach (OdePrim prm in _prims)
3741 {
3742 if (prm.CollisionScore > 0)
3743 {
3744 returncolliders.Add(prm.m_localID, prm.CollisionScore);
3745 cnt++;
3746 prm.CollisionScore = 0f;
3747 if (cnt > 25)
3748 {
3749 break;
3750 }
3751 }
3752 }
3753 }
3754 return returncolliders;
3755 }
3756
3757 public override bool SupportsRayCast()
3758 {
3759 return true;
3760 }
3761
3762 public override void RaycastWorld(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
3763 {
3764 if (retMethod != null)
3765 {
3766 m_rayCastManager.QueueRequest(position, direction, length, retMethod);
3767 }
3768 }
3769
3770#if USE_DRAWSTUFF
3771 // Keyboard callback
3772 public void command(int cmd)
3773 {
3774 IntPtr geom;
3775 d.Mass mass;
3776 d.Vector3 sides = new d.Vector3(d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f);
3777
3778
3779
3780 Char ch = Char.ToLower((Char)cmd);
3781 switch ((Char)ch)
3782 {
3783 case 'w':
3784 try
3785 {
3786 Vector3 rotate = (new Vector3(1, 0, 0) * Quaternion.CreateFromEulers(hpr.Z * Utils.DEG_TO_RAD, hpr.Y * Utils.DEG_TO_RAD, hpr.X * Utils.DEG_TO_RAD));
3787
3788 xyz.X += rotate.X; xyz.Y += rotate.Y; xyz.Z += rotate.Z;
3789 ds.SetViewpoint(ref xyz, ref hpr);
3790 }
3791 catch (ArgumentException)
3792 { hpr.X = 0; }
3793 break;
3794
3795 case 'a':
3796 hpr.X++;
3797 ds.SetViewpoint(ref xyz, ref hpr);
3798 break;
3799
3800 case 's':
3801 try
3802 {
3803 Vector3 rotate2 = (new Vector3(-1, 0, 0) * Quaternion.CreateFromEulers(hpr.Z * Utils.DEG_TO_RAD, hpr.Y * Utils.DEG_TO_RAD, hpr.X * Utils.DEG_TO_RAD));
3804
3805 xyz.X += rotate2.X; xyz.Y += rotate2.Y; xyz.Z += rotate2.Z;
3806 ds.SetViewpoint(ref xyz, ref hpr);
3807 }
3808 catch (ArgumentException)
3809 { hpr.X = 0; }
3810 break;
3811 case 'd':
3812 hpr.X--;
3813 ds.SetViewpoint(ref xyz, ref hpr);
3814 break;
3815 case 'r':
3816 xyz.Z++;
3817 ds.SetViewpoint(ref xyz, ref hpr);
3818 break;
3819 case 'f':
3820 xyz.Z--;
3821 ds.SetViewpoint(ref xyz, ref hpr);
3822 break;
3823 case 'e':
3824 xyz.Y++;
3825 ds.SetViewpoint(ref xyz, ref hpr);
3826 break;
3827 case 'q':
3828 xyz.Y--;
3829 ds.SetViewpoint(ref xyz, ref hpr);
3830 break;
3831 }
3832 }
3833
3834 public void step(int pause)
3835 {
3836
3837 ds.SetColor(1.0f, 1.0f, 0.0f);
3838 ds.SetTexture(ds.Texture.Wood);
3839 lock (_prims)
3840 {
3841 foreach (OdePrim prm in _prims)
3842 {
3843 //IntPtr body = d.GeomGetBody(prm.prim_geom);
3844 if (prm.prim_geom != IntPtr.Zero)
3845 {
3846 d.Vector3 pos;
3847 d.GeomCopyPosition(prm.prim_geom, out pos);
3848 //d.BodyCopyPosition(body, out pos);
3849
3850 d.Matrix3 R;
3851 d.GeomCopyRotation(prm.prim_geom, out R);
3852 //d.BodyCopyRotation(body, out R);
3853
3854
3855 d.Vector3 sides = new d.Vector3();
3856 sides.X = prm.Size.X;
3857 sides.Y = prm.Size.Y;
3858 sides.Z = prm.Size.Z;
3859
3860 ds.DrawBox(ref pos, ref R, ref sides);
3861 }
3862 }
3863 }
3864 ds.SetColor(1.0f, 0.0f, 0.0f);
3865 lock (_characters)
3866 {
3867 foreach (OdeCharacter chr in _characters)
3868 {
3869 if (chr.Shell != IntPtr.Zero)
3870 {
3871 IntPtr body = d.GeomGetBody(chr.Shell);
3872
3873 d.Vector3 pos;
3874 d.GeomCopyPosition(chr.Shell, out pos);
3875 //d.BodyCopyPosition(body, out pos);
3876
3877 d.Matrix3 R;
3878 d.GeomCopyRotation(chr.Shell, out R);
3879 //d.BodyCopyRotation(body, out R);
3880
3881 ds.DrawCapsule(ref pos, ref R, chr.Size.Z, 0.35f);
3882 d.Vector3 sides = new d.Vector3();
3883 sides.X = 0.5f;
3884 sides.Y = 0.5f;
3885 sides.Z = 0.5f;
3886
3887 ds.DrawBox(ref pos, ref R, ref sides);
3888 }
3889 }
3890 }
3891 }
3892
3893 public void start(int unused)
3894 {
3895 ds.SetViewpoint(ref xyz, ref hpr);
3896 }
3897#endif
3898 }
3899}
diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
new file mode 100644
index 0000000..99392cc
--- /dev/null
+++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
@@ -0,0 +1,3865 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28//#define USE_DRAWSTUFF
29//#define SPAM
30
31using System;
32using System.Collections.Generic;
33using System.Reflection;
34using System.Runtime.InteropServices;
35using System.Threading;
36using System.IO;
37using System.Diagnostics;
38using log4net;
39using Nini.Config;
40using Ode.NET;
41#if USE_DRAWSTUFF
42using Drawstuff.NET;
43#endif
44using OpenSim.Framework;
45using OpenSim.Region.Physics.Manager;
46using OpenMetaverse;
47
48namespace OpenSim.Region.Physics.OdePlugin
49{
50 public enum StatusIndicators : int
51 {
52 Generic = 0,
53 Start = 1,
54 End = 2
55 }
56
57 public struct sCollisionData
58 {
59 public uint ColliderLocalId;
60 public uint CollidedWithLocalId;
61 public int NumberOfCollisions;
62 public int CollisionType;
63 public int StatusIndicator;
64 public int lastframe;
65 }
66
67 [Flags]
68 public enum CollisionCategories : int
69 {
70 Disabled = 0,
71 Geom = 0x00000001,
72 Body = 0x00000002,
73 Space = 0x00000004,
74 Character = 0x00000008,
75 Land = 0x00000010,
76 Water = 0x00000020,
77 Wind = 0x00000040,
78 Sensor = 0x00000080,
79 Selected = 0x00000100
80 }
81
82 /// <summary>
83 /// Material type for a primitive
84 /// </summary>
85 public enum Material : int
86 {
87 /// <summary></summary>
88 Stone = 0,
89 /// <summary></summary>
90 Metal = 1,
91 /// <summary></summary>
92 Glass = 2,
93 /// <summary></summary>
94 Wood = 3,
95 /// <summary></summary>
96 Flesh = 4,
97 /// <summary></summary>
98 Plastic = 5,
99 /// <summary></summary>
100 Rubber = 6
101 }
102
103 public sealed class OdeScene : PhysicsScene
104 {
105 private readonly ILog m_log;
106 // private Dictionary<string, sCollisionData> m_storedCollisions = new Dictionary<string, sCollisionData>();
107
108 CollisionLocker ode;
109
110 private Random fluidRandomizer = new Random(Environment.TickCount);
111
112 private const uint m_regionWidth = Constants.RegionSize;
113 private const uint m_regionHeight = Constants.RegionSize;
114
115 private float ODE_STEPSIZE = 0.020f;
116 private float metersInSpace = 29.9f;
117 private float m_timeDilation = 1.0f;
118
119 public float gravityx = 0f;
120 public float gravityy = 0f;
121 public float gravityz = -9.8f;
122
123 private float contactsurfacelayer = 0.001f;
124
125 private int worldHashspaceLow = -4;
126 private int worldHashspaceHigh = 128;
127
128 private int smallHashspaceLow = -4;
129 private int smallHashspaceHigh = 66;
130
131 private float waterlevel = 0f;
132 private int framecount = 0;
133 //private int m_returncollisions = 10;
134
135 private readonly IntPtr contactgroup;
136
137 internal IntPtr LandGeom;
138 internal IntPtr WaterGeom;
139
140 private float nmTerrainContactFriction = 255.0f;
141 private float nmTerrainContactBounce = 0.1f;
142 private float nmTerrainContactERP = 0.1025f;
143
144 private float mTerrainContactFriction = 75f;
145 private float mTerrainContactBounce = 0.1f;
146 private float mTerrainContactERP = 0.05025f;
147
148 private float nmAvatarObjectContactFriction = 250f;
149 private float nmAvatarObjectContactBounce = 0.1f;
150
151 private float mAvatarObjectContactFriction = 75f;
152 private float mAvatarObjectContactBounce = 0.1f;
153
154 private float avPIDD = 3200f;
155 private float avPIDP = 1400f;
156 private float avCapRadius = 0.37f;
157 private float avStandupTensor = 2000000f;
158 private bool avCapsuleTilted = true; // true = old compatibility mode with leaning capsule; false = new corrected mode
159 public bool IsAvCapsuleTilted { get { return avCapsuleTilted; } set { avCapsuleTilted = value; } }
160 private float avDensity = 80f;
161 private float avHeightFudgeFactor = 0.52f;
162 private float avMovementDivisorWalk = 1.3f;
163 private float avMovementDivisorRun = 0.8f;
164 private float minimumGroundFlightOffset = 3f;
165 public float maximumMassObject = 10000.01f;
166
167 public bool meshSculptedPrim = true;
168 public bool forceSimplePrimMeshing = false;
169
170 public float meshSculptLOD = 32;
171 public float MeshSculptphysicalLOD = 16;
172
173 public float geomDefaultDensity = 10.000006836f;
174
175 public int geomContactPointsStartthrottle = 3;
176 public int geomUpdatesPerThrottledUpdate = 15;
177
178 public float bodyPIDD = 35f;
179 public float bodyPIDG = 25;
180
181 public int geomCrossingFailuresBeforeOutofbounds = 5;
182
183 public float bodyMotorJointMaxforceTensor = 2;
184
185 public int bodyFramesAutoDisable = 20;
186
187 private float[] _watermap;
188 private bool m_filterCollisions = true;
189
190 private d.NearCallback nearCallback;
191 public d.TriCallback triCallback;
192 public d.TriArrayCallback triArrayCallback;
193 private readonly HashSet<OdeCharacter> _characters = new HashSet<OdeCharacter>();
194 private readonly HashSet<OdePrim> _prims = new HashSet<OdePrim>();
195 private readonly HashSet<OdePrim> _activeprims = new HashSet<OdePrim>();
196 private readonly HashSet<OdePrim> _taintedPrimH = new HashSet<OdePrim>();
197 private readonly Object _taintedPrimLock = new Object();
198 private readonly List<OdePrim> _taintedPrimL = new List<OdePrim>();
199 private readonly HashSet<OdeCharacter> _taintedActors = new HashSet<OdeCharacter>();
200 private readonly List<d.ContactGeom> _perloopContact = new List<d.ContactGeom>();
201 private readonly List<PhysicsActor> _collisionEventPrim = new List<PhysicsActor>();
202 private readonly HashSet<OdeCharacter> _badCharacter = new HashSet<OdeCharacter>();
203 public Dictionary<IntPtr, String> geom_name_map = new Dictionary<IntPtr, String>();
204 public Dictionary<IntPtr, PhysicsActor> actor_name_map = new Dictionary<IntPtr, PhysicsActor>();
205 private bool m_NINJA_physics_joints_enabled = false;
206 //private Dictionary<String, IntPtr> jointpart_name_map = new Dictionary<String,IntPtr>();
207 private readonly Dictionary<String, List<PhysicsJoint>> joints_connecting_actor = new Dictionary<String, List<PhysicsJoint>>();
208 private d.ContactGeom[] contacts;
209 private readonly List<PhysicsJoint> requestedJointsToBeCreated = new List<PhysicsJoint>(); // lock only briefly. accessed by external code (to request new joints) and by OdeScene.Simulate() to move those joints into pending/active
210 private readonly List<PhysicsJoint> pendingJoints = new List<PhysicsJoint>(); // can lock for longer. accessed only by OdeScene.
211 private readonly List<PhysicsJoint> activeJoints = new List<PhysicsJoint>(); // can lock for longer. accessed only by OdeScene.
212 private readonly List<string> requestedJointsToBeDeleted = new List<string>(); // lock only briefly. accessed by external code (to request deletion of joints) and by OdeScene.Simulate() to move those joints out of pending/active
213 private Object externalJointRequestsLock = new Object();
214 private readonly Dictionary<String, PhysicsJoint> SOPName_to_activeJoint = new Dictionary<String, PhysicsJoint>();
215 private readonly Dictionary<String, PhysicsJoint> SOPName_to_pendingJoint = new Dictionary<String, PhysicsJoint>();
216 private readonly DoubleDictionary<Vector3, IntPtr, IntPtr> RegionTerrain = new DoubleDictionary<Vector3, IntPtr, IntPtr>();
217 private readonly Dictionary<IntPtr,float[]> TerrainHeightFieldHeights = new Dictionary<IntPtr, float[]>();
218
219 private d.Contact contact;
220 private d.Contact TerrainContact;
221 private d.Contact AvatarMovementprimContact;
222 private d.Contact AvatarMovementTerrainContact;
223 private d.Contact WaterContact;
224 private d.Contact[,] m_materialContacts;
225
226//Ckrinke: Comment out until used. We declare it, initialize it, but do not use it
227//Ckrinke private int m_randomizeWater = 200;
228 private int m_physicsiterations = 10;
229 private const float m_SkipFramesAtms = 0.40f; // Drop frames gracefully at a 400 ms lag
230 private readonly PhysicsActor PANull = new NullPhysicsActor();
231 private float step_time = 0.0f;
232//Ckrinke: Comment out until used. We declare it, initialize it, but do not use it
233//Ckrinke private int ms = 0;
234 public IntPtr world;
235 //private bool returncollisions = false;
236 // private uint obj1LocalID = 0;
237 private uint obj2LocalID = 0;
238 //private int ctype = 0;
239 private OdeCharacter cc1;
240 private OdePrim cp1;
241 private OdeCharacter cc2;
242 private OdePrim cp2;
243 private int tickCountFrameRun;
244
245 private int latertickcount=0;
246 //private int cStartStop = 0;
247 //private string cDictKey = "";
248
249 public IntPtr space;
250
251 //private IntPtr tmpSpace;
252 // split static geometry collision handling into spaces of 30 meters
253 public IntPtr[,] staticPrimspace;
254
255 public Object OdeLock;
256
257 public IMesher mesher;
258
259 private IConfigSource m_config;
260
261 public bool physics_logging = false;
262 public int physics_logging_interval = 0;
263 public bool physics_logging_append_existing_logfile = false;
264
265 public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f);
266 public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f);
267
268 // TODO: unused: private uint heightmapWidth = m_regionWidth + 1;
269 // TODO: unused: private uint heightmapHeight = m_regionHeight + 1;
270 // TODO: unused: private uint heightmapWidthSamples;
271 // TODO: unused: private uint heightmapHeightSamples;
272
273 private volatile int m_global_contactcount = 0;
274
275 private Vector3 m_worldOffset = Vector3.Zero;
276 public Vector2 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize);
277 private PhysicsScene m_parentScene = null;
278
279 private ODERayCastRequestManager m_rayCastManager;
280
281 /// <summary>
282 /// Initiailizes the scene
283 /// Sets many properties that ODE requires to be stable
284 /// These settings need to be tweaked 'exactly' right or weird stuff happens.
285 /// </summary>
286 public OdeScene(CollisionLocker dode, string sceneIdentifier)
287 {
288 m_log
289 = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.ToString() + "." + sceneIdentifier);
290
291 OdeLock = new Object();
292 ode = dode;
293 nearCallback = near;
294 triCallback = TriCallback;
295 triArrayCallback = TriArrayCallback;
296 m_rayCastManager = new ODERayCastRequestManager(this);
297 lock (OdeLock)
298 {
299 // Create the world and the first space
300 world = d.WorldCreate();
301 space = d.HashSpaceCreate(IntPtr.Zero);
302
303
304 contactgroup = d.JointGroupCreate(0);
305 //contactgroup
306
307 d.WorldSetAutoDisableFlag(world, false);
308 #if USE_DRAWSTUFF
309
310 Thread viewthread = new Thread(new ParameterizedThreadStart(startvisualization));
311 viewthread.Start();
312 #endif
313 }
314
315 _watermap = new float[258 * 258];
316
317 // Zero out the prim spaces array (we split our space into smaller spaces so
318 // we can hit test less.
319 }
320
321#if USE_DRAWSTUFF
322 public void startvisualization(object o)
323 {
324 ds.Functions fn;
325 fn.version = ds.VERSION;
326 fn.start = new ds.CallbackFunction(start);
327 fn.step = new ds.CallbackFunction(step);
328 fn.command = new ds.CallbackFunction(command);
329 fn.stop = null;
330 fn.path_to_textures = "./textures";
331 string[] args = new string[0];
332 ds.SimulationLoop(args.Length, args, 352, 288, ref fn);
333 }
334#endif
335
336 // Initialize the mesh plugin
337 public override void Initialise(IMesher meshmerizer, IConfigSource config)
338 {
339 mesher = meshmerizer;
340 m_config = config;
341 // Defaults
342
343 if (Environment.OSVersion.Platform == PlatformID.Unix)
344 {
345 avPIDD = 3200.0f;
346 avPIDP = 1400.0f;
347 avStandupTensor = 2000000f;
348 }
349 else
350 {
351 avPIDD = 2200.0f;
352 avPIDP = 900.0f;
353 avStandupTensor = 550000f;
354 }
355
356 int contactsPerCollision = 80;
357
358 if (m_config != null)
359 {
360 IConfig physicsconfig = m_config.Configs["ODEPhysicsSettings"];
361 if (physicsconfig != null)
362 {
363 gravityx = physicsconfig.GetFloat("world_gravityx", 0f);
364 gravityy = physicsconfig.GetFloat("world_gravityy", 0f);
365 gravityz = physicsconfig.GetFloat("world_gravityz", -9.8f);
366
367 worldHashspaceLow = physicsconfig.GetInt("world_hashspace_size_low", -4);
368 worldHashspaceHigh = physicsconfig.GetInt("world_hashspace_size_high", 128);
369
370 metersInSpace = physicsconfig.GetFloat("meters_in_small_space", 29.9f);
371 smallHashspaceLow = physicsconfig.GetInt("small_hashspace_size_low", -4);
372 smallHashspaceHigh = physicsconfig.GetInt("small_hashspace_size_high", 66);
373
374 contactsurfacelayer = physicsconfig.GetFloat("world_contact_surface_layer", 0.001f);
375
376 nmTerrainContactFriction = physicsconfig.GetFloat("nm_terraincontact_friction", 255.0f);
377 nmTerrainContactBounce = physicsconfig.GetFloat("nm_terraincontact_bounce", 0.1f);
378 nmTerrainContactERP = physicsconfig.GetFloat("nm_terraincontact_erp", 0.1025f);
379
380 mTerrainContactFriction = physicsconfig.GetFloat("m_terraincontact_friction", 75f);
381 mTerrainContactBounce = physicsconfig.GetFloat("m_terraincontact_bounce", 0.05f);
382 mTerrainContactERP = physicsconfig.GetFloat("m_terraincontact_erp", 0.05025f);
383
384 nmAvatarObjectContactFriction = physicsconfig.GetFloat("objectcontact_friction", 250f);
385 nmAvatarObjectContactBounce = physicsconfig.GetFloat("objectcontact_bounce", 0.2f);
386
387 mAvatarObjectContactFriction = physicsconfig.GetFloat("m_avatarobjectcontact_friction", 75f);
388 mAvatarObjectContactBounce = physicsconfig.GetFloat("m_avatarobjectcontact_bounce", 0.1f);
389
390 ODE_STEPSIZE = physicsconfig.GetFloat("world_stepsize", 0.020f);
391 m_physicsiterations = physicsconfig.GetInt("world_internal_steps_without_collisions", 10);
392
393 avDensity = physicsconfig.GetFloat("av_density", 80f);
394 avHeightFudgeFactor = physicsconfig.GetFloat("av_height_fudge_factor", 0.52f);
395 avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", 1.3f);
396 avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", 0.8f);
397 avCapRadius = physicsconfig.GetFloat("av_capsule_radius", 0.37f);
398 avCapsuleTilted = physicsconfig.GetBoolean("av_capsule_tilted", false);
399
400 contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80);
401
402 geomContactPointsStartthrottle = physicsconfig.GetInt("geom_contactpoints_start_throttling", 3);
403 geomUpdatesPerThrottledUpdate = physicsconfig.GetInt("geom_updates_before_throttled_update", 15);
404 geomCrossingFailuresBeforeOutofbounds = physicsconfig.GetInt("geom_crossing_failures_before_outofbounds", 5);
405
406 geomDefaultDensity = physicsconfig.GetFloat("geometry_default_density", 10.000006836f);
407 bodyFramesAutoDisable = physicsconfig.GetInt("body_frames_auto_disable", 20);
408
409 bodyPIDD = physicsconfig.GetFloat("body_pid_derivative", 35f);
410 bodyPIDG = physicsconfig.GetFloat("body_pid_gain", 25f);
411
412 forceSimplePrimMeshing = physicsconfig.GetBoolean("force_simple_prim_meshing", forceSimplePrimMeshing);
413 meshSculptedPrim = physicsconfig.GetBoolean("mesh_sculpted_prim", true);
414 meshSculptLOD = physicsconfig.GetFloat("mesh_lod", 32f);
415 MeshSculptphysicalLOD = physicsconfig.GetFloat("mesh_physical_lod", 16f);
416 m_filterCollisions = physicsconfig.GetBoolean("filter_collisions", false);
417
418 if (Environment.OSVersion.Platform == PlatformID.Unix)
419 {
420 avPIDD = physicsconfig.GetFloat("av_pid_derivative_linux", 2200.0f);
421 avPIDP = physicsconfig.GetFloat("av_pid_proportional_linux", 900.0f);
422 avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor_linux", 550000f);
423 bodyMotorJointMaxforceTensor = physicsconfig.GetFloat("body_motor_joint_maxforce_tensor_linux", 5f);
424 }
425 else
426 {
427 avPIDD = physicsconfig.GetFloat("av_pid_derivative_win", 2200.0f);
428 avPIDP = physicsconfig.GetFloat("av_pid_proportional_win", 900.0f);
429 avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor_win", 550000f);
430 bodyMotorJointMaxforceTensor = physicsconfig.GetFloat("body_motor_joint_maxforce_tensor_win", 5f);
431 }
432
433 physics_logging = physicsconfig.GetBoolean("physics_logging", false);
434 physics_logging_interval = physicsconfig.GetInt("physics_logging_interval", 0);
435 physics_logging_append_existing_logfile = physicsconfig.GetBoolean("physics_logging_append_existing_logfile", false);
436
437 m_NINJA_physics_joints_enabled = physicsconfig.GetBoolean("use_NINJA_physics_joints", false);
438 minimumGroundFlightOffset = physicsconfig.GetFloat("minimum_ground_flight_offset", 3f);
439 maximumMassObject = physicsconfig.GetFloat("maximum_mass_object", 10000.01f);
440 }
441 }
442
443 contacts = new d.ContactGeom[contactsPerCollision];
444
445 staticPrimspace = new IntPtr[(int)(300 / metersInSpace), (int)(300 / metersInSpace)];
446
447 // Centeral contact friction and bounce
448 // ckrinke 11/10/08 Enabling soft_erp but not soft_cfm until I figure out why
449 // an avatar falls through in Z but not in X or Y when walking on a prim.
450 contact.surface.mode |= d.ContactFlags.SoftERP;
451 contact.surface.mu = nmAvatarObjectContactFriction;
452 contact.surface.bounce = nmAvatarObjectContactBounce;
453 contact.surface.soft_cfm = 0.010f;
454 contact.surface.soft_erp = 0.010f;
455
456 // Terrain contact friction and Bounce
457 // This is the *non* moving version. Use this when an avatar
458 // isn't moving to keep it in place better
459 TerrainContact.surface.mode |= d.ContactFlags.SoftERP;
460 TerrainContact.surface.mu = nmTerrainContactFriction;
461 TerrainContact.surface.bounce = nmTerrainContactBounce;
462 TerrainContact.surface.soft_erp = nmTerrainContactERP;
463
464 WaterContact.surface.mode |= (d.ContactFlags.SoftERP | d.ContactFlags.SoftCFM);
465 WaterContact.surface.mu = 0f; // No friction
466 WaterContact.surface.bounce = 0.0f; // No bounce
467 WaterContact.surface.soft_cfm = 0.010f;
468 WaterContact.surface.soft_erp = 0.010f;
469
470 // Prim contact friction and bounce
471 // THis is the *non* moving version of friction and bounce
472 // Use this when an avatar comes in contact with a prim
473 // and is moving
474 AvatarMovementprimContact.surface.mu = mAvatarObjectContactFriction;
475 AvatarMovementprimContact.surface.bounce = mAvatarObjectContactBounce;
476
477 // Terrain contact friction bounce and various error correcting calculations
478 // Use this when an avatar is in contact with the terrain and moving.
479 AvatarMovementTerrainContact.surface.mode |= d.ContactFlags.SoftERP;
480 AvatarMovementTerrainContact.surface.mu = mTerrainContactFriction;
481 AvatarMovementTerrainContact.surface.bounce = mTerrainContactBounce;
482 AvatarMovementTerrainContact.surface.soft_erp = mTerrainContactERP;
483
484 /*
485 <summary></summary>
486 Stone = 0,
487 /// <summary></summary>
488 Metal = 1,
489 /// <summary></summary>
490 Glass = 2,
491 /// <summary></summary>
492 Wood = 3,
493 /// <summary></summary>
494 Flesh = 4,
495 /// <summary></summary>
496 Plastic = 5,
497 /// <summary></summary>
498 Rubber = 6
499 */
500
501 m_materialContacts = new d.Contact[7,2];
502
503 m_materialContacts[(int)Material.Stone, 0] = new d.Contact();
504 m_materialContacts[(int)Material.Stone, 0].surface.mode |= d.ContactFlags.SoftERP;
505 m_materialContacts[(int)Material.Stone, 0].surface.mu = nmAvatarObjectContactFriction;
506 m_materialContacts[(int)Material.Stone, 0].surface.bounce = nmAvatarObjectContactBounce;
507 m_materialContacts[(int)Material.Stone, 0].surface.soft_cfm = 0.010f;
508 m_materialContacts[(int)Material.Stone, 0].surface.soft_erp = 0.010f;
509
510 m_materialContacts[(int)Material.Stone, 1] = new d.Contact();
511 m_materialContacts[(int)Material.Stone, 1].surface.mode |= d.ContactFlags.SoftERP;
512 m_materialContacts[(int)Material.Stone, 1].surface.mu = mAvatarObjectContactFriction;
513 m_materialContacts[(int)Material.Stone, 1].surface.bounce = mAvatarObjectContactBounce;
514 m_materialContacts[(int)Material.Stone, 1].surface.soft_cfm = 0.010f;
515 m_materialContacts[(int)Material.Stone, 1].surface.soft_erp = 0.010f;
516
517 m_materialContacts[(int)Material.Metal, 0] = new d.Contact();
518 m_materialContacts[(int)Material.Metal, 0].surface.mode |= d.ContactFlags.SoftERP;
519 m_materialContacts[(int)Material.Metal, 0].surface.mu = nmAvatarObjectContactFriction;
520 m_materialContacts[(int)Material.Metal, 0].surface.bounce = nmAvatarObjectContactBounce;
521 m_materialContacts[(int)Material.Metal, 0].surface.soft_cfm = 0.010f;
522 m_materialContacts[(int)Material.Metal, 0].surface.soft_erp = 0.010f;
523
524 m_materialContacts[(int)Material.Metal, 1] = new d.Contact();
525 m_materialContacts[(int)Material.Metal, 1].surface.mode |= d.ContactFlags.SoftERP;
526 m_materialContacts[(int)Material.Metal, 1].surface.mu = mAvatarObjectContactFriction;
527 m_materialContacts[(int)Material.Metal, 1].surface.bounce = mAvatarObjectContactBounce;
528 m_materialContacts[(int)Material.Metal, 1].surface.soft_cfm = 0.010f;
529 m_materialContacts[(int)Material.Metal, 1].surface.soft_erp = 0.010f;
530
531 m_materialContacts[(int)Material.Glass, 0] = new d.Contact();
532 m_materialContacts[(int)Material.Glass, 0].surface.mode |= d.ContactFlags.SoftERP;
533 m_materialContacts[(int)Material.Glass, 0].surface.mu = 1f;
534 m_materialContacts[(int)Material.Glass, 0].surface.bounce = 0.5f;
535 m_materialContacts[(int)Material.Glass, 0].surface.soft_cfm = 0.010f;
536 m_materialContacts[(int)Material.Glass, 0].surface.soft_erp = 0.010f;
537
538 /*
539 private float nmAvatarObjectContactFriction = 250f;
540 private float nmAvatarObjectContactBounce = 0.1f;
541
542 private float mAvatarObjectContactFriction = 75f;
543 private float mAvatarObjectContactBounce = 0.1f;
544 */
545 m_materialContacts[(int)Material.Glass, 1] = new d.Contact();
546 m_materialContacts[(int)Material.Glass, 1].surface.mode |= d.ContactFlags.SoftERP;
547 m_materialContacts[(int)Material.Glass, 1].surface.mu = 1f;
548 m_materialContacts[(int)Material.Glass, 1].surface.bounce = 0.5f;
549 m_materialContacts[(int)Material.Glass, 1].surface.soft_cfm = 0.010f;
550 m_materialContacts[(int)Material.Glass, 1].surface.soft_erp = 0.010f;
551
552 m_materialContacts[(int)Material.Wood, 0] = new d.Contact();
553 m_materialContacts[(int)Material.Wood, 0].surface.mode |= d.ContactFlags.SoftERP;
554 m_materialContacts[(int)Material.Wood, 0].surface.mu = nmAvatarObjectContactFriction;
555 m_materialContacts[(int)Material.Wood, 0].surface.bounce = nmAvatarObjectContactBounce;
556 m_materialContacts[(int)Material.Wood, 0].surface.soft_cfm = 0.010f;
557 m_materialContacts[(int)Material.Wood, 0].surface.soft_erp = 0.010f;
558
559 m_materialContacts[(int)Material.Wood, 1] = new d.Contact();
560 m_materialContacts[(int)Material.Wood, 1].surface.mode |= d.ContactFlags.SoftERP;
561 m_materialContacts[(int)Material.Wood, 1].surface.mu = mAvatarObjectContactFriction;
562 m_materialContacts[(int)Material.Wood, 1].surface.bounce = mAvatarObjectContactBounce;
563 m_materialContacts[(int)Material.Wood, 1].surface.soft_cfm = 0.010f;
564 m_materialContacts[(int)Material.Wood, 1].surface.soft_erp = 0.010f;
565
566 m_materialContacts[(int)Material.Flesh, 0] = new d.Contact();
567 m_materialContacts[(int)Material.Flesh, 0].surface.mode |= d.ContactFlags.SoftERP;
568 m_materialContacts[(int)Material.Flesh, 0].surface.mu = nmAvatarObjectContactFriction;
569 m_materialContacts[(int)Material.Flesh, 0].surface.bounce = nmAvatarObjectContactBounce;
570 m_materialContacts[(int)Material.Flesh, 0].surface.soft_cfm = 0.010f;
571 m_materialContacts[(int)Material.Flesh, 0].surface.soft_erp = 0.010f;
572
573 m_materialContacts[(int)Material.Flesh, 1] = new d.Contact();
574 m_materialContacts[(int)Material.Flesh, 1].surface.mode |= d.ContactFlags.SoftERP;
575 m_materialContacts[(int)Material.Flesh, 1].surface.mu = mAvatarObjectContactFriction;
576 m_materialContacts[(int)Material.Flesh, 1].surface.bounce = mAvatarObjectContactBounce;
577 m_materialContacts[(int)Material.Flesh, 1].surface.soft_cfm = 0.010f;
578 m_materialContacts[(int)Material.Flesh, 1].surface.soft_erp = 0.010f;
579
580 m_materialContacts[(int)Material.Plastic, 0] = new d.Contact();
581 m_materialContacts[(int)Material.Plastic, 0].surface.mode |= d.ContactFlags.SoftERP;
582 m_materialContacts[(int)Material.Plastic, 0].surface.mu = nmAvatarObjectContactFriction;
583 m_materialContacts[(int)Material.Plastic, 0].surface.bounce = nmAvatarObjectContactBounce;
584 m_materialContacts[(int)Material.Plastic, 0].surface.soft_cfm = 0.010f;
585 m_materialContacts[(int)Material.Plastic, 0].surface.soft_erp = 0.010f;
586
587 m_materialContacts[(int)Material.Plastic, 1] = new d.Contact();
588 m_materialContacts[(int)Material.Plastic, 1].surface.mode |= d.ContactFlags.SoftERP;
589 m_materialContacts[(int)Material.Plastic, 1].surface.mu = mAvatarObjectContactFriction;
590 m_materialContacts[(int)Material.Plastic, 1].surface.bounce = mAvatarObjectContactBounce;
591 m_materialContacts[(int)Material.Plastic, 1].surface.soft_cfm = 0.010f;
592 m_materialContacts[(int)Material.Plastic, 1].surface.soft_erp = 0.010f;
593
594 m_materialContacts[(int)Material.Rubber, 0] = new d.Contact();
595 m_materialContacts[(int)Material.Rubber, 0].surface.mode |= d.ContactFlags.SoftERP;
596 m_materialContacts[(int)Material.Rubber, 0].surface.mu = nmAvatarObjectContactFriction;
597 m_materialContacts[(int)Material.Rubber, 0].surface.bounce = nmAvatarObjectContactBounce;
598 m_materialContacts[(int)Material.Rubber, 0].surface.soft_cfm = 0.010f;
599 m_materialContacts[(int)Material.Rubber, 0].surface.soft_erp = 0.010f;
600
601 m_materialContacts[(int)Material.Rubber, 1] = new d.Contact();
602 m_materialContacts[(int)Material.Rubber, 1].surface.mode |= d.ContactFlags.SoftERP;
603 m_materialContacts[(int)Material.Rubber, 1].surface.mu = mAvatarObjectContactFriction;
604 m_materialContacts[(int)Material.Rubber, 1].surface.bounce = mAvatarObjectContactBounce;
605 m_materialContacts[(int)Material.Rubber, 1].surface.soft_cfm = 0.010f;
606 m_materialContacts[(int)Material.Rubber, 1].surface.soft_erp = 0.010f;
607
608 d.HashSpaceSetLevels(space, worldHashspaceLow, worldHashspaceHigh);
609
610 // Set the gravity,, don't disable things automatically (we set it explicitly on some things)
611
612 d.WorldSetGravity(world, gravityx, gravityy, gravityz);
613 d.WorldSetContactSurfaceLayer(world, contactsurfacelayer);
614
615 d.WorldSetLinearDamping(world, 256f);
616 d.WorldSetAngularDamping(world, 256f);
617 d.WorldSetAngularDampingThreshold(world, 256f);
618 d.WorldSetLinearDampingThreshold(world, 256f);
619 d.WorldSetMaxAngularSpeed(world, 256f);
620
621 // Set how many steps we go without running collision testing
622 // This is in addition to the step size.
623 // Essentially Steps * m_physicsiterations
624 d.WorldSetQuickStepNumIterations(world, m_physicsiterations);
625 //d.WorldSetContactMaxCorrectingVel(world, 1000.0f);
626
627 for (int i = 0; i < staticPrimspace.GetLength(0); i++)
628 {
629 for (int j = 0; j < staticPrimspace.GetLength(1); j++)
630 {
631 staticPrimspace[i, j] = IntPtr.Zero;
632 }
633 }
634 }
635
636 internal void waitForSpaceUnlock(IntPtr space)
637 {
638 //if (space != IntPtr.Zero)
639 //while (d.SpaceLockQuery(space)) { } // Wait and do nothing
640 }
641
642 /// <summary>
643 /// Debug space message for printing the space that a prim/avatar is in.
644 /// </summary>
645 /// <param name="pos"></param>
646 /// <returns>Returns which split up space the given position is in.</returns>
647 public string whichspaceamIin(Vector3 pos)
648 {
649 return calculateSpaceForGeom(pos).ToString();
650 }
651
652 #region Collision Detection
653
654 /// <summary>
655 /// This is our near callback. A geometry is near a body
656 /// </summary>
657 /// <param name="space">The space that contains the geoms. Remember, spaces are also geoms</param>
658 /// <param name="g1">a geometry or space</param>
659 /// <param name="g2">another geometry or space</param>
660 private void near(IntPtr space, IntPtr g1, IntPtr g2)
661 {
662 // no lock here! It's invoked from within Simulate(), which is thread-locked
663
664 // Test if we're colliding a geom with a space.
665 // If so we have to drill down into the space recursively
666
667 if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2))
668 {
669 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
670 return;
671
672 // Separating static prim geometry spaces.
673 // We'll be calling near recursivly if one
674 // of them is a space to find all of the
675 // contact points in the space
676 try
677 {
678 d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback);
679 }
680 catch (AccessViolationException)
681 {
682 m_log.Warn("[PHYSICS]: Unable to collide test a space");
683 return;
684 }
685 //Colliding a space or a geom with a space or a geom. so drill down
686
687 //Collide all geoms in each space..
688 //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback);
689 //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback);
690 return;
691 }
692
693 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
694 return;
695
696 IntPtr b1 = d.GeomGetBody(g1);
697 IntPtr b2 = d.GeomGetBody(g2);
698
699 // d.GeomClassID id = d.GeomGetClass(g1);
700
701 String name1 = null;
702 String name2 = null;
703
704 if (!geom_name_map.TryGetValue(g1, out name1))
705 {
706 name1 = "null";
707 }
708 if (!geom_name_map.TryGetValue(g2, out name2))
709 {
710 name2 = "null";
711 }
712
713 //if (id == d.GeomClassId.TriMeshClass)
714 //{
715 // m_log.InfoFormat("near: A collision was detected between {1} and {2}", 0, name1, name2);
716 //m_log.Debug("near: A collision was detected between {1} and {2}", 0, name1, name2);
717 //}
718
719 // Figure out how many contact points we have
720 int count = 0;
721 try
722 {
723 // Colliding Geom To Geom
724 // This portion of the function 'was' blatantly ripped off from BoxStack.cs
725
726 if (g1 == g2)
727 return; // Can't collide with yourself
728
729 if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact))
730 return;
731
732 lock (contacts)
733 {
734 count = d.Collide(g1, g2, contacts.Length, contacts, d.ContactGeom.SizeOf);
735 if (count > contacts.Length)
736 m_log.Error("[PHYSICS]: Got " + count + " contacts when we asked for a maximum of " + contacts.Length);
737 }
738 }
739 catch (SEHException)
740 {
741 m_log.Error("[PHYSICS]: The Operating system shut down ODE because of corrupt memory. This could be a result of really irregular terrain. If this repeats continuously, restart using Basic Physics and terrain fill your terrain. Restarting the sim.");
742 ode.drelease(world);
743 base.TriggerPhysicsBasedRestart();
744 }
745 catch (Exception e)
746 {
747 m_log.WarnFormat("[PHYSICS]: Unable to collide test an object: {0}", e.Message);
748 return;
749 }
750
751 PhysicsActor p1;
752 PhysicsActor p2;
753
754 if (!actor_name_map.TryGetValue(g1, out p1))
755 {
756 p1 = PANull;
757 }
758
759 if (!actor_name_map.TryGetValue(g2, out p2))
760 {
761 p2 = PANull;
762 }
763
764 ContactPoint maxDepthContact = new ContactPoint();
765 if (p1.CollisionScore + count >= float.MaxValue)
766 p1.CollisionScore = 0;
767 p1.CollisionScore += count;
768
769 if (p2.CollisionScore + count >= float.MaxValue)
770 p2.CollisionScore = 0;
771 p2.CollisionScore += count;
772
773 for (int i = 0; i < count; i++)
774 {
775 d.ContactGeom curContact = contacts[i];
776
777 if (curContact.depth > maxDepthContact.PenetrationDepth)
778 {
779 maxDepthContact = new ContactPoint(
780 new Vector3(curContact.pos.X, curContact.pos.Y, curContact.pos.Z),
781 new Vector3(curContact.normal.X, curContact.normal.Y, curContact.normal.Z),
782 curContact.depth
783 );
784 }
785
786 //m_log.Warn("[CCOUNT]: " + count);
787 IntPtr joint;
788 // If we're colliding with terrain, use 'TerrainContact' instead of contact.
789 // allows us to have different settings
790
791 // We only need to test p2 for 'jump crouch purposes'
792 if (p2 is OdeCharacter && p1.PhysicsActorType == (int)ActorTypes.Prim)
793 {
794 // Testing if the collision is at the feet of the avatar
795
796 //m_log.DebugFormat("[PHYSICS]: {0} - {1} - {2} - {3}", curContact.pos.Z, p2.Position.Z, (p2.Position.Z - curContact.pos.Z), (p2.Size.Z * 0.6f));
797 if ((p2.Position.Z - curContact.pos.Z) > (p2.Size.Z * 0.6f))
798 p2.IsColliding = true;
799 }
800 else
801 {
802 p2.IsColliding = true;
803 }
804
805 //if ((framecount % m_returncollisions) == 0)
806
807 switch (p1.PhysicsActorType)
808 {
809 case (int)ActorTypes.Agent:
810 p2.CollidingObj = true;
811 break;
812 case (int)ActorTypes.Prim:
813 if (p2.Velocity.LengthSquared() > 0.0f)
814 p2.CollidingObj = true;
815 break;
816 case (int)ActorTypes.Unknown:
817 p2.CollidingGround = true;
818 break;
819 default:
820 p2.CollidingGround = true;
821 break;
822 }
823
824 // we don't want prim or avatar to explode
825
826 #region InterPenetration Handling - Unintended physics explosions
827# region disabled code1
828
829 if (curContact.depth >= 0.08f)
830 {
831 //This is disabled at the moment only because it needs more tweaking
832 //It will eventually be uncommented
833 /*
834 if (contact.depth >= 1.00f)
835 {
836 //m_log.Debug("[PHYSICS]: " + contact.depth.ToString());
837 }
838
839 //If you interpenetrate a prim with an agent
840 if ((p2.PhysicsActorType == (int) ActorTypes.Agent &&
841 p1.PhysicsActorType == (int) ActorTypes.Prim) ||
842 (p1.PhysicsActorType == (int) ActorTypes.Agent &&
843 p2.PhysicsActorType == (int) ActorTypes.Prim))
844 {
845
846 //contact.depth = contact.depth * 4.15f;
847 /*
848 if (p2.PhysicsActorType == (int) ActorTypes.Agent)
849 {
850 p2.CollidingObj = true;
851 contact.depth = 0.003f;
852 p2.Velocity = p2.Velocity + new PhysicsVector(0, 0, 2.5f);
853 OdeCharacter character = (OdeCharacter) p2;
854 character.SetPidStatus(true);
855 contact.pos = new d.Vector3(contact.pos.X + (p1.Size.X / 2), contact.pos.Y + (p1.Size.Y / 2), contact.pos.Z + (p1.Size.Z / 2));
856
857 }
858 else
859 {
860
861 //contact.depth = 0.0000000f;
862 }
863 if (p1.PhysicsActorType == (int) ActorTypes.Agent)
864 {
865
866 p1.CollidingObj = true;
867 contact.depth = 0.003f;
868 p1.Velocity = p1.Velocity + new PhysicsVector(0, 0, 2.5f);
869 contact.pos = new d.Vector3(contact.pos.X + (p2.Size.X / 2), contact.pos.Y + (p2.Size.Y / 2), contact.pos.Z + (p2.Size.Z / 2));
870 OdeCharacter character = (OdeCharacter)p1;
871 character.SetPidStatus(true);
872 }
873 else
874 {
875
876 //contact.depth = 0.0000000f;
877 }
878
879
880
881 }
882*/
883 // If you interpenetrate a prim with another prim
884 /*
885 if (p1.PhysicsActorType == (int) ActorTypes.Prim && p2.PhysicsActorType == (int) ActorTypes.Prim)
886 {
887 #region disabledcode2
888 //OdePrim op1 = (OdePrim)p1;
889 //OdePrim op2 = (OdePrim)p2;
890 //op1.m_collisionscore++;
891 //op2.m_collisionscore++;
892
893 //if (op1.m_collisionscore > 8000 || op2.m_collisionscore > 8000)
894 //{
895 //op1.m_taintdisable = true;
896 //AddPhysicsActorTaint(p1);
897 //op2.m_taintdisable = true;
898 //AddPhysicsActorTaint(p2);
899 //}
900
901 //if (contact.depth >= 0.25f)
902 //{
903 // Don't collide, one or both prim will expld.
904
905 //op1.m_interpenetrationcount++;
906 //op2.m_interpenetrationcount++;
907 //interpenetrations_before_disable = 200;
908 //if (op1.m_interpenetrationcount >= interpenetrations_before_disable)
909 //{
910 //op1.m_taintdisable = true;
911 //AddPhysicsActorTaint(p1);
912 //}
913 //if (op2.m_interpenetrationcount >= interpenetrations_before_disable)
914 //{
915 // op2.m_taintdisable = true;
916 //AddPhysicsActorTaint(p2);
917 //}
918
919 //contact.depth = contact.depth / 8f;
920 //contact.normal = new d.Vector3(0, 0, 1);
921 //}
922 //if (op1.m_disabled || op2.m_disabled)
923 //{
924 //Manually disabled objects stay disabled
925 //contact.depth = 0f;
926 //}
927 #endregion
928 }
929 */
930#endregion
931 if (curContact.depth >= 1.00f)
932 {
933 //m_log.Info("[P]: " + contact.depth.ToString());
934 if ((p2.PhysicsActorType == (int) ActorTypes.Agent &&
935 p1.PhysicsActorType == (int) ActorTypes.Unknown) ||
936 (p1.PhysicsActorType == (int) ActorTypes.Agent &&
937 p2.PhysicsActorType == (int) ActorTypes.Unknown))
938 {
939 if (p2.PhysicsActorType == (int) ActorTypes.Agent)
940 {
941 if (p2 is OdeCharacter)
942 {
943 OdeCharacter character = (OdeCharacter) p2;
944
945 //p2.CollidingObj = true;
946 curContact.depth = 0.00000003f;
947 p2.Velocity = p2.Velocity + new Vector3(0f, 0f, 0.5f);
948 curContact.pos =
949 new d.Vector3(curContact.pos.X + (p1.Size.X/2),
950 curContact.pos.Y + (p1.Size.Y/2),
951 curContact.pos.Z + (p1.Size.Z/2));
952 character.SetPidStatus(true);
953 }
954 }
955
956
957 if (p1.PhysicsActorType == (int) ActorTypes.Agent)
958 {
959 if (p1 is OdeCharacter)
960 {
961 OdeCharacter character = (OdeCharacter) p1;
962
963 //p2.CollidingObj = true;
964 curContact.depth = 0.00000003f;
965 p1.Velocity = p1.Velocity + new Vector3(0f, 0f, 0.5f);
966 curContact.pos =
967 new d.Vector3(curContact.pos.X + (p1.Size.X/2),
968 curContact.pos.Y + (p1.Size.Y/2),
969 curContact.pos.Z + (p1.Size.Z/2));
970 character.SetPidStatus(true);
971 }
972 }
973 }
974 }
975 }
976
977 #endregion
978
979 // Logic for collision handling
980 // Note, that if *all* contacts are skipped (VolumeDetect)
981 // The prim still detects (and forwards) collision events but
982 // appears to be phantom for the world
983 Boolean skipThisContact = false;
984
985 if ((p1 is OdePrim) && (((OdePrim)p1).m_isVolumeDetect))
986 skipThisContact = true; // No collision on volume detect prims
987
988 if (!skipThisContact && (p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect))
989 skipThisContact = true; // No collision on volume detect prims
990
991 if (!skipThisContact && curContact.depth < 0f)
992 skipThisContact = true;
993
994 if (!skipThisContact && checkDupe(curContact, p2.PhysicsActorType))
995 skipThisContact = true;
996
997 const int maxContactsbeforedeath = 4000;
998 joint = IntPtr.Zero;
999
1000 if (!skipThisContact)
1001 {
1002 // If we're colliding against terrain
1003 if (name1 == "Terrain" || name2 == "Terrain")
1004 {
1005 // If we're moving
1006 if ((p2.PhysicsActorType == (int) ActorTypes.Agent) &&
1007 (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
1008 {
1009 // Use the movement terrain contact
1010 AvatarMovementTerrainContact.geom = curContact;
1011 _perloopContact.Add(curContact);
1012 if (m_global_contactcount < maxContactsbeforedeath)
1013 {
1014 joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementTerrainContact);
1015 m_global_contactcount++;
1016 }
1017 }
1018 else
1019 {
1020 if (p2.PhysicsActorType == (int)ActorTypes.Agent)
1021 {
1022 // Use the non moving terrain contact
1023 TerrainContact.geom = curContact;
1024 _perloopContact.Add(curContact);
1025 if (m_global_contactcount < maxContactsbeforedeath)
1026 {
1027 joint = d.JointCreateContact(world, contactgroup, ref TerrainContact);
1028 m_global_contactcount++;
1029 }
1030 }
1031 else
1032 {
1033 if (p2.PhysicsActorType == (int)ActorTypes.Prim && p1.PhysicsActorType == (int)ActorTypes.Prim)
1034 {
1035 // prim prim contact
1036 // int pj294950 = 0;
1037 int movintYN = 0;
1038 int material = (int) Material.Wood;
1039 // prim terrain contact
1040 if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)
1041 {
1042 movintYN = 1;
1043 }
1044
1045 if (p2 is OdePrim)
1046 material = ((OdePrim)p2).m_material;
1047
1048 //m_log.DebugFormat("Material: {0}", material);
1049 m_materialContacts[material, movintYN].geom = curContact;
1050 _perloopContact.Add(curContact);
1051
1052 if (m_global_contactcount < maxContactsbeforedeath)
1053 {
1054 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]);
1055 m_global_contactcount++;
1056
1057 }
1058
1059 }
1060 else
1061 {
1062 int movintYN = 0;
1063 // prim terrain contact
1064 if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)
1065 {
1066 movintYN = 1;
1067 }
1068
1069 int material = (int)Material.Wood;
1070
1071 if (p2 is OdePrim)
1072 material = ((OdePrim)p2).m_material;
1073 //m_log.DebugFormat("Material: {0}", material);
1074 m_materialContacts[material, movintYN].geom = curContact;
1075 _perloopContact.Add(curContact);
1076
1077 if (m_global_contactcount < maxContactsbeforedeath)
1078 {
1079 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]);
1080 m_global_contactcount++;
1081
1082 }
1083 }
1084 }
1085 }
1086 //if (p2.PhysicsActorType == (int)ActorTypes.Prim)
1087 //{
1088 //m_log.Debug("[PHYSICS]: prim contacting with ground");
1089 //}
1090 }
1091 else if (name1 == "Water" || name2 == "Water")
1092 {
1093 /*
1094 if ((p2.PhysicsActorType == (int) ActorTypes.Prim))
1095 {
1096 }
1097 else
1098 {
1099 }
1100 */
1101 //WaterContact.surface.soft_cfm = 0.0000f;
1102 //WaterContact.surface.soft_erp = 0.00000f;
1103 if (curContact.depth > 0.1f)
1104 {
1105 curContact.depth *= 52;
1106 //contact.normal = new d.Vector3(0, 0, 1);
1107 //contact.pos = new d.Vector3(0, 0, contact.pos.Z - 5f);
1108 }
1109 WaterContact.geom = curContact;
1110 _perloopContact.Add(curContact);
1111 if (m_global_contactcount < maxContactsbeforedeath)
1112 {
1113 joint = d.JointCreateContact(world, contactgroup, ref WaterContact);
1114 m_global_contactcount++;
1115 }
1116 //m_log.Info("[PHYSICS]: Prim Water Contact" + contact.depth);
1117 }
1118 else
1119 {
1120 // we're colliding with prim or avatar
1121 // check if we're moving
1122 if ((p2.PhysicsActorType == (int)ActorTypes.Agent))
1123 {
1124 if ((Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
1125 {
1126 // Use the Movement prim contact
1127 AvatarMovementprimContact.geom = curContact;
1128 _perloopContact.Add(curContact);
1129 if (m_global_contactcount < maxContactsbeforedeath)
1130 {
1131 joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementprimContact);
1132 m_global_contactcount++;
1133 }
1134 }
1135 else
1136 {
1137 // Use the non movement contact
1138 contact.geom = curContact;
1139 _perloopContact.Add(curContact);
1140
1141 if (m_global_contactcount < maxContactsbeforedeath)
1142 {
1143 joint = d.JointCreateContact(world, contactgroup, ref contact);
1144 m_global_contactcount++;
1145 }
1146 }
1147 }
1148 else if (p2.PhysicsActorType == (int)ActorTypes.Prim)
1149 {
1150 //p1.PhysicsActorType
1151 int material = (int)Material.Wood;
1152
1153 if (p2 is OdePrim)
1154 material = ((OdePrim)p2).m_material;
1155
1156 //m_log.DebugFormat("Material: {0}", material);
1157 m_materialContacts[material, 0].geom = curContact;
1158 _perloopContact.Add(curContact);
1159
1160 if (m_global_contactcount < maxContactsbeforedeath)
1161 {
1162 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, 0]);
1163 m_global_contactcount++;
1164
1165 }
1166 }
1167 }
1168
1169 if (m_global_contactcount < maxContactsbeforedeath && joint != IntPtr.Zero) // stack collide!
1170 {
1171 d.JointAttach(joint, b1, b2);
1172 m_global_contactcount++;
1173 }
1174 }
1175
1176 collision_accounting_events(p1, p2, maxDepthContact);
1177
1178 if (count > geomContactPointsStartthrottle)
1179 {
1180 // If there are more then 3 contact points, it's likely
1181 // that we've got a pile of objects, so ...
1182 // We don't want to send out hundreds of terse updates over and over again
1183 // so lets throttle them and send them again after it's somewhat sorted out.
1184 p2.ThrottleUpdates = true;
1185 }
1186 //m_log.Debug(count.ToString());
1187 //m_log.Debug("near: A collision was detected between {1} and {2}", 0, name1, name2);
1188 }
1189 }
1190
1191 private bool checkDupe(d.ContactGeom contactGeom, int atype)
1192 {
1193 bool result = false;
1194 //return result;
1195 if (!m_filterCollisions)
1196 return false;
1197
1198 ActorTypes at = (ActorTypes)atype;
1199 lock (_perloopContact)
1200 {
1201 foreach (d.ContactGeom contact in _perloopContact)
1202 {
1203 //if ((contact.g1 == contactGeom.g1 && contact.g2 == contactGeom.g2))
1204 //{
1205 // || (contact.g2 == contactGeom.g1 && contact.g1 == contactGeom.g2)
1206 if (at == ActorTypes.Agent)
1207 {
1208 if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)) && contactGeom.g1 != LandGeom && contactGeom.g2 != LandGeom)
1209 {
1210
1211 if (Math.Abs(contact.depth - contactGeom.depth) < 0.052f)
1212 {
1213 //contactGeom.depth *= .00005f;
1214 //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
1215 // m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z));
1216 result = true;
1217 break;
1218 }
1219 else
1220 {
1221 //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
1222 }
1223 }
1224 else
1225 {
1226 //m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z));
1227 //int i = 0;
1228 }
1229 }
1230 else if (at == ActorTypes.Prim)
1231 {
1232 //d.AABB aabb1 = new d.AABB();
1233 //d.AABB aabb2 = new d.AABB();
1234
1235 //d.GeomGetAABB(contactGeom.g2, out aabb2);
1236 //d.GeomGetAABB(contactGeom.g1, out aabb1);
1237 //aabb1.
1238 if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)) && contactGeom.g1 != LandGeom && contactGeom.g2 != LandGeom)
1239 {
1240 if (contactGeom.normal.X == contact.normal.X && contactGeom.normal.Y == contact.normal.Y && contactGeom.normal.Z == contact.normal.Z)
1241 {
1242 if (Math.Abs(contact.depth - contactGeom.depth) < 0.272f)
1243 {
1244 result = true;
1245 break;
1246 }
1247 }
1248 //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
1249 //m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z));
1250 }
1251
1252 }
1253
1254 //}
1255
1256 }
1257 }
1258
1259 return result;
1260 }
1261
1262 private void collision_accounting_events(PhysicsActor p1, PhysicsActor p2, ContactPoint contact)
1263 {
1264 // obj1LocalID = 0;
1265 //returncollisions = false;
1266 obj2LocalID = 0;
1267 //ctype = 0;
1268 //cStartStop = 0;
1269 if (!p2.SubscribedEvents() && !p1.SubscribedEvents())
1270 return;
1271
1272 switch ((ActorTypes)p2.PhysicsActorType)
1273 {
1274 case ActorTypes.Agent:
1275 cc2 = (OdeCharacter)p2;
1276
1277 // obj1LocalID = cc2.m_localID;
1278 switch ((ActorTypes)p1.PhysicsActorType)
1279 {
1280 case ActorTypes.Agent:
1281 cc1 = (OdeCharacter)p1;
1282 obj2LocalID = cc1.m_localID;
1283 cc1.AddCollisionEvent(cc2.m_localID, contact);
1284 //ctype = (int)CollisionCategories.Character;
1285
1286 //if (cc1.CollidingObj)
1287 //cStartStop = (int)StatusIndicators.Generic;
1288 //else
1289 //cStartStop = (int)StatusIndicators.Start;
1290
1291 //returncollisions = true;
1292 break;
1293 case ActorTypes.Prim:
1294 if (p1 is OdePrim)
1295 {
1296 cp1 = (OdePrim) p1;
1297 obj2LocalID = cp1.m_localID;
1298 cp1.AddCollisionEvent(cc2.m_localID, contact);
1299 }
1300 //ctype = (int)CollisionCategories.Geom;
1301
1302 //if (cp1.CollidingObj)
1303 //cStartStop = (int)StatusIndicators.Generic;
1304 //else
1305 //cStartStop = (int)StatusIndicators.Start;
1306
1307 //returncollisions = true;
1308 break;
1309
1310 case ActorTypes.Ground:
1311 case ActorTypes.Unknown:
1312 obj2LocalID = 0;
1313 //ctype = (int)CollisionCategories.Land;
1314 //returncollisions = true;
1315 break;
1316 }
1317
1318 cc2.AddCollisionEvent(obj2LocalID, contact);
1319 break;
1320 case ActorTypes.Prim:
1321
1322 if (p2 is OdePrim)
1323 {
1324 cp2 = (OdePrim) p2;
1325
1326 // obj1LocalID = cp2.m_localID;
1327 switch ((ActorTypes) p1.PhysicsActorType)
1328 {
1329 case ActorTypes.Agent:
1330 if (p1 is OdeCharacter)
1331 {
1332 cc1 = (OdeCharacter) p1;
1333 obj2LocalID = cc1.m_localID;
1334 cc1.AddCollisionEvent(cp2.m_localID, contact);
1335 //ctype = (int)CollisionCategories.Character;
1336
1337 //if (cc1.CollidingObj)
1338 //cStartStop = (int)StatusIndicators.Generic;
1339 //else
1340 //cStartStop = (int)StatusIndicators.Start;
1341 //returncollisions = true;
1342 }
1343 break;
1344 case ActorTypes.Prim:
1345
1346 if (p1 is OdePrim)
1347 {
1348 cp1 = (OdePrim) p1;
1349 obj2LocalID = cp1.m_localID;
1350 cp1.AddCollisionEvent(cp2.m_localID, contact);
1351 //ctype = (int)CollisionCategories.Geom;
1352
1353 //if (cp1.CollidingObj)
1354 //cStartStop = (int)StatusIndicators.Generic;
1355 //else
1356 //cStartStop = (int)StatusIndicators.Start;
1357
1358 //returncollisions = true;
1359 }
1360 break;
1361
1362 case ActorTypes.Ground:
1363 case ActorTypes.Unknown:
1364 obj2LocalID = 0;
1365 //ctype = (int)CollisionCategories.Land;
1366
1367 //returncollisions = true;
1368 break;
1369 }
1370
1371 cp2.AddCollisionEvent(obj2LocalID, contact);
1372 }
1373 break;
1374 }
1375 //if (returncollisions)
1376 //{
1377
1378 //lock (m_storedCollisions)
1379 //{
1380 //cDictKey = obj1LocalID.ToString() + obj2LocalID.ToString() + cStartStop.ToString() + ctype.ToString();
1381 //if (m_storedCollisions.ContainsKey(cDictKey))
1382 //{
1383 //sCollisionData objd = m_storedCollisions[cDictKey];
1384 //objd.NumberOfCollisions += 1;
1385 //objd.lastframe = framecount;
1386 //m_storedCollisions[cDictKey] = objd;
1387 //}
1388 //else
1389 //{
1390 //sCollisionData objd = new sCollisionData();
1391 //objd.ColliderLocalId = obj1LocalID;
1392 //objd.CollidedWithLocalId = obj2LocalID;
1393 //objd.CollisionType = ctype;
1394 //objd.NumberOfCollisions = 1;
1395 //objd.lastframe = framecount;
1396 //objd.StatusIndicator = cStartStop;
1397 //m_storedCollisions.Add(cDictKey, objd);
1398 //}
1399 //}
1400 // }
1401 }
1402
1403 public int TriArrayCallback(IntPtr trimesh, IntPtr refObject, int[] triangleIndex, int triCount)
1404 {
1405 /* String name1 = null;
1406 String name2 = null;
1407
1408 if (!geom_name_map.TryGetValue(trimesh, out name1))
1409 {
1410 name1 = "null";
1411 }
1412 if (!geom_name_map.TryGetValue(refObject, out name2))
1413 {
1414 name2 = "null";
1415 }
1416
1417 m_log.InfoFormat("TriArrayCallback: A collision was detected between {1} and {2}", 0, name1, name2);
1418 */
1419 return 1;
1420 }
1421
1422 public int TriCallback(IntPtr trimesh, IntPtr refObject, int triangleIndex)
1423 {
1424 String name1 = null;
1425 String name2 = null;
1426
1427 if (!geom_name_map.TryGetValue(trimesh, out name1))
1428 {
1429 name1 = "null";
1430 }
1431
1432 if (!geom_name_map.TryGetValue(refObject, out name2))
1433 {
1434 name2 = "null";
1435 }
1436
1437 // m_log.InfoFormat("TriCallback: A collision was detected between {1} and {2}. Index was {3}", 0, name1, name2, triangleIndex);
1438
1439 d.Vector3 v0 = new d.Vector3();
1440 d.Vector3 v1 = new d.Vector3();
1441 d.Vector3 v2 = new d.Vector3();
1442
1443 d.GeomTriMeshGetTriangle(trimesh, 0, ref v0, ref v1, ref v2);
1444 // m_log.DebugFormat("Triangle {0} is <{1},{2},{3}>, <{4},{5},{6}>, <{7},{8},{9}>", triangleIndex, v0.X, v0.Y, v0.Z, v1.X, v1.Y, v1.Z, v2.X, v2.Y, v2.Z);
1445
1446 return 1;
1447 }
1448
1449 /// <summary>
1450 /// This is our collision testing routine in ODE
1451 /// </summary>
1452 /// <param name="timeStep"></param>
1453 private void collision_optimized(float timeStep)
1454 {
1455 _perloopContact.Clear();
1456
1457 lock (_characters)
1458 {
1459 foreach (OdeCharacter chr in _characters)
1460 {
1461 // Reset the collision values to false
1462 // since we don't know if we're colliding yet
1463
1464 // For some reason this can happen. Don't ask...
1465 //
1466 if (chr == null)
1467 continue;
1468
1469 if (chr.Shell == IntPtr.Zero || chr.Body == IntPtr.Zero)
1470 continue;
1471
1472 chr.IsColliding = false;
1473 chr.CollidingGround = false;
1474 chr.CollidingObj = false;
1475
1476 // test the avatar's geometry for collision with the space
1477 // This will return near and the space that they are the closest to
1478 // And we'll run this again against the avatar and the space segment
1479 // This will return with a bunch of possible objects in the space segment
1480 // and we'll run it again on all of them.
1481 try
1482 {
1483 d.SpaceCollide2(space, chr.Shell, IntPtr.Zero, nearCallback);
1484 }
1485 catch (AccessViolationException)
1486 {
1487 m_log.Warn("[PHYSICS]: Unable to space collide");
1488 }
1489 //float terrainheight = GetTerrainHeightAtXY(chr.Position.X, chr.Position.Y);
1490 //if (chr.Position.Z + (chr.Velocity.Z * timeStep) < terrainheight + 10)
1491 //{
1492 //chr.Position.Z = terrainheight + 10.0f;
1493 //forcedZ = true;
1494 //}
1495 }
1496 }
1497
1498 lock (_activeprims)
1499 {
1500 List<OdePrim> removeprims = null;
1501 foreach (OdePrim chr in _activeprims)
1502 {
1503 if (chr.Body != IntPtr.Zero && d.BodyIsEnabled(chr.Body) && (!chr.m_disabled))
1504 {
1505 try
1506 {
1507 lock (chr)
1508 {
1509 if (space != IntPtr.Zero && chr.prim_geom != IntPtr.Zero && chr.m_taintremove == false)
1510 {
1511 d.SpaceCollide2(space, chr.prim_geom, IntPtr.Zero, nearCallback);
1512 }
1513 else
1514 {
1515 if (removeprims == null)
1516 {
1517 removeprims = new List<OdePrim>();
1518 }
1519 removeprims.Add(chr);
1520 m_log.Debug("[PHYSICS]: unable to collide test active prim against space. The space was zero, the geom was zero or it was in the process of being removed. Removed it from the active prim list. This needs to be fixed!");
1521 }
1522 }
1523 }
1524 catch (AccessViolationException)
1525 {
1526 m_log.Warn("[PHYSICS]: Unable to space collide");
1527 }
1528 }
1529 }
1530
1531 if (removeprims != null)
1532 {
1533 foreach (OdePrim chr in removeprims)
1534 {
1535 _activeprims.Remove(chr);
1536 }
1537 }
1538 }
1539
1540 _perloopContact.Clear();
1541 }
1542
1543 #endregion
1544
1545 public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
1546 {
1547 m_worldOffset = offset;
1548 WorldExtents = new Vector2(extents.X, extents.Y);
1549 m_parentScene = pScene;
1550 }
1551
1552 // Recovered for use by fly height. Kitto Flora
1553 public float GetTerrainHeightAtXY(float x, float y)
1554 {
1555 int offsetX = ((int)(x / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
1556 int offsetY = ((int)(y / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
1557
1558 IntPtr heightFieldGeom = IntPtr.Zero;
1559
1560 if (RegionTerrain.TryGetValue(new Vector3(offsetX,offsetY,0), out heightFieldGeom))
1561 {
1562 if (heightFieldGeom != IntPtr.Zero)
1563 {
1564 if (TerrainHeightFieldHeights.ContainsKey(heightFieldGeom))
1565 {
1566
1567 int index;
1568
1569
1570 if ((int)x > WorldExtents.X || (int)y > WorldExtents.Y ||
1571 (int)x < 0.001f || (int)y < 0.001f)
1572 return 0;
1573
1574 x = x - offsetX;
1575 y = y - offsetY;
1576
1577 index = (int)((int)x * ((int)Constants.RegionSize + 2) + (int)y);
1578
1579 if (index < TerrainHeightFieldHeights[heightFieldGeom].Length)
1580 {
1581 //m_log.DebugFormat("x{0} y{1} = {2}", x, y, (float)TerrainHeightFieldHeights[heightFieldGeom][index]);
1582 return (float)TerrainHeightFieldHeights[heightFieldGeom][index];
1583 }
1584
1585 else
1586 return 0f;
1587 }
1588 else
1589 {
1590 return 0f;
1591 }
1592
1593 }
1594 else
1595 {
1596 return 0f;
1597 }
1598
1599 }
1600 else
1601 {
1602 return 0f;
1603 }
1604 }
1605// End recovered. Kitto Flora
1606
1607 public void addCollisionEventReporting(PhysicsActor obj)
1608 {
1609 lock (_collisionEventPrim)
1610 {
1611 if (!_collisionEventPrim.Contains(obj))
1612 _collisionEventPrim.Add(obj);
1613 }
1614 }
1615
1616 public void remCollisionEventReporting(PhysicsActor obj)
1617 {
1618 lock (_collisionEventPrim)
1619 {
1620 if (!_collisionEventPrim.Contains(obj))
1621 _collisionEventPrim.Remove(obj);
1622 }
1623 }
1624
1625 #region Add/Remove Entities
1626
1627 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
1628 {
1629 Vector3 pos;
1630 pos.X = position.X;
1631 pos.Y = position.Y;
1632 pos.Z = position.Z;
1633 OdeCharacter newAv = new OdeCharacter(avName, this, pos, ode, size, avPIDD, avPIDP, avCapRadius, avStandupTensor, avDensity, avHeightFudgeFactor, avMovementDivisorWalk, avMovementDivisorRun);
1634 newAv.Flying = isFlying;
1635 newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset;
1636
1637 return newAv;
1638 }
1639
1640 public void AddCharacter(OdeCharacter chr)
1641 {
1642 lock (_characters)
1643 {
1644 if (!_characters.Contains(chr))
1645 {
1646 _characters.Add(chr);
1647 if (chr.bad)
1648 m_log.DebugFormat("[PHYSICS] Added BAD actor {0} to characters list", chr.m_uuid);
1649 }
1650 }
1651 }
1652
1653 public void RemoveCharacter(OdeCharacter chr)
1654 {
1655 lock (_characters)
1656 {
1657 if (_characters.Contains(chr))
1658 {
1659 _characters.Remove(chr);
1660 }
1661 }
1662 }
1663
1664 public void BadCharacter(OdeCharacter chr)
1665 {
1666 lock (_badCharacter)
1667 {
1668 if (!_badCharacter.Contains(chr))
1669 _badCharacter.Add(chr);
1670 }
1671 }
1672
1673 public override void RemoveAvatar(PhysicsActor actor)
1674 {
1675 //m_log.Debug("[PHYSICS]:ODELOCK");
1676 ((OdeCharacter) actor).Destroy();
1677 }
1678
1679 private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation,
1680 IMesh mesh, PrimitiveBaseShape pbs, bool isphysical)
1681 {
1682 Vector3 pos = position;
1683 Vector3 siz = size;
1684 Quaternion rot = rotation;
1685
1686 OdePrim newPrim;
1687 lock (OdeLock)
1688 {
1689 newPrim = new OdePrim(name, this, pos, siz, rot, mesh, pbs, isphysical, ode);
1690
1691 lock (_prims)
1692 _prims.Add(newPrim);
1693 }
1694
1695 return newPrim;
1696 }
1697
1698 public void addActivePrim(OdePrim activatePrim)
1699 {
1700 // adds active prim.. (ones that should be iterated over in collisions_optimized
1701 lock (_activeprims)
1702 {
1703 if (!_activeprims.Contains(activatePrim))
1704 _activeprims.Add(activatePrim);
1705 //else
1706 // m_log.Warn("[PHYSICS]: Double Entry in _activeprims detected, potential crash immenent");
1707 }
1708 }
1709
1710 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
1711 Vector3 size, Quaternion rotation) //To be removed
1712 {
1713 return AddPrimShape(primName, pbs, position, size, rotation, false);
1714 }
1715
1716 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
1717 Vector3 size, Quaternion rotation, bool isPhysical)
1718 {
1719#if SPAM
1720 m_log.DebugFormat("[PHYSICS]: Adding physics actor to {0}", primName);
1721#endif
1722
1723 PhysicsActor result;
1724 IMesh mesh = null;
1725
1726 if (needsMeshing(pbs))
1727 {
1728 try
1729 {
1730 mesh = mesher.CreateMesh(primName, pbs, size, 32f, isPhysical);
1731 }
1732 catch(Exception e)
1733 {
1734 m_log.ErrorFormat("[PHYSICS]: Exception while meshing prim {0}.", primName);
1735 m_log.Debug(e.ToString());
1736 mesh = null;
1737 return null;
1738 }
1739 }
1740
1741 result = AddPrim(primName, position, size, rotation, mesh, pbs, isPhysical);
1742
1743 return result;
1744 }
1745
1746 public override float TimeDilation
1747 {
1748 get { return m_timeDilation; }
1749 }
1750
1751 public override bool SupportsNINJAJoints
1752 {
1753 get { return m_NINJA_physics_joints_enabled; }
1754 }
1755
1756 // internal utility function: must be called within a lock (OdeLock)
1757 private void InternalAddActiveJoint(PhysicsJoint joint)
1758 {
1759 activeJoints.Add(joint);
1760 SOPName_to_activeJoint.Add(joint.ObjectNameInScene, joint);
1761 }
1762
1763 // internal utility function: must be called within a lock (OdeLock)
1764 private void InternalAddPendingJoint(OdePhysicsJoint joint)
1765 {
1766 pendingJoints.Add(joint);
1767 SOPName_to_pendingJoint.Add(joint.ObjectNameInScene, joint);
1768 }
1769
1770 // internal utility function: must be called within a lock (OdeLock)
1771 private void InternalRemovePendingJoint(PhysicsJoint joint)
1772 {
1773 pendingJoints.Remove(joint);
1774 SOPName_to_pendingJoint.Remove(joint.ObjectNameInScene);
1775 }
1776
1777 // internal utility function: must be called within a lock (OdeLock)
1778 private void InternalRemoveActiveJoint(PhysicsJoint joint)
1779 {
1780 activeJoints.Remove(joint);
1781 SOPName_to_activeJoint.Remove(joint.ObjectNameInScene);
1782 }
1783
1784 public override void DumpJointInfo()
1785 {
1786 string hdr = "[NINJA] JOINTINFO: ";
1787 foreach (PhysicsJoint j in pendingJoints)
1788 {
1789 m_log.Debug(hdr + " pending joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1790 }
1791 m_log.Debug(hdr + pendingJoints.Count + " total pending joints");
1792 foreach (string jointName in SOPName_to_pendingJoint.Keys)
1793 {
1794 m_log.Debug(hdr + " pending joints dict contains Name: " + jointName);
1795 }
1796 m_log.Debug(hdr + SOPName_to_pendingJoint.Keys.Count + " total pending joints dict entries");
1797 foreach (PhysicsJoint j in activeJoints)
1798 {
1799 m_log.Debug(hdr + " active joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1800 }
1801 m_log.Debug(hdr + activeJoints.Count + " total active joints");
1802 foreach (string jointName in SOPName_to_activeJoint.Keys)
1803 {
1804 m_log.Debug(hdr + " active joints dict contains Name: " + jointName);
1805 }
1806 m_log.Debug(hdr + SOPName_to_activeJoint.Keys.Count + " total active joints dict entries");
1807
1808 m_log.Debug(hdr + " Per-body joint connectivity information follows.");
1809 m_log.Debug(hdr + joints_connecting_actor.Keys.Count + " bodies are connected by joints.");
1810 foreach (string actorName in joints_connecting_actor.Keys)
1811 {
1812 m_log.Debug(hdr + " Actor " + actorName + " has the following joints connecting it");
1813 foreach (PhysicsJoint j in joints_connecting_actor[actorName])
1814 {
1815 m_log.Debug(hdr + " * joint Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1816 }
1817 m_log.Debug(hdr + joints_connecting_actor[actorName].Count + " connecting joints total for this actor");
1818 }
1819 }
1820
1821 public override void RequestJointDeletion(string ObjectNameInScene)
1822 {
1823 lock (externalJointRequestsLock)
1824 {
1825 if (!requestedJointsToBeDeleted.Contains(ObjectNameInScene)) // forbid same deletion request from entering twice to prevent spurious deletions processed asynchronously
1826 {
1827 requestedJointsToBeDeleted.Add(ObjectNameInScene);
1828 }
1829 }
1830 }
1831
1832 private void DeleteRequestedJoints()
1833 {
1834 List<string> myRequestedJointsToBeDeleted;
1835 lock (externalJointRequestsLock)
1836 {
1837 // make a local copy of the shared list for processing (threading issues)
1838 myRequestedJointsToBeDeleted = new List<string>(requestedJointsToBeDeleted);
1839 }
1840
1841 foreach (string jointName in myRequestedJointsToBeDeleted)
1842 {
1843 lock (OdeLock)
1844 {
1845 //m_log.Debug("[NINJA] trying to deleting requested joint " + jointName);
1846 if (SOPName_to_activeJoint.ContainsKey(jointName) || SOPName_to_pendingJoint.ContainsKey(jointName))
1847 {
1848 OdePhysicsJoint joint = null;
1849 if (SOPName_to_activeJoint.ContainsKey(jointName))
1850 {
1851 joint = SOPName_to_activeJoint[jointName] as OdePhysicsJoint;
1852 InternalRemoveActiveJoint(joint);
1853 }
1854 else if (SOPName_to_pendingJoint.ContainsKey(jointName))
1855 {
1856 joint = SOPName_to_pendingJoint[jointName] as OdePhysicsJoint;
1857 InternalRemovePendingJoint(joint);
1858 }
1859
1860 if (joint != null)
1861 {
1862 //m_log.Debug("joint.BodyNames.Count is " + joint.BodyNames.Count + " and contents " + joint.BodyNames);
1863 for (int iBodyName = 0; iBodyName < 2; iBodyName++)
1864 {
1865 string bodyName = joint.BodyNames[iBodyName];
1866 if (bodyName != "NULL")
1867 {
1868 joints_connecting_actor[bodyName].Remove(joint);
1869 if (joints_connecting_actor[bodyName].Count == 0)
1870 {
1871 joints_connecting_actor.Remove(bodyName);
1872 }
1873 }
1874 }
1875
1876 DoJointDeactivated(joint);
1877 if (joint.jointID != IntPtr.Zero)
1878 {
1879 d.JointDestroy(joint.jointID);
1880 joint.jointID = IntPtr.Zero;
1881 //DoJointErrorMessage(joint, "successfully destroyed joint " + jointName);
1882 }
1883 else
1884 {
1885 //m_log.Warn("[NINJA] Ignoring re-request to destroy joint " + jointName);
1886 }
1887 }
1888 else
1889 {
1890 // DoJointErrorMessage(joint, "coult not find joint to destroy based on name " + jointName);
1891 }
1892 }
1893 else
1894 {
1895 // DoJointErrorMessage(joint, "WARNING - joint removal failed, joint " + jointName);
1896 }
1897 }
1898 }
1899
1900 // remove processed joints from the shared list
1901 lock (externalJointRequestsLock)
1902 {
1903 foreach (string jointName in myRequestedJointsToBeDeleted)
1904 {
1905 requestedJointsToBeDeleted.Remove(jointName);
1906 }
1907 }
1908 }
1909
1910 // for pending joints we don't know if their associated bodies exist yet or not.
1911 // the joint is actually created during processing of the taints
1912 private void CreateRequestedJoints()
1913 {
1914 List<PhysicsJoint> myRequestedJointsToBeCreated;
1915 lock (externalJointRequestsLock)
1916 {
1917 // make a local copy of the shared list for processing (threading issues)
1918 myRequestedJointsToBeCreated = new List<PhysicsJoint>(requestedJointsToBeCreated);
1919 }
1920
1921 foreach (PhysicsJoint joint in myRequestedJointsToBeCreated)
1922 {
1923 lock (OdeLock)
1924 {
1925 if (SOPName_to_pendingJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_pendingJoint[joint.ObjectNameInScene] != null)
1926 {
1927 DoJointErrorMessage(joint, "WARNING: ignoring request to re-add already pending joint Name:" + joint.ObjectNameInScene + " type:" + joint.Type + " parms: " + joint.RawParams + " pos: " + joint.Position + " rot:" + joint.Rotation);
1928 continue;
1929 }
1930 if (SOPName_to_activeJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_activeJoint[joint.ObjectNameInScene] != null)
1931 {
1932 DoJointErrorMessage(joint, "WARNING: ignoring request to re-add already active joint Name:" + joint.ObjectNameInScene + " type:" + joint.Type + " parms: " + joint.RawParams + " pos: " + joint.Position + " rot:" + joint.Rotation);
1933 continue;
1934 }
1935
1936 InternalAddPendingJoint(joint as OdePhysicsJoint);
1937
1938 if (joint.BodyNames.Count >= 2)
1939 {
1940 for (int iBodyName = 0; iBodyName < 2; iBodyName++)
1941 {
1942 string bodyName = joint.BodyNames[iBodyName];
1943 if (bodyName != "NULL")
1944 {
1945 if (!joints_connecting_actor.ContainsKey(bodyName))
1946 {
1947 joints_connecting_actor.Add(bodyName, new List<PhysicsJoint>());
1948 }
1949 joints_connecting_actor[bodyName].Add(joint);
1950 }
1951 }
1952 }
1953 }
1954 }
1955
1956 // remove processed joints from shared list
1957 lock (externalJointRequestsLock)
1958 {
1959 foreach (PhysicsJoint joint in myRequestedJointsToBeCreated)
1960 {
1961 requestedJointsToBeCreated.Remove(joint);
1962 }
1963 }
1964 }
1965
1966 /// <summary>
1967 /// Add a request for joint creation.
1968 /// </summary>
1969 /// <remarks>
1970 /// this joint will just be added to a waiting list that is NOT processed during the main
1971 /// Simulate() loop (to avoid deadlocks). After Simulate() is finished, we handle unprocessed joint requests.
1972 /// </remarks>
1973 /// <param name="objectNameInScene"></param>
1974 /// <param name="jointType"></param>
1975 /// <param name="position"></param>
1976 /// <param name="rotation"></param>
1977 /// <param name="parms"></param>
1978 /// <param name="bodyNames"></param>
1979 /// <param name="trackedBodyName"></param>
1980 /// <param name="localRotation"></param>
1981 /// <returns></returns>
1982 public override PhysicsJoint RequestJointCreation(
1983 string objectNameInScene, PhysicsJointType jointType, Vector3 position,
1984 Quaternion rotation, string parms, List<string> bodyNames, string trackedBodyName, Quaternion localRotation)
1985 {
1986 OdePhysicsJoint joint = new OdePhysicsJoint();
1987 joint.ObjectNameInScene = objectNameInScene;
1988 joint.Type = jointType;
1989 joint.Position = position;
1990 joint.Rotation = rotation;
1991 joint.RawParams = parms;
1992 joint.BodyNames = new List<string>(bodyNames);
1993 joint.TrackedBodyName = trackedBodyName;
1994 joint.LocalRotation = localRotation;
1995 joint.jointID = IntPtr.Zero;
1996 joint.ErrorMessageCount = 0;
1997
1998 lock (externalJointRequestsLock)
1999 {
2000 if (!requestedJointsToBeCreated.Contains(joint)) // forbid same creation request from entering twice
2001 {
2002 requestedJointsToBeCreated.Add(joint);
2003 }
2004 }
2005
2006 return joint;
2007 }
2008
2009 private void RemoveAllJointsConnectedToActor(PhysicsActor actor)
2010 {
2011 //m_log.Debug("RemoveAllJointsConnectedToActor: start");
2012 if (actor.SOPName != null && joints_connecting_actor.ContainsKey(actor.SOPName) && joints_connecting_actor[actor.SOPName] != null)
2013 {
2014
2015 List<PhysicsJoint> jointsToRemove = new List<PhysicsJoint>();
2016 //TODO: merge these 2 loops (originally it was needed to avoid altering a list being iterated over, but it is no longer needed due to the joint request queue mechanism)
2017 foreach (PhysicsJoint j in joints_connecting_actor[actor.SOPName])
2018 {
2019 jointsToRemove.Add(j);
2020 }
2021 foreach (PhysicsJoint j in jointsToRemove)
2022 {
2023 //m_log.Debug("RemoveAllJointsConnectedToActor: about to request deletion of " + j.ObjectNameInScene);
2024 RequestJointDeletion(j.ObjectNameInScene);
2025 //m_log.Debug("RemoveAllJointsConnectedToActor: done request deletion of " + j.ObjectNameInScene);
2026 j.TrackedBodyName = null; // *IMMEDIATELY* prevent any further movement of this joint (else a deleted actor might cause spurious tracking motion of the joint for a few frames, leading to the joint proxy object disappearing)
2027 }
2028 }
2029 }
2030
2031 public override void RemoveAllJointsConnectedToActorThreadLocked(PhysicsActor actor)
2032 {
2033 //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: start");
2034 lock (OdeLock)
2035 {
2036 //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: got lock");
2037 RemoveAllJointsConnectedToActor(actor);
2038 }
2039 }
2040
2041 // normally called from within OnJointMoved, which is called from within a lock (OdeLock)
2042 public override Vector3 GetJointAnchor(PhysicsJoint joint)
2043 {
2044 Debug.Assert(joint.IsInPhysicsEngine);
2045 d.Vector3 pos = new d.Vector3();
2046
2047 if (!(joint is OdePhysicsJoint))
2048 {
2049 DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene);
2050 }
2051 else
2052 {
2053 OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint;
2054 switch (odeJoint.Type)
2055 {
2056 case PhysicsJointType.Ball:
2057 d.JointGetBallAnchor(odeJoint.jointID, out pos);
2058 break;
2059 case PhysicsJointType.Hinge:
2060 d.JointGetHingeAnchor(odeJoint.jointID, out pos);
2061 break;
2062 }
2063 }
2064 return new Vector3(pos.X, pos.Y, pos.Z);
2065 }
2066
2067 /// <summary>
2068 /// Get joint axis.
2069 /// </summary>
2070 /// <remarks>
2071 /// normally called from within OnJointMoved, which is called from within a lock (OdeLock)
2072 /// WARNING: ODE sometimes returns <0,0,0> as the joint axis! Therefore this function
2073 /// appears to be unreliable. Fortunately we can compute the joint axis ourselves by
2074 /// keeping track of the joint's original orientation relative to one of the involved bodies.
2075 /// </remarks>
2076 /// <param name="joint"></param>
2077 /// <returns></returns>
2078 public override Vector3 GetJointAxis(PhysicsJoint joint)
2079 {
2080 Debug.Assert(joint.IsInPhysicsEngine);
2081 d.Vector3 axis = new d.Vector3();
2082
2083 if (!(joint is OdePhysicsJoint))
2084 {
2085 DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene);
2086 }
2087 else
2088 {
2089 OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint;
2090 switch (odeJoint.Type)
2091 {
2092 case PhysicsJointType.Ball:
2093 DoJointErrorMessage(joint, "warning - axis requested for ball joint: " + joint.ObjectNameInScene);
2094 break;
2095 case PhysicsJointType.Hinge:
2096 d.JointGetHingeAxis(odeJoint.jointID, out axis);
2097 break;
2098 }
2099 }
2100 return new Vector3(axis.X, axis.Y, axis.Z);
2101 }
2102
2103 public void remActivePrim(OdePrim deactivatePrim)
2104 {
2105 lock (_activeprims)
2106 {
2107 _activeprims.Remove(deactivatePrim);
2108 }
2109 }
2110
2111 public override void RemovePrim(PhysicsActor prim)
2112 {
2113 if (prim is OdePrim)
2114 {
2115 lock (OdeLock)
2116 {
2117 OdePrim p = (OdePrim) prim;
2118
2119 p.setPrimForRemoval();
2120 AddPhysicsActorTaint(prim);
2121 //RemovePrimThreadLocked(p);
2122 }
2123 }
2124 }
2125
2126 /// <summary>
2127 /// This is called from within simulate but outside the locked portion
2128 /// We need to do our own locking here
2129 /// Essentially, we need to remove the prim from our space segment, whatever segment it's in.
2130 ///
2131 /// If there are no more prim in the segment, we need to empty (spacedestroy)the segment and reclaim memory
2132 /// that the space was using.
2133 /// </summary>
2134 /// <param name="prim"></param>
2135 public void RemovePrimThreadLocked(OdePrim prim)
2136 {
2137//Console.WriteLine("RemovePrimThreadLocked " + prim.m_primName);
2138 lock (prim)
2139 {
2140 remCollisionEventReporting(prim);
2141 lock (ode)
2142 {
2143 if (prim.prim_geom != IntPtr.Zero)
2144 {
2145 prim.ResetTaints();
2146
2147 if (prim.IsPhysical)
2148 {
2149 prim.disableBody();
2150 if (prim.childPrim)
2151 {
2152 prim.childPrim = false;
2153 prim.Body = IntPtr.Zero;
2154 prim.m_disabled = true;
2155 prim.IsPhysical = false;
2156 }
2157
2158
2159 }
2160 // we don't want to remove the main space
2161
2162 // If the geometry is in the targetspace, remove it from the target space
2163 //m_log.Warn(prim.m_targetSpace);
2164
2165 //if (prim.m_targetSpace != IntPtr.Zero)
2166 //{
2167 //if (d.SpaceQuery(prim.m_targetSpace, prim.prim_geom))
2168 //{
2169
2170 //if (d.GeomIsSpace(prim.m_targetSpace))
2171 //{
2172 //waitForSpaceUnlock(prim.m_targetSpace);
2173 //d.SpaceRemove(prim.m_targetSpace, prim.prim_geom);
2174 prim.m_targetSpace = IntPtr.Zero;
2175 //}
2176 //else
2177 //{
2178 // m_log.Info("[Physics]: Invalid Scene passed to 'removeprim from scene':" +
2179 //((OdePrim)prim).m_targetSpace.ToString());
2180 //}
2181
2182 //}
2183 //}
2184 //m_log.Warn(prim.prim_geom);
2185 try
2186 {
2187 if (prim.prim_geom != IntPtr.Zero)
2188 {
2189 d.GeomDestroy(prim.prim_geom);
2190 prim.prim_geom = IntPtr.Zero;
2191 }
2192 else
2193 {
2194 m_log.Warn("[PHYSICS]: Unable to remove prim from physics scene");
2195 }
2196 }
2197 catch (AccessViolationException)
2198 {
2199 m_log.Info("[PHYSICS]: Couldn't remove prim from physics scene, it was already be removed.");
2200 }
2201 lock (_prims)
2202 _prims.Remove(prim);
2203
2204 //If there are no more geometries in the sub-space, we don't need it in the main space anymore
2205 //if (d.SpaceGetNumGeoms(prim.m_targetSpace) == 0)
2206 //{
2207 //if (prim.m_targetSpace != null)
2208 //{
2209 //if (d.GeomIsSpace(prim.m_targetSpace))
2210 //{
2211 //waitForSpaceUnlock(prim.m_targetSpace);
2212 //d.SpaceRemove(space, prim.m_targetSpace);
2213 // free up memory used by the space.
2214 //d.SpaceDestroy(prim.m_targetSpace);
2215 //int[] xyspace = calculateSpaceArrayItemFromPos(prim.Position);
2216 //resetSpaceArrayItemToZero(xyspace[0], xyspace[1]);
2217 //}
2218 //else
2219 //{
2220 //m_log.Info("[Physics]: Invalid Scene passed to 'removeprim from scene':" +
2221 //((OdePrim) prim).m_targetSpace.ToString());
2222 //}
2223 //}
2224 //}
2225
2226 if (SupportsNINJAJoints)
2227 {
2228 RemoveAllJointsConnectedToActorThreadLocked(prim);
2229 }
2230 }
2231 }
2232 }
2233 }
2234
2235 #endregion
2236
2237 #region Space Separation Calculation
2238
2239 /// <summary>
2240 /// Takes a space pointer and zeros out the array we're using to hold the spaces
2241 /// </summary>
2242 /// <param name="pSpace"></param>
2243 public void resetSpaceArrayItemToZero(IntPtr pSpace)
2244 {
2245 for (int x = 0; x < staticPrimspace.GetLength(0); x++)
2246 {
2247 for (int y = 0; y < staticPrimspace.GetLength(1); y++)
2248 {
2249 if (staticPrimspace[x, y] == pSpace)
2250 staticPrimspace[x, y] = IntPtr.Zero;
2251 }
2252 }
2253 }
2254
2255 public void resetSpaceArrayItemToZero(int arrayitemX, int arrayitemY)
2256 {
2257 staticPrimspace[arrayitemX, arrayitemY] = IntPtr.Zero;
2258 }
2259
2260 /// <summary>
2261 /// Called when a static prim moves. Allocates a space for the prim based on its position
2262 /// </summary>
2263 /// <param name="geom">the pointer to the geom that moved</param>
2264 /// <param name="pos">the position that the geom moved to</param>
2265 /// <param name="currentspace">a pointer to the space it was in before it was moved.</param>
2266 /// <returns>a pointer to the new space it's in</returns>
2267 public IntPtr recalculateSpaceForGeom(IntPtr geom, Vector3 pos, IntPtr currentspace)
2268 {
2269 // Called from setting the Position and Size of an ODEPrim so
2270 // it's already in locked space.
2271
2272 // we don't want to remove the main space
2273 // we don't need to test physical here because this function should
2274 // never be called if the prim is physical(active)
2275
2276 // All physical prim end up in the root space
2277 //Thread.Sleep(20);
2278 if (currentspace != space)
2279 {
2280 //m_log.Info("[SPACE]: C:" + currentspace.ToString() + " g:" + geom.ToString());
2281 //if (currentspace == IntPtr.Zero)
2282 //{
2283 //int adfadf = 0;
2284 //}
2285 if (d.SpaceQuery(currentspace, geom) && currentspace != IntPtr.Zero)
2286 {
2287 if (d.GeomIsSpace(currentspace))
2288 {
2289 waitForSpaceUnlock(currentspace);
2290 d.SpaceRemove(currentspace, geom);
2291 }
2292 else
2293 {
2294 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" + currentspace +
2295 " Geom:" + geom);
2296 }
2297 }
2298 else
2299 {
2300 IntPtr sGeomIsIn = d.GeomGetSpace(geom);
2301 if (sGeomIsIn != IntPtr.Zero)
2302 {
2303 if (d.GeomIsSpace(currentspace))
2304 {
2305 waitForSpaceUnlock(sGeomIsIn);
2306 d.SpaceRemove(sGeomIsIn, geom);
2307 }
2308 else
2309 {
2310 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2311 sGeomIsIn + " Geom:" + geom);
2312 }
2313 }
2314 }
2315
2316 //If there are no more geometries in the sub-space, we don't need it in the main space anymore
2317 if (d.SpaceGetNumGeoms(currentspace) == 0)
2318 {
2319 if (currentspace != IntPtr.Zero)
2320 {
2321 if (d.GeomIsSpace(currentspace))
2322 {
2323 waitForSpaceUnlock(currentspace);
2324 waitForSpaceUnlock(space);
2325 d.SpaceRemove(space, currentspace);
2326 // free up memory used by the space.
2327
2328 //d.SpaceDestroy(currentspace);
2329 resetSpaceArrayItemToZero(currentspace);
2330 }
2331 else
2332 {
2333 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2334 currentspace + " Geom:" + geom);
2335 }
2336 }
2337 }
2338 }
2339 else
2340 {
2341 // this is a physical object that got disabled. ;.;
2342 if (currentspace != IntPtr.Zero && geom != IntPtr.Zero)
2343 {
2344 if (d.SpaceQuery(currentspace, geom))
2345 {
2346 if (d.GeomIsSpace(currentspace))
2347 {
2348 waitForSpaceUnlock(currentspace);
2349 d.SpaceRemove(currentspace, geom);
2350 }
2351 else
2352 {
2353 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2354 currentspace + " Geom:" + geom);
2355 }
2356 }
2357 else
2358 {
2359 IntPtr sGeomIsIn = d.GeomGetSpace(geom);
2360 if (sGeomIsIn != IntPtr.Zero)
2361 {
2362 if (d.GeomIsSpace(sGeomIsIn))
2363 {
2364 waitForSpaceUnlock(sGeomIsIn);
2365 d.SpaceRemove(sGeomIsIn, geom);
2366 }
2367 else
2368 {
2369 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2370 sGeomIsIn + " Geom:" + geom);
2371 }
2372 }
2373 }
2374 }
2375 }
2376
2377 // The routines in the Position and Size sections do the 'inserting' into the space,
2378 // so all we have to do is make sure that the space that we're putting the prim into
2379 // is in the 'main' space.
2380 int[] iprimspaceArrItem = calculateSpaceArrayItemFromPos(pos);
2381 IntPtr newspace = calculateSpaceForGeom(pos);
2382
2383 if (newspace == IntPtr.Zero)
2384 {
2385 newspace = createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]);
2386 d.HashSpaceSetLevels(newspace, smallHashspaceLow, smallHashspaceHigh);
2387 }
2388
2389 return newspace;
2390 }
2391
2392 /// <summary>
2393 /// Creates a new space at X Y
2394 /// </summary>
2395 /// <param name="iprimspaceArrItemX"></param>
2396 /// <param name="iprimspaceArrItemY"></param>
2397 /// <returns>A pointer to the created space</returns>
2398 public IntPtr createprimspace(int iprimspaceArrItemX, int iprimspaceArrItemY)
2399 {
2400 // creating a new space for prim and inserting it into main space.
2401 staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY] = d.HashSpaceCreate(IntPtr.Zero);
2402 d.GeomSetCategoryBits(staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY], (int)CollisionCategories.Space);
2403 waitForSpaceUnlock(space);
2404 d.SpaceSetSublevel(space, 1);
2405 d.SpaceAdd(space, staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY]);
2406 return staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY];
2407 }
2408
2409 /// <summary>
2410 /// Calculates the space the prim should be in by its position
2411 /// </summary>
2412 /// <param name="pos"></param>
2413 /// <returns>a pointer to the space. This could be a new space or reused space.</returns>
2414 public IntPtr calculateSpaceForGeom(Vector3 pos)
2415 {
2416 int[] xyspace = calculateSpaceArrayItemFromPos(pos);
2417 //m_log.Info("[Physics]: Attempting to use arrayItem: " + xyspace[0].ToString() + "," + xyspace[1].ToString());
2418 return staticPrimspace[xyspace[0], xyspace[1]];
2419 }
2420
2421 /// <summary>
2422 /// Holds the space allocation logic
2423 /// </summary>
2424 /// <param name="pos"></param>
2425 /// <returns>an array item based on the position</returns>
2426 public int[] calculateSpaceArrayItemFromPos(Vector3 pos)
2427 {
2428 int[] returnint = new int[2];
2429
2430 returnint[0] = (int) (pos.X/metersInSpace);
2431
2432 if (returnint[0] > ((int) (259f/metersInSpace)))
2433 returnint[0] = ((int) (259f/metersInSpace));
2434 if (returnint[0] < 0)
2435 returnint[0] = 0;
2436
2437 returnint[1] = (int) (pos.Y/metersInSpace);
2438 if (returnint[1] > ((int) (259f/metersInSpace)))
2439 returnint[1] = ((int) (259f/metersInSpace));
2440 if (returnint[1] < 0)
2441 returnint[1] = 0;
2442
2443 return returnint;
2444 }
2445
2446 #endregion
2447
2448 /// <summary>
2449 /// Routine to figure out if we need to mesh this prim with our mesher
2450 /// </summary>
2451 /// <param name="pbs"></param>
2452 /// <returns></returns>
2453 public bool needsMeshing(PrimitiveBaseShape pbs)
2454 {
2455 // most of this is redundant now as the mesher will return null if it cant mesh a prim
2456 // but we still need to check for sculptie meshing being enabled so this is the most
2457 // convenient place to do it for now...
2458
2459 // //if (pbs.PathCurve == (byte)Primitive.PathCurve.Circle && pbs.ProfileCurve == (byte)Primitive.ProfileCurve.Circle && pbs.PathScaleY <= 0.75f)
2460 // //m_log.Debug("needsMeshing: " + " pathCurve: " + pbs.PathCurve.ToString() + " profileCurve: " + pbs.ProfileCurve.ToString() + " pathScaleY: " + Primitive.UnpackPathScale(pbs.PathScaleY).ToString());
2461 int iPropertiesNotSupportedDefault = 0;
2462
2463 if (pbs.SculptEntry && !meshSculptedPrim)
2464 {
2465#if SPAM
2466 m_log.Warn("NonMesh");
2467#endif
2468 return false;
2469 }
2470
2471 // if it's a standard box or sphere with no cuts, hollows, twist or top shear, return false since ODE can use an internal representation for the prim
2472 if (!forceSimplePrimMeshing && !pbs.SculptEntry)
2473 {
2474 if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
2475 || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1
2476 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z))
2477 {
2478
2479 if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
2480 && pbs.ProfileHollow == 0
2481 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
2482 && pbs.PathBegin == 0 && pbs.PathEnd == 0
2483 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
2484 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
2485 && pbs.PathShearX == 0 && pbs.PathShearY == 0)
2486 {
2487#if SPAM
2488 m_log.Warn("NonMesh");
2489#endif
2490 return false;
2491 }
2492 }
2493 }
2494
2495 if (pbs.ProfileHollow != 0)
2496 iPropertiesNotSupportedDefault++;
2497
2498 if ((pbs.PathBegin != 0) || pbs.PathEnd != 0)
2499 iPropertiesNotSupportedDefault++;
2500
2501 if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0))
2502 iPropertiesNotSupportedDefault++;
2503
2504 if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0)
2505 iPropertiesNotSupportedDefault++;
2506
2507 if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100))
2508 iPropertiesNotSupportedDefault++;
2509
2510 if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0))
2511 iPropertiesNotSupportedDefault++;
2512
2513 if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight)
2514 iPropertiesNotSupportedDefault++;
2515
2516 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 && (pbs.Scale.X != pbs.Scale.Y || pbs.Scale.Y != pbs.Scale.Z || pbs.Scale.Z != pbs.Scale.X))
2517 iPropertiesNotSupportedDefault++;
2518
2519 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte) Extrusion.Curve1)
2520 iPropertiesNotSupportedDefault++;
2521
2522 // test for torus
2523 if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square)
2524 {
2525 if (pbs.PathCurve == (byte)Extrusion.Curve1)
2526 {
2527 iPropertiesNotSupportedDefault++;
2528 }
2529 }
2530 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
2531 {
2532 if (pbs.PathCurve == (byte)Extrusion.Straight)
2533 {
2534 iPropertiesNotSupportedDefault++;
2535 }
2536
2537 // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits
2538 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
2539 {
2540 iPropertiesNotSupportedDefault++;
2541 }
2542 }
2543 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
2544 {
2545 if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2)
2546 {
2547 iPropertiesNotSupportedDefault++;
2548 }
2549 }
2550 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
2551 {
2552 if (pbs.PathCurve == (byte)Extrusion.Straight)
2553 {
2554 iPropertiesNotSupportedDefault++;
2555 }
2556 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
2557 {
2558 iPropertiesNotSupportedDefault++;
2559 }
2560 }
2561
2562 if (pbs.SculptEntry && meshSculptedPrim)
2563 iPropertiesNotSupportedDefault++;
2564
2565 if (iPropertiesNotSupportedDefault == 0)
2566 {
2567#if SPAM
2568 m_log.Warn("NonMesh");
2569#endif
2570 return false;
2571 }
2572#if SPAM
2573 m_log.Debug("Mesh");
2574#endif
2575 return true;
2576 }
2577
2578 /// <summary>
2579 /// Called after our prim properties are set Scale, position etc.
2580 /// We use this event queue like method to keep changes to the physical scene occuring in the threadlocked mutex
2581 /// This assures us that we have no race conditions
2582 /// </summary>
2583 /// <param name="prim"></param>
2584 public override void AddPhysicsActorTaint(PhysicsActor prim)
2585 {
2586 if (prim is OdePrim)
2587 {
2588 OdePrim taintedprim = ((OdePrim) prim);
2589 lock (_taintedPrimLock)
2590 {
2591 if (!(_taintedPrimH.Contains(taintedprim)))
2592 {
2593//Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.m_primName);
2594 _taintedPrimH.Add(taintedprim); // HashSet for searching
2595 _taintedPrimL.Add(taintedprim); // List for ordered readout
2596 }
2597 }
2598 return;
2599 }
2600 else if (prim is OdeCharacter)
2601 {
2602 OdeCharacter taintedchar = ((OdeCharacter)prim);
2603 lock (_taintedActors)
2604 {
2605 if (!(_taintedActors.Contains(taintedchar)))
2606 {
2607 _taintedActors.Add(taintedchar);
2608 if (taintedchar.bad)
2609 m_log.DebugFormat("[PHYSICS]: Added BAD actor {0} to tainted actors", taintedchar.m_uuid);
2610 }
2611 }
2612 }
2613 }
2614
2615 /// <summary>
2616 /// This is our main simulate loop
2617 /// It's thread locked by a Mutex in the scene.
2618 /// It holds Collisions, it instructs ODE to step through the physical reactions
2619 /// It moves the objects around in memory
2620 /// It calls the methods that report back to the object owners.. (scenepresence, SceneObjectGroup)
2621 /// </summary>
2622 /// <param name="timeStep"></param>
2623 /// <returns></returns>
2624 public override float Simulate(float timeStep)
2625 {
2626 if (framecount >= int.MaxValue)
2627 framecount = 0;
2628
2629 //if (m_worldOffset != Vector3.Zero)
2630 // return 0;
2631
2632 framecount++;
2633
2634 float fps = 0;
2635 //m_log.Info(timeStep.ToString());
2636 step_time += timeStep;
2637
2638 // If We're loaded down by something else,
2639 // or debugging with the Visual Studio project on pause
2640 // skip a few frames to catch up gracefully.
2641 // without shooting the physicsactors all over the place
2642
2643 if (step_time >= m_SkipFramesAtms)
2644 {
2645 // Instead of trying to catch up, it'll do 5 physics frames only
2646 step_time = ODE_STEPSIZE;
2647 m_physicsiterations = 5;
2648 }
2649 else
2650 {
2651 m_physicsiterations = 10;
2652 }
2653
2654 if (SupportsNINJAJoints)
2655 {
2656 DeleteRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks
2657 CreateRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks
2658 }
2659
2660 lock (OdeLock)
2661 {
2662 // Process 10 frames if the sim is running normal..
2663 // process 5 frames if the sim is running slow
2664 //try
2665 //{
2666 //d.WorldSetQuickStepNumIterations(world, m_physicsiterations);
2667 //}
2668 //catch (StackOverflowException)
2669 //{
2670 // m_log.Error("[PHYSICS]: The operating system wasn't able to allocate enough memory for the simulation. Restarting the sim.");
2671 // ode.drelease(world);
2672 //base.TriggerPhysicsBasedRestart();
2673 //}
2674
2675 int i = 0;
2676
2677 // Figure out the Frames Per Second we're going at.
2678 //(step_time == 0.004f, there's 250 of those per second. Times the step time/step size
2679
2680 fps = (step_time / ODE_STEPSIZE) * 1000;
2681 // HACK: Using a time dilation of 1.0 to debug rubberbanding issues
2682 //m_timeDilation = Math.Min((step_time / ODE_STEPSIZE) / (0.09375f / ODE_STEPSIZE), 1.0f);
2683
2684 step_time = 0.09375f;
2685
2686 while (step_time > 0.0f)
2687 {
2688 //lock (ode)
2689 //{
2690 //if (!ode.lockquery())
2691 //{
2692 // ode.dlock(world);
2693 try
2694 {
2695 // Insert, remove Characters
2696 bool processedtaints = false;
2697
2698 lock (_taintedActors)
2699 {
2700 if (_taintedActors.Count > 0)
2701 {
2702 foreach (OdeCharacter character in _taintedActors)
2703 {
2704 character.ProcessTaints(timeStep);
2705
2706 processedtaints = true;
2707 //character.m_collisionscore = 0;
2708 }
2709
2710 if (processedtaints)
2711 _taintedActors.Clear();
2712 }
2713 }
2714
2715 // Modify other objects in the scene.
2716 processedtaints = false;
2717
2718 lock (_taintedPrimLock)
2719 {
2720 foreach (OdePrim prim in _taintedPrimL)
2721 {
2722 if (prim.m_taintremove)
2723 {
2724 //Console.WriteLine("Simulate calls RemovePrimThreadLocked");
2725 RemovePrimThreadLocked(prim);
2726 }
2727 else
2728 {
2729 //Console.WriteLine("Simulate calls ProcessTaints");
2730 prim.ProcessTaints(timeStep);
2731 }
2732 processedtaints = true;
2733 prim.m_collisionscore = 0;
2734
2735 // This loop can block up the Heartbeat for a very long time on large regions.
2736 // We need to let the Watchdog know that the Heartbeat is not dead
2737 // NOTE: This is currently commented out, but if things like OAR loading are
2738 // timing the heartbeat out we will need to uncomment it
2739 //Watchdog.UpdateThread();
2740 }
2741
2742 if (SupportsNINJAJoints)
2743 {
2744 // Create pending joints, if possible
2745
2746 // joints can only be processed after ALL bodies are processed (and exist in ODE), since creating
2747 // a joint requires specifying the body id of both involved bodies
2748 if (pendingJoints.Count > 0)
2749 {
2750 List<PhysicsJoint> successfullyProcessedPendingJoints = new List<PhysicsJoint>();
2751 //DoJointErrorMessage(joints_connecting_actor, "taint: " + pendingJoints.Count + " pending joints");
2752 foreach (PhysicsJoint joint in pendingJoints)
2753 {
2754 //DoJointErrorMessage(joint, "taint: time to create joint with parms: " + joint.RawParams);
2755 string[] jointParams = joint.RawParams.Split(" ".ToCharArray(), System.StringSplitOptions.RemoveEmptyEntries);
2756 List<IntPtr> jointBodies = new List<IntPtr>();
2757 bool allJointBodiesAreReady = true;
2758 foreach (string jointParam in jointParams)
2759 {
2760 if (jointParam == "NULL")
2761 {
2762 //DoJointErrorMessage(joint, "attaching NULL joint to world");
2763 jointBodies.Add(IntPtr.Zero);
2764 }
2765 else
2766 {
2767 //DoJointErrorMessage(joint, "looking for prim name: " + jointParam);
2768 bool foundPrim = false;
2769 lock (_prims)
2770 {
2771 foreach (OdePrim prim in _prims) // FIXME: inefficient
2772 {
2773 if (prim.SOPName == jointParam)
2774 {
2775 //DoJointErrorMessage(joint, "found for prim name: " + jointParam);
2776 if (prim.IsPhysical && prim.Body != IntPtr.Zero)
2777 {
2778 jointBodies.Add(prim.Body);
2779 foundPrim = true;
2780 break;
2781 }
2782 else
2783 {
2784 DoJointErrorMessage(joint, "prim name " + jointParam +
2785 " exists but is not (yet) physical; deferring joint creation. " +
2786 "IsPhysical property is " + prim.IsPhysical +
2787 " and body is " + prim.Body);
2788 foundPrim = false;
2789 break;
2790 }
2791 }
2792 }
2793 }
2794 if (foundPrim)
2795 {
2796 // all is fine
2797 }
2798 else
2799 {
2800 allJointBodiesAreReady = false;
2801 break;
2802 }
2803 }
2804 }
2805 if (allJointBodiesAreReady)
2806 {
2807 //DoJointErrorMessage(joint, "allJointBodiesAreReady for " + joint.ObjectNameInScene + " with parms " + joint.RawParams);
2808 if (jointBodies[0] == jointBodies[1])
2809 {
2810 DoJointErrorMessage(joint, "ERROR: joint cannot be created; the joint bodies are the same, body1==body2. Raw body is " + jointBodies[0] + ". raw parms: " + joint.RawParams);
2811 }
2812 else
2813 {
2814 switch (joint.Type)
2815 {
2816 case PhysicsJointType.Ball:
2817 {
2818 IntPtr odeJoint;
2819 //DoJointErrorMessage(joint, "ODE creating ball joint ");
2820 odeJoint = d.JointCreateBall(world, IntPtr.Zero);
2821 //DoJointErrorMessage(joint, "ODE attaching ball joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]);
2822 d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]);
2823 //DoJointErrorMessage(joint, "ODE setting ball anchor: " + odeJoint + " to vec:" + joint.Position);
2824 d.JointSetBallAnchor(odeJoint,
2825 joint.Position.X,
2826 joint.Position.Y,
2827 joint.Position.Z);
2828 //DoJointErrorMessage(joint, "ODE joint setting OK");
2829 //DoJointErrorMessage(joint, "The ball joint's bodies are here: b0: ");
2830 //DoJointErrorMessage(joint, "" + (jointBodies[0] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[0]) : "fixed environment"));
2831 //DoJointErrorMessage(joint, "The ball joint's bodies are here: b1: ");
2832 //DoJointErrorMessage(joint, "" + (jointBodies[1] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[1]) : "fixed environment"));
2833
2834 if (joint is OdePhysicsJoint)
2835 {
2836 ((OdePhysicsJoint)joint).jointID = odeJoint;
2837 }
2838 else
2839 {
2840 DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!");
2841 }
2842 }
2843 break;
2844 case PhysicsJointType.Hinge:
2845 {
2846 IntPtr odeJoint;
2847 //DoJointErrorMessage(joint, "ODE creating hinge joint ");
2848 odeJoint = d.JointCreateHinge(world, IntPtr.Zero);
2849 //DoJointErrorMessage(joint, "ODE attaching hinge joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]);
2850 d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]);
2851 //DoJointErrorMessage(joint, "ODE setting hinge anchor: " + odeJoint + " to vec:" + joint.Position);
2852 d.JointSetHingeAnchor(odeJoint,
2853 joint.Position.X,
2854 joint.Position.Y,
2855 joint.Position.Z);
2856 // We use the orientation of the x-axis of the joint's coordinate frame
2857 // as the axis for the hinge.
2858
2859 // Therefore, we must get the joint's coordinate frame based on the
2860 // joint.Rotation field, which originates from the orientation of the
2861 // joint's proxy object in the scene.
2862
2863 // The joint's coordinate frame is defined as the transformation matrix
2864 // that converts a vector from joint-local coordinates into world coordinates.
2865 // World coordinates are defined as the XYZ coordinate system of the sim,
2866 // as shown in the top status-bar of the viewer.
2867
2868 // Once we have the joint's coordinate frame, we extract its X axis (AtAxis)
2869 // and use that as the hinge axis.
2870
2871 //joint.Rotation.Normalize();
2872 Matrix4 proxyFrame = Matrix4.CreateFromQuaternion(joint.Rotation);
2873
2874 // Now extract the X axis of the joint's coordinate frame.
2875
2876 // Do not try to use proxyFrame.AtAxis or you will become mired in the
2877 // tar pit of transposed, inverted, and generally messed-up orientations.
2878 // (In other words, Matrix4.AtAxis() is borked.)
2879 // Vector3 jointAxis = proxyFrame.AtAxis; <--- this path leadeth to madness
2880
2881 // Instead, compute the X axis of the coordinate frame by transforming
2882 // the (1,0,0) vector. At least that works.
2883
2884 //m_log.Debug("PHY: making axis: complete matrix is " + proxyFrame);
2885 Vector3 jointAxis = Vector3.Transform(Vector3.UnitX, proxyFrame);
2886 //m_log.Debug("PHY: making axis: hinge joint axis is " + jointAxis);
2887 //DoJointErrorMessage(joint, "ODE setting hinge axis: " + odeJoint + " to vec:" + jointAxis);
2888 d.JointSetHingeAxis(odeJoint,
2889 jointAxis.X,
2890 jointAxis.Y,
2891 jointAxis.Z);
2892 //d.JointSetHingeParam(odeJoint, (int)dParam.CFM, 0.1f);
2893 if (joint is OdePhysicsJoint)
2894 {
2895 ((OdePhysicsJoint)joint).jointID = odeJoint;
2896 }
2897 else
2898 {
2899 DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!");
2900 }
2901 }
2902 break;
2903 }
2904 successfullyProcessedPendingJoints.Add(joint);
2905 }
2906 }
2907 else
2908 {
2909 DoJointErrorMessage(joint, "joint could not yet be created; still pending");
2910 }
2911 }
2912 foreach (PhysicsJoint successfullyProcessedJoint in successfullyProcessedPendingJoints)
2913 {
2914 //DoJointErrorMessage(successfullyProcessedJoint, "finalizing succesfully procsssed joint " + successfullyProcessedJoint.ObjectNameInScene + " parms " + successfullyProcessedJoint.RawParams);
2915 //DoJointErrorMessage(successfullyProcessedJoint, "removing from pending");
2916 InternalRemovePendingJoint(successfullyProcessedJoint);
2917 //DoJointErrorMessage(successfullyProcessedJoint, "adding to active");
2918 InternalAddActiveJoint(successfullyProcessedJoint);
2919 //DoJointErrorMessage(successfullyProcessedJoint, "done");
2920 }
2921 }
2922 }
2923
2924 if (processedtaints)
2925//Console.WriteLine("Simulate calls Clear of _taintedPrim list");
2926 _taintedPrimH.Clear();
2927 _taintedPrimL.Clear();
2928 }
2929
2930 // Move characters
2931 lock (_characters)
2932 {
2933 List<OdeCharacter> defects = new List<OdeCharacter>();
2934 foreach (OdeCharacter actor in _characters)
2935 {
2936 if (actor != null)
2937 actor.Move(timeStep, defects);
2938 }
2939 if (0 != defects.Count)
2940 {
2941 foreach (OdeCharacter defect in defects)
2942 {
2943 RemoveCharacter(defect);
2944 }
2945 }
2946 }
2947
2948 // Move other active objects
2949 lock (_activeprims)
2950 {
2951 foreach (OdePrim prim in _activeprims)
2952 {
2953 prim.m_collisionscore = 0;
2954 prim.Move(timeStep);
2955 }
2956 }
2957
2958 //if ((framecount % m_randomizeWater) == 0)
2959 // randomizeWater(waterlevel);
2960
2961 //int RayCastTimeMS = m_rayCastManager.ProcessQueuedRequests();
2962 m_rayCastManager.ProcessQueuedRequests();
2963
2964 collision_optimized(timeStep);
2965
2966 lock (_collisionEventPrim)
2967 {
2968 foreach (PhysicsActor obj in _collisionEventPrim)
2969 {
2970 if (obj == null)
2971 continue;
2972
2973 switch ((ActorTypes)obj.PhysicsActorType)
2974 {
2975 case ActorTypes.Agent:
2976 OdeCharacter cobj = (OdeCharacter)obj;
2977 cobj.AddCollisionFrameTime(100);
2978 cobj.SendCollisions();
2979 break;
2980 case ActorTypes.Prim:
2981 OdePrim pobj = (OdePrim)obj;
2982 pobj.SendCollisions();
2983 break;
2984 }
2985 }
2986 }
2987
2988 //if (m_global_contactcount > 5)
2989 //{
2990 // m_log.DebugFormat("[PHYSICS]: Contacts:{0}", m_global_contactcount);
2991 //}
2992
2993 m_global_contactcount = 0;
2994
2995 d.WorldQuickStep(world, ODE_STEPSIZE);
2996 d.JointGroupEmpty(contactgroup);
2997 //ode.dunlock(world);
2998 }
2999 catch (Exception e)
3000 {
3001 m_log.ErrorFormat("[PHYSICS]: {0}, {1}, {2}", e.Message, e.TargetSite, e);
3002 ode.dunlock(world);
3003 }
3004
3005 step_time -= ODE_STEPSIZE;
3006 i++;
3007 //}
3008 //else
3009 //{
3010 //fps = 0;
3011 //}
3012 //}
3013 }
3014
3015 lock (_characters)
3016 {
3017 foreach (OdeCharacter actor in _characters)
3018 {
3019 if (actor != null)
3020 {
3021 if (actor.bad)
3022 m_log.WarnFormat("[PHYSICS]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid);
3023 actor.UpdatePositionAndVelocity();
3024 }
3025 }
3026 }
3027
3028 lock (_badCharacter)
3029 {
3030 if (_badCharacter.Count > 0)
3031 {
3032 foreach (OdeCharacter chr in _badCharacter)
3033 {
3034 RemoveCharacter(chr);
3035 }
3036 _badCharacter.Clear();
3037 }
3038 }
3039
3040 lock (_activeprims)
3041 {
3042 //if (timeStep < 0.2f)
3043 {
3044 foreach (OdePrim actor in _activeprims)
3045 {
3046 if (actor.IsPhysical && (d.BodyIsEnabled(actor.Body) || !actor._zeroFlag))
3047 {
3048 actor.UpdatePositionAndVelocity();
3049
3050 if (SupportsNINJAJoints)
3051 {
3052 // If an actor moved, move its joint proxy objects as well.
3053 // There seems to be an event PhysicsActor.OnPositionUpdate that could be used
3054 // for this purpose but it is never called! So we just do the joint
3055 // movement code here.
3056
3057 if (actor.SOPName != null &&
3058 joints_connecting_actor.ContainsKey(actor.SOPName) &&
3059 joints_connecting_actor[actor.SOPName] != null &&
3060 joints_connecting_actor[actor.SOPName].Count > 0)
3061 {
3062 foreach (PhysicsJoint affectedJoint in joints_connecting_actor[actor.SOPName])
3063 {
3064 if (affectedJoint.IsInPhysicsEngine)
3065 {
3066 DoJointMoved(affectedJoint);
3067 }
3068 else
3069 {
3070 DoJointErrorMessage(affectedJoint, "a body connected to a joint was moved, but the joint doesn't exist yet! this will lead to joint error. joint was: " + affectedJoint.ObjectNameInScene + " parms:" + affectedJoint.RawParams);
3071 }
3072 }
3073 }
3074 }
3075 }
3076 }
3077 }
3078 }
3079
3080 //DumpJointInfo();
3081
3082 // Finished with all sim stepping. If requested, dump world state to file for debugging.
3083 // TODO: This call to the export function is already inside lock (OdeLock) - but is an extra lock needed?
3084 // TODO: This overwrites all dump files in-place. Should this be a growing logfile, or separate snapshots?
3085 if (physics_logging && (physics_logging_interval>0) && (framecount % physics_logging_interval == 0))
3086 {
3087 string fname = "state-" + world.ToString() + ".DIF"; // give each physics world a separate filename
3088 string prefix = "world" + world.ToString(); // prefix for variable names in exported .DIF file
3089
3090 if (physics_logging_append_existing_logfile)
3091 {
3092 string header = "-------------- START OF PHYSICS FRAME " + framecount.ToString() + " --------------";
3093 TextWriter fwriter = File.AppendText(fname);
3094 fwriter.WriteLine(header);
3095 fwriter.Close();
3096 }
3097 d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix);
3098 }
3099 latertickcount = Util.EnvironmentTickCount() - tickCountFrameRun;
3100
3101 // OpenSimulator above does 10 fps. 10 fps = means that the main thread loop and physics
3102 // has a max of 100 ms to run theoretically.
3103 // If the main loop stalls, it calls Simulate later which makes the tick count ms larger.
3104 // If Physics stalls, it takes longer which makes the tick count ms larger.
3105
3106 if (latertickcount < 100)
3107 m_timeDilation = 1.0f;
3108 else
3109 {
3110 m_timeDilation = 100f / latertickcount;
3111 //m_timeDilation = Math.Min((Math.Max(100 - (Util.EnvironmentTickCount() - tickCountFrameRun), 1) / 100f), 1.0f);
3112 }
3113
3114 tickCountFrameRun = Util.EnvironmentTickCount();
3115 }
3116
3117 return fps;
3118 }
3119
3120 public override void GetResults()
3121 {
3122 }
3123
3124 public override bool IsThreaded
3125 {
3126 // for now we won't be multithreaded
3127 get { return (false); }
3128 }
3129
3130 #region ODE Specific Terrain Fixes
3131 public float[] ResizeTerrain512NearestNeighbour(float[] heightMap)
3132 {
3133 float[] returnarr = new float[262144];
3134 float[,] resultarr = new float[(int)WorldExtents.X, (int)WorldExtents.Y];
3135
3136 // Filling out the array into its multi-dimensional components
3137 for (int y = 0; y < WorldExtents.Y; y++)
3138 {
3139 for (int x = 0; x < WorldExtents.X; x++)
3140 {
3141 resultarr[y, x] = heightMap[y * (int)WorldExtents.Y + x];
3142 }
3143 }
3144
3145 // Resize using Nearest Neighbour
3146
3147 // This particular way is quick but it only works on a multiple of the original
3148
3149 // The idea behind this method can be described with the following diagrams
3150 // second pass and third pass happen in the same loop really.. just separated
3151 // them to show what this does.
3152
3153 // First Pass
3154 // ResultArr:
3155 // 1,1,1,1,1,1
3156 // 1,1,1,1,1,1
3157 // 1,1,1,1,1,1
3158 // 1,1,1,1,1,1
3159 // 1,1,1,1,1,1
3160 // 1,1,1,1,1,1
3161
3162 // Second Pass
3163 // ResultArr2:
3164 // 1,,1,,1,,1,,1,,1,
3165 // ,,,,,,,,,,
3166 // 1,,1,,1,,1,,1,,1,
3167 // ,,,,,,,,,,
3168 // 1,,1,,1,,1,,1,,1,
3169 // ,,,,,,,,,,
3170 // 1,,1,,1,,1,,1,,1,
3171 // ,,,,,,,,,,
3172 // 1,,1,,1,,1,,1,,1,
3173 // ,,,,,,,,,,
3174 // 1,,1,,1,,1,,1,,1,
3175
3176 // Third pass fills in the blanks
3177 // ResultArr2:
3178 // 1,1,1,1,1,1,1,1,1,1,1,1
3179 // 1,1,1,1,1,1,1,1,1,1,1,1
3180 // 1,1,1,1,1,1,1,1,1,1,1,1
3181 // 1,1,1,1,1,1,1,1,1,1,1,1
3182 // 1,1,1,1,1,1,1,1,1,1,1,1
3183 // 1,1,1,1,1,1,1,1,1,1,1,1
3184 // 1,1,1,1,1,1,1,1,1,1,1,1
3185 // 1,1,1,1,1,1,1,1,1,1,1,1
3186 // 1,1,1,1,1,1,1,1,1,1,1,1
3187 // 1,1,1,1,1,1,1,1,1,1,1,1
3188 // 1,1,1,1,1,1,1,1,1,1,1,1
3189
3190 // X,Y = .
3191 // X+1,y = ^
3192 // X,Y+1 = *
3193 // X+1,Y+1 = #
3194
3195 // Filling in like this;
3196 // .*
3197 // ^#
3198 // 1st .
3199 // 2nd *
3200 // 3rd ^
3201 // 4th #
3202 // on single loop.
3203
3204 float[,] resultarr2 = new float[512, 512];
3205 for (int y = 0; y < WorldExtents.Y; y++)
3206 {
3207 for (int x = 0; x < WorldExtents.X; x++)
3208 {
3209 resultarr2[y * 2, x * 2] = resultarr[y, x];
3210
3211 if (y < WorldExtents.Y)
3212 {
3213 resultarr2[(y * 2) + 1, x * 2] = resultarr[y, x];
3214 }
3215 if (x < WorldExtents.X)
3216 {
3217 resultarr2[y * 2, (x * 2) + 1] = resultarr[y, x];
3218 }
3219 if (x < WorldExtents.X && y < WorldExtents.Y)
3220 {
3221 resultarr2[(y * 2) + 1, (x * 2) + 1] = resultarr[y, x];
3222 }
3223 }
3224 }
3225
3226 //Flatten out the array
3227 int i = 0;
3228 for (int y = 0; y < 512; y++)
3229 {
3230 for (int x = 0; x < 512; x++)
3231 {
3232 if (resultarr2[y, x] <= 0)
3233 returnarr[i] = 0.0000001f;
3234 else
3235 returnarr[i] = resultarr2[y, x];
3236
3237 i++;
3238 }
3239 }
3240
3241 return returnarr;
3242 }
3243
3244 public float[] ResizeTerrain512Interpolation(float[] heightMap)
3245 {
3246 float[] returnarr = new float[262144];
3247 float[,] resultarr = new float[512,512];
3248
3249 // Filling out the array into its multi-dimensional components
3250 for (int y = 0; y < 256; y++)
3251 {
3252 for (int x = 0; x < 256; x++)
3253 {
3254 resultarr[y, x] = heightMap[y * 256 + x];
3255 }
3256 }
3257
3258 // Resize using interpolation
3259
3260 // This particular way is quick but it only works on a multiple of the original
3261
3262 // The idea behind this method can be described with the following diagrams
3263 // second pass and third pass happen in the same loop really.. just separated
3264 // them to show what this does.
3265
3266 // First Pass
3267 // ResultArr:
3268 // 1,1,1,1,1,1
3269 // 1,1,1,1,1,1
3270 // 1,1,1,1,1,1
3271 // 1,1,1,1,1,1
3272 // 1,1,1,1,1,1
3273 // 1,1,1,1,1,1
3274
3275 // Second Pass
3276 // ResultArr2:
3277 // 1,,1,,1,,1,,1,,1,
3278 // ,,,,,,,,,,
3279 // 1,,1,,1,,1,,1,,1,
3280 // ,,,,,,,,,,
3281 // 1,,1,,1,,1,,1,,1,
3282 // ,,,,,,,,,,
3283 // 1,,1,,1,,1,,1,,1,
3284 // ,,,,,,,,,,
3285 // 1,,1,,1,,1,,1,,1,
3286 // ,,,,,,,,,,
3287 // 1,,1,,1,,1,,1,,1,
3288
3289 // Third pass fills in the blanks
3290 // ResultArr2:
3291 // 1,1,1,1,1,1,1,1,1,1,1,1
3292 // 1,1,1,1,1,1,1,1,1,1,1,1
3293 // 1,1,1,1,1,1,1,1,1,1,1,1
3294 // 1,1,1,1,1,1,1,1,1,1,1,1
3295 // 1,1,1,1,1,1,1,1,1,1,1,1
3296 // 1,1,1,1,1,1,1,1,1,1,1,1
3297 // 1,1,1,1,1,1,1,1,1,1,1,1
3298 // 1,1,1,1,1,1,1,1,1,1,1,1
3299 // 1,1,1,1,1,1,1,1,1,1,1,1
3300 // 1,1,1,1,1,1,1,1,1,1,1,1
3301 // 1,1,1,1,1,1,1,1,1,1,1,1
3302
3303 // X,Y = .
3304 // X+1,y = ^
3305 // X,Y+1 = *
3306 // X+1,Y+1 = #
3307
3308 // Filling in like this;
3309 // .*
3310 // ^#
3311 // 1st .
3312 // 2nd *
3313 // 3rd ^
3314 // 4th #
3315 // on single loop.
3316
3317 float[,] resultarr2 = new float[512,512];
3318 for (int y = 0; y < (int)Constants.RegionSize; y++)
3319 {
3320 for (int x = 0; x < (int)Constants.RegionSize; x++)
3321 {
3322 resultarr2[y*2, x*2] = resultarr[y, x];
3323
3324 if (y < (int)Constants.RegionSize)
3325 {
3326 if (y + 1 < (int)Constants.RegionSize)
3327 {
3328 if (x + 1 < (int)Constants.RegionSize)
3329 {
3330 resultarr2[(y*2) + 1, x*2] = ((resultarr[y, x] + resultarr[y + 1, x] +
3331 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3332 }
3333 else
3334 {
3335 resultarr2[(y*2) + 1, x*2] = ((resultarr[y, x] + resultarr[y + 1, x])/2);
3336 }
3337 }
3338 else
3339 {
3340 resultarr2[(y*2) + 1, x*2] = resultarr[y, x];
3341 }
3342 }
3343 if (x < (int)Constants.RegionSize)
3344 {
3345 if (x + 1 < (int)Constants.RegionSize)
3346 {
3347 if (y + 1 < (int)Constants.RegionSize)
3348 {
3349 resultarr2[y*2, (x*2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] +
3350 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3351 }
3352 else
3353 {
3354 resultarr2[y*2, (x*2) + 1] = ((resultarr[y, x] + resultarr[y, x + 1])/2);
3355 }
3356 }
3357 else
3358 {
3359 resultarr2[y*2, (x*2) + 1] = resultarr[y, x];
3360 }
3361 }
3362 if (x < (int)Constants.RegionSize && y < (int)Constants.RegionSize)
3363 {
3364 if ((x + 1 < (int)Constants.RegionSize) && (y + 1 < (int)Constants.RegionSize))
3365 {
3366 resultarr2[(y*2) + 1, (x*2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] +
3367 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3368 }
3369 else
3370 {
3371 resultarr2[(y*2) + 1, (x*2) + 1] = resultarr[y, x];
3372 }
3373 }
3374 }
3375 }
3376 //Flatten out the array
3377 int i = 0;
3378 for (int y = 0; y < 512; y++)
3379 {
3380 for (int x = 0; x < 512; x++)
3381 {
3382 if (Single.IsNaN(resultarr2[y, x]) || Single.IsInfinity(resultarr2[y, x]))
3383 {
3384 m_log.Warn("[PHYSICS]: Non finite heightfield element detected. Setting it to 0");
3385 resultarr2[y, x] = 0;
3386 }
3387 returnarr[i] = resultarr2[y, x];
3388 i++;
3389 }
3390 }
3391
3392 return returnarr;
3393 }
3394
3395 #endregion
3396
3397 public override void SetTerrain(float[] heightMap)
3398 {
3399 if (m_worldOffset != Vector3.Zero && m_parentScene != null)
3400 {
3401 if (m_parentScene is OdeScene)
3402 {
3403 ((OdeScene)m_parentScene).SetTerrain(heightMap, m_worldOffset);
3404 }
3405 }
3406 else
3407 {
3408 SetTerrain(heightMap, m_worldOffset);
3409 }
3410 }
3411
3412 public void SetTerrain(float[] heightMap, Vector3 pOffset)
3413 {
3414 // this._heightmap[i] = (double)heightMap[i];
3415 // dbm (danx0r) -- creating a buffer zone of one extra sample all around
3416 //_origheightmap = heightMap;
3417
3418 float[] _heightmap;
3419
3420 // zero out a heightmap array float array (single dimension [flattened]))
3421 //if ((int)Constants.RegionSize == 256)
3422 // _heightmap = new float[514 * 514];
3423 //else
3424
3425 _heightmap = new float[(((int)Constants.RegionSize + 2) * ((int)Constants.RegionSize + 2))];
3426
3427 uint heightmapWidth = Constants.RegionSize + 1;
3428 uint heightmapHeight = Constants.RegionSize + 1;
3429
3430 uint heightmapWidthSamples;
3431
3432 uint heightmapHeightSamples;
3433
3434 //if (((int)Constants.RegionSize) == 256)
3435 //{
3436 // heightmapWidthSamples = 2 * (uint)Constants.RegionSize + 2;
3437 // heightmapHeightSamples = 2 * (uint)Constants.RegionSize + 2;
3438 // heightmapWidth++;
3439 // heightmapHeight++;
3440 //}
3441 //else
3442 //{
3443
3444 heightmapWidthSamples = (uint)Constants.RegionSize + 1;
3445 heightmapHeightSamples = (uint)Constants.RegionSize + 1;
3446 //}
3447
3448 const float scale = 1.0f;
3449 const float offset = 0.0f;
3450 const float thickness = 0.2f;
3451 const int wrap = 0;
3452
3453 int regionsize = (int) Constants.RegionSize + 2;
3454 //Double resolution
3455 //if (((int)Constants.RegionSize) == 256)
3456 // heightMap = ResizeTerrain512Interpolation(heightMap);
3457
3458
3459 // if (((int)Constants.RegionSize) == 256 && (int)Constants.RegionSize == 256)
3460 // regionsize = 512;
3461
3462 float hfmin = 2000;
3463 float hfmax = -2000;
3464
3465 for (int x = 0; x < heightmapWidthSamples; x++)
3466 {
3467 for (int y = 0; y < heightmapHeightSamples; y++)
3468 {
3469 int xx = Util.Clip(x - 1, 0, regionsize - 1);
3470 int yy = Util.Clip(y - 1, 0, regionsize - 1);
3471
3472
3473 float val= heightMap[yy * (int)Constants.RegionSize + xx];
3474 _heightmap[x * ((int)Constants.RegionSize + 2) + y] = val;
3475
3476 hfmin = (val < hfmin) ? val : hfmin;
3477 hfmax = (val > hfmax) ? val : hfmax;
3478 }
3479 }
3480
3481
3482
3483
3484 lock (OdeLock)
3485 {
3486 IntPtr GroundGeom = IntPtr.Zero;
3487 if (RegionTerrain.TryGetValue(pOffset, out GroundGeom))
3488 {
3489 RegionTerrain.Remove(pOffset);
3490 if (GroundGeom != IntPtr.Zero)
3491 {
3492 if (TerrainHeightFieldHeights.ContainsKey(GroundGeom))
3493 {
3494 TerrainHeightFieldHeights.Remove(GroundGeom);
3495 }
3496 d.SpaceRemove(space, GroundGeom);
3497 d.GeomDestroy(GroundGeom);
3498 }
3499
3500 }
3501 IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
3502 d.GeomHeightfieldDataBuildSingle(HeightmapData, _heightmap, 0, heightmapWidth + 1, heightmapHeight + 1,
3503 (int)heightmapWidthSamples + 1, (int)heightmapHeightSamples + 1, scale,
3504 offset, thickness, wrap);
3505 d.GeomHeightfieldDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1);
3506 GroundGeom = d.CreateHeightfield(space, HeightmapData, 1);
3507 if (GroundGeom != IntPtr.Zero)
3508 {
3509 d.GeomSetCategoryBits(GroundGeom, (int)(CollisionCategories.Land));
3510 d.GeomSetCollideBits(GroundGeom, (int)(CollisionCategories.Space));
3511
3512 }
3513 geom_name_map[GroundGeom] = "Terrain";
3514
3515 d.Matrix3 R = new d.Matrix3();
3516
3517 Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f);
3518 Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f);
3519 //Axiom.Math.Quaternion q3 = Axiom.Math.Quaternion.FromAngleAxis(3.14f, new Axiom.Math.Vector3(0, 0, 1));
3520
3521 q1 = q1 * q2;
3522 //q1 = q1 * q3;
3523 Vector3 v3;
3524 float angle;
3525 q1.GetAxisAngle(out v3, out angle);
3526
3527 d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle);
3528 d.GeomSetRotation(GroundGeom, ref R);
3529 d.GeomSetPosition(GroundGeom, (pOffset.X + ((int)Constants.RegionSize * 0.5f)) - 1, (pOffset.Y + ((int)Constants.RegionSize * 0.5f)) - 1, 0);
3530 IntPtr testGround = IntPtr.Zero;
3531 if (RegionTerrain.TryGetValue(pOffset, out testGround))
3532 {
3533 RegionTerrain.Remove(pOffset);
3534 }
3535 RegionTerrain.Add(pOffset, GroundGeom, GroundGeom);
3536 TerrainHeightFieldHeights.Add(GroundGeom,_heightmap);
3537
3538 }
3539 }
3540
3541 public override void DeleteTerrain()
3542 {
3543 }
3544
3545 public float GetWaterLevel()
3546 {
3547 return waterlevel;
3548 }
3549
3550 public override bool SupportsCombining()
3551 {
3552 return true;
3553 }
3554
3555 public override void UnCombine(PhysicsScene pScene)
3556 {
3557 IntPtr localGround = IntPtr.Zero;
3558// float[] localHeightfield;
3559 bool proceed = false;
3560 List<IntPtr> geomDestroyList = new List<IntPtr>();
3561
3562 lock (OdeLock)
3563 {
3564 if (RegionTerrain.TryGetValue(Vector3.Zero, out localGround))
3565 {
3566 foreach (IntPtr geom in TerrainHeightFieldHeights.Keys)
3567 {
3568 if (geom == localGround)
3569 {
3570// localHeightfield = TerrainHeightFieldHeights[geom];
3571 proceed = true;
3572 }
3573 else
3574 {
3575 geomDestroyList.Add(geom);
3576 }
3577 }
3578
3579 if (proceed)
3580 {
3581 m_worldOffset = Vector3.Zero;
3582 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize);
3583 m_parentScene = null;
3584
3585 foreach (IntPtr g in geomDestroyList)
3586 {
3587 // removingHeightField needs to be done or the garbage collector will
3588 // collect the terrain data before we tell ODE to destroy it causing
3589 // memory corruption
3590 if (TerrainHeightFieldHeights.ContainsKey(g))
3591 {
3592// float[] removingHeightField = TerrainHeightFieldHeights[g];
3593 TerrainHeightFieldHeights.Remove(g);
3594
3595 if (RegionTerrain.ContainsKey(g))
3596 {
3597 RegionTerrain.Remove(g);
3598 }
3599
3600 d.GeomDestroy(g);
3601 //removingHeightField = new float[0];
3602 }
3603 }
3604
3605 }
3606 else
3607 {
3608 m_log.Warn("[PHYSICS]: Couldn't proceed with UnCombine. Region has inconsistant data.");
3609 }
3610 }
3611 }
3612 }
3613
3614 public override void SetWaterLevel(float baseheight)
3615 {
3616 waterlevel = baseheight;
3617 randomizeWater(waterlevel);
3618 }
3619
3620 public void randomizeWater(float baseheight)
3621 {
3622 const uint heightmapWidth = m_regionWidth + 2;
3623 const uint heightmapHeight = m_regionHeight + 2;
3624 const uint heightmapWidthSamples = m_regionWidth + 2;
3625 const uint heightmapHeightSamples = m_regionHeight + 2;
3626 const float scale = 1.0f;
3627 const float offset = 0.0f;
3628 const float thickness = 2.9f;
3629 const int wrap = 0;
3630
3631 for (int i = 0; i < (258 * 258); i++)
3632 {
3633 _watermap[i] = (baseheight-0.1f) + ((float)fluidRandomizer.Next(1,9) / 10f);
3634 // m_log.Info((baseheight - 0.1f) + ((float)fluidRandomizer.Next(1, 9) / 10f));
3635 }
3636
3637 lock (OdeLock)
3638 {
3639 if (WaterGeom != IntPtr.Zero)
3640 {
3641 d.SpaceRemove(space, WaterGeom);
3642 }
3643 IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
3644 d.GeomHeightfieldDataBuildSingle(HeightmapData, _watermap, 0, heightmapWidth, heightmapHeight,
3645 (int)heightmapWidthSamples, (int)heightmapHeightSamples, scale,
3646 offset, thickness, wrap);
3647 d.GeomHeightfieldDataSetBounds(HeightmapData, m_regionWidth, m_regionHeight);
3648 WaterGeom = d.CreateHeightfield(space, HeightmapData, 1);
3649 if (WaterGeom != IntPtr.Zero)
3650 {
3651 d.GeomSetCategoryBits(WaterGeom, (int)(CollisionCategories.Water));
3652 d.GeomSetCollideBits(WaterGeom, (int)(CollisionCategories.Space));
3653
3654 }
3655 geom_name_map[WaterGeom] = "Water";
3656
3657 d.Matrix3 R = new d.Matrix3();
3658
3659 Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f);
3660 Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f);
3661 //Axiom.Math.Quaternion q3 = Axiom.Math.Quaternion.FromAngleAxis(3.14f, new Axiom.Math.Vector3(0, 0, 1));
3662
3663 q1 = q1 * q2;
3664 //q1 = q1 * q3;
3665 Vector3 v3;
3666 float angle;
3667 q1.GetAxisAngle(out v3, out angle);
3668
3669 d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle);
3670 d.GeomSetRotation(WaterGeom, ref R);
3671 d.GeomSetPosition(WaterGeom, 128, 128, 0);
3672
3673 }
3674
3675 }
3676
3677 public override void Dispose()
3678 {
3679 m_rayCastManager.Dispose();
3680 m_rayCastManager = null;
3681
3682 lock (OdeLock)
3683 {
3684 lock (_prims)
3685 {
3686 foreach (OdePrim prm in _prims)
3687 {
3688 RemovePrim(prm);
3689 }
3690 }
3691
3692 //foreach (OdeCharacter act in _characters)
3693 //{
3694 //RemoveAvatar(act);
3695 //}
3696 d.WorldDestroy(world);
3697 //d.CloseODE();
3698 }
3699 }
3700 public override Dictionary<uint, float> GetTopColliders()
3701 {
3702 Dictionary<uint, float> returncolliders = new Dictionary<uint, float>();
3703 int cnt = 0;
3704 lock (_prims)
3705 {
3706 foreach (OdePrim prm in _prims)
3707 {
3708 if (prm.CollisionScore > 0)
3709 {
3710 returncolliders.Add(prm.m_localID, prm.CollisionScore);
3711 cnt++;
3712 prm.CollisionScore = 0f;
3713 if (cnt > 25)
3714 {
3715 break;
3716 }
3717 }
3718 }
3719 }
3720 return returncolliders;
3721 }
3722
3723 public override bool SupportsRayCast()
3724 {
3725 return true;
3726 }
3727
3728 public override void RaycastWorld(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
3729 {
3730 if (retMethod != null)
3731 {
3732 m_rayCastManager.QueueRequest(position, direction, length, retMethod);
3733 }
3734 }
3735
3736#if USE_DRAWSTUFF
3737 // Keyboard callback
3738 public void command(int cmd)
3739 {
3740 IntPtr geom;
3741 d.Mass mass;
3742 d.Vector3 sides = new d.Vector3(d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f);
3743
3744
3745
3746 Char ch = Char.ToLower((Char)cmd);
3747 switch ((Char)ch)
3748 {
3749 case 'w':
3750 try
3751 {
3752 Vector3 rotate = (new Vector3(1, 0, 0) * Quaternion.CreateFromEulers(hpr.Z * Utils.DEG_TO_RAD, hpr.Y * Utils.DEG_TO_RAD, hpr.X * Utils.DEG_TO_RAD));
3753
3754 xyz.X += rotate.X; xyz.Y += rotate.Y; xyz.Z += rotate.Z;
3755 ds.SetViewpoint(ref xyz, ref hpr);
3756 }
3757 catch (ArgumentException)
3758 { hpr.X = 0; }
3759 break;
3760
3761 case 'a':
3762 hpr.X++;
3763 ds.SetViewpoint(ref xyz, ref hpr);
3764 break;
3765
3766 case 's':
3767 try
3768 {
3769 Vector3 rotate2 = (new Vector3(-1, 0, 0) * Quaternion.CreateFromEulers(hpr.Z * Utils.DEG_TO_RAD, hpr.Y * Utils.DEG_TO_RAD, hpr.X * Utils.DEG_TO_RAD));
3770
3771 xyz.X += rotate2.X; xyz.Y += rotate2.Y; xyz.Z += rotate2.Z;
3772 ds.SetViewpoint(ref xyz, ref hpr);
3773 }
3774 catch (ArgumentException)
3775 { hpr.X = 0; }
3776 break;
3777 case 'd':
3778 hpr.X--;
3779 ds.SetViewpoint(ref xyz, ref hpr);
3780 break;
3781 case 'r':
3782 xyz.Z++;
3783 ds.SetViewpoint(ref xyz, ref hpr);
3784 break;
3785 case 'f':
3786 xyz.Z--;
3787 ds.SetViewpoint(ref xyz, ref hpr);
3788 break;
3789 case 'e':
3790 xyz.Y++;
3791 ds.SetViewpoint(ref xyz, ref hpr);
3792 break;
3793 case 'q':
3794 xyz.Y--;
3795 ds.SetViewpoint(ref xyz, ref hpr);
3796 break;
3797 }
3798 }
3799
3800 public void step(int pause)
3801 {
3802
3803 ds.SetColor(1.0f, 1.0f, 0.0f);
3804 ds.SetTexture(ds.Texture.Wood);
3805 lock (_prims)
3806 {
3807 foreach (OdePrim prm in _prims)
3808 {
3809 //IntPtr body = d.GeomGetBody(prm.prim_geom);
3810 if (prm.prim_geom != IntPtr.Zero)
3811 {
3812 d.Vector3 pos;
3813 d.GeomCopyPosition(prm.prim_geom, out pos);
3814 //d.BodyCopyPosition(body, out pos);
3815
3816 d.Matrix3 R;
3817 d.GeomCopyRotation(prm.prim_geom, out R);
3818 //d.BodyCopyRotation(body, out R);
3819
3820
3821 d.Vector3 sides = new d.Vector3();
3822 sides.X = prm.Size.X;
3823 sides.Y = prm.Size.Y;
3824 sides.Z = prm.Size.Z;
3825
3826 ds.DrawBox(ref pos, ref R, ref sides);
3827 }
3828 }
3829 }
3830 ds.SetColor(1.0f, 0.0f, 0.0f);
3831 lock (_characters)
3832 {
3833 foreach (OdeCharacter chr in _characters)
3834 {
3835 if (chr.Shell != IntPtr.Zero)
3836 {
3837 IntPtr body = d.GeomGetBody(chr.Shell);
3838
3839 d.Vector3 pos;
3840 d.GeomCopyPosition(chr.Shell, out pos);
3841 //d.BodyCopyPosition(body, out pos);
3842
3843 d.Matrix3 R;
3844 d.GeomCopyRotation(chr.Shell, out R);
3845 //d.BodyCopyRotation(body, out R);
3846
3847 ds.DrawCapsule(ref pos, ref R, chr.Size.Z, 0.35f);
3848 d.Vector3 sides = new d.Vector3();
3849 sides.X = 0.5f;
3850 sides.Y = 0.5f;
3851 sides.Z = 0.5f;
3852
3853 ds.DrawBox(ref pos, ref R, ref sides);
3854 }
3855 }
3856 }
3857 }
3858
3859 public void start(int unused)
3860 {
3861 ds.SetViewpoint(ref xyz, ref hpr);
3862 }
3863#endif
3864 }
3865} \ No newline at end of file
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
index ce7d97c..fd6d64c 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
@@ -5050,7 +5050,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
5050 } 5050 }
5051 } 5051 }
5052 5052
5053 result.Add(src.Substring(start,length).Trim()); 5053 result.Add(new LSL_String(src.Substring(start,length).Trim()));
5054 5054
5055 return result; 5055 return result;
5056 } 5056 }
@@ -6900,7 +6900,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6900 // retain pathcurve 6900 // retain pathcurve
6901 shapeBlock.PathCurve = part.Shape.PathCurve; 6901 shapeBlock.PathCurve = part.Shape.PathCurve;
6902 6902
6903 part.Shape.SetSculptData((byte)type, sculptId); 6903 part.Shape.SetSculptProperties((byte)type, sculptId);
6904 part.Shape.SculptEntry = true; 6904 part.Shape.SculptEntry = true;
6905 part.UpdateShape(shapeBlock); 6905 part.UpdateShape(shapeBlock);
6906 } 6906 }
@@ -7391,7 +7391,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7391 UUID[] anims; 7391 UUID[] anims;
7392 anims = av.Animator.GetAnimationArray(); 7392 anims = av.Animator.GetAnimationArray();
7393 foreach (UUID foo in anims) 7393 foreach (UUID foo in anims)
7394 l.Add(foo.ToString()); 7394 l.Add(new LSL_Key(foo.ToString()));
7395 return l; 7395 return l;
7396 } 7396 }
7397 7397
@@ -7926,17 +7926,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7926 7926
7927 case (int)ScriptBaseClass.PRIM_TEXT: 7927 case (int)ScriptBaseClass.PRIM_TEXT:
7928 Color4 textColor = part.GetTextColor(); 7928 Color4 textColor = part.GetTextColor();
7929 res.Add(part.Text); 7929 res.Add(new LSL_String(part.Text));
7930 res.Add(new LSL_Vector(textColor.R, 7930 res.Add(new LSL_Vector(textColor.R,
7931 textColor.G, 7931 textColor.G,
7932 textColor.B)); 7932 textColor.B));
7933 res.Add(new LSL_Float(textColor.A)); 7933 res.Add(new LSL_Float(textColor.A));
7934 break; 7934 break;
7935 case (int)ScriptBaseClass.PRIM_NAME: 7935 case (int)ScriptBaseClass.PRIM_NAME:
7936 res.Add(part.Name); 7936 res.Add(new LSL_String(part.Name));
7937 break; 7937 break;
7938 case (int)ScriptBaseClass.PRIM_DESC: 7938 case (int)ScriptBaseClass.PRIM_DESC:
7939 res.Add(part.Description); 7939 res.Add(new LSL_String(part.Description));
7940 break; 7940 break;
7941 case (int)ScriptBaseClass.PRIM_ROT_LOCAL: 7941 case (int)ScriptBaseClass.PRIM_ROT_LOCAL:
7942 res.Add(new LSL_Rotation(part.RotationOffset.X, part.RotationOffset.Y, part.RotationOffset.Z, part.RotationOffset.W)); 7942 res.Add(new LSL_Rotation(part.RotationOffset.X, part.RotationOffset.Y, part.RotationOffset.Z, part.RotationOffset.W));
@@ -9895,8 +9895,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9895 { 9895 {
9896 foreach (KeyValuePair<UUID, int> detectedParams in land.GetLandObjectOwners()) 9896 foreach (KeyValuePair<UUID, int> detectedParams in land.GetLandObjectOwners())
9897 { 9897 {
9898 ret.Add(detectedParams.Key.ToString()); 9898 ret.Add(new LSL_String(detectedParams.Key.ToString()));
9899 ret.Add(detectedParams.Value); 9899 ret.Add(new LSL_Integer(detectedParams.Value));
9900 } 9900 }
9901 } 9901 }
9902 ScriptSleep(2000); 9902 ScriptSleep(2000);
@@ -9946,25 +9946,25 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9946 switch (o.ToString()) 9946 switch (o.ToString())
9947 { 9947 {
9948 case "0": 9948 case "0":
9949 ret = ret + new LSL_List(land.Name); 9949 ret.Add(new LSL_String(land.Name));
9950 break; 9950 break;
9951 case "1": 9951 case "1":
9952 ret = ret + new LSL_List(land.Description); 9952 ret.Add(new LSL_String(land.Description));
9953 break; 9953 break;
9954 case "2": 9954 case "2":
9955 ret = ret + new LSL_List(land.OwnerID.ToString()); 9955 ret.Add(new LSL_Key(land.OwnerID.ToString()));
9956 break; 9956 break;
9957 case "3": 9957 case "3":
9958 ret = ret + new LSL_List(land.GroupID.ToString()); 9958 ret.Add(new LSL_Key(land.GroupID.ToString()));
9959 break; 9959 break;
9960 case "4": 9960 case "4":
9961 ret = ret + new LSL_List(land.Area); 9961 ret.Add(new LSL_Integer(land.Area));
9962 break; 9962 break;
9963 case "5": 9963 case "5":
9964 ret = ret + new LSL_List(land.GlobalID); 9964 ret.Add(new LSL_Key(land.GlobalID.ToString()));
9965 break; 9965 break;
9966 default: 9966 default:
9967 ret = ret + new LSL_List(0); 9967 ret.Add(new LSL_Integer(0));
9968 break; 9968 break;
9969 } 9969 }
9970 } 9970 }
@@ -9996,10 +9996,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9996 switch (o.ToString()) 9996 switch (o.ToString())
9997 { 9997 {
9998 case "1": 9998 case "1":
9999 ret.Add(av.Firstname + " " + av.Lastname); 9999 ret.Add(new LSL_String(av.Firstname + " " + av.Lastname));
10000 break; 10000 break;
10001 case "2": 10001 case "2":
10002 ret.Add(""); 10002 ret.Add(new LSL_String(""));
10003 break; 10003 break;
10004 case "3": 10004 case "3":
10005 ret.Add(new LSL_Vector((double)av.AbsolutePosition.X, (double)av.AbsolutePosition.Y, (double)av.AbsolutePosition.Z)); 10005 ret.Add(new LSL_Vector((double)av.AbsolutePosition.X, (double)av.AbsolutePosition.Y, (double)av.AbsolutePosition.Z));
@@ -10011,13 +10011,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
10011 ret.Add(new LSL_Vector(av.Velocity.X, av.Velocity.Y, av.Velocity.Z)); 10011 ret.Add(new LSL_Vector(av.Velocity.X, av.Velocity.Y, av.Velocity.Z));
10012 break; 10012 break;
10013 case "6": 10013 case "6":
10014 ret.Add(id); 10014 ret.Add(new LSL_String(id));
10015 break; 10015 break;
10016 case "7": 10016 case "7":
10017 ret.Add(UUID.Zero.ToString()); 10017 ret.Add(new LSL_String(UUID.Zero.ToString()));
10018 break; 10018 break;
10019 case "8": 10019 case "8":
10020 ret.Add(UUID.Zero.ToString()); 10020 ret.Add(new LSL_String(UUID.Zero.ToString()));
10021 break; 10021 break;
10022 } 10022 }
10023 } 10023 }
@@ -10031,10 +10031,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
10031 switch (o.ToString()) 10031 switch (o.ToString())
10032 { 10032 {
10033 case "1": 10033 case "1":
10034 ret.Add(obj.Name); 10034 ret.Add(new LSL_String(obj.Name));
10035 break; 10035 break;
10036 case "2": 10036 case "2":
10037 ret.Add(obj.Description); 10037 ret.Add(new LSL_String(obj.Description));
10038 break; 10038 break;
10039 case "3": 10039 case "3":
10040 ret.Add(new LSL_Vector(obj.AbsolutePosition.X, obj.AbsolutePosition.Y, obj.AbsolutePosition.Z)); 10040 ret.Add(new LSL_Vector(obj.AbsolutePosition.X, obj.AbsolutePosition.Y, obj.AbsolutePosition.Z));
@@ -10046,13 +10046,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
10046 ret.Add(new LSL_Vector(obj.Velocity.X, obj.Velocity.Y, obj.Velocity.Z)); 10046 ret.Add(new LSL_Vector(obj.Velocity.X, obj.Velocity.Y, obj.Velocity.Z));
10047 break; 10047 break;
10048 case "6": 10048 case "6":
10049 ret.Add(obj.OwnerID.ToString()); 10049 ret.Add(new LSL_String(obj.OwnerID.ToString()));
10050 break; 10050 break;
10051 case "7": 10051 case "7":
10052 ret.Add(obj.GroupID.ToString()); 10052 ret.Add(new LSL_String(obj.GroupID.ToString()));
10053 break; 10053 break;
10054 case "8": 10054 case "8":
10055 ret.Add(obj.CreatorID.ToString()); 10055 ret.Add(new LSL_String(obj.CreatorID.ToString()));
10056 break; 10056 break;
10057 } 10057 }
10058 } 10058 }
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs
index 645566e..80daf5b 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs
@@ -130,7 +130,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
130 int idx = 0; 130 int idx = 0;
131 while (idx < rules.Length) 131 while (idx < rules.Length)
132 { 132 {
133 uint rule = (uint)rules.GetLSLIntegerItem(idx); 133 LSL_Integer ruleInt = rules.GetLSLIntegerItem(idx);
134 uint rule = (uint)ruleInt;
134 LSL_List toadd = new LSL_List(); 135 LSL_List toadd = new LSL_List();
135 136
136 switch (rule) 137 switch (rule)
@@ -247,7 +248,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
247 248
248 if (toadd.Length > 0) 249 if (toadd.Length > 0)
249 { 250 {
250 values.Add(rule); 251 values.Add(ruleInt);
251 values.Add(toadd.Data[0]); 252 values.Add(toadd.Data[0]);
252 } 253 }
253 idx++; 254 idx++;
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
index 64931d0..b710229 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
@@ -38,7 +38,6 @@ using OpenSim;
38using OpenSim.Framework; 38using OpenSim.Framework;
39 39
40using OpenSim.Framework.Console; 40using OpenSim.Framework.Console;
41using OpenSim.Region.CoreModules.Avatar.NPC;
42using OpenSim.Region.Framework.Interfaces; 41using OpenSim.Region.Framework.Interfaces;
43using OpenSim.Region.Framework.Scenes; 42using OpenSim.Region.Framework.Scenes;
44using OpenSim.Region.ScriptEngine.Shared; 43using OpenSim.Region.ScriptEngine.Shared;
@@ -812,7 +811,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
812 World.ForEachScenePresence(delegate(ScenePresence sp) 811 World.ForEachScenePresence(delegate(ScenePresence sp)
813 { 812 {
814 if (!sp.IsChildAgent) 813 if (!sp.IsChildAgent)
815 result.Add(sp.Name); 814 result.Add(new LSL_String(sp.Name));
816 }); 815 });
817 return result; 816 return result;
818 } 817 }
@@ -970,7 +969,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
970 969
971 public string osDrawPolygon(string drawList, LSL_List x, LSL_List y) 970 public string osDrawPolygon(string drawList, LSL_List x, LSL_List y)
972 { 971 {
973 CheckThreatLevel(ThreatLevel.None, "osDrawFilledPolygon"); 972 CheckThreatLevel(ThreatLevel.None, "osDrawPolygon");
974 973
975 m_host.AddScriptLPS(1); 974 m_host.AddScriptLPS(1);
976 975
@@ -1241,7 +1240,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1241 return String.Empty; 1240 return String.Empty;
1242 } 1241 }
1243 1242
1244 public void osSetWindParam(string plugin, string param, float value) 1243 public void osSetWindParam(string plugin, string param, LSL_Float value)
1245 { 1244 {
1246 CheckThreatLevel(ThreatLevel.VeryLow, "osSetWindParam"); 1245 CheckThreatLevel(ThreatLevel.VeryLow, "osSetWindParam");
1247 m_host.AddScriptLPS(1); 1246 m_host.AddScriptLPS(1);
@@ -1251,13 +1250,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1251 { 1250 {
1252 try 1251 try
1253 { 1252 {
1254 module.WindParamSet(plugin, param, value); 1253 module.WindParamSet(plugin, param, (float)value);
1255 } 1254 }
1256 catch (Exception) { } 1255 catch (Exception) { }
1257 } 1256 }
1258 } 1257 }
1259 1258
1260 public float osGetWindParam(string plugin, string param) 1259 public LSL_Float osGetWindParam(string plugin, string param)
1261 { 1260 {
1262 CheckThreatLevel(ThreatLevel.VeryLow, "osGetWindParam"); 1261 CheckThreatLevel(ThreatLevel.VeryLow, "osGetWindParam");
1263 m_host.AddScriptLPS(1); 1262 m_host.AddScriptLPS(1);
@@ -1409,7 +1408,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1409 { 1408 {
1410 // What actually is the difference to the LL function? 1409 // What actually is the difference to the LL function?
1411 // 1410 //
1412 CheckThreatLevel(ThreatLevel.VeryLow, "osSetParcelMediaURL"); 1411 CheckThreatLevel(ThreatLevel.VeryLow, "osSetParcelSIPAddress");
1413 1412
1414 m_host.AddScriptLPS(1); 1413 m_host.AddScriptLPS(1);
1415 1414
@@ -1910,8 +1909,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1910 }; 1909 };
1911 1910
1912 return NotecardCache.GetLines(assetID); 1911 return NotecardCache.GetLines(assetID);
1913
1914
1915 } 1912 }
1916 1913
1917 public string osAvatarName2Key(string firstname, string lastname) 1914 public string osAvatarName2Key(string firstname, string lastname)
@@ -2025,16 +2022,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2025 // Find matches beginning at start position 2022 // Find matches beginning at start position
2026 Regex matcher = new Regex(pattern); 2023 Regex matcher = new Regex(pattern);
2027 Match match = matcher.Match(src, start); 2024 Match match = matcher.Match(src, start);
2028 if (match.Success) 2025 while (match.Success)
2029 { 2026 {
2030 foreach (System.Text.RegularExpressions.Group g in match.Groups) 2027 foreach (System.Text.RegularExpressions.Group g in match.Groups)
2031 { 2028 {
2032 if (g.Success) 2029 if (g.Success)
2033 { 2030 {
2034 result.Add(g.Value); 2031 result.Add(new LSL_String(g.Value));
2035 result.Add(g.Index); 2032 result.Add(new LSL_Integer(g.Index));
2036 } 2033 }
2037 } 2034 }
2035
2036 match = match.NextMatch();
2038 } 2037 }
2039 2038
2040 return result; 2039 return result;
@@ -2209,12 +2208,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2209 return (int)pws; 2208 return (int)pws;
2210 } 2209 }
2211 2210
2212 public void osSetSpeed(string UUID, float SpeedModifier) 2211 public void osSetSpeed(string UUID, LSL_Float SpeedModifier)
2213 { 2212 {
2214 CheckThreatLevel(ThreatLevel.Moderate, "osSetSpeed"); 2213 CheckThreatLevel(ThreatLevel.Moderate, "osSetSpeed");
2215 m_host.AddScriptLPS(1); 2214 m_host.AddScriptLPS(1);
2216 ScenePresence avatar = World.GetScenePresence(new UUID(UUID)); 2215 ScenePresence avatar = World.GetScenePresence(new UUID(UUID));
2217 avatar.SpeedModifier = SpeedModifier; 2216 avatar.SpeedModifier = (float)SpeedModifier;
2218 } 2217 }
2219 2218
2220 public void osKickAvatar(string FirstName,string SurName,string alert) 2219 public void osKickAvatar(string FirstName,string SurName,string alert)
@@ -2295,14 +2294,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2295 { 2294 {
2296 CheckThreatLevel(ThreatLevel.High, "osGetPrimitiveParams"); 2295 CheckThreatLevel(ThreatLevel.High, "osGetPrimitiveParams");
2297 m_host.AddScriptLPS(1); 2296 m_host.AddScriptLPS(1);
2297 InitLSL();
2298 2298
2299 return m_LSL_Api.GetLinkPrimitiveParamsEx(prim, rules); 2299 return m_LSL_Api.GetLinkPrimitiveParamsEx(prim, rules);
2300 } 2300 }
2301 2301
2302 public void osSetPrimitiveParams(LSL_Key prim, LSL_List rules) 2302 public void osSetPrimitiveParams(LSL_Key prim, LSL_List rules)
2303 { 2303 {
2304 CheckThreatLevel(ThreatLevel.High, "osGetPrimitiveParams"); 2304 CheckThreatLevel(ThreatLevel.High, "osSetPrimitiveParams");
2305 m_host.AddScriptLPS(1); 2305 m_host.AddScriptLPS(1);
2306 InitLSL();
2306 2307
2307 m_LSL_Api.SetPrimitiveParamsEx(prim, rules); 2308 m_LSL_Api.SetPrimitiveParamsEx(prim, rules);
2308 } 2309 }
@@ -2364,9 +2365,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2364 { 2365 {
2365 if (avatar.IsChildAgent == false) 2366 if (avatar.IsChildAgent == false)
2366 { 2367 {
2367 result.Add(avatar.UUID); 2368 result.Add(new LSL_String(avatar.UUID.ToString()));
2368 result.Add(avatar.AbsolutePosition); 2369 OpenMetaverse.Vector3 ap = avatar.AbsolutePosition;
2369 result.Add(avatar.Name); 2370 result.Add(new LSL_Vector(ap.X, ap.Y, ap.Z));
2371 result.Add(new LSL_String(avatar.Name));
2370 } 2372 }
2371 } 2373 }
2372 }); 2374 });
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
index 63007c6..19352f0 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
@@ -129,8 +129,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
129 129
130 // Wind Module Functions 130 // Wind Module Functions
131 string osWindActiveModelPluginName(); 131 string osWindActiveModelPluginName();
132 void osSetWindParam(string plugin, string param, float value); 132 void osSetWindParam(string plugin, string param, LSL_Float value);
133 float osGetWindParam(string plugin, string param); 133 LSL_Float osGetWindParam(string plugin, string param);
134 134
135 // Parcel commands 135 // Parcel commands
136 void osParcelJoin(vector pos1, vector pos2); 136 void osParcelJoin(vector pos1, vector pos2);
@@ -180,7 +180,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
180 180
181 int osGetSimulatorMemory(); 181 int osGetSimulatorMemory();
182 void osKickAvatar(string FirstName,string SurName,string alert); 182 void osKickAvatar(string FirstName,string SurName,string alert);
183 void osSetSpeed(string UUID, float SpeedModifier); 183 void osSetSpeed(string UUID, LSL_Float SpeedModifier);
184 void osCauseHealing(string avatar, double healing); 184 void osCauseHealing(string avatar, double healing);
185 void osCauseDamage(string avatar, double damage); 185 void osCauseDamage(string avatar, double damage);
186 LSL_List osGetPrimitiveParams(LSL_Key prim, LSL_List rules); 186 LSL_List osGetPrimitiveParams(LSL_Key prim, LSL_List rules);
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
index e3ea556..7c59098 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
@@ -106,16 +106,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
106 return m_OSSL_Functions.osWindActiveModelPluginName(); 106 return m_OSSL_Functions.osWindActiveModelPluginName();
107 } 107 }
108 108
109// Not yet plugged in as available OSSL functions, so commented out 109 public void osSetWindParam(string plugin, string param, LSL_Float value)
110// void osSetWindParam(string plugin, string param, float value) 110 {
111// { 111 m_OSSL_Functions.osSetWindParam(plugin, param, value);
112// m_OSSL_Functions.osSetWindParam(plugin, param, value); 112 }
113// } 113
114// 114 public LSL_Float osGetWindParam(string plugin, string param)
115// float osGetWindParam(string plugin, string param) 115 {
116// { 116 return m_OSSL_Functions.osGetWindParam(plugin, param);
117// return m_OSSL_Functions.osGetWindParam(plugin, param); 117 }
118// }
119 118
120 public void osParcelJoin(vector pos1, vector pos2) 119 public void osParcelJoin(vector pos1, vector pos2)
121 { 120 {
@@ -714,7 +713,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
714 m_OSSL_Functions.osKickAvatar(FirstName, SurName, alert); 713 m_OSSL_Functions.osKickAvatar(FirstName, SurName, alert);
715 } 714 }
716 715
717 public void osSetSpeed(string UUID, float SpeedModifier) 716 public void osSetSpeed(string UUID, LSL_Float SpeedModifier)
718 { 717 {
719 m_OSSL_Functions.osSetSpeed(UUID, SpeedModifier); 718 m_OSSL_Functions.osSetSpeed(UUID, SpeedModifier);
720 } 719 }
diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs
index 49d6abe..734d4d5 100644
--- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs
@@ -106,6 +106,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
106 // Get some config 106 // Get some config
107 WriteScriptSourceToDebugFile = m_scriptEngine.Config.GetBoolean("WriteScriptSourceToDebugFile", false); 107 WriteScriptSourceToDebugFile = m_scriptEngine.Config.GetBoolean("WriteScriptSourceToDebugFile", false);
108 CompileWithDebugInformation = m_scriptEngine.Config.GetBoolean("CompileWithDebugInformation", true); 108 CompileWithDebugInformation = m_scriptEngine.Config.GetBoolean("CompileWithDebugInformation", true);
109 bool DeleteScriptsOnStartup = m_scriptEngine.Config.GetBoolean("DeleteScriptsOnStartup", true);
109 110
110 // Get file prefix from scriptengine name and make it file system safe: 111 // Get file prefix from scriptengine name and make it file system safe:
111 FilePrefix = "CommonCompiler"; 112 FilePrefix = "CommonCompiler";
@@ -114,11 +115,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
114 FilePrefix = FilePrefix.Replace(c, '_'); 115 FilePrefix = FilePrefix.Replace(c, '_');
115 } 116 }
116 117
117 // First time we start? Delete old files
118 if (in_startup) 118 if (in_startup)
119 { 119 {
120 in_startup = false; 120 in_startup = false;
121 DeleteOldFiles(); 121 CreateScriptsDirectory();
122
123 // First time we start? Delete old files
124 if (DeleteScriptsOnStartup)
125 DeleteOldFiles();
122 } 126 }
123 127
124 // Map name and enum type of our supported languages 128 // Map name and enum type of our supported languages
@@ -187,11 +191,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
187 } 191 }
188 192
189 /// <summary> 193 /// <summary>
190 /// Delete old script files 194 /// Create the directory where compiled scripts are stored.
191 /// </summary> 195 /// </summary>
192 private void DeleteOldFiles() 196 private void CreateScriptsDirectory()
193 { 197 {
194 // CREATE FOLDER IF IT DOESNT EXIST
195 if (!Directory.Exists(ScriptEnginesPath)) 198 if (!Directory.Exists(ScriptEnginesPath))
196 { 199 {
197 try 200 try
@@ -218,7 +221,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
218 m_scriptEngine.World.RegionInfo.RegionID.ToString()) + "\": " + ex.ToString()); 221 m_scriptEngine.World.RegionInfo.RegionID.ToString()) + "\": " + ex.ToString());
219 } 222 }
220 } 223 }
224 }
221 225
226 /// <summary>
227 /// Delete old script files
228 /// </summary>
229 private void DeleteOldFiles()
230 {
222 foreach (string file in Directory.GetFiles(Path.Combine(ScriptEnginesPath, 231 foreach (string file in Directory.GetFiles(Path.Combine(ScriptEnginesPath,
223 m_scriptEngine.World.RegionInfo.RegionID.ToString()), FilePrefix + "_compiled*")) 232 m_scriptEngine.World.RegionInfo.RegionID.ToString()), FilePrefix + "_compiled*"))
224 { 233 {
diff --git a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs
index 461b473..d848b2a 100644
--- a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs
@@ -1379,7 +1379,9 @@ namespace OpenSim.Region.ScriptEngine.Shared
1379 public struct LSLString 1379 public struct LSLString
1380 { 1380 {
1381 public string m_string; 1381 public string m_string;
1382
1382 #region Constructors 1383 #region Constructors
1384
1383 public LSLString(string s) 1385 public LSLString(string s)
1384 { 1386 {
1385 m_string = s; 1387 m_string = s;
@@ -1387,22 +1389,24 @@ namespace OpenSim.Region.ScriptEngine.Shared
1387 1389
1388 public LSLString(double d) 1390 public LSLString(double d)
1389 { 1391 {
1390 string s=String.Format(Culture.FormatProvider, "{0:0.000000}", d); 1392 string s = String.Format(Culture.FormatProvider, "{0:0.000000}", d);
1391 m_string=s; 1393 m_string = s;
1392 } 1394 }
1393 1395
1394 public LSLString(LSLFloat f) 1396 public LSLString(LSLFloat f)
1395 { 1397 {
1396 string s = String.Format(Culture.FormatProvider, "{0:0.000000}", f.value); 1398 string s = String.Format(Culture.FormatProvider, "{0:0.000000}", f.value);
1397 m_string=s; 1399 m_string = s;
1398 } 1400 }
1399 1401
1400 public LSLString(LSLInteger i) 1402 public LSLString(int i)
1401 { 1403 {
1402 string s = String.Format("{0}", i); 1404 string s = String.Format("{0}", i);
1403 m_string = s; 1405 m_string = s;
1404 } 1406 }
1405 1407
1408 public LSLString(LSLInteger i) : this(i.value) {}
1409
1406 #endregion 1410 #endregion
1407 1411
1408 #region Operators 1412 #region Operators
@@ -1469,6 +1473,11 @@ namespace OpenSim.Region.ScriptEngine.Shared
1469 { 1473 {
1470 return new LSLString(d); 1474 return new LSLString(d);
1471 } 1475 }
1476
1477 static public explicit operator LSLString(int i)
1478 {
1479 return new LSLString(i);
1480 }
1472 1481
1473 public static explicit operator LSLString(LSLFloat f) 1482 public static explicit operator LSLString(LSLFloat f)
1474 { 1483 {
@@ -1742,7 +1751,17 @@ namespace OpenSim.Region.ScriptEngine.Shared
1742 public override bool Equals(Object o) 1751 public override bool Equals(Object o)
1743 { 1752 {
1744 if (!(o is LSLInteger)) 1753 if (!(o is LSLInteger))
1745 return false; 1754 {
1755 if (o is int)
1756 {
1757 return value == (int)o;
1758 }
1759 else
1760 {
1761 return false;
1762 }
1763 }
1764
1746 return value == ((LSLInteger)o).value; 1765 return value == ((LSLInteger)o).value;
1747 } 1766 }
1748 1767