aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim')
-rw-r--r--OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs1
-rw-r--r--OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs13
-rw-r--r--OpenSim/Addons/Groups/Service/GroupsService.cs21
-rw-r--r--OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs23
-rw-r--r--OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs20
-rw-r--r--OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs116
-rw-r--r--OpenSim/Capabilities/LLSDAvatarPicker.cs51
-rw-r--r--OpenSim/Data/IProfilesData.cs56
-rw-r--r--OpenSim/Data/MSSQL/Resources/RegionStore.migrations12
-rw-r--r--OpenSim/Data/MySQL/MySQLAssetData.cs22
-rw-r--r--OpenSim/Data/MySQL/MySQLOfflineIMData.cs7
-rw-r--r--OpenSim/Data/MySQL/MySQLUserProfilesData.cs1096
-rw-r--r--OpenSim/Data/MySQL/Resources/EstateStore.migrations6
-rw-r--r--OpenSim/Data/MySQL/Resources/UserProfiles.migrations83
-rw-r--r--OpenSim/Data/SQLite/Resources/EstateStore.migrations9
-rw-r--r--OpenSim/Framework/Animation.cs20
-rw-r--r--OpenSim/Framework/CachedTextureEventArg.cs46
-rw-r--r--OpenSim/Framework/Console/LocalConsole.cs15
-rw-r--r--OpenSim/Framework/EstateSettings.cs1
-rw-r--r--OpenSim/Framework/IClientAPI.cs7
-rw-r--r--OpenSim/Framework/IPeople.cs47
-rw-r--r--OpenSim/Framework/IScene.cs7
-rw-r--r--OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs2
-rw-r--r--OpenSim/Framework/Servers/ServerBase.cs5
-rw-r--r--OpenSim/Framework/UserProfiles.cs117
-rw-r--r--OpenSim/Framework/Util.cs22
-rw-r--r--OpenSim/Region/Application/OpenSimBase.cs6
-rw-r--r--OpenSim/Region/ClientStack/IClientNetworkServer.cs15
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs139
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs2
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs80
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs12
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs2
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs4
-rw-r--r--OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs59
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs4
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs16
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs93
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/Tests/InventoryTransferModuleTests.cs449
-rw-r--r--OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs1332
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs5
-rw-r--r--OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs64
-rw-r--r--OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs5
-rw-r--r--OpenSim/Region/CoreModules/Framework/UserManagement/Tests/HGUserManagementModuleTests.cs76
-rw-r--r--OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs187
-rw-r--r--OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs3
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsIn/UserProfiles/LocalUserProfilesServiceConnector.cs226
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs44
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs2
-rw-r--r--OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs218
-rw-r--r--OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs256
-rw-r--r--OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs298
-rw-r--r--OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs51
-rw-r--r--OpenSim/Region/CoreModules/World/Land/LandObject.cs7
-rw-r--r--OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/World/Sound/SoundModule.cs9
-rw-r--r--OpenSim/Region/Framework/Interfaces/IEstateModule.cs2
-rw-r--r--OpenSim/Region/Framework/Interfaces/ISoundModule.cs8
-rw-r--r--OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs110
-rw-r--r--OpenSim/Region/Framework/Scenes/Animation/DefaultAvatarAnimations.cs26
-rw-r--r--OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs17
-rw-r--r--OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs10
-rw-r--r--OpenSim/Region/Framework/Scenes/EventManager.cs23
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.Inventory.cs11
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs108
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneBase.cs4
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs16
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPart.cs91
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs20
-rw-r--r--OpenSim/Region/Framework/Scenes/SimStatsReporter.cs3
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs107
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs4
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs14
-rw-r--r--OpenSim/Region/Framework/Scenes/UuidGatherer.cs66
-rw-r--r--OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs8
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs6
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs41
-rw-r--r--OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs579
-rw-r--r--OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs2
-rw-r--r--OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs8
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs60
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs164
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs351
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs173
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs187
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs157
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs137
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs138
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActors.cs160
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs35
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs432
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs2
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs4
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs2
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs315
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs21
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs276
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs20
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSMotors.cs71
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSParam.cs304
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs336
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs645
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs22
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs30
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs289
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs998
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapes.cs1111
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs30
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs93
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs56
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs48
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt28
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs12
-rw-r--r--OpenSim/Region/Physics/Meshing/Meshmerizer.cs249
-rw-r--r--OpenSim/Region/RegionCombinerModule/RegionCombinerLargeLandChannel.cs83
-rw-r--r--OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs2
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs326
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs11
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs14
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs60
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/XEngine.cs8
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs6
-rw-r--r--OpenSim/Server/Base/ServerUtils.cs1
-rw-r--r--OpenSim/Server/Base/ServicesServerBase.cs5
-rw-r--r--OpenSim/Server/Handlers/Hypergrid/GatekeeperServerConnector.cs8
-rw-r--r--OpenSim/Server/Handlers/Hypergrid/InstantMessageServerConnector.cs7
-rw-r--r--OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs7
-rw-r--r--OpenSim/Server/Handlers/Login/LLLoginServiceInConnector.cs9
-rw-r--r--OpenSim/Server/Handlers/Profiles/UserProfilesConnector.cs114
-rw-r--r--OpenSim/Server/Handlers/Profiles/UserProfilesHandlers.cs461
-rw-r--r--OpenSim/Server/Handlers/Simulation/AgentHandlers.cs2
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs193
-rw-r--r--OpenSim/Services/HypergridService/GatekeeperService.cs25
-rw-r--r--OpenSim/Services/Interfaces/IBansService.cs48
-rw-r--r--OpenSim/Services/Interfaces/IUserProfilesService.cs75
-rw-r--r--OpenSim/Services/LLLoginService/LLLoginResponse.cs20
-rw-r--r--OpenSim/Services/LLLoginService/LLLoginService.cs7
-rw-r--r--OpenSim/Services/UserAccountService/GridUserService.cs2
-rw-r--r--OpenSim/Services/UserProfilesService/UserProfilesService.cs187
-rw-r--r--OpenSim/Services/UserProfilesService/UserProfilesServiceBase.cs86
-rw-r--r--OpenSim/Tests/Common/Helpers/EntityTransferHelpers.cs2
-rw-r--r--OpenSim/Tests/Common/Helpers/SceneHelpers.cs54
-rw-r--r--OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs41
-rw-r--r--OpenSim/Tests/Common/Mock/TestClient.cs48
-rw-r--r--OpenSim/Tests/Common/Mock/TestXInventoryDataPlugin.cs28
147 files changed, 12051 insertions, 3624 deletions
diff --git a/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs b/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs
index f670272..7e0b112 100644
--- a/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs
+++ b/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs
@@ -186,7 +186,6 @@ namespace OpenSim.Groups
186 public UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, 186 public UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment,
187 bool allowPublish, bool maturePublish, UUID founderID, out string reason) 187 bool allowPublish, bool maturePublish, UUID founderID, out string reason)
188 { 188 {
189 m_log.DebugFormat("[Groups]: Creating group {0}", name);
190 reason = string.Empty; 189 reason = string.Empty;
191 if (m_UserManagement.IsLocalGridUser(RequestingAgentID)) 190 if (m_UserManagement.IsLocalGridUser(RequestingAgentID))
192 return m_LocalGroupsConnector.CreateGroup(RequestingAgentID, name, charter, showInList, insigniaID, 191 return m_LocalGroupsConnector.CreateGroup(RequestingAgentID, name, charter, showInList, insigniaID,
diff --git a/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs b/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs
index f991d01..28f7acc 100644
--- a/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs
+++ b/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs
@@ -170,11 +170,16 @@ namespace OpenSim.Groups
170 170
171 } 171 }
172 172
173 grec = m_GroupsService.GetGroupRecord(RequestingAgentID, grec.GroupID); 173 if (grec.GroupID != UUID.Zero)
174 if (grec == null) 174 {
175 NullResult(result, "Internal Error"); 175 grec = m_GroupsService.GetGroupRecord(RequestingAgentID, grec.GroupID);
176 if (grec == null)
177 NullResult(result, "Internal Error");
178 else
179 result["RESULT"] = GroupsDataUtils.GroupRecord(grec);
180 }
176 else 181 else
177 result["RESULT"] = GroupsDataUtils.GroupRecord(grec); 182 NullResult(result, reason);
178 } 183 }
179 184
180 string xmlString = ServerUtils.BuildXmlResponse(result); 185 string xmlString = ServerUtils.BuildXmlResponse(result);
diff --git a/OpenSim/Addons/Groups/Service/GroupsService.cs b/OpenSim/Addons/Groups/Service/GroupsService.cs
index 0668870..a2ef13a 100644
--- a/OpenSim/Addons/Groups/Service/GroupsService.cs
+++ b/OpenSim/Addons/Groups/Service/GroupsService.cs
@@ -130,6 +130,13 @@ namespace OpenSim.Groups
130 { 130 {
131 reason = string.Empty; 131 reason = string.Empty;
132 132
133 // Check if the group already exists
134 if (m_Database.RetrieveGroup(name) != null)
135 {
136 reason = "A group with that name already exists";
137 return UUID.Zero;
138 }
139
133 // Create the group 140 // Create the group
134 GroupData data = new GroupData(); 141 GroupData data = new GroupData();
135 data.GroupID = UUID.Random(); 142 data.GroupID = UUID.Random();
@@ -723,12 +730,12 @@ namespace OpenSim.Groups
723 730
724 #region Actions without permission checks 731 #region Actions without permission checks
725 732
726 private void _AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) 733 protected void _AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
727 { 734 {
728 _AddAgentToGroup(RequestingAgentID, AgentID, GroupID, RoleID, string.Empty); 735 _AddAgentToGroup(RequestingAgentID, AgentID, GroupID, RoleID, string.Empty);
729 } 736 }
730 737
731 public void _RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID) 738 protected void _RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID)
732 { 739 {
733 // 1. Delete membership 740 // 1. Delete membership
734 m_Database.DeleteMember(GroupID, AgentID); 741 m_Database.DeleteMember(GroupID, AgentID);
@@ -780,7 +787,7 @@ namespace OpenSim.Groups
780 787
781 } 788 }
782 789
783 private bool _AddOrUpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, bool add) 790 protected bool _AddOrUpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, bool add)
784 { 791 {
785 RoleData data = m_Database.RetrieveRole(groupID, roleID); 792 RoleData data = m_Database.RetrieveRole(groupID, roleID);
786 793
@@ -810,12 +817,12 @@ namespace OpenSim.Groups
810 return m_Database.StoreRole(data); 817 return m_Database.StoreRole(data);
811 } 818 }
812 819
813 private void _RemoveGroupRole(UUID groupID, UUID roleID) 820 protected void _RemoveGroupRole(UUID groupID, UUID roleID)
814 { 821 {
815 m_Database.DeleteRole(groupID, roleID); 822 m_Database.DeleteRole(groupID, roleID);
816 } 823 }
817 824
818 private void _AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) 825 protected void _AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
819 { 826 {
820 RoleMembershipData data = m_Database.RetrieveRoleMember(GroupID, RoleID, AgentID); 827 RoleMembershipData data = m_Database.RetrieveRoleMember(GroupID, RoleID, AgentID);
821 if (data != null) 828 if (data != null)
@@ -840,7 +847,7 @@ namespace OpenSim.Groups
840 847
841 } 848 }
842 849
843 private List<GroupRolesData> _GetGroupRoles(UUID groupID) 850 protected List<GroupRolesData> _GetGroupRoles(UUID groupID)
844 { 851 {
845 List<GroupRolesData> roles = new List<GroupRolesData>(); 852 List<GroupRolesData> roles = new List<GroupRolesData>();
846 853
@@ -865,7 +872,7 @@ namespace OpenSim.Groups
865 return roles; 872 return roles;
866 } 873 }
867 874
868 private List<ExtendedGroupRoleMembersData> _GetGroupRoleMembers(UUID GroupID, bool isInGroup) 875 protected List<ExtendedGroupRoleMembersData> _GetGroupRoleMembers(UUID GroupID, bool isInGroup)
869 { 876 {
870 List<ExtendedGroupRoleMembersData> rmembers = new List<ExtendedGroupRoleMembersData>(); 877 List<ExtendedGroupRoleMembersData> rmembers = new List<ExtendedGroupRoleMembersData>();
871 878
diff --git a/OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs b/OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs
index fcb6991..1d63d26 100644
--- a/OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs
+++ b/OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs
@@ -115,6 +115,8 @@ namespace OpenSim.ApplicationPlugins.LoadRegions
115 Environment.Exit(1); 115 Environment.Exit(1);
116 } 116 }
117 117
118 List<IScene> createdScenes = new List<IScene>();
119
118 for (int i = 0; i < regionsToLoad.Length; i++) 120 for (int i = 0; i < regionsToLoad.Length; i++)
119 { 121 {
120 IScene scene; 122 IScene scene;
@@ -123,17 +125,22 @@ namespace OpenSim.ApplicationPlugins.LoadRegions
123 ")"); 125 ")");
124 126
125 bool changed = m_openSim.PopulateRegionEstateInfo(regionsToLoad[i]); 127 bool changed = m_openSim.PopulateRegionEstateInfo(regionsToLoad[i]);
128
126 m_openSim.CreateRegion(regionsToLoad[i], true, out scene); 129 m_openSim.CreateRegion(regionsToLoad[i], true, out scene);
130 createdScenes.Add(scene);
131
127 if (changed) 132 if (changed)
128 regionsToLoad[i].EstateSettings.Save(); 133 regionsToLoad[i].EstateSettings.Save();
129 134 }
130 if (scene != null) 135
136 foreach (IScene scene in createdScenes)
137 {
138 scene.Start();
139
140 m_newRegionCreatedHandler = OnNewRegionCreated;
141 if (m_newRegionCreatedHandler != null)
131 { 142 {
132 m_newRegionCreatedHandler = OnNewRegionCreated; 143 m_newRegionCreatedHandler(scene);
133 if (m_newRegionCreatedHandler != null)
134 {
135 m_newRegionCreatedHandler(scene);
136 }
137 } 144 }
138 } 145 }
139 } 146 }
diff --git a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs
index e50dac6..729667c 100644
--- a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs
+++ b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs
@@ -161,6 +161,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController
161 availableMethods["admin_acl_add"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcAccessListAdd); 161 availableMethods["admin_acl_add"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcAccessListAdd);
162 availableMethods["admin_acl_remove"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcAccessListRemove); 162 availableMethods["admin_acl_remove"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcAccessListRemove);
163 availableMethods["admin_acl_list"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcAccessListList); 163 availableMethods["admin_acl_list"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcAccessListList);
164 availableMethods["admin_estate_reload"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcEstateReload);
164 165
165 // Misc 166 // Misc
166 availableMethods["admin_refresh_search"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcRefreshSearch); 167 availableMethods["admin_refresh_search"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcRefreshSearch);
@@ -831,6 +832,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController
831 832
832 IScene newScene; 833 IScene newScene;
833 m_application.CreateRegion(region, out newScene); 834 m_application.CreateRegion(region, out newScene);
835 newScene.Start();
834 836
835 // If an access specification was provided, use it. 837 // If an access specification was provided, use it.
836 // Otherwise accept the default. 838 // Otherwise accept the default.
@@ -1225,7 +1227,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController
1225 { 1227 {
1226 GridUserInfo userInfo = m_application.SceneManager.CurrentOrFirstScene.GridUserService.GetGridUserInfo(account.PrincipalID.ToString()); 1228 GridUserInfo userInfo = m_application.SceneManager.CurrentOrFirstScene.GridUserService.GetGridUserInfo(account.PrincipalID.ToString());
1227 if (userInfo != null) 1229 if (userInfo != null)
1228 responseData["lastlogin"] = userInfo.Login; 1230 responseData["lastlogin"] = Util.ToUnixTime(userInfo.Login);
1229 else 1231 else
1230 responseData["lastlogin"] = 0; 1232 responseData["lastlogin"] = 0;
1231 1233
@@ -1902,6 +1904,22 @@ namespace OpenSim.ApplicationPlugins.RemoteController
1902 m_log.Info("[RADMIN]: Access List List Request complete"); 1904 m_log.Info("[RADMIN]: Access List List Request complete");
1903 } 1905 }
1904 1906
1907 private void XmlRpcEstateReload(XmlRpcRequest request, XmlRpcResponse response, IPEndPoint remoteClient)
1908 {
1909 m_log.Info("[RADMIN]: Received Estate Reload Request");
1910
1911 Hashtable responseData = (Hashtable)response.Value;
1912// Hashtable requestData = (Hashtable)request.Params[0];
1913
1914 m_application.SceneManager.ForEachScene(s =>
1915 s.RegionInfo.EstateSettings = m_application.EstateDataService.LoadEstateSettings(s.RegionInfo.RegionID, false)
1916 );
1917
1918 responseData["success"] = true;
1919
1920 m_log.Info("[RADMIN]: Estate Reload Request complete");
1921 }
1922
1905 private void XmlRpcGetAgentsMethod(XmlRpcRequest request, XmlRpcResponse response, IPEndPoint remoteClient) 1923 private void XmlRpcGetAgentsMethod(XmlRpcRequest request, XmlRpcResponse response, IPEndPoint remoteClient)
1906 { 1924 {
1907 Hashtable responseData = (Hashtable)response.Value; 1925 Hashtable responseData = (Hashtable)response.Value;
diff --git a/OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs b/OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs
new file mode 100644
index 0000000..4dca592
--- /dev/null
+++ b/OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs
@@ -0,0 +1,116 @@
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.Collections.Specialized;
31using System.IO;
32using System.Reflection;
33using System.Web;
34using log4net;
35using Nini.Config;
36using OpenMetaverse;
37using OpenSim.Framework;
38using OpenSim.Framework.Capabilities;
39using OpenSim.Framework.Servers;
40using OpenSim.Framework.Servers.HttpServer;
41//using OpenSim.Region.Framework.Interfaces;
42using OpenSim.Services.Interfaces;
43using Caps = OpenSim.Framework.Capabilities.Caps;
44
45namespace OpenSim.Capabilities.Handlers
46{
47 public class AvatarPickerSearchHandler : BaseStreamHandler
48 {
49 private static readonly ILog m_log =
50 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51 private IPeople m_PeopleService;
52
53 public AvatarPickerSearchHandler(string path, IPeople peopleService, string name, string description)
54 : base("GET", path, name, description)
55 {
56 m_PeopleService = peopleService;
57 }
58
59 public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
60 {
61 // Try to parse the texture ID from the request URL
62 NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query);
63 string names = query.GetOne("names");
64 string psize = query.GetOne("page_size");
65 string pnumber = query.GetOne("page");
66
67 if (m_PeopleService == null)
68 return FailureResponse(names, (int)System.Net.HttpStatusCode.InternalServerError, httpResponse);
69
70 if (string.IsNullOrEmpty(names) || names.Length < 3)
71 return FailureResponse(names, (int)System.Net.HttpStatusCode.BadRequest, httpResponse);
72
73 m_log.DebugFormat("[AVATAR PICKER SEARCH]: search for {0}", names);
74
75 int page_size = (string.IsNullOrEmpty(psize) ? 500 : Int32.Parse(psize));
76 int page_number = (string.IsNullOrEmpty(pnumber) ? 1 : Int32.Parse(pnumber));
77
78 // Full content request
79 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.OK;
80 //httpResponse.ContentLength = ??;
81 httpResponse.ContentType = "application/llsd+xml";
82
83 List<UserData> users = m_PeopleService.GetUserData(names, page_size, page_number);
84
85 LLSDAvatarPicker osdReply = new LLSDAvatarPicker();
86 osdReply.next_page_url = httpRequest.RawUrl;
87 foreach (UserData u in users)
88 osdReply.agents.Array.Add(ConvertUserData(u));
89
90 string reply = LLSDHelpers.SerialiseLLSDReply(osdReply);
91 return System.Text.Encoding.UTF8.GetBytes(reply);
92 }
93
94 private LLSDPerson ConvertUserData(UserData user)
95 {
96 LLSDPerson p = new LLSDPerson();
97 p.legacy_first_name = user.FirstName;
98 p.legacy_last_name = user.LastName;
99 p.display_name = user.FirstName + " " + user.LastName;
100 if (user.LastName.StartsWith("@"))
101 p.username = user.FirstName.ToLower() + user.LastName.ToLower();
102 else
103 p.username = user.FirstName.ToLower() + "." + user.LastName.ToLower();
104 p.id = user.Id;
105 p.is_display_name_default = false;
106 return p;
107 }
108
109 private byte[] FailureResponse(string names, int statuscode, IOSHttpResponse httpResponse)
110 {
111 m_log.Error("[AVATAR PICKER SEARCH]: Error searching for " + names);
112 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
113 return System.Text.Encoding.UTF8.GetBytes(string.Empty);
114 }
115 }
116} \ No newline at end of file
diff --git a/OpenSim/Capabilities/LLSDAvatarPicker.cs b/OpenSim/Capabilities/LLSDAvatarPicker.cs
new file mode 100644
index 0000000..d0b3f3a
--- /dev/null
+++ b/OpenSim/Capabilities/LLSDAvatarPicker.cs
@@ -0,0 +1,51 @@
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 OpenMetaverse;
29
30namespace OpenSim.Framework.Capabilities
31{
32 [OSDMap]
33 public class LLSDAvatarPicker
34 {
35 public string next_page_url;
36 // an array of LLSDPerson
37 public OSDArray agents = new OSDArray();
38 }
39
40 [OSDMap]
41 public class LLSDPerson
42 {
43 public string username;
44 public string display_name;
45 //'display_name_next_update':d"1970-01-01T00:00:00Z"
46 public string legacy_first_name;
47 public string legacy_last_name;
48 public UUID id;
49 public bool is_display_name_default;
50 }
51} \ No newline at end of file
diff --git a/OpenSim/Data/IProfilesData.cs b/OpenSim/Data/IProfilesData.cs
new file mode 100644
index 0000000..0de7f68
--- /dev/null
+++ b/OpenSim/Data/IProfilesData.cs
@@ -0,0 +1,56 @@
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 OpenMetaverse;
30using OpenMetaverse.StructuredData;
31using OpenSim.Framework;
32
33namespace OpenSim.Data
34{
35
36 public interface IProfilesData
37 {
38 OSDArray GetClassifiedRecords(UUID creatorId);
39 bool UpdateClassifiedRecord(UserClassifiedAdd ad, ref string result);
40 bool DeleteClassifiedRecord(UUID recordId);
41 OSDArray GetAvatarPicks(UUID avatarId);
42 UserProfilePick GetPickInfo(UUID avatarId, UUID pickId);
43 bool UpdatePicksRecord(UserProfilePick pick);
44 bool DeletePicksRecord(UUID pickId);
45 bool GetAvatarNotes(ref UserProfileNotes note);
46 bool UpdateAvatarNotes(ref UserProfileNotes note, ref string result);
47 bool GetAvatarProperties(ref UserProfileProperties props, ref string result);
48 bool UpdateAvatarProperties(ref UserProfileProperties props, ref string result);
49 bool UpdateAvatarInterests(UserProfileProperties up, ref string result);
50 bool GetClassifiedInfo(ref UserClassifiedAdd ad, ref string result);
51 bool GetUserAppData(ref UserAppData props, ref string result);
52 bool SetUserAppData(UserAppData props, ref string result);
53 OSDArray GetUserImageAssets(UUID avatarId);
54 }
55}
56
diff --git a/OpenSim/Data/MSSQL/Resources/RegionStore.migrations b/OpenSim/Data/MSSQL/Resources/RegionStore.migrations
index b84c2a4..4549801 100644
--- a/OpenSim/Data/MSSQL/Resources/RegionStore.migrations
+++ b/OpenSim/Data/MSSQL/Resources/RegionStore.migrations
@@ -1153,7 +1153,7 @@ COMMIT
1153 1153
1154BEGIN TRANSACTION 1154BEGIN TRANSACTION
1155 1155
1156ALTER TABLE prims ADD COLUMN DynAttrs TEXT; 1156ALTER TABLE prims ADD DynAttrs TEXT;
1157 1157
1158COMMIT 1158COMMIT
1159 1159
@@ -1161,10 +1161,10 @@ COMMIT
1161 1161
1162BEGIN TRANSACTION 1162BEGIN TRANSACTION
1163 1163
1164ALTER TABLE prims ADD COLUMN `PhysicsShapeType` tinyint(4) NOT NULL default '0'; 1164ALTER TABLE prims ADD `PhysicsShapeType` tinyint(4) NOT NULL default '0';
1165ALTER TABLE prims ADD COLUMN `Density` double NOT NULL default '1000'; 1165ALTER TABLE prims ADD `Density` double NOT NULL default '1000';
1166ALTER TABLE prims ADD COLUMN `GravityModifier` double NOT NULL default '1'; 1166ALTER TABLE prims ADD `GravityModifier` double NOT NULL default '1';
1167ALTER TABLE prims ADD COLUMN `Friction` double NOT NULL default '0.6'; 1167ALTER TABLE prims ADD `Friction` double NOT NULL default '0.6';
1168ALTER TABLE prims ADD COLUMN `Restitution` double NOT NULL default '0.5'; 1168ALTER TABLE prims ADD `Restitution` double NOT NULL default '0.5';
1169 1169
1170COMMIT 1170COMMIT
diff --git a/OpenSim/Data/MySQL/MySQLAssetData.cs b/OpenSim/Data/MySQL/MySQLAssetData.cs
index 21dd5aa..59cc22a 100644
--- a/OpenSim/Data/MySQL/MySQLAssetData.cs
+++ b/OpenSim/Data/MySQL/MySQLAssetData.cs
@@ -142,7 +142,8 @@ namespace OpenSim.Data.MySQL
142 } 142 }
143 catch (Exception e) 143 catch (Exception e)
144 { 144 {
145 m_log.Error("[ASSETS DB]: MySql failure fetching asset " + assetID + ": " + e.Message); 145 m_log.Error(
146 string.Format("[ASSETS DB]: MySql failure fetching asset {0}. Exception ", assetID), e);
146 } 147 }
147 } 148 }
148 } 149 }
@@ -243,10 +244,11 @@ namespace OpenSim.Data.MySQL
243 } 244 }
244 catch (Exception e) 245 catch (Exception e)
245 { 246 {
246 m_log.ErrorFormat( 247 m_log.Error(
247 "[ASSETS DB]: " + 248 string.Format(
248 "MySql failure updating access_time for asset {0} with name {1}" + Environment.NewLine + e.ToString() 249 "[ASSETS DB]: Failure updating access_time for asset {0} with name {1}. Exception ",
249 + Environment.NewLine + "Attempting reconnection", asset.FullID, asset.Name); 250 asset.FullID, asset.Name),
251 e);
250 } 252 }
251 } 253 }
252 } 254 }
@@ -286,8 +288,8 @@ namespace OpenSim.Data.MySQL
286 } 288 }
287 catch (Exception e) 289 catch (Exception e)
288 { 290 {
289 m_log.ErrorFormat( 291 m_log.Error(
290 "[ASSETS DB]: MySql failure fetching asset {0}" + Environment.NewLine + e.ToString(), uuid); 292 string.Format("[ASSETS DB]: MySql failure fetching asset {0}. Exception ", uuid), e);
291 } 293 }
292 } 294 }
293 } 295 }
@@ -346,7 +348,11 @@ namespace OpenSim.Data.MySQL
346 } 348 }
347 catch (Exception e) 349 catch (Exception e)
348 { 350 {
349 m_log.Error("[ASSETS DB]: MySql failure fetching asset set" + Environment.NewLine + e.ToString()); 351 m_log.Error(
352 string.Format(
353 "[ASSETS DB]: MySql failure fetching asset set from {0}, count {1}. Exception ",
354 start, count),
355 e);
350 } 356 }
351 } 357 }
352 } 358 }
diff --git a/OpenSim/Data/MySQL/MySQLOfflineIMData.cs b/OpenSim/Data/MySQL/MySQLOfflineIMData.cs
index 252f358..bafd204 100644
--- a/OpenSim/Data/MySQL/MySQLOfflineIMData.cs
+++ b/OpenSim/Data/MySQL/MySQLOfflineIMData.cs
@@ -47,13 +47,10 @@ namespace OpenSim.Data.MySQL
47 47
48 public void DeleteOld() 48 public void DeleteOld()
49 { 49 {
50 uint now = (uint)Util.UnixTimeSinceEpoch();
51
52 using (MySqlCommand cmd = new MySqlCommand()) 50 using (MySqlCommand cmd = new MySqlCommand())
53 { 51 {
54 cmd.CommandText = String.Format("delete from {0} where TMStamp < ?tstamp", m_Realm); 52 cmd.CommandText = String.Format("delete from {0} where TMStamp < NOW() - INTERVAL 2 WEEK", m_Realm);
55 cmd.Parameters.AddWithValue("?tstamp", now - 14 * 24 * 60 * 60); // > 2 weeks old 53
56
57 ExecuteNonQuery(cmd); 54 ExecuteNonQuery(cmd);
58 } 55 }
59 56
diff --git a/OpenSim/Data/MySQL/MySQLUserProfilesData.cs b/OpenSim/Data/MySQL/MySQLUserProfilesData.cs
new file mode 100644
index 0000000..4c6c8e3
--- /dev/null
+++ b/OpenSim/Data/MySQL/MySQLUserProfilesData.cs
@@ -0,0 +1,1096 @@
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.Data;
30using System.Reflection;
31using OpenSim.Data;
32using OpenSim.Framework;
33using MySql.Data.MySqlClient;
34using OpenMetaverse;
35using OpenMetaverse.StructuredData;
36using log4net;
37
38namespace OpenSim.Data.MySQL
39{
40 public class UserProfilesData: IProfilesData
41 {
42 static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
43
44 #region Properites
45 string ConnectionString
46 {
47 get; set;
48 }
49
50 protected object Lock
51 {
52 get; set;
53 }
54
55 protected virtual Assembly Assembly
56 {
57 get { return GetType().Assembly; }
58 }
59
60 #endregion Properties
61
62 #region class Member Functions
63 public UserProfilesData(string connectionString)
64 {
65 ConnectionString = connectionString;
66 Init();
67 }
68
69 void Init()
70 {
71 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
72 {
73 dbcon.Open();
74
75 Migration m = new Migration(dbcon, Assembly, "UserProfiles");
76 m.Update();
77 }
78 }
79 #endregion Member Functions
80
81 #region Classifieds Queries
82 /// <summary>
83 /// Gets the classified records.
84 /// </summary>
85 /// <returns>
86 /// Array of classified records
87 /// </returns>
88 /// <param name='creatorId'>
89 /// Creator identifier.
90 /// </param>
91 public OSDArray GetClassifiedRecords(UUID creatorId)
92 {
93 OSDArray data = new OSDArray();
94
95 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
96 {
97 string query = "SELECT classifieduuid, name FROM classifieds WHERE creatoruuid = ?Id";
98 dbcon.Open();
99 using (MySqlCommand cmd = new MySqlCommand(query, dbcon))
100 {
101 cmd.Parameters.AddWithValue("?Id", creatorId);
102 using( MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.Default))
103 {
104 if(reader.HasRows)
105 {
106 while (reader.Read())
107 {
108 OSDMap n = new OSDMap();
109 UUID Id = UUID.Zero;
110
111 string Name = null;
112 try
113 {
114 UUID.TryParse(Convert.ToString( reader["classifieduuid"]), out Id);
115 Name = Convert.ToString(reader["name"]);
116 }
117 catch (Exception e)
118 {
119 m_log.DebugFormat("[PROFILES_DATA]" +
120 ": UserAccount exception {0}", e.Message);
121 }
122 n.Add("classifieduuid", OSD.FromUUID(Id));
123 n.Add("name", OSD.FromString(Name));
124 data.Add(n);
125 }
126 }
127 }
128 }
129 }
130 return data;
131 }
132
133 public bool UpdateClassifiedRecord(UserClassifiedAdd ad, ref string result)
134 {
135 string query = string.Empty;
136
137
138 query += "INSERT INTO classifieds (";
139 query += "`classifieduuid`,";
140 query += "`creatoruuid`,";
141 query += "`creationdate`,";
142 query += "`expirationdate`,";
143 query += "`category`,";
144 query += "`name`,";
145 query += "`description`,";
146 query += "`parceluuid`,";
147 query += "`parentestate`,";
148 query += "`snapshotuuid`,";
149 query += "`simname`,";
150 query += "`posglobal`,";
151 query += "`parcelname`,";
152 query += "`classifiedflags`,";
153 query += "`priceforlisting`) ";
154 query += "VALUES (";
155 query += "?ClassifiedId,";
156 query += "?CreatorId,";
157 query += "?CreatedDate,";
158 query += "?ExpirationDate,";
159 query += "?Category,";
160 query += "?Name,";
161 query += "?Description,";
162 query += "?ParcelId,";
163 query += "?ParentEstate,";
164 query += "?SnapshotId,";
165 query += "?SimName,";
166 query += "?GlobalPos,";
167 query += "?ParcelName,";
168 query += "?Flags,";
169 query += "?ListingPrice ) ";
170 query += "ON DUPLICATE KEY UPDATE ";
171 query += "category=?Category, ";
172 query += "expirationdate=?ExpirationDate, ";
173 query += "name=?Name, ";
174 query += "description=?Description, ";
175 query += "parentestate=?ParentEstate, ";
176 query += "posglobal=?GlobalPos, ";
177 query += "parcelname=?ParcelName, ";
178 query += "classifiedflags=?Flags, ";
179 query += "priceforlisting=?ListingPrice, ";
180 query += "snapshotuuid=?SnapshotId";
181
182 if(string.IsNullOrEmpty(ad.ParcelName))
183 ad.ParcelName = "Unknown";
184 if(ad.ParcelId == null)
185 ad.ParcelId = UUID.Zero;
186 if(string.IsNullOrEmpty(ad.Description))
187 ad.Description = "No Description";
188
189 DateTime epoch = new DateTime(1970, 1, 1);
190 DateTime now = DateTime.Now;
191 TimeSpan epochnow = now - epoch;
192 TimeSpan duration;
193 DateTime expiration;
194 TimeSpan epochexp;
195
196 if(ad.Flags == 2)
197 {
198 duration = new TimeSpan(7,0,0,0);
199 expiration = now.Add(duration);
200 epochexp = expiration - epoch;
201 }
202 else
203 {
204 duration = new TimeSpan(365,0,0,0);
205 expiration = now.Add(duration);
206 epochexp = expiration - epoch;
207 }
208 ad.CreationDate = (int)epochnow.TotalSeconds;
209 ad.ExpirationDate = (int)epochexp.TotalSeconds;
210
211 try
212 {
213 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
214 {
215 dbcon.Open();
216 using (MySqlCommand cmd = new MySqlCommand(query, dbcon))
217 {
218 cmd.Parameters.AddWithValue("?ClassifiedId", ad.ClassifiedId.ToString());
219 cmd.Parameters.AddWithValue("?CreatorId", ad.CreatorId.ToString());
220 cmd.Parameters.AddWithValue("?CreatedDate", ad.CreationDate.ToString());
221 cmd.Parameters.AddWithValue("?ExpirationDate", ad.ExpirationDate.ToString());
222 cmd.Parameters.AddWithValue("?Category", ad.Category.ToString());
223 cmd.Parameters.AddWithValue("?Name", ad.Name.ToString());
224 cmd.Parameters.AddWithValue("?Description", ad.Description.ToString());
225 cmd.Parameters.AddWithValue("?ParcelId", ad.ParcelId.ToString());
226 cmd.Parameters.AddWithValue("?ParentEstate", ad.ParentEstate.ToString());
227 cmd.Parameters.AddWithValue("?SnapshotId", ad.SnapshotId.ToString ());
228 cmd.Parameters.AddWithValue("?SimName", ad.SimName.ToString());
229 cmd.Parameters.AddWithValue("?GlobalPos", ad.GlobalPos.ToString());
230 cmd.Parameters.AddWithValue("?ParcelName", ad.ParcelName.ToString());
231 cmd.Parameters.AddWithValue("?Flags", ad.Flags.ToString());
232 cmd.Parameters.AddWithValue("?ListingPrice", ad.Price.ToString ());
233
234 cmd.ExecuteNonQuery();
235 }
236 }
237 }
238 catch (Exception e)
239 {
240 m_log.DebugFormat("[PROFILES_DATA]" +
241 ": ClassifiedesUpdate exception {0}", e.Message);
242 result = e.Message;
243 return false;
244 }
245 return true;
246 }
247
248 public bool DeleteClassifiedRecord(UUID recordId)
249 {
250 string query = string.Empty;
251
252 query += "DELETE FROM classifieds WHERE ";
253 query += "classifieduuid = ?ClasifiedId";
254
255 try
256 {
257 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
258 {
259 dbcon.Open();
260
261 using (MySqlCommand cmd = new MySqlCommand(query, dbcon))
262 {
263 cmd.Parameters.AddWithValue("?ClassifiedId", recordId.ToString());
264
265 lock(Lock)
266 {
267 cmd.ExecuteNonQuery();
268 }
269 }
270 }
271 }
272 catch (Exception e)
273 {
274 m_log.DebugFormat("[PROFILES_DATA]" +
275 ": DeleteClassifiedRecord exception {0}", e.Message);
276 return false;
277 }
278 return true;
279 }
280
281 public bool GetClassifiedInfo(ref UserClassifiedAdd ad, ref string result)
282 {
283 string query = string.Empty;
284
285 query += "SELECT * FROM classifieds WHERE ";
286 query += "classifieduuid = ?AdId";
287
288 try
289 {
290 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
291 {
292 dbcon.Open();
293 using (MySqlCommand cmd = new MySqlCommand(query, dbcon))
294 {
295 cmd.Parameters.AddWithValue("?AdId", ad.ClassifiedId.ToString());
296
297 using (MySqlDataReader reader = cmd.ExecuteReader())
298 {
299 if(reader.Read ())
300 {
301 ad.CreatorId = new UUID(reader.GetGuid("creatoruuid"));
302 ad.ParcelId = new UUID(reader.GetGuid("parceluuid"));
303 ad.SnapshotId = new UUID(reader.GetGuid("snapshotuuid"));
304 ad.CreationDate = Convert.ToInt32(reader["creationdate"]);
305 ad.ExpirationDate = Convert.ToInt32(reader["expirationdate"]);
306 ad.ParentEstate = Convert.ToInt32(reader["parentestate"]);
307 ad.Flags = (byte)reader.GetUInt32("classifiedflags");
308 ad.Category = reader.GetInt32("category");
309 ad.Price = reader.GetInt16("priceforlisting");
310 ad.Name = reader.GetString("name");
311 ad.Description = reader.GetString("description");
312 ad.SimName = reader.GetString("simname");
313 ad.GlobalPos = reader.GetString("posglobal");
314 ad.ParcelName = reader.GetString("parcelname");
315
316 }
317 }
318 }
319 dbcon.Close();
320 }
321 }
322 catch (Exception e)
323 {
324 m_log.DebugFormat("[PROFILES_DATA]" +
325 ": GetPickInfo exception {0}", e.Message);
326 }
327 return true;
328 }
329 #endregion Classifieds Queries
330
331 #region Picks Queries
332 public OSDArray GetAvatarPicks(UUID avatarId)
333 {
334 string query = string.Empty;
335
336 query += "SELECT `pickuuid`,`name` FROM userpicks WHERE ";
337 query += "creatoruuid = ?Id";
338 OSDArray data = new OSDArray();
339
340 try
341 {
342 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
343 {
344 dbcon.Open();
345 using (MySqlCommand cmd = new MySqlCommand(query, dbcon))
346 {
347 cmd.Parameters.AddWithValue("?Id", avatarId.ToString());
348
349 using (MySqlDataReader reader = cmd.ExecuteReader())
350 {
351 if(reader.HasRows)
352 {
353 while (reader.Read())
354 {
355 OSDMap record = new OSDMap();
356
357 record.Add("pickuuid",OSD.FromString((string)reader["pickuuid"]));
358 record.Add("name",OSD.FromString((string)reader["name"]));
359 data.Add(record);
360 }
361 }
362 }
363 }
364 }
365 }
366 catch (Exception e)
367 {
368 m_log.DebugFormat("[PROFILES_DATA]" +
369 ": GetAvatarPicks exception {0}", e.Message);
370 }
371 return data;
372 }
373
374 public UserProfilePick GetPickInfo(UUID avatarId, UUID pickId)
375 {
376 string query = string.Empty;
377 UserProfilePick pick = new UserProfilePick();
378
379 query += "SELECT * FROM userpicks WHERE ";
380 query += "creatoruuid = ?CreatorId AND ";
381 query += "pickuuid = ?PickId";
382
383 try
384 {
385 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
386 {
387 dbcon.Open();
388 using (MySqlCommand cmd = new MySqlCommand(query, dbcon))
389 {
390 cmd.Parameters.AddWithValue("?CreatorId", avatarId.ToString());
391 cmd.Parameters.AddWithValue("?PickId", pickId.ToString());
392
393 using (MySqlDataReader reader = cmd.ExecuteReader())
394 {
395 if(reader.HasRows)
396 {
397 reader.Read();
398
399 string description = (string)reader["description"];
400
401 if (string.IsNullOrEmpty(description))
402 description = "No description given.";
403
404 UUID.TryParse((string)reader["pickuuid"], out pick.PickId);
405 UUID.TryParse((string)reader["creatoruuid"], out pick.CreatorId);
406 UUID.TryParse((string)reader["parceluuid"], out pick.ParcelId);
407 UUID.TryParse((string)reader["snapshotuuid"], out pick.SnapshotId);
408 pick.GlobalPos = (string)reader["posglobal"];
409 bool.TryParse((string)reader["toppick"], out pick.TopPick);
410 bool.TryParse((string)reader["enabled"], out pick.Enabled);
411 pick.Name = (string)reader["name"];
412 pick.Desc = description;
413 pick.User = (string)reader["user"];
414 pick.OriginalName = (string)reader["originalname"];
415 pick.SimName = (string)reader["simname"];
416 pick.SortOrder = (int)reader["sortorder"];
417 }
418 }
419 }
420 dbcon.Close();
421 }
422 }
423 catch (Exception e)
424 {
425 m_log.DebugFormat("[PROFILES_DATA]" +
426 ": GetPickInfo exception {0}", e.Message);
427 }
428 return pick;
429 }
430
431 public bool UpdatePicksRecord(UserProfilePick pick)
432 {
433 string query = string.Empty;
434
435 query += "INSERT INTO userpicks VALUES (";
436 query += "?PickId,";
437 query += "?CreatorId,";
438 query += "?TopPick,";
439 query += "?ParcelId,";
440 query += "?Name,";
441 query += "?Desc,";
442 query += "?SnapshotId,";
443 query += "?User,";
444 query += "?Original,";
445 query += "?SimName,";
446 query += "?GlobalPos,";
447 query += "?SortOrder,";
448 query += "?Enabled) ";
449 query += "ON DUPLICATE KEY UPDATE ";
450 query += "parceluuid=?ParcelId,";
451 query += "name=?Name,";
452 query += "description=?Desc,";
453 query += "snapshotuuid=?SnapshotId,";
454 query += "pickuuid=?PickId,";
455 query += "posglobal=?GlobalPos";
456
457 try
458 {
459 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
460 {
461 dbcon.Open();
462 using (MySqlCommand cmd = new MySqlCommand(query, dbcon))
463 {
464 cmd.Parameters.AddWithValue("?PickId", pick.PickId.ToString());
465 cmd.Parameters.AddWithValue("?CreatorId", pick.CreatorId.ToString());
466 cmd.Parameters.AddWithValue("?TopPick", pick.TopPick.ToString());
467 cmd.Parameters.AddWithValue("?ParcelId", pick.ParcelId.ToString());
468 cmd.Parameters.AddWithValue("?Name", pick.Name.ToString());
469 cmd.Parameters.AddWithValue("?Desc", pick.Desc.ToString());
470 cmd.Parameters.AddWithValue("?SnapshotId", pick.SnapshotId.ToString());
471 cmd.Parameters.AddWithValue("?User", pick.User.ToString());
472 cmd.Parameters.AddWithValue("?Original", pick.OriginalName.ToString());
473 cmd.Parameters.AddWithValue("?SimName",pick.SimName.ToString());
474 cmd.Parameters.AddWithValue("?GlobalPos", pick.GlobalPos);
475 cmd.Parameters.AddWithValue("?SortOrder", pick.SortOrder.ToString ());
476 cmd.Parameters.AddWithValue("?Enabled", pick.Enabled.ToString());
477
478 cmd.ExecuteNonQuery();
479 }
480 }
481 }
482 catch (Exception e)
483 {
484 m_log.DebugFormat("[PROFILES_DATA]" +
485 ": UpdateAvatarNotes exception {0}", e.Message);
486 return false;
487 }
488 return true;
489 }
490
491 public bool DeletePicksRecord(UUID pickId)
492 {
493 string query = string.Empty;
494
495 query += "DELETE FROM userpicks WHERE ";
496 query += "pickuuid = ?PickId";
497
498 try
499 {
500 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
501 {
502 dbcon.Open();
503
504 using (MySqlCommand cmd = new MySqlCommand(query, dbcon))
505 {
506 cmd.Parameters.AddWithValue("?PickId", pickId.ToString());
507
508 cmd.ExecuteNonQuery();
509 }
510 }
511 }
512 catch (Exception e)
513 {
514 m_log.DebugFormat("[PROFILES_DATA]" +
515 ": DeleteUserPickRecord exception {0}", e.Message);
516 return false;
517 }
518 return true;
519 }
520 #endregion Picks Queries
521
522 #region Avatar Notes Queries
523 public bool GetAvatarNotes(ref UserProfileNotes notes)
524 { // WIP
525 string query = string.Empty;
526
527 query += "SELECT `notes` FROM usernotes WHERE ";
528 query += "useruuid = ?Id AND ";
529 query += "targetuuid = ?TargetId";
530 OSDArray data = new OSDArray();
531
532 try
533 {
534 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
535 {
536 dbcon.Open();
537 using (MySqlCommand cmd = new MySqlCommand(query, dbcon))
538 {
539 cmd.Parameters.AddWithValue("?Id", notes.UserId.ToString());
540 cmd.Parameters.AddWithValue("?TargetId", notes.TargetId.ToString());
541
542 using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow))
543 {
544 if(reader.HasRows)
545 {
546 reader.Read();
547 notes.Notes = OSD.FromString((string)reader["notes"]);
548 }
549 }
550 }
551 }
552 }
553 catch (Exception e)
554 {
555 m_log.DebugFormat("[PROFILES_DATA]" +
556 ": GetAvatarNotes exception {0}", e.Message);
557 }
558 return true;
559 }
560
561 public bool UpdateAvatarNotes(ref UserProfileNotes note, ref string result)
562 {
563 string query = string.Empty;
564 bool remove;
565
566 if(string.IsNullOrEmpty(note.Notes))
567 {
568 remove = true;
569 query += "DELETE FROM usernotes WHERE ";
570 query += "useruuid=?UserId AND ";
571 query += "targetuuid=?TargetId";
572 }
573 else
574 {
575 remove = false;
576 query += "INSERT INTO usernotes VALUES ( ";
577 query += "?UserId,";
578 query += "?TargetId,";
579 query += "?Notes )";
580 query += "ON DUPLICATE KEY ";
581 query += "UPDATE ";
582 query += "notes=?Notes";
583 }
584
585 try
586 {
587 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
588 {
589 dbcon.Open();
590 using (MySqlCommand cmd = new MySqlCommand(query, dbcon))
591 {
592 if(!remove)
593 cmd.Parameters.AddWithValue("?Notes", note.Notes);
594 cmd.Parameters.AddWithValue("?TargetId", note.TargetId.ToString ());
595 cmd.Parameters.AddWithValue("?UserId", note.UserId.ToString());
596
597 cmd.ExecuteNonQuery();
598 }
599 }
600 }
601 catch (Exception e)
602 {
603 m_log.DebugFormat("[PROFILES_DATA]" +
604 ": UpdateAvatarNotes exception {0}", e.Message);
605 return false;
606 }
607 return true;
608
609 }
610 #endregion Avatar Notes Queries
611
612 #region Avatar Properties
613 public bool GetAvatarProperties(ref UserProfileProperties props, ref string result)
614 {
615 string query = string.Empty;
616
617 query += "SELECT * FROM userprofile WHERE ";
618 query += "useruuid = ?Id";
619
620 try
621 {
622 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
623 {
624 dbcon.Open();
625 using (MySqlCommand cmd = new MySqlCommand(query, dbcon))
626 {
627 cmd.Parameters.AddWithValue("?Id", props.UserId.ToString());
628
629 using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow))
630 {
631 if(reader.HasRows)
632 {
633 m_log.DebugFormat("[PROFILES_DATA]" +
634 ": Getting data for {0}.", props.UserId);
635 reader.Read();
636 props.WebUrl = (string)reader["profileURL"];
637 UUID.TryParse((string)reader["profileImage"], out props.ImageId);
638 props.AboutText = (string)reader["profileAboutText"];
639 UUID.TryParse((string)reader["profileFirstImage"], out props.FirstLifeImageId);
640 props.FirstLifeText = (string)reader["profileFirstText"];
641 UUID.TryParse((string)reader["profilePartner"], out props.PartnerId);
642 props.WantToMask = (int)reader["profileWantToMask"];
643 props.WantToText = (string)reader["profileWantToText"];
644 props.SkillsMask = (int)reader["profileSkillsMask"];
645 props.SkillsText = (string)reader["profileSkillsText"];
646 props.Language = (string)reader["profileLanguages"];
647 }
648 else
649 {
650 m_log.DebugFormat("[PROFILES_DATA]" +
651 ": No data for {0}", props.UserId);
652
653 props.WebUrl = string.Empty;
654 props.ImageId = UUID.Zero;
655 props.AboutText = string.Empty;
656 props.FirstLifeImageId = UUID.Zero;
657 props.FirstLifeText = string.Empty;
658 props.PartnerId = UUID.Zero;
659 props.WantToMask = 0;
660 props.WantToText = string.Empty;
661 props.SkillsMask = 0;
662 props.SkillsText = string.Empty;
663 props.Language = string.Empty;
664 props.PublishProfile = false;
665 props.PublishMature = false;
666
667 query = "INSERT INTO userprofile (";
668 query += "useruuid, ";
669 query += "profilePartner, ";
670 query += "profileAllowPublish, ";
671 query += "profileMaturePublish, ";
672 query += "profileURL, ";
673 query += "profileWantToMask, ";
674 query += "profileWantToText, ";
675 query += "profileSkillsMask, ";
676 query += "profileSkillsText, ";
677 query += "profileLanguages, ";
678 query += "profileImage, ";
679 query += "profileAboutText, ";
680 query += "profileFirstImage, ";
681 query += "profileFirstText) VALUES (";
682 query += "?userId, ";
683 query += "?profilePartner, ";
684 query += "?profileAllowPublish, ";
685 query += "?profileMaturePublish, ";
686 query += "?profileURL, ";
687 query += "?profileWantToMask, ";
688 query += "?profileWantToText, ";
689 query += "?profileSkillsMask, ";
690 query += "?profileSkillsText, ";
691 query += "?profileLanguages, ";
692 query += "?profileImage, ";
693 query += "?profileAboutText, ";
694 query += "?profileFirstImage, ";
695 query += "?profileFirstText)";
696
697 dbcon.Close();
698 dbcon.Open();
699
700 using (MySqlCommand put = new MySqlCommand(query, dbcon))
701 {
702 put.Parameters.AddWithValue("?userId", props.UserId.ToString());
703 put.Parameters.AddWithValue("?profilePartner", props.PartnerId.ToString());
704 put.Parameters.AddWithValue("?profileAllowPublish", props.PublishProfile);
705 put.Parameters.AddWithValue("?profileMaturePublish", props.PublishMature);
706 put.Parameters.AddWithValue("?profileURL", props.WebUrl);
707 put.Parameters.AddWithValue("?profileWantToMask", props.WantToMask);
708 put.Parameters.AddWithValue("?profileWantToText", props.WantToText);
709 put.Parameters.AddWithValue("?profileSkillsMask", props.SkillsMask);
710 put.Parameters.AddWithValue("?profileSkillsText", props.SkillsText);
711 put.Parameters.AddWithValue("?profileLanguages", props.Language);
712 put.Parameters.AddWithValue("?profileImage", props.ImageId.ToString());
713 put.Parameters.AddWithValue("?profileAboutText", props.AboutText);
714 put.Parameters.AddWithValue("?profileFirstImage", props.FirstLifeImageId.ToString());
715 put.Parameters.AddWithValue("?profileFirstText", props.FirstLifeText);
716
717 put.ExecuteNonQuery();
718 }
719 }
720 }
721 }
722 }
723 }
724 catch (Exception e)
725 {
726 m_log.DebugFormat("[PROFILES_DATA]" +
727 ": Requst properties exception {0}", e.Message);
728 result = e.Message;
729 return false;
730 }
731 return true;
732 }
733
734 public bool UpdateAvatarProperties(ref UserProfileProperties props, ref string result)
735 {
736 string query = string.Empty;
737
738 query += "UPDATE userprofile SET ";
739 query += "profilePartner=?profilePartner, ";
740 query += "profileURL=?profileURL, ";
741 query += "profileImage=?image, ";
742 query += "profileAboutText=?abouttext,";
743 query += "profileFirstImage=?firstlifeimage,";
744 query += "profileFirstText=?firstlifetext ";
745 query += "WHERE useruuid=?uuid";
746
747 try
748 {
749 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
750 {
751 dbcon.Open();
752 using (MySqlCommand cmd = new MySqlCommand(query, dbcon))
753 {
754 cmd.Parameters.AddWithValue("?profileURL", props.WebUrl);
755 cmd.Parameters.AddWithValue("?profilePartner", props.PartnerId.ToString());
756 cmd.Parameters.AddWithValue("?image", props.ImageId.ToString());
757 cmd.Parameters.AddWithValue("?abouttext", props.AboutText);
758 cmd.Parameters.AddWithValue("?firstlifeimage", props.FirstLifeImageId.ToString());
759 cmd.Parameters.AddWithValue("?firstlifetext", props.FirstLifeText);
760 cmd.Parameters.AddWithValue("?uuid", props.UserId.ToString());
761
762 cmd.ExecuteNonQuery();
763 }
764 }
765 }
766 catch (Exception e)
767 {
768 m_log.DebugFormat("[PROFILES_DATA]" +
769 ": AgentPropertiesUpdate exception {0}", e.Message);
770
771 return false;
772 }
773 return true;
774 }
775 #endregion Avatar Properties
776
777 #region Avatar Interests
778 public bool UpdateAvatarInterests(UserProfileProperties up, ref string result)
779 {
780 string query = string.Empty;
781
782 query += "UPDATE userprofile SET ";
783 query += "profileWantToMask=?WantMask, ";
784 query += "profileWantToText=?WantText,";
785 query += "profileSkillsMask=?SkillsMask,";
786 query += "profileSkillsText=?SkillsText, ";
787 query += "profileLanguages=?Languages ";
788 query += "WHERE useruuid=?uuid";
789
790 try
791 {
792 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
793 {
794 dbcon.Open();
795 using (MySqlCommand cmd = new MySqlCommand(query, dbcon))
796 {
797 cmd.Parameters.AddWithValue("?WantMask", up.WantToMask);
798 cmd.Parameters.AddWithValue("?WantText", up.WantToText);
799 cmd.Parameters.AddWithValue("?SkillsMask", up.SkillsMask);
800 cmd.Parameters.AddWithValue("?SkillsText", up.SkillsText);
801 cmd.Parameters.AddWithValue("?Languages", up.Language);
802 cmd.Parameters.AddWithValue("?uuid", up.UserId.ToString());
803
804 cmd.ExecuteNonQuery();
805 }
806 }
807 }
808 catch (Exception e)
809 {
810 m_log.DebugFormat("[PROFILES_DATA]" +
811 ": AgentInterestsUpdate exception {0}", e.Message);
812 result = e.Message;
813 return false;
814 }
815 return true;
816 }
817 #endregion Avatar Interests
818
819 public OSDArray GetUserImageAssets(UUID avatarId)
820 {
821 OSDArray data = new OSDArray();
822 string query = "SELECT `snapshotuuid` FROM {0} WHERE `creatoruuid` = ?Id";
823
824 // Get classified image assets
825
826
827 try
828 {
829 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
830 {
831 dbcon.Open();
832
833 using (MySqlCommand cmd = new MySqlCommand(string.Format (query,"`classifieds`"), dbcon))
834 {
835 cmd.Parameters.AddWithValue("?Id", avatarId.ToString());
836
837 using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow))
838 {
839 if(reader.HasRows)
840 {
841 while (reader.Read())
842 {
843 data.Add(new OSDString((string)reader["snapshotuuid"].ToString ()));
844 }
845 }
846 }
847 }
848
849 dbcon.Close();
850 dbcon.Open();
851
852 using (MySqlCommand cmd = new MySqlCommand(string.Format (query,"`userpicks`"), dbcon))
853 {
854 cmd.Parameters.AddWithValue("?Id", avatarId.ToString());
855
856 using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow))
857 {
858 if(reader.HasRows)
859 {
860 while (reader.Read())
861 {
862 data.Add(new OSDString((string)reader["snapshotuuid"].ToString ()));
863 }
864 }
865 }
866 }
867
868 dbcon.Close();
869 dbcon.Open();
870
871 query = "SELECT `profileImage`, `profileFirstImage` FROM `userprofile` WHERE `useruuid` = ?Id";
872
873 using (MySqlCommand cmd = new MySqlCommand(string.Format (query,"`userpicks`"), dbcon))
874 {
875 cmd.Parameters.AddWithValue("?Id", avatarId.ToString());
876
877 using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow))
878 {
879 if(reader.HasRows)
880 {
881 while (reader.Read())
882 {
883 data.Add(new OSDString((string)reader["profileImage"].ToString ()));
884 data.Add(new OSDString((string)reader["profileFirstImage"].ToString ()));
885 }
886 }
887 }
888 }
889 }
890 }
891 catch (Exception e)
892 {
893 m_log.DebugFormat("[PROFILES_DATA]" +
894 ": GetAvatarNotes exception {0}", e.Message);
895 }
896 return data;
897 }
898
899 #region User Preferences
900 public OSDArray GetUserPreferences(UUID avatarId)
901 {
902 string query = string.Empty;
903
904 query += "SELECT imviaemail,visible,email FROM ";
905 query += "usersettings WHERE ";
906 query += "useruuid = ?Id";
907
908 OSDArray data = new OSDArray();
909
910 try
911 {
912 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
913 {
914 dbcon.Open();
915 using (MySqlCommand cmd = new MySqlCommand(query, dbcon))
916 {
917 cmd.Parameters.AddWithValue("?Id", avatarId.ToString());
918
919 using (MySqlDataReader reader = cmd.ExecuteReader())
920 {
921 if(reader.HasRows)
922 {
923 reader.Read();
924 OSDMap record = new OSDMap();
925
926 record.Add("imviaemail",OSD.FromString((string)reader["imviaemail"]));
927 record.Add("visible",OSD.FromString((string)reader["visible"]));
928 record.Add("email",OSD.FromString((string)reader["email"]));
929 data.Add(record);
930 }
931 else
932 {
933 using (MySqlCommand put = new MySqlCommand(query, dbcon))
934 {
935 query = "INSERT INTO usersettings VALUES ";
936 query += "(?Id,'false','false', '')";
937
938 lock(Lock)
939 {
940 put.ExecuteNonQuery();
941 }
942 }
943 }
944 }
945 }
946 }
947 }
948 catch (Exception e)
949 {
950 m_log.DebugFormat("[PROFILES_DATA]" +
951 ": Get preferences exception {0}", e.Message);
952 }
953 return data;
954 }
955
956 public bool UpdateUserPreferences(bool emailIm, bool visible, UUID avatarId )
957 {
958 string query = string.Empty;
959
960 query += "UPDATE userpsettings SET ";
961 query += "imviaemail=?ImViaEmail, ";
962 query += "visible=?Visible,";
963 query += "WHERE useruuid=?uuid";
964
965 try
966 {
967 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
968 {
969 dbcon.Open();
970 using (MySqlCommand cmd = new MySqlCommand(query, dbcon))
971 {
972 cmd.Parameters.AddWithValue("?ImViaEmail", emailIm.ToString().ToLower ());
973 cmd.Parameters.AddWithValue("?WantText", visible.ToString().ToLower ());
974 cmd.Parameters.AddWithValue("?uuid", avatarId.ToString());
975
976 lock(Lock)
977 {
978 cmd.ExecuteNonQuery();
979 }
980 }
981 }
982 }
983 catch (Exception e)
984 {
985 m_log.DebugFormat("[PROFILES_DATA]" +
986 ": AgentInterestsUpdate exception {0}", e.Message);
987 return false;
988 }
989 return true;
990 }
991 #endregion User Preferences
992
993 #region Integration
994 public bool GetUserAppData(ref UserAppData props, ref string result)
995 {
996 string query = string.Empty;
997
998 query += "SELECT * FROM `userdata` WHERE ";
999 query += "UserId = ?Id AND ";
1000 query += "TagId = ?TagId";
1001
1002 try
1003 {
1004 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
1005 {
1006 dbcon.Open();
1007 using (MySqlCommand cmd = new MySqlCommand(query, dbcon))
1008 {
1009 cmd.Parameters.AddWithValue("?Id", props.UserId.ToString());
1010 cmd.Parameters.AddWithValue ("?TagId", props.TagId.ToString());
1011
1012 using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow))
1013 {
1014 if(reader.HasRows)
1015 {
1016 reader.Read();
1017 props.DataKey = (string)reader["DataKey"];
1018 props.DataVal = (string)reader["DataVal"];
1019 }
1020 else
1021 {
1022 query += "INSERT INTO userdata VALUES ( ";
1023 query += "?UserId,";
1024 query += "?TagId,";
1025 query += "?DataKey,";
1026 query += "?DataVal) ";
1027
1028 using (MySqlCommand put = new MySqlCommand(query, dbcon))
1029 {
1030 put.Parameters.AddWithValue("?Id", props.UserId.ToString());
1031 put.Parameters.AddWithValue("?TagId", props.TagId.ToString());
1032 put.Parameters.AddWithValue("?DataKey", props.DataKey.ToString());
1033 put.Parameters.AddWithValue("?DataVal", props.DataVal.ToString());
1034
1035 lock(Lock)
1036 {
1037 put.ExecuteNonQuery();
1038 }
1039 }
1040 }
1041 }
1042 }
1043 }
1044 }
1045 catch (Exception e)
1046 {
1047 m_log.DebugFormat("[PROFILES_DATA]" +
1048 ": Requst application data exception {0}", e.Message);
1049 result = e.Message;
1050 return false;
1051 }
1052 return true;
1053 }
1054
1055 public bool SetUserAppData(UserAppData props, ref string result)
1056 {
1057 string query = string.Empty;
1058
1059 query += "UPDATE userdata SET ";
1060 query += "TagId = ?TagId, ";
1061 query += "DataKey = ?DataKey, ";
1062 query += "DataVal = ?DataVal WHERE ";
1063 query += "UserId = ?UserId AND ";
1064 query += "TagId = ?TagId";
1065
1066 try
1067 {
1068 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
1069 {
1070 dbcon.Open();
1071 using (MySqlCommand cmd = new MySqlCommand(query, dbcon))
1072 {
1073 cmd.Parameters.AddWithValue("?UserId", props.UserId.ToString());
1074 cmd.Parameters.AddWithValue("?TagId", props.TagId.ToString ());
1075 cmd.Parameters.AddWithValue("?DataKey", props.DataKey.ToString ());
1076 cmd.Parameters.AddWithValue("?DataVal", props.DataKey.ToString ());
1077
1078 lock(Lock)
1079 {
1080 cmd.ExecuteNonQuery();
1081 }
1082 }
1083 }
1084 }
1085 catch (Exception e)
1086 {
1087 m_log.DebugFormat("[PROFILES_DATA]" +
1088 ": SetUserData exception {0}", e.Message);
1089 return false;
1090 }
1091 return true;
1092 }
1093 #endregion Integration
1094 }
1095}
1096
diff --git a/OpenSim/Data/MySQL/Resources/EstateStore.migrations b/OpenSim/Data/MySQL/Resources/EstateStore.migrations
index df82a2e..2d1c2b5 100644
--- a/OpenSim/Data/MySQL/Resources/EstateStore.migrations
+++ b/OpenSim/Data/MySQL/Resources/EstateStore.migrations
@@ -77,5 +77,11 @@ BEGIN;
77ALTER TABLE estate_settings AUTO_INCREMENT = 100; 77ALTER TABLE estate_settings AUTO_INCREMENT = 100;
78COMMIT; 78COMMIT;
79 79
80:VERSION 33 #---------------------
80 81
82BEGIN;
83ALTER TABLE estate_settings ADD COLUMN `AllowLandmark` tinyint(4) NOT NULL default '1';
84ALTER TABLE estate_settings ADD COLUMN `AllowParcelChanges` tinyint(4) NOT NULL default '1';
85ALTER TABLE estate_settings ADD COLUMN `AllowSetHome` tinyint(4) NOT NULL default '1';
86COMMIT;
81 87
diff --git a/OpenSim/Data/MySQL/Resources/UserProfiles.migrations b/OpenSim/Data/MySQL/Resources/UserProfiles.migrations
new file mode 100644
index 0000000..c29f1ab
--- /dev/null
+++ b/OpenSim/Data/MySQL/Resources/UserProfiles.migrations
@@ -0,0 +1,83 @@
1:VERSION 1 # -------------------------------
2
3begin;
4
5CREATE TABLE IF NOT EXISTS `classifieds` (
6 `classifieduuid` char(36) NOT NULL,
7 `creatoruuid` char(36) NOT NULL,
8 `creationdate` int(20) NOT NULL,
9 `expirationdate` int(20) NOT NULL,
10 `category` varchar(20) NOT NULL,
11 `name` varchar(255) NOT NULL,
12 `description` text NOT NULL,
13 `parceluuid` char(36) NOT NULL,
14 `parentestate` int(11) NOT NULL,
15 `snapshotuuid` char(36) NOT NULL,
16 `simname` varchar(255) NOT NULL,
17 `posglobal` varchar(255) NOT NULL,
18 `parcelname` varchar(255) NOT NULL,
19 `classifiedflags` int(8) NOT NULL,
20 `priceforlisting` int(5) NOT NULL,
21 PRIMARY KEY (`classifieduuid`)
22) ENGINE=InnoDB DEFAULT CHARSET=latin1;
23
24
25CREATE TABLE IF NOT EXISTS `usernotes` (
26 `useruuid` varchar(36) NOT NULL,
27 `targetuuid` varchar(36) NOT NULL,
28 `notes` text NOT NULL,
29 UNIQUE KEY `useruuid` (`useruuid`,`targetuuid`)
30) ENGINE=MyISAM DEFAULT CHARSET=latin1;
31
32
33CREATE TABLE IF NOT EXISTS `userpicks` (
34 `pickuuid` varchar(36) NOT NULL,
35 `creatoruuid` varchar(36) NOT NULL,
36 `toppick` enum('true','false') NOT NULL,
37 `parceluuid` varchar(36) NOT NULL,
38 `name` varchar(255) NOT NULL,
39 `description` text NOT NULL,
40 `snapshotuuid` varchar(36) NOT NULL,
41 `user` varchar(255) NOT NULL,
42 `originalname` varchar(255) NOT NULL,
43 `simname` varchar(255) NOT NULL,
44 `posglobal` varchar(255) NOT NULL,
45 `sortorder` int(2) NOT NULL,
46 `enabled` enum('true','false') NOT NULL,
47 PRIMARY KEY (`pickuuid`)
48) ENGINE=MyISAM DEFAULT CHARSET=latin1;
49
50
51CREATE TABLE IF NOT EXISTS `userprofile` (
52 `useruuid` varchar(36) NOT NULL,
53 `profilePartner` varchar(36) NOT NULL,
54 `profileAllowPublish` binary(1) NOT NULL,
55 `profileMaturePublish` binary(1) NOT NULL,
56 `profileURL` varchar(255) NOT NULL,
57 `profileWantToMask` int(3) NOT NULL,
58 `profileWantToText` text NOT NULL,
59 `profileSkillsMask` int(3) NOT NULL,
60 `profileSkillsText` text NOT NULL,
61 `profileLanguages` text NOT NULL,
62 `profileImage` varchar(36) NOT NULL,
63 `profileAboutText` text NOT NULL,
64 `profileFirstImage` varchar(36) NOT NULL,
65 `profileFirstText` text NOT NULL,
66 PRIMARY KEY (`useruuid`)
67) ENGINE=MyISAM DEFAULT CHARSET=latin1;
68
69commit;
70
71:VERSION 2 # -------------------------------
72
73begin;
74CREATE TABLE IF NOT EXISTS `userdata` (
75 `UserId` char(36) NOT NULL,
76 `TagId` varchar(64) NOT NULL,
77 `DataKey` varchar(255),
78 `DataVal` varchar(255),
79 PRIMARY KEY (`UserId`,`TagId`)
80) ENGINE=MyISAM DEFAULT CHARSET=latin1;
81
82commit;
83
diff --git a/OpenSim/Data/SQLite/Resources/EstateStore.migrations b/OpenSim/Data/SQLite/Resources/EstateStore.migrations
index 62f6464..0aec49b 100644
--- a/OpenSim/Data/SQLite/Resources/EstateStore.migrations
+++ b/OpenSim/Data/SQLite/Resources/EstateStore.migrations
@@ -86,3 +86,12 @@ begin;
86alter table estate_settings add column DenyMinors tinyint not null default 0; 86alter table estate_settings add column DenyMinors tinyint not null default 0;
87 87
88commit; 88commit;
89
90:VERSION 9
91
92begin;
93alter table estate_settings add column AllowLandmark tinyint not null default '1';
94alter table estate_settings add column AllowParcelChanges tinyint not null default '1';
95alter table estate_settings add column AllowSetHome tinyint not null default '1';
96commit;
97
diff --git a/OpenSim/Framework/Animation.cs b/OpenSim/Framework/Animation.cs
index 232f5a1..8bdf8f4 100644
--- a/OpenSim/Framework/Animation.cs
+++ b/OpenSim/Framework/Animation.cs
@@ -120,5 +120,25 @@ namespace OpenSim.Framework
120 sequenceNum = args["seq_num"].AsInteger(); 120 sequenceNum = args["seq_num"].AsInteger();
121 } 121 }
122 122
123 public override bool Equals(object obj)
124 {
125 Animation other = obj as Animation;
126 if (other != null)
127 {
128 return (other.AnimID == this.AnimID
129 && other.SequenceNum == this.SequenceNum
130 && other.ObjectID == this.ObjectID);
131 }
132
133 return base.Equals(obj);
134 }
135
136 public override string ToString()
137 {
138 return "AnimID=" + AnimID.ToString()
139 + "/seq=" + SequenceNum.ToString()
140 + "/objID=" + ObjectID.ToString();
141 }
142
123 } 143 }
124} 144}
diff --git a/OpenSim/Framework/CachedTextureEventArg.cs b/OpenSim/Framework/CachedTextureEventArg.cs
new file mode 100644
index 0000000..239fc56
--- /dev/null
+++ b/OpenSim/Framework/CachedTextureEventArg.cs
@@ -0,0 +1,46 @@
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.Text;
30using OpenMetaverse;
31
32namespace OpenSim.Framework
33{
34 public class CachedTextureRequestArg
35 {
36 public int BakedTextureIndex;
37 public UUID WearableHashID;
38 }
39
40 public class CachedTextureResponseArg
41 {
42 public int BakedTextureIndex;
43 public UUID BakedTextureID;
44 public String HostName;
45 }
46}
diff --git a/OpenSim/Framework/Console/LocalConsole.cs b/OpenSim/Framework/Console/LocalConsole.cs
index d41481f..a967db6 100644
--- a/OpenSim/Framework/Console/LocalConsole.cs
+++ b/OpenSim/Framework/Console/LocalConsole.cs
@@ -426,6 +426,21 @@ namespace OpenSim.Framework.Console
426 System.Console.Write("{0}", prompt); 426 System.Console.Write("{0}", prompt);
427 427
428 break; 428 break;
429 case ConsoleKey.Delete:
430 if (m_cursorXPosition == m_commandLine.Length)
431 break;
432
433 m_commandLine.Remove(m_cursorXPosition, 1);
434
435 SetCursorLeft(0);
436 m_cursorYPosition = SetCursorTop(m_cursorYPosition);
437
438 if (m_echo)
439 System.Console.Write("{0}{1} ", prompt, m_commandLine);
440 else
441 System.Console.Write("{0}", prompt);
442
443 break;
429 case ConsoleKey.End: 444 case ConsoleKey.End:
430 m_cursorXPosition = m_commandLine.Length; 445 m_cursorXPosition = m_commandLine.Length;
431 break; 446 break;
diff --git a/OpenSim/Framework/EstateSettings.cs b/OpenSim/Framework/EstateSettings.cs
index e03750b..5ddbd61 100644
--- a/OpenSim/Framework/EstateSettings.cs
+++ b/OpenSim/Framework/EstateSettings.cs
@@ -430,6 +430,5 @@ namespace OpenSim.Framework
430 { 430 {
431 return l_EstateGroups.Contains(groupID); 431 return l_EstateGroups.Contains(groupID);
432 } 432 }
433
434 } 433 }
435} 434}
diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs
index ad3471a..6c9e7c9 100644
--- a/OpenSim/Framework/IClientAPI.cs
+++ b/OpenSim/Framework/IClientAPI.cs
@@ -65,6 +65,7 @@ namespace OpenSim.Framework
65 public delegate void NetworkStats(int inPackets, int outPackets, int unAckedBytes); 65 public delegate void NetworkStats(int inPackets, int outPackets, int unAckedBytes);
66 66
67 public delegate void SetAppearance(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 AvSize, WearableCacheItem[] CacheItems); 67 public delegate void SetAppearance(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 AvSize, WearableCacheItem[] CacheItems);
68 public delegate void CachedTextureRequest(IClientAPI remoteClient, int serial, List<CachedTextureRequestArg> cachedTextureRequest);
68 69
69 public delegate void StartAnim(IClientAPI remoteClient, UUID animID); 70 public delegate void StartAnim(IClientAPI remoteClient, UUID animID);
70 71
@@ -789,6 +790,7 @@ namespace OpenSim.Framework
789 event EstateChangeInfo OnEstateChangeInfo; 790 event EstateChangeInfo OnEstateChangeInfo;
790 event EstateManageTelehub OnEstateManageTelehub; 791 event EstateManageTelehub OnEstateManageTelehub;
791 // [Obsolete("LLClientView Specific.")] 792 // [Obsolete("LLClientView Specific.")]
793 event CachedTextureRequest OnCachedTextureRequest;
792 event SetAppearance OnSetAppearance; 794 event SetAppearance OnSetAppearance;
793 // [Obsolete("LLClientView Specific - Replace and rename OnAvatarUpdate. Difference from SetAppearance?")] 795 // [Obsolete("LLClientView Specific - Replace and rename OnAvatarUpdate. Difference from SetAppearance?")]
794 event AvatarNowWearing OnAvatarNowWearing; 796 event AvatarNowWearing OnAvatarNowWearing;
@@ -1100,14 +1102,15 @@ namespace OpenSim.Framework
1100 /// <param name="textureEntry"></param> 1102 /// <param name="textureEntry"></param>
1101 void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry); 1103 void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry);
1102 1104
1105 void SendCachedTextureResponse(ISceneEntity avatar, int serial, List<CachedTextureResponseArg> cachedTextures);
1106
1103 void SendStartPingCheck(byte seq); 1107 void SendStartPingCheck(byte seq);
1104 1108
1105 /// <summary> 1109 /// <summary>
1106 /// Tell the client that an object has been deleted 1110 /// Tell the client that an object has been deleted
1107 /// </summary> 1111 /// </summary>
1108 /// <param name="regionHandle"></param>
1109 /// <param name="localID"></param> 1112 /// <param name="localID"></param>
1110 void SendKillObject(ulong regionHandle, List<uint> localID); 1113 void SendKillObject(List<uint> localID);
1111 1114
1112 void SendAnimations(UUID[] animID, int[] seqs, UUID sourceAgentId, UUID[] objectIDs); 1115 void SendAnimations(UUID[] animID, int[] seqs, UUID sourceAgentId, UUID[] objectIDs);
1113 void SendRegionHandshake(RegionInfo regionInfo, RegionHandshakeArgs args); 1116 void SendRegionHandshake(RegionInfo regionInfo, RegionHandshakeArgs args);
diff --git a/OpenSim/Framework/IPeople.cs b/OpenSim/Framework/IPeople.cs
new file mode 100644
index 0000000..b88e103
--- /dev/null
+++ b/OpenSim/Framework/IPeople.cs
@@ -0,0 +1,47 @@
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 OpenMetaverse;
31
32namespace OpenSim.Framework
33{
34 public class UserData
35 {
36 public UUID Id { get; set; }
37 public string FirstName { get; set; }
38 public string LastName { get; set; }
39 public string HomeURL { get; set; }
40 public Dictionary<string, object> ServerURLs { get; set; }
41 }
42
43 public interface IPeople
44 {
45 List<UserData> GetUserData(string query, int page_size, int page_number);
46 }
47} \ No newline at end of file
diff --git a/OpenSim/Framework/IScene.cs b/OpenSim/Framework/IScene.cs
index 87ec99e..8164f41 100644
--- a/OpenSim/Framework/IScene.cs
+++ b/OpenSim/Framework/IScene.cs
@@ -136,5 +136,10 @@ namespace OpenSim.Framework
136 ISceneObject DeserializeObject(string representation); 136 ISceneObject DeserializeObject(string representation);
137 137
138 bool CheckClient(UUID agentID, System.Net.IPEndPoint ep); 138 bool CheckClient(UUID agentID, System.Net.IPEndPoint ep);
139
140 /// <summary>
141 /// Start the scene and associated scripts within it.
142 /// </summary>
143 void Start();
139 } 144 }
140} 145} \ No newline at end of file
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
index 97035e3..74954cc 100644
--- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
+++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
@@ -454,7 +454,7 @@ namespace OpenSim.Framework.Servers.HttpServer
454 } 454 }
455 455
456 OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request),context); 456 OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request),context);
457 457 resp.ReuseContext = true;
458 HandleRequest(req, resp); 458 HandleRequest(req, resp);
459 459
460 460
diff --git a/OpenSim/Framework/Servers/ServerBase.cs b/OpenSim/Framework/Servers/ServerBase.cs
index 1ff8aca..b9e3c18 100644
--- a/OpenSim/Framework/Servers/ServerBase.cs
+++ b/OpenSim/Framework/Servers/ServerBase.cs
@@ -76,6 +76,11 @@ namespace OpenSim.Framework.Servers
76 76
77 protected void CreatePIDFile(string path) 77 protected void CreatePIDFile(string path)
78 { 78 {
79 if (File.Exists(path))
80 m_log.ErrorFormat(
81 "[SERVER BASE]: Previous pid file {0} still exists on startup. Possibly previously unclean shutdown.",
82 path);
83
79 try 84 try
80 { 85 {
81 string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString(); 86 string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString();
diff --git a/OpenSim/Framework/UserProfiles.cs b/OpenSim/Framework/UserProfiles.cs
new file mode 100644
index 0000000..6133591
--- /dev/null
+++ b/OpenSim/Framework/UserProfiles.cs
@@ -0,0 +1,117 @@
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 OpenMetaverse;
30
31namespace OpenSim.Framework
32{
33 public class UserClassifiedAdd
34 {
35 public UUID ClassifiedId = UUID.Zero;
36 public UUID CreatorId = UUID.Zero;
37 public int CreationDate = 0;
38 public int ExpirationDate = 0;
39 public int Category = 0;
40 public string Name = string.Empty;
41 public string Description = string.Empty;
42 public UUID ParcelId = UUID.Zero;
43 public int ParentEstate = 0;
44 public UUID SnapshotId = UUID.Zero;
45 public string SimName = string.Empty;
46 public string GlobalPos = "<0,0,0>";
47 public string ParcelName = string.Empty;
48 public byte Flags = 0;
49 public int Price = 0;
50 }
51
52 public class UserProfileProperties
53 {
54 public UUID UserId = UUID.Zero;
55 public UUID PartnerId = UUID.Zero;
56 public bool PublishProfile = false;
57 public bool PublishMature = false;
58 public string WebUrl = string.Empty;
59 public int WantToMask = 0;
60 public string WantToText = string.Empty;
61 public int SkillsMask = 0;
62 public string SkillsText = string.Empty;
63 public string Language = string.Empty;
64 public UUID ImageId = UUID.Zero;
65 public string AboutText = string.Empty;
66 public UUID FirstLifeImageId = UUID.Zero;
67 public string FirstLifeText = string.Empty;
68 }
69
70 public class UserProfilePick
71 {
72 public UUID PickId = UUID.Zero;
73 public UUID CreatorId = UUID.Zero;
74 public bool TopPick = false;
75 public string Name = string.Empty;
76 public string OriginalName = string.Empty;
77 public string Desc = string.Empty;
78 public UUID ParcelId = UUID.Zero;
79 public UUID SnapshotId = UUID.Zero;
80 public string User = string.Empty;
81 public string SimName = string.Empty;
82 public string GlobalPos = "<0,0,0>";
83 public int SortOrder = 0;
84 public bool Enabled = false;
85 }
86
87 public class UserProfileNotes
88 {
89 public UUID UserId;
90 public UUID TargetId;
91 public string Notes;
92 }
93
94 public class UserAccountProperties
95 {
96 public string EmailAddress = string.Empty;
97 public string Firstname = string.Empty;
98 public string LastName = string.Empty;
99 public string Password = string.Empty;
100 public string UserId = string.Empty;
101 }
102
103 public class UserAccountAuth
104 {
105 public string UserId = UUID.Zero.ToString();
106 public string Password = string.Empty;
107 }
108
109 public class UserAppData
110 {
111 public string TagId = string.Empty;
112 public string DataKey = string.Empty;
113 public string UserId = UUID.Zero.ToString();
114 public string DataVal = string.Empty;
115 }
116}
117
diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs
index 557f38e..0852b49 100644
--- a/OpenSim/Framework/Util.cs
+++ b/OpenSim/Framework/Util.cs
@@ -1852,7 +1852,7 @@ namespace OpenSim.Framework
1852 case FireAndForgetMethod.SmartThreadPool: 1852 case FireAndForgetMethod.SmartThreadPool:
1853 if (m_ThreadPool == null) 1853 if (m_ThreadPool == null)
1854 InitThreadPool(15); 1854 InitThreadPool(15);
1855 m_ThreadPool.QueueWorkItem(SmartThreadPoolCallback, new object[] { realCallback, obj }); 1855 m_ThreadPool.QueueWorkItem((cb, o) => cb(o), realCallback, obj);
1856 break; 1856 break;
1857 case FireAndForgetMethod.Thread: 1857 case FireAndForgetMethod.Thread:
1858 Thread thread = new Thread(delegate(object o) { realCallback(o); }); 1858 Thread thread = new Thread(delegate(object o) { realCallback(o); });
@@ -1922,15 +1922,15 @@ namespace OpenSim.Framework
1922 return sb.ToString(); 1922 return sb.ToString();
1923 } 1923 }
1924 1924
1925 private static object SmartThreadPoolCallback(object o) 1925// private static object SmartThreadPoolCallback(object o)
1926 { 1926// {
1927 object[] array = (object[])o; 1927// object[] array = (object[])o;
1928 WaitCallback callback = (WaitCallback)array[0]; 1928// WaitCallback callback = (WaitCallback)array[0];
1929 object obj = array[1]; 1929// object obj = array[1];
1930 1930//
1931 callback(obj); 1931// callback(obj);
1932 return null; 1932// return null;
1933 } 1933// }
1934 1934
1935 #endregion FireAndForget Threading Pattern 1935 #endregion FireAndForget Threading Pattern
1936 1936
@@ -2148,7 +2148,7 @@ namespace OpenSim.Framework
2148 /// <param name="secret">the secret part</param> 2148 /// <param name="secret">the secret part</param>
2149 public static bool ParseUniversalUserIdentifier(string value, out UUID uuid, out string url, out string firstname, out string lastname, out string secret) 2149 public static bool ParseUniversalUserIdentifier(string value, out UUID uuid, out string url, out string firstname, out string lastname, out string secret)
2150 { 2150 {
2151 uuid = UUID.Zero; url = string.Empty; firstname = "Unknown"; lastname = "User"; secret = string.Empty; 2151 uuid = UUID.Zero; url = string.Empty; firstname = "Unknown"; lastname = "UserUPUUI"; secret = string.Empty;
2152 2152
2153 string[] parts = value.Split(';'); 2153 string[] parts = value.Split(';');
2154 if (parts.Length >= 1) 2154 if (parts.Length >= 1)
diff --git a/OpenSim/Region/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs
index 7361f50..0ed85b8 100644
--- a/OpenSim/Region/Application/OpenSimBase.cs
+++ b/OpenSim/Region/Application/OpenSimBase.cs
@@ -504,9 +504,6 @@ namespace OpenSim
504 scene.SnmpService.LinkUp(scene); 504 scene.SnmpService.LinkUp(scene);
505 } 505 }
506 506
507 scene.Start();
508 scene.StartScripts();
509
510 return clientServers; 507 return clientServers;
511 } 508 }
512 509
@@ -821,7 +818,7 @@ namespace OpenSim
821 818
822 if (foundClientServer) 819 if (foundClientServer)
823 { 820 {
824 m_clientServers[clientServerElement].NetworkStop(); 821 m_clientServers[clientServerElement].Stop();
825 m_clientServers.RemoveAt(clientServerElement); 822 m_clientServers.RemoveAt(clientServerElement);
826 } 823 }
827 } 824 }
@@ -835,6 +832,7 @@ namespace OpenSim
835 ShutdownClientServer(whichRegion); 832 ShutdownClientServer(whichRegion);
836 IScene scene; 833 IScene scene;
837 CreateRegion(whichRegion, true, out scene); 834 CreateRegion(whichRegion, true, out scene);
835 scene.Start();
838 } 836 }
839 837
840 # region Setup methods 838 # region Setup methods
diff --git a/OpenSim/Region/ClientStack/IClientNetworkServer.cs b/OpenSim/Region/ClientStack/IClientNetworkServer.cs
index 54a441b..bb7e6d0 100644
--- a/OpenSim/Region/ClientStack/IClientNetworkServer.cs
+++ b/OpenSim/Region/ClientStack/IClientNetworkServer.cs
@@ -38,11 +38,22 @@ namespace OpenSim.Region.ClientStack
38 IPAddress _listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, 38 IPAddress _listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource,
39 AgentCircuitManager authenticateClass); 39 AgentCircuitManager authenticateClass);
40 40
41 void NetworkStop();
42 bool HandlesRegion(Location x); 41 bool HandlesRegion(Location x);
43 void AddScene(IScene x);
44 42
43 /// <summary>
44 /// Add the given scene to be handled by this IClientNetworkServer.
45 /// </summary>
46 /// <param name='scene'></param>
47 void AddScene(IScene scene);
48
49 /// <summary>
50 /// Start sending and receiving data.
51 /// </summary>
45 void Start(); 52 void Start();
53
54 /// <summary>
55 /// Stop sending and receiving data.
56 /// </summary>
46 void Stop(); 57 void Stop();
47 } 58 }
48} 59}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs
new file mode 100644
index 0000000..9f2aed0
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs
@@ -0,0 +1,139 @@
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.Collections.Specialized;
31using System.Drawing;
32using System.Drawing.Imaging;
33using System.Reflection;
34using System.IO;
35using System.Web;
36using log4net;
37using Nini.Config;
38using Mono.Addins;
39using OpenMetaverse;
40using OpenMetaverse.StructuredData;
41using OpenSim.Framework;
42using OpenSim.Framework.Servers;
43using OpenSim.Framework.Servers.HttpServer;
44using OpenSim.Region.Framework.Interfaces;
45using OpenSim.Region.Framework.Scenes;
46using OpenSim.Services.Interfaces;
47using Caps = OpenSim.Framework.Capabilities.Caps;
48using OpenSim.Capabilities.Handlers;
49
50namespace OpenSim.Region.ClientStack.Linden
51{
52
53 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AvatarPickerSearchModule")]
54 public class AvatarPickerSearchModule : INonSharedRegionModule
55 {
56 private static readonly ILog m_log =
57 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
58
59 private Scene m_scene;
60 private IPeople m_People;
61 private bool m_Enabled = false;
62
63 private string m_URL;
64
65 #region ISharedRegionModule Members
66
67 public void Initialise(IConfigSource source)
68 {
69 IConfig config = source.Configs["ClientStack.LindenCaps"];
70 if (config == null)
71 return;
72
73 m_URL = config.GetString("Cap_AvatarPickerSearch", string.Empty);
74 // Cap doesn't exist
75 if (m_URL != string.Empty)
76 m_Enabled = true;
77 }
78
79 public void AddRegion(Scene s)
80 {
81 if (!m_Enabled)
82 return;
83
84 m_scene = s;
85 }
86
87 public void RemoveRegion(Scene s)
88 {
89 if (!m_Enabled)
90 return;
91
92 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
93 m_scene = null;
94 }
95
96 public void RegionLoaded(Scene s)
97 {
98 if (!m_Enabled)
99 return;
100
101 m_People = m_scene.RequestModuleInterface<IPeople>();
102 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
103 }
104
105 public void PostInitialise()
106 {
107 }
108
109 public void Close() { }
110
111 public string Name { get { return "AvatarPickerSearchModule"; } }
112
113 public Type ReplaceableInterface
114 {
115 get { return null; }
116 }
117
118 #endregion
119
120 public void RegisterCaps(UUID agentID, Caps caps)
121 {
122 UUID capID = UUID.Random();
123
124 if (m_URL == "localhost")
125 {
126 m_log.DebugFormat("[AVATAR PICKER SEARCH]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName);
127 caps.RegisterHandler(
128 "AvatarPickerSearch",
129 new AvatarPickerSearchHandler("/CAPS/" + capID + "/", m_People, "AvatarPickerSearch", "Search for avatars by name"));
130 }
131 else
132 {
133 // m_log.DebugFormat("[AVATAR PICKER SEARCH]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName);
134 caps.RegisterHandler("AvatarPickerSearch", m_URL);
135 }
136 }
137
138 }
139}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
index 3995620..dfc4419 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
@@ -429,7 +429,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
429 if (!assetServerURL.EndsWith("/") && !assetServerURL.EndsWith("=")) 429 if (!assetServerURL.EndsWith("/") && !assetServerURL.EndsWith("="))
430 assetServerURL = assetServerURL + "/"; 430 assetServerURL = assetServerURL + "/";
431 431
432 m_log.DebugFormat("[J2KIMAGE]: texture {0} not found in local asset storage. Trying user's storage.", assetServerURL + id); 432// m_log.DebugFormat("[J2KIMAGE]: texture {0} not found in local asset storage. Trying user's storage.", assetServerURL + id);
433 AssetService.Get(assetServerURL + id, InventoryAccessModule, AssetReceived); 433 AssetService.Get(assetServerURL + id, InventoryAccessModule, AssetReceived);
434 return; 434 return;
435 } 435 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index eebb8ae..c78d552 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -84,6 +84,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
84 public event ModifyTerrain OnModifyTerrain; 84 public event ModifyTerrain OnModifyTerrain;
85 public event Action<IClientAPI> OnRegionHandShakeReply; 85 public event Action<IClientAPI> OnRegionHandShakeReply;
86 public event GenericCall1 OnRequestWearables; 86 public event GenericCall1 OnRequestWearables;
87 public event CachedTextureRequest OnCachedTextureRequest;
87 public event SetAppearance OnSetAppearance; 88 public event SetAppearance OnSetAppearance;
88 public event AvatarNowWearing OnAvatarNowWearing; 89 public event AvatarNowWearing OnAvatarNowWearing;
89 public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv; 90 public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv;
@@ -820,12 +821,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
820 handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType); 821 handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType);
821 handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes; 822 handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes;
822 823
823 handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[0]; 824 handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[1];
824// OutPacket(handshake, ThrottleOutPacketType.Task); 825 handshake.RegionInfo4[0] = new RegionHandshakePacket.RegionInfo4Block();
825 // use same as MoveAgentIntoRegion (both should be task ) 826 handshake.RegionInfo4[0].RegionFlagsExtended = args.regionFlags;
827 handshake.RegionInfo4[0].RegionProtocols = 0; // 1 here would indicate that SSB is supported
828
826 OutPacket(handshake, ThrottleOutPacketType.Unknown); 829 OutPacket(handshake, ThrottleOutPacketType.Unknown);
827 } 830 }
828 831
832
829 public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) 833 public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look)
830 { 834 {
831 AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete); 835 AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete);
@@ -1580,7 +1584,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1580 OutPacket(pc, ThrottleOutPacketType.Unknown); 1584 OutPacket(pc, ThrottleOutPacketType.Unknown);
1581 } 1585 }
1582 1586
1583 public void SendKillObject(ulong regionHandle, List<uint> localIDs) 1587 public void SendKillObject(List<uint> localIDs)
1584 { 1588 {
1585// foreach (uint id in localIDs) 1589// foreach (uint id in localIDs)
1586// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle); 1590// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle);
@@ -11717,8 +11721,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11717 } 11721 }
11718 11722
11719 /// <summary> 11723 /// <summary>
11720 /// Send a response back to a client when it asks the asset server (via the region server) if it has
11721 /// its appearance texture cached.
11722 /// </summary> 11724 /// </summary>
11723 /// <remarks> 11725 /// <remarks>
11724 /// At the moment, we always reply that there is no cached texture. 11726 /// At the moment, we always reply that there is no cached texture.
@@ -11726,6 +11728,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11726 /// <param name="simclient"></param> 11728 /// <param name="simclient"></param>
11727 /// <param name="packet"></param> 11729 /// <param name="packet"></param>
11728 /// <returns></returns> 11730 /// <returns></returns>
11731 // TODO: Convert old handler to use new method
11732 /*protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet)
11733 {
11734 AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet;
11735
11736 if (cachedtex.AgentData.SessionID != SessionId)
11737 return false;
11738
11739
11740 List<CachedTextureRequestArg> requestArgs = new List<CachedTextureRequestArg>();
11741
11742 for (int i = 0; i < cachedtex.WearableData.Length; i++)
11743 {
11744 CachedTextureRequestArg arg = new CachedTextureRequestArg();
11745 arg.BakedTextureIndex = cachedtex.WearableData[i].TextureIndex;
11746 arg.WearableHashID = cachedtex.WearableData[i].ID;
11747
11748 requestArgs.Add(arg);
11749 }
11750
11751 CachedTextureRequest handlerCachedTextureRequest = OnCachedTextureRequest;
11752 if (handlerCachedTextureRequest != null)
11753 {
11754 handlerCachedTextureRequest(simclient,cachedtex.AgentData.SerialNum,requestArgs);
11755 }
11756
11757 return true;
11758 }*/
11759
11729 protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet) 11760 protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet)
11730 { 11761 {
11731 //m_log.Debug("texture cached: " + packet.ToString()); 11762 //m_log.Debug("texture cached: " + packet.ToString());
@@ -11884,6 +11915,40 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11884 return true; 11915 return true;
11885 } 11916 }
11886 11917
11918 /// <summary>
11919 /// Send a response back to a client when it asks the asset server (via the region server) if it has
11920 /// its appearance texture cached.
11921 /// </summary>
11922 /// <param name="avatar"></param>
11923 /// <param name="serial"></param>
11924 /// <param name="cachedTextures"></param>
11925 /// <returns></returns>
11926 public void SendCachedTextureResponse(ISceneEntity avatar, int serial, List<CachedTextureResponseArg> cachedTextures)
11927 {
11928 ScenePresence presence = avatar as ScenePresence;
11929 if (presence == null)
11930 return;
11931
11932 AgentCachedTextureResponsePacket cachedresp = (AgentCachedTextureResponsePacket)PacketPool.Instance.GetPacket(PacketType.AgentCachedTextureResponse);
11933
11934 // TODO: don't create new blocks if recycling an old packet
11935 cachedresp.AgentData.AgentID = m_agentId;
11936 cachedresp.AgentData.SessionID = m_sessionId;
11937 cachedresp.AgentData.SerialNum = serial;
11938 cachedresp.WearableData = new AgentCachedTextureResponsePacket.WearableDataBlock[cachedTextures.Count];
11939
11940 for (int i = 0; i < cachedTextures.Count; i++)
11941 {
11942 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11943 cachedresp.WearableData[i].TextureIndex = (byte)cachedTextures[i].BakedTextureIndex;
11944 cachedresp.WearableData[i].TextureID = cachedTextures[i].BakedTextureID;
11945 cachedresp.WearableData[i].HostName = new byte[0];
11946 }
11947
11948 cachedresp.Header.Zerocoded = true;
11949 OutPacket(cachedresp, ThrottleOutPacketType.Task);
11950 }
11951
11887 protected bool HandleMultipleObjUpdate(IClientAPI simClient, Packet packet) 11952 protected bool HandleMultipleObjUpdate(IClientAPI simClient, Packet packet)
11888 { 11953 {
11889 MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet; 11954 MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet;
@@ -11909,8 +11974,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11909 if (part == null) 11974 if (part == null)
11910 { 11975 {
11911 // It's a ghost! tell the client to delete it from view. 11976 // It's a ghost! tell the client to delete it from view.
11912 simClient.SendKillObject(Scene.RegionInfo.RegionHandle, 11977 simClient.SendKillObject(new List<uint> { localId });
11913 new List<uint> { localId });
11914 } 11978 }
11915 else 11979 else
11916 { 11980 {
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index 4154ef2..d008702 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -62,11 +62,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
62 m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager); 62 m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager);
63 } 63 }
64 64
65 public void NetworkStop()
66 {
67 m_udpServer.Stop();
68 }
69
70 public void AddScene(IScene scene) 65 public void AddScene(IScene scene)
71 { 66 {
72 m_udpServer.AddScene(scene); 67 m_udpServer.AddScene(scene);
@@ -1421,7 +1416,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1421 1416
1422 // We only want to send initial data to new clients, not ones which are being converted from child to root. 1417 // We only want to send initial data to new clients, not ones which are being converted from child to root.
1423 if (client != null) 1418 if (client != null)
1424 client.SceneAgent.SendInitialDataToMe(); 1419 {
1420 AgentCircuitData aCircuit = m_scene.AuthenticateHandler.GetAgentCircuitData(uccp.CircuitCode.Code);
1421 bool tp = (aCircuit.teleportFlags > 0);
1422 if (!tp)
1423 client.SceneAgent.SendInitialDataToMe();
1424 }
1425 1425
1426 // Now we know we can handle more data 1426 // Now we know we can handle more data
1427 Thread.Sleep(200); 1427 Thread.Sleep(200);
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs
index 7d9f581..a0e0078 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs
@@ -75,6 +75,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
75 [SetUp] 75 [SetUp]
76 public void SetUp() 76 public void SetUp()
77 { 77 {
78 base.SetUp();
79
78 UUID userId = TestHelpers.ParseTail(0x3); 80 UUID userId = TestHelpers.ParseTail(0x3);
79 81
80 J2KDecoderModule j2kdm = new J2KDecoderModule(); 82 J2KDecoderModule j2kdm = new J2KDecoderModule();
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
index cb724aa..0f03ad0 100644
--- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
@@ -841,7 +841,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
841 m_scene.ForEachClient( 841 m_scene.ForEachClient(
842 client => 842 client =>
843 { if (client.AgentId != so.AttachedAvatar) 843 { if (client.AgentId != so.AttachedAvatar)
844 client.SendKillObject(m_scene.RegionInfo.RegionHandle, new List<uint>() { so.LocalId }); 844 client.SendKillObject(new List<uint>() { so.LocalId });
845 }); 845 });
846 } 846 }
847 847
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs
index 1a38619..8f9b17e 100644
--- a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs
@@ -833,11 +833,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
833 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(sceneA, 0x1); 833 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(sceneA, 0x1);
834 834
835 AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID); 835 AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID);
836 TestClient tc = new TestClient(acd, sceneA, sh.SceneManager); 836 TestClient tc = new TestClient(acd, sceneA);
837 List<TestClient> destinationTestClients = new List<TestClient>(); 837 List<TestClient> destinationTestClients = new List<TestClient>();
838 EntityTransferHelpers.SetUpInformClientOfNeighbour(tc, destinationTestClients); 838 EntityTransferHelpers.SetUpInformClientOfNeighbour(tc, destinationTestClients);
839 839
840 ScenePresence beforeTeleportSp = SceneHelpers.AddScenePresence(sceneA, tc, acd, sh.SceneManager); 840 ScenePresence beforeTeleportSp = SceneHelpers.AddScenePresence(sceneA, tc, acd);
841 beforeTeleportSp.AbsolutePosition = new Vector3(30, 31, 32); 841 beforeTeleportSp.AbsolutePosition = new Vector3(30, 31, 32);
842 842
843 InventoryItemBase attItem = CreateAttachmentItem(sceneA, ua1.PrincipalID, "att", 0x10, 0x20); 843 InventoryItemBase attItem = CreateAttachmentItem(sceneA, ua1.PrincipalID, "att", 0x10, 0x20);
diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
index bc79944..09cc998 100644
--- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
@@ -55,6 +55,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
55 55
56 private int m_savetime = 5; // seconds to wait before saving changed appearance 56 private int m_savetime = 5; // seconds to wait before saving changed appearance
57 private int m_sendtime = 2; // seconds to wait before sending changed appearance 57 private int m_sendtime = 2; // seconds to wait before sending changed appearance
58 private bool m_reusetextures = false;
58 59
59 private int m_checkTime = 500; // milliseconds to wait between checks for appearance updates 60 private int m_checkTime = 500; // milliseconds to wait between checks for appearance updates
60 private System.Timers.Timer m_updateTimer = new System.Timers.Timer(); 61 private System.Timers.Timer m_updateTimer = new System.Timers.Timer();
@@ -73,6 +74,8 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
73 { 74 {
74 m_savetime = Convert.ToInt32(appearanceConfig.GetString("DelayBeforeAppearanceSave",Convert.ToString(m_savetime))); 75 m_savetime = Convert.ToInt32(appearanceConfig.GetString("DelayBeforeAppearanceSave",Convert.ToString(m_savetime)));
75 m_sendtime = Convert.ToInt32(appearanceConfig.GetString("DelayBeforeAppearanceSend",Convert.ToString(m_sendtime))); 76 m_sendtime = Convert.ToInt32(appearanceConfig.GetString("DelayBeforeAppearanceSend",Convert.ToString(m_sendtime)));
77 m_reusetextures = appearanceConfig.GetBoolean("ReuseTextures",m_reusetextures);
78
76 // m_log.InfoFormat("[AVFACTORY] configured for {0} save and {1} send",m_savetime,m_sendtime); 79 // m_log.InfoFormat("[AVFACTORY] configured for {0} save and {1} send",m_savetime,m_sendtime);
77 } 80 }
78 81
@@ -131,6 +134,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
131 client.OnRequestWearables += Client_OnRequestWearables; 134 client.OnRequestWearables += Client_OnRequestWearables;
132 client.OnSetAppearance += Client_OnSetAppearance; 135 client.OnSetAppearance += Client_OnSetAppearance;
133 client.OnAvatarNowWearing += Client_OnAvatarNowWearing; 136 client.OnAvatarNowWearing += Client_OnAvatarNowWearing;
137 client.OnCachedTextureRequest += Client_OnCachedTextureRequest;
134 } 138 }
135 139
136 #endregion 140 #endregion
@@ -1068,6 +1072,61 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
1068 QueueAppearanceSave(client.AgentId); 1072 QueueAppearanceSave(client.AgentId);
1069 } 1073 }
1070 } 1074 }
1075
1076 /// <summary>
1077 /// Respond to the cached textures request from the client
1078 /// </summary>
1079 /// <param name="client"></param>
1080 /// <param name="serial"></param>
1081 /// <param name="cachedTextureRequest"></param>
1082 private void Client_OnCachedTextureRequest(IClientAPI client, int serial, List<CachedTextureRequestArg> cachedTextureRequest)
1083 {
1084 // m_log.WarnFormat("[AVFACTORY]: Client_OnCachedTextureRequest called for {0} ({1})", client.Name, client.AgentId);
1085 ScenePresence sp = m_scene.GetScenePresence(client.AgentId);
1086
1087 List<CachedTextureResponseArg> cachedTextureResponse = new List<CachedTextureResponseArg>();
1088 foreach (CachedTextureRequestArg request in cachedTextureRequest)
1089 {
1090 UUID texture = UUID.Zero;
1091 int index = request.BakedTextureIndex;
1092
1093 if (m_reusetextures)
1094 {
1095 // this is the most insanely dumb way to do this... however it seems to
1096 // actually work. if the appearance has been reset because wearables have
1097 // changed then the texture entries are zero'd out until the bakes are
1098 // uploaded. on login, if the textures exist in the cache (eg if you logged
1099 // into the simulator recently, then the appearance will pull those and send
1100 // them back in the packet and you won't have to rebake. if the textures aren't
1101 // in the cache then the intial makeroot() call in scenepresence will zero
1102 // them out.
1103 //
1104 // a better solution (though how much better is an open question) is to
1105 // store the hashes in the appearance and compare them. Thats's coming.
1106
1107 Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[index];
1108 if (face != null)
1109 texture = face.TextureID;
1110
1111 // m_log.WarnFormat("[AVFACTORY]: reuse texture {0} for index {1}",texture,index);
1112 }
1113
1114 CachedTextureResponseArg response = new CachedTextureResponseArg();
1115 response.BakedTextureIndex = index;
1116 response.BakedTextureID = texture;
1117 response.HostName = null;
1118
1119 cachedTextureResponse.Add(response);
1120 }
1121
1122 // m_log.WarnFormat("[AVFACTORY]: serial is {0}",serial);
1123 // The serial number appears to be used to match requests and responses
1124 // in the texture transaction. We just send back the serial number
1125 // that was provided in the request. The viewer bumps this for us.
1126 client.SendCachedTextureResponse(sp, serial, cachedTextureResponse);
1127 }
1128
1129
1071 #endregion 1130 #endregion
1072 1131
1073 public void WriteBakedTexturesReport(IScenePresence sp, ReportOutputAction outputAction) 1132 public void WriteBakedTexturesReport(IScenePresence sp, ReportOutputAction outputAction)
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
index 8056030..4613344 100644
--- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
@@ -371,7 +371,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
371 foreach (string fid in outstanding) 371 foreach (string fid in outstanding)
372 { 372 {
373 UUID fromAgentID; 373 UUID fromAgentID;
374 string firstname = "Unknown", lastname = "User"; 374 string firstname = "Unknown", lastname = "UserFMSFOIN";
375 if (!GetAgentInfo(client.Scene.RegionInfo.ScopeID, fid, out fromAgentID, out firstname, out lastname)) 375 if (!GetAgentInfo(client.Scene.RegionInfo.ScopeID, fid, out fromAgentID, out firstname, out lastname))
376 { 376 {
377 m_log.DebugFormat("[FRIENDS MODULE]: skipping malformed friend {0}", fid); 377 m_log.DebugFormat("[FRIENDS MODULE]: skipping malformed friend {0}", fid);
@@ -397,7 +397,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
397 397
398 protected virtual bool GetAgentInfo(UUID scopeID, string fid, out UUID agentID, out string first, out string last) 398 protected virtual bool GetAgentInfo(UUID scopeID, string fid, out UUID agentID, out string first, out string last)
399 { 399 {
400 first = "Unknown"; last = "User"; 400 first = "Unknown"; last = "UserFMGAI";
401 if (!UUID.TryParse(fid, out agentID)) 401 if (!UUID.TryParse(fid, out agentID))
402 return false; 402 return false;
403 403
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs
index bf5c0bb..b3e3aa2 100644
--- a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs
@@ -293,7 +293,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
293 293
294 protected override bool GetAgentInfo(UUID scopeID, string fid, out UUID agentID, out string first, out string last) 294 protected override bool GetAgentInfo(UUID scopeID, string fid, out UUID agentID, out string first, out string last)
295 { 295 {
296 first = "Unknown"; last = "User"; 296 first = "Unknown"; last = "UserHGGAI";
297 if (base.GetAgentInfo(scopeID, fid, out agentID, out first, out last)) 297 if (base.GetAgentInfo(scopeID, fid, out agentID, out first, out last))
298 return true; 298 return true;
299 299
diff --git a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs
index fa8c3f3..5b12ecb 100644
--- a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs
@@ -26,27 +26,25 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Collections.Generic;
30using Nini.Config;
31using OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.Framework.Scenes;
34using OpenSim.Region.Framework.Interfaces;
35using System;
36using System.Reflection;
37using System.Collections; 29using System.Collections;
30using System.Collections.Generic;
38using System.Collections.Specialized; 31using System.Collections.Specialized;
39using System.Reflection;
40using System.IO; 32using System.IO;
33using System.Reflection;
41using System.Web; 34using System.Web;
42using System.Xml; 35using System.Xml;
43using log4net; 36using log4net;
44using Mono.Addins; 37using Mono.Addins;
38using Nini.Config;
39using OpenMetaverse;
45using OpenMetaverse.Messages.Linden; 40using OpenMetaverse.Messages.Linden;
46using OpenMetaverse.StructuredData; 41using OpenMetaverse.StructuredData;
42using OpenSim.Framework;
47using OpenSim.Framework.Capabilities; 43using OpenSim.Framework.Capabilities;
48using OpenSim.Framework.Servers; 44using OpenSim.Framework.Servers;
49using OpenSim.Framework.Servers.HttpServer; 45using OpenSim.Framework.Servers.HttpServer;
46using OpenSim.Region.Framework.Scenes;
47using OpenSim.Region.Framework.Interfaces;
50using Caps = OpenSim.Framework.Capabilities.Caps; 48using Caps = OpenSim.Framework.Capabilities.Caps;
51using OSDArray = OpenMetaverse.StructuredData.OSDArray; 49using OSDArray = OpenMetaverse.StructuredData.OSDArray;
52using OSDMap = OpenMetaverse.StructuredData.OSDMap; 50using OSDMap = OpenMetaverse.StructuredData.OSDMap;
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
index f122d00..e285f21 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
@@ -47,10 +47,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
47 47
48 /// <summary> 48 /// <summary>
49 private List<Scene> m_Scenelist = new List<Scene>(); 49 private List<Scene> m_Scenelist = new List<Scene>();
50// private Dictionary<UUID, Scene> m_AgentRegions =
51// new Dictionary<UUID, Scene>();
52 50
53 private IMessageTransferModule m_TransferModule = null; 51 private IMessageTransferModule m_TransferModule;
54 private bool m_Enabled = true; 52 private bool m_Enabled = true;
55 53
56 #region Region Module interface 54 #region Region Module interface
@@ -81,9 +79,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
81// scene.RegisterModuleInterface<IInventoryTransferModule>(this); 79// scene.RegisterModuleInterface<IInventoryTransferModule>(this);
82 80
83 scene.EventManager.OnNewClient += OnNewClient; 81 scene.EventManager.OnNewClient += OnNewClient;
84// scene.EventManager.OnClientClosed += ClientLoggedOut;
85 scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage; 82 scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage;
86// scene.EventManager.OnSetRootAgentScene += OnSetRootAgentScene;
87 } 83 }
88 84
89 public void RegionLoaded(Scene scene) 85 public void RegionLoaded(Scene scene)
@@ -96,11 +92,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
96 m_log.Error("[INVENTORY TRANSFER]: No Message transfer module found, transfers will be local only"); 92 m_log.Error("[INVENTORY TRANSFER]: No Message transfer module found, transfers will be local only");
97 m_Enabled = false; 93 m_Enabled = false;
98 94
99 m_Scenelist.Clear(); 95// m_Scenelist.Clear();
100 scene.EventManager.OnNewClient -= OnNewClient; 96// scene.EventManager.OnNewClient -= OnNewClient;
101// scene.EventManager.OnClientClosed -= ClientLoggedOut;
102 scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage; 97 scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage;
103// scene.EventManager.OnSetRootAgentScene -= OnSetRootAgentScene;
104 } 98 }
105 } 99 }
106 } 100 }
@@ -108,9 +102,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
108 public void RemoveRegion(Scene scene) 102 public void RemoveRegion(Scene scene)
109 { 103 {
110 scene.EventManager.OnNewClient -= OnNewClient; 104 scene.EventManager.OnNewClient -= OnNewClient;
111// scene.EventManager.OnClientClosed -= ClientLoggedOut;
112 scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage; 105 scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage;
113// scene.EventManager.OnSetRootAgentScene -= OnSetRootAgentScene;
114 m_Scenelist.Remove(scene); 106 m_Scenelist.Remove(scene);
115 } 107 }
116 108
@@ -139,11 +131,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
139 // Inventory giving is conducted via instant message 131 // Inventory giving is conducted via instant message
140 client.OnInstantMessage += OnInstantMessage; 132 client.OnInstantMessage += OnInstantMessage;
141 } 133 }
142
143// protected void OnSetRootAgentScene(UUID id, Scene scene)
144// {
145// m_AgentRegions[id] = scene;
146// }
147 134
148 private Scene FindClientScene(UUID agentId) 135 private Scene FindClientScene(UUID agentId)
149 { 136 {
@@ -188,9 +175,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
188 { 175 {
189 UUID folderID = new UUID(im.binaryBucket, 1); 176 UUID folderID = new UUID(im.binaryBucket, 1);
190 177
191 m_log.DebugFormat("[INVENTORY TRANSFER]: Inserting original folder {0} "+ 178 m_log.DebugFormat(
192 "into agent {1}'s inventory", 179 "[INVENTORY TRANSFER]: Inserting original folder {0} into agent {1}'s inventory",
193 folderID, new UUID(im.toAgentID)); 180 folderID, new UUID(im.toAgentID));
194 181
195 InventoryFolderBase folderCopy 182 InventoryFolderBase folderCopy
196 = scene.GiveInventoryFolder(recipientID, client.AgentId, folderID, UUID.Zero); 183 = scene.GiveInventoryFolder(recipientID, client.AgentId, folderID, UUID.Zero);
@@ -213,7 +200,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
213 user.ControllingClient.SendBulkUpdateInventory(folderCopy); 200 user.ControllingClient.SendBulkUpdateInventory(folderCopy);
214 201
215 // HACK!! 202 // HACK!!
216 // Insert the ID of the copied item into the IM so that we know which item to move to trash if it 203 // Insert the ID of the copied folder into the IM so that we know which item to move to trash if it
217 // is rejected. 204 // is rejected.
218 // XXX: This is probably a misuse of the session ID slot. 205 // XXX: This is probably a misuse of the session ID slot.
219 im.imSessionID = copyID.Guid; 206 im.imSessionID = copyID.Guid;
@@ -425,7 +412,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
425 { 412 {
426 folder = new InventoryFolderBase(inventoryID, client.AgentId); 413 folder = new InventoryFolderBase(inventoryID, client.AgentId);
427 folder = invService.GetFolder(folder); 414 folder = invService.GetFolder(folder);
428 415
429 if (folder != null & trashFolder != null) 416 if (folder != null & trashFolder != null)
430 { 417 {
431 previousParentFolderID = folder.ParentID; 418 previousParentFolderID = folder.ParentID;
@@ -477,70 +464,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
477 } 464 }
478 } 465 }
479 466
480// public bool NeedSceneCacheClear(UUID agentID, Scene scene)
481// {
482// if (!m_AgentRegions.ContainsKey(agentID))
483// {
484// // Since we can get here two ways, we need to scan
485// // the scenes here. This is somewhat more expensive
486// // but helps avoid a nasty bug
487// //
488//
489// foreach (Scene s in m_Scenelist)
490// {
491// ScenePresence presence;
492//
493// if (s.TryGetScenePresence(agentID, out presence))
494// {
495// // If the agent is in this scene, then we
496// // are being called twice in a single
497// // teleport. This is wasteful of cycles
498// // but harmless due to this 2nd level check
499// //
500// // If the agent is found in another scene
501// // then the list wasn't current
502// //
503// // If the agent is totally unknown, then what
504// // are we even doing here??
505// //
506// if (s == scene)
507// {
508// //m_log.Debug("[INVTRANSFERMOD]: s == scene. Returning true in " + scene.RegionInfo.RegionName);
509// return true;
510// }
511// else
512// {
513// //m_log.Debug("[INVTRANSFERMOD]: s != scene. Returning false in " + scene.RegionInfo.RegionName);
514// return false;
515// }
516// }
517// }
518// //m_log.Debug("[INVTRANSFERMOD]: agent not in scene. Returning true in " + scene.RegionInfo.RegionName);
519// return true;
520// }
521//
522// // The agent is left in current Scene, so we must be
523// // going to another instance
524// //
525// if (m_AgentRegions[agentID] == scene)
526// {
527// //m_log.Debug("[INVTRANSFERMOD]: m_AgentRegions[agentID] == scene. Returning true in " + scene.RegionInfo.RegionName);
528// m_AgentRegions.Remove(agentID);
529// return true;
530// }
531//
532// // Another region has claimed the agent
533// //
534// //m_log.Debug("[INVTRANSFERMOD]: last resort. Returning false in " + scene.RegionInfo.RegionName);
535// return false;
536// }
537//
538// public void ClientLoggedOut(UUID agentID, Scene scene)
539// {
540// if (m_AgentRegions.ContainsKey(agentID))
541// m_AgentRegions.Remove(agentID);
542// }
543
544 /// <summary> 467 /// <summary>
545 /// 468 ///
546 /// </summary> 469 /// </summary>
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/Tests/InventoryTransferModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/Tests/InventoryTransferModuleTests.cs
new file mode 100644
index 0000000..162a0c3
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/Tests/InventoryTransferModuleTests.cs
@@ -0,0 +1,449 @@
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 log4net.Config;
32using Nini.Config;
33using NUnit.Framework;
34using OpenMetaverse;
35using OpenMetaverse.Assets;
36using OpenSim.Framework;
37using OpenSim.Region.CoreModules.Avatar.Inventory.Transfer;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Services.Interfaces;
41using OpenSim.Tests.Common;
42using OpenSim.Tests.Common.Mock;
43
44namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer.Tests
45{
46 [TestFixture]
47 public class InventoryTransferModuleTests : OpenSimTestCase
48 {
49 protected TestScene m_scene;
50
51 [SetUp]
52 public override void SetUp()
53 {
54 base.SetUp();
55
56 IConfigSource config = new IniConfigSource();
57 config.AddConfig("Messaging");
58 config.Configs["Messaging"].Set("InventoryTransferModule", "InventoryTransferModule");
59
60 m_scene = new SceneHelpers().SetupScene();
61 SceneHelpers.SetupSceneModules(m_scene, config, new InventoryTransferModule());
62 }
63
64 [Test]
65 public void TestAcceptGivenItem()
66 {
67// TestHelpers.EnableLogging();
68
69 UUID initialSessionId = TestHelpers.ParseTail(0x10);
70 UUID itemId = TestHelpers.ParseTail(0x100);
71 UUID assetId = TestHelpers.ParseTail(0x200);
72
73 UserAccount ua1
74 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "One", TestHelpers.ParseTail(0x1), "pw");
75 UserAccount ua2
76 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "Two", TestHelpers.ParseTail(0x2), "pw");
77
78 ScenePresence giverSp = SceneHelpers.AddScenePresence(m_scene, ua1);
79 TestClient giverClient = (TestClient)giverSp.ControllingClient;
80
81 ScenePresence receiverSp = SceneHelpers.AddScenePresence(m_scene, ua2);
82 TestClient receiverClient = (TestClient)receiverSp.ControllingClient;
83
84 // Create the object to test give
85 InventoryItemBase originalItem
86 = UserInventoryHelpers.CreateInventoryItem(
87 m_scene, "givenObj", itemId, assetId, giverSp.UUID, InventoryType.Object);
88
89 byte[] giveImBinaryBucket = new byte[17];
90 byte[] itemIdBytes = itemId.GetBytes();
91 Array.Copy(itemIdBytes, 0, giveImBinaryBucket, 1, itemIdBytes.Length);
92
93 GridInstantMessage giveIm
94 = new GridInstantMessage(
95 m_scene,
96 giverSp.UUID,
97 giverSp.Name,
98 receiverSp.UUID,
99 (byte)InstantMessageDialog.InventoryOffered,
100 false,
101 "inventory offered msg",
102 initialSessionId,
103 false,
104 Vector3.Zero,
105 giveImBinaryBucket,
106 true);
107
108 giverClient.HandleImprovedInstantMessage(giveIm);
109
110 // These details might not all be correct.
111 GridInstantMessage acceptIm
112 = new GridInstantMessage(
113 m_scene,
114 receiverSp.UUID,
115 receiverSp.Name,
116 giverSp.UUID,
117 (byte)InstantMessageDialog.InventoryAccepted,
118 false,
119 "inventory accepted msg",
120 initialSessionId,
121 false,
122 Vector3.Zero,
123 null,
124 true);
125
126 receiverClient.HandleImprovedInstantMessage(acceptIm);
127
128 // Test for item remaining in the giver's inventory (here we assume a copy item)
129 // TODO: Test no-copy items.
130 InventoryItemBase originalItemAfterGive
131 = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, giverSp.UUID, "Objects/givenObj");
132
133 Assert.That(originalItemAfterGive, Is.Not.Null);
134 Assert.That(originalItemAfterGive.ID, Is.EqualTo(originalItem.ID));
135
136 // Test for item successfully making it into the receiver's inventory
137 InventoryItemBase receivedItem
138 = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, receiverSp.UUID, "Objects/givenObj");
139
140 Assert.That(receivedItem, Is.Not.Null);
141 Assert.That(receivedItem.ID, Is.Not.EqualTo(originalItem.ID));
142
143 // Test that on a delete, item still exists and is accessible for the giver.
144 m_scene.InventoryService.DeleteItems(receiverSp.UUID, new List<UUID>() { receivedItem.ID });
145
146 InventoryItemBase originalItemAfterDelete
147 = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, giverSp.UUID, "Objects/givenObj");
148
149 Assert.That(originalItemAfterDelete, Is.Not.Null);
150
151 // TODO: Test scenario where giver deletes their item first.
152 }
153
154 /// <summary>
155 /// Test user rejection of a given item.
156 /// </summary>
157 /// <remarks>
158 /// A rejected item still ends up in the user's trash folder.
159 /// </remarks>
160 [Test]
161 public void TestRejectGivenItem()
162 {
163// TestHelpers.EnableLogging();
164
165 UUID initialSessionId = TestHelpers.ParseTail(0x10);
166 UUID itemId = TestHelpers.ParseTail(0x100);
167 UUID assetId = TestHelpers.ParseTail(0x200);
168
169 UserAccount ua1
170 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "One", TestHelpers.ParseTail(0x1), "pw");
171 UserAccount ua2
172 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "Two", TestHelpers.ParseTail(0x2), "pw");
173
174 ScenePresence giverSp = SceneHelpers.AddScenePresence(m_scene, ua1);
175 TestClient giverClient = (TestClient)giverSp.ControllingClient;
176
177 ScenePresence receiverSp = SceneHelpers.AddScenePresence(m_scene, ua2);
178 TestClient receiverClient = (TestClient)receiverSp.ControllingClient;
179
180 // Create the object to test give
181 InventoryItemBase originalItem
182 = UserInventoryHelpers.CreateInventoryItem(
183 m_scene, "givenObj", itemId, assetId, giverSp.UUID, InventoryType.Object);
184
185 GridInstantMessage receivedIm = null;
186 receiverClient.OnReceivedInstantMessage += im => receivedIm = im;
187
188 byte[] giveImBinaryBucket = new byte[17];
189 byte[] itemIdBytes = itemId.GetBytes();
190 Array.Copy(itemIdBytes, 0, giveImBinaryBucket, 1, itemIdBytes.Length);
191
192 GridInstantMessage giveIm
193 = new GridInstantMessage(
194 m_scene,
195 giverSp.UUID,
196 giverSp.Name,
197 receiverSp.UUID,
198 (byte)InstantMessageDialog.InventoryOffered,
199 false,
200 "inventory offered msg",
201 initialSessionId,
202 false,
203 Vector3.Zero,
204 giveImBinaryBucket,
205 true);
206
207 giverClient.HandleImprovedInstantMessage(giveIm);
208
209 // These details might not all be correct.
210 // Session ID is now the created item ID (!)
211 GridInstantMessage rejectIm
212 = new GridInstantMessage(
213 m_scene,
214 receiverSp.UUID,
215 receiverSp.Name,
216 giverSp.UUID,
217 (byte)InstantMessageDialog.InventoryDeclined,
218 false,
219 "inventory declined msg",
220 new UUID(receivedIm.imSessionID),
221 false,
222 Vector3.Zero,
223 null,
224 true);
225
226 receiverClient.HandleImprovedInstantMessage(rejectIm);
227
228 // Test for item remaining in the giver's inventory (here we assume a copy item)
229 // TODO: Test no-copy items.
230 InventoryItemBase originalItemAfterGive
231 = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, giverSp.UUID, "Objects/givenObj");
232
233 Assert.That(originalItemAfterGive, Is.Not.Null);
234 Assert.That(originalItemAfterGive.ID, Is.EqualTo(originalItem.ID));
235
236 // Test for item successfully making it into the receiver's inventory
237 InventoryItemBase receivedItem
238 = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, receiverSp.UUID, "Trash/givenObj");
239
240 InventoryFolderBase trashFolder
241 = m_scene.InventoryService.GetFolderForType(receiverSp.UUID, AssetType.TrashFolder);
242
243 Assert.That(receivedItem, Is.Not.Null);
244 Assert.That(receivedItem.ID, Is.Not.EqualTo(originalItem.ID));
245 Assert.That(receivedItem.Folder, Is.EqualTo(trashFolder.ID));
246
247 // Test that on a delete, item still exists and is accessible for the giver.
248 m_scene.InventoryService.PurgeFolder(trashFolder);
249
250 InventoryItemBase originalItemAfterDelete
251 = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, giverSp.UUID, "Objects/givenObj");
252
253 Assert.That(originalItemAfterDelete, Is.Not.Null);
254 }
255
256 [Test]
257 public void TestAcceptGivenFolder()
258 {
259 TestHelpers.InMethod();
260// TestHelpers.EnableLogging();
261
262 UUID initialSessionId = TestHelpers.ParseTail(0x10);
263 UUID folderId = TestHelpers.ParseTail(0x100);
264
265 UserAccount ua1
266 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "One", TestHelpers.ParseTail(0x1), "pw");
267 UserAccount ua2
268 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "Two", TestHelpers.ParseTail(0x2), "pw");
269
270 ScenePresence giverSp = SceneHelpers.AddScenePresence(m_scene, ua1);
271 TestClient giverClient = (TestClient)giverSp.ControllingClient;
272
273 ScenePresence receiverSp = SceneHelpers.AddScenePresence(m_scene, ua2);
274 TestClient receiverClient = (TestClient)receiverSp.ControllingClient;
275
276 InventoryFolderBase originalFolder
277 = UserInventoryHelpers.CreateInventoryFolder(
278 m_scene.InventoryService, giverSp.UUID, folderId, "f1", true);
279
280 byte[] giveImBinaryBucket = new byte[17];
281 giveImBinaryBucket[0] = (byte)AssetType.Folder;
282 byte[] itemIdBytes = folderId.GetBytes();
283 Array.Copy(itemIdBytes, 0, giveImBinaryBucket, 1, itemIdBytes.Length);
284
285 GridInstantMessage giveIm
286 = new GridInstantMessage(
287 m_scene,
288 giverSp.UUID,
289 giverSp.Name,
290 receiverSp.UUID,
291 (byte)InstantMessageDialog.InventoryOffered,
292 false,
293 "inventory offered msg",
294 initialSessionId,
295 false,
296 Vector3.Zero,
297 giveImBinaryBucket,
298 true);
299
300 giverClient.HandleImprovedInstantMessage(giveIm);
301
302 // These details might not all be correct.
303 GridInstantMessage acceptIm
304 = new GridInstantMessage(
305 m_scene,
306 receiverSp.UUID,
307 receiverSp.Name,
308 giverSp.UUID,
309 (byte)InstantMessageDialog.InventoryAccepted,
310 false,
311 "inventory accepted msg",
312 initialSessionId,
313 false,
314 Vector3.Zero,
315 null,
316 true);
317
318 receiverClient.HandleImprovedInstantMessage(acceptIm);
319
320 // Test for item remaining in the giver's inventory (here we assume a copy item)
321 // TODO: Test no-copy items.
322 InventoryFolderBase originalFolderAfterGive
323 = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, giverSp.UUID, "f1");
324
325 Assert.That(originalFolderAfterGive, Is.Not.Null);
326 Assert.That(originalFolderAfterGive.ID, Is.EqualTo(originalFolder.ID));
327
328 // Test for item successfully making it into the receiver's inventory
329 InventoryFolderBase receivedFolder
330 = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, receiverSp.UUID, "f1");
331
332 Assert.That(receivedFolder, Is.Not.Null);
333 Assert.That(receivedFolder.ID, Is.Not.EqualTo(originalFolder.ID));
334
335 // Test that on a delete, item still exists and is accessible for the giver.
336 m_scene.InventoryService.DeleteFolders(receiverSp.UUID, new List<UUID>() { receivedFolder.ID });
337
338 InventoryFolderBase originalFolderAfterDelete
339 = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, giverSp.UUID, "f1");
340
341 Assert.That(originalFolderAfterDelete, Is.Not.Null);
342
343 // TODO: Test scenario where giver deletes their item first.
344 }
345
346 /// <summary>
347 /// Test user rejection of a given item.
348 /// </summary>
349 /// <remarks>
350 /// A rejected item still ends up in the user's trash folder.
351 /// </remarks>
352 [Test]
353 public void TestRejectGivenFolder()
354 {
355 TestHelpers.InMethod();
356// TestHelpers.EnableLogging();
357
358 UUID initialSessionId = TestHelpers.ParseTail(0x10);
359 UUID folderId = TestHelpers.ParseTail(0x100);
360
361 UserAccount ua1
362 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "One", TestHelpers.ParseTail(0x1), "pw");
363 UserAccount ua2
364 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "Two", TestHelpers.ParseTail(0x2), "pw");
365
366 ScenePresence giverSp = SceneHelpers.AddScenePresence(m_scene, ua1);
367 TestClient giverClient = (TestClient)giverSp.ControllingClient;
368
369 ScenePresence receiverSp = SceneHelpers.AddScenePresence(m_scene, ua2);
370 TestClient receiverClient = (TestClient)receiverSp.ControllingClient;
371
372 // Create the folder to test give
373 InventoryFolderBase originalFolder
374 = UserInventoryHelpers.CreateInventoryFolder(
375 m_scene.InventoryService, giverSp.UUID, folderId, "f1", true);
376
377 GridInstantMessage receivedIm = null;
378 receiverClient.OnReceivedInstantMessage += im => receivedIm = im;
379
380 byte[] giveImBinaryBucket = new byte[17];
381 giveImBinaryBucket[0] = (byte)AssetType.Folder;
382 byte[] itemIdBytes = folderId.GetBytes();
383 Array.Copy(itemIdBytes, 0, giveImBinaryBucket, 1, itemIdBytes.Length);
384
385 GridInstantMessage giveIm
386 = new GridInstantMessage(
387 m_scene,
388 giverSp.UUID,
389 giverSp.Name,
390 receiverSp.UUID,
391 (byte)InstantMessageDialog.InventoryOffered,
392 false,
393 "inventory offered msg",
394 initialSessionId,
395 false,
396 Vector3.Zero,
397 giveImBinaryBucket,
398 true);
399
400 giverClient.HandleImprovedInstantMessage(giveIm);
401
402 // These details might not all be correct.
403 // Session ID is now the created item ID (!)
404 GridInstantMessage rejectIm
405 = new GridInstantMessage(
406 m_scene,
407 receiverSp.UUID,
408 receiverSp.Name,
409 giverSp.UUID,
410 (byte)InstantMessageDialog.InventoryDeclined,
411 false,
412 "inventory declined msg",
413 new UUID(receivedIm.imSessionID),
414 false,
415 Vector3.Zero,
416 null,
417 true);
418
419 receiverClient.HandleImprovedInstantMessage(rejectIm);
420
421 // Test for item remaining in the giver's inventory (here we assume a copy item)
422 // TODO: Test no-copy items.
423 InventoryFolderBase originalFolderAfterGive
424 = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, giverSp.UUID, "f1");
425
426 Assert.That(originalFolderAfterGive, Is.Not.Null);
427 Assert.That(originalFolderAfterGive.ID, Is.EqualTo(originalFolder.ID));
428
429 // Test for folder successfully making it into the receiver's inventory
430 InventoryFolderBase receivedFolder
431 = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, receiverSp.UUID, "Trash/f1");
432
433 InventoryFolderBase trashFolder
434 = m_scene.InventoryService.GetFolderForType(receiverSp.UUID, AssetType.TrashFolder);
435
436 Assert.That(receivedFolder, Is.Not.Null);
437 Assert.That(receivedFolder.ID, Is.Not.EqualTo(originalFolder.ID));
438 Assert.That(receivedFolder.ParentID, Is.EqualTo(trashFolder.ID));
439
440 // Test that on a delete, item still exists and is accessible for the giver.
441 m_scene.InventoryService.PurgeFolder(trashFolder);
442
443 InventoryFolderBase originalFolderAfterDelete
444 = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, giverSp.UUID, "f1");
445
446 Assert.That(originalFolderAfterDelete, Is.Not.Null);
447 }
448 }
449} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs
new file mode 100644
index 0000000..a97c9b4
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs
@@ -0,0 +1,1332 @@
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.IO;
30using System.Text;
31using System.Collections;
32using System.Collections.Generic;
33using System.Globalization;
34using System.Net;
35using System.Net.Sockets;
36using System.Reflection;
37using System.Xml;
38using OpenMetaverse;
39using OpenMetaverse.StructuredData;
40using log4net;
41using Nini.Config;
42using Nwc.XmlRpc;
43using OpenSim.Framework;
44using OpenSim.Region.Framework.Interfaces;
45using OpenSim.Region.Framework.Scenes;
46using OpenSim.Services.Interfaces;
47using Mono.Addins;
48using OpenSim.Services.Connectors.Hypergrid;
49
50namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles
51{
52 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UserProfilesModule")]
53 public class UserProfileModule : IProfileModule, INonSharedRegionModule
54 {
55 /// <summary>
56 /// Logging
57 /// </summary>
58 static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
59
60 // The pair of Dictionaries are used to handle the switching of classified ads
61 // by maintaining a cache of classified id to creator id mappings and an interest
62 // count. The entries are removed when the interest count reaches 0.
63 Dictionary<UUID,UUID> classifiedCache = new Dictionary<UUID, UUID>();
64 Dictionary<UUID,int> classifiedInterest = new Dictionary<UUID, int>();
65
66 public Scene Scene
67 {
68 get; private set;
69 }
70
71 /// <summary>
72 /// Gets or sets the ConfigSource.
73 /// </summary>
74 /// <value>
75 /// The configuration
76 /// </value>
77 public IConfigSource Config {
78 get;
79 set;
80 }
81
82 /// <summary>
83 /// Gets or sets the URI to the profile server.
84 /// </summary>
85 /// <value>
86 /// The profile server URI.
87 /// </value>
88 public string ProfileServerUri {
89 get;
90 set;
91 }
92
93 IProfileModule ProfileModule
94 {
95 get; set;
96 }
97
98 IUserManagement UserManagementModule
99 {
100 get; set;
101 }
102
103 /// <summary>
104 /// Gets or sets a value indicating whether this
105 /// <see cref="BlueWall.SlipStream.ProfileModule.UserProfileModule"/> is enabled.
106 /// </summary>
107 /// <value>
108 /// <c>true</c> if enabled; otherwise, <c>false</c>.
109 /// </value>
110 public bool Enabled {
111 get;
112 set;
113 }
114
115 #region IRegionModuleBase implementation
116 /// <summary>
117 /// This is called to initialize the region module. For shared modules, this is called exactly once, after
118 /// creating the single (shared) instance. For non-shared modules, this is called once on each instance, after
119 /// the instace for the region has been created.
120 /// </summary>
121 /// <param name='source'>
122 /// Source.
123 /// </param>
124 public void Initialise(IConfigSource source)
125 {
126 Config = source;
127 ReplaceableInterface = typeof(IProfileModule);
128
129 IConfig profileConfig = Config.Configs["UserProfiles"];
130
131 if (profileConfig == null)
132 {
133 Enabled = false;
134 return;
135 }
136
137 // If we find ProfileURL then we configure for FULL support
138 // else we setup for BASIC support
139 ProfileServerUri = profileConfig.GetString("ProfileServiceURL", "");
140 if (ProfileServerUri == "")
141 {
142 Enabled = false;
143 return;
144 }
145
146 m_log.Debug("[PROFILES]: Full Profiles Enabled");
147 ReplaceableInterface = null;
148 Enabled = true;
149 }
150
151 /// <summary>
152 /// Adds the region.
153 /// </summary>
154 /// <param name='scene'>
155 /// Scene.
156 /// </param>
157 public void AddRegion(Scene scene)
158 {
159 if(!Enabled)
160 return;
161
162 Scene = scene;
163 Scene.RegisterModuleInterface<IProfileModule>(this);
164 Scene.EventManager.OnNewClient += OnNewClient;
165 Scene.EventManager.OnMakeRootAgent += HandleOnMakeRootAgent;
166
167 UserManagementModule = Scene.RequestModuleInterface<IUserManagement>();
168 }
169
170 void HandleOnMakeRootAgent (ScenePresence obj)
171 {
172 if(obj.PresenceType == PresenceType.Npc)
173 return;
174
175 GetImageAssets(((IScenePresence)obj).UUID);
176 }
177
178 /// <summary>
179 /// Removes the region.
180 /// </summary>
181 /// <param name='scene'>
182 /// Scene.
183 /// </param>
184 public void RemoveRegion(Scene scene)
185 {
186 if(!Enabled)
187 return;
188 }
189
190 /// <summary>
191 /// This will be called once for every scene loaded. In a shared module this will be multiple times in one
192 /// instance, while a nonshared module instance will only be called once. This method is called after AddRegion
193 /// has been called in all modules for that scene, providing an opportunity to request another module's
194 /// interface, or hook an event from another module.
195 /// </summary>
196 /// <param name='scene'>
197 /// Scene.
198 /// </param>
199 public void RegionLoaded(Scene scene)
200 {
201 if(!Enabled)
202 return;
203 }
204
205 /// <summary>
206 /// If this returns non-null, it is the type of an interface that this module intends to register. This will
207 /// cause the loader to defer loading of this module until all other modules have been loaded. If no other
208 /// module has registered the interface by then, this module will be activated, else it will remain inactive,
209 /// letting the other module take over. This should return non-null ONLY in modules that are intended to be
210 /// easily replaceable, e.g. stub implementations that the developer expects to be replaced by third party
211 /// provided modules.
212 /// </summary>
213 /// <value>
214 /// The replaceable interface.
215 /// </value>
216 public Type ReplaceableInterface
217 {
218 get; private set;
219 }
220
221 /// <summary>
222 /// Called as the instance is closed.
223 /// </summary>
224 public void Close()
225 {
226 }
227
228 /// <value>
229 /// The name of the module
230 /// </value>
231 /// <summary>
232 /// Gets the module name.
233 /// </summary>
234 public string Name
235 {
236 get { return "UserProfileModule"; }
237 }
238 #endregion IRegionModuleBase implementation
239
240 #region Region Event Handlers
241 /// <summary>
242 /// Raises the new client event.
243 /// </summary>
244 /// <param name='client'>
245 /// Client.
246 /// </param>
247 void OnNewClient(IClientAPI client)
248 {
249 //Profile
250 client.OnRequestAvatarProperties += RequestAvatarProperties;
251 client.OnUpdateAvatarProperties += AvatarPropertiesUpdate;
252 client.OnAvatarInterestUpdate += AvatarInterestsUpdate;
253
254 // Classifieds
255 client.AddGenericPacketHandler("avatarclassifiedsrequest", ClassifiedsRequest);
256 client.OnClassifiedInfoUpdate += ClassifiedInfoUpdate;
257 client.OnClassifiedInfoRequest += ClassifiedInfoRequest;
258 client.OnClassifiedDelete += ClassifiedDelete;
259
260 // Picks
261 client.AddGenericPacketHandler("avatarpicksrequest", PicksRequest);
262 client.AddGenericPacketHandler("pickinforequest", PickInfoRequest);
263 client.OnPickInfoUpdate += PickInfoUpdate;
264 client.OnPickDelete += PickDelete;
265
266 // Notes
267 client.AddGenericPacketHandler("avatarnotesrequest", NotesRequest);
268 client.OnAvatarNotesUpdate += NotesUpdate;
269 }
270 #endregion Region Event Handlers
271
272 #region Classified
273 ///
274 /// <summary>
275 /// Handles the avatar classifieds request.
276 /// </summary>
277 /// <param name='sender'>
278 /// Sender.
279 /// </param>
280 /// <param name='method'>
281 /// Method.
282 /// </param>
283 /// <param name='args'>
284 /// Arguments.
285 /// </param>
286 public void ClassifiedsRequest(Object sender, string method, List<String> args)
287 {
288 if (!(sender is IClientAPI))
289 return;
290
291 IClientAPI remoteClient = (IClientAPI)sender;
292
293 UUID targetID;
294 UUID.TryParse(args[0], out targetID);
295
296 // Can't handle NPC yet...
297 ScenePresence p = FindPresence(targetID);
298
299 if (null != p)
300 {
301 if (p.PresenceType == PresenceType.Npc)
302 return;
303 }
304
305 string serverURI = string.Empty;
306 bool foreign = GetUserProfileServerURI(targetID, out serverURI);
307 UUID creatorId = UUID.Zero;
308
309 OSDMap parameters= new OSDMap();
310 UUID.TryParse(args[0], out creatorId);
311 parameters.Add("creatorId", OSD.FromUUID(creatorId));
312 OSD Params = (OSD)parameters;
313 if(!JsonRpcRequest(ref Params, "avatarclassifiedsrequest", serverURI, UUID.Random().ToString()))
314 {
315 // Error Handling here!
316 // if(parameters.ContainsKey("message")
317 }
318
319 parameters = (OSDMap)Params;
320
321 OSDArray list = (OSDArray)parameters["result"];
322
323 Dictionary<UUID, string> classifieds = new Dictionary<UUID, string>();
324
325 foreach(OSD map in list)
326 {
327 OSDMap m = (OSDMap)map;
328 UUID cid = m["classifieduuid"].AsUUID();
329 string name = m["name"].AsString();
330
331 classifieds[cid] = name;
332
333 if(!classifiedCache.ContainsKey(cid))
334 {
335 lock(classifiedCache)
336 classifiedCache.Add(cid,creatorId);
337 lock(classifiedInterest)
338 classifiedInterest.Add(cid, 0);
339 }
340
341 lock(classifiedInterest)
342 classifiedInterest[cid] ++;
343 }
344
345 remoteClient.SendAvatarClassifiedReply(new UUID(args[0]), classifieds);
346 }
347
348 public void ClassifiedInfoRequest(UUID queryClassifiedID, IClientAPI remoteClient)
349 {
350 UUID target = remoteClient.AgentId;
351 UserClassifiedAdd ad = new UserClassifiedAdd();
352 ad.ClassifiedId = queryClassifiedID;
353
354 if(classifiedCache.ContainsKey(queryClassifiedID))
355 {
356 target = classifiedCache[queryClassifiedID];
357
358 lock(classifiedInterest)
359 classifiedInterest[queryClassifiedID] --;
360
361 if(classifiedInterest[queryClassifiedID] == 0)
362 {
363 lock(classifiedInterest)
364 classifiedInterest.Remove(queryClassifiedID);
365 lock(classifiedCache)
366 classifiedCache.Remove(queryClassifiedID);
367 }
368 }
369
370 string serverURI = string.Empty;
371 bool foreign = GetUserProfileServerURI(target, out serverURI);
372
373 object Ad = (object)ad;
374 if(!JsonRpcRequest(ref Ad, "classifieds_info_query", serverURI, UUID.Random().ToString()))
375 {
376 remoteClient.SendAgentAlertMessage(
377 "Error getting classified info", false);
378 return;
379 }
380 ad = (UserClassifiedAdd) Ad;
381
382 if(ad.CreatorId == UUID.Zero)
383 return;
384
385 Vector3 globalPos = new Vector3();
386 Vector3.TryParse(ad.GlobalPos, out globalPos);
387
388 remoteClient.SendClassifiedInfoReply(ad.ClassifiedId, ad.CreatorId, (uint)ad.CreationDate, (uint)ad.ExpirationDate,
389 (uint)ad.Category, ad.Name, ad.Description, ad.ParcelId, (uint)ad.ParentEstate,
390 ad.SnapshotId, ad.SimName, globalPos, ad.ParcelName, ad.Flags, ad.Price);
391
392 }
393
394 /// <summary>
395 /// Classifieds info update.
396 /// </summary>
397 /// <param name='queryclassifiedID'>
398 /// Queryclassified I.
399 /// </param>
400 /// <param name='queryCategory'>
401 /// Query category.
402 /// </param>
403 /// <param name='queryName'>
404 /// Query name.
405 /// </param>
406 /// <param name='queryDescription'>
407 /// Query description.
408 /// </param>
409 /// <param name='queryParcelID'>
410 /// Query parcel I.
411 /// </param>
412 /// <param name='queryParentEstate'>
413 /// Query parent estate.
414 /// </param>
415 /// <param name='querySnapshotID'>
416 /// Query snapshot I.
417 /// </param>
418 /// <param name='queryGlobalPos'>
419 /// Query global position.
420 /// </param>
421 /// <param name='queryclassifiedFlags'>
422 /// Queryclassified flags.
423 /// </param>
424 /// <param name='queryclassifiedPrice'>
425 /// Queryclassified price.
426 /// </param>
427 /// <param name='remoteClient'>
428 /// Remote client.
429 /// </param>
430 public void ClassifiedInfoUpdate(UUID queryclassifiedID, uint queryCategory, string queryName, string queryDescription, UUID queryParcelID,
431 uint queryParentEstate, UUID querySnapshotID, Vector3 queryGlobalPos, byte queryclassifiedFlags,
432 int queryclassifiedPrice, IClientAPI remoteClient)
433 {
434 UserClassifiedAdd ad = new UserClassifiedAdd();
435
436 Scene s = (Scene) remoteClient.Scene;
437 Vector3 pos = remoteClient.SceneAgent.AbsolutePosition;
438 ILandObject land = s.LandChannel.GetLandObject(pos.X, pos.Y);
439 ScenePresence p = FindPresence(remoteClient.AgentId);
440 Vector3 avaPos = p.AbsolutePosition;
441
442 string serverURI = string.Empty;
443 bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
444
445 if (land == null)
446 {
447 ad.ParcelName = string.Empty;
448 }
449 else
450 {
451 ad.ParcelName = land.LandData.Name;
452 }
453
454 ad.CreatorId = remoteClient.AgentId;
455 ad.ClassifiedId = queryclassifiedID;
456 ad.Category = Convert.ToInt32(queryCategory);
457 ad.Name = queryName;
458 ad.Description = queryDescription;
459 ad.ParentEstate = Convert.ToInt32(queryParentEstate);
460 ad.SnapshotId = querySnapshotID;
461 ad.SimName = remoteClient.Scene.RegionInfo.RegionName;
462 ad.GlobalPos = queryGlobalPos.ToString ();
463 ad.Flags = queryclassifiedFlags;
464 ad.Price = queryclassifiedPrice;
465 ad.ParcelId = p.currentParcelUUID;
466
467 object Ad = ad;
468
469 OSD X = OSD.SerializeMembers(Ad);
470
471 if(!JsonRpcRequest(ref Ad, "classified_update", serverURI, UUID.Random().ToString()))
472 {
473 remoteClient.SendAgentAlertMessage(
474 "Error updating classified", false);
475 }
476 }
477
478 /// <summary>
479 /// Classifieds delete.
480 /// </summary>
481 /// <param name='queryClassifiedID'>
482 /// Query classified I.
483 /// </param>
484 /// <param name='remoteClient'>
485 /// Remote client.
486 /// </param>
487 public void ClassifiedDelete(UUID queryClassifiedID, IClientAPI remoteClient)
488 {
489 string serverURI = string.Empty;
490 bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
491
492 UUID classifiedId;
493 OSDMap parameters= new OSDMap();
494 UUID.TryParse(queryClassifiedID.ToString(), out classifiedId);
495 parameters.Add("classifiedId", OSD.FromUUID(classifiedId));
496 OSD Params = (OSD)parameters;
497 if(!JsonRpcRequest(ref Params, "classified_delete", serverURI, UUID.Random().ToString()))
498 {
499 remoteClient.SendAgentAlertMessage(
500 "Error classified delete", false);
501 }
502
503 parameters = (OSDMap)Params;
504 }
505 #endregion Classified
506
507 #region Picks
508 /// <summary>
509 /// Handles the avatar picks request.
510 /// </summary>
511 /// <param name='sender'>
512 /// Sender.
513 /// </param>
514 /// <param name='method'>
515 /// Method.
516 /// </param>
517 /// <param name='args'>
518 /// Arguments.
519 /// </param>
520 public void PicksRequest(Object sender, string method, List<String> args)
521 {
522 if (!(sender is IClientAPI))
523 return;
524
525 IClientAPI remoteClient = (IClientAPI)sender;
526
527 UUID targetId;
528 UUID.TryParse(args[0], out targetId);
529
530 // Can't handle NPC yet...
531 ScenePresence p = FindPresence(targetId);
532
533 if (null != p)
534 {
535 if (p.PresenceType == PresenceType.Npc)
536 return;
537 }
538
539 string serverURI = string.Empty;
540 bool foreign = GetUserProfileServerURI(targetId, out serverURI);
541
542 OSDMap parameters= new OSDMap();
543 parameters.Add("creatorId", OSD.FromUUID(targetId));
544 OSD Params = (OSD)parameters;
545 if(!JsonRpcRequest(ref Params, "avatarpicksrequest", serverURI, UUID.Random().ToString()))
546 {
547 remoteClient.SendAgentAlertMessage(
548 "Error requesting picks", false);
549 return;
550 }
551
552 parameters = (OSDMap)Params;
553
554 OSDArray list = (OSDArray)parameters["result"];
555
556 Dictionary<UUID, string> picks = new Dictionary<UUID, string>();
557
558 foreach(OSD map in list)
559 {
560 OSDMap m = (OSDMap)map;
561 UUID cid = m["pickuuid"].AsUUID();
562 string name = m["name"].AsString();
563
564 m_log.DebugFormat("[PROFILES]: PicksRequest {0}", name);
565
566 picks[cid] = name;
567 }
568 remoteClient.SendAvatarPicksReply(new UUID(args[0]), picks);
569 }
570
571 /// <summary>
572 /// Handles the pick info request.
573 /// </summary>
574 /// <param name='sender'>
575 /// Sender.
576 /// </param>
577 /// <param name='method'>
578 /// Method.
579 /// </param>
580 /// <param name='args'>
581 /// Arguments.
582 /// </param>
583 public void PickInfoRequest(Object sender, string method, List<String> args)
584 {
585 if (!(sender is IClientAPI))
586 return;
587
588 UUID targetID;
589 UUID.TryParse(args[0], out targetID);
590 string serverURI = string.Empty;
591 bool foreign = GetUserProfileServerURI(targetID, out serverURI);
592 IClientAPI remoteClient = (IClientAPI)sender;
593
594 UserProfilePick pick = new UserProfilePick();
595 UUID.TryParse(args[0], out pick.CreatorId);
596 UUID.TryParse(args[1], out pick.PickId);
597
598
599 object Pick = (object)pick;
600 if(!JsonRpcRequest(ref Pick, "pickinforequest", serverURI, UUID.Random().ToString()))
601 {
602 remoteClient.SendAgentAlertMessage(
603 "Error selecting pick", false);
604 }
605 pick = (UserProfilePick) Pick;
606 if(pick.SnapshotId == UUID.Zero)
607 {
608 // In case of a new UserPick, the data may not be ready and we would send wrong data, skip it...
609 m_log.DebugFormat("[PROFILES]: PickInfoRequest: SnapshotID is {0}", UUID.Zero.ToString());
610 return;
611 }
612
613 Vector3 globalPos;
614 Vector3.TryParse(pick.GlobalPos,out globalPos);
615
616 m_log.DebugFormat("[PROFILES]: PickInfoRequest: {0} : {1}", pick.Name.ToString(), pick.SnapshotId.ToString());
617
618 remoteClient.SendPickInfoReply(pick.PickId,pick.CreatorId,pick.TopPick,pick.ParcelId,pick.Name,
619 pick.Desc,pick.SnapshotId,pick.User,pick.OriginalName,pick.SimName,
620 globalPos,pick.SortOrder,pick.Enabled);
621 }
622
623 /// <summary>
624 /// Updates the userpicks
625 /// </summary>
626 /// <param name='remoteClient'>
627 /// Remote client.
628 /// </param>
629 /// <param name='pickID'>
630 /// Pick I.
631 /// </param>
632 /// <param name='creatorID'>
633 /// the creator of the pick
634 /// </param>
635 /// <param name='topPick'>
636 /// Top pick.
637 /// </param>
638 /// <param name='name'>
639 /// Name.
640 /// </param>
641 /// <param name='desc'>
642 /// Desc.
643 /// </param>
644 /// <param name='snapshotID'>
645 /// Snapshot I.
646 /// </param>
647 /// <param name='sortOrder'>
648 /// Sort order.
649 /// </param>
650 /// <param name='enabled'>
651 /// Enabled.
652 /// </param>
653 public void PickInfoUpdate(IClientAPI remoteClient, UUID pickID, UUID creatorID, bool topPick, string name, string desc, UUID snapshotID, int sortOrder, bool enabled)
654 {
655
656 m_log.DebugFormat("[PROFILES]: Start PickInfoUpdate Name: {0} PickId: {1} SnapshotId: {2}", name, pickID.ToString(), snapshotID.ToString());
657 UserProfilePick pick = new UserProfilePick();
658 string serverURI = string.Empty;
659 bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
660 ScenePresence p = FindPresence(remoteClient.AgentId);
661
662 Vector3 avaPos = p.AbsolutePosition;
663 // Getting the global position for the Avatar
664 Vector3 posGlobal = new Vector3(remoteClient.Scene.RegionInfo.RegionLocX*Constants.RegionSize + avaPos.X,
665 remoteClient.Scene.RegionInfo.RegionLocY*Constants.RegionSize + avaPos.Y,
666 avaPos.Z);
667
668 string landOwnerName = string.Empty;
669 ILandObject land = p.Scene.LandChannel.GetLandObject(avaPos.X, avaPos.Y);
670 if(land.LandData.IsGroupOwned)
671 {
672 IGroupsModule groupMod = p.Scene.RequestModuleInterface<IGroupsModule>();
673 UUID groupId = land.LandData.GroupID;
674 GroupRecord groupRecord = groupMod.GetGroupRecord(groupId);
675 landOwnerName = groupRecord.GroupName;
676 }
677 else
678 {
679 IUserAccountService accounts = p.Scene.RequestModuleInterface<IUserAccountService>();
680 UserAccount user = accounts.GetUserAccount(p.Scene.RegionInfo.ScopeID, land.LandData.OwnerID);
681 landOwnerName = user.Name;
682 }
683
684 pick.PickId = pickID;
685 pick.CreatorId = creatorID;
686 pick.TopPick = topPick;
687 pick.Name = name;
688 pick.Desc = desc;
689 pick.ParcelId = p.currentParcelUUID;
690 pick.SnapshotId = snapshotID;
691 pick.User = landOwnerName;
692 pick.SimName = remoteClient.Scene.RegionInfo.RegionName;
693 pick.GlobalPos = posGlobal.ToString();
694 pick.SortOrder = sortOrder;
695 pick.Enabled = enabled;
696
697 object Pick = (object)pick;
698 if(!JsonRpcRequest(ref Pick, "picks_update", serverURI, UUID.Random().ToString()))
699 {
700 remoteClient.SendAgentAlertMessage(
701 "Error updating pick", false);
702 }
703
704 m_log.DebugFormat("[PROFILES]: Finish PickInfoUpdate {0} {1}", pick.Name, pick.PickId.ToString());
705 }
706
707 /// <summary>
708 /// Delete a Pick
709 /// </summary>
710 /// <param name='remoteClient'>
711 /// Remote client.
712 /// </param>
713 /// <param name='queryPickID'>
714 /// Query pick I.
715 /// </param>
716 public void PickDelete(IClientAPI remoteClient, UUID queryPickID)
717 {
718 string serverURI = string.Empty;
719 bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
720
721 OSDMap parameters= new OSDMap();
722 parameters.Add("pickId", OSD.FromUUID(queryPickID));
723 OSD Params = (OSD)parameters;
724 if(!JsonRpcRequest(ref Params, "picks_delete", serverURI, UUID.Random().ToString()))
725 {
726 remoteClient.SendAgentAlertMessage(
727 "Error picks delete", false);
728 }
729 }
730 #endregion Picks
731
732 #region Notes
733 /// <summary>
734 /// Handles the avatar notes request.
735 /// </summary>
736 /// <param name='sender'>
737 /// Sender.
738 /// </param>
739 /// <param name='method'>
740 /// Method.
741 /// </param>
742 /// <param name='args'>
743 /// Arguments.
744 /// </param>
745 public void NotesRequest(Object sender, string method, List<String> args)
746 {
747 UserProfileNotes note = new UserProfileNotes();
748
749 if (!(sender is IClientAPI))
750 return;
751
752 IClientAPI remoteClient = (IClientAPI)sender;
753 string serverURI = string.Empty;
754 bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
755 note.TargetId = remoteClient.AgentId;
756 UUID.TryParse(args[0], out note.UserId);
757
758 object Note = (object)note;
759 if(!JsonRpcRequest(ref Note, "avatarnotesrequest", serverURI, UUID.Random().ToString()))
760 {
761 remoteClient.SendAgentAlertMessage(
762 "Error requesting note", false);
763 }
764 note = (UserProfileNotes) Note;
765
766 remoteClient.SendAvatarNotesReply(note.TargetId, note.Notes);
767 }
768
769 /// <summary>
770 /// Avatars the notes update.
771 /// </summary>
772 /// <param name='remoteClient'>
773 /// Remote client.
774 /// </param>
775 /// <param name='queryTargetID'>
776 /// Query target I.
777 /// </param>
778 /// <param name='queryNotes'>
779 /// Query notes.
780 /// </param>
781 public void NotesUpdate(IClientAPI remoteClient, UUID queryTargetID, string queryNotes)
782 {
783 UserProfileNotes note = new UserProfileNotes();
784
785 note.UserId = remoteClient.AgentId;
786 note.TargetId = queryTargetID;
787 note.Notes = queryNotes;
788
789 string serverURI = string.Empty;
790 bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
791
792 object Note = note;
793 if(!JsonRpcRequest(ref Note, "avatar_notes_update", serverURI, UUID.Random().ToString()))
794 {
795 remoteClient.SendAgentAlertMessage(
796 "Error updating note", false);
797 }
798 }
799 #endregion Notes
800
801 #region Avatar Properties
802 /// <summary>
803 /// Update the avatars interests .
804 /// </summary>
805 /// <param name='remoteClient'>
806 /// Remote client.
807 /// </param>
808 /// <param name='wantmask'>
809 /// Wantmask.
810 /// </param>
811 /// <param name='wanttext'>
812 /// Wanttext.
813 /// </param>
814 /// <param name='skillsmask'>
815 /// Skillsmask.
816 /// </param>
817 /// <param name='skillstext'>
818 /// Skillstext.
819 /// </param>
820 /// <param name='languages'>
821 /// Languages.
822 /// </param>
823 public void AvatarInterestsUpdate(IClientAPI remoteClient, uint wantmask, string wanttext, uint skillsmask, string skillstext, string languages)
824 {
825 UserProfileProperties prop = new UserProfileProperties();
826
827 prop.UserId = remoteClient.AgentId;
828 prop.WantToMask = (int)wantmask;
829 prop.WantToText = wanttext;
830 prop.SkillsMask = (int)skillsmask;
831 prop.SkillsText = skillstext;
832 prop.Language = languages;
833
834 string serverURI = string.Empty;
835 bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
836
837 object Param = prop;
838 if(!JsonRpcRequest(ref Param, "avatar_interests_update", serverURI, UUID.Random().ToString()))
839 {
840 remoteClient.SendAgentAlertMessage(
841 "Error updating interests", false);
842 }
843 }
844
845 public void RequestAvatarProperties(IClientAPI remoteClient, UUID avatarID)
846 {
847 if ( String.IsNullOrEmpty(avatarID.ToString()) || String.IsNullOrEmpty(remoteClient.AgentId.ToString()))
848 {
849 // Looking for a reason that some viewers are sending null Id's
850 m_log.DebugFormat("[PROFILES]: This should not happen remoteClient.AgentId {0} - avatarID {1}", remoteClient.AgentId, avatarID);
851 return;
852 }
853
854 // Can't handle NPC yet...
855 ScenePresence p = FindPresence(avatarID);
856
857 if (null != p)
858 {
859 if (p.PresenceType == PresenceType.Npc)
860 return;
861 }
862
863 string serverURI = string.Empty;
864 bool foreign = GetUserProfileServerURI(avatarID, out serverURI);
865
866 UserAccount account = null;
867 Dictionary<string,object> userInfo;
868
869 if (!foreign)
870 {
871 account = Scene.UserAccountService.GetUserAccount(Scene.RegionInfo.ScopeID, avatarID);
872 }
873 else
874 {
875 userInfo = new Dictionary<string, object>();
876 }
877
878 Byte[] charterMember = new Byte[1];
879 string born = String.Empty;
880 uint flags = 0x00;
881
882 if (null != account)
883 {
884 if (account.UserTitle == "")
885 {
886 charterMember[0] = (Byte)((account.UserFlags & 0xf00) >> 8);
887 }
888 else
889 {
890 charterMember = Utils.StringToBytes(account.UserTitle);
891 }
892
893 born = Util.ToDateTime(account.Created).ToString(
894 "M/d/yyyy", CultureInfo.InvariantCulture);
895 flags = (uint)(account.UserFlags & 0xff);
896 }
897 else
898 {
899 if (GetUserAccountData(avatarID, out userInfo) == true)
900 {
901 if ((string)userInfo["user_title"] == "")
902 {
903 charterMember[0] = (Byte)(((Byte)userInfo["user_flags"] & 0xf00) >> 8);
904 }
905 else
906 {
907 charterMember = Utils.StringToBytes((string)userInfo["user_title"]);
908 }
909
910 int val_born = (int)userInfo["user_created"];
911 born = Util.ToDateTime(val_born).ToString(
912 "M/d/yyyy", CultureInfo.InvariantCulture);
913
914 // picky, picky
915 int val_flags = (int)userInfo["user_flags"];
916 flags = (uint)(val_flags & 0xff);
917 }
918 }
919
920 UserProfileProperties props = new UserProfileProperties();
921 string result = string.Empty;
922
923 props.UserId = avatarID;
924 GetProfileData(ref props, out result);
925
926 remoteClient.SendAvatarProperties(props.UserId, props.AboutText, born, charterMember , props.FirstLifeText, flags,
927 props.FirstLifeImageId, props.ImageId, props.WebUrl, props.PartnerId);
928
929
930 remoteClient.SendAvatarInterestsReply(props.UserId, (uint)props.WantToMask, props.WantToText, (uint)props.SkillsMask,
931 props.SkillsText, props.Language);
932 }
933
934 /// <summary>
935 /// Updates the avatar properties.
936 /// </summary>
937 /// <param name='remoteClient'>
938 /// Remote client.
939 /// </param>
940 /// <param name='newProfile'>
941 /// New profile.
942 /// </param>
943 public void AvatarPropertiesUpdate(IClientAPI remoteClient, UserProfileData newProfile)
944 {
945 if (remoteClient.AgentId == newProfile.ID)
946 {
947 UserProfileProperties prop = new UserProfileProperties();
948
949 prop.UserId = remoteClient.AgentId;
950 prop.WebUrl = newProfile.ProfileUrl;
951 prop.ImageId = newProfile.Image;
952 prop.AboutText = newProfile.AboutText;
953 prop.FirstLifeImageId = newProfile.FirstLifeImage;
954 prop.FirstLifeText = newProfile.FirstLifeAboutText;
955
956 string serverURI = string.Empty;
957 bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
958
959 object Prop = prop;
960
961 if(!JsonRpcRequest(ref Prop, "avatar_properties_update", serverURI, UUID.Random().ToString()))
962 {
963 remoteClient.SendAgentAlertMessage(
964 "Error updating properties", false);
965 }
966
967 RequestAvatarProperties(remoteClient, newProfile.ID);
968 }
969 }
970
971
972 /// <summary>
973 /// Gets the profile data.
974 /// </summary>
975 /// <returns>
976 /// The profile data.
977 /// </returns>
978 /// <param name='userID'>
979 /// User I.
980 /// </param>
981 bool GetProfileData(ref UserProfileProperties properties, out string message)
982 {
983 // Can't handle NPC yet...
984 ScenePresence p = FindPresence(properties.UserId);
985
986 if (null != p)
987 {
988 if (p.PresenceType == PresenceType.Npc)
989 {
990 message = "Id points to NPC";
991 return false;
992 }
993 }
994
995 string serverURI = string.Empty;
996 bool foreign = GetUserProfileServerURI(properties.UserId, out serverURI);
997
998 // This is checking a friend on the home grid
999 // Not HG friend
1000 if ( String.IsNullOrEmpty(serverURI))
1001 {
1002 message = "No Presence - foreign friend";
1003 return false;
1004 }
1005
1006 object Prop = (object)properties;
1007 JsonRpcRequest(ref Prop, "avatar_properties_request", serverURI, UUID.Random().ToString());
1008 properties = (UserProfileProperties)Prop;
1009
1010 message = "Success";
1011 return true;
1012 }
1013 #endregion Avatar Properties
1014
1015 #region Utils
1016 bool GetImageAssets(UUID avatarId)
1017 {
1018 string profileServerURI = string.Empty;
1019 string assetServerURI = string.Empty;
1020
1021 bool foreign = GetUserProfileServerURI(avatarId, out profileServerURI);
1022
1023 if(!foreign)
1024 return true;
1025
1026 assetServerURI = UserManagementModule.GetUserServerURL(avatarId, "AssetServerURI");
1027
1028 OSDMap parameters= new OSDMap();
1029 parameters.Add("avatarId", OSD.FromUUID(avatarId));
1030 OSD Params = (OSD)parameters;
1031 if(!JsonRpcRequest(ref Params, "image_assets_request", profileServerURI, UUID.Random().ToString()))
1032 {
1033 // Error Handling here!
1034 // if(parameters.ContainsKey("message")
1035 return false;
1036 }
1037
1038 parameters = (OSDMap)Params;
1039
1040 OSDArray list = (OSDArray)parameters["result"];
1041
1042 foreach(OSD asset in list)
1043 {
1044 OSDString assetId = (OSDString)asset;
1045
1046 Scene.AssetService.Get(string.Format("{0}/{1}",assetServerURI, assetId.AsString()), this,
1047 delegate (string assetID, Object s, AssetBase a)
1048 {
1049 // m_log.DebugFormat("[PROFILES]: Getting Image Assets {0}", assetID);
1050 return;
1051 });
1052 }
1053 return true;
1054 }
1055
1056 /// <summary>
1057 /// Gets the user account data.
1058 /// </summary>
1059 /// <returns>
1060 /// The user profile data.
1061 /// </returns>
1062 /// <param name='userID'>
1063 /// If set to <c>true</c> user I.
1064 /// </param>
1065 /// <param name='userInfo'>
1066 /// If set to <c>true</c> user info.
1067 /// </param>
1068 bool GetUserAccountData(UUID userID, out Dictionary<string, object> userInfo)
1069 {
1070 Dictionary<string,object> info = new Dictionary<string, object>();
1071
1072 if (UserManagementModule.IsLocalGridUser(userID))
1073 {
1074 // Is local
1075 IUserAccountService uas = Scene.UserAccountService;
1076 UserAccount account = uas.GetUserAccount(Scene.RegionInfo.ScopeID, userID);
1077
1078 info["user_flags"] = account.UserFlags;
1079 info["user_created"] = account.Created;
1080
1081 if (!String.IsNullOrEmpty(account.UserTitle))
1082 info["user_title"] = account.UserTitle;
1083 else
1084 info["user_title"] = "";
1085
1086 userInfo = info;
1087
1088 return false;
1089 }
1090 else
1091 {
1092 // Is Foreign
1093 string home_url = UserManagementModule.GetUserServerURL(userID, "HomeURI");
1094
1095 if (String.IsNullOrEmpty(home_url))
1096 {
1097 info["user_flags"] = 0;
1098 info["user_created"] = 0;
1099 info["user_title"] = "Unavailable";
1100
1101 userInfo = info;
1102 return true;
1103 }
1104
1105 UserAgentServiceConnector uConn = new UserAgentServiceConnector(home_url);
1106
1107 Dictionary<string, object> account = uConn.GetUserInfo(userID);
1108
1109 if (account.Count > 0)
1110 {
1111 if (account.ContainsKey("user_flags"))
1112 info["user_flags"] = account["user_flags"];
1113 else
1114 info["user_flags"] = "";
1115
1116 if (account.ContainsKey("user_created"))
1117 info["user_created"] = account["user_created"];
1118 else
1119 info["user_created"] = "";
1120
1121 info["user_title"] = "HG Visitor";
1122 }
1123 else
1124 {
1125 info["user_flags"] = 0;
1126 info["user_created"] = 0;
1127 info["user_title"] = "HG Visitor";
1128 }
1129 userInfo = info;
1130 return true;
1131 }
1132 }
1133
1134 /// <summary>
1135 /// Gets the user profile server UR.
1136 /// </summary>
1137 /// <returns>
1138 /// The user profile server UR.
1139 /// </returns>
1140 /// <param name='userID'>
1141 /// If set to <c>true</c> user I.
1142 /// </param>
1143 /// <param name='serverURI'>
1144 /// If set to <c>true</c> server UR.
1145 /// </param>
1146 bool GetUserProfileServerURI(UUID userID, out string serverURI)
1147 {
1148 bool local;
1149 local = UserManagementModule.IsLocalGridUser(userID);
1150
1151 if (!local)
1152 {
1153 serverURI = UserManagementModule.GetUserServerURL(userID, "ProfileServerURI");
1154 // Is Foreign
1155 return true;
1156 }
1157 else
1158 {
1159 serverURI = ProfileServerUri;
1160 // Is local
1161 return false;
1162 }
1163 }
1164
1165 /// <summary>
1166 /// Finds the presence.
1167 /// </summary>
1168 /// <returns>
1169 /// The presence.
1170 /// </returns>
1171 /// <param name='clientID'>
1172 /// Client I.
1173 /// </param>
1174 ScenePresence FindPresence(UUID clientID)
1175 {
1176 ScenePresence p;
1177
1178 p = Scene.GetScenePresence(clientID);
1179 if (p != null && !p.IsChildAgent)
1180 return p;
1181
1182 return null;
1183 }
1184 #endregion Util
1185
1186 #region Web Util
1187 /// <summary>
1188 /// Sends json-rpc request with a serializable type.
1189 /// </summary>
1190 /// <returns>
1191 /// OSD Map.
1192 /// </returns>
1193 /// <param name='parameters'>
1194 /// Serializable type .
1195 /// </param>
1196 /// <param name='method'>
1197 /// Json-rpc method to call.
1198 /// </param>
1199 /// <param name='uri'>
1200 /// URI of json-rpc service.
1201 /// </param>
1202 /// <param name='jsonId'>
1203 /// Id for our call.
1204 /// </param>
1205 bool JsonRpcRequest(ref object parameters, string method, string uri, string jsonId)
1206 {
1207 if (jsonId == null)
1208 throw new ArgumentNullException ("jsonId");
1209 if (uri == null)
1210 throw new ArgumentNullException ("uri");
1211 if (method == null)
1212 throw new ArgumentNullException ("method");
1213 if (parameters == null)
1214 throw new ArgumentNullException ("parameters");
1215
1216 // Prep our payload
1217 OSDMap json = new OSDMap();
1218
1219 json.Add("jsonrpc", OSD.FromString("2.0"));
1220 json.Add("id", OSD.FromString(jsonId));
1221 json.Add("method", OSD.FromString(method));
1222 // Experiment
1223 json.Add("params", OSD.SerializeMembers(parameters));
1224
1225 string jsonRequestData = OSDParser.SerializeJsonString(json);
1226 byte[] content = Encoding.UTF8.GetBytes(jsonRequestData);
1227
1228 HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri);
1229 // webRequest.Credentials = new NetworkCredential(rpcUser, rpcPass);
1230 webRequest.ContentType = "application/json-rpc";
1231 webRequest.Method = "POST";
1232
1233 Stream dataStream = webRequest.GetRequestStream();
1234 dataStream.Write(content, 0, content.Length);
1235 dataStream.Close();
1236
1237 WebResponse webResponse = null;
1238 try
1239 {
1240 webResponse = webRequest.GetResponse();
1241 }
1242 catch (WebException e)
1243 {
1244 Console.WriteLine("Web Error" + e.Message);
1245 Console.WriteLine ("Please check input");
1246 return false;
1247 }
1248
1249 byte[] buf = new byte[8192];
1250 Stream rstream = webResponse.GetResponseStream();
1251 OSDMap mret = (OSDMap)OSDParser.DeserializeJson(rstream);
1252
1253 if(mret.ContainsKey("error"))
1254 return false;
1255
1256 // get params...
1257 OSD.DeserializeMembers(ref parameters, (OSDMap) mret["result"]);
1258 return true;
1259 }
1260
1261 /// <summary>
1262 /// Sends json-rpc request with OSD parameter.
1263 /// </summary>
1264 /// <returns>
1265 /// The rpc request.
1266 /// </returns>
1267 /// <param name='data'>
1268 /// data - incoming as parameters, outgong as result/error
1269 /// </param>
1270 /// <param name='method'>
1271 /// Json-rpc method to call.
1272 /// </param>
1273 /// <param name='uri'>
1274 /// URI of json-rpc service.
1275 /// </param>
1276 /// <param name='jsonId'>
1277 /// If set to <c>true</c> json identifier.
1278 /// </param>
1279 bool JsonRpcRequest(ref OSD data, string method, string uri, string jsonId)
1280 {
1281 OSDMap map = new OSDMap();
1282
1283 map["jsonrpc"] = "2.0";
1284 if(string.IsNullOrEmpty(jsonId))
1285 map["id"] = UUID.Random().ToString();
1286 else
1287 map["id"] = jsonId;
1288
1289 map["method"] = method;
1290 map["params"] = data;
1291
1292 string jsonRequestData = OSDParser.SerializeJsonString(map);
1293 byte[] content = Encoding.UTF8.GetBytes(jsonRequestData);
1294
1295 HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri);
1296 webRequest.ContentType = "application/json-rpc";
1297 webRequest.Method = "POST";
1298
1299 Stream dataStream = webRequest.GetRequestStream();
1300 dataStream.Write(content, 0, content.Length);
1301 dataStream.Close();
1302
1303 WebResponse webResponse = null;
1304 try
1305 {
1306 webResponse = webRequest.GetResponse();
1307 }
1308 catch (WebException e)
1309 {
1310 Console.WriteLine("Web Error" + e.Message);
1311 Console.WriteLine ("Please check input");
1312 return false;
1313 }
1314
1315 byte[] buf = new byte[8192];
1316 Stream rstream = webResponse.GetResponseStream();
1317
1318 OSDMap response = new OSDMap();
1319 response = (OSDMap)OSDParser.DeserializeJson(rstream);
1320 if(response.ContainsKey("error"))
1321 {
1322 data = response["error"];
1323 return false;
1324 }
1325
1326 data = response;
1327
1328 return true;
1329 }
1330 #endregion Web Util
1331 }
1332}
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
index ed867b8..b9c88d4 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
@@ -280,10 +280,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
280 280
281 private void OnConnectionClosed(IClientAPI client) 281 private void OnConnectionClosed(IClientAPI client)
282 { 282 {
283 if (client.IsLoggingOut) 283 if (client.IsLoggingOut && m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Aborting))
284 { 284 {
285 m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Aborting);
286
287 m_log.DebugFormat( 285 m_log.DebugFormat(
288 "[ENTITY TRANSFER MODULE]: Aborted teleport request from {0} in {1} due to simultaneous logout", 286 "[ENTITY TRANSFER MODULE]: Aborted teleport request from {0} in {1} due to simultaneous logout",
289 client.Name, Scene.Name); 287 client.Name, Scene.Name);
@@ -944,6 +942,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
944 EnableChildAgents(sp); 942 EnableChildAgents(sp);
945 943
946 // Finally, kill the agent we just created at the destination. 944 // Finally, kill the agent we just created at the destination.
945 // XXX: Possibly this should be done asynchronously.
947 Scene.SimulationService.CloseAgent(finalDestination, sp.UUID); 946 Scene.SimulationService.CloseAgent(finalDestination, sp.UUID);
948 } 947 }
949 948
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
index 4c11135..d5c2661 100644
--- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
@@ -358,7 +358,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
358 bool asAttachment) 358 bool asAttachment)
359 { 359 {
360 CoalescedSceneObjects coa = new CoalescedSceneObjects(UUID.Zero); 360 CoalescedSceneObjects coa = new CoalescedSceneObjects(UUID.Zero);
361 Dictionary<UUID, Vector3> originalPositions = new Dictionary<UUID, Vector3>(); 361// Dictionary<UUID, Vector3> originalPositions = new Dictionary<UUID, Vector3>();
362 362
363 foreach (SceneObjectGroup objectGroup in objlist) 363 foreach (SceneObjectGroup objectGroup in objlist)
364 { 364 {
@@ -379,7 +379,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
379 objectGroup.AbsolutePosition.Z); 379 objectGroup.AbsolutePosition.Z);
380 380
381 Quaternion inventoryStoredRotation = objectGroup.GroupRotation; 381 Quaternion inventoryStoredRotation = objectGroup.GroupRotation;
382 originalPositions[objectGroup.UUID] = objectGroup.AbsolutePosition; 382 //originalPositions[objectGroup.UUID] = objectGroup.AbsolutePosition;
383 383
384 // Restore attachment data after trip through the sim 384 // Restore attachment data after trip through the sim
385 if (objectGroup.RootPart.AttachPoint > 0) 385 if (objectGroup.RootPart.AttachPoint > 0)
@@ -423,9 +423,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
423 else 423 else
424 itemXml = SceneObjectSerializer.ToOriginalXmlFormat(objlist[0], !asAttachment); 424 itemXml = SceneObjectSerializer.ToOriginalXmlFormat(objlist[0], !asAttachment);
425 425
426 // Restore the position of each group now that it has been stored to inventory. 426// // Restore the position of each group now that it has been stored to inventory.
427 foreach (SceneObjectGroup objectGroup in objlist) 427// foreach (SceneObjectGroup objectGroup in objlist)
428 objectGroup.AbsolutePosition = originalPositions[objectGroup.UUID]; 428// objectGroup.AbsolutePosition = originalPositions[objectGroup.UUID];
429 429
430 InventoryItemBase item = CreateItemForObject(action, remoteClient, objlist[0], folderID); 430 InventoryItemBase item = CreateItemForObject(action, remoteClient, objlist[0], folderID);
431 431
@@ -707,6 +707,12 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
707 InventoryFolderBase f = new InventoryFolderBase(so.FromFolderID, userID); 707 InventoryFolderBase f = new InventoryFolderBase(so.FromFolderID, userID);
708 if (f != null) 708 if (f != null)
709 folder = m_Scene.InventoryService.GetFolder(f); 709 folder = m_Scene.InventoryService.GetFolder(f);
710
711 if(folder.Type == 14 || folder.Type == 16)
712 {
713 // folder.Type = 6;
714 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.Object);
715 }
710 } 716 }
711 } 717 }
712 718
@@ -876,7 +882,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
876 return null; 882 return null;
877 } 883 }
878 884
879 if (item != null && !DoPreRezWhenFromItem(remoteClient, item, objlist, pos, attachment)) 885 if (item != null && !DoPreRezWhenFromItem(remoteClient, item, objlist, pos, veclist, attachment))
880 return null; 886 return null;
881 887
882 for (int i = 0; i < objlist.Count; i++) 888 for (int i = 0; i < objlist.Count; i++)
@@ -975,10 +981,15 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
975 /// <param name="item"></param> 981 /// <param name="item"></param>
976 /// <param name="objlist"></param> 982 /// <param name="objlist"></param>
977 /// <param name="pos"></param> 983 /// <param name="pos"></param>
984 /// <param name="veclist">
985 /// List of vector position adjustments for a coalesced objects. For ordinary objects
986 /// this list will contain just Vector3.Zero. The order of adjustments must match the order of objlist
987 /// </param>
978 /// <param name="isAttachment"></param> 988 /// <param name="isAttachment"></param>
979 /// <returns>true if we can processed with rezzing, false if we need to abort</returns> 989 /// <returns>true if we can processed with rezzing, false if we need to abort</returns>
980 private bool DoPreRezWhenFromItem( 990 private bool DoPreRezWhenFromItem(
981 IClientAPI remoteClient, InventoryItemBase item, List<SceneObjectGroup> objlist, Vector3 pos, bool isAttachment) 991 IClientAPI remoteClient, InventoryItemBase item, List<SceneObjectGroup> objlist,
992 Vector3 pos, List<Vector3> veclist, bool isAttachment)
982 { 993 {
983 UUID fromUserInventoryItemId = UUID.Zero; 994 UUID fromUserInventoryItemId = UUID.Zero;
984 995
@@ -1001,28 +1012,29 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
1001 } 1012 }
1002 } 1013 }
1003 1014
1004 int primcount = 0; 1015 for (int i = 0; i < objlist.Count; i++)
1005 foreach (SceneObjectGroup g in objlist)
1006 primcount += g.PrimCount;
1007
1008 if (!m_Scene.Permissions.CanRezObject(
1009 primcount, remoteClient.AgentId, pos)
1010 && !isAttachment)
1011 { 1016 {
1012 // The client operates in no fail mode. It will 1017 SceneObjectGroup g = objlist[i];
1013 // have already removed the item from the folder 1018
1014 // if it's no copy. 1019 if (!m_Scene.Permissions.CanRezObject(
1015 // Put it back if it's not an attachment 1020 g.PrimCount, remoteClient.AgentId, pos + veclist[i])
1016 // 1021 && !isAttachment)
1017 if (((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) && (!isAttachment)) 1022 {
1018 remoteClient.SendBulkUpdateInventory(item); 1023 // The client operates in no fail mode. It will
1024 // have already removed the item from the folder
1025 // if it's no copy.
1026 // Put it back if it's not an attachment
1027 //
1028 if (((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) && (!isAttachment))
1029 remoteClient.SendBulkUpdateInventory(item);
1019 1030
1020 ILandObject land = m_Scene.LandChannel.GetLandObject(pos.X, pos.Y); 1031 ILandObject land = m_Scene.LandChannel.GetLandObject(pos.X, pos.Y);
1021 remoteClient.SendAlertMessage(string.Format( 1032 remoteClient.SendAlertMessage(string.Format(
1022 "Can't rez object '{0}' at <{1:F3}, {2:F3}, {3:F3}> on parcel '{4}' in region {5}.", 1033 "Can't rez object '{0}' at <{1:F3}, {2:F3}, {3:F3}> on parcel '{4}' in region {5}.",
1023 item.Name, pos.X, pos.Y, pos.Z, land != null ? land.LandData.Name : "Unknown", m_Scene.RegionInfo.RegionName)); 1034 item.Name, pos.X, pos.Y, pos.Z, land != null ? land.LandData.Name : "Unknown", m_Scene.Name));
1024 1035
1025 return false; 1036 return false;
1037 }
1026 } 1038 }
1027 1039
1028 for (int i = 0; i < objlist.Count; i++) 1040 for (int i = 0; i < objlist.Count; i++)
diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs
index 4ef57fe..ad3cf15 100644
--- a/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs
@@ -50,12 +50,11 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
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
54 #region ISharedRegionModule 53 #region ISharedRegionModule
55 54
56 public new void Initialise(IConfigSource config) 55 public new void Initialise(IConfigSource config)
57 { 56 {
58 string umanmod = config.Configs["Modules"].GetString("UserManagementModule", base.Name); 57 string umanmod = config.Configs["Modules"].GetString("UserManagementModule", null);
59 if (umanmod == Name) 58 if (umanmod == Name)
60 { 59 {
61 m_Enabled = true; 60 m_Enabled = true;
@@ -71,7 +70,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
71 70
72 #endregion ISharedRegionModule 71 #endregion ISharedRegionModule
73 72
74 protected override void AddAdditionalUsers(UUID avatarID, string query, List<UserData> users) 73 protected override void AddAdditionalUsers(string query, List<UserData> users)
75 { 74 {
76 if (query.Contains("@")) // First.Last@foo.com, maybe? 75 if (query.Contains("@")) // First.Last@foo.com, maybe?
77 { 76 {
diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/Tests/HGUserManagementModuleTests.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/Tests/HGUserManagementModuleTests.cs
new file mode 100644
index 0000000..9d36aa5
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Framework/UserManagement/Tests/HGUserManagementModuleTests.cs
@@ -0,0 +1,76 @@
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 Nini.Config;
30using NUnit.Framework;
31using OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.CoreModules.Framework.UserManagement;
34using OpenSim.Tests.Common;
35using OpenSim.Tests.Common.Mock;
36
37namespace OpenSim.Region.CoreModules.Framework.UserManagement.Tests
38{
39 [TestFixture]
40 public class HGUserManagementModuleTests : OpenSimTestCase
41 {
42 /// <summary>
43 /// Test that a new HG agent (i.e. one without a user account) has their name cached in the UMM upon creation.
44 /// </summary>
45 [Test]
46 public void TestCachedUserNameForNewAgent()
47 {
48 TestHelpers.InMethod();
49// TestHelpers.EnableLogging();
50
51 HGUserManagementModule hgumm = new HGUserManagementModule();
52 UUID userId = TestHelpers.ParseStem("11");
53 string firstName = "Fred";
54 string lastName = "Astaire";
55 string homeUri = "example.com";
56
57 IConfigSource config = new IniConfigSource();
58 config.AddConfig("Modules");
59 config.Configs["Modules"].Set("UserManagementModule", hgumm.Name);
60
61 SceneHelpers sceneHelpers = new SceneHelpers();
62 TestScene scene = sceneHelpers.SetupScene();
63 SceneHelpers.SetupSceneModules(scene, config, hgumm);
64
65 AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId);
66 acd.firstname = firstName;
67 acd.lastname = lastName;
68 acd.ServiceURLs["HomeURI"] = "http://" + homeUri;
69
70 SceneHelpers.AddScenePresence(scene, acd);
71
72 string name = hgumm.GetUserName(userId);
73 Assert.That(name, Is.EqualTo(string.Format("{0}.{1} @{2}", firstName, lastName, homeUri)));
74 }
75 }
76} \ 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 77e8b00..1e70b84 100644
--- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs
@@ -46,17 +46,8 @@ using Mono.Addins;
46 46
47namespace OpenSim.Region.CoreModules.Framework.UserManagement 47namespace OpenSim.Region.CoreModules.Framework.UserManagement
48{ 48{
49 public class UserData
50 {
51 public UUID Id { get; set; }
52 public string FirstName { get; set; }
53 public string LastName { get; set; }
54 public string HomeURL { get; set; }
55 public Dictionary<string, object> ServerURLs { get; set; }
56 }
57
58 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UserManagementModule")] 49 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UserManagementModule")]
59 public class UserManagementModule : ISharedRegionModule, IUserManagement 50 public class UserManagementModule : ISharedRegionModule, IUserManagement, IPeople
60 { 51 {
61 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 52 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
62 53
@@ -101,6 +92,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
101 m_Scenes.Add(scene); 92 m_Scenes.Add(scene);
102 93
103 scene.RegisterModuleInterface<IUserManagement>(this); 94 scene.RegisterModuleInterface<IUserManagement>(this);
95 scene.RegisterModuleInterface<IPeople>(this);
104 scene.EventManager.OnNewClient += new EventManager.OnNewClientDelegate(EventManager_OnNewClient); 96 scene.EventManager.OnNewClient += new EventManager.OnNewClientDelegate(EventManager_OnNewClient);
105 scene.EventManager.OnPrimsLoaded += new EventManager.PrimsLoaded(EventManager_OnPrimsLoaded); 97 scene.EventManager.OnPrimsLoaded += new EventManager.PrimsLoaded(EventManager_OnPrimsLoaded);
106 } 98 }
@@ -165,13 +157,16 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
165 } 157 }
166 else 158 else
167 { 159 {
168 string[] names = GetUserNames(uuid); 160 string[] names;
161 bool foundRealName = TryGetUserNames(uuid, out names);
162
169 if (names.Length == 2) 163 if (names.Length == 2)
170 { 164 {
171 //m_log.DebugFormat("[XXX] HandleUUIDNameRequest {0} is {1} {2}", uuid, names[0], names[1]); 165 if (!foundRealName)
166 m_log.DebugFormat("[USER MANAGEMENT MODULE]: Sending {0} {1} for {2} to {3} since no bound name found", names[0], names[1], uuid, remote_client.Name);
167
172 remote_client.SendNameReply(uuid, names[0], names[1]); 168 remote_client.SendNameReply(uuid, names[0], names[1]);
173 } 169 }
174
175 } 170 }
176 } 171 }
177 172
@@ -181,29 +176,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
181 176
182 m_log.DebugFormat("[USER MANAGEMENT MODULE]: HandleAvatarPickerRequest for {0}", query); 177 m_log.DebugFormat("[USER MANAGEMENT MODULE]: HandleAvatarPickerRequest for {0}", query);
183 178
184 // searhc the user accounts service 179 List<UserData> users = GetUserData(query, 500, 1);
185 List<UserAccount> accs = m_Scenes[0].UserAccountService.GetUserAccounts(m_Scenes[0].RegionInfo.ScopeID, query);
186
187 List<UserData> users = new List<UserData>();
188 if (accs != null)
189 {
190 foreach (UserAccount acc in accs)
191 {
192 UserData ud = new UserData();
193 ud.FirstName = acc.FirstName;
194 ud.LastName = acc.LastName;
195 ud.Id = acc.PrincipalID;
196 users.Add(ud);
197 }
198 }
199
200 // search the local cache
201 foreach (UserData data in m_UserCache.Values)
202 if (users.Find(delegate(UserData d) { return d.Id == data.Id; }) == null &&
203 (data.FirstName.StartsWith(query) || data.LastName.StartsWith(query)))
204 users.Add(data);
205
206 AddAdditionalUsers(avatarID, query, users);
207 180
208 AvatarPickerReplyPacket replyPacket = (AvatarPickerReplyPacket)PacketPool.Instance.GetPacket(PacketType.AvatarPickerReply); 181 AvatarPickerReplyPacket replyPacket = (AvatarPickerReplyPacket)PacketPool.Instance.GetPacket(PacketType.AvatarPickerReply);
209 // TODO: don't create new blocks if recycling an old packet 182 // TODO: don't create new blocks if recycling an old packet
@@ -249,12 +222,51 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
249 client.SendAvatarPickerReply(agent_data, data_args); 222 client.SendAvatarPickerReply(agent_data, data_args);
250 } 223 }
251 224
252 protected virtual void AddAdditionalUsers(UUID avatarID, string query, List<UserData> users) 225 protected virtual void AddAdditionalUsers(string query, List<UserData> users)
253 { 226 {
254 } 227 }
255 228
256 #endregion Event Handlers 229 #endregion Event Handlers
257 230
231 #region IPeople
232
233 public List<UserData> GetUserData(string query, int page_size, int page_number)
234 {
235 // search the user accounts service
236 List<UserAccount> accs = m_Scenes[0].UserAccountService.GetUserAccounts(m_Scenes[0].RegionInfo.ScopeID, query);
237
238 List<UserData> users = new List<UserData>();
239 if (accs != null)
240 {
241 foreach (UserAccount acc in accs)
242 {
243 UserData ud = new UserData();
244 ud.FirstName = acc.FirstName;
245 ud.LastName = acc.LastName;
246 ud.Id = acc.PrincipalID;
247 users.Add(ud);
248 }
249 }
250
251 // search the local cache
252 lock (m_UserCache)
253 {
254 foreach (UserData data in m_UserCache.Values)
255 {
256 if (users.Find(delegate(UserData d) { return d.Id == data.Id; }) == null &&
257 (data.FirstName.ToLower().StartsWith(query.ToLower()) || data.LastName.ToLower().StartsWith(query.ToLower())))
258 users.Add(data);
259 }
260 }
261
262 AddAdditionalUsers(query, users);
263
264 return users;
265
266 }
267
268 #endregion IPeople
269
258 private void CacheCreators(SceneObjectGroup sog) 270 private void CacheCreators(SceneObjectGroup sog)
259 { 271 {
260 //m_log.DebugFormat("[USER MANAGEMENT MODULE]: processing {0} {1}; {2}", sog.RootPart.Name, sog.RootPart.CreatorData, sog.RootPart.CreatorIdentification); 272 //m_log.DebugFormat("[USER MANAGEMENT MODULE]: processing {0} {1}; {2}", sog.RootPart.Name, sog.RootPart.CreatorData, sog.RootPart.CreatorIdentification);
@@ -268,17 +280,24 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
268 } 280 }
269 } 281 }
270 282
271 private string[] GetUserNames(UUID uuid) 283 /// <summary>
284 /// Try to get the names bound to the given uuid.
285 /// </summary>
286 /// <returns>True if the name was found, false if not.</returns>
287 /// <param name='uuid'></param>
288 /// <param name='names'>The array of names if found. If not found, then names[0] = "Unknown" and names[1] = "User"</param>
289 private bool TryGetUserNames(UUID uuid, out string[] names)
272 { 290 {
273 string[] returnstring = new string[2]; 291 names = new string[2];
274 292
275 lock (m_UserCache) 293 lock (m_UserCache)
276 { 294 {
277 if (m_UserCache.ContainsKey(uuid)) 295 if (m_UserCache.ContainsKey(uuid))
278 { 296 {
279 returnstring[0] = m_UserCache[uuid].FirstName; 297 names[0] = m_UserCache[uuid].FirstName;
280 returnstring[1] = m_UserCache[uuid].LastName; 298 names[1] = m_UserCache[uuid].LastName;
281 return returnstring; 299
300 return true;
282 } 301 }
283 } 302 }
284 303
@@ -286,8 +305,8 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
286 305
287 if (account != null) 306 if (account != null)
288 { 307 {
289 returnstring[0] = account.FirstName; 308 names[0] = account.FirstName;
290 returnstring[1] = account.LastName; 309 names[1] = account.LastName;
291 310
292 UserData user = new UserData(); 311 UserData user = new UserData();
293 user.FirstName = account.FirstName; 312 user.FirstName = account.FirstName;
@@ -295,14 +314,16 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
295 314
296 lock (m_UserCache) 315 lock (m_UserCache)
297 m_UserCache[uuid] = user; 316 m_UserCache[uuid] = user;
317
318 return true;
298 } 319 }
299 else 320 else
300 { 321 {
301 returnstring[0] = "Unknown"; 322 names[0] = "Unknown";
302 returnstring[1] = "User"; 323 names[1] = "UserUMMTGUN2";
303 }
304 324
305 return returnstring; 325 return false;
326 }
306 } 327 }
307 328
308 #region IUserManagement 329 #region IUserManagement
@@ -338,15 +359,17 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
338 359
339 public string GetUserName(UUID uuid) 360 public string GetUserName(UUID uuid)
340 { 361 {
341 string[] names = GetUserNames(uuid); 362 string[] names;
363 TryGetUserNames(uuid, out names);
364
342 if (names.Length == 2) 365 if (names.Length == 2)
343 { 366 {
344 string firstname = names[0]; 367 string firstname = names[0];
345 string lastname = names[1]; 368 string lastname = names[1];
346 369
347 return firstname + " " + lastname; 370 return firstname + " " + lastname;
348
349 } 371 }
372
350 return "(hippos)"; 373 return "(hippos)";
351 } 374 }
352 375
@@ -462,12 +485,13 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
462 //ignore updates without creator data 485 //ignore updates without creator data
463 return; 486 return;
464 } 487 }
488
465 //try update unknown users 489 //try update unknown users
466 //and creator's home URL's 490 //and creator's home URL's
467 if ((oldUser.FirstName == "Unknown" && !creatorData.Contains ("Unknown")) || (oldUser.HomeURL != null && !creatorData.StartsWith (oldUser.HomeURL))) 491 if ((oldUser.FirstName == "Unknown" && !creatorData.Contains ("Unknown")) || (oldUser.HomeURL != null && !creatorData.StartsWith (oldUser.HomeURL)))
468 { 492 {
469 m_UserCache.Remove (id); 493 m_UserCache.Remove (id);
470// m_log.DebugFormat("[USER MANAGEMENT MODULE]: Re-adding user with id {0}, creatorData [{1}] and old HomeURL {2}", id, creatorData,oldUser.HomeURL); 494 m_log.DebugFormat("[USER MANAGEMENT MODULE]: Re-adding user with id {0}, creatorData [{1}] and old HomeURL {2}", id, creatorData, oldUser.HomeURL);
471 } 495 }
472 else 496 else
473 { 497 {
@@ -512,7 +536,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
512 else 536 else
513 { 537 {
514 user.FirstName = "Unknown"; 538 user.FirstName = "Unknown";
515 user.LastName = "User"; 539 user.LastName = "UserUMMAU";
516 } 540 }
517 541
518 AddUserInternal (user); 542 AddUserInternal (user);
@@ -544,6 +568,13 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
544 protected void RegisterConsoleCmds() 568 protected void RegisterConsoleCmds()
545 { 569 {
546 MainConsole.Instance.Commands.AddCommand("Users", true, 570 MainConsole.Instance.Commands.AddCommand("Users", true,
571 "show name",
572 "show name <uuid>",
573 "Show the bindings between a single user UUID and a user name",
574 String.Empty,
575 HandleShowUser);
576
577 MainConsole.Instance.Commands.AddCommand("Users", true,
547 "show names", 578 "show names",
548 "show names", 579 "show names",
549 "Show the bindings between user UUIDs and user names", 580 "Show the bindings between user UUIDs and user names",
@@ -551,26 +582,54 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
551 HandleShowUsers); 582 HandleShowUsers);
552 } 583 }
553 584
554 private void HandleShowUsers(string module, string[] cmd) 585 private void HandleShowUser(string module, string[] cmd)
555 { 586 {
587 if (cmd.Length < 3)
588 {
589 MainConsole.Instance.OutputFormat("Usage: show name <uuid>");
590 return;
591 }
592
593 UUID userId;
594 if (!ConsoleUtil.TryParseConsoleUuid(MainConsole.Instance, cmd[2], out userId))
595 return;
596
597 string[] names;
598
599 UserData ud;
600
556 lock (m_UserCache) 601 lock (m_UserCache)
557 { 602 {
558 if (m_UserCache.Count == 0) 603 if (!m_UserCache.TryGetValue(userId, out ud))
559 { 604 {
560 MainConsole.Instance.Output("No users found"); 605 MainConsole.Instance.OutputFormat("No name known for user with id {0}", userId);
561 return; 606 return;
562 } 607 }
563 608 }
564 MainConsole.Instance.Output("UUID User Name"); 609
565 MainConsole.Instance.Output("-----------------------------------------------------------------------------"); 610 ConsoleDisplayTable cdt = new ConsoleDisplayTable();
611 cdt.AddColumn("UUID", 36);
612 cdt.AddColumn("Name", 30);
613 cdt.AddColumn("HomeURL", 40);
614 cdt.AddRow(userId, string.Format("{0} {1}", ud.FirstName, ud.LastName), ud.HomeURL);
615
616 MainConsole.Instance.Output(cdt.ToString());
617 }
618
619 private void HandleShowUsers(string module, string[] cmd)
620 {
621 ConsoleDisplayTable cdt = new ConsoleDisplayTable();
622 cdt.AddColumn("UUID", 36);
623 cdt.AddColumn("Name", 30);
624 cdt.AddColumn("HomeURL", 40);
625
626 lock (m_UserCache)
627 {
566 foreach (KeyValuePair<UUID, UserData> kvp in m_UserCache) 628 foreach (KeyValuePair<UUID, UserData> kvp in m_UserCache)
567 { 629 cdt.AddRow(kvp.Key, string.Format("{0} {1}", kvp.Value.FirstName, kvp.Value.LastName), kvp.Value.HomeURL);
568 MainConsole.Instance.Output(String.Format("{0} {1} {2} ({3})",
569 kvp.Key, kvp.Value.FirstName, kvp.Value.LastName, kvp.Value.HomeURL));
570 }
571
572 return;
573 } 630 }
631
632 MainConsole.Instance.Output(cdt.ToString());
574 } 633 }
575 } 634 }
576} \ No newline at end of file 635} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs
index 2b13a8b..6eb25ef 100644
--- a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs
+++ b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs
@@ -412,7 +412,6 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
412 //public bool HttpVerboseThrottle = true; // not implemented 412 //public bool HttpVerboseThrottle = true; // not implemented
413 public List<string> HttpCustomHeaders = null; 413 public List<string> HttpCustomHeaders = null;
414 public bool HttpPragmaNoCache = true; 414 public bool HttpPragmaNoCache = true;
415 private Thread httpThread;
416 415
417 // Request info 416 // Request info
418 private UUID _itemID; 417 private UUID _itemID;
@@ -622,7 +621,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
622 { 621 {
623 if (!WorkItem.Cancel()) 622 if (!WorkItem.Cancel())
624 { 623 {
625 WorkItem.Abort(); 624 WorkItem.Cancel(true);
626 } 625 }
627 } 626 }
628 catch (Exception) 627 catch (Exception)
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/UserProfiles/LocalUserProfilesServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/UserProfiles/LocalUserProfilesServiceConnector.cs
new file mode 100644
index 0000000..323535a
--- /dev/null
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/UserProfiles/LocalUserProfilesServiceConnector.cs
@@ -0,0 +1,226 @@
1
2/*
3 * Copyright (c) Contributors, http://opensimulator.org/
4 * See CONTRIBUTORS.TXT for a full list of copyright holders.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the OpenSimulator Project nor the
14 * names of its contributors may be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29using log4net;
30using Mono.Addins;
31using Nini.Config;
32using System;
33using System.Collections.Generic;
34using System.Reflection;
35using OpenSim.Framework;
36using OpenSim.Framework.Console;
37using OpenSim.Server.Base;
38using OpenSim.Server.Handlers;
39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Framework.Servers.HttpServer;
41using OpenSim.Framework.Servers;
42using OpenSim.Region.Framework.Scenes;
43using OpenSim.Services.Interfaces;
44using GridRegion = OpenSim.Services.Interfaces.GridRegion;
45using OpenMetaverse;
46
47namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Profile
48{
49 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "LocalUserProfilesServicesConnector")]
50 public class LocalUserProfilesServicesConnector : ISharedRegionModule
51 {
52 private static readonly ILog m_log =
53 LogManager.GetLogger(
54 MethodBase.GetCurrentMethod().DeclaringType);
55
56 private Dictionary<UUID, Scene> regions = new Dictionary<UUID, Scene>();
57
58 public IUserProfilesService ServiceModule
59 {
60 get; private set;
61 }
62
63 public bool Enabled
64 {
65 get; private set;
66 }
67
68 public string Name
69 {
70 get
71 {
72 return "LocalUserProfilesServicesConnector";
73 }
74 }
75
76 public string ConfigName
77 {
78 get; private set;
79 }
80
81 public Type ReplaceableInterface
82 {
83 get { return null; }
84 }
85
86 public LocalUserProfilesServicesConnector()
87 {
88 m_log.Debug("[LOCAL USERPROFILES SERVICE CONNECTOR]: LocalUserProfileServicesConnector no params");
89 }
90
91 public LocalUserProfilesServicesConnector(IConfigSource source)
92 {
93 m_log.Debug("[LOCAL USERPROFILES SERVICE CONNECTOR]: LocalUserProfileServicesConnector instantiated directly.");
94 InitialiseService(source);
95 }
96
97 public void InitialiseService(IConfigSource source)
98 {
99 ConfigName = "UserProfilesService";
100
101 // Instantiate the request handler
102 IHttpServer Server = MainServer.Instance;
103
104 IConfig config = source.Configs[ConfigName];
105 if (config == null)
106 {
107 m_log.Error("[LOCAL USERPROFILES SERVICE CONNECTOR]: UserProfilesService missing from OpenSim.ini");
108 return;
109 }
110
111 if(!config.GetBoolean("Enabled",false))
112 {
113 Enabled = false;
114 return;
115 }
116
117 Enabled = true;
118
119 string serviceDll = config.GetString("LocalServiceModule",
120 String.Empty);
121
122 if (serviceDll == String.Empty)
123 {
124 m_log.Error("[LOCAL USERPROFILES SERVICE CONNECTOR]: No LocalServiceModule named in section UserProfilesService");
125 return;
126 }
127
128 Object[] args = new Object[] { source, ConfigName };
129 ServiceModule =
130 ServerUtils.LoadPlugin<IUserProfilesService>(serviceDll,
131 args);
132
133 if (ServiceModule == null)
134 {
135 m_log.Error("[LOCAL USERPROFILES SERVICE CONNECTOR]: Can't load user profiles service");
136 return;
137 }
138
139 Enabled = true;
140
141 JsonRpcProfileHandlers handler = new JsonRpcProfileHandlers(ServiceModule);
142
143 Server.AddJsonRPCHandler("avatarclassifiedsrequest", handler.AvatarClassifiedsRequest);
144 Server.AddJsonRPCHandler("classified_update", handler.ClassifiedUpdate);
145 Server.AddJsonRPCHandler("classifieds_info_query", handler.ClassifiedInfoRequest);
146 Server.AddJsonRPCHandler("classified_delete", handler.ClassifiedDelete);
147 Server.AddJsonRPCHandler("avatarpicksrequest", handler.AvatarPicksRequest);
148 Server.AddJsonRPCHandler("pickinforequest", handler.PickInfoRequest);
149 Server.AddJsonRPCHandler("picks_update", handler.PicksUpdate);
150 Server.AddJsonRPCHandler("picks_delete", handler.PicksDelete);
151 Server.AddJsonRPCHandler("avatarnotesrequest", handler.AvatarNotesRequest);
152 Server.AddJsonRPCHandler("avatar_notes_update", handler.NotesUpdate);
153 Server.AddJsonRPCHandler("avatar_properties_request", handler.AvatarPropertiesRequest);
154 Server.AddJsonRPCHandler("avatar_properties_update", handler.AvatarPropertiesUpdate);
155 Server.AddJsonRPCHandler("avatar_interests_update", handler.AvatarInterestsUpdate);
156 Server.AddJsonRPCHandler("image_assets_request", handler.AvatarImageAssetsRequest);
157 Server.AddJsonRPCHandler("user_data_request", handler.RequestUserAppData);
158 Server.AddJsonRPCHandler("user_data_update", handler.UpdateUserAppData);
159
160 }
161
162 #region ISharedRegionModule implementation
163
164 void ISharedRegionModule.PostInitialise()
165 {
166 if(!Enabled)
167 return;
168 }
169
170 #endregion
171
172 #region IRegionModuleBase implementation
173
174 void IRegionModuleBase.Initialise(IConfigSource source)
175 {
176 IConfig moduleConfig = source.Configs["Modules"];
177 if (moduleConfig != null)
178 {
179 string name = moduleConfig.GetString("UserProfilesServices", "");
180 if (name == Name)
181 {
182 InitialiseService(source);
183 m_log.Info("[LOCAL USERPROFILES SERVICE CONNECTOR]: Local user profiles connector enabled");
184 }
185 }
186 }
187
188 void IRegionModuleBase.Close()
189 {
190 return;
191 }
192
193 void IRegionModuleBase.AddRegion(Scene scene)
194 {
195 if (!Enabled)
196 return;
197
198 lock (regions)
199 {
200 if (regions.ContainsKey(scene.RegionInfo.RegionID))
201 m_log.ErrorFormat("[LOCAL USERPROFILES SERVICE CONNECTOR]: simulator seems to have more than one region with the same UUID. Please correct this!");
202 else
203 regions.Add(scene.RegionInfo.RegionID, scene);
204 }
205 }
206
207 void IRegionModuleBase.RemoveRegion(Scene scene)
208 {
209 if (!Enabled)
210 return;
211
212 lock (regions)
213 {
214 if (regions.ContainsKey(scene.RegionInfo.RegionID))
215 regions.Remove(scene.RegionInfo.RegionID);
216 }
217 }
218
219 void IRegionModuleBase.RegionLoaded(Scene scene)
220 {
221 if (!Enabled)
222 return;
223 }
224 #endregion
225 }
226} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs
index c0c2ca7..3849a3f 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs
@@ -56,6 +56,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
56 56
57 public LocalGridServicesConnector() 57 public LocalGridServicesConnector()
58 { 58 {
59 m_log.Debug("[LOCAL GRID SERVICE CONNECTOR]: LocalGridServicesConnector no parms.");
59 } 60 }
60 61
61 public LocalGridServicesConnector(IConfigSource source) 62 public LocalGridServicesConnector(IConfigSource source)
@@ -142,10 +143,13 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
142 143
143 scene.RegisterModuleInterface<IGridService>(this); 144 scene.RegisterModuleInterface<IGridService>(this);
144 145
145 if (m_LocalCache.ContainsKey(scene.RegionInfo.RegionID)) 146 lock (m_LocalCache)
146 m_log.ErrorFormat("[LOCAL GRID SERVICE CONNECTOR]: simulator seems to have more than one region with the same UUID. Please correct this!"); 147 {
147 else 148 if (m_LocalCache.ContainsKey(scene.RegionInfo.RegionID))
148 m_LocalCache.Add(scene.RegionInfo.RegionID, new RegionCache(scene)); 149 m_log.ErrorFormat("[LOCAL GRID SERVICE CONNECTOR]: simulator seems to have more than one region with the same UUID. Please correct this!");
150 else
151 m_LocalCache.Add(scene.RegionInfo.RegionID, new RegionCache(scene));
152 }
149 } 153 }
150 154
151 public void RemoveRegion(Scene scene) 155 public void RemoveRegion(Scene scene)
@@ -153,8 +157,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
153 if (!m_Enabled) 157 if (!m_Enabled)
154 return; 158 return;
155 159
156 m_LocalCache[scene.RegionInfo.RegionID].Clear(); 160 lock (m_LocalCache)
157 m_LocalCache.Remove(scene.RegionInfo.RegionID); 161 {
162 m_LocalCache[scene.RegionInfo.RegionID].Clear();
163 m_LocalCache.Remove(scene.RegionInfo.RegionID);
164 }
158 } 165 }
159 166
160 public void RegionLoaded(Scene scene) 167 public void RegionLoaded(Scene scene)
@@ -191,12 +198,16 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
191 198
192 // First see if it's a neighbour, even if it isn't on this sim. 199 // First see if it's a neighbour, even if it isn't on this sim.
193 // Neighbour data is cached in memory, so this is fast 200 // Neighbour data is cached in memory, so this is fast
194 foreach (RegionCache rcache in m_LocalCache.Values) 201
202 lock (m_LocalCache)
195 { 203 {
196 region = rcache.GetRegionByPosition(x, y); 204 foreach (RegionCache rcache in m_LocalCache.Values)
197 if (region != null)
198 { 205 {
199 return region; 206 region = rcache.GetRegionByPosition(x, y);
207 if (region != null)
208 {
209 return region;
210 }
200 } 211 }
201 } 212 }
202 213
@@ -245,12 +256,15 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
245 { 256 {
246 System.Text.StringBuilder caps = new System.Text.StringBuilder(); 257 System.Text.StringBuilder caps = new System.Text.StringBuilder();
247 258
248 foreach (KeyValuePair<UUID, RegionCache> kvp in m_LocalCache) 259 lock (m_LocalCache)
249 { 260 {
250 caps.AppendFormat("*** Neighbours of {0} ({1}) ***\n", kvp.Value.RegionName, kvp.Key); 261 foreach (KeyValuePair<UUID, RegionCache> kvp in m_LocalCache)
251 List<GridRegion> regions = kvp.Value.GetNeighbours(); 262 {
252 foreach (GridRegion r in regions) 263 caps.AppendFormat("*** Neighbours of {0} ({1}) ***\n", kvp.Value.RegionName, kvp.Key);
253 caps.AppendFormat(" {0} @ {1}-{2}\n", r.RegionName, r.RegionLocX / Constants.RegionSize, r.RegionLocY / Constants.RegionSize); 264 List<GridRegion> regions = kvp.Value.GetNeighbours();
265 foreach (GridRegion r in regions)
266 caps.AppendFormat(" {0} @ {1}-{2}\n", r.RegionName, r.RegionLocX / Constants.RegionSize, r.RegionLocY / Constants.RegionSize);
267 }
254 } 268 }
255 269
256 MainConsole.Instance.Output(caps.ToString()); 270 MainConsole.Instance.Output(caps.ToString());
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs
index 8b8bb37..e4aa7bc 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs
@@ -322,7 +322,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
322// "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate", 322// "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate",
323// s.RegionInfo.RegionName, destination.RegionHandle); 323// s.RegionInfo.RegionName, destination.RegionHandle);
324 324
325 Util.FireAndForget(delegate { m_scenes[destination.RegionID].IncomingCloseAgent(id, false); }); 325 m_scenes[destination.RegionID].IncomingCloseAgent(id, false);
326 return true; 326 return true;
327 } 327 }
328 //m_log.Debug("[LOCAL COMMS]: region not found in SendCloseAgent"); 328 //m_log.Debug("[LOCAL COMMS]: region not found in SendCloseAgent");
diff --git a/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs b/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs
new file mode 100644
index 0000000..73e706c
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs
@@ -0,0 +1,218 @@
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;
31
32using OpenSim.Services.Interfaces;
33using GridRegion = OpenSim.Services.Interfaces.GridRegion;
34using OpenSim.Server.Base;
35using OpenSim.Framework.Servers.HttpServer;
36using OpenSim.Framework;
37using OpenSim.Region.Framework.Scenes;
38
39using OpenMetaverse;
40using log4net;
41
42namespace OpenSim.Region.CoreModules.World.Estate
43{
44 public class EstateConnector
45 {
46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47
48 protected XEstateModule m_EstateModule;
49
50 public EstateConnector(XEstateModule module)
51 {
52 m_EstateModule = module;
53 }
54
55 public void SendTeleportHomeOneUser(uint EstateID, UUID PreyID)
56 {
57 Dictionary<string, object> sendData = new Dictionary<string, object>();
58 sendData["METHOD"] = "teleport_home_one_user";
59
60 sendData["EstateID"] = EstateID.ToString();
61 sendData["PreyID"] = PreyID.ToString();
62
63 SendToEstate(EstateID, sendData);
64 }
65
66 public void SendTeleportHomeAllUsers(uint EstateID)
67 {
68 Dictionary<string, object> sendData = new Dictionary<string, object>();
69 sendData["METHOD"] = "teleport_home_all_users";
70
71 sendData["EstateID"] = EstateID.ToString();
72
73 SendToEstate(EstateID, sendData);
74 }
75
76 public bool SendUpdateCovenant(uint EstateID, UUID CovenantID)
77 {
78 Dictionary<string, object> sendData = new Dictionary<string, object>();
79 sendData["METHOD"] = "update_covenant";
80
81 sendData["CovenantID"] = CovenantID.ToString();
82 sendData["EstateID"] = EstateID.ToString();
83
84 // Handle local regions locally
85 //
86 foreach (Scene s in m_EstateModule.Scenes)
87 {
88 if (s.RegionInfo.EstateSettings.EstateID == EstateID)
89 s.RegionInfo.RegionSettings.Covenant = CovenantID;
90// s.ReloadEstateData();
91 }
92
93 SendToEstate(EstateID, sendData);
94
95 return true;
96 }
97
98 public bool SendUpdateEstate(uint EstateID)
99 {
100 Dictionary<string, object> sendData = new Dictionary<string, object>();
101 sendData["METHOD"] = "update_estate";
102
103 sendData["EstateID"] = EstateID.ToString();
104
105 // Handle local regions locally
106 //
107 foreach (Scene s in m_EstateModule.Scenes)
108 {
109 if (s.RegionInfo.EstateSettings.EstateID == EstateID)
110 s.ReloadEstateData();
111 }
112
113 SendToEstate(EstateID, sendData);
114
115 return true;
116 }
117
118 public void SendEstateMessage(uint EstateID, UUID FromID, string FromName, string Message)
119 {
120 Dictionary<string, object> sendData = new Dictionary<string, object>();
121 sendData["METHOD"] = "estate_message";
122
123 sendData["EstateID"] = EstateID.ToString();
124 sendData["FromID"] = FromID.ToString();
125 sendData["FromName"] = FromName;
126 sendData["Message"] = Message;
127
128 SendToEstate(EstateID, sendData);
129 }
130
131 private void SendToEstate(uint EstateID, Dictionary<string, object> sendData)
132 {
133 List<UUID> regions = m_EstateModule.Scenes[0].GetEstateRegions((int)EstateID);
134
135 UUID ScopeID = UUID.Zero;
136
137 // Handle local regions locally
138 //
139 lock (m_EstateModule.Scenes)
140 {
141 foreach (Scene s in m_EstateModule.Scenes)
142 {
143 if (regions.Contains(s.RegionInfo.RegionID))
144 {
145 // All regions in one estate are in the same scope.
146 // Use that scope.
147 //
148 ScopeID = s.RegionInfo.ScopeID;
149 regions.Remove(s.RegionInfo.RegionID);
150 }
151 }
152 }
153
154 // Our own region should always be in the above list.
155 // In a standalone this would not be true. But then,
156 // Scope ID is not relevat there. Use first scope.
157 //
158 if (ScopeID == UUID.Zero)
159 ScopeID = m_EstateModule.Scenes[0].RegionInfo.ScopeID;
160
161 // Don't send to the same instance twice
162 //
163 List<string> done = new List<string>();
164
165 // Send to remote regions
166 //
167 foreach (UUID regionID in regions)
168 {
169 GridRegion region = m_EstateModule.Scenes[0].GridService.GetRegionByUUID(ScopeID, regionID);
170 if (region != null)
171 {
172 string url = "http://" + region.ExternalHostName + ":" + region.HttpPort;
173 if (done.Contains(url))
174 continue;
175
176 Call(region, sendData);
177 done.Add(url);
178 }
179 }
180 }
181
182 private bool Call(GridRegion region, Dictionary<string, object> sendData)
183 {
184 string reqString = ServerUtils.BuildQueryString(sendData);
185 // m_log.DebugFormat("[XESTATE CONNECTOR]: queryString = {0}", reqString);
186 try
187 {
188 string url = "http://" + region.ExternalHostName + ":" + region.HttpPort;
189 string reply = SynchronousRestFormsRequester.MakeRequest("POST",
190 url + "/estate",
191 reqString);
192 if (reply != string.Empty)
193 {
194 Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply);
195
196 if (replyData.ContainsKey("RESULT"))
197 {
198 if (replyData["RESULT"].ToString().ToLower() == "true")
199 return true;
200 else
201 return false;
202 }
203 else
204 m_log.DebugFormat("[XESTATE CONNECTOR]: reply data does not contain result field");
205
206 }
207 else
208 m_log.DebugFormat("[XESTATE CONNECTOR]: received empty reply");
209 }
210 catch (Exception e)
211 {
212 m_log.DebugFormat("[XESTATE CONNECTOR]: Exception when contacting remote sim: {0}", e.Message);
213 }
214
215 return false;
216 }
217 }
218}
diff --git a/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs b/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs
new file mode 100644
index 0000000..f54ab2c
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs
@@ -0,0 +1,256 @@
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.Collections.Generic;
31using System.Reflection;
32using log4net;
33using Nini.Config;
34using Nwc.XmlRpc;
35using OpenMetaverse;
36using OpenSim.Framework;
37using OpenSim.Framework.Communications;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Services.Interfaces;
41using OpenSim.Server.Base;
42using OpenSim.Framework.Servers;
43using OpenSim.Framework.Servers.HttpServer;
44using Mono.Addins;
45
46namespace OpenSim.Region.CoreModules.World.Estate
47{
48 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "XEstate")]
49 public class XEstateModule : ISharedRegionModule
50 {
51 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
52
53 protected List<Scene> m_Scenes = new List<Scene>();
54 protected bool m_InInfoUpdate = false;
55
56 public bool InInfoUpdate
57 {
58 get { return m_InInfoUpdate; }
59 set { m_InInfoUpdate = value; }
60 }
61
62 public List<Scene> Scenes
63 {
64 get { return m_Scenes; }
65 }
66
67 protected EstateConnector m_EstateConnector;
68
69 public void Initialise(IConfigSource config)
70 {
71 int port = 0;
72
73 IConfig estateConfig = config.Configs["Estate"];
74 if (estateConfig != null)
75 {
76 port = estateConfig.GetInt("Port", 0);
77 }
78
79 m_EstateConnector = new EstateConnector(this);
80
81 // Instantiate the request handler
82 IHttpServer server = MainServer.GetHttpServer((uint)port);
83 server.AddStreamHandler(new EstateRequestHandler(this));
84 }
85
86 public void PostInitialise()
87 {
88 }
89
90 public void Close()
91 {
92 }
93
94 public void AddRegion(Scene scene)
95 {
96 lock (m_Scenes)
97 m_Scenes.Add(scene);
98
99 scene.EventManager.OnNewClient += OnNewClient;
100 }
101
102 public void RegionLoaded(Scene scene)
103 {
104 IEstateModule em = scene.RequestModuleInterface<IEstateModule>();
105
106 em.OnRegionInfoChange += OnRegionInfoChange;
107 em.OnEstateInfoChange += OnEstateInfoChange;
108 em.OnEstateMessage += OnEstateMessage;
109 }
110
111 public void RemoveRegion(Scene scene)
112 {
113 scene.EventManager.OnNewClient -= OnNewClient;
114
115 lock (m_Scenes)
116 m_Scenes.Remove(scene);
117 }
118
119 public string Name
120 {
121 get { return "EstateModule"; }
122 }
123
124 public Type ReplaceableInterface
125 {
126 get { return null; }
127 }
128
129 private Scene FindScene(UUID RegionID)
130 {
131 foreach (Scene s in Scenes)
132 {
133 if (s.RegionInfo.RegionID == RegionID)
134 return s;
135 }
136
137 return null;
138 }
139
140 private void OnRegionInfoChange(UUID RegionID)
141 {
142 Scene s = FindScene(RegionID);
143 if (s == null)
144 return;
145
146 if (!m_InInfoUpdate)
147 m_EstateConnector.SendUpdateCovenant(s.RegionInfo.EstateSettings.EstateID, s.RegionInfo.RegionSettings.Covenant);
148 }
149
150 private void OnEstateInfoChange(UUID RegionID)
151 {
152 Scene s = FindScene(RegionID);
153 if (s == null)
154 return;
155
156 if (!m_InInfoUpdate)
157 m_EstateConnector.SendUpdateEstate(s.RegionInfo.EstateSettings.EstateID);
158 }
159
160 private void OnEstateMessage(UUID RegionID, UUID FromID, string FromName, string Message)
161 {
162 Scene senderScenes = FindScene(RegionID);
163 if (senderScenes == null)
164 return;
165
166 uint estateID = senderScenes.RegionInfo.EstateSettings.EstateID;
167
168 foreach (Scene s in Scenes)
169 {
170 if (s.RegionInfo.EstateSettings.EstateID == estateID)
171 {
172 IDialogModule dm = s.RequestModuleInterface<IDialogModule>();
173
174 if (dm != null)
175 {
176 dm.SendNotificationToUsersInRegion(FromID, FromName,
177 Message);
178 }
179 }
180 }
181 if (!m_InInfoUpdate)
182 m_EstateConnector.SendEstateMessage(estateID, FromID, FromName, Message);
183 }
184
185 private void OnNewClient(IClientAPI client)
186 {
187 client.OnEstateTeleportOneUserHomeRequest += OnEstateTeleportOneUserHomeRequest;
188 client.OnEstateTeleportAllUsersHomeRequest += OnEstateTeleportAllUsersHomeRequest;
189
190 }
191
192 private void OnEstateTeleportOneUserHomeRequest(IClientAPI client, UUID invoice, UUID senderID, UUID prey)
193 {
194 if (prey == UUID.Zero)
195 return;
196
197 if (!(client.Scene is Scene))
198 return;
199
200 Scene scene = (Scene)client.Scene;
201
202 uint estateID = scene.RegionInfo.EstateSettings.EstateID;
203
204 if (!scene.Permissions.CanIssueEstateCommand(client.AgentId, false))
205 return;
206
207 foreach (Scene s in Scenes)
208 {
209 if (s == scene)
210 continue; // Already handles by estate module
211 if (s.RegionInfo.EstateSettings.EstateID != estateID)
212 continue;
213
214 ScenePresence p = scene.GetScenePresence(prey);
215 if (p != null && !p.IsChildAgent)
216 {
217 p.ControllingClient.SendTeleportStart(16);
218 scene.TeleportClientHome(prey, p.ControllingClient);
219 }
220 }
221
222 m_EstateConnector.SendTeleportHomeOneUser(estateID, prey);
223 }
224
225 private void OnEstateTeleportAllUsersHomeRequest(IClientAPI client, UUID invoice, UUID senderID)
226 {
227 if (!(client.Scene is Scene))
228 return;
229
230 Scene scene = (Scene)client.Scene;
231
232 uint estateID = scene.RegionInfo.EstateSettings.EstateID;
233
234 if (!scene.Permissions.CanIssueEstateCommand(client.AgentId, false))
235 return;
236
237 foreach (Scene s in Scenes)
238 {
239 if (s == scene)
240 continue; // Already handles by estate module
241 if (s.RegionInfo.EstateSettings.EstateID != estateID)
242 continue;
243
244 scene.ForEachScenePresence(delegate(ScenePresence p) {
245 if (p != null && !p.IsChildAgent)
246 {
247 p.ControllingClient.SendTeleportStart(16);
248 scene.TeleportClientHome(p.ControllingClient.AgentId, p.ControllingClient);
249 }
250 });
251 }
252
253 m_EstateConnector.SendTeleportHomeAllUsers(estateID);
254 }
255 }
256}
diff --git a/OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs b/OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs
new file mode 100644
index 0000000..eb74cda
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs
@@ -0,0 +1,298 @@
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.Xml;
33
34using OpenSim.Framework;
35using OpenSim.Server.Base;
36using OpenSim.Framework.Servers.HttpServer;
37using OpenSim.Region.Framework.Scenes;
38using OpenSim.Region.Framework.Interfaces;
39
40using OpenMetaverse;
41using log4net;
42
43namespace OpenSim.Region.CoreModules.World.Estate
44{
45 public class EstateRequestHandler : BaseStreamHandler
46 {
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48
49 protected XEstateModule m_EstateModule;
50 protected Object m_RequestLock = new Object();
51
52 public EstateRequestHandler(XEstateModule fmodule)
53 : base("POST", "/estate")
54 {
55 m_EstateModule = fmodule;
56 }
57
58 public override byte[] Handle(string path, Stream requestData,
59 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
60 {
61 StreamReader sr = new StreamReader(requestData);
62 string body = sr.ReadToEnd();
63 sr.Close();
64 body = body.Trim();
65
66 m_log.DebugFormat("[XESTATE HANDLER]: query String: {0}", body);
67
68 try
69 {
70 lock (m_RequestLock)
71 {
72 Dictionary<string, object> request =
73 ServerUtils.ParseQueryString(body);
74
75 if (!request.ContainsKey("METHOD"))
76 return FailureResult();
77
78 string method = request["METHOD"].ToString();
79 request.Remove("METHOD");
80
81 try
82 {
83 m_EstateModule.InInfoUpdate = false;
84
85 switch (method)
86 {
87 case "update_covenant":
88 return UpdateCovenant(request);
89 case "update_estate":
90 return UpdateEstate(request);
91 case "estate_message":
92 return EstateMessage(request);
93 case "teleport_home_one_user":
94 return TeleportHomeOneUser(request);
95 case "teleport_home_all_users":
96 return TeleportHomeAllUsers(request);
97 }
98 }
99 finally
100 {
101 m_EstateModule.InInfoUpdate = false;
102 }
103 }
104 }
105 catch (Exception e)
106 {
107 m_log.Debug("[XESTATE]: Exception {0}" + e.ToString());
108 }
109
110 return FailureResult();
111 }
112
113 byte[] TeleportHomeAllUsers(Dictionary<string, object> request)
114 {
115 UUID PreyID = UUID.Zero;
116 int EstateID = 0;
117
118 if (!request.ContainsKey("EstateID"))
119 return FailureResult();
120
121 if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID))
122 return FailureResult();
123
124 foreach (Scene s in m_EstateModule.Scenes)
125 {
126 if (s.RegionInfo.EstateSettings.EstateID == EstateID)
127 {
128 s.ForEachScenePresence(delegate(ScenePresence p) {
129 if (p != null && !p.IsChildAgent)
130 {
131 p.ControllingClient.SendTeleportStart(16);
132 s.TeleportClientHome(p.ControllingClient.AgentId, p.ControllingClient);
133 }
134 });
135 }
136 }
137
138 return SuccessResult();
139 }
140
141 byte[] TeleportHomeOneUser(Dictionary<string, object> request)
142 {
143 UUID PreyID = UUID.Zero;
144 int EstateID = 0;
145
146 if (!request.ContainsKey("PreyID") ||
147 !request.ContainsKey("EstateID"))
148 {
149 return FailureResult();
150 }
151
152 if (!UUID.TryParse(request["PreyID"].ToString(), out PreyID))
153 return FailureResult();
154
155 if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID))
156 return FailureResult();
157
158 foreach (Scene s in m_EstateModule.Scenes)
159 {
160 if (s.RegionInfo.EstateSettings.EstateID == EstateID)
161 {
162 ScenePresence p = s.GetScenePresence(PreyID);
163 if (p != null && !p.IsChildAgent)
164 {
165 p.ControllingClient.SendTeleportStart(16);
166 s.TeleportClientHome(PreyID, p.ControllingClient);
167 }
168 }
169 }
170
171 return SuccessResult();
172 }
173
174 byte[] EstateMessage(Dictionary<string, object> request)
175 {
176 UUID FromID = UUID.Zero;
177 string FromName = String.Empty;
178 string Message = String.Empty;
179 int EstateID = 0;
180
181 if (!request.ContainsKey("FromID") ||
182 !request.ContainsKey("FromName") ||
183 !request.ContainsKey("Message") ||
184 !request.ContainsKey("EstateID"))
185 {
186 return FailureResult();
187 }
188
189 if (!UUID.TryParse(request["FromID"].ToString(), out FromID))
190 return FailureResult();
191
192 if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID))
193 return FailureResult();
194
195 FromName = request["FromName"].ToString();
196 Message = request["Message"].ToString();
197
198 foreach (Scene s in m_EstateModule.Scenes)
199 {
200 if (s.RegionInfo.EstateSettings.EstateID == EstateID)
201 {
202 IDialogModule dm = s.RequestModuleInterface<IDialogModule>();
203
204 if (dm != null)
205 {
206 dm.SendNotificationToUsersInRegion(FromID, FromName,
207 Message);
208 }
209 }
210 }
211
212 return SuccessResult();
213 }
214
215 byte[] UpdateCovenant(Dictionary<string, object> request)
216 {
217 UUID CovenantID = UUID.Zero;
218 int EstateID = 0;
219
220 if (!request.ContainsKey("CovenantID") || !request.ContainsKey("EstateID"))
221 return FailureResult();
222
223 if (!UUID.TryParse(request["CovenantID"].ToString(), out CovenantID))
224 return FailureResult();
225
226 if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID))
227 return FailureResult();
228
229 foreach (Scene s in m_EstateModule.Scenes)
230 {
231 if (s.RegionInfo.EstateSettings.EstateID == (uint)EstateID)
232 s.RegionInfo.RegionSettings.Covenant = CovenantID;
233 }
234
235 return SuccessResult();
236 }
237
238 byte[] UpdateEstate(Dictionary<string, object> request)
239 {
240 int EstateID = 0;
241
242 if (!request.ContainsKey("EstateID"))
243 return FailureResult();
244 if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID))
245 return FailureResult();
246
247 foreach (Scene s in m_EstateModule.Scenes)
248 {
249 if (s.RegionInfo.EstateSettings.EstateID == (uint)EstateID)
250 s.ReloadEstateData();
251 }
252 return SuccessResult();
253 }
254
255 private byte[] FailureResult()
256 {
257 return BoolResult(false);
258 }
259
260 private byte[] SuccessResult()
261 {
262 return BoolResult(true);
263 }
264
265 private byte[] BoolResult(bool value)
266 {
267 XmlDocument doc = new XmlDocument();
268
269 XmlNode xmlnode = doc.CreateNode(XmlNodeType.XmlDeclaration,
270 "", "");
271
272 doc.AppendChild(xmlnode);
273
274 XmlElement rootElement = doc.CreateElement("", "ServerResponse",
275 "");
276
277 doc.AppendChild(rootElement);
278
279 XmlElement result = doc.CreateElement("", "RESULT", "");
280 result.AppendChild(doc.CreateTextNode(value.ToString()));
281
282 rootElement.AppendChild(result);
283
284 return DocToBytes(doc);
285 }
286
287 private byte[] DocToBytes(XmlDocument doc)
288 {
289 MemoryStream ms = new MemoryStream();
290 XmlTextWriter xw = new XmlTextWriter(ms, null);
291 xw.Formatting = Formatting.Indented;
292 doc.WriteTo(xw);
293 xw.Flush();
294
295 return ms.ToArray();
296 }
297 }
298}
diff --git a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
index c307998..dbc9296 100644
--- a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
+++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
@@ -74,6 +74,7 @@ namespace OpenSim.Region.CoreModules.World.Land
74 74
75 protected IUserManagement m_userManager; 75 protected IUserManagement m_userManager;
76 protected IPrimCountModule m_primCountModule; 76 protected IPrimCountModule m_primCountModule;
77 protected IDialogModule m_Dialog;
77 78
78 // Minimum for parcels to work is 64m even if we don't actually use them. 79 // Minimum for parcels to work is 64m even if we don't actually use them.
79 #pragma warning disable 0429 80 #pragma warning disable 0429
@@ -161,6 +162,7 @@ namespace OpenSim.Region.CoreModules.World.Land
161 { 162 {
162 m_userManager = m_scene.RequestModuleInterface<IUserManagement>(); 163 m_userManager = m_scene.RequestModuleInterface<IUserManagement>();
163 m_primCountModule = m_scene.RequestModuleInterface<IPrimCountModule>(); 164 m_primCountModule = m_scene.RequestModuleInterface<IPrimCountModule>();
165 m_Dialog = m_scene.RequestModuleInterface<IDialogModule>();
164 } 166 }
165 167
166 public void RemoveRegion(Scene scene) 168 public void RemoveRegion(Scene scene)
@@ -213,6 +215,7 @@ namespace OpenSim.Region.CoreModules.World.Land
213 client.OnPreAgentUpdate += ClientOnPreAgentUpdate; 215 client.OnPreAgentUpdate += ClientOnPreAgentUpdate;
214 client.OnParcelEjectUser += ClientOnParcelEjectUser; 216 client.OnParcelEjectUser += ClientOnParcelEjectUser;
215 client.OnParcelFreezeUser += ClientOnParcelFreezeUser; 217 client.OnParcelFreezeUser += ClientOnParcelFreezeUser;
218 client.OnSetStartLocationRequest += ClientOnSetHome;
216 219
217 EntityBase presenceEntity; 220 EntityBase presenceEntity;
218 if (m_scene.Entities.TryGetValue(client.AgentId, out presenceEntity) && presenceEntity is ScenePresence) 221 if (m_scene.Entities.TryGetValue(client.AgentId, out presenceEntity) && presenceEntity is ScenePresence)
@@ -1896,7 +1899,53 @@ namespace OpenSim.Region.CoreModules.World.Land
1896 land.LandData.ParcelAccessList.Add(entry); 1899 land.LandData.ParcelAccessList.Add(entry);
1897 } 1900 }
1898 } 1901 }
1899 1902
1903 /// <summary>
1904 /// Sets the Home Point. The LoginService uses this to know where to put a user when they log-in
1905 /// </summary>
1906 /// <param name="remoteClient"></param>
1907 /// <param name="regionHandle"></param>
1908 /// <param name="position"></param>
1909 /// <param name="lookAt"></param>
1910 /// <param name="flags"></param>
1911 public virtual void ClientOnSetHome(IClientAPI remoteClient, ulong regionHandle, Vector3 position, Vector3 lookAt, uint flags)
1912 {
1913 // Let's find the parcel in question
1914 ILandObject land = landChannel.GetLandObject(position);
1915 if (land == null || m_scene.GridUserService == null)
1916 {
1917 m_Dialog.SendAlertToUser(remoteClient, "Set Home request failed.");
1918 return;
1919 }
1920
1921 // Gather some data
1922 ulong gpowers = remoteClient.GetGroupPowers(land.LandData.GroupID);
1923 SceneObjectGroup telehub = null;
1924 if (m_scene.RegionInfo.RegionSettings.TelehubObject != UUID.Zero)
1925 // Does the telehub exist in the scene?
1926 telehub = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject);
1927
1928 // Can the user set home here?
1929 if (// (a) gods and land managers can set home
1930 m_scene.Permissions.IsAdministrator(remoteClient.AgentId) ||
1931 m_scene.Permissions.IsGod(remoteClient.AgentId) ||
1932 // (b) land owners can set home
1933 remoteClient.AgentId == land.LandData.OwnerID ||
1934 // (c) members of the land-associated group in roles that can set home
1935 ((gpowers & (ulong)GroupPowers.AllowSetHome) == (ulong)GroupPowers.AllowSetHome) ||
1936 // (d) parcels with telehubs can be the home of anyone
1937 (telehub != null && land.ContainsPoint((int)telehub.AbsolutePosition.X, (int)telehub.AbsolutePosition.Y)))
1938 {
1939 if (m_scene.GridUserService.SetHome(remoteClient.AgentId.ToString(), land.RegionUUID, position, lookAt))
1940 // FUBAR ALERT: this needs to be "Home position set." so the viewer saves a home-screenshot.
1941 m_Dialog.SendAlertToUser(remoteClient, "Home position set.");
1942 else
1943 m_Dialog.SendAlertToUser(remoteClient, "Set Home request failed.");
1944 }
1945 else
1946 m_Dialog.SendAlertToUser(remoteClient, "You are not allowed to set your home location in this parcel.");
1947 }
1948
1900 protected void InstallInterfaces() 1949 protected void InstallInterfaces()
1901 { 1950 {
1902 Command clearCommand 1951 Command clearCommand
diff --git a/OpenSim/Region/CoreModules/World/Land/LandObject.cs b/OpenSim/Region/CoreModules/World/Land/LandObject.cs
index 07d00c0..31f8a3f 100644
--- a/OpenSim/Region/CoreModules/World/Land/LandObject.cs
+++ b/OpenSim/Region/CoreModules/World/Land/LandObject.cs
@@ -249,13 +249,6 @@ namespace OpenSim.Region.CoreModules.World.Land
249 if (estateModule != null) 249 if (estateModule != null)
250 regionFlags = estateModule.GetRegionFlags(); 250 regionFlags = estateModule.GetRegionFlags();
251 251
252 // In a perfect world, this would have worked.
253 //
254// if ((landData.Flags & (uint)ParcelFlags.AllowLandmark) != 0)
255// regionFlags |= (uint)RegionFlags.AllowLandmark;
256// if (landData.OwnerID == remote_client.AgentId)
257// regionFlags |= (uint)RegionFlags.AllowSetHome;
258
259 int seq_id; 252 int seq_id;
260 if (snap_selection && (sequence_id == 0)) 253 if (snap_selection && (sequence_id == 0))
261 { 254 {
diff --git a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
index 79dd4a0..f8e93e1 100644
--- a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
+++ b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
@@ -1453,6 +1453,8 @@ namespace OpenSim.Region.CoreModules.World.Permissions
1453 1453
1454 bool permission = false; 1454 bool permission = false;
1455 1455
1456// m_log.DebugFormat("[PERMISSIONS MODULE]: Checking rez object at {0} in {1}", objectPosition, m_scene.Name);
1457
1456 ILandObject land = m_scene.LandChannel.GetLandObject(objectPosition.X, objectPosition.Y); 1458 ILandObject land = m_scene.LandChannel.GetLandObject(objectPosition.X, objectPosition.Y);
1457 if (land == null) return false; 1459 if (land == null) return false;
1458 1460
diff --git a/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs b/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs
index 883045a..d093224 100644
--- a/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs
+++ b/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs
@@ -369,6 +369,15 @@ namespace OpenSim.Region.CoreModules.World.Sound
369 }); 369 });
370 } 370 }
371 371
372 public void SetSoundQueueing(UUID objectID, bool shouldQueue)
373 {
374 SceneObjectPart part;
375 if (!m_scene.TryGetSceneObjectPart(objectID, out part))
376 return;
377
378 part.SoundQueueing = shouldQueue;
379 }
380
372 #endregion 381 #endregion
373 } 382 }
374} 383}
diff --git a/OpenSim/Region/Framework/Interfaces/IEstateModule.cs b/OpenSim/Region/Framework/Interfaces/IEstateModule.cs
index 292efa4..d49b24e 100644
--- a/OpenSim/Region/Framework/Interfaces/IEstateModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/IEstateModule.cs
@@ -40,7 +40,7 @@ namespace OpenSim.Region.Framework.Interfaces
40 40
41 uint GetRegionFlags(); 41 uint GetRegionFlags();
42 bool IsManager(UUID avatarID); 42 bool IsManager(UUID avatarID);
43 43
44 /// <summary> 44 /// <summary>
45 /// Tell all clients about the current state of the region (terrain textures, water height, etc.). 45 /// Tell all clients about the current state of the region (terrain textures, water height, etc.).
46 /// </summary> 46 /// </summary>
diff --git a/OpenSim/Region/Framework/Interfaces/ISoundModule.cs b/OpenSim/Region/Framework/Interfaces/ISoundModule.cs
index 68af492..8372ddd 100644
--- a/OpenSim/Region/Framework/Interfaces/ISoundModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/ISoundModule.cs
@@ -104,7 +104,6 @@ namespace OpenSim.Region.Framework.Interfaces
104 /// <param name="sound">Sound asset ID</param> 104 /// <param name="sound">Sound asset ID</param>
105 /// <param name="volume">Sound volume</param> 105 /// <param name="volume">Sound volume</param>
106 /// <param name="triggered">Triggered or not.</param> 106 /// <param name="triggered">Triggered or not.</param>
107 /// <param name="flags"></param>
108 /// <param name="radius">Sound radius</param> 107 /// <param name="radius">Sound radius</param>
109 /// <param name="useMaster">Play using sound master</param> 108 /// <param name="useMaster">Play using sound master</param>
110 /// <param name="isMaster">Play as sound master</param> 109 /// <param name="isMaster">Play as sound master</param>
@@ -123,5 +122,12 @@ namespace OpenSim.Region.Framework.Interfaces
123 /// <param name="max">AABB top north-east corner</param> 122 /// <param name="max">AABB top north-east corner</param>
124 void TriggerSoundLimited(UUID objectID, UUID sound, double volume, 123 void TriggerSoundLimited(UUID objectID, UUID sound, double volume,
125 Vector3 min, Vector3 max); 124 Vector3 min, Vector3 max);
125
126 /// <summary>
127 /// Set whether sounds on the given prim should be queued.
128 /// </summary>
129 /// <param name='objectID'></param>
130 /// <param name='shouldQueue'></param>
131 void SetSoundQueueing(UUID objectID, bool shouldQueue);
126 } 132 }
127} \ No newline at end of file 133} \ No newline at end of file
diff --git a/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs b/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs
index 66edfed..5dee64d 100644
--- a/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs
+++ b/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs
@@ -28,8 +28,11 @@
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Reflection; 30using System.Reflection;
31using System.Text;
31using log4net; 32using log4net;
32using OpenMetaverse; 33using OpenMetaverse;
34using OpenMetaverse.StructuredData;
35
33using OpenSim.Framework; 36using OpenSim.Framework;
34 37
35using Animation = OpenSim.Framework.Animation; 38using Animation = OpenSim.Framework.Animation;
@@ -60,6 +63,12 @@ namespace OpenSim.Region.Framework.Scenes.Animation
60 ResetDefaultAnimation(); 63 ResetDefaultAnimation();
61 } 64 }
62 65
66 public AnimationSet(OSDArray pArray)
67 {
68 ResetDefaultAnimation();
69 FromOSDArray(pArray);
70 }
71
63 public bool HasAnimation(UUID animID) 72 public bool HasAnimation(UUID animID)
64 { 73 {
65 if (m_defaultAnimation.AnimID == animID) 74 if (m_defaultAnimation.AnimID == animID)
@@ -218,5 +227,106 @@ namespace OpenSim.Region.Framework.Scenes.Animation
218 foreach (OpenSim.Framework.Animation anim in theArray) 227 foreach (OpenSim.Framework.Animation anim in theArray)
219 m_animations.Add(anim); 228 m_animations.Add(anim);
220 } 229 }
230
231 // Create representation of this AnimationSet as an OSDArray.
232 // First two entries in the array are the default and implicitDefault animations
233 // followed by the other animations.
234 public OSDArray ToOSDArray()
235 {
236 OSDArray ret = new OSDArray();
237 ret.Add(DefaultAnimation.PackUpdateMessage());
238 ret.Add(ImplicitDefaultAnimation.PackUpdateMessage());
239
240 foreach (OpenSim.Framework.Animation anim in m_animations)
241 ret.Add(anim.PackUpdateMessage());
242
243 return ret;
244 }
245
246 public void FromOSDArray(OSDArray pArray)
247 {
248 this.Clear();
249
250 if (pArray.Count >= 1)
251 {
252 m_defaultAnimation = new OpenSim.Framework.Animation((OSDMap)pArray[0]);
253 }
254 if (pArray.Count >= 2)
255 {
256 m_implicitDefaultAnimation = new OpenSim.Framework.Animation((OSDMap)pArray[1]);
257 }
258 for (int ii = 2; ii < pArray.Count; ii++)
259 {
260 m_animations.Add(new OpenSim.Framework.Animation((OSDMap)pArray[ii]));
261 }
262 }
263
264 // Compare two AnimationSets and return 'true' if the default animations are the same
265 // and all of the animations in the list are equal.
266 public override bool Equals(object obj)
267 {
268 AnimationSet other = obj as AnimationSet;
269 if (other != null)
270 {
271 if (this.DefaultAnimation.Equals(other.DefaultAnimation)
272 && this.ImplicitDefaultAnimation.Equals(other.ImplicitDefaultAnimation))
273 {
274 // The defaults are the same. Is the list of animations the same?
275 OpenSim.Framework.Animation[] thisAnims = this.ToArray();
276 OpenSim.Framework.Animation[] otherAnims = other.ToArray();
277 if (thisAnims.Length == 0 && otherAnims.Length == 0)
278 return true; // the common case
279 if (thisAnims.Length == otherAnims.Length)
280 {
281 // Do this the hard way but since the list is usually short this won't take long.
282 foreach (OpenSim.Framework.Animation thisAnim in thisAnims)
283 {
284 bool found = false;
285 foreach (OpenSim.Framework.Animation otherAnim in otherAnims)
286 {
287 if (thisAnim.Equals(otherAnim))
288 {
289 found = true;
290 break;
291 }
292 }
293 if (!found)
294 {
295 // If anything is not in the other list, these are not equal
296 return false;
297 }
298 }
299 // Found everything in the other list. Since lists are equal length, they must be equal.
300 return true;
301 }
302 }
303 return false;
304 }
305 // Don't know what was passed, but the base system will figure it out for me.
306 return base.Equals(obj);
307 }
308
309 public override string ToString()
310 {
311 StringBuilder buff = new StringBuilder();
312 buff.Append("dflt=");
313 buff.Append(DefaultAnimation.ToString());
314 buff.Append(",iDflt=");
315 if (DefaultAnimation == ImplicitDefaultAnimation)
316 buff.Append("same");
317 else
318 buff.Append(ImplicitDefaultAnimation.ToString());
319 if (m_animations.Count > 0)
320 {
321 buff.Append(",anims=");
322 foreach (OpenSim.Framework.Animation anim in m_animations)
323 {
324 buff.Append("<");
325 buff.Append(anim.ToString());
326 buff.Append(">,");
327 }
328 }
329 return buff.ToString();
330 }
221 } 331 }
222} 332}
diff --git a/OpenSim/Region/Framework/Scenes/Animation/DefaultAvatarAnimations.cs b/OpenSim/Region/Framework/Scenes/Animation/DefaultAvatarAnimations.cs
index c2b0468..b79dd8f 100644
--- a/OpenSim/Region/Framework/Scenes/Animation/DefaultAvatarAnimations.cs
+++ b/OpenSim/Region/Framework/Scenes/Animation/DefaultAvatarAnimations.cs
@@ -104,5 +104,31 @@ namespace OpenSim.Region.Framework.Scenes.Animation
104 104
105 return UUID.Zero; 105 return UUID.Zero;
106 } 106 }
107
108 /// <summary>
109 /// Get the name of the animation given a UUID. If there is no matching animation
110 /// return the UUID as a string.
111 /// </summary>
112 public static string GetDefaultAnimationName(UUID uuid)
113 {
114 string ret = "unknown";
115 if (AnimsUUID.ContainsValue(uuid))
116 {
117 foreach (KeyValuePair<string, UUID> kvp in AnimsUUID)
118 {
119 if (kvp.Value == uuid)
120 {
121 ret = kvp.Key;
122 break;
123 }
124 }
125 }
126 else
127 {
128 ret = uuid.ToString();
129 }
130
131 return ret;
132 }
107 } 133 }
108} \ No newline at end of file 134} \ No newline at end of file
diff --git a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs
index 65c279e..eb70eee 100644
--- a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs
+++ b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs
@@ -93,7 +93,9 @@ namespace OpenSim.Region.Framework.Scenes.Animation
93 GetAnimName(animID), animID, m_scenePresence.Name); 93 GetAnimName(animID), animID, m_scenePresence.Name);
94 94
95 if (m_animations.Add(animID, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, objectID)) 95 if (m_animations.Add(animID, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, objectID))
96 {
96 SendAnimPack(); 97 SendAnimPack();
98 }
97 } 99 }
98 100
99 // Called from scripts 101 // Called from scripts
@@ -132,7 +134,9 @@ namespace OpenSim.Region.Framework.Scenes.Animation
132 GetAnimName(animID), animID, m_scenePresence.Name); 134 GetAnimName(animID), animID, m_scenePresence.Name);
133 135
134 if (m_animations.Remove(animID, allowNoDefault)) 136 if (m_animations.Remove(animID, allowNoDefault))
137 {
135 SendAnimPack(); 138 SendAnimPack();
139 }
136 } 140 }
137 141
138 public void avnChangeAnim(UUID animID, bool addRemove, bool sendPack) 142 public void avnChangeAnim(UUID animID, bool addRemove, bool sendPack)
@@ -180,8 +184,10 @@ namespace OpenSim.Region.Framework.Scenes.Animation
180 /// The movement animation is reserved for "main" animations 184 /// The movement animation is reserved for "main" animations
181 /// that are mutually exclusive, e.g. flying and sitting. 185 /// that are mutually exclusive, e.g. flying and sitting.
182 /// </summary> 186 /// </summary>
183 public void TrySetMovementAnimation(string anim) 187 /// <returns>'true' if the animation was updated</returns>
188 public bool TrySetMovementAnimation(string anim)
184 { 189 {
190 bool ret = false;
185 if (!m_scenePresence.IsChildAgent) 191 if (!m_scenePresence.IsChildAgent)
186 { 192 {
187// m_log.DebugFormat( 193// m_log.DebugFormat(
@@ -198,6 +204,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation
198 // 16384 is CHANGED_ANIMATION 204 // 16384 is CHANGED_ANIMATION
199 m_scenePresence.SendScriptEventToAttachments("changed", new Object[] { (int)Changed.ANIMATION}); 205 m_scenePresence.SendScriptEventToAttachments("changed", new Object[] { (int)Changed.ANIMATION});
200 SendAnimPack(); 206 SendAnimPack();
207 ret = true;
201 } 208 }
202 } 209 }
203 else 210 else
@@ -206,6 +213,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation
206 "[SCENE PRESENCE ANIMATOR]: Tried to set movement animation {0} on child presence {1}", 213 "[SCENE PRESENCE ANIMATOR]: Tried to set movement animation {0} on child presence {1}",
207 anim, m_scenePresence.Name); 214 anim, m_scenePresence.Name);
208 } 215 }
216 return ret;
209 } 217 }
210 218
211 /// <summary> 219 /// <summary>
@@ -439,8 +447,10 @@ namespace OpenSim.Region.Framework.Scenes.Animation
439 /// <summary> 447 /// <summary>
440 /// Update the movement animation of this avatar according to its current state 448 /// Update the movement animation of this avatar according to its current state
441 /// </summary> 449 /// </summary>
442 public void UpdateMovementAnimations() 450 /// <returns>'true' if the animation was changed</returns>
451 public bool UpdateMovementAnimations()
443 { 452 {
453 bool ret = false;
444 lock (m_animations) 454 lock (m_animations)
445 { 455 {
446 string newMovementAnimation = DetermineMovementAnimation(); 456 string newMovementAnimation = DetermineMovementAnimation();
@@ -454,9 +464,10 @@ namespace OpenSim.Region.Framework.Scenes.Animation
454 464
455 // Only set it if it's actually changed, give a script 465 // Only set it if it's actually changed, give a script
456 // a chance to stop a default animation 466 // a chance to stop a default animation
457 TrySetMovementAnimation(CurrentMovementAnimation); 467 ret = TrySetMovementAnimation(CurrentMovementAnimation);
458 } 468 }
459 } 469 }
470 return ret;
460 } 471 }
461 472
462 public UUID[] GetAnimationArray() 473 public UUID[] GetAnimationArray()
diff --git a/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs b/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs
index f555b49..11a0146 100644
--- a/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs
+++ b/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs
@@ -104,14 +104,8 @@ namespace OpenSim.Region.Framework.Scenes
104 // better than losing the object for now. 104 // better than losing the object for now.
105 if (permissionToDelete) 105 if (permissionToDelete)
106 { 106 {
107 List<uint> killIDs = new List<uint>();
108
109 foreach (SceneObjectGroup g in objectGroups) 107 foreach (SceneObjectGroup g in objectGroups)
110 { killIDs.Add(g.LocalId); 108 g.DeleteGroupFromScene(false);
111 g.DeleteGroupFromScene(true);
112 }
113
114 m_scene.SendKillObject(killIDs);
115 } 109 }
116 } 110 }
117 111
@@ -160,7 +154,7 @@ namespace OpenSim.Region.Framework.Scenes
160 if (x.permissionToDelete) 154 if (x.permissionToDelete)
161 { 155 {
162 foreach (SceneObjectGroup g in x.objectGroups) 156 foreach (SceneObjectGroup g in x.objectGroups)
163 m_scene.DeleteSceneObject(g, false); 157 m_scene.DeleteSceneObject(g, true);
164 } 158 }
165 } 159 }
166 catch (Exception e) 160 catch (Exception e)
diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs
index 4733547..4fec44f 100644
--- a/OpenSim/Region/Framework/Scenes/EventManager.cs
+++ b/OpenSim/Region/Framework/Scenes/EventManager.cs
@@ -974,6 +974,8 @@ namespace OpenSim.Region.Framework.Scenes
974 public delegate void RegionStarted(Scene scene); 974 public delegate void RegionStarted(Scene scene);
975 public event RegionStarted OnRegionStarted; 975 public event RegionStarted OnRegionStarted;
976 976
977 public delegate void RegionHeartbeatStart(Scene scene);
978 public event RegionHeartbeatStart OnRegionHeartbeatStart;
977 public delegate void RegionHeartbeatEnd(Scene scene); 979 public delegate void RegionHeartbeatEnd(Scene scene);
978 public event RegionHeartbeatEnd OnRegionHeartbeatEnd; 980 public event RegionHeartbeatEnd OnRegionHeartbeatEnd;
979 981
@@ -3096,6 +3098,27 @@ namespace OpenSim.Region.Framework.Scenes
3096 } 3098 }
3097 } 3099 }
3098 3100
3101 public void TriggerRegionHeartbeatStart(Scene scene)
3102 {
3103 RegionHeartbeatStart handler = OnRegionHeartbeatStart;
3104
3105 if (handler != null)
3106 {
3107 foreach (RegionHeartbeatStart d in handler.GetInvocationList())
3108 {
3109 try
3110 {
3111 d(scene);
3112 }
3113 catch (Exception e)
3114 {
3115 m_log.ErrorFormat("[EVENT MANAGER]: Delegate for OnRegionHeartbeatStart failed - continuing {0} - {1}",
3116 e.Message, e.StackTrace);
3117 }
3118 }
3119 }
3120 }
3121
3099 public void TriggerRegionHeartbeatEnd(Scene scene) 3122 public void TriggerRegionHeartbeatEnd(Scene scene)
3100 { 3123 {
3101 RegionHeartbeatEnd handler = OnRegionHeartbeatEnd; 3124 RegionHeartbeatEnd handler = OnRegionHeartbeatEnd;
diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
index d2e41f8..70018c8 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
@@ -417,13 +417,13 @@ namespace OpenSim.Region.Framework.Scenes
417 // is not allowed to change the export flag. 417 // is not allowed to change the export flag.
418 bool denyExportChange = false; 418 bool denyExportChange = false;
419 419
420 m_log.InfoFormat("[XXX]: B: {0} O: {1} E: {2}", itemUpd.BasePermissions, itemUpd.CurrentPermissions, itemUpd.EveryOnePermissions); 420// m_log.DebugFormat("[XXX]: B: {0} O: {1} E: {2}", itemUpd.BasePermissions, itemUpd.CurrentPermissions, itemUpd.EveryOnePermissions);
421 421
422 // If the user is not the creator or doesn't have "E" in both "B" and "O", deny setting export 422 // If the user is not the creator or doesn't have "E" in both "B" and "O", deny setting export
423 if ((item.BasePermissions & (uint)(PermissionMask.All | PermissionMask.Export)) != (uint)(PermissionMask.All | PermissionMask.Export) || (item.CurrentPermissions & (uint)PermissionMask.Export) == 0 || item.CreatorIdAsUuid != item.Owner) 423 if ((item.BasePermissions & (uint)(PermissionMask.All | PermissionMask.Export)) != (uint)(PermissionMask.All | PermissionMask.Export) || (item.CurrentPermissions & (uint)PermissionMask.Export) == 0 || item.CreatorIdAsUuid != item.Owner)
424 denyExportChange = true; 424 denyExportChange = true;
425 425
426 m_log.InfoFormat("[XXX]: Deny Export Update {0}", denyExportChange); 426// m_log.DebugFormat("[XXX]: Deny Export Update {0}", denyExportChange);
427 427
428 // If it is already set, force it set and also force full perm 428 // If it is already set, force it set and also force full perm
429 // else prevent setting it. It can and should never be set unless 429 // else prevent setting it. It can and should never be set unless
@@ -447,7 +447,7 @@ namespace OpenSim.Region.Framework.Scenes
447 // If the new state is exportable, force full perm 447 // If the new state is exportable, force full perm
448 if ((itemUpd.EveryOnePermissions & (uint)PermissionMask.Export) != 0) 448 if ((itemUpd.EveryOnePermissions & (uint)PermissionMask.Export) != 0)
449 { 449 {
450 m_log.InfoFormat("[XXX]: Force full perm"); 450// m_log.DebugFormat("[XXX]: Force full perm");
451 itemUpd.NextPermissions = (uint)(PermissionMask.All); 451 itemUpd.NextPermissions = (uint)(PermissionMask.All);
452 } 452 }
453 } 453 }
@@ -485,7 +485,10 @@ namespace OpenSim.Region.Framework.Scenes
485 item.SaleType = itemUpd.SaleType; 485 item.SaleType = itemUpd.SaleType;
486 486
487 InventoryService.UpdateItem(item); 487 InventoryService.UpdateItem(item);
488 remoteClient.SendBulkUpdateInventory(item); 488
489 // We cannot send out a bulk update here, since this will cause editing of clothing to start
490 // failing frequently. Possibly this is a race with a separate transaction that uploads the asset.
491// remoteClient.SendBulkUpdateInventory(item);
489 } 492 }
490 493
491 if (UUID.Zero != transactionID) 494 if (UUID.Zero != transactionID)
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index 2b58795..436a544 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -396,10 +396,12 @@ namespace OpenSim.Region.Framework.Scenes
396 if (value) 396 if (value)
397 { 397 {
398 if (!m_active) 398 if (!m_active)
399 Start(); 399 Start(false);
400 } 400 }
401 else 401 else
402 { 402 {
403 // This appears assymetric with Start() above but is not - setting m_active = false stops the loops
404 // XXX: Possibly this should be in an explicit Stop() method for symmetry.
403 m_active = false; 405 m_active = false;
404 } 406 }
405 } 407 }
@@ -1361,10 +1363,18 @@ namespace OpenSim.Region.Framework.Scenes
1361 } 1363 }
1362 } 1364 }
1363 1365
1366 public override void Start()
1367 {
1368 Start(true);
1369 }
1370
1364 /// <summary> 1371 /// <summary>
1365 /// Start the scene 1372 /// Start the scene
1366 /// </summary> 1373 /// </summary>
1367 public void Start() 1374 /// <param name='startScripts'>
1375 /// Start the scripts within the scene.
1376 /// </param>
1377 public void Start(bool startScripts)
1368 { 1378 {
1369 m_active = true; 1379 m_active = true;
1370 1380
@@ -1401,6 +1411,8 @@ namespace OpenSim.Region.Framework.Scenes
1401 m_heartbeatThread 1411 m_heartbeatThread
1402 = Watchdog.StartThread( 1412 = Watchdog.StartThread(
1403 Heartbeat, string.Format("Heartbeat ({0})", RegionInfo.RegionName), ThreadPriority.Normal, false, false); 1413 Heartbeat, string.Format("Heartbeat ({0})", RegionInfo.RegionName), ThreadPriority.Normal, false, false);
1414
1415 StartScripts();
1404 } 1416 }
1405 1417
1406 /// <summary> 1418 /// <summary>
@@ -1557,6 +1569,8 @@ namespace OpenSim.Region.Framework.Scenes
1557 1569
1558 try 1570 try
1559 { 1571 {
1572 EventManager.TriggerRegionHeartbeatStart(this);
1573
1560 // Apply taints in terrain module to terrain in physics scene 1574 // Apply taints in terrain module to terrain in physics scene
1561 if (Frame % m_update_terrain == 0) 1575 if (Frame % m_update_terrain == 0)
1562 { 1576 {
@@ -3001,7 +3015,9 @@ namespace OpenSim.Region.Framework.Scenes
3001 // client is for a root or child agent. 3015 // client is for a root or child agent.
3002 client.SceneAgent = sp; 3016 client.SceneAgent = sp;
3003 3017
3004 // Cache the user's name 3018 // This is currently also being done earlier in NewUserConnection for real users to see if this
3019 // resolves problems where HG agents are occasionally seen by others as "Unknown user" in chat and other
3020 // places. However, we still need to do it here for NPCs.
3005 CacheUserName(sp, aCircuit); 3021 CacheUserName(sp, aCircuit);
3006 3022
3007 EventManager.TriggerOnNewClient(client); 3023 EventManager.TriggerOnNewClient(client);
@@ -3025,7 +3041,7 @@ namespace OpenSim.Region.Framework.Scenes
3025 { 3041 {
3026 string first = aCircuit.firstname, last = aCircuit.lastname; 3042 string first = aCircuit.firstname, last = aCircuit.lastname;
3027 3043
3028 if (sp.PresenceType == PresenceType.Npc) 3044 if (sp != null && sp.PresenceType == PresenceType.Npc)
3029 { 3045 {
3030 UserManagementModule.AddUser(aCircuit.AgentID, first, last); 3046 UserManagementModule.AddUser(aCircuit.AgentID, first, last);
3031 } 3047 }
@@ -3242,7 +3258,6 @@ namespace OpenSim.Region.Framework.Scenes
3242 { 3258 {
3243 //client.OnNameFromUUIDRequest += HandleUUIDNameRequest; 3259 //client.OnNameFromUUIDRequest += HandleUUIDNameRequest;
3244 client.OnMoneyTransferRequest += ProcessMoneyTransferRequest; 3260 client.OnMoneyTransferRequest += ProcessMoneyTransferRequest;
3245 client.OnSetStartLocationRequest += SetHomeRezPoint;
3246 client.OnRegionHandleRequest += RegionHandleRequest; 3261 client.OnRegionHandleRequest += RegionHandleRequest;
3247 } 3262 }
3248 3263
@@ -3369,7 +3384,6 @@ namespace OpenSim.Region.Framework.Scenes
3369 { 3384 {
3370 //client.OnNameFromUUIDRequest -= HandleUUIDNameRequest; 3385 //client.OnNameFromUUIDRequest -= HandleUUIDNameRequest;
3371 client.OnMoneyTransferRequest -= ProcessMoneyTransferRequest; 3386 client.OnMoneyTransferRequest -= ProcessMoneyTransferRequest;
3372 client.OnSetStartLocationRequest -= SetHomeRezPoint;
3373 client.OnRegionHandleRequest -= RegionHandleRequest; 3387 client.OnRegionHandleRequest -= RegionHandleRequest;
3374 } 3388 }
3375 3389
@@ -3496,33 +3510,6 @@ namespace OpenSim.Region.Framework.Scenes
3496 } 3510 }
3497 3511
3498 /// <summary> 3512 /// <summary>
3499 /// Sets the Home Point. The LoginService uses this to know where to put a user when they log-in
3500 /// </summary>
3501 /// <param name="remoteClient"></param>
3502 /// <param name="regionHandle"></param>
3503 /// <param name="position"></param>
3504 /// <param name="lookAt"></param>
3505 /// <param name="flags"></param>
3506 public virtual void SetHomeRezPoint(IClientAPI remoteClient, ulong regionHandle, Vector3 position, Vector3 lookAt, uint flags)
3507 {
3508 //Add half the avatar's height so that the user doesn't fall through prims
3509 ScenePresence presence;
3510 if (TryGetScenePresence(remoteClient.AgentId, out presence))
3511 {
3512 if (presence.Appearance != null)
3513 {
3514 position.Z = position.Z + (presence.Appearance.AvatarHeight / 2);
3515 }
3516 }
3517
3518 if (GridUserService != null && GridUserService.SetHome(remoteClient.AgentId.ToString(), RegionInfo.RegionID, position, lookAt))
3519 // FUBAR ALERT: this needs to be "Home position set." so the viewer saves a home-screenshot.
3520 m_dialogModule.SendAlertToUser(remoteClient, "Home position set.");
3521 else
3522 m_dialogModule.SendAlertToUser(remoteClient, "Set Home request Failed.");
3523 }
3524
3525 /// <summary>
3526 /// Get the avatar apperance for the given client. 3513 /// Get the avatar apperance for the given client.
3527 /// </summary> 3514 /// </summary>
3528 /// <param name="client"></param> 3515 /// <param name="client"></param>
@@ -3618,15 +3605,12 @@ namespace OpenSim.Region.Framework.Scenes
3618 if (closeChildAgents && CapsModule != null) 3605 if (closeChildAgents && CapsModule != null)
3619 CapsModule.RemoveCaps(agentID, avatar.ControllingClient.CircuitCode); 3606 CapsModule.RemoveCaps(agentID, avatar.ControllingClient.CircuitCode);
3620 3607
3621// // REFACTORING PROBLEM -- well not really a problem, but just to point out that whatever
3622// // this method is doing is HORRIBLE!!!
3623 // Commented pending deletion since this method no longer appears to do anything at all
3624// avatar.Scene.NeedSceneCacheClear(avatar.UUID);
3625
3626 if (closeChildAgents && !isChildAgent) 3608 if (closeChildAgents && !isChildAgent)
3627 { 3609 {
3628 List<ulong> regions = avatar.KnownRegionHandles; 3610 List<ulong> regions = avatar.KnownRegionHandles;
3629 regions.Remove(RegionInfo.RegionHandle); 3611 regions.Remove(RegionInfo.RegionHandle);
3612
3613 // This ends up being done asynchronously so that a logout isn't held up where there are many present but unresponsive neighbours.
3630 m_sceneGridService.SendCloseChildAgentConnections(agentID, regions); 3614 m_sceneGridService.SendCloseChildAgentConnections(agentID, regions);
3631 } 3615 }
3632 3616
@@ -3644,7 +3628,7 @@ namespace OpenSim.Region.Framework.Scenes
3644 delegate(IClientAPI client) 3628 delegate(IClientAPI client)
3645 { 3629 {
3646 //We can safely ignore null reference exceptions. It means the avatar is dead and cleaned up anyway 3630 //We can safely ignore null reference exceptions. It means the avatar is dead and cleaned up anyway
3647 try { client.SendKillObject(avatar.RegionHandle, new List<uint> { avatar.LocalId }); } 3631 try { client.SendKillObject(new List<uint> { avatar.LocalId }); }
3648 catch (NullReferenceException) { } 3632 catch (NullReferenceException) { }
3649 }); 3633 });
3650 } 3634 }
@@ -3725,7 +3709,8 @@ namespace OpenSim.Region.Framework.Scenes
3725 } 3709 }
3726 deleteIDs.Add(localID); 3710 deleteIDs.Add(localID);
3727 } 3711 }
3728 ForEachClient(delegate(IClientAPI client) { client.SendKillObject(m_regionHandle, deleteIDs); }); 3712
3713 ForEachClient(c => c.SendKillObject(deleteIDs));
3729 } 3714 }
3730 3715
3731 #endregion 3716 #endregion
@@ -3881,7 +3866,13 @@ namespace OpenSim.Region.Framework.Scenes
3881 3866
3882 lock (agent) 3867 lock (agent)
3883 { 3868 {
3884 //On login test land permisions 3869 // Optimistic: add or update the circuit data with the new agent circuit data and teleport flags.
3870 // We need the circuit data here for some of the subsequent checks. (groups, for example)
3871 // If the checks fail, we remove the circuit.
3872 agent.teleportFlags = teleportFlags;
3873 m_authenticateHandler.AddNewCircuit(agent.circuitcode, agent);
3874
3875 // On login test land permisions
3885 if (vialogin) 3876 if (vialogin)
3886 { 3877 {
3887 IUserAccountCacheModule cache = RequestModuleInterface<IUserAccountCacheModule>(); 3878 IUserAccountCacheModule cache = RequestModuleInterface<IUserAccountCacheModule>();
@@ -3890,6 +3881,7 @@ namespace OpenSim.Region.Framework.Scenes
3890 if (!TestLandRestrictions(agent.AgentID, out reason, ref agent.startpos.X, ref agent.startpos.Y)) 3881 if (!TestLandRestrictions(agent.AgentID, out reason, ref agent.startpos.X, ref agent.startpos.Y))
3891 { 3882 {
3892 m_log.DebugFormat("[CONNECTION BEGIN]: Denying access to {0} due to no land access", agent.AgentID.ToString()); 3883 m_log.DebugFormat("[CONNECTION BEGIN]: Denying access to {0} due to no land access", agent.AgentID.ToString());
3884 m_authenticateHandler.RemoveCircuit(agent.circuitcode);
3893 return false; 3885 return false;
3894 } 3886 }
3895 } 3887 }
@@ -3901,11 +3893,17 @@ namespace OpenSim.Region.Framework.Scenes
3901 try 3893 try
3902 { 3894 {
3903 if (!VerifyUserPresence(agent, out reason)) 3895 if (!VerifyUserPresence(agent, out reason))
3896 {
3897 m_authenticateHandler.RemoveCircuit(agent.circuitcode);
3904 return false; 3898 return false;
3905 } catch (Exception e) 3899 }
3900 }
3901 catch (Exception e)
3906 { 3902 {
3907 m_log.ErrorFormat( 3903 m_log.ErrorFormat(
3908 "[SCENE]: Exception verifying presence {0}{1}", e.Message, e.StackTrace); 3904 "[SCENE]: Exception verifying presence {0}{1}", e.Message, e.StackTrace);
3905
3906 m_authenticateHandler.RemoveCircuit(agent.circuitcode);
3909 return false; 3907 return false;
3910 } 3908 }
3911 } 3909 }
@@ -3918,6 +3916,7 @@ namespace OpenSim.Region.Framework.Scenes
3918 { 3916 {
3919 if (!AuthorizeUser(agent, out reason)) 3917 if (!AuthorizeUser(agent, out reason))
3920 { 3918 {
3919 m_authenticateHandler.RemoveCircuit(agent.circuitcode);
3921 return false; 3920 return false;
3922 } 3921 }
3923 } 3922 }
@@ -3926,6 +3925,8 @@ namespace OpenSim.Region.Framework.Scenes
3926 { 3925 {
3927 m_log.ErrorFormat( 3926 m_log.ErrorFormat(
3928 "[SCENE]: Exception authorizing user {0}{1}", e.Message, e.StackTrace); 3927 "[SCENE]: Exception authorizing user {0}{1}", e.Message, e.StackTrace);
3928
3929 m_authenticateHandler.RemoveCircuit(agent.circuitcode);
3929 return false; 3930 return false;
3930 } 3931 }
3931 3932
@@ -3953,11 +3954,12 @@ namespace OpenSim.Region.Framework.Scenes
3953 CapsModule.SetAgentCapsSeeds(agent); 3954 CapsModule.SetAgentCapsSeeds(agent);
3954 } 3955 }
3955 } 3956 }
3956 }
3957 3957
3958 // In all cases, add or update the circuit data with the new agent circuit data and teleport flags 3958 // Try caching an incoming user name much earlier on to see if this helps with an issue
3959 agent.teleportFlags = teleportFlags; 3959 // where HG users are occasionally seen by others as "Unknown User" because their UUIDName
3960 m_authenticateHandler.AddNewCircuit(agent.circuitcode, agent); 3960 // request for the HG avatar appears to trigger before the user name is cached.
3961 CacheUserName(null, agent);
3962 }
3961 3963
3962 if (CapsModule != null) 3964 if (CapsModule != null)
3963 { 3965 {
@@ -4365,8 +4367,6 @@ namespace OpenSim.Region.Framework.Scenes
4365 m_log.DebugFormat( 4367 m_log.DebugFormat(
4366 "[SCENE]: Incoming child agent update for {0} in {1}", cAgentData.AgentID, RegionInfo.RegionName); 4368 "[SCENE]: Incoming child agent update for {0} in {1}", cAgentData.AgentID, RegionInfo.RegionName);
4367 4369
4368 // XPTO: if this agent is not allowed here as root, always return false
4369
4370 // We have to wait until the viewer contacts this region after receiving EAC. 4370 // We have to wait until the viewer contacts this region after receiving EAC.
4371 // That calls AddNewClient, which finally creates the ScenePresence 4371 // That calls AddNewClient, which finally creates the ScenePresence
4372 int flags = GetUserFlags(cAgentData.AgentID); 4372 int flags = GetUserFlags(cAgentData.AgentID);
@@ -5655,12 +5655,12 @@ Environment.Exit(1);
5655 List<SceneObjectGroup> objects, 5655 List<SceneObjectGroup> objects,
5656 out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) 5656 out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ)
5657 { 5657 {
5658 minX = 256; 5658 minX = float.MaxValue;
5659 maxX = -256; 5659 maxX = float.MinValue;
5660 minY = 256; 5660 minY = float.MaxValue;
5661 maxY = -256; 5661 maxY = float.MinValue;
5662 minZ = 8192; 5662 minZ = float.MaxValue;
5663 maxZ = -256; 5663 maxZ = float.MinValue;
5664 5664
5665 List<Vector3> offsets = new List<Vector3>(); 5665 List<Vector3> offsets = new List<Vector3>();
5666 5666
diff --git a/OpenSim/Region/Framework/Scenes/SceneBase.cs b/OpenSim/Region/Framework/Scenes/SceneBase.cs
index 74c9582..4eef162 100644
--- a/OpenSim/Region/Framework/Scenes/SceneBase.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneBase.cs
@@ -562,6 +562,10 @@ namespace OpenSim.Region.Framework.Scenes
562 get { return false; } 562 get { return false; }
563 } 563 }
564 564
565 public virtual void Start()
566 {
567 }
568
565 public void Restart() 569 public void Restart()
566 { 570 {
567 // This has to be here to fire the event 571 // This has to be here to fire the event
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 0ea4e09..02a8935 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -1862,11 +1862,11 @@ namespace OpenSim.Region.Framework.Scenes
1862 /// <summary> 1862 /// <summary>
1863 /// Delete this group from its scene. 1863 /// Delete this group from its scene.
1864 /// </summary> 1864 /// </summary>
1865 /// 1865 /// <remarks>
1866 /// This only handles the in-world consequences of deletion (e.g. any avatars sitting on it are forcibly stood 1866 /// This only handles the in-world consequences of deletion (e.g. any avatars sitting on it are forcibly stood
1867 /// up and all avatars receive notification of its removal. Removal of the scene object from database backup 1867 /// up and all avatars receive notification of its removal. Removal of the scene object from database backup
1868 /// must be handled by the caller. 1868 /// must be handled by the caller.
1869 /// 1869 /// </remarks>
1870 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1870 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1871 public void DeleteGroupFromScene(bool silent) 1871 public void DeleteGroupFromScene(bool silent)
1872 { 1872 {
@@ -1880,10 +1880,10 @@ namespace OpenSim.Region.Framework.Scenes
1880 { 1880 {
1881 SceneObjectPart part = parts[i]; 1881 SceneObjectPart part = parts[i];
1882 1882
1883 Scene.ForEachRootScenePresence(delegate(ScenePresence avatar) 1883 Scene.ForEachScenePresence(sp =>
1884 { 1884 {
1885 if (avatar.ParentID == LocalId) 1885 if (!sp.IsChildAgent && sp.ParentID == LocalId)
1886 avatar.StandUp(); 1886 sp.StandUp();
1887 1887
1888 if (!silent) 1888 if (!silent)
1889 { 1889 {
@@ -1891,9 +1891,9 @@ namespace OpenSim.Region.Framework.Scenes
1891 if (part == m_rootPart) 1891 if (part == m_rootPart)
1892 { 1892 {
1893 if (!IsAttachment 1893 if (!IsAttachment
1894 || AttachedAvatar == avatar.ControllingClient.AgentId 1894 || AttachedAvatar == sp.UUID
1895 || !HasPrivateAttachmentPoint) 1895 || !HasPrivateAttachmentPoint)
1896 avatar.ControllingClient.SendKillObject(m_regionHandle, new List<uint> { part.LocalId }); 1896 sp.ControllingClient.SendKillObject(new List<uint> { part.LocalId });
1897 } 1897 }
1898 } 1898 }
1899 }); 1899 });
@@ -2202,7 +2202,7 @@ namespace OpenSim.Region.Framework.Scenes
2202 if (!userExposed) 2202 if (!userExposed)
2203 dupe.IsAttachment = true; 2203 dupe.IsAttachment = true;
2204 2204
2205 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z); 2205 dupe.m_sittingAvatars = new List<UUID>();
2206 2206
2207 if (!userExposed) 2207 if (!userExposed)
2208 { 2208 {
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
index 261e958..8c6450d 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
@@ -231,6 +231,13 @@ namespace OpenSim.Region.Framework.Scenes
231 231
232 public double SoundRadius; 232 public double SoundRadius;
233 233
234 /// <summary>
235 /// Should sounds played from this prim be queued?
236 /// </summary>
237 /// <remarks>
238 /// This should only be changed by sound modules. It is up to sound modules as to how they interpret this setting.
239 /// </remarks>
240 public bool SoundQueueing { get; set; }
234 241
235 public uint TimeStampFull; 242 public uint TimeStampFull;
236 243
@@ -1218,23 +1225,14 @@ namespace OpenSim.Region.Framework.Scenes
1218 // the mappings more consistant. 1225 // the mappings more consistant.
1219 public Vector3 SitTargetPositionLL 1226 public Vector3 SitTargetPositionLL
1220 { 1227 {
1221 get { return new Vector3(m_sitTargetPosition.X, m_sitTargetPosition.Y,m_sitTargetPosition.Z); } 1228 get { return m_sitTargetPosition; }
1222 set { m_sitTargetPosition = value; } 1229 set { m_sitTargetPosition = value; }
1223 } 1230 }
1224 1231
1225 public Quaternion SitTargetOrientationLL 1232 public Quaternion SitTargetOrientationLL
1226 { 1233 {
1227 get 1234 get { return m_sitTargetOrientation; }
1228 { 1235 set { m_sitTargetOrientation = value; }
1229 return new Quaternion(
1230 m_sitTargetOrientation.X,
1231 m_sitTargetOrientation.Y,
1232 m_sitTargetOrientation.Z,
1233 m_sitTargetOrientation.W
1234 );
1235 }
1236
1237 set { m_sitTargetOrientation = new Quaternion(value.X, value.Y, value.Z, value.W); }
1238 } 1236 }
1239 1237
1240 public bool Stopped 1238 public bool Stopped
@@ -4350,30 +4348,31 @@ namespace OpenSim.Region.Framework.Scenes
4350 } 4348 }
4351 } 4349 }
4352 4350
4353 public void UpdateGroupPosition(Vector3 pos) 4351 public void UpdateGroupPosition(Vector3 newPos)
4354 { 4352 {
4355 if ((pos.X != GroupPosition.X) || 4353 Vector3 oldPos = GroupPosition;
4356 (pos.Y != GroupPosition.Y) || 4354
4357 (pos.Z != GroupPosition.Z)) 4355 if ((newPos.X != oldPos.X) ||
4356 (newPos.Y != oldPos.Y) ||
4357 (newPos.Z != oldPos.Z))
4358 { 4358 {
4359 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
4360 GroupPosition = newPos; 4359 GroupPosition = newPos;
4361 ScheduleTerseUpdate(); 4360 ScheduleTerseUpdate();
4362 } 4361 }
4363 } 4362 }
4364 4363
4365 /// <summary> 4364 /// <summary>
4366 /// 4365 /// Update this part's offset position.
4367 /// </summary> 4366 /// </summary>
4368 /// <param name="pos"></param> 4367 /// <param name="pos"></param>
4369 public void UpdateOffSet(Vector3 pos) 4368 public void UpdateOffSet(Vector3 newPos)
4370 { 4369 {
4371 if ((pos.X != OffsetPosition.X) || 4370 Vector3 oldPos = OffsetPosition;
4372 (pos.Y != OffsetPosition.Y) ||
4373 (pos.Z != OffsetPosition.Z))
4374 {
4375 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
4376 4371
4372 if ((newPos.X != oldPos.X) ||
4373 (newPos.Y != oldPos.Y) ||
4374 (newPos.Z != oldPos.Z))
4375 {
4377 if (ParentGroup.RootPart.GetStatusSandbox()) 4376 if (ParentGroup.RootPart.GetStatusSandbox())
4378 { 4377 {
4379 if (Util.GetDistanceTo(ParentGroup.RootPart.StatusSandboxPos, newPos) > 10) 4378 if (Util.GetDistanceTo(ParentGroup.RootPart.StatusSandboxPos, newPos) > 10)
@@ -5014,6 +5013,14 @@ namespace OpenSim.Region.Framework.Scenes
5014 oldTex.DefaultTexture = fallbackOldFace; 5013 oldTex.DefaultTexture = fallbackOldFace;
5015 } 5014 }
5016 5015
5016 // Materials capable viewers can send a ObjectImage packet
5017 // when nothing in TE has changed. MaterialID should be updated
5018 // by the RenderMaterials CAP handler, so updating it here may cause a
5019 // race condtion. Therefore, if no non-materials TE fields have changed,
5020 // we should ignore any changes and not update Shape.TextureEntry
5021
5022 bool otherFieldsChanged = false;
5023
5017 for (int i = 0 ; i < GetNumberOfSides(); i++) 5024 for (int i = 0 ; i < GetNumberOfSides(); i++)
5018 { 5025 {
5019 5026
@@ -5040,18 +5047,36 @@ namespace OpenSim.Region.Framework.Scenes
5040 // Max change, skip the rest of testing 5047 // Max change, skip the rest of testing
5041 if (changeFlags == (Changed.TEXTURE | Changed.COLOR)) 5048 if (changeFlags == (Changed.TEXTURE | Changed.COLOR))
5042 break; 5049 break;
5050
5051 if (!otherFieldsChanged)
5052 {
5053 if (oldFace.Bump != newFace.Bump) otherFieldsChanged = true;
5054 if (oldFace.Fullbright != newFace.Fullbright) otherFieldsChanged = true;
5055 if (oldFace.Glow != newFace.Glow) otherFieldsChanged = true;
5056 if (oldFace.MediaFlags != newFace.MediaFlags) otherFieldsChanged = true;
5057 if (oldFace.OffsetU != newFace.OffsetU) otherFieldsChanged = true;
5058 if (oldFace.OffsetV != newFace.OffsetV) otherFieldsChanged = true;
5059 if (oldFace.RepeatU != newFace.RepeatU) otherFieldsChanged = true;
5060 if (oldFace.RepeatV != newFace.RepeatV) otherFieldsChanged = true;
5061 if (oldFace.Rotation != newFace.Rotation) otherFieldsChanged = true;
5062 if (oldFace.Shiny != newFace.Shiny) otherFieldsChanged = true;
5063 if (oldFace.TexMapType != newFace.TexMapType) otherFieldsChanged = true;
5064 }
5043 } 5065 }
5044 5066
5045 m_shape.TextureEntry = newTex.GetBytes(); 5067 if (changeFlags != 0 || otherFieldsChanged)
5046 if (changeFlags != 0) 5068 {
5047 TriggerScriptChangedEvent(changeFlags); 5069 m_shape.TextureEntry = newTex.GetBytes();
5048 UpdateFlag = UpdateRequired.FULL; 5070 if (changeFlags != 0)
5049 ParentGroup.HasGroupChanged = true; 5071 TriggerScriptChangedEvent(changeFlags);
5072 UpdateFlag = UpdateRequired.FULL;
5073 ParentGroup.HasGroupChanged = true;
5050 5074
5051 //This is madness.. 5075 //This is madness..
5052 //ParentGroup.ScheduleGroupForFullUpdate(); 5076 //ParentGroup.ScheduleGroupForFullUpdate();
5053 //This is sparta 5077 //This is sparta
5054 ScheduleFullUpdate(); 5078 ScheduleFullUpdate();
5079 }
5055 } 5080 }
5056 5081
5057 5082
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index 0ab267a..1859cb1 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -1550,6 +1550,8 @@ namespace OpenSim.Region.Framework.Scenes
1550 // Create child agents in neighbouring regions 1550 // Create child agents in neighbouring regions
1551 if (openChildAgents && !IsChildAgent) 1551 if (openChildAgents && !IsChildAgent)
1552 { 1552 {
1553 // Remember in HandleUseCircuitCode, we delayed this to here
1554 SendInitialDataToMe();
1553 1555
1554 IEntityTransferModule m_agentTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>(); 1556 IEntityTransferModule m_agentTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>();
1555 if (m_agentTransfer != null) 1557 if (m_agentTransfer != null)
@@ -2308,6 +2310,7 @@ namespace OpenSim.Region.Framework.Scenes
2308 AddToPhysicalScene(false); 2310 AddToPhysicalScene(false);
2309 2311
2310 Animator.TrySetMovementAnimation("STAND"); 2312 Animator.TrySetMovementAnimation("STAND");
2313 TriggerScenePresenceUpdated();
2311 } 2314 }
2312 2315
2313 private SceneObjectPart FindNextAvailableSitTarget(UUID targetID) 2316 private SceneObjectPart FindNextAvailableSitTarget(UUID targetID)
@@ -2406,7 +2409,7 @@ namespace OpenSim.Region.Framework.Scenes
2406 ControllingClient.SendSitResponse( 2409 ControllingClient.SendSitResponse(
2407 part.UUID, offset, sitOrientation, false, cameraAtOffset, cameraEyeOffset, forceMouselook); 2410 part.UUID, offset, sitOrientation, false, cameraAtOffset, cameraEyeOffset, forceMouselook);
2408 2411
2409 m_requestedSitTargetUUID = targetID; 2412 m_requestedSitTargetUUID = part.UUID;
2410 2413
2411 HandleAgentSit(ControllingClient, UUID); 2414 HandleAgentSit(ControllingClient, UUID);
2412 2415
@@ -2434,7 +2437,7 @@ namespace OpenSim.Region.Framework.Scenes
2434 if (part != null) 2437 if (part != null)
2435 { 2438 {
2436 m_requestedSitTargetID = part.LocalId; 2439 m_requestedSitTargetID = part.LocalId;
2437 m_requestedSitTargetUUID = targetID; 2440 m_requestedSitTargetUUID = part.UUID;
2438 2441
2439 } 2442 }
2440 else 2443 else
@@ -2633,6 +2636,7 @@ namespace OpenSim.Region.Framework.Scenes
2633 } 2636 }
2634 Animator.TrySetMovementAnimation(sitAnimation); 2637 Animator.TrySetMovementAnimation(sitAnimation);
2635 SendAvatarDataToAllAgents(); 2638 SendAvatarDataToAllAgents();
2639 TriggerScenePresenceUpdated();
2636 } 2640 }
2637 } 2641 }
2638 2642
@@ -2641,6 +2645,7 @@ namespace OpenSim.Region.Framework.Scenes
2641// m_updateCount = 0; // Kill animation update burst so that the SIT_G.. will stick.. 2645// m_updateCount = 0; // Kill animation update burst so that the SIT_G.. will stick..
2642 m_AngularVelocity = Vector3.Zero; 2646 m_AngularVelocity = Vector3.Zero;
2643 Animator.TrySetMovementAnimation("SIT_GROUND_CONSTRAINED"); 2647 Animator.TrySetMovementAnimation("SIT_GROUND_CONSTRAINED");
2648 TriggerScenePresenceUpdated();
2644 SitGround = true; 2649 SitGround = true;
2645 RemoveFromPhysicalScene(); 2650 RemoveFromPhysicalScene();
2646 } 2651 }
@@ -2657,11 +2662,13 @@ namespace OpenSim.Region.Framework.Scenes
2657 public void HandleStartAnim(IClientAPI remoteClient, UUID animID) 2662 public void HandleStartAnim(IClientAPI remoteClient, UUID animID)
2658 { 2663 {
2659 Animator.AddAnimation(animID, UUID.Zero); 2664 Animator.AddAnimation(animID, UUID.Zero);
2665 TriggerScenePresenceUpdated();
2660 } 2666 }
2661 2667
2662 public void HandleStopAnim(IClientAPI remoteClient, UUID animID) 2668 public void HandleStopAnim(IClientAPI remoteClient, UUID animID)
2663 { 2669 {
2664 Animator.RemoveAnimation(animID, false); 2670 Animator.RemoveAnimation(animID, false);
2671 TriggerScenePresenceUpdated();
2665 } 2672 }
2666 2673
2667 public void avnHandleChangeAnim(UUID animID, bool addRemove,bool sendPack) 2674 public void avnHandleChangeAnim(UUID animID, bool addRemove,bool sendPack)
@@ -3347,10 +3354,8 @@ namespace OpenSim.Region.Framework.Scenes
3347 if (byebyeRegions.Count > 0) 3354 if (byebyeRegions.Count > 0)
3348 { 3355 {
3349 m_log.Debug("[SCENE PRESENCE]: Closing " + byebyeRegions.Count + " child agents"); 3356 m_log.Debug("[SCENE PRESENCE]: Closing " + byebyeRegions.Count + " child agents");
3350 Util.FireAndForget(delegate 3357
3351 { 3358 m_scene.SceneGridService.SendCloseChildAgentConnections(ControllingClient.AgentId, byebyeRegions);
3352 m_scene.SceneGridService.SendCloseChildAgentConnections(ControllingClient.AgentId, byebyeRegions);
3353 });
3354 } 3359 }
3355 3360
3356 foreach (ulong handle in byebyeRegions) 3361 foreach (ulong handle in byebyeRegions)
@@ -3693,7 +3698,8 @@ namespace OpenSim.Region.Framework.Scenes
3693 3698
3694// if (m_updateCount > 0) 3699// if (m_updateCount > 0)
3695// { 3700// {
3696 Animator.UpdateMovementAnimations(); 3701 if (Animator.UpdateMovementAnimations())
3702 TriggerScenePresenceUpdated();
3697// m_updateCount--; 3703// m_updateCount--;
3698// } 3704// }
3699 3705
diff --git a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
index 5398ab9..bf32251 100644
--- a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
+++ b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
@@ -290,6 +290,9 @@ namespace OpenSim.Region.Framework.Scenes
290 290
291 private void statsHeartBeat(object sender, EventArgs e) 291 private void statsHeartBeat(object sender, EventArgs e)
292 { 292 {
293 if (!m_scene.Active)
294 return;
295
293 SimStatsPacket.StatBlock[] sb = new SimStatsPacket.StatBlock[23]; 296 SimStatsPacket.StatBlock[] sb = new SimStatsPacket.StatBlock[23];
294 SimStatsPacket.RegionBlock rb = new SimStatsPacket.RegionBlock(); 297 SimStatsPacket.RegionBlock rb = new SimStatsPacket.RegionBlock();
295 298
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs
index 52ad538..d670dad 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs
@@ -33,7 +33,9 @@ using NUnit.Framework;
33using OpenMetaverse; 33using OpenMetaverse;
34using OpenSim.Framework; 34using OpenSim.Framework;
35using OpenSim.Framework.Communications; 35using OpenSim.Framework.Communications;
36using OpenSim.Region.CoreModules.Framework.EntityTransfer;
36using OpenSim.Region.CoreModules.Framework.InventoryAccess; 37using OpenSim.Region.CoreModules.Framework.InventoryAccess;
38using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation;
37using OpenSim.Region.CoreModules.World.Permissions; 39using OpenSim.Region.CoreModules.World.Permissions;
38using OpenSim.Region.Framework.Scenes; 40using OpenSim.Region.Framework.Scenes;
39using OpenSim.Services.Interfaces; 41using OpenSim.Services.Interfaces;
@@ -52,6 +54,24 @@ namespace OpenSim.Region.Framework.Scenes.Tests
52 [TestFixture] 54 [TestFixture]
53 public class SceneObjectDeRezTests : OpenSimTestCase 55 public class SceneObjectDeRezTests : OpenSimTestCase
54 { 56 {
57 [TestFixtureSetUp]
58 public void FixtureInit()
59 {
60 // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
61 // This facility was added after the original async delete tests were written, so it may be possible now
62 // to not bother explicitly disabling their async (since everything will be running sync).
63 Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest;
64 }
65
66 [TestFixtureTearDown]
67 public void TearDown()
68 {
69 // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
70 // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression
71 // tests really shouldn't).
72 Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
73 }
74
55 /// <summary> 75 /// <summary>
56 /// Test deleting an object from a scene. 76 /// Test deleting an object from a scene.
57 /// </summary> 77 /// </summary>
@@ -59,46 +79,96 @@ namespace OpenSim.Region.Framework.Scenes.Tests
59 public void TestDeRezSceneObject() 79 public void TestDeRezSceneObject()
60 { 80 {
61 TestHelpers.InMethod(); 81 TestHelpers.InMethod();
62// log4net.Config.XmlConfigurator.Configure();
63 82
64 UUID userId = UUID.Parse("10000000-0000-0000-0000-000000000001"); 83 UUID userId = UUID.Parse("10000000-0000-0000-0000-000000000001");
65 84
66 TestScene scene = new SceneHelpers().SetupScene(); 85 TestScene scene = new SceneHelpers().SetupScene();
67 IConfigSource configSource = new IniConfigSource(); 86 SceneHelpers.SetupSceneModules(scene, new PermissionsModule());
68 IConfig config = configSource.AddConfig("Startup"); 87 TestClient client = (TestClient)SceneHelpers.AddScenePresence(scene, userId).ControllingClient;
69 config.Set("serverside_object_permissions", true);
70 SceneHelpers.SetupSceneModules(scene, configSource, new object[] { new PermissionsModule() });
71 IClientAPI client = SceneHelpers.AddScenePresence(scene, userId).ControllingClient;
72 88
73 // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. 89 // Turn off the timer on the async sog deleter - we'll crank it by hand for this test.
74 AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter; 90 AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter;
75 sogd.Enabled = false; 91 sogd.Enabled = false;
76 92
77 SceneObjectPart part 93 SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, "so1", userId);
78 = new SceneObjectPart(userId, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero); 94 uint soLocalId = so.LocalId;
79 part.Name = "obj1";
80 scene.AddNewSceneObject(new SceneObjectGroup(part), false);
81 95
82 List<uint> localIds = new List<uint>(); 96 List<uint> localIds = new List<uint>();
83 localIds.Add(part.LocalId); 97 localIds.Add(so.LocalId);
84 scene.DeRezObjects(client, localIds, UUID.Zero, DeRezAction.Delete, UUID.Zero); 98 scene.DeRezObjects(client, localIds, UUID.Zero, DeRezAction.Delete, UUID.Zero);
85 99
86 // Check that object isn't deleted until we crank the sogd handle. 100 // Check that object isn't deleted until we crank the sogd handle.
87 SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId); 101 SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId);
88 Assert.That(retrievedPart, Is.Not.Null); 102 Assert.That(retrievedPart, Is.Not.Null);
89 Assert.That(retrievedPart.ParentGroup.IsDeleted, Is.False); 103 Assert.That(retrievedPart.ParentGroup.IsDeleted, Is.False);
90 104
91 sogd.InventoryDeQueueAndDelete(); 105 sogd.InventoryDeQueueAndDelete();
92 106
93 SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(part.LocalId); 107 SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId);
94 Assert.That(retrievedPart2, Is.Null); 108 Assert.That(retrievedPart2, Is.Null);
109
110 Assert.That(client.ReceivedKills.Count, Is.EqualTo(1));
111 Assert.That(client.ReceivedKills[0], Is.EqualTo(soLocalId));
112 }
113
114 /// <summary>
115 /// Test that child and root agents correctly receive KillObject notifications.
116 /// </summary>
117 [Test]
118 public void TestDeRezSceneObjectToAgents()
119 {
120 TestHelpers.InMethod();
121// TestHelpers.EnableLogging();
122
123 SceneHelpers sh = new SceneHelpers();
124 TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000);
125 TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1000, 999);
126
127 // We need this so that the creation of the root client for userB in sceneB can trigger the creation of a child client in sceneA
128 LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule();
129 EntityTransferModule etmB = new EntityTransferModule();
130 IConfigSource config = new IniConfigSource();
131 IConfig modulesConfig = config.AddConfig("Modules");
132 modulesConfig.Set("EntityTransferModule", etmB.Name);
133 modulesConfig.Set("SimulationServices", lscm.Name);
134 SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm);
135 SceneHelpers.SetupSceneModules(sceneB, config, etmB);
136
137 // We need this for derez
138 SceneHelpers.SetupSceneModules(sceneA, new PermissionsModule());
139
140 UserAccount uaA = UserAccountHelpers.CreateUserWithInventory(sceneA, "Andy", "AAA", 0x1, "");
141 UserAccount uaB = UserAccountHelpers.CreateUserWithInventory(sceneA, "Brian", "BBB", 0x2, "");
142
143 TestClient clientA = (TestClient)SceneHelpers.AddScenePresence(sceneA, uaA).ControllingClient;
144
145 // This is the more long-winded route we have to take to get a child client created for userB in sceneA
146 // rather than just calling AddScenePresence() as for userA
147 AgentCircuitData acd = SceneHelpers.GenerateAgentData(uaB);
148 TestClient clientB = new TestClient(acd, sceneB);
149 List<TestClient> childClientsB = new List<TestClient>();
150 EntityTransferHelpers.SetUpInformClientOfNeighbour(clientB, childClientsB);
151
152 SceneHelpers.AddScenePresence(sceneB, clientB, acd);
153
154 SceneObjectGroup so = SceneHelpers.AddSceneObject(sceneA);
155 uint soLocalId = so.LocalId;
156
157 sceneA.DeleteSceneObject(so, false);
158
159 Assert.That(clientA.ReceivedKills.Count, Is.EqualTo(1));
160 Assert.That(clientA.ReceivedKills[0], Is.EqualTo(soLocalId));
161
162 Assert.That(childClientsB[0].ReceivedKills.Count, Is.EqualTo(1));
163 Assert.That(childClientsB[0].ReceivedKills[0], Is.EqualTo(soLocalId));
95 } 164 }
96 165
97 /// <summary> 166 /// <summary>
98 /// Test deleting an object from a scene where the deleter is not the owner 167 /// Test deleting an object from a scene where the deleter is not the owner
99 /// </summary> 168 /// </summary>
100 /// 169 /// <remarks>
101 /// This test assumes that the deleter is not a god. 170 /// This test assumes that the deleter is not a god.
171 /// </remarks>
102 [Test] 172 [Test]
103 public void TestDeRezSceneObjectNotOwner() 173 public void TestDeRezSceneObjectNotOwner()
104 { 174 {
@@ -109,10 +179,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
109 UUID objectOwnerId = UUID.Parse("20000000-0000-0000-0000-000000000001"); 179 UUID objectOwnerId = UUID.Parse("20000000-0000-0000-0000-000000000001");
110 180
111 TestScene scene = new SceneHelpers().SetupScene(); 181 TestScene scene = new SceneHelpers().SetupScene();
112 IConfigSource configSource = new IniConfigSource(); 182 SceneHelpers.SetupSceneModules(scene, new PermissionsModule());
113 IConfig config = configSource.AddConfig("Startup");
114 config.Set("serverside_object_permissions", true);
115 SceneHelpers.SetupSceneModules(scene, configSource, new object[] { new PermissionsModule() });
116 IClientAPI client = SceneHelpers.AddScenePresence(scene, userId).ControllingClient; 183 IClientAPI client = SceneHelpers.AddScenePresence(scene, userId).ControllingClient;
117 184
118 // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. 185 // Turn off the timer on the async sog deleter - we'll crank it by hand for this test.
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs
index 8775949..5a72239 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs
@@ -95,11 +95,11 @@ namespace OpenSim.Region.Framework.Scenes.Tests
95 SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), etmB); 95 SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), etmB);
96 96
97 AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId); 97 AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId);
98 TestClient tc = new TestClient(acd, sceneA, sh.SceneManager); 98 TestClient tc = new TestClient(acd, sceneA);
99 List<TestClient> destinationTestClients = new List<TestClient>(); 99 List<TestClient> destinationTestClients = new List<TestClient>();
100 EntityTransferHelpers.SetUpInformClientOfNeighbour(tc, destinationTestClients); 100 EntityTransferHelpers.SetUpInformClientOfNeighbour(tc, destinationTestClients);
101 101
102 ScenePresence originalSp = SceneHelpers.AddScenePresence(sceneA, tc, acd, sh.SceneManager); 102 ScenePresence originalSp = SceneHelpers.AddScenePresence(sceneA, tc, acd);
103 originalSp.AbsolutePosition = new Vector3(128, 32, 10); 103 originalSp.AbsolutePosition = new Vector3(128, 32, 10);
104 104
105// originalSp.Flying = true; 105// originalSp.Flying = true;
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs
index de4458d..297c66b 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs
@@ -139,7 +139,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
139 Vector3 teleportPosition = new Vector3(10, 11, 12); 139 Vector3 teleportPosition = new Vector3(10, 11, 12);
140 Vector3 teleportLookAt = new Vector3(20, 21, 22); 140 Vector3 teleportLookAt = new Vector3(20, 21, 22);
141 141
142 ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); 142 ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId);
143 sp.AbsolutePosition = new Vector3(30, 31, 32); 143 sp.AbsolutePosition = new Vector3(30, 31, 32);
144 144
145 List<TestClient> destinationTestClients = new List<TestClient>(); 145 List<TestClient> destinationTestClients = new List<TestClient>();
@@ -224,7 +224,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
224 Vector3 teleportPosition = new Vector3(10, 11, 12); 224 Vector3 teleportPosition = new Vector3(10, 11, 12);
225 Vector3 teleportLookAt = new Vector3(20, 21, 22); 225 Vector3 teleportLookAt = new Vector3(20, 21, 22);
226 226
227 ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); 227 ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId);
228 sp.AbsolutePosition = preTeleportPosition; 228 sp.AbsolutePosition = preTeleportPosition;
229 229
230 // Make sceneB return false on query access 230 // Make sceneB return false on query access
@@ -300,7 +300,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
300 Vector3 teleportPosition = new Vector3(10, 11, 12); 300 Vector3 teleportPosition = new Vector3(10, 11, 12);
301 Vector3 teleportLookAt = new Vector3(20, 21, 22); 301 Vector3 teleportLookAt = new Vector3(20, 21, 22);
302 302
303 ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); 303 ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId);
304 sp.AbsolutePosition = preTeleportPosition; 304 sp.AbsolutePosition = preTeleportPosition;
305 305
306 // Make sceneB refuse CreateAgent 306 // Make sceneB refuse CreateAgent
@@ -389,7 +389,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
389 Vector3 teleportPosition = new Vector3(10, 11, 12); 389 Vector3 teleportPosition = new Vector3(10, 11, 12);
390 Vector3 teleportLookAt = new Vector3(20, 21, 22); 390 Vector3 teleportLookAt = new Vector3(20, 21, 22);
391 391
392 ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); 392 ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId);
393 sp.AbsolutePosition = preTeleportPosition; 393 sp.AbsolutePosition = preTeleportPosition;
394 394
395 sceneA.RequestTeleportLocation( 395 sceneA.RequestTeleportLocation(
@@ -428,7 +428,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
428 public void TestSameSimulatorNeighbouringRegions() 428 public void TestSameSimulatorNeighbouringRegions()
429 { 429 {
430 TestHelpers.InMethod(); 430 TestHelpers.InMethod();
431 TestHelpers.EnableLogging(); 431// TestHelpers.EnableLogging();
432 432
433 UUID userId = TestHelpers.ParseTail(0x1); 433 UUID userId = TestHelpers.ParseTail(0x1);
434 434
@@ -458,11 +458,11 @@ namespace OpenSim.Region.Framework.Scenes.Tests
458 Vector3 teleportLookAt = new Vector3(20, 21, 22); 458 Vector3 teleportLookAt = new Vector3(20, 21, 22);
459 459
460 AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId); 460 AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId);
461 TestClient tc = new TestClient(acd, sceneA, sh.SceneManager); 461 TestClient tc = new TestClient(acd, sceneA);
462 List<TestClient> destinationTestClients = new List<TestClient>(); 462 List<TestClient> destinationTestClients = new List<TestClient>();
463 EntityTransferHelpers.SetUpInformClientOfNeighbour(tc, destinationTestClients); 463 EntityTransferHelpers.SetUpInformClientOfNeighbour(tc, destinationTestClients);
464 464
465 ScenePresence beforeSceneASp = SceneHelpers.AddScenePresence(sceneA, tc, acd, sh.SceneManager); 465 ScenePresence beforeSceneASp = SceneHelpers.AddScenePresence(sceneA, tc, acd);
466 beforeSceneASp.AbsolutePosition = new Vector3(30, 31, 32); 466 beforeSceneASp.AbsolutePosition = new Vector3(30, 31, 32);
467 467
468 Assert.That(beforeSceneASp, Is.Not.Null); 468 Assert.That(beforeSceneASp, Is.Not.Null);
diff --git a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs
index b09ae39..7b47275 100644
--- a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs
+++ b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs
@@ -34,6 +34,7 @@ using System.Threading;
34using log4net; 34using log4net;
35using OpenMetaverse; 35using OpenMetaverse;
36using OpenMetaverse.Assets; 36using OpenMetaverse.Assets;
37using OpenMetaverse.StructuredData;
37using OpenSim.Framework; 38using OpenSim.Framework;
38using OpenSim.Region.Framework.Scenes.Serialization; 39using OpenSim.Region.Framework.Scenes.Serialization;
39using OpenSim.Services.Interfaces; 40using OpenSim.Services.Interfaces;
@@ -180,6 +181,9 @@ namespace OpenSim.Region.Framework.Scenes
180 if (!assetUuids.ContainsKey(tii.AssetID)) 181 if (!assetUuids.ContainsKey(tii.AssetID))
181 GatherAssetUuids(tii.AssetID, (AssetType)tii.Type, assetUuids); 182 GatherAssetUuids(tii.AssetID, (AssetType)tii.Type, assetUuids);
182 } 183 }
184
185 // get any texture UUIDs used for materials such as normal and specular maps
186 GatherMaterialsUuids(part, assetUuids);
183 } 187 }
184 catch (Exception e) 188 catch (Exception e)
185 { 189 {
@@ -204,6 +208,68 @@ namespace OpenSim.Region.Framework.Scenes
204// } 208// }
205// } 209// }
206 210
211
212 /// <summary>
213 /// Gather all of the texture asset UUIDs used to reference "Materials" such as normal and specular maps
214 /// </summary>
215 /// <param name="part"></param>
216 /// <param name="assetUuids"></param>
217 public void GatherMaterialsUuids(SceneObjectPart part, IDictionary<UUID, AssetType> assetUuids)
218 {
219 // scan thru the dynAttrs map of this part for any textures used as materials
220 OSDMap OSMaterials = null;
221
222 lock (part.DynAttrs)
223 {
224 if (part.DynAttrs.ContainsKey("OS:Materials"))
225 OSMaterials = part.DynAttrs["OS:Materials"];
226 if (OSMaterials != null && OSMaterials.ContainsKey("Materials"))
227 {
228 OSD osd = OSMaterials["Materials"];
229 //m_log.Info("[UUID Gatherer]: found Materials: " + OSDParser.SerializeJsonString(osd));
230
231 if (osd is OSDArray)
232 {
233 OSDArray matsArr = osd as OSDArray;
234 foreach (OSDMap matMap in matsArr)
235 {
236 try
237 {
238 if (matMap.ContainsKey("Material"))
239 {
240 OSDMap mat = matMap["Material"] as OSDMap;
241 if (mat.ContainsKey("NormMap"))
242 {
243 UUID normalMapId = mat["NormMap"].AsUUID();
244 if (normalMapId != UUID.Zero)
245 {
246 assetUuids[normalMapId] = AssetType.Texture;
247 //m_log.Info("[UUID Gatherer]: found normal map ID: " + normalMapId.ToString());
248 }
249 }
250 if (mat.ContainsKey("SpecMap"))
251 {
252 UUID specularMapId = mat["SpecMap"].AsUUID();
253 if (specularMapId != UUID.Zero)
254 {
255 assetUuids[specularMapId] = AssetType.Texture;
256 //m_log.Info("[UUID Gatherer]: found specular map ID: " + specularMapId.ToString());
257 }
258 }
259 }
260
261 }
262 catch (Exception e)
263 {
264 m_log.Warn("[UUID Gatherer]: exception getting materials: " + e.Message);
265 }
266 }
267 }
268 }
269 }
270 }
271
272
207 /// <summary> 273 /// <summary>
208 /// Get an asset synchronously, potentially using an asynchronous callback. If the 274 /// Get an asset synchronously, potentially using an asynchronous callback. If the
209 /// asynchronous callback is used, we will wait for it to complete. 275 /// asynchronous callback is used, we will wait for it to complete.
diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
index dd72cfb..b28d96b 100644
--- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
+++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
@@ -660,6 +660,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
660 public event BakeTerrain OnBakeTerrain; 660 public event BakeTerrain OnBakeTerrain;
661 public event EstateChangeInfo OnEstateChangeInfo; 661 public event EstateChangeInfo OnEstateChangeInfo;
662 public event EstateManageTelehub OnEstateManageTelehub; 662 public event EstateManageTelehub OnEstateManageTelehub;
663 public event CachedTextureRequest OnCachedTextureRequest;
663 public event SetAppearance OnSetAppearance; 664 public event SetAppearance OnSetAppearance;
664 public event AvatarNowWearing OnAvatarNowWearing; 665 public event AvatarNowWearing OnAvatarNowWearing;
665 public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv; 666 public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv;
@@ -943,13 +944,18 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
943 { 944 {
944 945
945 } 946 }
947
948 public void SendCachedTextureResponse(ISceneEntity avatar, int serial, List<CachedTextureResponseArg> cachedTextures)
949 {
946 950
951 }
952
947 public void SendStartPingCheck(byte seq) 953 public void SendStartPingCheck(byte seq)
948 { 954 {
949 955
950 } 956 }
951 957
952 public void SendKillObject(ulong regionHandle, List<uint> localID) 958 public void SendKillObject(List<uint> localID)
953 { 959 {
954 960
955 } 961 }
diff --git a/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs b/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs
index 018357a..c48e585 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs
@@ -375,11 +375,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Concierge
375 scene.GetRootAgentCount(), scene.RegionInfo.RegionName, 375 scene.GetRootAgentCount(), scene.RegionInfo.RegionName,
376 scene.RegionInfo.RegionID, 376 scene.RegionInfo.RegionID,
377 DateTime.UtcNow.ToString("s"))); 377 DateTime.UtcNow.ToString("s")));
378
378 scene.ForEachRootScenePresence(delegate(ScenePresence sp) 379 scene.ForEachRootScenePresence(delegate(ScenePresence sp)
379 { 380 {
380 list.Append(String.Format(" <avatar name=\"{0}\" uuid=\"{1}\" />\n", sp.Name, sp.UUID)); 381 list.Append(String.Format(" <avatar name=\"{0}\" uuid=\"{1}\" />\n", sp.Name, sp.UUID));
381 list.Append("</avatars>");
382 }); 382 });
383
384 list.Append("</avatars>");
383 string payload = list.ToString(); 385 string payload = list.ToString();
384 386
385 // post via REST to broker 387 // post via REST to broker
diff --git a/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs b/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs
index e756c70..2f07c42 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs
@@ -117,6 +117,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
117 117
118 private IConfig m_config; 118 private IConfig m_config;
119 119
120 private object m_Lock;
121
120 public void Initialise(IConfigSource config) 122 public void Initialise(IConfigSource config)
121 { 123 {
122 124
@@ -128,6 +130,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
128 if (!m_config.GetBoolean("enabled", false)) 130 if (!m_config.GetBoolean("enabled", false))
129 return; 131 return;
130 132
133 m_Lock = new object();
134
131 try 135 try
132 { 136 {
133 // retrieve configuration variables 137 // retrieve configuration variables
@@ -837,7 +841,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
837 requrl = String.Format("{0}&chan_roll_off={1}", requrl, m_vivoxChannelRollOff); 841 requrl = String.Format("{0}&chan_roll_off={1}", requrl, m_vivoxChannelRollOff);
838 requrl = String.Format("{0}&chan_dist_model={1}", requrl, m_vivoxChannelDistanceModel); 842 requrl = String.Format("{0}&chan_dist_model={1}", requrl, m_vivoxChannelDistanceModel);
839 requrl = String.Format("{0}&chan_max_range={1}", requrl, m_vivoxChannelMaximumRange); 843 requrl = String.Format("{0}&chan_max_range={1}", requrl, m_vivoxChannelMaximumRange);
840 requrl = String.Format("{0}&chan_ckamping_distance={1}", requrl, m_vivoxChannelClampingDistance); 844 requrl = String.Format("{0}&chan_clamping_distance={1}", requrl, m_vivoxChannelClampingDistance);
841 845
842 XmlElement resp = VivoxCall(requrl, true); 846 XmlElement resp = VivoxCall(requrl, true);
843 if (XmlFind(resp, "response.level0.body.chan_uri", out channelUri)) 847 if (XmlFind(resp, "response.level0.body.chan_uri", out channelUri))
@@ -1118,25 +1122,32 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
1118 1122
1119 doc = new XmlDocument(); 1123 doc = new XmlDocument();
1120 1124
1121 try 1125 // Let's serialize all calls to Vivox. Most of these are driven by
1126 // the clients (CAPs), when the user arrives at the region. We don't
1127 // want to issue many simultaneous http requests to Vivox, because mono
1128 // doesn't like that
1129 lock (m_Lock)
1122 { 1130 {
1123 // Otherwise prepare the request 1131 try
1124// m_log.DebugFormat("[VivoxVoice] Sending request <{0}>", requrl); 1132 {
1133 // Otherwise prepare the request
1134 //m_log.DebugFormat("[VivoxVoice] Sending request <{0}>", requrl);
1125 1135
1126 HttpWebRequest req = (HttpWebRequest)WebRequest.Create(requrl); 1136 HttpWebRequest req = (HttpWebRequest)WebRequest.Create(requrl);
1127 1137
1128 // We are sending just parameters, no content 1138 // We are sending just parameters, no content
1129 req.ContentLength = 0; 1139 req.ContentLength = 0;
1130 1140
1131 // Send request and retrieve the response 1141 // Send request and retrieve the response
1132 using (HttpWebResponse rsp = (HttpWebResponse)req.GetResponse()) 1142 using (HttpWebResponse rsp = (HttpWebResponse)req.GetResponse())
1133 using (Stream s = rsp.GetResponseStream()) 1143 using (Stream s = rsp.GetResponseStream())
1134 using (XmlTextReader rdr = new XmlTextReader(s)) 1144 using (XmlTextReader rdr = new XmlTextReader(s))
1135 doc.Load(rdr); 1145 doc.Load(rdr);
1136 } 1146 }
1137 catch (Exception e) 1147 catch (Exception e)
1138 { 1148 {
1139 m_log.ErrorFormat("[VivoxVoice] Error in admin call : {0}", e.Message); 1149 m_log.ErrorFormat("[VivoxVoice] Error in admin call : {0}", e.Message);
1150 }
1140 } 1151 }
1141 1152
1142 // If we're debugging server responses, dump the whole 1153 // If we're debugging server responses, dump the whole
diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs
new file mode 100644
index 0000000..4ab6609
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs
@@ -0,0 +1,579 @@
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.Security.Cryptography; // for computing md5 hash
33using log4net;
34using Mono.Addins;
35using Nini.Config;
36
37using OpenMetaverse;
38using OpenMetaverse.StructuredData;
39
40using OpenSim.Framework;
41using OpenSim.Framework.Servers;
42using OpenSim.Framework.Servers.HttpServer;
43using OpenSim.Region.Framework.Interfaces;
44using OpenSim.Region.Framework.Scenes;
45
46using Ionic.Zlib;
47
48// You will need to uncomment these lines if you are adding a region module to some other assembly which does not already
49// specify its assembly. Otherwise, the region modules in the assembly will not be picked up when OpenSimulator scans
50// the available DLLs
51//[assembly: Addin("MaterialsDemoModule", "1.0")]
52//[assembly: AddinDependency("OpenSim", "0.5")]
53
54namespace OpenSim.Region.OptionalModules.MaterialsDemoModule
55{
56 /// <summary>
57 ///
58 // # # ## ##### # # # # # ####
59 // # # # # # # ## # # ## # # #
60 // # # # # # # # # # # # # # #
61 // # ## # ###### ##### # # # # # # # # ###
62 // ## ## # # # # # ## # # ## # #
63 // # # # # # # # # # # # ####
64 //
65 // THIS MODULE IS FOR EXPERIMENTAL USE ONLY AND MAY CAUSE REGION OR ASSET CORRUPTION!
66 //
67 ////////////// WARNING //////////////////////////////////////////////////////////////////
68 /// This is an *Experimental* module for developing support for materials-capable viewers
69 /// This module should NOT be used in a production environment! It may cause data corruption and
70 /// viewer crashes. It should be only used to evaluate implementations of materials.
71 ///
72 /// Materials are persisted via SceneObjectPart.dynattrs. This is a relatively new feature
73 /// of OpenSimulator and is not field proven at the time this module was written. Persistence
74 /// may fail or become corrupt and this could cause viewer crashes due to erroneous materials
75 /// data being sent to viewers. Materials descriptions might survive IAR, OAR, or other means
76 /// of archiving however the texture resources used by these materials probably will not as they
77 /// may not be adequately referenced to ensure proper archiving.
78 ///
79 ///
80 ///
81 /// To enable this module, add this string at the bottom of OpenSim.ini:
82 /// [MaterialsDemoModule]
83 ///
84 /// </summary>
85 ///
86
87 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "MaterialsDemoModule")]
88 public class MaterialsDemoModule : INonSharedRegionModule
89 {
90 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
91
92 public string Name { get { return "MaterialsDemoModule"; } }
93
94 public Type ReplaceableInterface { get { return null; } }
95
96 private Scene m_scene = null;
97 private bool m_enabled = false;
98
99 public Dictionary<UUID, OSDMap> m_knownMaterials = new Dictionary<UUID, OSDMap>();
100
101 public void Initialise(IConfigSource source)
102 {
103 m_enabled = (source.Configs["MaterialsDemoModule"] != null);
104 if (!m_enabled)
105 return;
106
107 m_log.DebugFormat("[MaterialsDemoModule]: INITIALIZED MODULE");
108 }
109
110 public void Close()
111 {
112 if (!m_enabled)
113 return;
114
115 m_log.DebugFormat("[MaterialsDemoModule]: CLOSED MODULE");
116 }
117
118 public void AddRegion(Scene scene)
119 {
120 if (!m_enabled)
121 return;
122
123 m_log.DebugFormat("[MaterialsDemoModule]: REGION {0} ADDED", scene.RegionInfo.RegionName);
124 m_scene = scene;
125 m_scene.EventManager.OnRegisterCaps += new EventManager.RegisterCapsEvent(OnRegisterCaps);
126 m_scene.EventManager.OnObjectAddedToScene += new Action<SceneObjectGroup>(EventManager_OnObjectAddedToScene);
127 }
128
129 void EventManager_OnObjectAddedToScene(SceneObjectGroup obj)
130 {
131 foreach (var part in obj.Parts)
132 if (part != null)
133 GetStoredMaterialsForPart(part);
134 }
135
136 void OnRegisterCaps(OpenMetaverse.UUID agentID, OpenSim.Framework.Capabilities.Caps caps)
137 {
138 string capsBase = "/CAPS/" + caps.CapsObjectPath;
139
140 IRequestHandler renderMaterialsPostHandler = new RestStreamHandler("POST", capsBase + "/", RenderMaterialsPostCap);
141 caps.RegisterHandler("RenderMaterials", renderMaterialsPostHandler);
142
143 // OpenSimulator CAPs infrastructure seems to be somewhat hostile towards any CAP that requires both GET
144 // and POST handlers, (at least at the time this was originally written), so we first set up a POST
145 // handler normally and then add a GET handler via MainServer
146
147 IRequestHandler renderMaterialsGetHandler = new RestStreamHandler("GET", capsBase + "/", RenderMaterialsGetCap);
148 MainServer.Instance.AddStreamHandler(renderMaterialsGetHandler);
149
150 // materials viewer seems to use either POST or PUT, so assign POST handler for PUT as well
151 IRequestHandler renderMaterialsPutHandler = new RestStreamHandler("PUT", capsBase + "/", RenderMaterialsPostCap);
152 MainServer.Instance.AddStreamHandler(renderMaterialsPutHandler);
153 }
154
155 public void RemoveRegion(Scene scene)
156 {
157 if (!m_enabled)
158 return;
159
160 m_log.DebugFormat("[MaterialsDemoModule]: REGION {0} REMOVED", scene.RegionInfo.RegionName);
161 }
162
163 public void RegionLoaded(Scene scene)
164 {
165 }
166
167 OSDMap GetMaterial(UUID id)
168 {
169 OSDMap map = null;
170 if (m_knownMaterials.ContainsKey(id))
171 {
172 map = new OSDMap();
173 map["ID"] = OSD.FromBinary(id.GetBytes());
174 map["Material"] = m_knownMaterials[id];
175 }
176 return map;
177 }
178
179 void GetStoredMaterialsForPart(SceneObjectPart part)
180 {
181 OSDMap OSMaterials = null;
182 OSDArray matsArr = null;
183
184 if (part.DynAttrs == null)
185 {
186 m_log.Warn("[MaterialsDemoModule]: NULL DYNATTRS :( ");
187 }
188
189 lock (part.DynAttrs)
190 {
191 if (part.DynAttrs.ContainsKey("OS:Materials"))
192 OSMaterials = part.DynAttrs["OS:Materials"];
193 if (OSMaterials != null && OSMaterials.ContainsKey("Materials"))
194 {
195
196 OSD osd = OSMaterials["Materials"];
197 if (osd is OSDArray)
198 matsArr = osd as OSDArray;
199 }
200 }
201
202 if (OSMaterials == null)
203 return;
204
205 m_log.Info("[MaterialsDemoModule]: OSMaterials: " + OSDParser.SerializeJsonString(OSMaterials));
206
207
208 if (matsArr == null)
209 {
210 m_log.Info("[MaterialsDemoModule]: matsArr is null :( ");
211 return;
212 }
213
214 foreach (OSD elemOsd in matsArr)
215 {
216 if (elemOsd != null && elemOsd is OSDMap)
217 {
218
219 OSDMap matMap = elemOsd as OSDMap;
220 if (matMap.ContainsKey("ID") && matMap.ContainsKey("Material"))
221 {
222 try
223 {
224 m_knownMaterials[matMap["ID"].AsUUID()] = (OSDMap)matMap["Material"];
225 }
226 catch (Exception e)
227 {
228 m_log.Warn("[MaterialsDemoModule]: exception decoding persisted material: " + e.ToString());
229 }
230 }
231 }
232 }
233 }
234
235
236 void StoreMaterialsForPart(SceneObjectPart part)
237 {
238 try
239 {
240 if (part == null || part.Shape == null)
241 return;
242
243 Dictionary<UUID, OSDMap> mats = new Dictionary<UUID, OSDMap>();
244
245 Primitive.TextureEntry te = part.Shape.Textures;
246
247 if (te.DefaultTexture != null)
248 {
249 if (m_knownMaterials.ContainsKey(te.DefaultTexture.MaterialID))
250 mats[te.DefaultTexture.MaterialID] = m_knownMaterials[te.DefaultTexture.MaterialID];
251 }
252
253 if (te.FaceTextures != null)
254 {
255 foreach (var face in te.FaceTextures)
256 {
257 if (face != null)
258 {
259 if (m_knownMaterials.ContainsKey(face.MaterialID))
260 mats[face.MaterialID] = m_knownMaterials[face.MaterialID];
261 }
262 }
263 }
264 if (mats.Count == 0)
265 return;
266
267 OSDArray matsArr = new OSDArray();
268 foreach (KeyValuePair<UUID, OSDMap> kvp in mats)
269 {
270 OSDMap matOsd = new OSDMap();
271 matOsd["ID"] = OSD.FromUUID(kvp.Key);
272 matOsd["Material"] = kvp.Value;
273 matsArr.Add(matOsd);
274 }
275
276 OSDMap OSMaterials = new OSDMap();
277 OSMaterials["Materials"] = matsArr;
278
279 lock (part.DynAttrs)
280 part.DynAttrs["OS:Materials"] = OSMaterials;
281 }
282 catch (Exception e)
283 {
284 m_log.Warn("[MaterialsDemoModule]: exception in StoreMaterialsForPart(): " + e.ToString());
285 }
286 }
287
288
289 public string RenderMaterialsPostCap(string request, string path,
290 string param, IOSHttpRequest httpRequest,
291 IOSHttpResponse httpResponse)
292 {
293 m_log.Debug("[MaterialsDemoModule]: POST cap handler");
294
295 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
296 OSDMap resp = new OSDMap();
297
298 OSDMap materialsFromViewer = null;
299
300 OSDArray respArr = new OSDArray();
301
302 if (req.ContainsKey("Zipped"))
303 {
304 OSD osd = null;
305
306 byte[] inBytes = req["Zipped"].AsBinary();
307
308 try
309 {
310 osd = ZDecompressBytesToOsd(inBytes);
311
312 if (osd != null)
313 {
314 if (osd is OSDArray) // assume array of MaterialIDs designating requested material entries
315 {
316 foreach (OSD elem in (OSDArray)osd)
317 {
318
319 try
320 {
321 UUID id = new UUID(elem.AsBinary(), 0);
322
323 if (m_knownMaterials.ContainsKey(id))
324 {
325 m_log.Info("[MaterialsDemoModule]: request for known material ID: " + id.ToString());
326 OSDMap matMap = new OSDMap();
327 matMap["ID"] = OSD.FromBinary(id.GetBytes());
328
329 matMap["Material"] = m_knownMaterials[id];
330 respArr.Add(matMap);
331 }
332 else
333 m_log.Info("[MaterialsDemoModule]: request for UNKNOWN material ID: " + id.ToString());
334 }
335 catch (Exception e)
336 {
337 // report something here?
338 continue;
339 }
340 }
341 }
342 else if (osd is OSDMap) // reqest to assign a material
343 {
344 materialsFromViewer = osd as OSDMap;
345
346 if (materialsFromViewer.ContainsKey("FullMaterialsPerFace"))
347 {
348 OSD matsOsd = materialsFromViewer["FullMaterialsPerFace"];
349 if (matsOsd is OSDArray)
350 {
351 OSDArray matsArr = matsOsd as OSDArray;
352
353 try
354 {
355 foreach (OSDMap matsMap in matsArr)
356 {
357 m_log.Debug("[MaterialsDemoModule]: processing matsMap: " + OSDParser.SerializeJsonString(matsMap));
358
359 uint matLocalID = 0;
360 try { matLocalID = matsMap["ID"].AsUInteger(); }
361 catch (Exception e) { m_log.Warn("[MaterialsDemoModule]: cannot decode \"ID\" from matsMap: " + e.Message); }
362 m_log.Debug("[MaterialsDemoModule]: matLocalId: " + matLocalID.ToString());
363
364
365 OSDMap mat = null;
366 try { mat = matsMap["Material"] as OSDMap; }
367 catch (Exception e) { m_log.Warn("[MaterialsDemoModule]: cannot decode \"Material\" from matsMap: " + e.Message); }
368 m_log.Debug("[MaterialsDemoModule]: mat: " + OSDParser.SerializeJsonString(mat));
369
370 UUID id = HashOsd(mat);
371 m_knownMaterials[id] = mat;
372
373
374 var sop = m_scene.GetSceneObjectPart(matLocalID);
375 if (sop == null)
376 m_log.Debug("[MaterialsDemoModule]: null SOP for localId: " + matLocalID.ToString());
377 else
378 {
379 //var te = sop.Shape.Textures;
380 var te = new Primitive.TextureEntry(sop.Shape.TextureEntry, 0, sop.Shape.TextureEntry.Length);
381
382 if (te == null)
383 {
384 m_log.Debug("[MaterialsDemoModule]: null TextureEntry for localId: " + matLocalID.ToString());
385 }
386 else
387 {
388 int face = -1;
389
390 if (matsMap.ContainsKey("Face"))
391 {
392 face = matsMap["Face"].AsInteger();
393 if (te.FaceTextures == null) // && face == 0)
394 {
395 if (te.DefaultTexture == null)
396 m_log.Debug("[MaterialsDemoModule]: te.DefaultTexture is null");
397 else
398 {
399 if (te.DefaultTexture.MaterialID == null)
400 m_log.Debug("[MaterialsDemoModule]: te.DefaultTexture.MaterialID is null");
401 else
402 {
403 te.DefaultTexture.MaterialID = id;
404 }
405 }
406 }
407 else
408 {
409 if (te.FaceTextures.Length >= face - 1)
410 {
411 if (te.FaceTextures[face] == null)
412 te.DefaultTexture.MaterialID = id;
413 else
414 te.FaceTextures[face].MaterialID = id;
415 }
416 }
417 }
418 else
419 {
420 if (te.DefaultTexture != null)
421 te.DefaultTexture.MaterialID = id;
422 }
423
424 m_log.Debug("[MaterialsDemoModule]: setting material ID for face " + face.ToString() + " to " + id.ToString());
425
426 //we cant use sop.UpdateTextureEntry(te); because it filters so do it manually
427
428 if (sop.ParentGroup != null)
429 {
430 sop.Shape.TextureEntry = te.GetBytes();
431 sop.TriggerScriptChangedEvent(Changed.TEXTURE);
432 sop.UpdateFlag = UpdateRequired.FULL;
433 sop.ParentGroup.HasGroupChanged = true;
434
435 sop.ScheduleFullUpdate();
436
437 StoreMaterialsForPart(sop);
438 }
439 }
440 }
441 }
442 }
443 catch (Exception e)
444 {
445 m_log.Warn("[MaterialsDemoModule]: exception processing received material: " + e.Message);
446 }
447 }
448 }
449 }
450 }
451
452 }
453 catch (Exception e)
454 {
455 m_log.Warn("[MaterialsDemoModule]: exception decoding zipped CAP payload: " + e.Message);
456 //return "";
457 }
458 m_log.Debug("[MaterialsDemoModule]: knownMaterials.Count: " + m_knownMaterials.Count.ToString());
459 }
460
461
462 resp["Zipped"] = ZCompressOSD(respArr, false);
463 string response = OSDParser.SerializeLLSDXmlString(resp);
464
465 //m_log.Debug("[MaterialsDemoModule]: cap request: " + request);
466 m_log.Debug("[MaterialsDemoModule]: cap request (zipped portion): " + ZippedOsdBytesToString(req["Zipped"].AsBinary()));
467 m_log.Debug("[MaterialsDemoModule]: cap response: " + response);
468 return response;
469 }
470
471
472 public string RenderMaterialsGetCap(string request, string path,
473 string param, IOSHttpRequest httpRequest,
474 IOSHttpResponse httpResponse)
475 {
476 m_log.Debug("[MaterialsDemoModule]: GET cap handler");
477
478 OSDMap resp = new OSDMap();
479
480
481 int matsCount = 0;
482
483 OSDArray allOsd = new OSDArray();
484
485 foreach (KeyValuePair<UUID, OSDMap> kvp in m_knownMaterials)
486 {
487 OSDMap matMap = new OSDMap();
488
489 matMap["ID"] = OSD.FromBinary(kvp.Key.GetBytes());
490
491 matMap["Material"] = kvp.Value;
492 allOsd.Add(matMap);
493 matsCount++;
494 }
495
496
497 resp["Zipped"] = ZCompressOSD(allOsd, false);
498 m_log.Debug("[MaterialsDemoModule]: matsCount: " + matsCount.ToString());
499
500 return OSDParser.SerializeLLSDXmlString(resp);
501 }
502
503 static string ZippedOsdBytesToString(byte[] bytes)
504 {
505 try
506 {
507 return OSDParser.SerializeJsonString(ZDecompressBytesToOsd(bytes));
508 }
509 catch (Exception e)
510 {
511 return "ZippedOsdBytesToString caught an exception: " + e.ToString();
512 }
513 }
514
515 /// <summary>
516 /// computes a UUID by hashing a OSD object
517 /// </summary>
518 /// <param name="osd"></param>
519 /// <returns></returns>
520 private static UUID HashOsd(OSD osd)
521 {
522 using (var md5 = MD5.Create())
523 using (MemoryStream ms = new MemoryStream(OSDParser.SerializeLLSDBinary(osd, false)))
524 return new UUID(md5.ComputeHash(ms), 0);
525 }
526
527 public static OSD ZCompressOSD(OSD inOsd, bool useHeader)
528 {
529 OSD osd = null;
530
531 using (MemoryStream msSinkCompressed = new MemoryStream())
532 {
533 using (Ionic.Zlib.ZlibStream zOut = new Ionic.Zlib.ZlibStream(msSinkCompressed,
534 Ionic.Zlib.CompressionMode.Compress, CompressionLevel.BestCompression, true))
535 {
536 CopyStream(new MemoryStream(OSDParser.SerializeLLSDBinary(inOsd, useHeader)), zOut);
537 zOut.Close();
538 }
539
540 msSinkCompressed.Seek(0L, SeekOrigin.Begin);
541 osd = OSD.FromBinary( msSinkCompressed.ToArray());
542 }
543
544 return osd;
545 }
546
547
548 public static OSD ZDecompressBytesToOsd(byte[] input)
549 {
550 OSD osd = null;
551
552 using (MemoryStream msSinkUnCompressed = new MemoryStream())
553 {
554 using (Ionic.Zlib.ZlibStream zOut = new Ionic.Zlib.ZlibStream(msSinkUnCompressed, CompressionMode.Decompress, true))
555 {
556 CopyStream(new MemoryStream(input), zOut);
557 zOut.Close();
558 }
559 msSinkUnCompressed.Seek(0L, SeekOrigin.Begin);
560 osd = OSDParser.DeserializeLLSDBinary(msSinkUnCompressed.ToArray());
561 }
562
563 return osd;
564 }
565
566 static void CopyStream(System.IO.Stream input, System.IO.Stream output)
567 {
568 byte[] buffer = new byte[2048];
569 int len;
570 while ((len = input.Read(buffer, 0, 2048)) > 0)
571 {
572 output.Write(buffer, 0, len);
573 }
574
575 output.Flush();
576 }
577
578 }
579} \ No newline at end of file
diff --git a/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs b/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs
index 0c9fdb9..25f198b 100644
--- a/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs
+++ b/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs
@@ -695,7 +695,7 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
695 /// <param name="agentId"></param> 695 /// <param name="agentId"></param>
696 public void EconomyDataRequestHandler(IClientAPI user) 696 public void EconomyDataRequestHandler(IClientAPI user)
697 { 697 {
698 Scene s = LocateSceneClientIn(user.AgentId); 698 Scene s = (Scene)user.Scene;
699 699
700 user.SendEconomyData(EnergyEfficiency, s.RegionInfo.ObjectCapacity, ObjectCount, PriceEnergyUnit, PriceGroupCreate, 700 user.SendEconomyData(EnergyEfficiency, s.RegionInfo.ObjectCapacity, ObjectCount, PriceEnergyUnit, PriceGroupCreate,
701 PriceObjectClaim, PriceObjectRent, PriceObjectScaleFactor, PriceParcelClaim, PriceParcelClaimFactor, 701 PriceObjectClaim, PriceObjectRent, PriceObjectScaleFactor, PriceParcelClaim, PriceParcelClaimFactor,
diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
index 4674489..c8aab54 100644
--- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
+++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
@@ -393,6 +393,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
393 public event EstateTeleportAllUsersHomeRequest OnEstateTeleportAllUsersHomeRequest; 393 public event EstateTeleportAllUsersHomeRequest OnEstateTeleportAllUsersHomeRequest;
394 public event EstateChangeInfo OnEstateChangeInfo; 394 public event EstateChangeInfo OnEstateChangeInfo;
395 public event EstateManageTelehub OnEstateManageTelehub; 395 public event EstateManageTelehub OnEstateManageTelehub;
396 public event CachedTextureRequest OnCachedTextureRequest;
396 public event ScriptReset OnScriptReset; 397 public event ScriptReset OnScriptReset;
397 public event GetScriptRunning OnGetScriptRunning; 398 public event GetScriptRunning OnGetScriptRunning;
398 public event SetScriptRunning OnSetScriptRunning; 399 public event SetScriptRunning OnSetScriptRunning;
@@ -573,6 +574,11 @@ namespace OpenSim.Region.OptionalModules.World.NPC
573 { 574 {
574 } 575 }
575 576
577 public void SendCachedTextureResponse(ISceneEntity avatar, int serial, List<CachedTextureResponseArg> cachedTextures)
578 {
579
580 }
581
576 public virtual void Kick(string message) 582 public virtual void Kick(string message)
577 { 583 {
578 } 584 }
@@ -590,7 +596,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
590 596
591 } 597 }
592 598
593 public virtual void SendKillObject(ulong regionHandle, List<uint> localID) 599 public virtual void SendKillObject(List<uint> localID)
594 { 600 {
595 } 601 }
596 602
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs
index 77ea3ed..12a0c17 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs
@@ -75,11 +75,11 @@ private sealed class BulletBodyUnman : BulletBody
75private sealed class BulletShapeUnman : BulletShape 75private sealed class BulletShapeUnman : BulletShape
76{ 76{
77 public IntPtr ptr; 77 public IntPtr ptr;
78 public BulletShapeUnman(IntPtr xx, BSPhysicsShapeType typ) 78 public BulletShapeUnman(IntPtr xx, BSPhysicsShapeType typ)
79 : base() 79 : base()
80 { 80 {
81 ptr = xx; 81 ptr = xx;
82 type = typ; 82 shapeType = typ;
83 } 83 }
84 public override bool HasPhysicalShape 84 public override bool HasPhysicalShape
85 { 85 {
@@ -91,7 +91,7 @@ private sealed class BulletShapeUnman : BulletShape
91 } 91 }
92 public override BulletShape Clone() 92 public override BulletShape Clone()
93 { 93 {
94 return new BulletShapeUnman(ptr, type); 94 return new BulletShapeUnman(ptr, shapeType);
95 } 95 }
96 public override bool ReferenceSame(BulletShape other) 96 public override bool ReferenceSame(BulletShape other)
97 { 97 {
@@ -251,23 +251,52 @@ public override BulletShape CreateMeshShape(BulletWorld world,
251 BSPhysicsShapeType.SHAPE_MESH); 251 BSPhysicsShapeType.SHAPE_MESH);
252} 252}
253 253
254public override BulletShape CreateGImpactShape(BulletWorld world,
255 int indicesCount, int[] indices,
256 int verticesCount, float[] vertices)
257{
258 BulletWorldUnman worldu = world as BulletWorldUnman;
259 return new BulletShapeUnman(
260 BSAPICPP.CreateGImpactShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices),
261 BSPhysicsShapeType.SHAPE_GIMPACT);
262}
263
254public override BulletShape CreateHullShape(BulletWorld world, int hullCount, float[] hulls) 264public override BulletShape CreateHullShape(BulletWorld world, int hullCount, float[] hulls)
255{ 265{
256 BulletWorldUnman worldu = world as BulletWorldUnman; 266 BulletWorldUnman worldu = world as BulletWorldUnman;
257 return new BulletShapeUnman( 267 return new BulletShapeUnman(
258 BSAPICPP.CreateHullShape2(worldu.ptr, hullCount, hulls), 268 BSAPICPP.CreateHullShape2(worldu.ptr, hullCount, hulls),
259 BSPhysicsShapeType.SHAPE_HULL); 269 BSPhysicsShapeType.SHAPE_HULL);
260} 270}
261 271
262public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape) 272public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms)
263{ 273{
264 BulletWorldUnman worldu = world as BulletWorldUnman; 274 BulletWorldUnman worldu = world as BulletWorldUnman;
265 BulletShapeUnman shapeu = meshShape as BulletShapeUnman; 275 BulletShapeUnman shapeu = meshShape as BulletShapeUnman;
266 return new BulletShapeUnman( 276 return new BulletShapeUnman(
267 BSAPICPP.BuildHullShapeFromMesh2(worldu.ptr, shapeu.ptr), 277 BSAPICPP.BuildHullShapeFromMesh2(worldu.ptr, shapeu.ptr, parms),
268 BSPhysicsShapeType.SHAPE_HULL); 278 BSPhysicsShapeType.SHAPE_HULL);
269} 279}
270 280
281public override BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape)
282{
283 BulletWorldUnman worldu = world as BulletWorldUnman;
284 BulletShapeUnman shapeu = meshShape as BulletShapeUnman;
285 return new BulletShapeUnman(
286 BSAPICPP.BuildConvexHullShapeFromMesh2(worldu.ptr, shapeu.ptr),
287 BSPhysicsShapeType.SHAPE_CONVEXHULL);
288}
289
290public override BulletShape CreateConvexHullShape(BulletWorld world,
291 int indicesCount, int[] indices,
292 int verticesCount, float[] vertices)
293{
294 BulletWorldUnman worldu = world as BulletWorldUnman;
295 return new BulletShapeUnman(
296 BSAPICPP.CreateConvexHullShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices),
297 BSPhysicsShapeType.SHAPE_CONVEXHULL);
298}
299
271public override BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData) 300public override BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData)
272{ 301{
273 BulletWorldUnman worldu = world as BulletWorldUnman; 302 BulletWorldUnman worldu = world as BulletWorldUnman;
@@ -356,7 +385,7 @@ public override BulletShape DuplicateCollisionShape(BulletWorld world, BulletSha
356{ 385{
357 BulletWorldUnman worldu = world as BulletWorldUnman; 386 BulletWorldUnman worldu = world as BulletWorldUnman;
358 BulletShapeUnman srcShapeu = srcShape as BulletShapeUnman; 387 BulletShapeUnman srcShapeu = srcShape as BulletShapeUnman;
359 return new BulletShapeUnman(BSAPICPP.DuplicateCollisionShape2(worldu.ptr, srcShapeu.ptr, id), srcShape.type); 388 return new BulletShapeUnman(BSAPICPP.DuplicateCollisionShape2(worldu.ptr, srcShapeu.ptr, id), srcShape.shapeType);
360} 389}
361 390
362public override bool DeleteCollisionShape(BulletWorld world, BulletShape shape) 391public override bool DeleteCollisionShape(BulletWorld world, BulletShape shape)
@@ -1407,11 +1436,24 @@ public static extern IntPtr CreateMeshShape2(IntPtr world,
1407 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices ); 1436 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices );
1408 1437
1409[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1438[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1439public static extern IntPtr CreateGImpactShape2(IntPtr world,
1440 int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
1441 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices );
1442
1443[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1410public static extern IntPtr CreateHullShape2(IntPtr world, 1444public static extern IntPtr CreateHullShape2(IntPtr world,
1411 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls); 1445 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls);
1412 1446
1413[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1447[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1414public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape); 1448public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape, HACDParams parms);
1449
1450[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1451public static extern IntPtr BuildConvexHullShapeFromMesh2(IntPtr world, IntPtr meshShape);
1452
1453[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1454public static extern IntPtr CreateConvexHullShape2(IntPtr world,
1455 int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
1456 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices );
1415 1457
1416[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1458[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1417public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData); 1459public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData);
@@ -1476,7 +1518,7 @@ public static extern void DestroyObject2(IntPtr sim, IntPtr obj);
1476public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin); 1518public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin);
1477 1519
1478[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1520[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1479public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight, 1521public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight,
1480 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, 1522 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap,
1481 float scaleFactor, float collisionMargin); 1523 float scaleFactor, float collisionMargin);
1482 1524
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs
index 6fc10e9..6db5f5e 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs
@@ -81,11 +81,11 @@ private sealed class BulletBodyXNA : BulletBody
81private sealed class BulletShapeXNA : BulletShape 81private sealed class BulletShapeXNA : BulletShape
82{ 82{
83 public CollisionShape shape; 83 public CollisionShape shape;
84 public BulletShapeXNA(CollisionShape xx, BSPhysicsShapeType typ) 84 public BulletShapeXNA(CollisionShape xx, BSPhysicsShapeType typ)
85 : base() 85 : base()
86 { 86 {
87 shape = xx; 87 shape = xx;
88 type = typ; 88 shapeType = typ;
89 } 89 }
90 public override bool HasPhysicalShape 90 public override bool HasPhysicalShape
91 { 91 {
@@ -97,7 +97,7 @@ private sealed class BulletShapeXNA : BulletShape
97 } 97 }
98 public override BulletShape Clone() 98 public override BulletShape Clone()
99 { 99 {
100 return new BulletShapeXNA(shape, type); 100 return new BulletShapeXNA(shape, shapeType);
101 } 101 }
102 public override bool ReferenceSame(BulletShape other) 102 public override bool ReferenceSame(BulletShape other)
103 { 103 {
@@ -137,8 +137,8 @@ private sealed class BulletConstraintXNA : BulletConstraint
137 internal int LastEntityProperty = 0; 137 internal int LastEntityProperty = 0;
138 138
139 internal EntityProperties[] UpdatedObjects; 139 internal EntityProperties[] UpdatedObjects;
140 internal Dictionary<uint, GhostObject> specialCollisionObjects; 140 internal Dictionary<uint, GhostObject> specialCollisionObjects;
141 141
142 private static int m_collisionsThisFrame; 142 private static int m_collisionsThisFrame;
143 private BSScene PhysicsScene { get; set; } 143 private BSScene PhysicsScene { get; set; }
144 144
@@ -151,7 +151,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
151 } 151 }
152 152
153 /// <summary> 153 /// <summary>
154 /// 154 ///
155 /// </summary> 155 /// </summary>
156 /// <param name="p"></param> 156 /// <param name="p"></param>
157 /// <param name="p_2"></param> 157 /// <param name="p_2"></param>
@@ -174,7 +174,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
174 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; 174 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
175 TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain; 175 TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain;
176 world.AddConstraint(constraint, pDisableCollisionsBetweenLinkedObjects); 176 world.AddConstraint(constraint, pDisableCollisionsBetweenLinkedObjects);
177 177
178 return true; 178 return true;
179 179
180 } 180 }
@@ -300,7 +300,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
300 public override bool GetForceUpdateAllAabbs(BulletWorld pWorld) { 300 public override bool GetForceUpdateAllAabbs(BulletWorld pWorld) {
301 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; 301 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
302 return world.GetForceUpdateAllAabbs(); 302 return world.GetForceUpdateAllAabbs();
303 303
304 } 304 }
305 public override void SetForceUpdateAllAabbs(BulletWorld pWorld, bool pForce) 305 public override void SetForceUpdateAllAabbs(BulletWorld pWorld, bool pForce)
306 { 306 {
@@ -404,7 +404,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
404 IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion); 404 IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion);
405 mat._origin = vposition; 405 mat._origin = vposition;
406 collisionObject.SetWorldTransform(mat); 406 collisionObject.SetWorldTransform(mat);
407 407
408 } 408 }
409 409
410 public override Vector3 GetPosition(BulletBody pCollisionObject) 410 public override Vector3 GetPosition(BulletBody pCollisionObject)
@@ -457,7 +457,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
457 { 457 {
458 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; 458 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
459 collisionObject.Activate(pforceactivation); 459 collisionObject.Activate(pforceactivation);
460 460
461 } 461 }
462 462
463 public override Quaternion GetOrientation(BulletBody pCollisionObject) 463 public override Quaternion GetOrientation(BulletBody pCollisionObject)
@@ -486,7 +486,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
486 { 486 {
487 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; 487 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
488 return collisionObject.GetCcdSweptSphereRadius(); 488 return collisionObject.GetCcdSweptSphereRadius();
489 489
490 } 490 }
491 491
492 public override IntPtr GetUserPointer(BulletBody pCollisionObject) 492 public override IntPtr GetUserPointer(BulletBody pCollisionObject)
@@ -559,8 +559,8 @@ private sealed class BulletConstraintXNA : BulletConstraint
559 } 559 }
560 560
561 561
562 public override BulletConstraint Create6DofConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, 562 public override BulletConstraint Create6DofConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
563 Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, 563 Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot,
564 bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) 564 bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
565 565
566 { 566 {
@@ -604,7 +604,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
604 } 604 }
605 605
606 /// <summary> 606 /// <summary>
607 /// 607 ///
608 /// </summary> 608 /// </summary>
609 /// <param name="pWorld"></param> 609 /// <param name="pWorld"></param>
610 /// <param name="pBody1"></param> 610 /// <param name="pBody1"></param>
@@ -824,7 +824,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
824 { 824 {
825 RigidBody body = (pBody as BulletBodyXNA).rigidBody; 825 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
826 float angularDamping = body.GetAngularDamping(); 826 float angularDamping = body.GetAngularDamping();
827 body.SetDamping(lin_damping, angularDamping); 827 body.SetDamping(lin_damping, angularDamping);
828 } 828 }
829 829
830 public override float GetLinearDamping(BulletBody pBody) 830 public override float GetLinearDamping(BulletBody pBody)
@@ -907,7 +907,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
907 RigidBody bo = co as RigidBody; 907 RigidBody bo = co as RigidBody;
908 if (bo == null) 908 if (bo == null)
909 { 909 {
910 910
911 if (world.IsInWorld(co)) 911 if (world.IsInWorld(co))
912 { 912 {
913 world.RemoveCollisionObject(co); 913 world.RemoveCollisionObject(co);
@@ -915,7 +915,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
915 } 915 }
916 else 916 else
917 { 917 {
918 918
919 if (world.IsInWorld(bo)) 919 if (world.IsInWorld(bo))
920 { 920 {
921 world.RemoveRigidBody(bo); 921 world.RemoveRigidBody(bo);
@@ -947,7 +947,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
947 947
948 // TODO: Turn this from a reference copy to a Value Copy. 948 // TODO: Turn this from a reference copy to a Value Copy.
949 BulletShapeXNA shape2 = new BulletShapeXNA(shape1, BSShapeTypeFromBroadPhaseNativeType(shape1.GetShapeType())); 949 BulletShapeXNA shape2 = new BulletShapeXNA(shape1, BSShapeTypeFromBroadPhaseNativeType(shape1.GetShapeType()));
950 950
951 return shape2; 951 return shape2;
952 } 952 }
953 953
@@ -957,7 +957,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
957 return false; 957 return false;
958 } 958 }
959 //(sim.ptr, shape.ptr, prim.LocalID, prim.RawPosition, prim.RawOrientation); 959 //(sim.ptr, shape.ptr, prim.LocalID, prim.RawPosition, prim.RawOrientation);
960 960
961 public override BulletBody CreateBodyFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) 961 public override BulletBody CreateBodyFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
962 { 962 {
963 CollisionWorld world = (pWorld as BulletWorldXNA).world; 963 CollisionWorld world = (pWorld as BulletWorldXNA).world;
@@ -993,11 +993,11 @@ private sealed class BulletConstraintXNA : BulletConstraint
993 m_startWorldTransform = IndexedMatrix.Identity; 993 m_startWorldTransform = IndexedMatrix.Identity;
994 */ 994 */
995 body.SetUserPointer(pLocalID); 995 body.SetUserPointer(pLocalID);
996 996
997 return new BulletBodyXNA(pLocalID, body); 997 return new BulletBodyXNA(pLocalID, body);
998 } 998 }
999 999
1000 1000
1001 public override BulletBody CreateBodyWithDefaultMotionState( BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) 1001 public override BulletBody CreateBodyWithDefaultMotionState( BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
1002 { 1002 {
1003 1003
@@ -1025,7 +1025,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1025 public override Vector3 GetAnisotripicFriction(BulletConstraint pconstrain) 1025 public override Vector3 GetAnisotripicFriction(BulletConstraint pconstrain)
1026 { 1026 {
1027 1027
1028 /* TODO */ 1028 /* TODO */
1029 return Vector3.Zero; 1029 return Vector3.Zero;
1030 } 1030 }
1031 public override Vector3 SetAnisotripicFriction(BulletConstraint pconstrain, Vector3 frict) { /* TODO */ return Vector3.Zero; } 1031 public override Vector3 SetAnisotripicFriction(BulletConstraint pconstrain, Vector3 frict) { /* TODO */ return Vector3.Zero; }
@@ -1035,7 +1035,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1035 { 1035 {
1036 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; 1036 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1037 return collisionObject.IsStaticObject(); 1037 return collisionObject.IsStaticObject();
1038 1038
1039 } 1039 }
1040 public override bool IsKinematicObject(BulletBody pCollisionObject) 1040 public override bool IsKinematicObject(BulletBody pCollisionObject)
1041 { 1041 {
@@ -1098,10 +1098,10 @@ private sealed class BulletConstraintXNA : BulletConstraint
1098 return new BulletWorldXNA(1, PhysicsScene, BSAPIXNA.Initialize2(worldExtent, configparms, maxCollisions, ref collisionArray, maxUpdates, ref updateArray, null)); 1098 return new BulletWorldXNA(1, PhysicsScene, BSAPIXNA.Initialize2(worldExtent, configparms, maxCollisions, ref collisionArray, maxUpdates, ref updateArray, null));
1099 } 1099 }
1100 1100
1101 private static DiscreteDynamicsWorld Initialize2(Vector3 worldExtent, 1101 private static DiscreteDynamicsWorld Initialize2(Vector3 worldExtent,
1102 ConfigurationParameters[] o, 1102 ConfigurationParameters[] o,
1103 int mMaxCollisionsPerFrame, ref CollisionDesc[] collisionArray, 1103 int mMaxCollisionsPerFrame, ref CollisionDesc[] collisionArray,
1104 int mMaxUpdatesPerFrame, ref EntityProperties[] updateArray, 1104 int mMaxUpdatesPerFrame, ref EntityProperties[] updateArray,
1105 object mDebugLogCallbackHandle) 1105 object mDebugLogCallbackHandle)
1106 { 1106 {
1107 CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData(); 1107 CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData();
@@ -1138,9 +1138,9 @@ private sealed class BulletConstraintXNA : BulletConstraint
1138 p.avatarCapsuleDepth = BSParam.AvatarCapsuleDepth; 1138 p.avatarCapsuleDepth = BSParam.AvatarCapsuleDepth;
1139 p.avatarCapsuleHeight = BSParam.AvatarCapsuleHeight; 1139 p.avatarCapsuleHeight = BSParam.AvatarCapsuleHeight;
1140 p.avatarContactProcessingThreshold = BSParam.AvatarContactProcessingThreshold; 1140 p.avatarContactProcessingThreshold = BSParam.AvatarContactProcessingThreshold;
1141 1141
1142 p.vehicleAngularDamping = BSParam.VehicleAngularDamping; 1142 p.vehicleAngularDamping = BSParam.VehicleAngularDamping;
1143 1143
1144 p.maxPersistantManifoldPoolSize = o[0].maxPersistantManifoldPoolSize; 1144 p.maxPersistantManifoldPoolSize = o[0].maxPersistantManifoldPoolSize;
1145 p.maxCollisionAlgorithmPoolSize = o[0].maxCollisionAlgorithmPoolSize; 1145 p.maxCollisionAlgorithmPoolSize = o[0].maxCollisionAlgorithmPoolSize;
1146 p.shouldDisableContactPoolDynamicAllocation = o[0].shouldDisableContactPoolDynamicAllocation; 1146 p.shouldDisableContactPoolDynamicAllocation = o[0].shouldDisableContactPoolDynamicAllocation;
@@ -1160,7 +1160,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1160 p.linkConstraintSolverIterations = BSParam.LinkConstraintSolverIterations; 1160 p.linkConstraintSolverIterations = BSParam.LinkConstraintSolverIterations;
1161 p.physicsLoggingFrames = o[0].physicsLoggingFrames; 1161 p.physicsLoggingFrames = o[0].physicsLoggingFrames;
1162 DefaultCollisionConstructionInfo ccci = new DefaultCollisionConstructionInfo(); 1162 DefaultCollisionConstructionInfo ccci = new DefaultCollisionConstructionInfo();
1163 1163
1164 DefaultCollisionConfiguration cci = new DefaultCollisionConfiguration(); 1164 DefaultCollisionConfiguration cci = new DefaultCollisionConfiguration();
1165 CollisionDispatcher m_dispatcher = new CollisionDispatcher(cci); 1165 CollisionDispatcher m_dispatcher = new CollisionDispatcher(cci);
1166 1166
@@ -1263,7 +1263,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1263 } 1263 }
1264 } 1264 }
1265 return ret; 1265 return ret;
1266 1266
1267 } 1267 }
1268 1268
1269 public override float GetAngularMotionDisc(BulletShape pShape) 1269 public override float GetAngularMotionDisc(BulletShape pShape)
@@ -1353,10 +1353,10 @@ private sealed class BulletConstraintXNA : BulletConstraint
1353 CollisionShape shape = (pShape as BulletShapeXNA).shape; 1353 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1354 gObj.SetCollisionShape(shape); 1354 gObj.SetCollisionShape(shape);
1355 gObj.SetUserPointer(pLocalID); 1355 gObj.SetUserPointer(pLocalID);
1356 1356
1357 if (specialCollisionObjects.ContainsKey(pLocalID)) 1357 if (specialCollisionObjects.ContainsKey(pLocalID))
1358 specialCollisionObjects[pLocalID] = gObj; 1358 specialCollisionObjects[pLocalID] = gObj;
1359 else 1359 else
1360 specialCollisionObjects.Add(pLocalID, gObj); 1360 specialCollisionObjects.Add(pLocalID, gObj);
1361 1361
1362 // TODO: Add to Special CollisionObjects! 1362 // TODO: Add to Special CollisionObjects!
@@ -1447,8 +1447,8 @@ private sealed class BulletConstraintXNA : BulletConstraint
1447 return new BulletShapeXNA(ret, BSShapeTypeFromBroadPhaseNativeType(ret.GetShapeType())); 1447 return new BulletShapeXNA(ret, BSShapeTypeFromBroadPhaseNativeType(ret.GetShapeType()));
1448 } 1448 }
1449 1449
1450 public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx) { 1450 public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx) {
1451 1451
1452 if (cShape == null) 1452 if (cShape == null)
1453 return null; 1453 return null;
1454 CompoundShape compoundShape = (cShape as BulletShapeXNA).shape as CompoundShape; 1454 CompoundShape compoundShape = (cShape as BulletShapeXNA).shape as CompoundShape;
@@ -1456,7 +1456,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1456 BulletShape retShape = new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType())); 1456 BulletShape retShape = new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType()));
1457 1457
1458 1458
1459 return retShape; 1459 return retShape;
1460 } 1460 }
1461 1461
1462 public BSPhysicsShapeType BSShapeTypeFromBroadPhaseNativeType(BroadphaseNativeTypes pin) 1462 public BSPhysicsShapeType BSShapeTypeFromBroadPhaseNativeType(BroadphaseNativeTypes pin)
@@ -1475,7 +1475,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1475 ret = BSPhysicsShapeType.SHAPE_UNKNOWN; 1475 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1476 break; 1476 break;
1477 case BroadphaseNativeTypes.CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE: 1477 case BroadphaseNativeTypes.CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE:
1478 ret = BSPhysicsShapeType.SHAPE_MESH; 1478 ret = BSPhysicsShapeType.SHAPE_CONVEXHULL;
1479 break; 1479 break;
1480 case BroadphaseNativeTypes.CONVEX_HULL_SHAPE_PROXYTYPE: 1480 case BroadphaseNativeTypes.CONVEX_HULL_SHAPE_PROXYTYPE:
1481 ret = BSPhysicsShapeType.SHAPE_HULL; 1481 ret = BSPhysicsShapeType.SHAPE_HULL;
@@ -1503,7 +1503,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1503 ret = BSPhysicsShapeType.SHAPE_CONE; 1503 ret = BSPhysicsShapeType.SHAPE_CONE;
1504 break; 1504 break;
1505 case BroadphaseNativeTypes.CONVEX_SHAPE_PROXYTYPE: 1505 case BroadphaseNativeTypes.CONVEX_SHAPE_PROXYTYPE:
1506 ret = BSPhysicsShapeType.SHAPE_UNKNOWN; 1506 ret = BSPhysicsShapeType.SHAPE_CONVEXHULL;
1507 break; 1507 break;
1508 case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE: 1508 case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE:
1509 ret = BSPhysicsShapeType.SHAPE_CYLINDER; 1509 ret = BSPhysicsShapeType.SHAPE_CYLINDER;
@@ -1547,7 +1547,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1547 break; 1547 break;
1548 ///Used for GIMPACT Trimesh integration 1548 ///Used for GIMPACT Trimesh integration
1549 case BroadphaseNativeTypes.GIMPACT_SHAPE_PROXYTYPE: 1549 case BroadphaseNativeTypes.GIMPACT_SHAPE_PROXYTYPE:
1550 ret = BSPhysicsShapeType.SHAPE_MESH; 1550 ret = BSPhysicsShapeType.SHAPE_GIMPACT;
1551 break; 1551 break;
1552 ///Multimaterial mesh 1552 ///Multimaterial mesh
1553 case BroadphaseNativeTypes.MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE: 1553 case BroadphaseNativeTypes.MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE:
@@ -1598,8 +1598,8 @@ private sealed class BulletConstraintXNA : BulletConstraint
1598 return new BulletShapeXNA(m_planeshape, BSPhysicsShapeType.SHAPE_GROUNDPLANE); 1598 return new BulletShapeXNA(m_planeshape, BSPhysicsShapeType.SHAPE_GROUNDPLANE);
1599 } 1599 }
1600 1600
1601 public override BulletConstraint Create6DofSpringConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, 1601 public override BulletConstraint Create6DofSpringConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
1602 Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, 1602 Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot,
1603 bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) 1603 bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
1604 1604
1605 { 1605 {
@@ -1745,7 +1745,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1745 { 1745 {
1746 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; 1746 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1747 CompoundShape compoundshape = new CompoundShape(false); 1747 CompoundShape compoundshape = new CompoundShape(false);
1748 1748
1749 compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin); 1749 compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin);
1750 int ii = 1; 1750 int ii = 1;
1751 1751
@@ -1761,7 +1761,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1761 int ender = ((ii + 4) + (vertexCount*3)); 1761 int ender = ((ii + 4) + (vertexCount*3));
1762 for (int iii = ii + 4; iii < ender; iii+=3) 1762 for (int iii = ii + 4; iii < ender; iii+=3)
1763 { 1763 {
1764 1764
1765 virts.Add(new IndexedVector3(pConvHulls[iii], pConvHulls[iii + 1], pConvHulls[iii +2])); 1765 virts.Add(new IndexedVector3(pConvHulls[iii], pConvHulls[iii + 1], pConvHulls[iii +2]));
1766 } 1766 }
1767 ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount); 1767 ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount);
@@ -1769,26 +1769,35 @@ private sealed class BulletConstraintXNA : BulletConstraint
1769 compoundshape.AddChildShape(ref childTrans, convexShape); 1769 compoundshape.AddChildShape(ref childTrans, convexShape);
1770 ii += (vertexCount*3 + 4); 1770 ii += (vertexCount*3 + 4);
1771 } 1771 }
1772 1772
1773 return new BulletShapeXNA(compoundshape, BSPhysicsShapeType.SHAPE_HULL); 1773 return new BulletShapeXNA(compoundshape, BSPhysicsShapeType.SHAPE_HULL);
1774 } 1774 }
1775 1775
1776 public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape) 1776 public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms)
1777 {
1778 /* TODO */ return null;
1779 }
1780
1781 public override BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape)
1777 { 1782 {
1778 /* TODO */ return null; 1783 /* TODO */ return null;
1784 }
1779 1785
1786 public override BulletShape CreateConvexHullShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats)
1787 {
1788 /* TODO */ return null;
1780 } 1789 }
1781 1790
1782 public override BulletShape CreateMeshShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) 1791 public override BulletShape CreateMeshShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats)
1783 { 1792 {
1784 //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount); 1793 //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount);
1785 1794
1786 for (int iter = 0; iter < pVerticesCount; iter++) 1795 for (int iter = 0; iter < pVerticesCount; iter++)
1787 { 1796 {
1788 if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0; 1797 if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0;
1789 if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0; 1798 if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0;
1790 } 1799 }
1791 1800
1792 ObjectArray<int> indicesarr = new ObjectArray<int>(indices); 1801 ObjectArray<int> indicesarr = new ObjectArray<int>(indices);
1793 ObjectArray<float> vertices = new ObjectArray<float>(verticesAsFloats); 1802 ObjectArray<float> vertices = new ObjectArray<float>(verticesAsFloats);
1794 DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount); 1803 DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount);
@@ -1802,7 +1811,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1802 mesh.m_vertexStride = 3; 1811 mesh.m_vertexStride = 3;
1803 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; 1812 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
1804 mesh.m_triangleIndexStride = 3; 1813 mesh.m_triangleIndexStride = 3;
1805 1814
1806 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); 1815 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
1807 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); 1816 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
1808 BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true); 1817 BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true);
@@ -1811,9 +1820,14 @@ private sealed class BulletConstraintXNA : BulletConstraint
1811 return new BulletShapeXNA(meshShape, BSPhysicsShapeType.SHAPE_MESH); 1820 return new BulletShapeXNA(meshShape, BSPhysicsShapeType.SHAPE_MESH);
1812 1821
1813 } 1822 }
1823 public override BulletShape CreateGImpactShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats)
1824 {
1825 // TODO:
1826 return null;
1827 }
1814 public static void DumpRaw(ObjectArray<int>indices, ObjectArray<float> vertices, int pIndicesCount,int pVerticesCount ) 1828 public static void DumpRaw(ObjectArray<int>indices, ObjectArray<float> vertices, int pIndicesCount,int pVerticesCount )
1815 { 1829 {
1816 1830
1817 String fileName = "objTest3.raw"; 1831 String fileName = "objTest3.raw";
1818 String completePath = System.IO.Path.Combine(Util.configDir(), fileName); 1832 String completePath = System.IO.Path.Combine(Util.configDir(), fileName);
1819 StreamWriter sw = new StreamWriter(completePath); 1833 StreamWriter sw = new StreamWriter(completePath);
@@ -1839,7 +1853,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1839 string s = vertices[indices[i * 3]].ToString("0.0000"); 1853 string s = vertices[indices[i * 3]].ToString("0.0000");
1840 s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000"); 1854 s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000");
1841 s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000"); 1855 s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000");
1842 1856
1843 sw.Write(s + "\n"); 1857 sw.Write(s + "\n");
1844 } 1858 }
1845 1859
@@ -1861,7 +1875,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1861 mesh.m_vertexStride = 3; 1875 mesh.m_vertexStride = 3;
1862 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; 1876 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
1863 mesh.m_triangleIndexStride = 3; 1877 mesh.m_triangleIndexStride = 3;
1864 1878
1865 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); 1879 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
1866 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); 1880 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
1867 1881
@@ -1892,7 +1906,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1892 sw.Close(); 1906 sw.Close();
1893 } 1907 }
1894 1908
1895 public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, 1909 public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
1896 float scaleFactor, float collisionMargin) 1910 float scaleFactor, float collisionMargin)
1897 { 1911 {
1898 const int upAxis = 2; 1912 const int upAxis = 2;
@@ -1934,14 +1948,14 @@ private sealed class BulletConstraintXNA : BulletConstraint
1934 /* TODO */ 1948 /* TODO */
1935 updatedEntityCount = 0; 1949 updatedEntityCount = 0;
1936 collidersCount = 0; 1950 collidersCount = 0;
1937 1951
1938 1952
1939 int ret = PhysicsStep2(world,timeStep,maxSubSteps,fixedTimeStep,out updatedEntityCount,out world.physicsScene.m_updateArray, out collidersCount, out world.physicsScene.m_collisionArray); 1953 int ret = PhysicsStep2(world,timeStep,maxSubSteps,fixedTimeStep,out updatedEntityCount,out world.physicsScene.m_updateArray, out collidersCount, out world.physicsScene.m_collisionArray);
1940 1954
1941 return ret; 1955 return ret;
1942 } 1956 }
1943 1957
1944 private int PhysicsStep2(BulletWorld pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep, 1958 private int PhysicsStep2(BulletWorld pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep,
1945 out int updatedEntityCount, out EntityProperties[] updatedEntities, 1959 out int updatedEntityCount, out EntityProperties[] updatedEntities,
1946 out int collidersCount, out CollisionDesc[] colliders) 1960 out int collidersCount, out CollisionDesc[] colliders)
1947 { 1961 {
@@ -1950,24 +1964,24 @@ private sealed class BulletConstraintXNA : BulletConstraint
1950 return epic; 1964 return epic;
1951 } 1965 }
1952 1966
1953 private int PhysicsStepint(BulletWorld pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount, 1967 private int PhysicsStepint(BulletWorld pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount,
1954 out EntityProperties[] updatedEntities, out int collidersCount, out CollisionDesc[] colliders, int maxCollisions, int maxUpdates) 1968 out EntityProperties[] updatedEntities, out int collidersCount, out CollisionDesc[] colliders, int maxCollisions, int maxUpdates)
1955 { 1969 {
1956 int numSimSteps = 0; 1970 int numSimSteps = 0;
1957 Array.Clear(UpdatedObjects, 0, UpdatedObjects.Length); 1971 Array.Clear(UpdatedObjects, 0, UpdatedObjects.Length);
1958 Array.Clear(UpdatedCollisions, 0, UpdatedCollisions.Length); 1972 Array.Clear(UpdatedCollisions, 0, UpdatedCollisions.Length);
1959 LastEntityProperty=0; 1973 LastEntityProperty=0;
1960 1974
1961 1975
1962 1976
1963 1977
1964 1978
1965 1979
1966 LastCollisionDesc=0; 1980 LastCollisionDesc=0;
1967 1981
1968 updatedEntityCount = 0; 1982 updatedEntityCount = 0;
1969 collidersCount = 0; 1983 collidersCount = 0;
1970 1984
1971 1985
1972 if (pWorld is BulletWorldXNA) 1986 if (pWorld is BulletWorldXNA)
1973 { 1987 {
@@ -2024,7 +2038,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
2024 2038
2025 collidersCount = LastCollisionDesc; 2039 collidersCount = LastCollisionDesc;
2026 colliders = UpdatedCollisions; 2040 colliders = UpdatedCollisions;
2027 2041
2028 2042
2029 } 2043 }
2030 else 2044 else
@@ -2032,15 +2046,15 @@ private sealed class BulletConstraintXNA : BulletConstraint
2032 //if (updatedEntities is null) 2046 //if (updatedEntities is null)
2033 //updatedEntities = new List<BulletXNA.EntityProperties>(); 2047 //updatedEntities = new List<BulletXNA.EntityProperties>();
2034 //updatedEntityCount = 0; 2048 //updatedEntityCount = 0;
2035 2049
2036 2050
2037 //collidersCount = 0; 2051 //collidersCount = 0;
2038 2052
2039 updatedEntities = new EntityProperties[0]; 2053 updatedEntities = new EntityProperties[0];
2040 2054
2041 2055
2042 colliders = new CollisionDesc[0]; 2056 colliders = new CollisionDesc[0];
2043 2057
2044 } 2058 }
2045 return numSimSteps; 2059 return numSimSteps;
2046 } 2060 }
@@ -2048,7 +2062,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
2048 { 2062 {
2049 IOverlappingPairCache cache = obj.GetOverlappingPairCache(); 2063 IOverlappingPairCache cache = obj.GetOverlappingPairCache();
2050 ObjectArray<BroadphasePair> pairs = cache.GetOverlappingPairArray(); 2064 ObjectArray<BroadphasePair> pairs = cache.GetOverlappingPairArray();
2051 2065
2052 DiscreteDynamicsWorld world = (PhysicsScene.World as BulletWorldXNA).world; 2066 DiscreteDynamicsWorld world = (PhysicsScene.World as BulletWorldXNA).world;
2053 PersistentManifoldArray manifoldArray = new PersistentManifoldArray(); 2067 PersistentManifoldArray manifoldArray = new PersistentManifoldArray();
2054 BroadphasePair collisionPair; 2068 BroadphasePair collisionPair;
@@ -2060,7 +2074,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
2060 ManifoldPoint pt; 2074 ManifoldPoint pt;
2061 2075
2062 int numPairs = pairs.Count; 2076 int numPairs = pairs.Count;
2063 2077
2064 for (int i = 0; i < numPairs; i++) 2078 for (int i = 0; i < numPairs; i++)
2065 { 2079 {
2066 manifoldArray.Clear(); 2080 manifoldArray.Clear();
@@ -2069,7 +2083,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
2069 collisionPair = world.GetPairCache().FindPair(pairs[i].m_pProxy0, pairs[i].m_pProxy1); 2083 collisionPair = world.GetPairCache().FindPair(pairs[i].m_pProxy0, pairs[i].m_pProxy1);
2070 if (collisionPair == null) 2084 if (collisionPair == null)
2071 continue; 2085 continue;
2072 2086
2073 collisionPair.m_algorithm.GetAllContactManifolds(manifoldArray); 2087 collisionPair.m_algorithm.GetAllContactManifolds(manifoldArray);
2074 for (int j = 0; j < manifoldArray.Count; j++) 2088 for (int j = 0; j < manifoldArray.Count; j++)
2075 { 2089 {
@@ -2092,7 +2106,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
2092 } 2106 }
2093 private static void RecordCollision(BSAPIXNA world, CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm, float penetration) 2107 private static void RecordCollision(BSAPIXNA world, CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm, float penetration)
2094 { 2108 {
2095 2109
2096 IndexedVector3 contactNormal = norm; 2110 IndexedVector3 contactNormal = norm;
2097 if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 && 2111 if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 &&
2098 (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0) 2112 (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0)
@@ -2162,11 +2176,11 @@ private sealed class BulletConstraintXNA : BulletConstraint
2162 if (NotMe is BulletBodyXNA && NotMe.HasPhysicalBody) 2176 if (NotMe is BulletBodyXNA && NotMe.HasPhysicalBody)
2163 { 2177 {
2164 CollisionObject AvoidBody = (NotMe as BulletBodyXNA).body; 2178 CollisionObject AvoidBody = (NotMe as BulletBodyXNA).body;
2165 2179
2166 IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z); 2180 IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z);
2167 IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight); 2181 IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight);
2168 using ( 2182 using (
2169 ClosestNotMeRayResultCallback rayCallback = 2183 ClosestNotMeRayResultCallback rayCallback =
2170 new ClosestNotMeRayResultCallback(rOrigin, rEnd, AvoidBody) 2184 new ClosestNotMeRayResultCallback(rOrigin, rEnd, AvoidBody)
2171 ) 2185 )
2172 { 2186 {
@@ -2182,9 +2196,9 @@ private sealed class BulletConstraintXNA : BulletConstraint
2182 return false; 2196 return false;
2183 } 2197 }
2184} 2198}
2185
2186 2199
2187 2200
2201
2188 2202
2189 public class SimMotionState : DefaultMotionState 2203 public class SimMotionState : DefaultMotionState
2190 { 2204 {
@@ -2277,12 +2291,12 @@ private sealed class BulletConstraintXNA : BulletConstraint
2277 m_lastProperties = m_properties; 2291 m_lastProperties = m_properties;
2278 if (m_world.LastEntityProperty < m_world.UpdatedObjects.Length) 2292 if (m_world.LastEntityProperty < m_world.UpdatedObjects.Length)
2279 m_world.UpdatedObjects[m_world.LastEntityProperty++]=(m_properties); 2293 m_world.UpdatedObjects[m_world.LastEntityProperty++]=(m_properties);
2280 2294
2281 //(*m_updatesThisFrame)[m_properties.ID] = &m_properties; 2295 //(*m_updatesThisFrame)[m_properties.ID] = &m_properties;
2282 } 2296 }
2283 2297
2284 2298
2285 2299
2286 2300
2287 } 2301 }
2288 public override void SetRigidBody(RigidBody body) 2302 public override void SetRigidBody(RigidBody body)
@@ -2305,7 +2319,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
2305 (((v1.Z - nEpsilon) < v2.Z) && (v2.Z < (v1.Z + nEpsilon))) && 2319 (((v1.Z - nEpsilon) < v2.Z) && (v2.Z < (v1.Z + nEpsilon))) &&
2306 (((v1.W - nEpsilon) < v2.W) && (v2.W < (v1.W + nEpsilon))); 2320 (((v1.W - nEpsilon) < v2.W) && (v2.W < (v1.W + nEpsilon)));
2307 } 2321 }
2308 2322
2309 } 2323 }
2310} 2324}
2311 2325
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs
new file mode 100755
index 0000000..ac8c30c
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs
@@ -0,0 +1,351 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using OpenSim.Region.Physics.Manager;
34
35using OMV = OpenMetaverse;
36
37namespace OpenSim.Region.Physics.BulletSPlugin
38{
39public class BSActorAvatarMove : BSActor
40{
41 BSVMotor m_velocityMotor;
42
43 // Set to true if we think we're going up stairs.
44 // This state is remembered because collisions will turn on and off as we go up stairs.
45 int m_walkingUpStairs;
46 float m_lastStepUp;
47
48 public BSActorAvatarMove(BSScene physicsScene, BSPhysObject pObj, string actorName)
49 : base(physicsScene, pObj, actorName)
50 {
51 m_velocityMotor = null;
52 m_walkingUpStairs = 0;
53 m_physicsScene.DetailLog("{0},BSActorAvatarMove,constructor", m_controllingPrim.LocalID);
54 }
55
56 // BSActor.isActive
57 public override bool isActive
58 {
59 get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
60 }
61
62 // Release any connections and resources used by the actor.
63 // BSActor.Dispose()
64 public override void Dispose()
65 {
66 Enabled = false;
67 }
68
69 // Called when physical parameters (properties set in Bullet) need to be re-applied.
70 // Called at taint-time.
71 // BSActor.Refresh()
72 public override void Refresh()
73 {
74 m_physicsScene.DetailLog("{0},BSActorAvatarMove,refresh", m_controllingPrim.LocalID);
75
76 // If the object is physically active, add the hoverer prestep action
77 if (isActive)
78 {
79 ActivateAvatarMove();
80 }
81 else
82 {
83 DeactivateAvatarMove();
84 }
85 }
86
87 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
88 // Register a prestep action to restore physical requirements before the next simulation step.
89 // Called at taint-time.
90 // BSActor.RemoveDependencies()
91 public override void RemoveDependencies()
92 {
93 // Nothing to do for the hoverer since it is all software at pre-step action time.
94 }
95
96 // Usually called when target velocity changes to set the current velocity and the target
97 // into the movement motor.
98 public void SetVelocityAndTarget(OMV.Vector3 vel, OMV.Vector3 targ, bool inTaintTime)
99 {
100 m_physicsScene.TaintedObject(inTaintTime, "BSActorAvatarMove.setVelocityAndTarget", delegate()
101 {
102 if (m_velocityMotor != null)
103 {
104 m_velocityMotor.Reset();
105 m_velocityMotor.SetTarget(targ);
106 m_velocityMotor.SetCurrent(vel);
107 m_velocityMotor.Enabled = true;
108 }
109 });
110 }
111
112 // If a hover motor has not been created, create one and start the hovering.
113 private void ActivateAvatarMove()
114 {
115 if (m_velocityMotor == null)
116 {
117 // Infinite decay and timescale values so motor only changes current to target values.
118 m_velocityMotor = new BSVMotor("BSCharacter.Velocity",
119 0.2f, // time scale
120 BSMotor.Infinite, // decay time scale
121 1f // efficiency
122 );
123 // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
124 SetVelocityAndTarget(m_controllingPrim.RawVelocity, m_controllingPrim.TargetVelocity, true /* inTaintTime */);
125
126 m_physicsScene.BeforeStep += Mover;
127
128 m_walkingUpStairs = 0;
129 }
130 }
131
132 private void DeactivateAvatarMove()
133 {
134 if (m_velocityMotor != null)
135 {
136 m_physicsScene.BeforeStep -= Mover;
137 m_velocityMotor = null;
138 }
139 }
140
141 // Called just before the simulation step. Update the vertical position for hoverness.
142 private void Mover(float timeStep)
143 {
144 // Don't do movement while the object is selected.
145 if (!isActive)
146 return;
147
148 // TODO: Decide if the step parameters should be changed depending on the avatar's
149 // state (flying, colliding, ...). There is code in ODE to do this.
150
151 // COMMENTARY: when the user is making the avatar walk, except for falling, the velocity
152 // specified for the avatar is the one that should be used. For falling, if the avatar
153 // is not flying and is not colliding then it is presumed to be falling and the Z
154 // component is not fooled with (thus allowing gravity to do its thing).
155 // When the avatar is standing, though, the user has specified a velocity of zero and
156 // the avatar should be standing. But if the avatar is pushed by something in the world
157 // (raising elevator platform, moving vehicle, ...) the avatar should be allowed to
158 // move. Thus, the velocity cannot be forced to zero. The problem is that small velocity
159 // errors can creap in and the avatar will slowly float off in some direction.
160 // So, the problem is that, when an avatar is standing, we cannot tell creaping error
161 // from real pushing.
162 // The code below uses whether the collider is static or moving to decide whether to zero motion.
163
164 m_velocityMotor.Step(timeStep);
165 m_controllingPrim.IsStationary = false;
166
167 // If we're not supposed to be moving, make sure things are zero.
168 if (m_velocityMotor.ErrorIsZero() && m_velocityMotor.TargetValue == OMV.Vector3.Zero)
169 {
170 // The avatar shouldn't be moving
171 m_velocityMotor.Zero();
172
173 if (m_controllingPrim.IsColliding)
174 {
175 // If we are colliding with a stationary object, presume we're standing and don't move around
176 if (!m_controllingPrim.ColliderIsMoving)
177 {
178 m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", m_controllingPrim.LocalID);
179 m_controllingPrim.IsStationary = true;
180 m_controllingPrim.ZeroMotion(true /* inTaintTime */);
181 }
182
183 // Standing has more friction on the ground
184 if (m_controllingPrim.Friction != BSParam.AvatarStandingFriction)
185 {
186 m_controllingPrim.Friction = BSParam.AvatarStandingFriction;
187 m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction);
188 }
189 }
190 else
191 {
192 if (m_controllingPrim.Flying)
193 {
194 // Flying and not collising and velocity nearly zero.
195 m_controllingPrim.ZeroMotion(true /* inTaintTime */);
196 }
197 }
198
199 m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2}",
200 m_controllingPrim.LocalID, m_velocityMotor.TargetValue, m_controllingPrim.IsColliding);
201 }
202 else
203 {
204 // Supposed to be moving.
205 OMV.Vector3 stepVelocity = m_velocityMotor.CurrentValue;
206
207 if (m_controllingPrim.Friction != BSParam.AvatarFriction)
208 {
209 // Probably starting up walking. Set friction to moving friction.
210 m_controllingPrim.Friction = BSParam.AvatarFriction;
211 m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction);
212 }
213
214 // If falling, we keep the world's downward vector no matter what the other axis specify.
215 // The check for RawVelocity.Z < 0 makes jumping work (temporary upward force).
216 if (!m_controllingPrim.Flying && !m_controllingPrim.IsColliding)
217 {
218 if (m_controllingPrim.RawVelocity.Z < 0)
219 stepVelocity.Z = m_controllingPrim.RawVelocity.Z;
220 // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity);
221 }
222
223 // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force.
224 OMV.Vector3 moveForce = (stepVelocity - m_controllingPrim.RawVelocity) * m_controllingPrim.Mass;
225
226 // Add special movement force to allow avatars to walk up stepped surfaces.
227 moveForce += WalkUpStairs();
228
229 m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}",
230 m_controllingPrim.LocalID, stepVelocity, m_controllingPrim.RawVelocity, m_controllingPrim.Mass, moveForce);
231 m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, moveForce);
232 }
233 }
234
235 // Decide if the character is colliding with a low object and compute a force to pop the
236 // avatar up so it can walk up and over the low objects.
237 private OMV.Vector3 WalkUpStairs()
238 {
239 OMV.Vector3 ret = OMV.Vector3.Zero;
240
241 m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4},avHeight={5}",
242 m_controllingPrim.LocalID, m_controllingPrim.IsColliding, m_controllingPrim.Flying,
243 m_controllingPrim.TargetVelocitySpeed, m_controllingPrim.CollisionsLastTick.Count, m_controllingPrim.Size.Z);
244 // This test is done if moving forward, not flying and is colliding with something.
245 // Check for stairs climbing if colliding, not flying and moving forward
246 if ( m_controllingPrim.IsColliding
247 && !m_controllingPrim.Flying
248 && m_controllingPrim.TargetVelocitySpeed > 0.1f )
249 {
250 // The range near the character's feet where we will consider stairs
251 // float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) + 0.05f;
252 // Note: there is a problem with the computation of the capsule height. Thus RawPosition is off
253 // from the height. Revisit size and this computation when height is scaled properly.
254 float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) - 0.05f;
255 float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight;
256
257 // Look for a collision point that is near the character's feet and is oriented the same as the charactor is.
258 // Find the highest 'good' collision.
259 OMV.Vector3 highestTouchPosition = OMV.Vector3.Zero;
260 foreach (KeyValuePair<uint, ContactPoint> kvp in m_controllingPrim.CollisionsLastTick.m_objCollisionList)
261 {
262 // Don't care about collisions with the terrain
263 if (kvp.Key > m_physicsScene.TerrainManager.HighestTerrainID)
264 {
265 OMV.Vector3 touchPosition = kvp.Value.Position;
266 m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}",
267 m_controllingPrim.LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition);
268 if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax)
269 {
270 // This contact is within the 'near the feet' range.
271 // The normal should be our contact point to the object so it is pointing away
272 // thus the difference between our facing orientation and the normal should be small.
273 OMV.Vector3 directionFacing = OMV.Vector3.UnitX * m_controllingPrim.RawOrientation;
274 OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal);
275 float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal));
276 if (diff < BSParam.AvatarStepApproachFactor)
277 {
278 if (highestTouchPosition.Z < touchPosition.Z)
279 highestTouchPosition = touchPosition;
280 }
281 }
282 }
283 }
284 m_walkingUpStairs = 0;
285 // If there is a good step sensing, move the avatar over the step.
286 if (highestTouchPosition != OMV.Vector3.Zero)
287 {
288 // Remember that we are going up stairs. This is needed because collisions
289 // will stop when we move up so this smoothes out that effect.
290 m_walkingUpStairs = BSParam.AvatarStepSmoothingSteps;
291
292 m_lastStepUp = highestTouchPosition.Z - nearFeetHeightMin;
293 ret = ComputeStairCorrection(m_lastStepUp);
294 m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},ret={3}",
295 m_controllingPrim.LocalID, highestTouchPosition, nearFeetHeightMin, ret);
296 }
297 }
298 else
299 {
300 // If we used to be going up stairs but are not now, smooth the case where collision goes away while
301 // we are bouncing up the stairs.
302 if (m_walkingUpStairs > 0)
303 {
304 m_walkingUpStairs--;
305 ret = ComputeStairCorrection(m_lastStepUp);
306 }
307 }
308
309 return ret;
310 }
311
312 private OMV.Vector3 ComputeStairCorrection(float stepUp)
313 {
314 OMV.Vector3 ret = OMV.Vector3.Zero;
315 OMV.Vector3 displacement = OMV.Vector3.Zero;
316
317 if (stepUp > 0f)
318 {
319 // Found the stairs contact point. Push up a little to raise the character.
320 if (BSParam.AvatarStepForceFactor > 0f)
321 {
322 float upForce = stepUp * m_controllingPrim.Mass * BSParam.AvatarStepForceFactor;
323 ret = new OMV.Vector3(0f, 0f, upForce);
324 }
325
326 // Also move the avatar up for the new height
327 if (BSParam.AvatarStepUpCorrectionFactor > 0f)
328 {
329 // Move the avatar up related to the height of the collision
330 displacement = new OMV.Vector3(0f, 0f, stepUp * BSParam.AvatarStepUpCorrectionFactor);
331 m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement;
332 }
333 else
334 {
335 if (BSParam.AvatarStepUpCorrectionFactor < 0f)
336 {
337 // Move the avatar up about the specified step height
338 displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight);
339 m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement;
340 }
341 }
342 m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs.ComputeStairCorrection,disp={1},force={2}",
343 m_controllingPrim.LocalID, displacement, ret);
344
345 }
346 return ret;
347 }
348}
349}
350
351
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs
new file mode 100755
index 0000000..8a79809
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs
@@ -0,0 +1,173 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using OpenSim.Region.Physics.Manager;
34
35using OMV = OpenMetaverse;
36
37namespace OpenSim.Region.Physics.BulletSPlugin
38{
39public class BSActorHover : BSActor
40{
41 private BSFMotor m_hoverMotor;
42
43 public BSActorHover(BSScene physicsScene, BSPhysObject pObj, string actorName)
44 : base(physicsScene, pObj, actorName)
45 {
46 m_hoverMotor = null;
47 m_physicsScene.DetailLog("{0},BSActorHover,constructor", m_controllingPrim.LocalID);
48 }
49
50 // BSActor.isActive
51 public override bool isActive
52 {
53 get { return Enabled; }
54 }
55
56 // Release any connections and resources used by the actor.
57 // BSActor.Dispose()
58 public override void Dispose()
59 {
60 Enabled = false;
61 }
62
63 // Called when physical parameters (properties set in Bullet) need to be re-applied.
64 // Called at taint-time.
65 // BSActor.Refresh()
66 public override void Refresh()
67 {
68 m_physicsScene.DetailLog("{0},BSActorHover,refresh", m_controllingPrim.LocalID);
69
70 // If not active any more, turn me off
71 if (!m_controllingPrim.HoverActive)
72 {
73 SetEnabled(false);
74 }
75
76 // If the object is physically active, add the hoverer prestep action
77 if (isActive)
78 {
79 ActivateHover();
80 }
81 else
82 {
83 DeactivateHover();
84 }
85 }
86
87 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
88 // Register a prestep action to restore physical requirements before the next simulation step.
89 // Called at taint-time.
90 // BSActor.RemoveDependencies()
91 public override void RemoveDependencies()
92 {
93 // Nothing to do for the hoverer since it is all software at pre-step action time.
94 }
95
96 // If a hover motor has not been created, create one and start the hovering.
97 private void ActivateHover()
98 {
99 if (m_hoverMotor == null)
100 {
101 // Turning the target on
102 m_hoverMotor = new BSFMotor("BSActorHover",
103 m_controllingPrim.HoverTau, // timeScale
104 BSMotor.Infinite, // decay time scale
105 1f // efficiency
106 );
107 m_hoverMotor.SetTarget(ComputeCurrentHoverHeight());
108 m_hoverMotor.SetCurrent(m_controllingPrim.RawPosition.Z);
109 m_hoverMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG so motor will output detail log messages.
110
111 m_physicsScene.BeforeStep += Hoverer;
112 }
113 }
114
115 private void DeactivateHover()
116 {
117 if (m_hoverMotor != null)
118 {
119 m_physicsScene.BeforeStep -= Hoverer;
120 m_hoverMotor = null;
121 }
122 }
123
124 // Called just before the simulation step. Update the vertical position for hoverness.
125 private void Hoverer(float timeStep)
126 {
127 // Don't do hovering while the object is selected.
128 if (!isActive)
129 return;
130
131 m_hoverMotor.SetCurrent(m_controllingPrim.RawPosition.Z);
132 m_hoverMotor.SetTarget(ComputeCurrentHoverHeight());
133 float targetHeight = m_hoverMotor.Step(timeStep);
134
135 // 'targetHeight' is where we'd like the Z of the prim to be at this moment.
136 // Compute the amount of force to push us there.
137 float moveForce = (targetHeight - m_controllingPrim.RawPosition.Z) * m_controllingPrim.RawMass;
138 // Undo anything the object thinks it's doing at the moment
139 moveForce = -m_controllingPrim.RawVelocity.Z * m_controllingPrim.Mass;
140
141 m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, new OMV.Vector3(0f, 0f, moveForce));
142 m_physicsScene.DetailLog("{0},BSPrim.Hover,move,targHt={1},moveForce={2},mass={3}",
143 m_controllingPrim.LocalID, targetHeight, moveForce, m_controllingPrim.RawMass);
144 }
145
146 // Based on current position, determine what we should be hovering at now.
147 // Must recompute often. What if we walked offa cliff>
148 private float ComputeCurrentHoverHeight()
149 {
150 float ret = m_controllingPrim.HoverHeight;
151 float groundHeight = m_physicsScene.TerrainManager.GetTerrainHeightAtXYZ(m_controllingPrim.RawPosition);
152
153 switch (m_controllingPrim.HoverType)
154 {
155 case PIDHoverType.Ground:
156 ret = groundHeight + m_controllingPrim.HoverHeight;
157 break;
158 case PIDHoverType.GroundAndWater:
159 float waterHeight = m_physicsScene.TerrainManager.GetWaterLevelAtXYZ(m_controllingPrim.RawPosition);
160 if (groundHeight > waterHeight)
161 {
162 ret = groundHeight + m_controllingPrim.HoverHeight;
163 }
164 else
165 {
166 ret = waterHeight + m_controllingPrim.HoverHeight;
167 }
168 break;
169 }
170 return ret;
171 }
172}
173}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs
new file mode 100755
index 0000000..8b0fdeb
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs
@@ -0,0 +1,187 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using OMV = OpenMetaverse;
34
35namespace OpenSim.Region.Physics.BulletSPlugin
36{
37public class BSActorLockAxis : BSActor
38{
39 BSConstraint LockAxisConstraint = null;
40
41 public BSActorLockAxis(BSScene physicsScene, BSPhysObject pObj, string actorName)
42 : base(physicsScene, pObj, actorName)
43 {
44 m_physicsScene.DetailLog("{0},BSActorLockAxis,constructor", m_controllingPrim.LocalID);
45 LockAxisConstraint = null;
46 }
47
48 // BSActor.isActive
49 public override bool isActive
50 {
51 get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
52 }
53
54 // Release any connections and resources used by the actor.
55 // BSActor.Dispose()
56 public override void Dispose()
57 {
58 RemoveAxisLockConstraint();
59 }
60
61 // Called when physical parameters (properties set in Bullet) need to be re-applied.
62 // Called at taint-time.
63 // BSActor.Refresh()
64 public override void Refresh()
65 {
66 m_physicsScene.DetailLog("{0},BSActorLockAxis,refresh,lockedAxis={1},enabled={2},pActive={3}",
67 m_controllingPrim.LocalID, m_controllingPrim.LockedAngularAxis, Enabled, m_controllingPrim.IsPhysicallyActive);
68 // If all the axis are free, we don't need to exist
69 if (m_controllingPrim.LockedAngularAxis == m_controllingPrim.LockedAxisFree)
70 {
71 Enabled = false;
72 }
73
74 // If the object is physically active, add the axis locking constraint
75 if (isActive)
76 {
77 AddAxisLockConstraint();
78 }
79 else
80 {
81 RemoveAxisLockConstraint();
82 }
83 }
84
85 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
86 // Register a prestep action to restore physical requirements before the next simulation step.
87 // Called at taint-time.
88 // BSActor.RemoveDependencies()
89 public override void RemoveDependencies()
90 {
91 if (LockAxisConstraint != null)
92 {
93 // If a constraint is set up, remove it from the physical scene
94 RemoveAxisLockConstraint();
95 // Schedule a call before the next simulation step to restore the constraint.
96 m_physicsScene.PostTaintObject("BSActorLockAxis:" + ActorName, m_controllingPrim.LocalID, delegate()
97 {
98 Refresh();
99 });
100 }
101 }
102
103 private void AddAxisLockConstraint()
104 {
105 if (LockAxisConstraint == null)
106 {
107 // Lock that axis by creating a 6DOF constraint that has one end in the world and
108 // the other in the object.
109 // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=20817
110 // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=26380
111
112 // Remove any existing axis constraint (just to be sure)
113 RemoveAxisLockConstraint();
114
115 BSConstraint6Dof axisConstrainer = new BSConstraint6Dof(m_physicsScene.World, m_controllingPrim.PhysBody,
116 OMV.Vector3.Zero, OMV.Quaternion.Identity,
117 false /* useLinearReferenceFrameB */, true /* disableCollisionsBetweenLinkedBodies */);
118 LockAxisConstraint = axisConstrainer;
119 m_physicsScene.Constraints.AddConstraint(LockAxisConstraint);
120
121 // The constraint is tied to the world and oriented to the prim.
122
123 // Free to move linearly in the region
124 OMV.Vector3 linearLow = OMV.Vector3.Zero;
125 OMV.Vector3 linearHigh = m_physicsScene.TerrainManager.DefaultRegionSize;
126 if (m_controllingPrim.LockedLinearAxis.X != BSPhysObject.FreeAxis)
127 {
128 linearLow.X = m_controllingPrim.RawPosition.X;
129 linearHigh.X = m_controllingPrim.RawPosition.X;
130 }
131 if (m_controllingPrim.LockedLinearAxis.Y != BSPhysObject.FreeAxis)
132 {
133 linearLow.Y = m_controllingPrim.RawPosition.Y;
134 linearHigh.Y = m_controllingPrim.RawPosition.Y;
135 }
136 if (m_controllingPrim.LockedLinearAxis.Z != BSPhysObject.FreeAxis)
137 {
138 linearLow.Z = m_controllingPrim.RawPosition.Z;
139 linearHigh.Z = m_controllingPrim.RawPosition.Z;
140 }
141 axisConstrainer.SetLinearLimits(linearLow, linearHigh);
142
143 // Angular with some axis locked
144 float fPI = (float)Math.PI;
145 OMV.Vector3 angularLow = new OMV.Vector3(-fPI, -fPI, -fPI);
146 OMV.Vector3 angularHigh = new OMV.Vector3(fPI, fPI, fPI);
147 if (m_controllingPrim.LockedAngularAxis.X != BSPhysObject.FreeAxis)
148 {
149 angularLow.X = 0f;
150 angularHigh.X = 0f;
151 }
152 if (m_controllingPrim.LockedAngularAxis.Y != BSPhysObject.FreeAxis)
153 {
154 angularLow.Y = 0f;
155 angularHigh.Y = 0f;
156 }
157 if (m_controllingPrim.LockedAngularAxis.Z != BSPhysObject.FreeAxis)
158 {
159 angularLow.Z = 0f;
160 angularHigh.Z = 0f;
161 }
162 if (!axisConstrainer.SetAngularLimits(angularLow, angularHigh))
163 {
164 m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,failedSetAngularLimits", m_controllingPrim.LocalID);
165 }
166
167 m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,create,linLow={1},linHi={2},angLow={3},angHi={4}",
168 m_controllingPrim.LocalID, linearLow, linearHigh, angularLow, angularHigh);
169
170 // Constants from one of the posts mentioned above and used in Bullet's ConstraintDemo.
171 axisConstrainer.TranslationalLimitMotor(true /* enable */, 5.0f, 0.1f);
172
173 axisConstrainer.RecomputeConstraintVariables(m_controllingPrim.RawMass);
174 }
175 }
176
177 private void RemoveAxisLockConstraint()
178 {
179 if (LockAxisConstraint != null)
180 {
181 m_physicsScene.Constraints.RemoveAndDestroyConstraint(LockAxisConstraint);
182 LockAxisConstraint = null;
183 m_physicsScene.DetailLog("{0},BSActorLockAxis.RemoveAxisLockConstraint,destroyingConstraint", m_controllingPrim.LocalID);
184 }
185 }
186}
187}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs
new file mode 100755
index 0000000..75ff24e
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs
@@ -0,0 +1,157 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using OpenSim.Region.Physics.Manager;
34
35using OMV = OpenMetaverse;
36
37namespace OpenSim.Region.Physics.BulletSPlugin
38{
39public class BSActorMoveToTarget : BSActor
40{
41 private BSVMotor m_targetMotor;
42
43 public BSActorMoveToTarget(BSScene physicsScene, BSPhysObject pObj, string actorName)
44 : base(physicsScene, pObj, actorName)
45 {
46 m_targetMotor = null;
47 m_physicsScene.DetailLog("{0},BSActorMoveToTarget,constructor", m_controllingPrim.LocalID);
48 }
49
50 // BSActor.isActive
51 public override bool isActive
52 {
53 get { return Enabled; }
54 }
55
56 // Release any connections and resources used by the actor.
57 // BSActor.Dispose()
58 public override void Dispose()
59 {
60 Enabled = false;
61 }
62
63 // Called when physical parameters (properties set in Bullet) need to be re-applied.
64 // Called at taint-time.
65 // BSActor.Refresh()
66 public override void Refresh()
67 {
68 m_physicsScene.DetailLog("{0},BSActorMoveToTarget,refresh,enabled={1},active={2},target={3},tau={4}",
69 m_controllingPrim.LocalID, Enabled, m_controllingPrim.MoveToTargetActive,
70 m_controllingPrim.MoveToTargetTarget, m_controllingPrim.MoveToTargetTau );
71
72 // If not active any more...
73 if (!m_controllingPrim.MoveToTargetActive)
74 {
75 Enabled = false;
76 }
77
78 if (isActive)
79 {
80 ActivateMoveToTarget();
81 }
82 else
83 {
84 DeactivateMoveToTarget();
85 }
86 }
87
88 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
89 // Register a prestep action to restore physical requirements before the next simulation step.
90 // Called at taint-time.
91 // BSActor.RemoveDependencies()
92 public override void RemoveDependencies()
93 {
94 // Nothing to do for the moveToTarget since it is all software at pre-step action time.
95 }
96
97 // If a hover motor has not been created, create one and start the hovering.
98 private void ActivateMoveToTarget()
99 {
100 if (m_targetMotor == null)
101 {
102 // We're taking over after this.
103 m_controllingPrim.ZeroMotion(true);
104
105 m_targetMotor = new BSVMotor("BSActorMoveToTargget.Activate",
106 m_controllingPrim.MoveToTargetTau, // timeScale
107 BSMotor.Infinite, // decay time scale
108 1f // efficiency
109 );
110 m_targetMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG so motor will output detail log messages.
111 m_targetMotor.SetTarget(m_controllingPrim.MoveToTargetTarget);
112 m_targetMotor.SetCurrent(m_controllingPrim.RawPosition);
113
114 m_physicsScene.BeforeStep += Mover;
115 }
116 }
117
118 private void DeactivateMoveToTarget()
119 {
120 if (m_targetMotor != null)
121 {
122 m_physicsScene.BeforeStep -= Mover;
123 m_targetMotor = null;
124 }
125 }
126
127 // Called just before the simulation step. Update the vertical position for hoverness.
128 private void Mover(float timeStep)
129 {
130 // Don't do hovering while the object is selected.
131 if (!isActive)
132 return;
133
134 OMV.Vector3 origPosition = m_controllingPrim.RawPosition; // DEBUG DEBUG (for printout below)
135
136 // 'movePosition' is where we'd like the prim to be at this moment.
137 OMV.Vector3 movePosition = m_controllingPrim.RawPosition + m_targetMotor.Step(timeStep);
138
139 // If we are very close to our target, turn off the movement motor.
140 if (m_targetMotor.ErrorIsZero())
141 {
142 m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover,zeroMovement,movePos={1},pos={2},mass={3}",
143 m_controllingPrim.LocalID, movePosition, m_controllingPrim.RawPosition, m_controllingPrim.Mass);
144 m_controllingPrim.ForcePosition = m_targetMotor.TargetValue;
145 // Setting the position does not cause the physics engine to generate a property update. Force it.
146 m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody);
147 }
148 else
149 {
150 m_controllingPrim.ForcePosition = movePosition;
151 // Setting the position does not cause the physics engine to generate a property update. Force it.
152 m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody);
153 }
154 m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover,move,fromPos={1},movePos={2}", m_controllingPrim.LocalID, origPosition, movePosition);
155 }
156}
157}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs
new file mode 100755
index 0000000..96fa0b6
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs
@@ -0,0 +1,137 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using OpenSim.Region.Physics.Manager;
34
35using OMV = OpenMetaverse;
36
37namespace OpenSim.Region.Physics.BulletSPlugin
38{
39public class BSActorSetForce : BSActor
40{
41 BSFMotor m_forceMotor;
42
43 public BSActorSetForce(BSScene physicsScene, BSPhysObject pObj, string actorName)
44 : base(physicsScene, pObj, actorName)
45 {
46 m_forceMotor = null;
47 m_physicsScene.DetailLog("{0},BSActorSetForce,constructor", m_controllingPrim.LocalID);
48 }
49
50 // BSActor.isActive
51 public override bool isActive
52 {
53 get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
54 }
55
56 // Release any connections and resources used by the actor.
57 // BSActor.Dispose()
58 public override void Dispose()
59 {
60 Enabled = false;
61 }
62
63 // Called when physical parameters (properties set in Bullet) need to be re-applied.
64 // Called at taint-time.
65 // BSActor.Refresh()
66 public override void Refresh()
67 {
68 m_physicsScene.DetailLog("{0},BSActorSetForce,refresh", m_controllingPrim.LocalID);
69
70 // If not active any more, get rid of me (shouldn't ever happen, but just to be safe)
71 if (m_controllingPrim.RawForce == OMV.Vector3.Zero)
72 {
73 m_physicsScene.DetailLog("{0},BSActorSetForce,refresh,notSetForce,removing={1}", m_controllingPrim.LocalID, ActorName);
74 Enabled = false;
75 return;
76 }
77
78 // If the object is physically active, add the hoverer prestep action
79 if (isActive)
80 {
81 ActivateSetForce();
82 }
83 else
84 {
85 DeactivateSetForce();
86 }
87 }
88
89 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
90 // Register a prestep action to restore physical requirements before the next simulation step.
91 // Called at taint-time.
92 // BSActor.RemoveDependencies()
93 public override void RemoveDependencies()
94 {
95 // Nothing to do for the hoverer since it is all software at pre-step action time.
96 }
97
98 // If a hover motor has not been created, create one and start the hovering.
99 private void ActivateSetForce()
100 {
101 if (m_forceMotor == null)
102 {
103 // A fake motor that might be used someday
104 m_forceMotor = new BSFMotor("setForce", 1f, 1f, 1f);
105
106 m_physicsScene.BeforeStep += Mover;
107 }
108 }
109
110 private void DeactivateSetForce()
111 {
112 if (m_forceMotor != null)
113 {
114 m_physicsScene.BeforeStep -= Mover;
115 m_forceMotor = null;
116 }
117 }
118
119 // Called just before the simulation step. Update the vertical position for hoverness.
120 private void Mover(float timeStep)
121 {
122 // Don't do force while the object is selected.
123 if (!isActive)
124 return;
125
126 m_physicsScene.DetailLog("{0},BSActorSetForce,preStep,force={1}", m_controllingPrim.LocalID, m_controllingPrim.RawForce);
127 if (m_controllingPrim.PhysBody.HasPhysicalBody)
128 {
129 m_physicsScene.PE.ApplyCentralForce(m_controllingPrim.PhysBody, m_controllingPrim.RawForce);
130 m_controllingPrim.ActivateIfPhysical(false);
131 }
132
133 // TODO:
134 }
135}
136}
137
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs
new file mode 100755
index 0000000..65098e1
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs
@@ -0,0 +1,138 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using OpenSim.Region.Physics.Manager;
34
35using OMV = OpenMetaverse;
36
37namespace OpenSim.Region.Physics.BulletSPlugin
38{
39public class BSActorSetTorque : BSActor
40{
41 BSFMotor m_torqueMotor;
42
43 public BSActorSetTorque(BSScene physicsScene, BSPhysObject pObj, string actorName)
44 : base(physicsScene, pObj, actorName)
45 {
46 m_torqueMotor = null;
47 m_physicsScene.DetailLog("{0},BSActorSetTorque,constructor", m_controllingPrim.LocalID);
48 }
49
50 // BSActor.isActive
51 public override bool isActive
52 {
53 get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
54 }
55
56 // Release any connections and resources used by the actor.
57 // BSActor.Dispose()
58 public override void Dispose()
59 {
60 Enabled = false;
61 }
62
63 // Called when physical parameters (properties set in Bullet) need to be re-applied.
64 // Called at taint-time.
65 // BSActor.Refresh()
66 public override void Refresh()
67 {
68 m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh,torque={1}", m_controllingPrim.LocalID, m_controllingPrim.RawTorque);
69
70 // If not active any more, get rid of me (shouldn't ever happen, but just to be safe)
71 if (m_controllingPrim.RawTorque == OMV.Vector3.Zero)
72 {
73 m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh,notSetTorque,disabling={1}", m_controllingPrim.LocalID, ActorName);
74 Enabled = false;
75 return;
76 }
77
78 // If the object is physically active, add the hoverer prestep action
79 if (isActive)
80 {
81 ActivateSetTorque();
82 }
83 else
84 {
85 DeactivateSetTorque();
86 }
87 }
88
89 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
90 // Register a prestep action to restore physical requirements before the next simulation step.
91 // Called at taint-time.
92 // BSActor.RemoveDependencies()
93 public override void RemoveDependencies()
94 {
95 // Nothing to do for the hoverer since it is all software at pre-step action time.
96 }
97
98 // If a hover motor has not been created, create one and start the hovering.
99 private void ActivateSetTorque()
100 {
101 if (m_torqueMotor == null)
102 {
103 // A fake motor that might be used someday
104 m_torqueMotor = new BSFMotor("setTorque", 1f, 1f, 1f);
105
106 m_physicsScene.BeforeStep += Mover;
107 }
108 }
109
110 private void DeactivateSetTorque()
111 {
112 if (m_torqueMotor != null)
113 {
114 m_physicsScene.BeforeStep -= Mover;
115 m_torqueMotor = null;
116 }
117 }
118
119 // Called just before the simulation step. Update the vertical position for hoverness.
120 private void Mover(float timeStep)
121 {
122 // Don't do force while the object is selected.
123 if (!isActive)
124 return;
125
126 m_physicsScene.DetailLog("{0},BSActorSetTorque,preStep,force={1}", m_controllingPrim.LocalID, m_controllingPrim.RawTorque);
127 if (m_controllingPrim.PhysBody.HasPhysicalBody)
128 {
129 m_controllingPrim.AddAngularForce(m_controllingPrim.RawTorque, false, true);
130 m_controllingPrim.ActivateIfPhysical(false);
131 }
132
133 // TODO:
134 }
135}
136}
137
138
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs
new file mode 100755
index 0000000..fff63e4
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs
@@ -0,0 +1,160 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31namespace OpenSim.Region.Physics.BulletSPlugin
32{
33public class BSActorCollection
34{
35 private BSScene m_physicsScene { get; set; }
36 private Dictionary<string, BSActor> m_actors;
37
38 public BSActorCollection(BSScene physicsScene)
39 {
40 m_physicsScene = physicsScene;
41 m_actors = new Dictionary<string, BSActor>();
42 }
43 public void Add(string name, BSActor actor)
44 {
45 lock (m_actors)
46 {
47 if (!m_actors.ContainsKey(name))
48 {
49 m_actors[name] = actor;
50 }
51 }
52 }
53 public bool RemoveAndRelease(string name)
54 {
55 bool ret = false;
56 lock (m_actors)
57 {
58 if (m_actors.ContainsKey(name))
59 {
60 BSActor beingRemoved = m_actors[name];
61 m_actors.Remove(name);
62 beingRemoved.Dispose();
63 ret = true;
64 }
65 }
66 return ret;
67 }
68 public void Clear()
69 {
70 lock (m_actors)
71 {
72 Release();
73 m_actors.Clear();
74 }
75 }
76 public void Dispose()
77 {
78 Clear();
79 }
80 public bool HasActor(string name)
81 {
82 return m_actors.ContainsKey(name);
83 }
84 public bool TryGetActor(string actorName, out BSActor theActor)
85 {
86 return m_actors.TryGetValue(actorName, out theActor);
87 }
88 public void ForEachActor(Action<BSActor> act)
89 {
90 lock (m_actors)
91 {
92 foreach (KeyValuePair<string, BSActor> kvp in m_actors)
93 act(kvp.Value);
94 }
95 }
96
97 public void Enable(bool enabl)
98 {
99 ForEachActor(a => a.SetEnabled(enabl));
100 }
101 public void Release()
102 {
103 ForEachActor(a => a.Dispose());
104 }
105 public void Refresh()
106 {
107 ForEachActor(a => a.Refresh());
108 }
109 public void RemoveDependencies()
110 {
111 ForEachActor(a => a.RemoveDependencies());
112 }
113}
114
115// =============================================================================
116/// <summary>
117/// Each physical object can have 'actors' who are pushing the object around.
118/// This can be used for hover, locking axis, making vehicles, etc.
119/// Each physical object can have multiple actors acting on it.
120///
121/// An actor usually registers itself with physics scene events (pre-step action)
122/// and modifies the parameters on the host physical object.
123/// </summary>
124public abstract class BSActor
125{
126 protected BSScene m_physicsScene { get; private set; }
127 protected BSPhysObject m_controllingPrim { get; private set; }
128 public virtual bool Enabled { get; set; }
129 public string ActorName { get; private set; }
130
131 public BSActor(BSScene physicsScene, BSPhysObject pObj, string actorName)
132 {
133 m_physicsScene = physicsScene;
134 m_controllingPrim = pObj;
135 ActorName = actorName;
136 Enabled = true;
137 }
138
139 // Return 'true' if activily updating the prim
140 public virtual bool isActive
141 {
142 get { return Enabled; }
143 }
144
145 // Turn the actor on an off. Only used by ActorCollection to set all enabled/disabled.
146 // Anyone else should assign true/false to 'Enabled'.
147 public void SetEnabled(bool setEnabled)
148 {
149 Enabled = setEnabled;
150 }
151 // Release any connections and resources used by the actor.
152 public abstract void Dispose();
153 // Called when physical parameters (properties set in Bullet) need to be re-applied.
154 public abstract void Refresh();
155 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
156 // Register a prestep action to restore physical requirements before the next simulation step.
157 public abstract void RemoveDependencies();
158
159}
160}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs
index 5765b0d..6cdc112 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs
@@ -70,6 +70,8 @@ public enum BSPhysicsShapeType
70 SHAPE_COMPOUND = 22, 70 SHAPE_COMPOUND = 22,
71 SHAPE_HEIGHTMAP = 23, 71 SHAPE_HEIGHTMAP = 23,
72 SHAPE_AVATAR = 24, 72 SHAPE_AVATAR = 24,
73 SHAPE_CONVEXHULL= 25,
74 SHAPE_GIMPACT = 26,
73}; 75};
74 76
75// The native shapes have predefined shape hash keys 77// The native shapes have predefined shape hash keys
@@ -191,6 +193,21 @@ public struct ConfigurationParameters
191 public const float numericFalse = 0f; 193 public const float numericFalse = 0f;
192} 194}
193 195
196// Parameters passed for the conversion of a mesh to a hull using Bullet's HACD library.
197[StructLayout(LayoutKind.Sequential)]
198public struct HACDParams
199{
200 // usual default values
201 public float maxVerticesPerHull; // 100
202 public float minClusters; // 2
203 public float compacityWeight; // 0.1
204 public float volumeWeight; // 0.0
205 public float concavity; // 100
206 public float addExtraDistPoints; // false
207 public float addNeighboursDistPoints; // false
208 public float addFacesPoints; // false
209 public float shouldAdjustCollisionMargin; // false
210}
194 211
195// The states a bullet collision object can have 212// The states a bullet collision object can have
196public enum ActivationState : uint 213public enum ActivationState : uint
@@ -282,7 +299,7 @@ public abstract class BSAPITemplate
282{ 299{
283// Returns the name of the underlying Bullet engine 300// Returns the name of the underlying Bullet engine
284public abstract string BulletEngineName { get; } 301public abstract string BulletEngineName { get; }
285public abstract string BulletEngineVersion { get; protected set;} 302public abstract string BulletEngineVersion { get; protected set;}
286 303
287// Initialization and simulation 304// Initialization and simulation
288public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms, 305public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms,
@@ -305,10 +322,20 @@ public abstract BulletShape CreateMeshShape(BulletWorld world,
305 int indicesCount, int[] indices, 322 int indicesCount, int[] indices,
306 int verticesCount, float[] vertices ); 323 int verticesCount, float[] vertices );
307 324
325public abstract BulletShape CreateGImpactShape(BulletWorld world,
326 int indicesCount, int[] indices,
327 int verticesCount, float[] vertices );
328
308public abstract BulletShape CreateHullShape(BulletWorld world, 329public abstract BulletShape CreateHullShape(BulletWorld world,
309 int hullCount, float[] hulls); 330 int hullCount, float[] hulls);
310 331
311public abstract BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape); 332public abstract BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms);
333
334public abstract BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape);
335
336public abstract BulletShape CreateConvexHullShape(BulletWorld world,
337 int indicesCount, int[] indices,
338 int verticesCount, float[] vertices );
312 339
313public abstract BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData); 340public abstract BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData);
314 341
@@ -351,7 +378,7 @@ public abstract void DestroyObject(BulletWorld sim, BulletBody obj);
351// ===================================================================================== 378// =====================================================================================
352public abstract BulletShape CreateGroundPlaneShape(UInt32 id, float height, float collisionMargin); 379public abstract BulletShape CreateGroundPlaneShape(UInt32 id, float height, float collisionMargin);
353 380
354public abstract BulletShape CreateTerrainShape(UInt32 id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, 381public abstract BulletShape CreateTerrainShape(UInt32 id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
355 float scaleFactor, float collisionMargin); 382 float scaleFactor, float collisionMargin);
356 383
357// ===================================================================================== 384// =====================================================================================
@@ -366,7 +393,7 @@ public abstract BulletConstraint Create6DofConstraintToPoint(BulletWorld world,
366 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); 393 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
367 394
368public abstract BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1, 395public abstract BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1,
369 Vector3 frameInBloc, Quaternion frameInBrot, 396 Vector3 frameInBloc, Quaternion frameInBrot,
370 bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies); 397 bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies);
371 398
372public abstract BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, 399public abstract BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index 90c2d9c..48f842e 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -1,4 +1,4 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
@@ -46,9 +46,6 @@ public sealed class BSCharacter : BSPhysObject
46 private OMV.Vector3 _position; 46 private OMV.Vector3 _position;
47 private float _mass; 47 private float _mass;
48 private float _avatarVolume; 48 private float _avatarVolume;
49 private OMV.Vector3 _force;
50 private OMV.Vector3 _velocity;
51 private OMV.Vector3 _torque;
52 private float _collisionScore; 49 private float _collisionScore;
53 private OMV.Vector3 _acceleration; 50 private OMV.Vector3 _acceleration;
54 private OMV.Quaternion _orientation; 51 private OMV.Quaternion _orientation;
@@ -62,15 +59,12 @@ public sealed class BSCharacter : BSPhysObject
62 private bool _kinematic; 59 private bool _kinematic;
63 private float _buoyancy; 60 private float _buoyancy;
64 61
65 private BSVMotor _velocityMotor; 62 private BSActorAvatarMove m_moveActor;
63 private const string AvatarMoveActorName = "BSCharacter.AvatarMove";
66 64
67 private OMV.Vector3 _PIDTarget; 65 private OMV.Vector3 _PIDTarget;
68 private bool _usePID; 66 private bool _usePID;
69 private float _PIDTau; 67 private float _PIDTau;
70 private bool _useHoverPID;
71 private float _PIDHoverHeight;
72 private PIDHoverType _PIDHoverType;
73 private float _PIDHoverTao;
74 68
75 public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying) 69 public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying)
76 : base(parent_scene, localID, avName, "BSCharacter") 70 : base(parent_scene, localID, avName, "BSCharacter")
@@ -80,7 +74,7 @@ public sealed class BSCharacter : BSPhysObject
80 74
81 _flying = isFlying; 75 _flying = isFlying;
82 _orientation = OMV.Quaternion.Identity; 76 _orientation = OMV.Quaternion.Identity;
83 _velocity = OMV.Vector3.Zero; 77 RawVelocity = OMV.Vector3.Zero;
84 _buoyancy = ComputeBuoyancyFromFlying(isFlying); 78 _buoyancy = ComputeBuoyancyFromFlying(isFlying);
85 Friction = BSParam.AvatarStandingFriction; 79 Friction = BSParam.AvatarStandingFriction;
86 Density = BSParam.AvatarDensity / BSParam.DensityScaleFactor; 80 Density = BSParam.AvatarDensity / BSParam.DensityScaleFactor;
@@ -97,17 +91,22 @@ public sealed class BSCharacter : BSPhysObject
97 // set _avatarVolume and _mass based on capsule size, _density and Scale 91 // set _avatarVolume and _mass based on capsule size, _density and Scale
98 ComputeAvatarVolumeAndMass(); 92 ComputeAvatarVolumeAndMass();
99 93
100 SetupMovementMotor(); 94 // The avatar's movement is controlled by this motor that speeds up and slows down
95 // the avatar seeking to reach the motor's target speed.
96 // This motor runs as a prestep action for the avatar so it will keep the avatar
97 // standing as well as moving. Destruction of the avatar will destroy the pre-step action.
98 m_moveActor = new BSActorAvatarMove(PhysScene, this, AvatarMoveActorName);
99 PhysicalActors.Add(AvatarMoveActorName, m_moveActor);
101 100
102 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", 101 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
103 LocalID, _size, Scale, Density, _avatarVolume, RawMass); 102 LocalID, _size, Scale, Density, _avatarVolume, RawMass);
104 103
105 // do actual creation in taint time 104 // do actual creation in taint time
106 PhysicsScene.TaintedObject("BSCharacter.create", delegate() 105 PhysScene.TaintedObject("BSCharacter.create", delegate()
107 { 106 {
108 DetailLog("{0},BSCharacter.create,taint", LocalID); 107 DetailLog("{0},BSCharacter.create,taint", LocalID);
109 // New body and shape into PhysBody and PhysShape 108 // New body and shape into PhysBody and PhysShape
110 PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this); 109 PhysScene.Shapes.GetBodyAndShape(true, PhysScene.World, this);
111 110
112 SetPhysicalProperties(); 111 SetPhysicalProperties();
113 }); 112 });
@@ -120,214 +119,63 @@ public sealed class BSCharacter : BSPhysObject
120 base.Destroy(); 119 base.Destroy();
121 120
122 DetailLog("{0},BSCharacter.Destroy", LocalID); 121 DetailLog("{0},BSCharacter.Destroy", LocalID);
123 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() 122 PhysScene.TaintedObject("BSCharacter.destroy", delegate()
124 { 123 {
125 PhysicsScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */); 124 PhysScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */);
126 PhysBody.Clear(); 125 PhysBody.Clear();
127 PhysicsScene.Shapes.DereferenceShape(PhysShape, null /* bodyCallback */); 126 PhysShape.Dereference(PhysScene);
128 PhysShape.Clear(); 127 PhysShape = new BSShapeNull();
129 }); 128 });
130 } 129 }
131 130
132 private void SetPhysicalProperties() 131 private void SetPhysicalProperties()
133 { 132 {
134 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); 133 PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
135 134
136 ZeroMotion(true); 135 ZeroMotion(true);
137 ForcePosition = _position; 136 ForcePosition = _position;
138 137
139 // Set the velocity 138 // Set the velocity
140 _velocityMotor.Reset(); 139 if (m_moveActor != null)
141 _velocityMotor.SetTarget(_velocity); 140 m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, false);
142 _velocityMotor.SetCurrent(_velocity); 141
143 ForceVelocity = _velocity; 142 ForceVelocity = RawVelocity;
144 143
145 // This will enable or disable the flying buoyancy of the avatar. 144 // This will enable or disable the flying buoyancy of the avatar.
146 // Needs to be reset especially when an avatar is recreated after crossing a region boundry. 145 // Needs to be reset especially when an avatar is recreated after crossing a region boundry.
147 Flying = _flying; 146 Flying = _flying;
148 147
149 PhysicsScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution); 148 PhysScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution);
150 PhysicsScene.PE.SetMargin(PhysShape, PhysicsScene.Params.collisionMargin); 149 PhysScene.PE.SetMargin(PhysShape.physShapeInfo, PhysScene.Params.collisionMargin);
151 PhysicsScene.PE.SetLocalScaling(PhysShape, Scale); 150 PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale);
152 PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); 151 PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
153 if (BSParam.CcdMotionThreshold > 0f) 152 if (BSParam.CcdMotionThreshold > 0f)
154 { 153 {
155 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); 154 PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
156 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); 155 PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
157 } 156 }
158 157
159 UpdatePhysicalMassProperties(RawMass, false); 158 UpdatePhysicalMassProperties(RawMass, false);
160 159
161 // Make so capsule does not fall over 160 // Make so capsule does not fall over
162 PhysicsScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero); 161 PhysScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero);
162
163 // The avatar mover sets some parameters.
164 PhysicalActors.Refresh();
163 165
164 PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT); 166 PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT);
165 167
166 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); 168 PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody);
167 169
168 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); 170 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
169 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION); 171 PhysScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION);
170 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody); 172 PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody);
171 173
172 // Do this after the object has been added to the world 174 // Do this after the object has been added to the world
173 PhysBody.collisionType = CollisionType.Avatar; 175 PhysBody.collisionType = CollisionType.Avatar;
174 PhysBody.ApplyCollisionMask(PhysicsScene); 176 PhysBody.ApplyCollisionMask(PhysScene);
175 }
176
177 // The avatar's movement is controlled by this motor that speeds up and slows down
178 // the avatar seeking to reach the motor's target speed.
179 // This motor runs as a prestep action for the avatar so it will keep the avatar
180 // standing as well as moving. Destruction of the avatar will destroy the pre-step action.
181 private void SetupMovementMotor()
182 {
183 // Infinite decay and timescale values so motor only changes current to target values.
184 _velocityMotor = new BSVMotor("BSCharacter.Velocity",
185 0.2f, // time scale
186 BSMotor.Infinite, // decay time scale
187 BSMotor.InfiniteVector, // friction timescale
188 1f // efficiency
189 );
190 // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
191
192 RegisterPreStepAction("BSCharactor.Movement", LocalID, delegate(float timeStep)
193 {
194 // TODO: Decide if the step parameters should be changed depending on the avatar's
195 // state (flying, colliding, ...). There is code in ODE to do this.
196
197 // COMMENTARY: when the user is making the avatar walk, except for falling, the velocity
198 // specified for the avatar is the one that should be used. For falling, if the avatar
199 // is not flying and is not colliding then it is presumed to be falling and the Z
200 // component is not fooled with (thus allowing gravity to do its thing).
201 // When the avatar is standing, though, the user has specified a velocity of zero and
202 // the avatar should be standing. But if the avatar is pushed by something in the world
203 // (raising elevator platform, moving vehicle, ...) the avatar should be allowed to
204 // move. Thus, the velocity cannot be forced to zero. The problem is that small velocity
205 // errors can creap in and the avatar will slowly float off in some direction.
206 // So, the problem is that, when an avatar is standing, we cannot tell creaping error
207 // from real pushing.
208 // The code below uses whether the collider is static or moving to decide whether to zero motion.
209
210 _velocityMotor.Step(timeStep);
211
212 // If we're not supposed to be moving, make sure things are zero.
213 if (_velocityMotor.ErrorIsZero() && _velocityMotor.TargetValue == OMV.Vector3.Zero)
214 {
215 // The avatar shouldn't be moving
216 _velocityMotor.Zero();
217
218 if (IsColliding)
219 {
220 // If we are colliding with a stationary object, presume we're standing and don't move around
221 if (!ColliderIsMoving)
222 {
223 DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", LocalID);
224 ZeroMotion(true /* inTaintTime */);
225 }
226
227 // Standing has more friction on the ground
228 if (Friction != BSParam.AvatarStandingFriction)
229 {
230 Friction = BSParam.AvatarStandingFriction;
231 PhysicsScene.PE.SetFriction(PhysBody, Friction);
232 }
233 }
234 else
235 {
236 if (Flying)
237 {
238 // Flying and not collising and velocity nearly zero.
239 ZeroMotion(true /* inTaintTime */);
240 }
241 }
242
243 DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2}", LocalID, _velocityMotor.TargetValue, IsColliding);
244 }
245 else
246 {
247 // Supposed to be moving.
248 OMV.Vector3 stepVelocity = _velocityMotor.CurrentValue;
249
250 if (Friction != BSParam.AvatarFriction)
251 {
252 // Probably starting up walking. Set friction to moving friction.
253 Friction = BSParam.AvatarFriction;
254 PhysicsScene.PE.SetFriction(PhysBody, Friction);
255 }
256
257 // If falling, we keep the world's downward vector no matter what the other axis specify.
258 // The check for _velocity.Z < 0 makes jumping work (temporary upward force).
259 if (!Flying && !IsColliding)
260 {
261 if (_velocity.Z < 0)
262 stepVelocity.Z = _velocity.Z;
263 // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity);
264 }
265
266 // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force.
267 OMV.Vector3 moveForce = (stepVelocity - _velocity) * Mass;
268
269 // Should we check for move force being small and forcing velocity to zero?
270
271 // Add special movement force to allow avatars to walk up stepped surfaces.
272 moveForce += WalkUpStairs();
273
274 DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", LocalID, stepVelocity, _velocity, Mass, moveForce);
275 PhysicsScene.PE.ApplyCentralImpulse(PhysBody, moveForce);
276 }
277 });
278 } 177 }
279 178
280 // Decide if the character is colliding with a low object and compute a force to pop the
281 // avatar up so it can walk up and over the low objects.
282 private OMV.Vector3 WalkUpStairs()
283 {
284 OMV.Vector3 ret = OMV.Vector3.Zero;
285
286 // This test is done if moving forward, not flying and is colliding with something.
287 // DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4}",
288 // LocalID, IsColliding, Flying, TargetSpeed, CollisionsLastTick.Count);
289 if (IsColliding && !Flying && TargetVelocitySpeed > 0.1f /* && ForwardSpeed < 0.1f */)
290 {
291 // The range near the character's feet where we will consider stairs
292 float nearFeetHeightMin = RawPosition.Z - (Size.Z / 2f) + 0.05f;
293 float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight;
294
295 // Look for a collision point that is near the character's feet and is oriented the same as the charactor is
296 foreach (KeyValuePair<uint, ContactPoint> kvp in CollisionsLastTick.m_objCollisionList)
297 {
298 // Don't care about collisions with the terrain
299 if (kvp.Key > PhysicsScene.TerrainManager.HighestTerrainID)
300 {
301 OMV.Vector3 touchPosition = kvp.Value.Position;
302 // DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}",
303 // LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition);
304 if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax)
305 {
306 // This contact is within the 'near the feet' range.
307 // The normal should be our contact point to the object so it is pointing away
308 // thus the difference between our facing orientation and the normal should be small.
309 OMV.Vector3 directionFacing = OMV.Vector3.UnitX * RawOrientation;
310 OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal);
311 float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal));
312 if (diff < BSParam.AvatarStepApproachFactor)
313 {
314 // Found the stairs contact point. Push up a little to raise the character.
315 float upForce = (touchPosition.Z - nearFeetHeightMin) * Mass * BSParam.AvatarStepForceFactor;
316 ret = new OMV.Vector3(0f, 0f, upForce);
317
318 // Also move the avatar up for the new height
319 OMV.Vector3 displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight / 2f);
320 ForcePosition = RawPosition + displacement;
321 }
322 DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},faceDir={3},norm={4},diff={5},ret={6}",
323 LocalID, touchPosition, nearFeetHeightMin, directionFacing, touchNormal, diff, ret);
324 }
325 }
326 }
327 }
328
329 return ret;
330 }
331 179
332 public override void RequestPhysicsterseUpdate() 180 public override void RequestPhysicsterseUpdate()
333 { 181 {
@@ -355,14 +203,14 @@ public sealed class BSCharacter : BSPhysObject
355 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", 203 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}",
356 LocalID, _size, Scale, Density, _avatarVolume, RawMass); 204 LocalID, _size, Scale, Density, _avatarVolume, RawMass);
357 205
358 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() 206 PhysScene.TaintedObject("BSCharacter.setSize", delegate()
359 { 207 {
360 if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape) 208 if (PhysBody.HasPhysicalBody && PhysShape.physShapeInfo.HasPhysicalShape)
361 { 209 {
362 PhysicsScene.PE.SetLocalScaling(PhysShape, Scale); 210 PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale);
363 UpdatePhysicalMassProperties(RawMass, true); 211 UpdatePhysicalMassProperties(RawMass, true);
364 // Make sure this change appears as a property update event 212 // Make sure this change appears as a property update event
365 PhysicsScene.PE.PushUpdate(PhysBody); 213 PhysScene.PE.PushUpdate(PhysBody);
366 } 214 }
367 }); 215 });
368 216
@@ -373,11 +221,6 @@ public sealed class BSCharacter : BSPhysObject
373 { 221 {
374 set { BaseShape = value; } 222 set { BaseShape = value; }
375 } 223 }
376 // I want the physics engine to make an avatar capsule
377 public override BSPhysicsShapeType PreferredPhysicalShape
378 {
379 get {return BSPhysicsShapeType.SHAPE_CAPSULE; }
380 }
381 224
382 public override bool Grabbed { 225 public override bool Grabbed {
383 set { _grabbed = value; } 226 set { _grabbed = value; }
@@ -399,29 +242,29 @@ public sealed class BSCharacter : BSPhysObject
399 // Called at taint time! 242 // Called at taint time!
400 public override void ZeroMotion(bool inTaintTime) 243 public override void ZeroMotion(bool inTaintTime)
401 { 244 {
402 _velocity = OMV.Vector3.Zero; 245 RawVelocity = OMV.Vector3.Zero;
403 _acceleration = OMV.Vector3.Zero; 246 _acceleration = OMV.Vector3.Zero;
404 _rotationalVelocity = OMV.Vector3.Zero; 247 _rotationalVelocity = OMV.Vector3.Zero;
405 248
406 // Zero some other properties directly into the physics engine 249 // Zero some other properties directly into the physics engine
407 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() 250 PhysScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
408 { 251 {
409 if (PhysBody.HasPhysicalBody) 252 if (PhysBody.HasPhysicalBody)
410 PhysicsScene.PE.ClearAllForces(PhysBody); 253 PhysScene.PE.ClearAllForces(PhysBody);
411 }); 254 });
412 } 255 }
413 public override void ZeroAngularMotion(bool inTaintTime) 256 public override void ZeroAngularMotion(bool inTaintTime)
414 { 257 {
415 _rotationalVelocity = OMV.Vector3.Zero; 258 _rotationalVelocity = OMV.Vector3.Zero;
416 259
417 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() 260 PhysScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
418 { 261 {
419 if (PhysBody.HasPhysicalBody) 262 if (PhysBody.HasPhysicalBody)
420 { 263 {
421 PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero); 264 PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero);
422 PhysicsScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero); 265 PhysScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero);
423 // The next also get rid of applied linear force but the linear velocity is untouched. 266 // The next also get rid of applied linear force but the linear velocity is untouched.
424 PhysicsScene.PE.ClearForces(PhysBody); 267 PhysScene.PE.ClearForces(PhysBody);
425 } 268 }
426 }); 269 });
427 } 270 }
@@ -443,7 +286,7 @@ public sealed class BSCharacter : BSPhysObject
443 set { 286 set {
444 _position = value; 287 _position = value;
445 288
446 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() 289 PhysScene.TaintedObject("BSCharacter.setPosition", delegate()
447 { 290 {
448 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 291 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
449 PositionSanityCheck(); 292 PositionSanityCheck();
@@ -453,14 +296,14 @@ public sealed class BSCharacter : BSPhysObject
453 } 296 }
454 public override OMV.Vector3 ForcePosition { 297 public override OMV.Vector3 ForcePosition {
455 get { 298 get {
456 _position = PhysicsScene.PE.GetPosition(PhysBody); 299 _position = PhysScene.PE.GetPosition(PhysBody);
457 return _position; 300 return _position;
458 } 301 }
459 set { 302 set {
460 _position = value; 303 _position = value;
461 if (PhysBody.HasPhysicalBody) 304 if (PhysBody.HasPhysicalBody)
462 { 305 {
463 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); 306 PhysScene.PE.SetTranslation(PhysBody, _position, _orientation);
464 } 307 }
465 } 308 }
466 } 309 }
@@ -474,18 +317,18 @@ public sealed class BSCharacter : BSPhysObject
474 bool ret = false; 317 bool ret = false;
475 318
476 // TODO: check for out of bounds 319 // TODO: check for out of bounds
477 if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) 320 if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition))
478 { 321 {
479 // The character is out of the known/simulated area. 322 // The character is out of the known/simulated area.
480 // Force the avatar position to be within known. ScenePresence will use the position 323 // Force the avatar position to be within known. ScenePresence will use the position
481 // plus the velocity to decide if the avatar is moving out of the region. 324 // plus the velocity to decide if the avatar is moving out of the region.
482 RawPosition = PhysicsScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition); 325 RawPosition = PhysScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition);
483 DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition); 326 DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition);
484 return true; 327 return true;
485 } 328 }
486 329
487 // If below the ground, move the avatar up 330 // If below the ground, move the avatar up
488 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); 331 float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
489 if (Position.Z < terrainHeight) 332 if (Position.Z < terrainHeight)
490 { 333 {
491 DetailLog("{0},BSCharacter.PositionSanityCheck,adjustForUnderGround,pos={1},terrain={2}", LocalID, _position, terrainHeight); 334 DetailLog("{0},BSCharacter.PositionSanityCheck,adjustForUnderGround,pos={1},terrain={2}", LocalID, _position, terrainHeight);
@@ -494,7 +337,7 @@ public sealed class BSCharacter : BSPhysObject
494 } 337 }
495 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) 338 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
496 { 339 {
497 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); 340 float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(_position);
498 if (Position.Z < waterHeight) 341 if (Position.Z < waterHeight)
499 { 342 {
500 _position.Z = waterHeight; 343 _position.Z = waterHeight;
@@ -515,7 +358,7 @@ public sealed class BSCharacter : BSPhysObject
515 { 358 {
516 // The new position value must be pushed into the physics engine but we can't 359 // The new position value must be pushed into the physics engine but we can't
517 // just assign to "Position" because of potential call loops. 360 // just assign to "Position" because of potential call loops.
518 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() 361 PhysScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate()
519 { 362 {
520 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); 363 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
521 ForcePosition = _position; 364 ForcePosition = _position;
@@ -528,25 +371,25 @@ public sealed class BSCharacter : BSPhysObject
528 public override float Mass { get { return _mass; } } 371 public override float Mass { get { return _mass; } }
529 372
530 // used when we only want this prim's mass and not the linkset thing 373 // used when we only want this prim's mass and not the linkset thing
531 public override float RawMass { 374 public override float RawMass {
532 get {return _mass; } 375 get {return _mass; }
533 } 376 }
534 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) 377 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
535 { 378 {
536 OMV.Vector3 localInertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass); 379 OMV.Vector3 localInertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass);
537 PhysicsScene.PE.SetMassProps(PhysBody, physMass, localInertia); 380 PhysScene.PE.SetMassProps(PhysBody, physMass, localInertia);
538 } 381 }
539 382
540 public override OMV.Vector3 Force { 383 public override OMV.Vector3 Force {
541 get { return _force; } 384 get { return RawForce; }
542 set { 385 set {
543 _force = value; 386 RawForce = value;
544 // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); 387 // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
545 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() 388 PhysScene.TaintedObject("BSCharacter.SetForce", delegate()
546 { 389 {
547 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); 390 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, RawForce);
548 if (PhysBody.HasPhysicalBody) 391 if (PhysBody.HasPhysicalBody)
549 PhysicsScene.PE.SetObjectForce(PhysBody, _force); 392 PhysScene.PE.SetObjectForce(PhysBody, RawForce);
550 }); 393 });
551 } 394 }
552 } 395 }
@@ -569,61 +412,49 @@ public sealed class BSCharacter : BSPhysObject
569 { 412 {
570 get 413 get
571 { 414 {
572 return m_targetVelocity; 415 return base.m_targetVelocity;
573 } 416 }
574 set 417 set
575 { 418 {
576 DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value); 419 DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value);
577 m_targetVelocity = value; 420 m_targetVelocity = value;
578 OMV.Vector3 targetVel = value; 421 OMV.Vector3 targetVel = value;
579 if (_setAlwaysRun) 422 if (_setAlwaysRun && !_flying)
580 targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 0f); 423 targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 0f);
581 424
582 PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate() 425 if (m_moveActor != null)
583 { 426 m_moveActor.SetVelocityAndTarget(RawVelocity, targetVel, false /* inTaintTime */);
584 _velocityMotor.Reset();
585 _velocityMotor.SetTarget(targetVel);
586 _velocityMotor.SetCurrent(_velocity);
587 _velocityMotor.Enabled = true;
588 });
589 } 427 }
590 } 428 }
591 public override OMV.Vector3 RawVelocity
592 {
593 get { return _velocity; }
594 set { _velocity = value; }
595 }
596 // Directly setting velocity means this is what the user really wants now. 429 // Directly setting velocity means this is what the user really wants now.
597 public override OMV.Vector3 Velocity { 430 public override OMV.Vector3 Velocity {
598 get { return _velocity; } 431 get { return RawVelocity; }
599 set { 432 set {
600 _velocity = value; 433 RawVelocity = value;
601 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); 434 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, RawVelocity);
602 PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() 435 PhysScene.TaintedObject("BSCharacter.setVelocity", delegate()
603 { 436 {
604 _velocityMotor.Reset(); 437 if (m_moveActor != null)
605 _velocityMotor.SetCurrent(_velocity); 438 m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, true /* inTaintTime */);
606 _velocityMotor.SetTarget(_velocity);
607 _velocityMotor.Enabled = false;
608 439
609 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); 440 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, RawVelocity);
610 ForceVelocity = _velocity; 441 ForceVelocity = RawVelocity;
611 }); 442 });
612 } 443 }
613 } 444 }
614 public override OMV.Vector3 ForceVelocity { 445 public override OMV.Vector3 ForceVelocity {
615 get { return _velocity; } 446 get { return RawVelocity; }
616 set { 447 set {
617 PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity"); 448 PhysScene.AssertInTaintTime("BSCharacter.ForceVelocity");
618 449
619 _velocity = value; 450 RawVelocity = value;
620 PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity); 451 PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity);
621 PhysicsScene.PE.Activate(PhysBody, true); 452 PhysScene.PE.Activate(PhysBody, true);
622 } 453 }
623 } 454 }
624 public override OMV.Vector3 Torque { 455 public override OMV.Vector3 Torque {
625 get { return _torque; } 456 get { return RawTorque; }
626 set { _torque = value; 457 set { RawTorque = value;
627 } 458 }
628 } 459 }
629 public override float CollisionScore { 460 public override float CollisionScore {
@@ -648,9 +479,19 @@ public sealed class BSCharacter : BSPhysObject
648 if (_orientation != value) 479 if (_orientation != value)
649 { 480 {
650 _orientation = value; 481 _orientation = value;
651 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() 482 PhysScene.TaintedObject("BSCharacter.setOrientation", delegate()
652 { 483 {
653 ForceOrientation = _orientation; 484 // Bullet assumes we know what we are doing when forcing orientation
485 // so it lets us go against all the rules and just compensates for them later.
486 // This forces rotation to be only around the Z axis and doesn't change any of the other axis.
487 // This keeps us from flipping the capsule over which the veiwer does not understand.
488 float oRoll, oPitch, oYaw;
489 _orientation.GetEulerAngles(out oRoll, out oPitch, out oYaw);
490 OMV.Quaternion trimmedOrientation = OMV.Quaternion.CreateFromEulers(0f, 0f, oYaw);
491 // DetailLog("{0},BSCharacter.setOrientation,taint,val={1},valDir={2},conv={3},convDir={4}",
492 // LocalID, _orientation, OMV.Vector3.UnitX * _orientation,
493 // trimmedOrientation, OMV.Vector3.UnitX * trimmedOrientation);
494 ForceOrientation = trimmedOrientation;
654 }); 495 });
655 } 496 }
656 } 497 }
@@ -660,7 +501,7 @@ public sealed class BSCharacter : BSPhysObject
660 { 501 {
661 get 502 get
662 { 503 {
663 _orientation = PhysicsScene.PE.GetOrientation(PhysBody); 504 _orientation = PhysScene.PE.GetOrientation(PhysBody);
664 return _orientation; 505 return _orientation;
665 } 506 }
666 set 507 set
@@ -669,7 +510,7 @@ public sealed class BSCharacter : BSPhysObject
669 if (PhysBody.HasPhysicalBody) 510 if (PhysBody.HasPhysicalBody)
670 { 511 {
671 // _position = PhysicsScene.PE.GetPosition(BSBody); 512 // _position = PhysicsScene.PE.GetPosition(BSBody);
672 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); 513 PhysScene.PE.SetTranslation(PhysBody, _position, _orientation);
673 } 514 }
674 } 515 }
675 } 516 }
@@ -718,14 +559,14 @@ public sealed class BSCharacter : BSPhysObject
718 public override bool FloatOnWater { 559 public override bool FloatOnWater {
719 set { 560 set {
720 _floatOnWater = value; 561 _floatOnWater = value;
721 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() 562 PhysScene.TaintedObject("BSCharacter.setFloatOnWater", delegate()
722 { 563 {
723 if (PhysBody.HasPhysicalBody) 564 if (PhysBody.HasPhysicalBody)
724 { 565 {
725 if (_floatOnWater) 566 if (_floatOnWater)
726 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); 567 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
727 else 568 else
728 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); 569 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
729 } 570 }
730 }); 571 });
731 } 572 }
@@ -746,7 +587,7 @@ public sealed class BSCharacter : BSPhysObject
746 public override float Buoyancy { 587 public override float Buoyancy {
747 get { return _buoyancy; } 588 get { return _buoyancy; }
748 set { _buoyancy = value; 589 set { _buoyancy = value;
749 PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate() 590 PhysScene.TaintedObject("BSCharacter.setBuoyancy", delegate()
750 { 591 {
751 DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 592 DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
752 ForceBuoyancy = _buoyancy; 593 ForceBuoyancy = _buoyancy;
@@ -755,8 +596,8 @@ public sealed class BSCharacter : BSPhysObject
755 } 596 }
756 public override float ForceBuoyancy { 597 public override float ForceBuoyancy {
757 get { return _buoyancy; } 598 get { return _buoyancy; }
758 set { 599 set {
759 PhysicsScene.AssertInTaintTime("BSCharacter.ForceBuoyancy"); 600 PhysScene.AssertInTaintTime("BSCharacter.ForceBuoyancy");
760 601
761 _buoyancy = value; 602 _buoyancy = value;
762 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 603 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
@@ -764,7 +605,7 @@ public sealed class BSCharacter : BSPhysObject
764 float grav = BSParam.Gravity * (1f - _buoyancy); 605 float grav = BSParam.Gravity * (1f - _buoyancy);
765 Gravity = new OMV.Vector3(0f, 0f, grav); 606 Gravity = new OMV.Vector3(0f, 0f, grav);
766 if (PhysBody.HasPhysicalBody) 607 if (PhysBody.HasPhysicalBody)
767 PhysicsScene.PE.SetGravity(PhysBody, Gravity); 608 PhysScene.PE.SetGravity(PhysBody, Gravity);
768 } 609 }
769 } 610 }
770 611
@@ -779,31 +620,10 @@ public sealed class BSCharacter : BSPhysObject
779 set { _PIDTau = value; } 620 set { _PIDTau = value; }
780 } 621 }
781 622
782 // Used for llSetHoverHeight and maybe vehicle height
783 // Hover Height will override MoveTo target's Z
784 public override bool PIDHoverActive {
785 set { _useHoverPID = value; }
786 }
787 public override float PIDHoverHeight {
788 set { _PIDHoverHeight = value; }
789 }
790 public override PIDHoverType PIDHoverType {
791 set { _PIDHoverType = value; }
792 }
793 public override float PIDHoverTau {
794 set { _PIDHoverTao = value; }
795 }
796
797 // For RotLookAt
798 public override OMV.Quaternion APIDTarget { set { return; } }
799 public override bool APIDActive { set { return; } }
800 public override float APIDStrength { set { return; } }
801 public override float APIDDamping { set { return; } }
802
803 public override void AddForce(OMV.Vector3 force, bool pushforce) 623 public override void AddForce(OMV.Vector3 force, bool pushforce)
804 { 624 {
805 // Since this force is being applied in only one step, make this a force per second. 625 // Since this force is being applied in only one step, make this a force per second.
806 OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep; 626 OMV.Vector3 addForce = force / PhysScene.LastTimeStep;
807 AddForce(addForce, pushforce, false); 627 AddForce(addForce, pushforce, false);
808 } 628 }
809 private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { 629 private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
@@ -812,13 +632,13 @@ public sealed class BSCharacter : BSPhysObject
812 OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); 632 OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);
813 // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce); 633 // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce);
814 634
815 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate() 635 PhysScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate()
816 { 636 {
817 // Bullet adds this central force to the total force for this tick 637 // Bullet adds this central force to the total force for this tick
818 // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce); 638 // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce);
819 if (PhysBody.HasPhysicalBody) 639 if (PhysBody.HasPhysicalBody)
820 { 640 {
821 PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce); 641 PhysScene.PE.ApplyCentralForce(PhysBody, addForce);
822 } 642 }
823 }); 643 });
824 } 644 }
@@ -829,7 +649,7 @@ public sealed class BSCharacter : BSPhysObject
829 } 649 }
830 } 650 }
831 651
832 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 652 public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
833 } 653 }
834 public override void SetMomentum(OMV.Vector3 momentum) { 654 public override void SetMomentum(OMV.Vector3 momentum) {
835 } 655 }
@@ -837,14 +657,14 @@ public sealed class BSCharacter : BSPhysObject
837 private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size) 657 private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size)
838 { 658 {
839 OMV.Vector3 newScale; 659 OMV.Vector3 newScale;
840 660
841 // Bullet's capsule total height is the "passed height + radius * 2"; 661 // Bullet's capsule total height is the "passed height + radius * 2";
842 // The base capsule is 1 diameter and 2 height (passed radius=0.5, passed height = 1) 662 // The base capsule is 1 unit in diameter and 2 units in height (passed radius=0.5, passed height = 1)
843 // The number we pass in for 'scaling' is the multiplier to get that base 663 // The number we pass in for 'scaling' is the multiplier to get that base
844 // shape to be the size desired. 664 // shape to be the size desired.
845 // So, when creating the scale for the avatar height, we take the passed height 665 // So, when creating the scale for the avatar height, we take the passed height
846 // (size.Z) and remove the caps. 666 // (size.Z) and remove the caps.
847 // Another oddity of the Bullet capsule implementation is that it presumes the Y 667 // An oddity of the Bullet capsule implementation is that it presumes the Y
848 // dimension is the radius of the capsule. Even though some of the code allows 668 // dimension is the radius of the capsule. Even though some of the code allows
849 // for a asymmetrical capsule, other parts of the code presume it is cylindrical. 669 // for a asymmetrical capsule, other parts of the code presume it is cylindrical.
850 670
@@ -852,8 +672,27 @@ public sealed class BSCharacter : BSPhysObject
852 newScale.X = size.X / 2f; 672 newScale.X = size.X / 2f;
853 newScale.Y = size.Y / 2f; 673 newScale.Y = size.Y / 2f;
854 674
675 float heightAdjust = BSParam.AvatarHeightMidFudge;
676 if (BSParam.AvatarHeightLowFudge != 0f || BSParam.AvatarHeightHighFudge != 0f)
677 {
678 // An avatar is between 1.61 and 2.12 meters. Midpoint is 1.87m.
679 // The "times 4" relies on the fact that the difference from the midpoint to the extremes is exactly 0.25
680 float midHeightOffset = size.Z - 1.87f;
681 if (midHeightOffset < 0f)
682 {
683 // Small avatar. Add the adjustment based on the distance from midheight
684 heightAdjust += -1f * midHeightOffset * 4f * BSParam.AvatarHeightLowFudge;
685 }
686 else
687 {
688 // Large avatar. Add the adjustment based on the distance from midheight
689 heightAdjust += midHeightOffset * 4f * BSParam.AvatarHeightHighFudge;
690 }
691 }
855 // The total scale height is the central cylindar plus the caps on the two ends. 692 // The total scale height is the central cylindar plus the caps on the two ends.
856 newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2)) / 2f; 693 newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2) + heightAdjust) / 2f;
694 // m_log.DebugFormat("{0} ComputeAvatarScale: size={1},adj={2},scale={3}", LogHeader, size, heightAdjust, newScale);
695
857 // If smaller than the endcaps, just fake like we're almost that small 696 // If smaller than the endcaps, just fake like we're almost that small
858 if (newScale.Z < 0) 697 if (newScale.Z < 0)
859 newScale.Z = 0.1f; 698 newScale.Z = 0.1f;
@@ -882,15 +721,18 @@ public sealed class BSCharacter : BSPhysObject
882 // the world that things have changed. 721 // the world that things have changed.
883 public override void UpdateProperties(EntityProperties entprop) 722 public override void UpdateProperties(EntityProperties entprop)
884 { 723 {
885 _position = entprop.Position; 724 // Don't change position if standing on a stationary object.
725 if (!IsStationary)
726 _position = entprop.Position;
727
886 _orientation = entprop.Rotation; 728 _orientation = entprop.Rotation;
887 729
888 // Smooth velocity. OpenSimulator is VERY sensitive to changes in velocity of the avatar 730 // Smooth velocity. OpenSimulator is VERY sensitive to changes in velocity of the avatar
889 // and will send agent updates to the clients if velocity changes by more than 731 // and will send agent updates to the clients if velocity changes by more than
890 // 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many 732 // 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many
891 // extra updates. 733 // extra updates.
892 if (!entprop.Velocity.ApproxEquals(_velocity, 0.1f)) 734 if (!entprop.Velocity.ApproxEquals(RawVelocity, 0.1f))
893 _velocity = entprop.Velocity; 735 RawVelocity = entprop.Velocity;
894 736
895 _acceleration = entprop.Acceleration; 737 _acceleration = entprop.Acceleration;
896 _rotationalVelocity = entprop.RotationalVelocity; 738 _rotationalVelocity = entprop.RotationalVelocity;
@@ -913,7 +755,7 @@ public sealed class BSCharacter : BSPhysObject
913 // base.RequestPhysicsterseUpdate(); 755 // base.RequestPhysicsterseUpdate();
914 756
915 DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", 757 DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
916 LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); 758 LocalID, _position, _orientation, RawVelocity, _acceleration, _rotationalVelocity);
917 } 759 }
918} 760}
919} 761}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
index b813974..42b5c49 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
@@ -85,7 +85,9 @@ public abstract class BSConstraint : IDisposable
85 { 85 {
86 bool ret = false; 86 bool ret = false;
87 if (m_enabled) 87 if (m_enabled)
88 {
88 ret = PhysicsScene.PE.SetAngularLimits(m_constraint, low, high); 89 ret = PhysicsScene.PE.SetAngularLimits(m_constraint, low, high);
90 }
89 return ret; 91 return ret;
90 } 92 }
91 93
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs
index 476a0e5..d0949f5 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs
@@ -97,14 +97,14 @@ public sealed class BSConstraint6Dof : BSConstraint
97 97
98 // A 6 Dof constraint that is fixed in the world and constrained to a on-the-fly created static object 98 // A 6 Dof constraint that is fixed in the world and constrained to a on-the-fly created static object
99 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, Vector3 frameInBloc, Quaternion frameInBrot, 99 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, Vector3 frameInBloc, Quaternion frameInBrot,
100 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) 100 bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies)
101 : base(world) 101 : base(world)
102 { 102 {
103 m_body1 = obj1; 103 m_body1 = obj1;
104 m_body2 = obj1; // Look out for confusion down the road 104 m_body2 = obj1; // Look out for confusion down the road
105 m_constraint = PhysicsScene.PE.Create6DofConstraintFixed(m_world, m_body1, 105 m_constraint = PhysicsScene.PE.Create6DofConstraintFixed(m_world, m_body1,
106 frameInBloc, frameInBrot, 106 frameInBloc, frameInBrot,
107 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); 107 useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies);
108 m_enabled = true; 108 m_enabled = true;
109 world.physicsScene.DetailLog("{0},BS6DofConstraint,createFixed,wID={1},rID={2},rBody={3}", 109 world.physicsScene.DetailLog("{0},BS6DofConstraint,createFixed,wID={1},rID={2},rBody={3}",
110 BSScene.DetailLogZero, world.worldID, obj1.ID, obj1.AddrString); 110 BSScene.DetailLogZero, world.worldID, obj1.ID, obj1.AddrString);
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs
index 7714a03..ed89f63 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs
@@ -45,7 +45,7 @@ public sealed class BSConstraintHinge : BSConstraint
45 m_body1 = obj1; 45 m_body1 = obj1;
46 m_body2 = obj2; 46 m_body2 = obj2;
47 m_constraint = PhysicsScene.PE.CreateHingeConstraint(world, obj1, obj2, 47 m_constraint = PhysicsScene.PE.CreateHingeConstraint(world, obj1, obj2,
48 pivotInA, pivotInB, axisInA, axisInB, 48 pivotInA, pivotInB, axisInA, axisInB,
49 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); 49 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
50 m_enabled = true; 50 m_enabled = true;
51 } 51 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index 65df741..311cf4f 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -40,13 +40,14 @@ using OpenSim.Region.Physics.Manager;
40 40
41namespace OpenSim.Region.Physics.BulletSPlugin 41namespace OpenSim.Region.Physics.BulletSPlugin
42{ 42{
43 public sealed class BSDynamics 43 public sealed class BSDynamics : BSActor
44 { 44 {
45 private static string LogHeader = "[BULLETSIM VEHICLE]"; 45 private static string LogHeader = "[BULLETSIM VEHICLE]";
46 46
47 private BSScene PhysicsScene { get; set; }
48 // the prim this dynamic controller belongs to 47 // the prim this dynamic controller belongs to
49 private BSPrim Prim { get; set; } 48 private BSPrim ControllingPrim { get; set; }
49
50 private bool m_haveRegisteredForSceneEvents;
50 51
51 // mass of the vehicle fetched each time we're calles 52 // mass of the vehicle fetched each time we're calles
52 private float m_vehicleMass; 53 private float m_vehicleMass;
@@ -129,11 +130,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
129 public bool enableAngularDeflection; 130 public bool enableAngularDeflection;
130 public bool enableAngularBanking; 131 public bool enableAngularBanking;
131 132
132 public BSDynamics(BSScene myScene, BSPrim myPrim) 133 public BSDynamics(BSScene myScene, BSPrim myPrim, string actorName)
134 : base(myScene, myPrim, actorName)
133 { 135 {
134 PhysicsScene = myScene; 136 ControllingPrim = myPrim;
135 Prim = myPrim;
136 Type = Vehicle.TYPE_NONE; 137 Type = Vehicle.TYPE_NONE;
138 m_haveRegisteredForSceneEvents = false;
137 SetupVehicleDebugging(); 139 SetupVehicleDebugging();
138 } 140 }
139 141
@@ -144,7 +146,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
144 enableAngularVerticalAttraction = true; 146 enableAngularVerticalAttraction = true;
145 enableAngularDeflection = false; 147 enableAngularDeflection = false;
146 enableAngularBanking = true; 148 enableAngularBanking = true;
147 if (BSParam.VehicleDebuggingEnabled) 149 if (BSParam.VehicleDebuggingEnable)
148 { 150 {
149 enableAngularVerticalAttraction = true; 151 enableAngularVerticalAttraction = true;
150 enableAngularDeflection = false; 152 enableAngularDeflection = false;
@@ -155,7 +157,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
155 // Return 'true' if this vehicle is doing vehicle things 157 // Return 'true' if this vehicle is doing vehicle things
156 public bool IsActive 158 public bool IsActive
157 { 159 {
158 get { return (Type != Vehicle.TYPE_NONE && Prim.IsPhysicallyActive); } 160 get { return (Type != Vehicle.TYPE_NONE && ControllingPrim.IsPhysicallyActive); }
159 } 161 }
160 162
161 // Return 'true' if this a vehicle that should be sitting on the ground 163 // Return 'true' if this a vehicle that should be sitting on the ground
@@ -167,7 +169,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
167 #region Vehicle parameter setting 169 #region Vehicle parameter setting
168 public void ProcessFloatVehicleParam(Vehicle pParam, float pValue) 170 public void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
169 { 171 {
170 VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); 172 VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue);
171 switch (pParam) 173 switch (pParam)
172 { 174 {
173 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: 175 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
@@ -195,7 +197,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
195 break; 197 break;
196 case Vehicle.BUOYANCY: 198 case Vehicle.BUOYANCY:
197 m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f); 199 m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f);
198 m_VehicleGravity = Prim.ComputeGravity(m_VehicleBuoyancy); 200 m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy);
199 break; 201 break;
200 case Vehicle.HOVER_EFFICIENCY: 202 case Vehicle.HOVER_EFFICIENCY:
201 m_VhoverEfficiency = ClampInRange(0f, pValue, 1f); 203 m_VhoverEfficiency = ClampInRange(0f, pValue, 1f);
@@ -233,7 +235,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin
233 // set all of the components to the same value 235 // set all of the components to the same value
234 case Vehicle.ANGULAR_FRICTION_TIMESCALE: 236 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
235 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); 237 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue);
236 m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
237 break; 238 break;
238 case Vehicle.ANGULAR_MOTOR_DIRECTION: 239 case Vehicle.ANGULAR_MOTOR_DIRECTION:
239 m_angularMotorDirection = new Vector3(pValue, pValue, pValue); 240 m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
@@ -242,7 +243,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin
242 break; 243 break;
243 case Vehicle.LINEAR_FRICTION_TIMESCALE: 244 case Vehicle.LINEAR_FRICTION_TIMESCALE:
244 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); 245 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
245 m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
246 break; 246 break;
247 case Vehicle.LINEAR_MOTOR_DIRECTION: 247 case Vehicle.LINEAR_MOTOR_DIRECTION:
248 m_linearMotorDirection = new Vector3(pValue, pValue, pValue); 248 m_linearMotorDirection = new Vector3(pValue, pValue, pValue);
@@ -258,12 +258,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
258 258
259 internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue) 259 internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue)
260 { 260 {
261 VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); 261 VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue);
262 switch (pParam) 262 switch (pParam)
263 { 263 {
264 case Vehicle.ANGULAR_FRICTION_TIMESCALE: 264 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
265 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); 265 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
266 m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
267 break; 266 break;
268 case Vehicle.ANGULAR_MOTOR_DIRECTION: 267 case Vehicle.ANGULAR_MOTOR_DIRECTION:
269 // Limit requested angular speed to 2 rps= 4 pi rads/sec 268 // Limit requested angular speed to 2 rps= 4 pi rads/sec
@@ -276,7 +275,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin
276 break; 275 break;
277 case Vehicle.LINEAR_FRICTION_TIMESCALE: 276 case Vehicle.LINEAR_FRICTION_TIMESCALE:
278 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); 277 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
279 m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
280 break; 278 break;
281 case Vehicle.LINEAR_MOTOR_DIRECTION: 279 case Vehicle.LINEAR_MOTOR_DIRECTION:
282 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); 280 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
@@ -294,7 +292,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
294 292
295 internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) 293 internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue)
296 { 294 {
297 VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); 295 VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue);
298 switch (pParam) 296 switch (pParam)
299 { 297 {
300 case Vehicle.REFERENCE_FRAME: 298 case Vehicle.REFERENCE_FRAME:
@@ -308,7 +306,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
308 306
309 internal void ProcessVehicleFlags(int pParam, bool remove) 307 internal void ProcessVehicleFlags(int pParam, bool remove)
310 { 308 {
311 VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", Prim.LocalID, pParam, remove); 309 VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", ControllingPrim.LocalID, pParam, remove);
312 VehicleFlag parm = (VehicleFlag)pParam; 310 VehicleFlag parm = (VehicleFlag)pParam;
313 if (pParam == -1) 311 if (pParam == -1)
314 m_flags = (VehicleFlag)0; 312 m_flags = (VehicleFlag)0;
@@ -323,7 +321,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
323 321
324 public void ProcessTypeChange(Vehicle pType) 322 public void ProcessTypeChange(Vehicle pType)
325 { 323 {
326 VDetailLog("{0},ProcessTypeChange,type={1}", Prim.LocalID, pType); 324 VDetailLog("{0},ProcessTypeChange,type={1}", ControllingPrim.LocalID, pType);
327 // Set Defaults For Type 325 // Set Defaults For Type
328 Type = pType; 326 Type = pType;
329 switch (pType) 327 switch (pType)
@@ -557,34 +555,40 @@ namespace OpenSim.Region.Physics.BulletSPlugin
557 break; 555 break;
558 } 556 }
559 557
560 // Update any physical parameters based on this type. 558 m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale, m_linearMotorDecayTimescale, 1f);
561 Refresh(); 559 m_linearMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
562
563 m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale,
564 m_linearMotorDecayTimescale, m_linearFrictionTimescale,
565 1f);
566 m_linearMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
567 560
568 m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, 561 m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, m_angularMotorDecayTimescale, 1f);
569 m_angularMotorDecayTimescale, m_angularFrictionTimescale, 562 m_angularMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
570 1f);
571 m_angularMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
572 563
573 /* Not implemented 564 /* Not implemented
574 m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale, 565 m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale,
575 BSMotor.Infinite, BSMotor.InfiniteVector, 566 BSMotor.Infinite, BSMotor.InfiniteVector,
576 m_verticalAttractionEfficiency); 567 m_verticalAttractionEfficiency);
577 // Z goes away and we keep X and Y 568 // Z goes away and we keep X and Y
578 m_verticalAttractionMotor.FrictionTimescale = new Vector3(BSMotor.Infinite, BSMotor.Infinite, 0.1f);
579 m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) 569 m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
580 */ 570 */
571
572 if (this.Type == Vehicle.TYPE_NONE)
573 {
574 UnregisterForSceneEvents();
575 }
576 else
577 {
578 RegisterForSceneEvents();
579 }
580
581 // Update any physical parameters based on this type.
582 Refresh();
581 } 583 }
582 #endregion // Vehicle parameter setting 584 #endregion // Vehicle parameter setting
583 585
584 public void Refresh() 586 // BSActor.Refresh()
587 public override void Refresh()
585 { 588 {
586 // If asking for a refresh, reset the physical parameters before the next simulation step. 589 // If asking for a refresh, reset the physical parameters before the next simulation step.
587 PhysicsScene.PostTaintObject("BSDynamics.Refresh", Prim.LocalID, delegate() 590 // Called whether active or not since the active state may be updated before the next step.
591 m_physicsScene.PostTaintObject("BSDynamics.Refresh", ControllingPrim.LocalID, delegate()
588 { 592 {
589 SetPhysicalParameters(); 593 SetPhysicalParameters();
590 }); 594 });
@@ -597,49 +601,91 @@ namespace OpenSim.Region.Physics.BulletSPlugin
597 if (IsActive) 601 if (IsActive)
598 { 602 {
599 // Remember the mass so we don't have to fetch it every step 603 // Remember the mass so we don't have to fetch it every step
600 m_vehicleMass = Prim.TotalMass; 604 m_vehicleMass = ControllingPrim.TotalMass;
601 605
602 // Friction affects are handled by this vehicle code 606 // Friction affects are handled by this vehicle code
603 PhysicsScene.PE.SetFriction(Prim.PhysBody, BSParam.VehicleFriction); 607 m_physicsScene.PE.SetFriction(ControllingPrim.PhysBody, BSParam.VehicleFriction);
604 PhysicsScene.PE.SetRestitution(Prim.PhysBody, BSParam.VehicleRestitution); 608 m_physicsScene.PE.SetRestitution(ControllingPrim.PhysBody, BSParam.VehicleRestitution);
605 609
606 // Moderate angular movement introduced by Bullet. 610 // Moderate angular movement introduced by Bullet.
607 // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle. 611 // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle.
608 // Maybe compute linear and angular factor and damping from params. 612 // Maybe compute linear and angular factor and damping from params.
609 PhysicsScene.PE.SetAngularDamping(Prim.PhysBody, BSParam.VehicleAngularDamping); 613 m_physicsScene.PE.SetAngularDamping(ControllingPrim.PhysBody, BSParam.VehicleAngularDamping);
610 PhysicsScene.PE.SetLinearFactor(Prim.PhysBody, BSParam.VehicleLinearFactor); 614 m_physicsScene.PE.SetLinearFactor(ControllingPrim.PhysBody, BSParam.VehicleLinearFactor);
611 PhysicsScene.PE.SetAngularFactorV(Prim.PhysBody, BSParam.VehicleAngularFactor); 615 m_physicsScene.PE.SetAngularFactorV(ControllingPrim.PhysBody, BSParam.VehicleAngularFactor);
612 616
613 // Vehicles report collision events so we know when it's on the ground 617 // Vehicles report collision events so we know when it's on the ground
614 PhysicsScene.PE.AddToCollisionFlags(Prim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); 618 m_physicsScene.PE.AddToCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
615 619
616 Prim.Inertia = PhysicsScene.PE.CalculateLocalInertia(Prim.PhysShape, m_vehicleMass); 620 Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(ControllingPrim.PhysShape.physShapeInfo, m_vehicleMass);
617 PhysicsScene.PE.SetMassProps(Prim.PhysBody, m_vehicleMass, Prim.Inertia); 621 ControllingPrim.Inertia = inertia * BSParam.VehicleInertiaFactor;
618 PhysicsScene.PE.UpdateInertiaTensor(Prim.PhysBody); 622 m_physicsScene.PE.SetMassProps(ControllingPrim.PhysBody, m_vehicleMass, ControllingPrim.Inertia);
623 m_physicsScene.PE.UpdateInertiaTensor(ControllingPrim.PhysBody);
619 624
620 // Set the gravity for the vehicle depending on the buoyancy 625 // Set the gravity for the vehicle depending on the buoyancy
621 // TODO: what should be done if prim and vehicle buoyancy differ? 626 // TODO: what should be done if prim and vehicle buoyancy differ?
622 m_VehicleGravity = Prim.ComputeGravity(m_VehicleBuoyancy); 627 m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy);
623 // The actual vehicle gravity is set to zero in Bullet so we can do all the application of same. 628 // The actual vehicle gravity is set to zero in Bullet so we can do all the application of same.
624 PhysicsScene.PE.SetGravity(Prim.PhysBody, Vector3.Zero); 629 m_physicsScene.PE.SetGravity(ControllingPrim.PhysBody, Vector3.Zero);
625 630
626 VDetailLog("{0},BSDynamics.SetPhysicalParameters,mass={1},inert={2},vehGrav={3},aDamp={4},frict={5},rest={6},lFact={7},aFact={8}", 631 VDetailLog("{0},BSDynamics.SetPhysicalParameters,mass={1},inert={2},vehGrav={3},aDamp={4},frict={5},rest={6},lFact={7},aFact={8}",
627 Prim.LocalID, m_vehicleMass, Prim.Inertia, m_VehicleGravity, 632 ControllingPrim.LocalID, m_vehicleMass, ControllingPrim.Inertia, m_VehicleGravity,
628 BSParam.VehicleAngularDamping, BSParam.VehicleFriction, BSParam.VehicleRestitution, 633 BSParam.VehicleAngularDamping, BSParam.VehicleFriction, BSParam.VehicleRestitution,
629 BSParam.VehicleLinearFactor, BSParam.VehicleAngularFactor 634 BSParam.VehicleLinearFactor, BSParam.VehicleAngularFactor
630 ); 635 );
631 } 636 }
632 else 637 else
633 { 638 {
634 if (Prim.PhysBody.HasPhysicalBody) 639 if (ControllingPrim.PhysBody.HasPhysicalBody)
635 PhysicsScene.PE.RemoveFromCollisionFlags(Prim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); 640 m_physicsScene.PE.RemoveFromCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
636 } 641 }
637 } 642 }
638 643
639 public bool RemoveBodyDependencies(BSPhysObject prim) 644 // BSActor.RemoveBodyDependencies
645 public override void RemoveDependencies()
640 { 646 {
641 Refresh(); 647 Refresh();
642 return IsActive; 648 }
649
650 // BSActor.Release()
651 public override void Dispose()
652 {
653 UnregisterForSceneEvents();
654 Type = Vehicle.TYPE_NONE;
655 Enabled = false;
656 return;
657 }
658
659 private void RegisterForSceneEvents()
660 {
661 if (!m_haveRegisteredForSceneEvents)
662 {
663 m_physicsScene.BeforeStep += this.Step;
664 m_physicsScene.AfterStep += this.PostStep;
665 ControllingPrim.OnPreUpdateProperty += this.PreUpdateProperty;
666 m_haveRegisteredForSceneEvents = true;
667 }
668 }
669
670 private void UnregisterForSceneEvents()
671 {
672 if (m_haveRegisteredForSceneEvents)
673 {
674 m_physicsScene.BeforeStep -= this.Step;
675 m_physicsScene.AfterStep -= this.PostStep;
676 ControllingPrim.OnPreUpdateProperty -= this.PreUpdateProperty;
677 m_haveRegisteredForSceneEvents = false;
678 }
679 }
680
681 private void PreUpdateProperty(ref EntityProperties entprop)
682 {
683 // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet
684 // TODO: handle physics introduced by Bullet with computed vehicle physics.
685 if (IsActive)
686 {
687 entprop.RotationalVelocity = Vector3.Zero;
688 }
643 } 689 }
644 690
645 #region Known vehicle value functions 691 #region Known vehicle value functions
@@ -686,14 +732,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin
686 if (m_knownChanged != 0) 732 if (m_knownChanged != 0)
687 { 733 {
688 if ((m_knownChanged & m_knownChangedPosition) != 0) 734 if ((m_knownChanged & m_knownChangedPosition) != 0)
689 Prim.ForcePosition = m_knownPosition; 735 ControllingPrim.ForcePosition = m_knownPosition;
690 736
691 if ((m_knownChanged & m_knownChangedOrientation) != 0) 737 if ((m_knownChanged & m_knownChangedOrientation) != 0)
692 Prim.ForceOrientation = m_knownOrientation; 738 ControllingPrim.ForceOrientation = m_knownOrientation;
693 739
694 if ((m_knownChanged & m_knownChangedVelocity) != 0) 740 if ((m_knownChanged & m_knownChangedVelocity) != 0)
695 { 741 {
696 Prim.ForceVelocity = m_knownVelocity; 742 ControllingPrim.ForceVelocity = m_knownVelocity;
697 // Fake out Bullet by making it think the velocity is the same as last time. 743 // Fake out Bullet by making it think the velocity is the same as last time.
698 // Bullet does a bunch of smoothing for changing parameters. 744 // Bullet does a bunch of smoothing for changing parameters.
699 // Since the vehicle is demanding this setting, we override Bullet's smoothing 745 // Since the vehicle is demanding this setting, we override Bullet's smoothing
@@ -702,28 +748,28 @@ namespace OpenSim.Region.Physics.BulletSPlugin
702 } 748 }
703 749
704 if ((m_knownChanged & m_knownChangedForce) != 0) 750 if ((m_knownChanged & m_knownChangedForce) != 0)
705 Prim.AddForce((Vector3)m_knownForce, false /*pushForce*/, true /*inTaintTime*/); 751 ControllingPrim.AddForce((Vector3)m_knownForce, false /*pushForce*/, true /*inTaintTime*/);
706 752
707 if ((m_knownChanged & m_knownChangedForceImpulse) != 0) 753 if ((m_knownChanged & m_knownChangedForceImpulse) != 0)
708 Prim.AddForceImpulse((Vector3)m_knownForceImpulse, false /*pushforce*/, true /*inTaintTime*/); 754 ControllingPrim.AddForceImpulse((Vector3)m_knownForceImpulse, false /*pushforce*/, true /*inTaintTime*/);
709 755
710 if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0) 756 if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0)
711 { 757 {
712 Prim.ForceRotationalVelocity = m_knownRotationalVelocity; 758 ControllingPrim.ForceRotationalVelocity = m_knownRotationalVelocity;
713 // PhysicsScene.PE.SetInterpolationAngularVelocity(Prim.PhysBody, m_knownRotationalVelocity); 759 // PhysicsScene.PE.SetInterpolationAngularVelocity(Prim.PhysBody, m_knownRotationalVelocity);
714 } 760 }
715 761
716 if ((m_knownChanged & m_knownChangedRotationalImpulse) != 0) 762 if ((m_knownChanged & m_knownChangedRotationalImpulse) != 0)
717 Prim.ApplyTorqueImpulse((Vector3)m_knownRotationalImpulse, true /*inTaintTime*/); 763 ControllingPrim.ApplyTorqueImpulse((Vector3)m_knownRotationalImpulse, true /*inTaintTime*/);
718 764
719 if ((m_knownChanged & m_knownChangedRotationalForce) != 0) 765 if ((m_knownChanged & m_knownChangedRotationalForce) != 0)
720 { 766 {
721 Prim.AddAngularForce((Vector3)m_knownRotationalForce, false /*pushForce*/, true /*inTaintTime*/); 767 ControllingPrim.AddAngularForce((Vector3)m_knownRotationalForce, false /*pushForce*/, true /*inTaintTime*/);
722 } 768 }
723 769
724 // If we set one of the values (ie, the physics engine didn't do it) we must force 770 // If we set one of the values (ie, the physics engine didn't do it) we must force
725 // an UpdateProperties event to send the changes up to the simulator. 771 // an UpdateProperties event to send the changes up to the simulator.
726 PhysicsScene.PE.PushUpdate(Prim.PhysBody); 772 m_physicsScene.PE.PushUpdate(ControllingPrim.PhysBody);
727 } 773 }
728 m_knownChanged = 0; 774 m_knownChanged = 0;
729 } 775 }
@@ -736,7 +782,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
736 if ((m_knownHas & m_knownChangedTerrainHeight) == 0 || pos != lastRememberedHeightPos) 782 if ((m_knownHas & m_knownChangedTerrainHeight) == 0 || pos != lastRememberedHeightPos)
737 { 783 {
738 lastRememberedHeightPos = pos; 784 lastRememberedHeightPos = pos;
739 m_knownTerrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); 785 m_knownTerrainHeight = ControllingPrim.PhysScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
740 m_knownHas |= m_knownChangedTerrainHeight; 786 m_knownHas |= m_knownChangedTerrainHeight;
741 } 787 }
742 return m_knownTerrainHeight; 788 return m_knownTerrainHeight;
@@ -748,7 +794,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
748 { 794 {
749 if ((m_knownHas & m_knownChangedWaterLevel) == 0) 795 if ((m_knownHas & m_knownChangedWaterLevel) == 0)
750 { 796 {
751 m_knownWaterLevel = Prim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos); 797 m_knownWaterLevel = ControllingPrim.PhysScene.TerrainManager.GetWaterLevelAtXYZ(pos);
752 m_knownHas |= m_knownChangedWaterLevel; 798 m_knownHas |= m_knownChangedWaterLevel;
753 } 799 }
754 return (float)m_knownWaterLevel; 800 return (float)m_knownWaterLevel;
@@ -760,7 +806,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
760 { 806 {
761 if ((m_knownHas & m_knownChangedPosition) == 0) 807 if ((m_knownHas & m_knownChangedPosition) == 0)
762 { 808 {
763 m_knownPosition = Prim.ForcePosition; 809 m_knownPosition = ControllingPrim.ForcePosition;
764 m_knownHas |= m_knownChangedPosition; 810 m_knownHas |= m_knownChangedPosition;
765 } 811 }
766 return m_knownPosition; 812 return m_knownPosition;
@@ -779,7 +825,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
779 { 825 {
780 if ((m_knownHas & m_knownChangedOrientation) == 0) 826 if ((m_knownHas & m_knownChangedOrientation) == 0)
781 { 827 {
782 m_knownOrientation = Prim.ForceOrientation; 828 m_knownOrientation = ControllingPrim.ForceOrientation;
783 m_knownHas |= m_knownChangedOrientation; 829 m_knownHas |= m_knownChangedOrientation;
784 } 830 }
785 return m_knownOrientation; 831 return m_knownOrientation;
@@ -798,7 +844,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
798 { 844 {
799 if ((m_knownHas & m_knownChangedVelocity) == 0) 845 if ((m_knownHas & m_knownChangedVelocity) == 0)
800 { 846 {
801 m_knownVelocity = Prim.ForceVelocity; 847 m_knownVelocity = ControllingPrim.ForceVelocity;
802 m_knownHas |= m_knownChangedVelocity; 848 m_knownHas |= m_knownChangedVelocity;
803 } 849 }
804 return m_knownVelocity; 850 return m_knownVelocity;
@@ -839,7 +885,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
839 { 885 {
840 if ((m_knownHas & m_knownChangedRotationalVelocity) == 0) 886 if ((m_knownHas & m_knownChangedRotationalVelocity) == 0)
841 { 887 {
842 m_knownRotationalVelocity = Prim.ForceRotationalVelocity; 888 m_knownRotationalVelocity = ControllingPrim.ForceRotationalVelocity;
843 m_knownHas |= m_knownChangedRotationalVelocity; 889 m_knownHas |= m_knownChangedRotationalVelocity;
844 } 890 }
845 return (Vector3)m_knownRotationalVelocity; 891 return (Vector3)m_knownRotationalVelocity;
@@ -914,11 +960,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
914 // for the physics engine to note the changes so an UpdateProperties event will happen. 960 // for the physics engine to note the changes so an UpdateProperties event will happen.
915 PushKnownChanged(); 961 PushKnownChanged();
916 962
917 if (PhysicsScene.VehiclePhysicalLoggingEnabled) 963 if (m_physicsScene.VehiclePhysicalLoggingEnabled)
918 PhysicsScene.PE.DumpRigidBody(PhysicsScene.World, Prim.PhysBody); 964 m_physicsScene.PE.DumpRigidBody(m_physicsScene.World, ControllingPrim.PhysBody);
919 965
920 VDetailLog("{0},BSDynamics.Step,done,pos={1}, force={2},velocity={3},angvel={4}", 966 VDetailLog("{0},BSDynamics.Step,done,pos={1}, force={2},velocity={3},angvel={4}",
921 Prim.LocalID, VehiclePosition, m_knownForce, VehicleVelocity, VehicleRotationalVelocity); 967 ControllingPrim.LocalID, VehiclePosition, m_knownForce, VehicleVelocity, VehicleRotationalVelocity);
922 } 968 }
923 969
924 // Called after the simulation step 970 // Called after the simulation step
@@ -926,8 +972,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
926 { 972 {
927 if (!IsActive) return; 973 if (!IsActive) return;
928 974
929 if (PhysicsScene.VehiclePhysicalLoggingEnabled) 975 if (m_physicsScene.VehiclePhysicalLoggingEnabled)
930 PhysicsScene.PE.DumpRigidBody(PhysicsScene.World, Prim.PhysBody); 976 m_physicsScene.PE.DumpRigidBody(m_physicsScene.World, ControllingPrim.PhysBody);
931 } 977 }
932 978
933 // Apply the effect of the linear motor and other linear motions (like hover and float). 979 // Apply the effect of the linear motor and other linear motions (like hover and float).
@@ -966,13 +1012,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
966 Vector3 origVelW = VehicleVelocity; // DEBUG DEBUG 1012 Vector3 origVelW = VehicleVelocity; // DEBUG DEBUG
967 VehicleVelocity /= VehicleVelocity.Length(); 1013 VehicleVelocity /= VehicleVelocity.Length();
968 VehicleVelocity *= BSParam.VehicleMaxLinearVelocity; 1014 VehicleVelocity *= BSParam.VehicleMaxLinearVelocity;
969 VDetailLog("{0}, MoveLinear,clampMax,origVelW={1},lenSq={2},maxVelSq={3},,newVelW={4}", 1015 VDetailLog("{0}, MoveLinear,clampMax,origVelW={1},lenSq={2},maxVelSq={3},,newVelW={4}",
970 Prim.LocalID, origVelW, newVelocityLengthSq, BSParam.VehicleMaxLinearVelocitySquared, VehicleVelocity); 1016 ControllingPrim.LocalID, origVelW, newVelocityLengthSq, BSParam.VehicleMaxLinearVelocitySquared, VehicleVelocity);
971 } 1017 }
972 else if (newVelocityLengthSq < 0.001f) 1018 else if (newVelocityLengthSq < 0.001f)
973 VehicleVelocity = Vector3.Zero; 1019 VehicleVelocity = Vector3.Zero;
974 1020
975 VDetailLog("{0}, MoveLinear,done,isColl={1},newVel={2}", Prim.LocalID, Prim.IsColliding, VehicleVelocity ); 1021 VDetailLog("{0}, MoveLinear,done,isColl={1},newVel={2}", ControllingPrim.LocalID, ControllingPrim.IsColliding, VehicleVelocity );
976 1022
977 } // end MoveLinear() 1023 } // end MoveLinear()
978 1024
@@ -983,6 +1029,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
983 Vector3 currentVelV = VehicleVelocity * Quaternion.Inverse(VehicleOrientation); 1029 Vector3 currentVelV = VehicleVelocity * Quaternion.Inverse(VehicleOrientation);
984 Vector3 linearMotorCorrectionV = m_linearMotor.Step(pTimestep, currentVelV); 1030 Vector3 linearMotorCorrectionV = m_linearMotor.Step(pTimestep, currentVelV);
985 1031
1032 // Friction reduces vehicle motion
1033 Vector3 frictionFactorW = ComputeFrictionFactor(m_linearFrictionTimescale, pTimestep);
1034 linearMotorCorrectionV -= (currentVelV * frictionFactorW);
1035
986 // Motor is vehicle coordinates. Rotate it to world coordinates 1036 // Motor is vehicle coordinates. Rotate it to world coordinates
987 Vector3 linearMotorVelocityW = linearMotorCorrectionV * VehicleOrientation; 1037 Vector3 linearMotorVelocityW = linearMotorCorrectionV * VehicleOrientation;
988 1038
@@ -996,8 +1046,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
996 // Add this correction to the velocity to make it faster/slower. 1046 // Add this correction to the velocity to make it faster/slower.
997 VehicleVelocity += linearMotorVelocityW; 1047 VehicleVelocity += linearMotorVelocityW;
998 1048
999 VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},correctV={3},correctW={4},newVelW={5}", 1049
1000 Prim.LocalID, origVelW, currentVelV, linearMotorCorrectionV, linearMotorVelocityW, VehicleVelocity); 1050
1051 VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},correctV={3},correctW={4},newVelW={5},fricFact={6}",
1052 ControllingPrim.LocalID, origVelW, currentVelV, linearMotorCorrectionV,
1053 linearMotorVelocityW, VehicleVelocity, frictionFactorW);
1001 } 1054 }
1002 1055
1003 public void ComputeLinearTerrainHeightCorrection(float pTimestep) 1056 public void ComputeLinearTerrainHeightCorrection(float pTimestep)
@@ -1011,7 +1064,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1011 newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f; 1064 newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f;
1012 VehiclePosition = newPosition; 1065 VehiclePosition = newPosition;
1013 VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}", 1066 VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}",
1014 Prim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition); 1067 ControllingPrim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition);
1015 } 1068 }
1016 } 1069 }
1017 1070
@@ -1041,7 +1094,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1041 if (VehiclePosition.Z > m_VhoverTargetHeight) 1094 if (VehiclePosition.Z > m_VhoverTargetHeight)
1042 m_VhoverTargetHeight = VehiclePosition.Z; 1095 m_VhoverTargetHeight = VehiclePosition.Z;
1043 } 1096 }
1044 1097
1045 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) 1098 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0)
1046 { 1099 {
1047 if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f) 1100 if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f)
@@ -1050,7 +1103,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1050 pos.Z = m_VhoverTargetHeight; 1103 pos.Z = m_VhoverTargetHeight;
1051 VehiclePosition = pos; 1104 VehiclePosition = pos;
1052 1105
1053 VDetailLog("{0}, MoveLinear,hover,pos={1},lockHoverHeight", Prim.LocalID, pos); 1106 VDetailLog("{0}, MoveLinear,hover,pos={1},lockHoverHeight", ControllingPrim.LocalID, pos);
1054 } 1107 }
1055 } 1108 }
1056 else 1109 else
@@ -1079,7 +1132,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1079 */ 1132 */
1080 1133
1081 VDetailLog("{0}, MoveLinear,hover,pos={1},eff={2},hoverTS={3},height={4},target={5},err={6},corr={7}", 1134 VDetailLog("{0}, MoveLinear,hover,pos={1},eff={2},hoverTS={3},height={4},target={5},err={6},corr={7}",
1082 Prim.LocalID, VehiclePosition, m_VhoverEfficiency, 1135 ControllingPrim.LocalID, VehiclePosition, m_VhoverEfficiency,
1083 m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight, 1136 m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight,
1084 verticalError, verticalCorrection); 1137 verticalError, verticalCorrection);
1085 } 1138 }
@@ -1124,7 +1177,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1124 { 1177 {
1125 VehiclePosition = pos; 1178 VehiclePosition = pos;
1126 VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", 1179 VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}",
1127 Prim.LocalID, m_BlockingEndPoint, posChange, pos); 1180 ControllingPrim.LocalID, m_BlockingEndPoint, posChange, pos);
1128 } 1181 }
1129 } 1182 }
1130 return changed; 1183 return changed;
@@ -1135,7 +1188,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1135 // used with conjunction with banking: the strength of the banking will decay when the 1188 // used with conjunction with banking: the strength of the banking will decay when the
1136 // vehicle no longer experiences collisions. The decay timescale is the same as 1189 // vehicle no longer experiences collisions. The decay timescale is the same as
1137 // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering 1190 // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering
1138 // when they are in mid jump. 1191 // when they are in mid jump.
1139 // TODO: this code is wrong. Also, what should it do for boats (height from water)? 1192 // TODO: this code is wrong. Also, what should it do for boats (height from water)?
1140 // This is just using the ground and a general collision check. Should really be using 1193 // This is just using the ground and a general collision check. Should really be using
1141 // a downward raycast to find what is below. 1194 // a downward raycast to find what is below.
@@ -1164,7 +1217,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1164 1217
1165 // Another approach is to measure if we're going up. If going up and not colliding, 1218 // Another approach is to measure if we're going up. If going up and not colliding,
1166 // the vehicle is in the air. Fix that by pushing down. 1219 // the vehicle is in the air. Fix that by pushing down.
1167 if (!Prim.IsColliding && VehicleVelocity.Z > 0.1) 1220 if (!ControllingPrim.IsColliding && VehicleVelocity.Z > 0.1)
1168 { 1221 {
1169 // Get rid of any of the velocity vector that is pushing us up. 1222 // Get rid of any of the velocity vector that is pushing us up.
1170 float upVelocity = VehicleVelocity.Z; 1223 float upVelocity = VehicleVelocity.Z;
@@ -1186,7 +1239,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1186 } 1239 }
1187 */ 1240 */
1188 VDetailLog("{0}, MoveLinear,limitMotorUp,collide={1},upVel={2},newVel={3}", 1241 VDetailLog("{0}, MoveLinear,limitMotorUp,collide={1},upVel={2},newVel={3}",
1189 Prim.LocalID, Prim.IsColliding, upVelocity, VehicleVelocity); 1242 ControllingPrim.LocalID, ControllingPrim.IsColliding, upVelocity, VehicleVelocity);
1190 } 1243 }
1191 } 1244 }
1192 } 1245 }
@@ -1196,14 +1249,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1196 Vector3 appliedGravity = m_VehicleGravity * m_vehicleMass; 1249 Vector3 appliedGravity = m_VehicleGravity * m_vehicleMass;
1197 1250
1198 // Hack to reduce downward force if the vehicle is probably sitting on the ground 1251 // Hack to reduce downward force if the vehicle is probably sitting on the ground
1199 if (Prim.IsColliding && IsGroundVehicle) 1252 if (ControllingPrim.IsColliding && IsGroundVehicle)
1200 appliedGravity *= BSParam.VehicleGroundGravityFudge; 1253 appliedGravity *= BSParam.VehicleGroundGravityFudge;
1201 1254
1202 VehicleAddForce(appliedGravity); 1255 VehicleAddForce(appliedGravity);
1203 1256
1204 VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={3}", 1257 VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={3}",
1205 Prim.LocalID, m_VehicleGravity, 1258 ControllingPrim.LocalID, m_VehicleGravity,
1206 Prim.IsColliding, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity); 1259 ControllingPrim.IsColliding, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity);
1207 } 1260 }
1208 1261
1209 // ======================================================================= 1262 // =======================================================================
@@ -1227,11 +1280,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1227 { 1280 {
1228 // The vehicle is not adding anything angular wise. 1281 // The vehicle is not adding anything angular wise.
1229 VehicleRotationalVelocity = Vector3.Zero; 1282 VehicleRotationalVelocity = Vector3.Zero;
1230 VDetailLog("{0}, MoveAngular,done,zero", Prim.LocalID); 1283 VDetailLog("{0}, MoveAngular,done,zero", ControllingPrim.LocalID);
1231 } 1284 }
1232 else 1285 else
1233 { 1286 {
1234 VDetailLog("{0}, MoveAngular,done,nonZero,angVel={1}", Prim.LocalID, VehicleRotationalVelocity); 1287 VDetailLog("{0}, MoveAngular,done,nonZero,angVel={1}", ControllingPrim.LocalID, VehicleRotationalVelocity);
1235 } 1288 }
1236 1289
1237 // ================================================================== 1290 // ==================================================================
@@ -1262,7 +1315,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1262 torqueFromOffset.Z = 0; 1315 torqueFromOffset.Z = 0;
1263 1316
1264 VehicleAddAngularForce(torqueFromOffset * m_vehicleMass); 1317 VehicleAddAngularForce(torqueFromOffset * m_vehicleMass);
1265 VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset); 1318 VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", ControllingPrim.LocalID, torqueFromOffset);
1266 } 1319 }
1267 1320
1268 } 1321 }
@@ -1277,7 +1330,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1277 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags : 1330 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
1278 // This flag prevents linear deflection parallel to world z-axis. This is useful 1331 // This flag prevents linear deflection parallel to world z-axis. This is useful
1279 // for preventing ground vehicles with large linear deflection, like bumper cars, 1332 // for preventing ground vehicles with large linear deflection, like bumper cars,
1280 // from climbing their linear deflection into the sky. 1333 // from climbing their linear deflection into the sky.
1281 // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement 1334 // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
1282 // TODO: This is here because this is where ODE put it but documentation says it 1335 // TODO: This is here because this is where ODE put it but documentation says it
1283 // is a linear effect. Where should this check go? 1336 // is a linear effect. Where should this check go?
@@ -1287,8 +1340,15 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1287 // angularMotorContributionV.Y = 0f; 1340 // angularMotorContributionV.Y = 0f;
1288 // } 1341 // }
1289 1342
1343 // Reduce any velocity by friction.
1344 Vector3 frictionFactorW = ComputeFrictionFactor(m_angularFrictionTimescale, pTimestep);
1345 angularMotorContributionV -= (currentAngularV * frictionFactorW);
1346
1290 VehicleRotationalVelocity += angularMotorContributionV * VehicleOrientation; 1347 VehicleRotationalVelocity += angularMotorContributionV * VehicleOrientation;
1291 VDetailLog("{0}, MoveAngular,angularTurning,angularMotorContrib={1}", Prim.LocalID, angularMotorContributionV); 1348
1349
1350
1351 VDetailLog("{0}, MoveAngular,angularTurning,angContribV={1}", ControllingPrim.LocalID, angularMotorContributionV);
1292 } 1352 }
1293 1353
1294 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: 1354 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
@@ -1305,6 +1365,35 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1305 // If vertical attaction timescale is reasonable 1365 // If vertical attaction timescale is reasonable
1306 if (enableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff) 1366 if (enableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1307 { 1367 {
1368 //Another formula to try got from :
1369 //http://answers.unity3d.com/questions/10425/how-to-stabilize-angular-motion-alignment-of-hover.html
1370
1371 Vector3 VehicleUpAxis = Vector3.UnitZ * VehicleOrientation;
1372
1373 // Flipping what was originally a timescale into a speed variable and then multiplying it by 2
1374 // since only computing half the distance between the angles.
1375 float VerticalAttractionSpeed = (1 / m_verticalAttractionTimescale) * 2.0f;
1376
1377 // Make a prediction of where the up axis will be when this is applied rather then where it is now as
1378 // this makes for a smoother adjustment and less fighting between the various forces.
1379 Vector3 predictedUp = VehicleUpAxis * Quaternion.CreateFromAxisAngle(VehicleRotationalVelocity, 0f);
1380
1381 // This is only half the distance to the target so it will take 2 seconds to complete the turn.
1382 Vector3 torqueVector = Vector3.Cross(predictedUp, Vector3.UnitZ);
1383
1384 // Scale vector by our timescale since it is an acceleration it is r/s^2 or radians a timescale squared
1385 Vector3 vertContributionV = torqueVector * VerticalAttractionSpeed * VerticalAttractionSpeed;
1386
1387 VehicleRotationalVelocity += vertContributionV;
1388
1389 VDetailLog("{0}, MoveAngular,verticalAttraction,UpAxis={1},PredictedUp={2},torqueVector={3},contrib={4}",
1390 ControllingPrim.LocalID,
1391 VehicleUpAxis,
1392 predictedUp,
1393 torqueVector,
1394 vertContributionV);
1395 //=====================================================================
1396 /*
1308 // Possible solution derived from a discussion at: 1397 // Possible solution derived from a discussion at:
1309 // http://stackoverflow.com/questions/14939657/computing-vector-from-quaternion-works-computing-quaternion-from-vector-does-no 1398 // http://stackoverflow.com/questions/14939657/computing-vector-from-quaternion-works-computing-quaternion-from-vector-does-no
1310 1399
@@ -1334,11 +1423,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1334 VehicleRotationalVelocity += vertContributionV; 1423 VehicleRotationalVelocity += vertContributionV;
1335 1424
1336 VDetailLog("{0}, MoveAngular,verticalAttraction,diffAxis={1},diffAng={2},corrRot={3},contrib={4}", 1425 VDetailLog("{0}, MoveAngular,verticalAttraction,diffAxis={1},diffAng={2},corrRot={3},contrib={4}",
1337 Prim.LocalID, 1426 ControllingPrim.LocalID,
1338 differenceAxis, 1427 differenceAxis,
1339 differenceAngle, 1428 differenceAngle,
1340 correctionRotation, 1429 correctionRotation,
1341 vertContributionV); 1430 vertContributionV);
1431 */
1342 1432
1343 // =================================================================== 1433 // ===================================================================
1344 /* 1434 /*
@@ -1380,7 +1470,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1380 VehicleRotationalVelocity += (vertContributionV * VehicleOrientation); 1470 VehicleRotationalVelocity += (vertContributionV * VehicleOrientation);
1381 1471
1382 VDetailLog("{0}, MoveAngular,verticalAttraction,,origRotVW={1},vertError={2},unscaledV={3},eff={4},ts={5},vertContribV={6}", 1472 VDetailLog("{0}, MoveAngular,verticalAttraction,,origRotVW={1},vertError={2},unscaledV={3},eff={4},ts={5},vertContribV={6}",
1383 Prim.LocalID, origRotVelW, verticalError, unscaledContribVerticalErrorV, 1473 Prim.LocalID, origRotVelW, verticalError, unscaledContribVerticalErrorV,
1384 m_verticalAttractionEfficiency, m_verticalAttractionTimescale, vertContributionV); 1474 m_verticalAttractionEfficiency, m_verticalAttractionTimescale, vertContributionV);
1385 */ 1475 */
1386 } 1476 }
@@ -1433,9 +1523,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1433 VehicleRotationalVelocity += deflectContributionV * VehicleOrientation; 1523 VehicleRotationalVelocity += deflectContributionV * VehicleOrientation;
1434 1524
1435 VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}", 1525 VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}",
1436 Prim.LocalID, movingDirection, pointingDirection, deflectionError, deflectContributionV); 1526 ControllingPrim.LocalID, movingDirection, pointingDirection, deflectionError, deflectContributionV);
1437 VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3}", 1527 VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3}",
1438 Prim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale); 1528 ControllingPrim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale);
1439 } 1529 }
1440 } 1530 }
1441 1531
@@ -1447,13 +1537,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1447 // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude 1537 // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude
1448 // of the yaw effect will be proportional to the 1538 // of the yaw effect will be proportional to the
1449 // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's 1539 // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's
1450 // velocity along its preferred axis of motion. 1540 // velocity along its preferred axis of motion.
1451 // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any 1541 // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any
1452 // positive rotation (by the right-hand rule) about the roll-axis will effect a 1542 // positive rotation (by the right-hand rule) about the roll-axis will effect a
1453 // (negative) torque around the yaw-axis, making it turn to the right--that is the 1543 // (negative) torque around the yaw-axis, making it turn to the right--that is the
1454 // vehicle will lean into the turn, which is how real airplanes and motorcycle's work. 1544 // vehicle will lean into the turn, which is how real airplanes and motorcycle's work.
1455 // Negating the banking coefficient will make it so that the vehicle leans to the 1545 // Negating the banking coefficient will make it so that the vehicle leans to the
1456 // outside of the turn (not very "physical" but might allow interesting vehicles so why not?). 1546 // outside of the turn (not very "physical" but might allow interesting vehicles so why not?).
1457 // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making 1547 // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making
1458 // banking vehicles do what you want rather than what the laws of physics allow. 1548 // banking vehicles do what you want rather than what the laws of physics allow.
1459 // For example, consider a real motorcycle...it must be moving forward in order for 1549 // For example, consider a real motorcycle...it must be moving forward in order for
@@ -1465,11 +1555,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1465 // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the 1555 // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the
1466 // banking effect depends only on the vehicle's rotation about its roll-axis compared 1556 // banking effect depends only on the vehicle's rotation about its roll-axis compared
1467 // to "dynamic" where the banking is also proportional to its velocity along its 1557 // to "dynamic" where the banking is also proportional to its velocity along its
1468 // roll-axis. Finding the best value of the "mixture" will probably require trial and error. 1558 // roll-axis. Finding the best value of the "mixture" will probably require trial and error.
1469 // The time it takes for the banking behavior to defeat a preexisting angular velocity about the 1559 // The time it takes for the banking behavior to defeat a preexisting angular velocity about the
1470 // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to 1560 // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to
1471 // bank quickly then give it a banking timescale of about a second or less, otherwise you can 1561 // bank quickly then give it a banking timescale of about a second or less, otherwise you can
1472 // make a sluggish vehicle by giving it a timescale of several seconds. 1562 // make a sluggish vehicle by giving it a timescale of several seconds.
1473 public void ComputeAngularBanking() 1563 public void ComputeAngularBanking()
1474 { 1564 {
1475 if (enableAngularBanking && m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff) 1565 if (enableAngularBanking && m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
@@ -1498,10 +1588,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1498 1588
1499 //VehicleRotationalVelocity += bankingContributionV * VehicleOrientation; 1589 //VehicleRotationalVelocity += bankingContributionV * VehicleOrientation;
1500 VehicleRotationalVelocity += bankingContributionV; 1590 VehicleRotationalVelocity += bankingContributionV;
1501 1591
1502 1592
1503 VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},rollComp={3},yAng={4},mYAng={5},ret={6}", 1593 VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},rollComp={3},yAng={4},mYAng={5},ret={6}",
1504 Prim.LocalID, rollComponents, VehicleForwardSpeed, rollComponents, yawAngle, mixedYawAngle, bankingContributionV); 1594 ControllingPrim.LocalID, rollComponents, VehicleForwardSpeed, rollComponents, yawAngle, mixedYawAngle, bankingContributionV);
1505 } 1595 }
1506 } 1596 }
1507 1597
@@ -1540,11 +1630,28 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1540 if (rotq != m_rot) 1630 if (rotq != m_rot)
1541 { 1631 {
1542 VehicleOrientation = m_rot; 1632 VehicleOrientation = m_rot;
1543 VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot); 1633 VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", ControllingPrim.LocalID, rotq, m_rot);
1544 } 1634 }
1545 1635
1546 } 1636 }
1547 1637
1638 // Given a friction vector (reduction in seconds) and a timestep, return the factor to reduce
1639 // some value by to apply this friction.
1640 private Vector3 ComputeFrictionFactor(Vector3 friction, float pTimestep)
1641 {
1642 Vector3 frictionFactor = Vector3.Zero;
1643 if (friction != BSMotor.InfiniteVector)
1644 {
1645 // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep;
1646 // Individual friction components can be 'infinite' so compute each separately.
1647 frictionFactor.X = (friction.X == BSMotor.Infinite) ? 0f : (1f / friction.X);
1648 frictionFactor.Y = (friction.Y == BSMotor.Infinite) ? 0f : (1f / friction.Y);
1649 frictionFactor.Z = (friction.Z == BSMotor.Infinite) ? 0f : (1f / friction.Z);
1650 frictionFactor *= pTimestep;
1651 }
1652 return frictionFactor;
1653 }
1654
1548 private float ClampInRange(float low, float val, float high) 1655 private float ClampInRange(float low, float val, float high)
1549 { 1656 {
1550 return Math.Max(low, Math.Min(val, high)); 1657 return Math.Max(low, Math.Min(val, high));
@@ -1554,8 +1661,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1554 // Invoke the detailed logger and output something if it's enabled. 1661 // Invoke the detailed logger and output something if it's enabled.
1555 private void VDetailLog(string msg, params Object[] args) 1662 private void VDetailLog(string msg, params Object[] args)
1556 { 1663 {
1557 if (Prim.PhysicsScene.VehicleLoggingEnabled) 1664 if (ControllingPrim.PhysScene.VehicleLoggingEnabled)
1558 Prim.PhysicsScene.DetailLog(msg, args); 1665 ControllingPrim.PhysScene.DetailLog(msg, args);
1559 } 1666 }
1560 } 1667 }
1561} 1668}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
index 4ece1eb..76c2187 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
@@ -80,7 +80,7 @@ public abstract class BSLinkset
80 80
81 public BSPrimLinkable LinksetRoot { get; protected set; } 81 public BSPrimLinkable LinksetRoot { get; protected set; }
82 82
83 public BSScene PhysicsScene { get; private set; } 83 protected BSScene m_physicsScene { get; private set; }
84 84
85 static int m_nextLinksetID = 1; 85 static int m_nextLinksetID = 1;
86 public int LinksetID { get; private set; } 86 public int LinksetID { get; private set; }
@@ -93,13 +93,6 @@ public abstract class BSLinkset
93 // to the physical representation is done via the tainting mechenism. 93 // to the physical representation is done via the tainting mechenism.
94 protected object m_linksetActivityLock = new Object(); 94 protected object m_linksetActivityLock = new Object();
95 95
96 // Some linksets have a preferred physical shape.
97 // Returns SHAPE_UNKNOWN if there is no preference. Causes the correct shape to be selected.
98 public virtual BSPhysicsShapeType PreferredPhysicalShape(BSPrimLinkable requestor)
99 {
100 return BSPhysicsShapeType.SHAPE_UNKNOWN;
101 }
102
103 // We keep the prim's mass in the linkset structure since it could be dependent on other prims 96 // We keep the prim's mass in the linkset structure since it could be dependent on other prims
104 public float LinksetMass { get; protected set; } 97 public float LinksetMass { get; protected set; }
105 98
@@ -122,7 +115,7 @@ public abstract class BSLinkset
122 // We create LOTS of linksets. 115 // We create LOTS of linksets.
123 if (m_nextLinksetID <= 0) 116 if (m_nextLinksetID <= 0)
124 m_nextLinksetID = 1; 117 m_nextLinksetID = 1;
125 PhysicsScene = scene; 118 m_physicsScene = scene;
126 LinksetRoot = parent; 119 LinksetRoot = parent;
127 m_children = new HashSet<BSPrimLinkable>(); 120 m_children = new HashSet<BSPrimLinkable>();
128 LinksetMass = parent.RawMass; 121 LinksetMass = parent.RawMass;
@@ -165,7 +158,7 @@ public abstract class BSLinkset
165 } 158 }
166 159
167 // The child is down to a linkset of just itself 160 // The child is down to a linkset of just itself
168 return BSLinkset.Factory(PhysicsScene, child); 161 return BSLinkset.Factory(m_physicsScene, child);
169 } 162 }
170 163
171 // Return 'true' if the passed object is the root object of this linkset 164 // Return 'true' if the passed object is the root object of this linkset
@@ -221,7 +214,7 @@ public abstract class BSLinkset
221 // I am the root of a linkset and a new child is being added 214 // I am the root of a linkset and a new child is being added
222 // Called while LinkActivity is locked. 215 // Called while LinkActivity is locked.
223 protected abstract void AddChildToLinkset(BSPrimLinkable child); 216 protected abstract void AddChildToLinkset(BSPrimLinkable child);
224 217
225 // I am the root of a linkset and one of my children is being removed. 218 // I am the root of a linkset and one of my children is being removed.
226 // Safe to call even if the child is not really in my linkset. 219 // Safe to call even if the child is not really in my linkset.
227 protected abstract void RemoveChildFromLinkset(BSPrimLinkable child); 220 protected abstract void RemoveChildFromLinkset(BSPrimLinkable child);
@@ -263,7 +256,7 @@ public abstract class BSLinkset
263 // This is called when the root body is changing. 256 // This is called when the root body is changing.
264 // Returns 'true' of something was actually removed and would need restoring 257 // Returns 'true' of something was actually removed and would need restoring
265 // Called at taint-time!! 258 // Called at taint-time!!
266 public abstract bool RemoveBodyDependencies(BSPrimLinkable child); 259 public abstract bool RemoveDependencies(BSPrimLinkable child);
267 260
268 // ================================================================ 261 // ================================================================
269 protected virtual float ComputeLinksetMass() 262 protected virtual float ComputeLinksetMass()
@@ -323,8 +316,8 @@ public abstract class BSLinkset
323 // Invoke the detailed logger and output something if it's enabled. 316 // Invoke the detailed logger and output something if it's enabled.
324 protected void DetailLog(string msg, params Object[] args) 317 protected void DetailLog(string msg, params Object[] args)
325 { 318 {
326 if (PhysicsScene.PhysicsLogging.Enabled) 319 if (m_physicsScene.PhysicsLogging.Enabled)
327 PhysicsScene.DetailLog(msg, args); 320 m_physicsScene.DetailLog(msg, args);
328 } 321 }
329 322
330} 323}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
index e05562a..350a5d1 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
@@ -35,6 +35,7 @@ using OMV = OpenMetaverse;
35namespace OpenSim.Region.Physics.BulletSPlugin 35namespace OpenSim.Region.Physics.BulletSPlugin
36{ 36{
37 37
38 /*
38// When a child is linked, the relationship position of the child to the parent 39// When a child is linked, the relationship position of the child to the parent
39// is remembered so the child's world position can be recomputed when it is 40// is remembered so the child's world position can be recomputed when it is
40// removed from the linkset. 41// removed from the linkset.
@@ -88,6 +89,7 @@ sealed class BSLinksetCompoundInfo : BSLinksetInfo
88 return buff.ToString(); 89 return buff.ToString();
89 } 90 }
90}; 91};
92 */
91 93
92public sealed class BSLinksetCompound : BSLinkset 94public sealed class BSLinksetCompound : BSLinkset
93{ 95{
@@ -98,19 +100,6 @@ public sealed class BSLinksetCompound : BSLinkset
98 { 100 {
99 } 101 }
100 102
101 // For compound implimented linksets, if there are children, use compound shape for the root.
102 public override BSPhysicsShapeType PreferredPhysicalShape(BSPrimLinkable requestor)
103 {
104 // Returning 'unknown' means we don't have a preference.
105 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
106 if (IsRoot(requestor) && HasAnyChildren)
107 {
108 ret = BSPhysicsShapeType.SHAPE_COMPOUND;
109 }
110 // DetailLog("{0},BSLinksetCompound.PreferredPhysicalShape,call,shape={1}", LinksetRoot.LocalID, ret);
111 return ret;
112 }
113
114 // When physical properties are changed the linkset needs to recalculate 103 // When physical properties are changed the linkset needs to recalculate
115 // its internal properties. 104 // its internal properties.
116 public override void Refresh(BSPrimLinkable requestor) 105 public override void Refresh(BSPrimLinkable requestor)
@@ -124,14 +113,14 @@ public sealed class BSLinksetCompound : BSLinkset
124 // Schedule a refresh to happen after all the other taint processing. 113 // Schedule a refresh to happen after all the other taint processing.
125 private void ScheduleRebuild(BSPrimLinkable requestor) 114 private void ScheduleRebuild(BSPrimLinkable requestor)
126 { 115 {
127 DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}", 116 DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}",
128 requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren)); 117 requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren));
129 // When rebuilding, it is possible to set properties that would normally require a rebuild. 118 // When rebuilding, it is possible to set properties that would normally require a rebuild.
130 // If already rebuilding, don't request another rebuild. 119 // If already rebuilding, don't request another rebuild.
131 // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding. 120 // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding.
132 if (!Rebuilding && HasAnyChildren) 121 if (!Rebuilding && HasAnyChildren)
133 { 122 {
134 PhysicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate() 123 m_physicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate()
135 { 124 {
136 if (HasAnyChildren) 125 if (HasAnyChildren)
137 RecomputeLinksetCompound(); 126 RecomputeLinksetCompound();
@@ -153,26 +142,11 @@ public sealed class BSLinksetCompound : BSLinkset
153 // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. 142 // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly.
154 ScheduleRebuild(LinksetRoot); 143 ScheduleRebuild(LinksetRoot);
155 } 144 }
156 else
157 {
158 // The origional prims are removed from the world as the shape of the root compound
159 // shape takes over.
160 PhysicsScene.PE.AddToCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
161 PhysicsScene.PE.ForceActivationState(child.PhysBody, ActivationState.DISABLE_SIMULATION);
162 // We don't want collisions from the old linkset children.
163 PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
164
165 child.PhysBody.collisionType = CollisionType.LinksetChild;
166
167 ret = true;
168 }
169 return ret; 145 return ret;
170 } 146 }
171 147
172 // The object is going static (non-physical). Do any setup necessary for a static linkset. 148 // The object is going static (non-physical). We do not do anything for static linksets.
173 // Return 'true' if any properties updated on the passed object. 149 // Return 'true' if any properties updated on the passed object.
174 // This doesn't normally happen -- OpenSim removes the objects from the physical
175 // world if it is a static linkset.
176 // Called at taint-time! 150 // Called at taint-time!
177 public override bool MakeStatic(BSPrimLinkable child) 151 public override bool MakeStatic(BSPrimLinkable child)
178 { 152 {
@@ -180,19 +154,9 @@ public sealed class BSLinksetCompound : BSLinkset
180 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); 154 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
181 if (IsRoot(child)) 155 if (IsRoot(child))
182 { 156 {
157 // Schedule a rebuild to verify that the root shape is set to the real shape.
183 ScheduleRebuild(LinksetRoot); 158 ScheduleRebuild(LinksetRoot);
184 } 159 }
185 else
186 {
187 // The non-physical children can come back to life.
188 PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
189
190 child.PhysBody.collisionType = CollisionType.LinksetChild;
191
192 // Don't force activation so setting of DISABLE_SIMULATION can stay if used.
193 PhysicsScene.PE.Activate(child.PhysBody, false);
194 ret = true;
195 }
196 return ret; 160 return ret;
197 } 161 }
198 162
@@ -200,13 +164,20 @@ public sealed class BSLinksetCompound : BSLinkset
200 // Called at taint-time. 164 // Called at taint-time.
201 public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable updated) 165 public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable updated)
202 { 166 {
167 if (!LinksetRoot.IsPhysicallyActive)
168 {
169 // No reason to do this physical stuff for static linksets.
170 DetailLog("{0},BSLinksetCompound.UpdateProperties,notPhysical", LinksetRoot.LocalID);
171 return;
172 }
173
203 // The user moving a child around requires the rebuilding of the linkset compound shape 174 // The user moving a child around requires the rebuilding of the linkset compound shape
204 // One problem is this happens when a border is crossed -- the simulator implementation 175 // One problem is this happens when a border is crossed -- the simulator implementation
205 // stores the position into the group which causes the move of the object 176 // stores the position into the group which causes the move of the object
206 // but it also means all the child positions get updated. 177 // but it also means all the child positions get updated.
207 // What would cause an unnecessary rebuild so we make sure the linkset is in a 178 // What would cause an unnecessary rebuild so we make sure the linkset is in a
208 // region before bothering to do a rebuild. 179 // region before bothering to do a rebuild.
209 if (!IsRoot(updated) && PhysicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition)) 180 if (!IsRoot(updated) && m_physicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition))
210 { 181 {
211 // If a child of the linkset is updating only the position or rotation, that can be done 182 // If a child of the linkset is updating only the position or rotation, that can be done
212 // without rebuilding the linkset. 183 // without rebuilding the linkset.
@@ -218,22 +189,22 @@ public sealed class BSLinksetCompound : BSLinkset
218 // and that is caused by us updating the object. 189 // and that is caused by us updating the object.
219 if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0) 190 if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0)
220 { 191 {
221 // Find the physical instance of the child 192 // Find the physical instance of the child
222 if (LinksetRoot.PhysShape.HasPhysicalShape && PhysicsScene.PE.IsCompound(LinksetRoot.PhysShape)) 193 if (LinksetRoot.PhysShape.HasPhysicalShape && m_physicsScene.PE.IsCompound(LinksetRoot.PhysShape.physShapeInfo))
223 { 194 {
224 // It is possible that the linkset is still under construction and the child is not yet 195 // It is possible that the linkset is still under construction and the child is not yet
225 // inserted into the compound shape. A rebuild of the linkset in a pre-step action will 196 // inserted into the compound shape. A rebuild of the linkset in a pre-step action will
226 // build the whole thing with the new position or rotation. 197 // build the whole thing with the new position or rotation.
227 // The index must be checked because Bullet references the child array but does no validity 198 // The index must be checked because Bullet references the child array but does no validity
228 // checking of the child index passed. 199 // checking of the child index passed.
229 int numLinksetChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape); 200 int numLinksetChildren = m_physicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape.physShapeInfo);
230 if (updated.LinksetChildIndex < numLinksetChildren) 201 if (updated.LinksetChildIndex < numLinksetChildren)
231 { 202 {
232 BulletShape linksetChildShape = PhysicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape, updated.LinksetChildIndex); 203 BulletShape linksetChildShape = m_physicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex);
233 if (linksetChildShape.HasPhysicalShape) 204 if (linksetChildShape.HasPhysicalShape)
234 { 205 {
235 // Found the child shape within the compound shape 206 // Found the child shape within the compound shape
236 PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, updated.LinksetChildIndex, 207 m_physicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex,
237 updated.RawPosition - LinksetRoot.RawPosition, 208 updated.RawPosition - LinksetRoot.RawPosition,
238 updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation), 209 updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation),
239 true /* shouldRecalculateLocalAabb */); 210 true /* shouldRecalculateLocalAabb */);
@@ -275,75 +246,22 @@ public sealed class BSLinksetCompound : BSLinkset
275 } 246 }
276 247
277 // Routine called when rebuilding the body of some member of the linkset. 248 // Routine called when rebuilding the body of some member of the linkset.
278 // Since we don't keep in world relationships, do nothing unless it's a child changing. 249 // If one of the bodies is being changed, the linkset needs rebuilding.
250 // For instance, a linkset is built and then a mesh asset is read in and the mesh is recreated.
279 // Returns 'true' of something was actually removed and would need restoring 251 // Returns 'true' of something was actually removed and would need restoring
280 // Called at taint-time!! 252 // Called at taint-time!!
281 public override bool RemoveBodyDependencies(BSPrimLinkable child) 253 public override bool RemoveDependencies(BSPrimLinkable child)
282 { 254 {
283 bool ret = false; 255 bool ret = false;
284 256
285 DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", 257 DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}",
286 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child)); 258 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child));
287 259
288 if (!IsRoot(child)) 260 ScheduleRebuild(child);
289 {
290 // Because it is a convenient time, recompute child world position and rotation based on
291 // its position in the linkset.
292 RecomputeChildWorldPosition(child, true /* inTaintTime */);
293 child.LinksetInfo = null;
294 }
295
296 // Cannot schedule a refresh/rebuild here because this routine is called when
297 // the linkset is being rebuilt.
298 // InternalRefresh(LinksetRoot);
299 261
300 return ret; 262 return ret;
301 } 263 }
302 264
303 // When the linkset is built, the child shape is added to the compound shape relative to the
304 // root shape. The linkset then moves around but this does not move the actual child
305 // prim. The child prim's location must be recomputed based on the location of the root shape.
306 private void RecomputeChildWorldPosition(BSPrimLinkable child, bool inTaintTime)
307 {
308 // For the moment (20130201), disable this computation (converting the child physical addr back to
309 // a region address) until we have a good handle on center-of-mass offsets and what the physics
310 // engine moving a child actually means.
311 // The simulator keeps track of where children should be as the linkset moves. Setting
312 // the pos/rot here does not effect that knowledge as there is no good way for the
313 // physics engine to send the simulator an update for a child.
314
315 /*
316 BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo;
317 if (lci != null)
318 {
319 if (inTaintTime)
320 {
321 OMV.Vector3 oldPos = child.RawPosition;
322 child.ForcePosition = LinksetRoot.RawPosition + lci.OffsetFromRoot;
323 child.ForceOrientation = LinksetRoot.RawOrientation * lci.OffsetRot;
324 DetailLog("{0},BSLinksetCompound.RecomputeChildWorldPosition,oldPos={1},lci={2},newPos={3}",
325 child.LocalID, oldPos, lci, child.RawPosition);
326 }
327 else
328 {
329 // TaintedObject is not used here so the raw position is set now and not at taint-time.
330 child.Position = LinksetRoot.RawPosition + lci.OffsetFromRoot;
331 child.Orientation = LinksetRoot.RawOrientation * lci.OffsetRot;
332 }
333 }
334 else
335 {
336 // This happens when children have been added to the linkset but the linkset
337 // has not been constructed yet. So like, at taint time, adding children to a linkset
338 // and then changing properties of the children (makePhysical, for instance)
339 // but the post-print action of actually rebuilding the linkset has not yet happened.
340 // PhysicsScene.Logger.WarnFormat("{0} Restoring linkset child position failed because of no relative position computed. ID={1}",
341 // LogHeader, child.LocalID);
342 DetailLog("{0},BSLinksetCompound.recomputeChildWorldPosition,noRelativePositonInfo", child.LocalID);
343 }
344 */
345 }
346
347 // ================================================================ 265 // ================================================================
348 266
349 // Add a new child to the linkset. 267 // Add a new child to the linkset.
@@ -376,7 +294,6 @@ public sealed class BSLinksetCompound : BSLinkset
376 child.LocalID, child.PhysBody.AddrString); 294 child.LocalID, child.PhysBody.AddrString);
377 295
378 // Cause the child's body to be rebuilt and thus restored to normal operation 296 // Cause the child's body to be rebuilt and thus restored to normal operation
379 RecomputeChildWorldPosition(child, false);
380 child.LinksetInfo = null; 297 child.LinksetInfo = null;
381 child.ForceBodyShapeRebuild(false); 298 child.ForceBodyShapeRebuild(false);
382 299
@@ -399,108 +316,105 @@ public sealed class BSLinksetCompound : BSLinkset
399 // Constraint linksets are rebuilt every time. 316 // Constraint linksets are rebuilt every time.
400 // Note that this works for rebuilding just the root after a linkset is taken apart. 317 // Note that this works for rebuilding just the root after a linkset is taken apart.
401 // Called at taint time!! 318 // Called at taint time!!
402 private bool disableCOM = true; // DEBUG DEBUG: disable until we get this debugged 319 private bool UseBulletSimRootOffsetHack = false; // Attempt to have Bullet track the coords of root compound shape
320 private bool disableCOM = true; // For basic linkset debugging, turn off the center-of-mass setting
403 private void RecomputeLinksetCompound() 321 private void RecomputeLinksetCompound()
404 { 322 {
405 try 323 try
406 { 324 {
407 // Suppress rebuilding while rebuilding. (We know rebuilding is on only one thread.)
408 Rebuilding = true; 325 Rebuilding = true;
409 326
410 // Cause the root shape to be rebuilt as a compound object with just the root in it 327 // No matter what is being done, force the root prim's PhysBody and PhysShape to get set
411 LinksetRoot.ForceBodyShapeRebuild(true /* inTaintTime */); 328 // to what they should be as if the root was not in a linkset.
329 // Not that bad since we only get into this routine if there are children in the linkset and
330 // something has been updated/changed.
331 LinksetRoot.ForceBodyShapeRebuild(true);
412 332
413 // The center of mass for the linkset is the geometric center of the group. 333 // There is no reason to build all this physical stuff for a non-physical linkset.
414 // Compute a displacement for each component so it is relative to the center-of-mass. 334 if (!LinksetRoot.IsPhysicallyActive)
415 // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass
416 OMV.Vector3 centerOfMassW = LinksetRoot.RawPosition;
417 if (!disableCOM) // DEBUG DEBUG
418 { 335 {
419 // Compute a center-of-mass in world coordinates. 336 // Clean up any old linkset shape and make sure the root shape is set to the root object.
420 centerOfMassW = ComputeLinksetCenterOfMass(); 337 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,notPhysical", LinksetRoot.LocalID);
421 }
422 338
423 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation); 339 return; // Note the 'finally' clause at the botton which will get executed.
424 340 }
425 // 'centerDisplacement' is the value to subtract from children to give physical offset position
426 OMV.Vector3 centerDisplacement = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation;
427 LinksetRoot.SetEffectiveCenterOfMassW(centerDisplacement);
428 341
429 // This causes the physical position of the root prim to be offset to accomodate for the displacements 342 // Get a new compound shape to build the linkset shape in.
430 LinksetRoot.ForcePosition = LinksetRoot.RawPosition; 343 BSShape linksetShape = BSShapeCompound.GetReference(m_physicsScene);
431 344
432 // Update the local transform for the root child shape so it is offset from the <0,0,0> which is COM 345 // The center of mass for the linkset is the geometric center of the group.
433 PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, 0 /* childIndex */, 346 // Compute a displacement for each component so it is relative to the center-of-mass.
434 -centerDisplacement, 347 // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass
435 OMV.Quaternion.Identity, // LinksetRoot.RawOrientation, 348 OMV.Vector3 centerOfMassW = ComputeLinksetCenterOfMass();
436 false /* shouldRecalculateLocalAabb (is done later after linkset built) */);
437 349
438 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,com={1},rootPos={2},centerDisp={3}", 350 OMV.Quaternion invRootOrientation = OMV.Quaternion.Normalize(OMV.Quaternion.Inverse(LinksetRoot.RawOrientation));
439 LinksetRoot.LocalID, centerOfMassW, LinksetRoot.RawPosition, centerDisplacement);
440 351
441 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}", 352 // 'centerDisplacement' is the value to subtract from children to give physical offset position
442 LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren); 353 OMV.Vector3 centerDisplacementV = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation;
354 if (UseBulletSimRootOffsetHack || disableCOM)
355 {
356 centerDisplacementV = OMV.Vector3.Zero;
357 LinksetRoot.ClearDisplacement();
358 }
359 else
360 {
361 LinksetRoot.SetEffectiveCenterOfMassDisplacement(centerDisplacementV);
362 }
363 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,rootPos={1},com={2},comDisp={3}",
364 LinksetRoot.LocalID, LinksetRoot.RawPosition, centerOfMassW, centerDisplacementV);
443 365
444 // Add a shape for each of the other children in the linkset 366 // Add the shapes of all the components of the linkset
445 int memberIndex = 1; 367 int memberIndex = 1;
446 ForEachMember(delegate(BSPrimLinkable cPrim) 368 ForEachMember(delegate(BSPrimLinkable cPrim)
447 { 369 {
448 if (IsRoot(cPrim)) 370 // Root shape is always index zero.
371 cPrim.LinksetChildIndex = IsRoot(cPrim) ? 0 : memberIndex;
372
373 // Get a reference to the shape of the child and add that shape to the linkset compound shape
374 BSShape childShape = cPrim.PhysShape.GetReference(m_physicsScene, cPrim);
375 OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacementV;
376 OMV.Quaternion offsetRot = OMV.Quaternion.Normalize(cPrim.RawOrientation) * invRootOrientation;
377 m_physicsScene.PE.AddChildShapeToCompoundShape(linksetShape.physShapeInfo, childShape.physShapeInfo, offsetPos, offsetRot);
378 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChild,indx={1},cShape={2},offPos={3},offRot={4}",
379 LinksetRoot.LocalID, memberIndex, childShape, offsetPos, offsetRot);
380
381 // Since we are borrowing the shape of the child, disable the origional child body
382 if (!IsRoot(cPrim))
449 { 383 {
450 cPrim.LinksetChildIndex = 0; 384 m_physicsScene.PE.AddToCollisionFlags(cPrim.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
385 m_physicsScene.PE.ForceActivationState(cPrim.PhysBody, ActivationState.DISABLE_SIMULATION);
386 // We don't want collisions from the old linkset children.
387 m_physicsScene.PE.RemoveFromCollisionFlags(cPrim.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
388 cPrim.PhysBody.collisionType = CollisionType.LinksetChild;
451 } 389 }
452 else
453 {
454 cPrim.LinksetChildIndex = memberIndex;
455 390
456 if (cPrim.PhysShape.isNativeShape) 391 memberIndex++;
457 {
458 // A native shape is turned into a hull collision shape because native
459 // shapes are not shared so we have to hullify it so it will be tracked
460 // and freed at the correct time. This also solves the scaling problem
461 // (native shapes scale but hull/meshes are assumed to not be).
462 // TODO: decide of the native shape can just be used in the compound shape.
463 // Use call to CreateGeomNonSpecial().
464 BulletShape saveShape = cPrim.PhysShape;
465 cPrim.PhysShape.Clear(); // Don't let the create free the child's shape
466 PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
467 BulletShape newShape = cPrim.PhysShape;
468 cPrim.PhysShape = saveShape;
469
470 OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacement;
471 OMV.Quaternion offsetRot = cPrim.RawOrientation * invRootOrientation;
472 PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, newShape, offsetPos, offsetRot);
473 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addNative,indx={1},rShape={2},cShape={3},offPos={4},offRot={5}",
474 LinksetRoot.LocalID, memberIndex, LinksetRoot.PhysShape, newShape, offsetPos, offsetRot);
475 }
476 else
477 {
478 // For the shared shapes (meshes and hulls), just use the shape in the child.
479 // The reference count added here will be decremented when the compound shape
480 // is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced).
481 if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape))
482 {
483 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}",
484 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape);
485 }
486 OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacement;
487 OMV.Quaternion offsetRot = cPrim.RawOrientation * invRootOrientation;
488 PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, cPrim.PhysShape, offsetPos, offsetRot);
489 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addNonNative,indx={1},rShape={2},cShape={3},offPos={4},offRot={5}",
490 LinksetRoot.LocalID, memberIndex, LinksetRoot.PhysShape, cPrim.PhysShape, offsetPos, offsetRot);
491 392
492 }
493 memberIndex++;
494 }
495 return false; // 'false' says to move onto the next child in the list 393 return false; // 'false' says to move onto the next child in the list
496 }); 394 });
497 395
396 // Replace the root shape with the built compound shape.
397 // Object removed and added to world to get collision cache rebuilt for new shape.
398 LinksetRoot.PhysShape.Dereference(m_physicsScene);
399 LinksetRoot.PhysShape = linksetShape;
400 m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, LinksetRoot.PhysBody);
401 m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, LinksetRoot.PhysBody, linksetShape.physShapeInfo);
402 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, LinksetRoot.PhysBody);
403 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addBody,body={1},shape={2}",
404 LinksetRoot.LocalID, LinksetRoot.PhysBody, linksetShape);
405
498 // With all of the linkset packed into the root prim, it has the mass of everyone. 406 // With all of the linkset packed into the root prim, it has the mass of everyone.
499 LinksetMass = ComputeLinksetMass(); 407 LinksetMass = ComputeLinksetMass();
500 LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true); 408 LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true);
501 409
502 // Enable the physical position updator to return the position and rotation of the root shape 410 if (UseBulletSimRootOffsetHack)
503 PhysicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE); 411 {
412 // Enable the physical position updator to return the position and rotation of the root shape.
413 // This enables a feature in the C++ code to return the world coordinates of the first shape in the
414 // compound shape. This eleviates the need to offset the returned physical position by the
415 // center-of-mass offset.
416 m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE);
417 }
504 } 418 }
505 finally 419 finally
506 { 420 {
@@ -508,7 +422,7 @@ public sealed class BSLinksetCompound : BSLinkset
508 } 422 }
509 423
510 // See that the Aabb surrounds the new shape 424 // See that the Aabb surrounds the new shape
511 PhysicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape); 425 m_physicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape.physShapeInfo);
512 } 426 }
513} 427}
514} \ No newline at end of file 428} \ No newline at end of file
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
index 6d252ca..a06a44d 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
@@ -51,7 +51,7 @@ public sealed class BSLinksetConstraints : BSLinkset
51 if (HasAnyChildren && IsRoot(requestor)) 51 if (HasAnyChildren && IsRoot(requestor))
52 { 52 {
53 // Queue to happen after all the other taint processing 53 // Queue to happen after all the other taint processing
54 PhysicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() 54 m_physicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate()
55 { 55 {
56 if (HasAnyChildren && IsRoot(requestor)) 56 if (HasAnyChildren && IsRoot(requestor))
57 RecomputeLinksetConstraints(); 57 RecomputeLinksetConstraints();
@@ -93,11 +93,11 @@ public sealed class BSLinksetConstraints : BSLinkset
93 // up to rebuild the constraints before the next simulation step. 93 // up to rebuild the constraints before the next simulation step.
94 // Returns 'true' of something was actually removed and would need restoring 94 // Returns 'true' of something was actually removed and would need restoring
95 // Called at taint-time!! 95 // Called at taint-time!!
96 public override bool RemoveBodyDependencies(BSPrimLinkable child) 96 public override bool RemoveDependencies(BSPrimLinkable child)
97 { 97 {
98 bool ret = false; 98 bool ret = false;
99 99
100 DetailLog("{0},BSLinksetConstraint.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}", 100 DetailLog("{0},BSLinksetConstraint.RemoveDependencies,removeChildrenForRoot,rID={1},rBody={2}",
101 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString); 101 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString);
102 102
103 lock (m_linksetActivityLock) 103 lock (m_linksetActivityLock)
@@ -142,7 +142,7 @@ public sealed class BSLinksetConstraints : BSLinkset
142 rootx.LocalID, rootx.PhysBody.AddrString, 142 rootx.LocalID, rootx.PhysBody.AddrString,
143 childx.LocalID, childx.PhysBody.AddrString); 143 childx.LocalID, childx.PhysBody.AddrString);
144 144
145 PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate() 145 m_physicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate()
146 { 146 {
147 PhysicallyUnlinkAChildFromRoot(rootx, childx); 147 PhysicallyUnlinkAChildFromRoot(rootx, childx);
148 }); 148 });
@@ -187,7 +187,7 @@ public sealed class BSLinksetConstraints : BSLinkset
187 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 187 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
188 188
189 BSConstraint6Dof constrain = new BSConstraint6Dof( 189 BSConstraint6Dof constrain = new BSConstraint6Dof(
190 PhysicsScene.World, rootPrim.PhysBody, childPrim.PhysBody, midPoint, true, true ); 190 m_physicsScene.World, rootPrim.PhysBody, childPrim.PhysBody, midPoint, true, true );
191 // PhysicsScene.World, childPrim.BSBody, rootPrim.BSBody, midPoint, true, true ); 191 // PhysicsScene.World, childPrim.BSBody, rootPrim.BSBody, midPoint, true, true );
192 192
193 /* NOTE: below is an attempt to build constraint with full frame computation, etc. 193 /* NOTE: below is an attempt to build constraint with full frame computation, etc.
@@ -216,7 +216,7 @@ public sealed class BSLinksetConstraints : BSLinkset
216 // ================================================================================== 216 // ==================================================================================
217 */ 217 */
218 218
219 PhysicsScene.Constraints.AddConstraint(constrain); 219 m_physicsScene.Constraints.AddConstraint(constrain);
220 220
221 // zero linear and angular limits makes the objects unable to move in relation to each other 221 // zero linear and angular limits makes the objects unable to move in relation to each other
222 constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); 222 constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
@@ -248,10 +248,10 @@ public sealed class BSLinksetConstraints : BSLinkset
248 childPrim.LocalID, childPrim.PhysBody.AddrString); 248 childPrim.LocalID, childPrim.PhysBody.AddrString);
249 249
250 // Find the constraint for this link and get rid of it from the overall collection and from my list 250 // Find the constraint for this link and get rid of it from the overall collection and from my list
251 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody)) 251 if (m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody))
252 { 252 {
253 // Make the child refresh its location 253 // Make the child refresh its location
254 PhysicsScene.PE.PushUpdate(childPrim.PhysBody); 254 m_physicsScene.PE.PushUpdate(childPrim.PhysBody);
255 ret = true; 255 ret = true;
256 } 256 }
257 257
@@ -265,7 +265,7 @@ public sealed class BSLinksetConstraints : BSLinkset
265 { 265 {
266 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); 266 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
267 267
268 return PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody); 268 return m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody);
269 } 269 }
270 270
271 // Call each of the constraints that make up this linkset and recompute the 271 // Call each of the constraints that make up this linkset and recompute the
@@ -289,7 +289,7 @@ public sealed class BSLinksetConstraints : BSLinkset
289 child.UpdatePhysicalMassProperties(linksetMass, true); 289 child.UpdatePhysicalMassProperties(linksetMass, true);
290 290
291 BSConstraint constrain; 291 BSConstraint constrain;
292 if (!PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain)) 292 if (!m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain))
293 { 293 {
294 // If constraint doesn't exist yet, create it. 294 // If constraint doesn't exist yet, create it.
295 constrain = BuildConstraint(LinksetRoot, child); 295 constrain = BuildConstraint(LinksetRoot, child);
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
index 9501e2d..ef662b5 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
@@ -65,13 +65,11 @@ public abstract class BSMotor
65} 65}
66 66
67// Motor which moves CurrentValue to TargetValue over TimeScale seconds. 67// Motor which moves CurrentValue to TargetValue over TimeScale seconds.
68// The TargetValue decays in TargetValueDecayTimeScale and 68// The TargetValue decays in TargetValueDecayTimeScale.
69// the CurrentValue will be held back by FrictionTimeScale.
70// This motor will "zero itself" over time in that the targetValue will 69// This motor will "zero itself" over time in that the targetValue will
71// decay to zero and the currentValue will follow it to that zero. 70// decay to zero and the currentValue will follow it to that zero.
72// The overall effect is for the returned correction value to go from large 71// The overall effect is for the returned correction value to go from large
73// values (the total difference between current and target minus friction) 72// values to small and eventually zero values.
74// to small and eventually zero values.
75// TimeScale and TargetDelayTimeScale may be 'infinite' which means no decay. 73// TimeScale and TargetDelayTimeScale may be 'infinite' which means no decay.
76 74
77// For instance, if something is moving at speed X and the desired speed is Y, 75// For instance, if something is moving at speed X and the desired speed is Y,
@@ -88,7 +86,6 @@ public class BSVMotor : BSMotor
88 86
89 public virtual float TimeScale { get; set; } 87 public virtual float TimeScale { get; set; }
90 public virtual float TargetValueDecayTimeScale { get; set; } 88 public virtual float TargetValueDecayTimeScale { get; set; }
91 public virtual Vector3 FrictionTimescale { get; set; }
92 public virtual float Efficiency { get; set; } 89 public virtual float Efficiency { get; set; }
93 90
94 public virtual float ErrorZeroThreshold { get; set; } 91 public virtual float ErrorZeroThreshold { get; set; }
@@ -102,7 +99,7 @@ public class BSVMotor : BSMotor
102 return ErrorIsZero(LastError); 99 return ErrorIsZero(LastError);
103 } 100 }
104 public virtual bool ErrorIsZero(Vector3 err) 101 public virtual bool ErrorIsZero(Vector3 err)
105 { 102 {
106 return (err == Vector3.Zero || err.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)); 103 return (err == Vector3.Zero || err.ApproxEquals(Vector3.Zero, ErrorZeroThreshold));
107 } 104 }
108 105
@@ -111,16 +108,14 @@ public class BSVMotor : BSMotor
111 { 108 {
112 TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite; 109 TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite;
113 Efficiency = 1f; 110 Efficiency = 1f;
114 FrictionTimescale = BSMotor.InfiniteVector;
115 CurrentValue = TargetValue = Vector3.Zero; 111 CurrentValue = TargetValue = Vector3.Zero;
116 ErrorZeroThreshold = 0.001f; 112 ErrorZeroThreshold = 0.001f;
117 } 113 }
118 public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency) 114 public BSVMotor(string useName, float timeScale, float decayTimeScale, float efficiency)
119 : this(useName) 115 : this(useName)
120 { 116 {
121 TimeScale = timeScale; 117 TimeScale = timeScale;
122 TargetValueDecayTimeScale = decayTimeScale; 118 TargetValueDecayTimeScale = decayTimeScale;
123 FrictionTimescale = frictionTimeScale;
124 Efficiency = efficiency; 119 Efficiency = efficiency;
125 CurrentValue = TargetValue = Vector3.Zero; 120 CurrentValue = TargetValue = Vector3.Zero;
126 } 121 }
@@ -165,26 +160,11 @@ public class BSVMotor : BSMotor
165 TargetValue *= (1f - decayFactor); 160 TargetValue *= (1f - decayFactor);
166 } 161 }
167 162
168 // The amount we can correct the error is reduced by the friction
169 Vector3 frictionFactor = Vector3.Zero;
170 if (FrictionTimescale != BSMotor.InfiniteVector)
171 {
172 // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep;
173 // Individual friction components can be 'infinite' so compute each separately.
174 frictionFactor.X = (FrictionTimescale.X == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.X);
175 frictionFactor.Y = (FrictionTimescale.Y == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Y);
176 frictionFactor.Z = (FrictionTimescale.Z == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Z);
177 frictionFactor *= timeStep;
178 CurrentValue *= (Vector3.One - frictionFactor);
179 }
180
181 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}", 163 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}",
182 BSScene.DetailLogZero, UseName, origCurrVal, origTarget, 164 BSScene.DetailLogZero, UseName, origCurrVal, origTarget,
183 timeStep, error, correction); 165 timeStep, error, correction);
184 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},frictTS={4},frictFact={5},tgt={6},curr={7}", 166 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},tgt={4},curr={5}",
185 BSScene.DetailLogZero, UseName, 167 BSScene.DetailLogZero, UseName, TargetValueDecayTimeScale, decayFactor, TargetValue, CurrentValue);
186 TargetValueDecayTimeScale, decayFactor, FrictionTimescale, frictionFactor,
187 TargetValue, CurrentValue);
188 } 168 }
189 else 169 else
190 { 170 {
@@ -235,9 +215,9 @@ public class BSVMotor : BSMotor
235 // maximum number of outputs to generate. 215 // maximum number of outputs to generate.
236 int maxOutput = 50; 216 int maxOutput = 50;
237 MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName); 217 MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName);
238 MDetailLog("{0},BSVMotor.Test,{1},timeScale={2},targDlyTS={3},frictTS={4},eff={5},curr={6},tgt={7}", 218 MDetailLog("{0},BSVMotor.Test,{1},timeScale={2},targDlyTS={3},eff={4},curr={5},tgt={6}",
239 BSScene.DetailLogZero, UseName, 219 BSScene.DetailLogZero, UseName,
240 TimeScale, TargetValueDecayTimeScale, FrictionTimescale, Efficiency, 220 TimeScale, TargetValueDecayTimeScale, Efficiency,
241 CurrentValue, TargetValue); 221 CurrentValue, TargetValue);
242 222
243 LastError = BSMotor.InfiniteVector; 223 LastError = BSMotor.InfiniteVector;
@@ -248,14 +228,14 @@ public class BSVMotor : BSMotor
248 BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep); 228 BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep);
249 } 229 }
250 MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName); 230 MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName);
251 231
252 232
253 } 233 }
254 234
255 public override string ToString() 235 public override string ToString()
256 { 236 {
257 return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4},frictTS={5}>", 237 return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4}>",
258 UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale, FrictionTimescale); 238 UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale);
259 } 239 }
260} 240}
261 241
@@ -265,7 +245,6 @@ public class BSFMotor : BSMotor
265{ 245{
266 public virtual float TimeScale { get; set; } 246 public virtual float TimeScale { get; set; }
267 public virtual float TargetValueDecayTimeScale { get; set; } 247 public virtual float TargetValueDecayTimeScale { get; set; }
268 public virtual float FrictionTimescale { get; set; }
269 public virtual float Efficiency { get; set; } 248 public virtual float Efficiency { get; set; }
270 249
271 public virtual float ErrorZeroThreshold { get; set; } 250 public virtual float ErrorZeroThreshold { get; set; }
@@ -279,16 +258,15 @@ public class BSFMotor : BSMotor
279 return ErrorIsZero(LastError); 258 return ErrorIsZero(LastError);
280 } 259 }
281 public virtual bool ErrorIsZero(float err) 260 public virtual bool ErrorIsZero(float err)
282 { 261 {
283 return (err >= -ErrorZeroThreshold && err <= ErrorZeroThreshold); 262 return (err >= -ErrorZeroThreshold && err <= ErrorZeroThreshold);
284 } 263 }
285 264
286 public BSFMotor(string useName, float timeScale, float decayTimescale, float friction, float efficiency) 265 public BSFMotor(string useName, float timeScale, float decayTimescale, float efficiency)
287 : base(useName) 266 : base(useName)
288 { 267 {
289 TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite; 268 TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite;
290 Efficiency = 1f; 269 Efficiency = 1f;
291 FrictionTimescale = BSMotor.Infinite;
292 CurrentValue = TargetValue = 0f; 270 CurrentValue = TargetValue = 0f;
293 ErrorZeroThreshold = 0.01f; 271 ErrorZeroThreshold = 0.01f;
294 } 272 }
@@ -331,24 +309,11 @@ public class BSFMotor : BSMotor
331 TargetValue *= (1f - decayFactor); 309 TargetValue *= (1f - decayFactor);
332 } 310 }
333 311
334 // The amount we can correct the error is reduced by the friction
335 float frictionFactor = 0f;
336 if (FrictionTimescale != BSMotor.Infinite)
337 {
338 // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep;
339 // Individual friction components can be 'infinite' so compute each separately.
340 frictionFactor = 1f / FrictionTimescale;
341 frictionFactor *= timeStep;
342 CurrentValue *= (1f - frictionFactor);
343 }
344
345 MDetailLog("{0}, BSFMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}", 312 MDetailLog("{0}, BSFMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}",
346 BSScene.DetailLogZero, UseName, origCurrVal, origTarget, 313 BSScene.DetailLogZero, UseName, origCurrVal, origTarget,
347 timeStep, error, correction); 314 timeStep, error, correction);
348 MDetailLog("{0}, BSFMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},frictTS={4},frictFact={5},tgt={6},curr={7}", 315 MDetailLog("{0}, BSFMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},tgt={4},curr={5}",
349 BSScene.DetailLogZero, UseName, 316 BSScene.DetailLogZero, UseName, TargetValueDecayTimeScale, decayFactor, TargetValue, CurrentValue);
350 TargetValueDecayTimeScale, decayFactor, FrictionTimescale, frictionFactor,
351 TargetValue, CurrentValue);
352 } 317 }
353 else 318 else
354 { 319 {
@@ -390,8 +355,8 @@ public class BSFMotor : BSMotor
390 355
391 public override string ToString() 356 public override string ToString()
392 { 357 {
393 return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4},frictTS={5}>", 358 return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4}>",
394 UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale, FrictionTimescale); 359 UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale);
395 } 360 }
396 361
397} 362}
@@ -410,7 +375,7 @@ public class BSPIDVMotor : BSVMotor
410 // The factors are vectors for the three dimensions. This is the proportional of each 375 // The factors are vectors for the three dimensions. This is the proportional of each
411 // that is applied. This could be multiplied through the actual factors but it 376 // that is applied. This could be multiplied through the actual factors but it
412 // is sometimes easier to manipulate the factors and their mix separately. 377 // is sometimes easier to manipulate the factors and their mix separately.
413 // to 378 // to
414 public Vector3 FactorMix; 379 public Vector3 FactorMix;
415 380
416 // Arbritrary factor range. 381 // Arbritrary factor range.
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
index 385ed9e..aad1108 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
@@ -26,6 +26,7 @@
26 */ 26 */
27using System; 27using System;
28using System.Collections.Generic; 28using System.Collections.Generic;
29using System.Reflection;
29using System.Text; 30using System.Text;
30 31
31using OpenSim.Region.Physics.Manager; 32using OpenSim.Region.Physics.Manager;
@@ -37,7 +38,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
37{ 38{
38public static class BSParam 39public static class BSParam
39{ 40{
40 private static string LogHeader = "[BULLETSIM PARAMETERS]"; 41 private static string LogHeader = "[BULLETSIM PARAMETERS]";
41 42
42 // Tuning notes: 43 // Tuning notes:
43 // From: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=6575 44 // From: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=6575
@@ -51,7 +52,10 @@ public static class BSParam
51 // This is separate/independent from the collision margin. The collision margin increases the object a bit 52 // This is separate/independent from the collision margin. The collision margin increases the object a bit
52 // to improve collision detection performance and accuracy. 53 // to improve collision detection performance and accuracy.
53 // =================== 54 // ===================
54 // From: 55 // From:
56
57 public static bool UseSeparatePhysicsThread { get; private set; }
58 public static float PhysicsTimeStep { get; private set; }
55 59
56 // Level of Detail values kept as float because that's what the Meshmerizer wants 60 // Level of Detail values kept as float because that's what the Meshmerizer wants
57 public static float MeshLOD { get; private set; } 61 public static float MeshLOD { get; private set; }
@@ -86,8 +90,12 @@ public static class BSParam
86 public static bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes 90 public static bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes
87 public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects 91 public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects
88 public static bool ShouldRemoveZeroWidthTriangles { get; private set; } 92 public static bool ShouldRemoveZeroWidthTriangles { get; private set; }
93 public static bool ShouldUseBulletHACD { get; set; }
94 public static bool ShouldUseSingleConvexHullForPrims { get; set; }
95 public static bool ShouldUseGImpactShapeForPrims { get; set; }
96 public static bool ShouldUseAssetHulls { get; set; }
89 97
90 public static float TerrainImplementation { get; private set; } 98 public static float TerrainImplementation { get; set; }
91 public static int TerrainMeshMagnification { get; private set; } 99 public static int TerrainMeshMagnification { get; private set; }
92 public static float TerrainFriction { get; private set; } 100 public static float TerrainFriction { get; private set; }
93 public static float TerrainHitFraction { get; private set; } 101 public static float TerrainHitFraction { get; private set; }
@@ -122,11 +130,16 @@ public static class BSParam
122 public static float AvatarCapsuleWidth { get; private set; } 130 public static float AvatarCapsuleWidth { get; private set; }
123 public static float AvatarCapsuleDepth { get; private set; } 131 public static float AvatarCapsuleDepth { get; private set; }
124 public static float AvatarCapsuleHeight { get; private set; } 132 public static float AvatarCapsuleHeight { get; private set; }
133 public static float AvatarHeightLowFudge { get; private set; }
134 public static float AvatarHeightMidFudge { get; private set; }
135 public static float AvatarHeightHighFudge { get; private set; }
125 public static float AvatarContactProcessingThreshold { get; private set; } 136 public static float AvatarContactProcessingThreshold { get; private set; }
126 public static float AvatarBelowGroundUpCorrectionMeters { get; private set; } 137 public static float AvatarBelowGroundUpCorrectionMeters { get; private set; }
127 public static float AvatarStepHeight { get; private set; } 138 public static float AvatarStepHeight { get; private set; }
128 public static float AvatarStepApproachFactor { get; private set; } 139 public static float AvatarStepApproachFactor { get; private set; }
129 public static float AvatarStepForceFactor { get; private set; } 140 public static float AvatarStepForceFactor { get; private set; }
141 public static float AvatarStepUpCorrectionFactor { get; private set; }
142 public static int AvatarStepSmoothingSteps { get; private set; }
130 143
131 // Vehicle parameters 144 // Vehicle parameters
132 public static float VehicleMaxLinearVelocity { get; private set; } 145 public static float VehicleMaxLinearVelocity { get; private set; }
@@ -138,9 +151,10 @@ public static class BSParam
138 public static float VehicleRestitution { get; private set; } 151 public static float VehicleRestitution { get; private set; }
139 public static Vector3 VehicleLinearFactor { get; private set; } 152 public static Vector3 VehicleLinearFactor { get; private set; }
140 public static Vector3 VehicleAngularFactor { get; private set; } 153 public static Vector3 VehicleAngularFactor { get; private set; }
154 public static Vector3 VehicleInertiaFactor { get; private set; }
141 public static float VehicleGroundGravityFudge { get; private set; } 155 public static float VehicleGroundGravityFudge { get; private set; }
142 public static float VehicleAngularBankingTimescaleFudge { get; private set; } 156 public static float VehicleAngularBankingTimescaleFudge { get; private set; }
143 public static bool VehicleDebuggingEnabled { get; private set; } 157 public static bool VehicleDebuggingEnable { get; private set; }
144 158
145 // Convex Hulls 159 // Convex Hulls
146 public static int CSHullMaxDepthSplit { get; private set; } 160 public static int CSHullMaxDepthSplit { get; private set; }
@@ -149,6 +163,15 @@ public static class BSParam
149 public static float CSHullVolumeConservationThresholdPercent { get; private set; } 163 public static float CSHullVolumeConservationThresholdPercent { get; private set; }
150 public static int CSHullMaxVertices { get; private set; } 164 public static int CSHullMaxVertices { get; private set; }
151 public static float CSHullMaxSkinWidth { get; private set; } 165 public static float CSHullMaxSkinWidth { get; private set; }
166 public static float BHullMaxVerticesPerHull { get; private set; } // 100
167 public static float BHullMinClusters { get; private set; } // 2
168 public static float BHullCompacityWeight { get; private set; } // 0.1
169 public static float BHullVolumeWeight { get; private set; } // 0.0
170 public static float BHullConcavity { get; private set; } // 100
171 public static bool BHullAddExtraDistPoints { get; private set; } // false
172 public static bool BHullAddNeighboursDistPoints { get; private set; } // false
173 public static bool BHullAddFacesPoints { get; private set; } // false
174 public static bool BHullShouldAdjustCollisionMargin { get; private set; } // false
152 175
153 // Linkset implementation parameters 176 // Linkset implementation parameters
154 public static float LinksetImplementation { get; private set; } 177 public static float LinksetImplementation { get; private set; }
@@ -223,16 +246,41 @@ public static class BSParam
223 getter = pGetter; 246 getter = pGetter;
224 objectSet = pObjSetter; 247 objectSet = pObjSetter;
225 } 248 }
226 /* Wish I could simplify using this definition but CLR doesn't store references so closure around delegates of references won't work 249 // Simple parameter variable where property name is the same as the INI file name
227 public ParameterDefn(string pName, string pDesc, T pDefault, ref T loc) 250 // and the value is only a simple get and set.
251 public ParameterDefn(string pName, string pDesc, T pDefault)
228 : base(pName, pDesc) 252 : base(pName, pDesc)
229 { 253 {
230 defaultValue = pDefault; 254 defaultValue = pDefault;
231 setter = (s, v) => { loc = v; }; 255 setter = (s, v) => { SetValueByName(s, name, v); };
232 getter = (s) => { return loc; }; 256 getter = (s) => { return GetValueByName(s, name); };
233 objectSet = null; 257 objectSet = null;
234 } 258 }
235 */ 259 // Use reflection to find the property named 'pName' in BSParam and assign 'val' to same.
260 private void SetValueByName(BSScene s, string pName, T val)
261 {
262 PropertyInfo prop = typeof(BSParam).GetProperty(pName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
263 if (prop == null)
264 {
265 // This should only be output when someone adds a new INI parameter and misspells the name.
266 s.Logger.ErrorFormat("{0} SetValueByName: did not find '{1}'. Verify specified property name is the same as the given INI parameters name.", LogHeader, pName);
267 }
268 else
269 {
270 prop.SetValue(null, val, null);
271 }
272 }
273 // Use reflection to find the property named 'pName' in BSParam and return the value in same.
274 private T GetValueByName(BSScene s, string pName)
275 {
276 PropertyInfo prop = typeof(BSParam).GetProperty(pName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
277 if (prop == null)
278 {
279 // This should only be output when someone adds a new INI parameter and misspells the name.
280 s.Logger.ErrorFormat("{0} GetValueByName: did not find '{1}'. Verify specified property name is the same as the given INI parameter name.", LogHeader, pName);
281 }
282 return (T)prop.GetValue(null, null);
283 }
236 public override void AssignDefault(BSScene s) 284 public override void AssignDefault(BSScene s)
237 { 285 {
238 setter(s, defaultValue); 286 setter(s, defaultValue);
@@ -309,6 +357,11 @@ public static class BSParam
309 // v = value (appropriate type) 357 // v = value (appropriate type)
310 private static ParameterDefnBase[] ParameterDefinitions = 358 private static ParameterDefnBase[] ParameterDefinitions =
311 { 359 {
360 new ParameterDefn<bool>("UseSeparatePhysicsThread", "If 'true', the physics engine runs independent from the simulator heartbeat",
361 false ),
362 new ParameterDefn<float>("PhysicsTimeStep", "If separate thread, seconds to simulate each interval",
363 0.089f ),
364
312 new ParameterDefn<bool>("MeshSculptedPrim", "Whether to create meshes for sculpties", 365 new ParameterDefn<bool>("MeshSculptedPrim", "Whether to create meshes for sculpties",
313 true, 366 true,
314 (s) => { return ShouldMeshSculptedPrim; }, 367 (s) => { return ShouldMeshSculptedPrim; },
@@ -322,18 +375,20 @@ public static class BSParam
322 (s) => { return ShouldUseHullsForPhysicalObjects; }, 375 (s) => { return ShouldUseHullsForPhysicalObjects; },
323 (s,v) => { ShouldUseHullsForPhysicalObjects = v; } ), 376 (s,v) => { ShouldUseHullsForPhysicalObjects = v; } ),
324 new ParameterDefn<bool>("ShouldRemoveZeroWidthTriangles", "If true, remove degenerate triangles from meshes", 377 new ParameterDefn<bool>("ShouldRemoveZeroWidthTriangles", "If true, remove degenerate triangles from meshes",
325 true, 378 true ),
326 (s) => { return ShouldRemoveZeroWidthTriangles; }, 379 new ParameterDefn<bool>("ShouldUseBulletHACD", "If true, use the Bullet version of HACD",
327 (s,v) => { ShouldRemoveZeroWidthTriangles = v; } ), 380 false ),
381 new ParameterDefn<bool>("ShouldUseSingleConvexHullForPrims", "If true, use a single convex hull shape for physical prims",
382 true ),
383 new ParameterDefn<bool>("ShouldUseGImpactShapeForPrims", "If true, use a GImpact shape for prims with cuts and twists",
384 false ),
385 new ParameterDefn<bool>("ShouldUseAssetHulls", "If true, use hull if specified in the mesh asset info",
386 true ),
328 387
329 new ParameterDefn<int>("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions", 388 new ParameterDefn<int>("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions",
330 5, 389 5 ),
331 (s) => { return CrossingFailuresBeforeOutOfBounds; },
332 (s,v) => { CrossingFailuresBeforeOutOfBounds = v; } ),
333 new ParameterDefn<float>("UpdateVelocityChangeThreshold", "Change in updated velocity required before reporting change to simulator", 390 new ParameterDefn<float>("UpdateVelocityChangeThreshold", "Change in updated velocity required before reporting change to simulator",
334 0.1f, 391 0.1f ),
335 (s) => { return UpdateVelocityChangeThreshold; },
336 (s,v) => { UpdateVelocityChangeThreshold = v; } ),
337 392
338 new ParameterDefn<float>("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", 393 new ParameterDefn<float>("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
339 32f, 394 32f,
@@ -400,18 +455,12 @@ public static class BSParam
400 (s,v) => { MaxAddForceMagnitude = v; MaxAddForceMagnitudeSquared = v * v; } ), 455 (s,v) => { MaxAddForceMagnitude = v; MaxAddForceMagnitudeSquared = v * v; } ),
401 // Density is passed around as 100kg/m3. This scales that to 1kg/m3. 456 // Density is passed around as 100kg/m3. This scales that to 1kg/m3.
402 new ParameterDefn<float>("DensityScaleFactor", "Conversion for simulator/viewer density (100kg/m3) to physical density (1kg/m3)", 457 new ParameterDefn<float>("DensityScaleFactor", "Conversion for simulator/viewer density (100kg/m3) to physical density (1kg/m3)",
403 0.01f, 458 0.01f ),
404 (s) => { return DensityScaleFactor; },
405 (s,v) => { DensityScaleFactor = v; } ),
406 459
407 new ParameterDefn<float>("PID_D", "Derivitive factor for motion smoothing", 460 new ParameterDefn<float>("PID_D", "Derivitive factor for motion smoothing",
408 2200f, 461 2200f ),
409 (s) => { return (float)PID_D; },
410 (s,v) => { PID_D = v; } ),
411 new ParameterDefn<float>("PID_P", "Parameteric factor for motion smoothing", 462 new ParameterDefn<float>("PID_P", "Parameteric factor for motion smoothing",
412 900f, 463 900f ),
413 (s) => { return (float)PID_P; },
414 (s,v) => { PID_P = v; } ),
415 464
416 new ParameterDefn<float>("DefaultFriction", "Friction factor used on new objects", 465 new ParameterDefn<float>("DefaultFriction", "Friction factor used on new objects",
417 0.2f, 466 0.2f,
@@ -478,86 +527,56 @@ public static class BSParam
478 (s,o) => { s.PE.SetContactProcessingThreshold(o.PhysBody, ContactProcessingThreshold); } ), 527 (s,o) => { s.PE.SetContactProcessingThreshold(o.PhysBody, ContactProcessingThreshold); } ),
479 528
480 new ParameterDefn<float>("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)", 529 new ParameterDefn<float>("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)",
481 (float)BSTerrainPhys.TerrainImplementation.Mesh, 530 (float)BSTerrainPhys.TerrainImplementation.Mesh ),
482 (s) => { return TerrainImplementation; },
483 (s,v) => { TerrainImplementation = v; } ),
484 new ParameterDefn<int>("TerrainMeshMagnification", "Number of times the 256x256 heightmap is multiplied to create the terrain mesh" , 531 new ParameterDefn<int>("TerrainMeshMagnification", "Number of times the 256x256 heightmap is multiplied to create the terrain mesh" ,
485 2, 532 2 ),
486 (s) => { return TerrainMeshMagnification; },
487 (s,v) => { TerrainMeshMagnification = v; } ),
488 new ParameterDefn<float>("TerrainFriction", "Factor to reduce movement against terrain surface" , 533 new ParameterDefn<float>("TerrainFriction", "Factor to reduce movement against terrain surface" ,
489 0.3f, 534 0.3f ),
490 (s) => { return TerrainFriction; },
491 (s,v) => { TerrainFriction = v; /* TODO: set on real terrain */} ),
492 new ParameterDefn<float>("TerrainHitFraction", "Distance to measure hit collisions" , 535 new ParameterDefn<float>("TerrainHitFraction", "Distance to measure hit collisions" ,
493 0.8f, 536 0.8f ),
494 (s) => { return TerrainHitFraction; },
495 (s,v) => { TerrainHitFraction = v; /* TODO: set on real terrain */ } ),
496 new ParameterDefn<float>("TerrainRestitution", "Bouncyness" , 537 new ParameterDefn<float>("TerrainRestitution", "Bouncyness" ,
497 0f, 538 0f ),
498 (s) => { return TerrainRestitution; },
499 (s,v) => { TerrainRestitution = v; /* TODO: set on real terrain */ } ),
500 new ParameterDefn<float>("TerrainContactProcessingThreshold", "Distance from terrain to stop processing collisions" , 539 new ParameterDefn<float>("TerrainContactProcessingThreshold", "Distance from terrain to stop processing collisions" ,
501 0.0f, 540 0.0f ),
502 (s) => { return TerrainContactProcessingThreshold; },
503 (s,v) => { TerrainContactProcessingThreshold = v; /* TODO: set on real terrain */ } ),
504 new ParameterDefn<float>("TerrainCollisionMargin", "Margin where collision checking starts" , 541 new ParameterDefn<float>("TerrainCollisionMargin", "Margin where collision checking starts" ,
505 0.08f, 542 0.08f ),
506 (s) => { return TerrainCollisionMargin; },
507 (s,v) => { TerrainCollisionMargin = v; /* TODO: set on real terrain */ } ),
508 543
509 new ParameterDefn<float>("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", 544 new ParameterDefn<float>("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
510 0.2f, 545 0.2f ),
511 (s) => { return AvatarFriction; },
512 (s,v) => { AvatarFriction = v; } ),
513 new ParameterDefn<float>("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", 546 new ParameterDefn<float>("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.",
514 0.95f, 547 0.95f ),
515 (s) => { return AvatarStandingFriction; },
516 (s,v) => { AvatarStandingFriction = v; } ),
517 new ParameterDefn<float>("AvatarAlwaysRunFactor", "Speed multiplier if avatar is set to always run", 548 new ParameterDefn<float>("AvatarAlwaysRunFactor", "Speed multiplier if avatar is set to always run",
518 1.3f, 549 1.3f ),
519 (s) => { return AvatarAlwaysRunFactor; },
520 (s,v) => { AvatarAlwaysRunFactor = v; } ),
521 new ParameterDefn<float>("AvatarDensity", "Density of an avatar. Changed on avatar recreation.", 550 new ParameterDefn<float>("AvatarDensity", "Density of an avatar. Changed on avatar recreation.",
522 3.5f, 551 3.5f) ,
523 (s) => { return AvatarDensity; },
524 (s,v) => { AvatarDensity = v; } ),
525 new ParameterDefn<float>("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", 552 new ParameterDefn<float>("AvatarRestitution", "Bouncyness. Changed on avatar recreation.",
526 0f, 553 0f ),
527 (s) => { return AvatarRestitution; },
528 (s,v) => { AvatarRestitution = v; } ),
529 new ParameterDefn<float>("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule", 554 new ParameterDefn<float>("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule",
530 0.6f, 555 0.6f ) ,
531 (s) => { return AvatarCapsuleWidth; },
532 (s,v) => { AvatarCapsuleWidth = v; } ),
533 new ParameterDefn<float>("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule", 556 new ParameterDefn<float>("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule",
534 0.45f, 557 0.45f ),
535 (s) => { return AvatarCapsuleDepth; },
536 (s,v) => { AvatarCapsuleDepth = v; } ),
537 new ParameterDefn<float>("AvatarCapsuleHeight", "Default height of space around avatar", 558 new ParameterDefn<float>("AvatarCapsuleHeight", "Default height of space around avatar",
538 1.5f, 559 1.5f ),
539 (s) => { return AvatarCapsuleHeight; }, 560 new ParameterDefn<float>("AvatarHeightLowFudge", "A fudge factor to make small avatars stand on the ground",
540 (s,v) => { AvatarCapsuleHeight = v; } ), 561 -0.2f ),
562 new ParameterDefn<float>("AvatarHeightMidFudge", "A fudge distance to adjust average sized avatars to be standing on ground",
563 0.1f ),
564 new ParameterDefn<float>("AvatarHeightHighFudge", "A fudge factor to make tall avatars stand on the ground",
565 0.1f ),
541 new ParameterDefn<float>("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", 566 new ParameterDefn<float>("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
542 0.1f, 567 0.1f ),
543 (s) => { return AvatarContactProcessingThreshold; },
544 (s,v) => { AvatarContactProcessingThreshold = v; } ),
545 new ParameterDefn<float>("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground", 568 new ParameterDefn<float>("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground",
546 1.0f, 569 1.0f ),
547 (s) => { return AvatarBelowGroundUpCorrectionMeters; },
548 (s,v) => { AvatarBelowGroundUpCorrectionMeters = v; } ),
549 new ParameterDefn<float>("AvatarStepHeight", "Height of a step obstacle to consider step correction", 570 new ParameterDefn<float>("AvatarStepHeight", "Height of a step obstacle to consider step correction",
550 0.3f, 571 0.6f ) ,
551 (s) => { return AvatarStepHeight; },
552 (s,v) => { AvatarStepHeight = v; } ),
553 new ParameterDefn<float>("AvatarStepApproachFactor", "Factor to control angle of approach to step (0=straight on)", 572 new ParameterDefn<float>("AvatarStepApproachFactor", "Factor to control angle of approach to step (0=straight on)",
554 0.6f, 573 0.6f ),
555 (s) => { return AvatarStepApproachFactor; },
556 (s,v) => { AvatarStepApproachFactor = v; } ),
557 new ParameterDefn<float>("AvatarStepForceFactor", "Controls the amount of force up applied to step up onto a step", 574 new ParameterDefn<float>("AvatarStepForceFactor", "Controls the amount of force up applied to step up onto a step",
558 2.0f, 575 1.0f ),
559 (s) => { return AvatarStepForceFactor; }, 576 new ParameterDefn<float>("AvatarStepUpCorrectionFactor", "Multiplied by height of step collision to create up movement at step",
560 (s,v) => { AvatarStepForceFactor = v; } ), 577 1.0f ),
578 new ParameterDefn<int>("AvatarStepSmoothingSteps", "Number of frames after a step collision that we continue walking up stairs",
579 2 ),
561 580
562 new ParameterDefn<float>("VehicleMaxLinearVelocity", "Maximum velocity magnitude that can be assigned to a vehicle", 581 new ParameterDefn<float>("VehicleMaxLinearVelocity", "Maximum velocity magnitude that can be assigned to a vehicle",
563 1000.0f, 582 1000.0f,
@@ -568,37 +587,23 @@ public static class BSParam
568 (s) => { return (float)VehicleMaxAngularVelocity; }, 587 (s) => { return (float)VehicleMaxAngularVelocity; },
569 (s,v) => { VehicleMaxAngularVelocity = v; VehicleMaxAngularVelocitySq = v * v; } ), 588 (s,v) => { VehicleMaxAngularVelocity = v; VehicleMaxAngularVelocitySq = v * v; } ),
570 new ParameterDefn<float>("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)", 589 new ParameterDefn<float>("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)",
571 0.0f, 590 0.0f ),
572 (s) => { return VehicleAngularDamping; },
573 (s,v) => { VehicleAngularDamping = v; } ),
574 new ParameterDefn<Vector3>("VehicleLinearFactor", "Fraction of physical linear changes applied to vehicle (<0,0,0> to <1,1,1>)", 591 new ParameterDefn<Vector3>("VehicleLinearFactor", "Fraction of physical linear changes applied to vehicle (<0,0,0> to <1,1,1>)",
575 new Vector3(1f, 1f, 1f), 592 new Vector3(1f, 1f, 1f) ),
576 (s) => { return VehicleLinearFactor; },
577 (s,v) => { VehicleLinearFactor = v; } ),
578 new ParameterDefn<Vector3>("VehicleAngularFactor", "Fraction of physical angular changes applied to vehicle (<0,0,0> to <1,1,1>)", 593 new ParameterDefn<Vector3>("VehicleAngularFactor", "Fraction of physical angular changes applied to vehicle (<0,0,0> to <1,1,1>)",
579 new Vector3(1f, 1f, 1f), 594 new Vector3(1f, 1f, 1f) ),
580 (s) => { return VehicleAngularFactor; }, 595 new ParameterDefn<Vector3>("VehicleInertiaFactor", "Fraction of physical inertia applied (<0,0,0> to <1,1,1>)",
581 (s,v) => { VehicleAngularFactor = v; } ), 596 new Vector3(1f, 1f, 1f) ),
582 new ParameterDefn<float>("VehicleFriction", "Friction of vehicle on the ground (0.0 - 1.0)", 597 new ParameterDefn<float>("VehicleFriction", "Friction of vehicle on the ground (0.0 - 1.0)",
583 0.0f, 598 0.0f ),
584 (s) => { return VehicleFriction; },
585 (s,v) => { VehicleFriction = v; } ),
586 new ParameterDefn<float>("VehicleRestitution", "Bouncyness factor for vehicles (0.0 - 1.0)", 599 new ParameterDefn<float>("VehicleRestitution", "Bouncyness factor for vehicles (0.0 - 1.0)",
587 0.0f, 600 0.0f ),
588 (s) => { return VehicleRestitution; },
589 (s,v) => { VehicleRestitution = v; } ),
590 new ParameterDefn<float>("VehicleGroundGravityFudge", "Factor to multiply gravity if a ground vehicle is probably on the ground (0.0 - 1.0)", 601 new ParameterDefn<float>("VehicleGroundGravityFudge", "Factor to multiply gravity if a ground vehicle is probably on the ground (0.0 - 1.0)",
591 0.2f, 602 0.2f ),
592 (s) => { return VehicleGroundGravityFudge; },
593 (s,v) => { VehicleGroundGravityFudge = v; } ),
594 new ParameterDefn<float>("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.", 603 new ParameterDefn<float>("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.",
595 60.0f, 604 60.0f ),
596 (s) => { return VehicleAngularBankingTimescaleFudge; },
597 (s,v) => { VehicleAngularBankingTimescaleFudge = v; } ),
598 new ParameterDefn<bool>("VehicleDebuggingEnable", "Turn on/off vehicle debugging", 605 new ParameterDefn<bool>("VehicleDebuggingEnable", "Turn on/off vehicle debugging",
599 false, 606 false ),
600 (s) => { return VehicleDebuggingEnabled; },
601 (s,v) => { VehicleDebuggingEnabled = v; } ),
602 607
603 new ParameterDefn<float>("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", 608 new ParameterDefn<float>("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
604 0f, 609 0f,
@@ -611,7 +616,7 @@ public static class BSParam
611 new ParameterDefn<bool>("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count", 616 new ParameterDefn<bool>("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count",
612 false, 617 false,
613 (s) => { return ShouldDisableContactPoolDynamicAllocation; }, 618 (s) => { return ShouldDisableContactPoolDynamicAllocation; },
614 (s,v) => { ShouldDisableContactPoolDynamicAllocation = v; 619 (s,v) => { ShouldDisableContactPoolDynamicAllocation = v;
615 s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = NumericBool(v); } ), 620 s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = NumericBool(v); } ),
616 new ParameterDefn<bool>("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step", 621 new ParameterDefn<bool>("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step",
617 false, 622 false,
@@ -643,62 +648,53 @@ public static class BSParam
643 (s,v) => { GlobalContactBreakingThreshold = v; s.UnmanagedParams[0].globalContactBreakingThreshold = v; } ), 648 (s,v) => { GlobalContactBreakingThreshold = v; s.UnmanagedParams[0].globalContactBreakingThreshold = v; } ),
644 649
645 new ParameterDefn<int>("CSHullMaxDepthSplit", "CS impl: max depth to split for hull. 1-10 but > 7 is iffy", 650 new ParameterDefn<int>("CSHullMaxDepthSplit", "CS impl: max depth to split for hull. 1-10 but > 7 is iffy",
646 7, 651 7 ),
647 (s) => { return CSHullMaxDepthSplit; },
648 (s,v) => { CSHullMaxDepthSplit = v; } ),
649 new ParameterDefn<int>("CSHullMaxDepthSplitForSimpleShapes", "CS impl: max depth setting for simple prim shapes", 652 new ParameterDefn<int>("CSHullMaxDepthSplitForSimpleShapes", "CS impl: max depth setting for simple prim shapes",
650 2, 653 2 ),
651 (s) => { return CSHullMaxDepthSplitForSimpleShapes; },
652 (s,v) => { CSHullMaxDepthSplitForSimpleShapes = v; } ),
653 new ParameterDefn<float>("CSHullConcavityThresholdPercent", "CS impl: concavity threshold percent (0-20)", 654 new ParameterDefn<float>("CSHullConcavityThresholdPercent", "CS impl: concavity threshold percent (0-20)",
654 5f, 655 5f ),
655 (s) => { return CSHullConcavityThresholdPercent; },
656 (s,v) => { CSHullConcavityThresholdPercent = v; } ),
657 new ParameterDefn<float>("CSHullVolumeConservationThresholdPercent", "percent volume conservation to collapse hulls (0-30)", 656 new ParameterDefn<float>("CSHullVolumeConservationThresholdPercent", "percent volume conservation to collapse hulls (0-30)",
658 5f, 657 5f ),
659 (s) => { return CSHullVolumeConservationThresholdPercent; },
660 (s,v) => { CSHullVolumeConservationThresholdPercent = v; } ),
661 new ParameterDefn<int>("CSHullMaxVertices", "CS impl: maximum number of vertices in output hulls. Keep < 50.", 658 new ParameterDefn<int>("CSHullMaxVertices", "CS impl: maximum number of vertices in output hulls. Keep < 50.",
662 32, 659 32 ),
663 (s) => { return CSHullMaxVertices; },
664 (s,v) => { CSHullMaxVertices = v; } ),
665 new ParameterDefn<float>("CSHullMaxSkinWidth", "CS impl: skin width to apply to output hulls.", 660 new ParameterDefn<float>("CSHullMaxSkinWidth", "CS impl: skin width to apply to output hulls.",
666 0, 661 0f ),
667 (s) => { return CSHullMaxSkinWidth; }, 662
668 (s,v) => { CSHullMaxSkinWidth = v; } ), 663 new ParameterDefn<float>("BHullMaxVerticesPerHull", "Bullet impl: max number of vertices per created hull",
664 100f ),
665 new ParameterDefn<float>("BHullMinClusters", "Bullet impl: minimum number of hulls to create per mesh",
666 2f ),
667 new ParameterDefn<float>("BHullCompacityWeight", "Bullet impl: weight factor for how compact to make hulls",
668 0.1f ),
669 new ParameterDefn<float>("BHullVolumeWeight", "Bullet impl: weight factor for volume in created hull",
670 0f ),
671 new ParameterDefn<float>("BHullConcavity", "Bullet impl: weight factor for how convex a created hull can be",
672 100f ),
673 new ParameterDefn<bool>("BHullAddExtraDistPoints", "Bullet impl: whether to add extra vertices for long distance vectors",
674 false ),
675 new ParameterDefn<bool>("BHullAddNeighboursDistPoints", "Bullet impl: whether to add extra vertices between neighbor hulls",
676 false ),
677 new ParameterDefn<bool>("BHullAddFacesPoints", "Bullet impl: whether to add extra vertices to break up hull faces",
678 false ),
679 new ParameterDefn<bool>("BHullShouldAdjustCollisionMargin", "Bullet impl: whether to shrink resulting hulls to account for collision margin",
680 false ),
669 681
670 new ParameterDefn<float>("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", 682 new ParameterDefn<float>("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)",
671 (float)BSLinkset.LinksetImplementation.Compound, 683 (float)BSLinkset.LinksetImplementation.Compound ),
672 (s) => { return LinksetImplementation; },
673 (s,v) => { LinksetImplementation = v; } ),
674 new ParameterDefn<bool>("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", 684 new ParameterDefn<bool>("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
675 false, 685 false ),
676 (s) => { return LinkConstraintUseFrameOffset; },
677 (s,v) => { LinkConstraintUseFrameOffset = v; } ),
678 new ParameterDefn<bool>("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints", 686 new ParameterDefn<bool>("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints",
679 true, 687 true ),
680 (s) => { return LinkConstraintEnableTransMotor; },
681 (s,v) => { LinkConstraintEnableTransMotor = v; } ),
682 new ParameterDefn<float>("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints", 688 new ParameterDefn<float>("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints",
683 5.0f, 689 5.0f ),
684 (s) => { return LinkConstraintTransMotorMaxVel; },
685 (s,v) => { LinkConstraintTransMotorMaxVel = v; } ),
686 new ParameterDefn<float>("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints", 690 new ParameterDefn<float>("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints",
687 0.1f, 691 0.1f ),
688 (s) => { return LinkConstraintTransMotorMaxForce; },
689 (s,v) => { LinkConstraintTransMotorMaxForce = v; } ),
690 new ParameterDefn<float>("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1", 692 new ParameterDefn<float>("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1",
691 0.1f, 693 0.1f ),
692 (s) => { return LinkConstraintCFM; },
693 (s,v) => { LinkConstraintCFM = v; } ),
694 new ParameterDefn<float>("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", 694 new ParameterDefn<float>("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2",
695 0.1f, 695 0.1f ),
696 (s) => { return LinkConstraintERP; },
697 (s,v) => { LinkConstraintERP = v; } ),
698 new ParameterDefn<float>("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)", 696 new ParameterDefn<float>("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)",
699 40, 697 40 ),
700 (s) => { return LinkConstraintSolverIterations; },
701 (s,v) => { LinkConstraintSolverIterations = v; } ),
702 698
703 new ParameterDefn<int>("PhysicsMetricFrames", "Frames between outputting detailed phys metrics. (0 is off)", 699 new ParameterDefn<int>("PhysicsMetricFrames", "Frames between outputting detailed phys metrics. (0 is off)",
704 0, 700 0,
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
index 6bb88c7..cca887a 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
@@ -38,12 +38,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
38 * Class to wrap all objects. 38 * Class to wrap all objects.
39 * The rest of BulletSim doesn't need to keep checking for avatars or prims 39 * The rest of BulletSim doesn't need to keep checking for avatars or prims
40 * unless the difference is significant. 40 * unless the difference is significant.
41 * 41 *
42 * Variables in the physicsl objects are in three forms: 42 * Variables in the physicsl objects are in three forms:
43 * VariableName: used by the simulator and performs taint operations, etc 43 * VariableName: used by the simulator and performs taint operations, etc
44 * RawVariableName: direct reference to the BulletSim storage for the variable value 44 * RawVariableName: direct reference to the BulletSim storage for the variable value
45 * ForceVariableName: direct reference (store and fetch) to the value in the physics engine. 45 * ForceVariableName: direct reference (store and fetch) to the value in the physics engine.
46 * The last two (and certainly the last one) should be referenced only in taint-time. 46 * The last one should only be referenced in taint-time.
47 */ 47 */
48 48
49/* 49/*
@@ -52,7 +52,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
52 * SOP.ApplyImpulse SOP.ApplyAngularImpulse SOP.SetAngularImpulse SOP.SetForce 52 * SOP.ApplyImpulse SOP.ApplyAngularImpulse SOP.SetAngularImpulse SOP.SetForce
53 * SOG.ApplyImpulse SOG.ApplyAngularImpulse SOG.SetAngularImpulse 53 * SOG.ApplyImpulse SOG.ApplyAngularImpulse SOG.SetAngularImpulse
54 * PA.AddForce PA.AddAngularForce PA.Torque = v PA.Force = v 54 * PA.AddForce PA.AddAngularForce PA.Torque = v PA.Force = v
55 * BS.ApplyCentralForce BS.ApplyTorque 55 * BS.ApplyCentralForce BS.ApplyTorque
56 */ 56 */
57 57
58// Flags used to denote which properties updates when making UpdateProperties calls to linksets, etc. 58// Flags used to denote which properties updates when making UpdateProperties calls to linksets, etc.
@@ -72,19 +72,23 @@ public abstract class BSPhysObject : PhysicsActor
72 } 72 }
73 protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName) 73 protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName)
74 { 74 {
75 PhysicsScene = parentScene; 75 PhysScene = parentScene;
76 LocalID = localID; 76 LocalID = localID;
77 PhysObjectName = name; 77 PhysObjectName = name;
78 Name = name; // PhysicsActor also has the name of the object. Someday consolidate. 78 Name = name; // PhysicsActor also has the name of the object. Someday consolidate.
79 TypeName = typeName; 79 TypeName = typeName;
80 80
81 // The collection of things that push me around
82 PhysicalActors = new BSActorCollection(PhysScene);
83
81 // Initialize variables kept in base. 84 // Initialize variables kept in base.
82 GravModifier = 1.0f; 85 GravModifier = 1.0f;
83 Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity); 86 Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity);
87 HoverActive = false;
84 88
85 // We don't have any physical representation yet. 89 // We don't have any physical representation yet.
86 PhysBody = new BulletBody(localID); 90 PhysBody = new BulletBody(localID);
87 PhysShape = new BulletShape(); 91 PhysShape = new BSShapeNull();
88 92
89 PrimAssetState = PrimAssetCondition.Unknown; 93 PrimAssetState = PrimAssetCondition.Unknown;
90 94
@@ -92,7 +96,10 @@ public abstract class BSPhysObject : PhysicsActor
92 SetMaterial((int)MaterialAttributes.Material.Wood); 96 SetMaterial((int)MaterialAttributes.Material.Wood);
93 97
94 CollisionCollection = new CollisionEventUpdate(); 98 CollisionCollection = new CollisionEventUpdate();
95 CollisionsLastTick = CollisionCollection; 99 CollisionsLastReported = CollisionCollection;
100 CollisionsLastTick = new CollisionEventUpdate();
101 CollisionsLastTickStep = -1;
102
96 SubscribedEventsMs = 0; 103 SubscribedEventsMs = 0;
97 CollidingStep = 0; 104 CollidingStep = 0;
98 CollidingGroundStep = 0; 105 CollidingGroundStep = 0;
@@ -101,17 +108,21 @@ public abstract class BSPhysObject : PhysicsActor
101 CollisionScore = 0; 108 CollisionScore = 0;
102 109
103 // All axis free. 110 // All axis free.
104 LockedAxis = LockedAxisFree; 111 LockedLinearAxis = LockedAxisFree;
112 LockedAngularAxis = LockedAxisFree;
105 } 113 }
106 114
107 // Tell the object to clean up. 115 // Tell the object to clean up.
108 public virtual void Destroy() 116 public virtual void Destroy()
109 { 117 {
110 UnRegisterAllPreStepActions(); 118 PhysicalActors.Enable(false);
111 UnRegisterAllPostStepActions(); 119 PhysScene.TaintedObject("BSPhysObject.Destroy", delegate()
120 {
121 PhysicalActors.Dispose();
122 });
112 } 123 }
113 124
114 public BSScene PhysicsScene { get; protected set; } 125 public BSScene PhysScene { get; protected set; }
115 // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor 126 // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor
116 public string PhysObjectName { get; protected set; } 127 public string PhysObjectName { get; protected set; }
117 public string TypeName { get; protected set; } 128 public string TypeName { get; protected set; }
@@ -131,7 +142,7 @@ public abstract class BSPhysObject : PhysicsActor
131 // Reference to the physical body (btCollisionObject) of this object 142 // Reference to the physical body (btCollisionObject) of this object
132 public BulletBody PhysBody; 143 public BulletBody PhysBody;
133 // Reference to the physical shape (btCollisionShape) of this object 144 // Reference to the physical shape (btCollisionShape) of this object
134 public BulletShape PhysShape; 145 public BSShape PhysShape;
135 146
136 // The physical representation of the prim might require an asset fetch. 147 // The physical representation of the prim might require an asset fetch.
137 // The asset state is first 'Unknown' then 'Waiting' then either 'Failed' or 'Fetched'. 148 // The asset state is first 'Unknown' then 'Waiting' then either 'Failed' or 'Fetched'.
@@ -144,13 +155,6 @@ public abstract class BSPhysObject : PhysicsActor
144 // The objects base shape information. Null if not a prim type shape. 155 // The objects base shape information. Null if not a prim type shape.
145 public PrimitiveBaseShape BaseShape { get; protected set; } 156 public PrimitiveBaseShape BaseShape { get; protected set; }
146 157
147 // Some types of objects have preferred physical representations.
148 // Returns SHAPE_UNKNOWN if there is no preference.
149 public virtual BSPhysicsShapeType PreferredPhysicalShape
150 {
151 get { return BSPhysicsShapeType.SHAPE_UNKNOWN; }
152 }
153
154 // When the physical properties are updated, an EntityProperty holds the update values. 158 // When the physical properties are updated, an EntityProperty holds the update values.
155 // Keep the current and last EntityProperties to enable computation of differences 159 // Keep the current and last EntityProperties to enable computation of differences
156 // between the current update and the previous values. 160 // between the current update and the previous values.
@@ -180,7 +184,7 @@ public abstract class BSPhysObject : PhysicsActor
180 Friction = matAttrib.friction; 184 Friction = matAttrib.friction;
181 Restitution = matAttrib.restitution; 185 Restitution = matAttrib.restitution;
182 Density = matAttrib.density / BSParam.DensityScaleFactor; 186 Density = matAttrib.density / BSParam.DensityScaleFactor;
183 DetailLog("{0},{1}.SetMaterial,Mat={2},frict={3},rest={4},den={5}", LocalID, TypeName, Material, Friction, Restitution, Density); 187 // DetailLog("{0},{1}.SetMaterial,Mat={2},frict={3},rest={4},den={5}", LocalID, TypeName, Material, Friction, Restitution, Density);
184 } 188 }
185 189
186 // Stop all physical motion. 190 // Stop all physical motion.
@@ -196,15 +200,48 @@ public abstract class BSPhysObject : PhysicsActor
196 public abstract OMV.Quaternion RawOrientation { get; set; } 200 public abstract OMV.Quaternion RawOrientation { get; set; }
197 public abstract OMV.Quaternion ForceOrientation { get; set; } 201 public abstract OMV.Quaternion ForceOrientation { get; set; }
198 202
199 public abstract OMV.Vector3 RawVelocity { get; set; } 203 public OMV.Vector3 RawVelocity { get; set; }
200 public abstract OMV.Vector3 ForceVelocity { get; set; } 204 public abstract OMV.Vector3 ForceVelocity { get; set; }
201 205
206 public OMV.Vector3 RawForce { get; set; }
207 public OMV.Vector3 RawTorque { get; set; }
208 public override void AddAngularForce(OMV.Vector3 force, bool pushforce)
209 {
210 AddAngularForce(force, pushforce, false);
211 }
212 public abstract void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime);
213
202 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } 214 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
203 215
204 public abstract float ForceBuoyancy { get; set; } 216 public abstract float ForceBuoyancy { get; set; }
205 217
206 public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; } 218 public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; }
207 219
220 public override bool PIDActive { set { MoveToTargetActive = value; } }
221 public override OMV.Vector3 PIDTarget { set { MoveToTargetTarget = value; } }
222 public override float PIDTau { set { MoveToTargetTau = value; } }
223
224 public bool MoveToTargetActive { get; set; }
225 public OMV.Vector3 MoveToTargetTarget { get; set; }
226 public float MoveToTargetTau { get; set; }
227
228 // Used for llSetHoverHeight and maybe vehicle height. Hover Height will override MoveTo target's Z
229 public override bool PIDHoverActive { set { HoverActive = value; } }
230 public override float PIDHoverHeight { set { HoverHeight = value; } }
231 public override PIDHoverType PIDHoverType { set { HoverType = value; } }
232 public override float PIDHoverTau { set { HoverTau = value; } }
233
234 public bool HoverActive { get; set; }
235 public float HoverHeight { get; set; }
236 public PIDHoverType HoverType { get; set; }
237 public float HoverTau { get; set; }
238
239 // For RotLookAt
240 public override OMV.Quaternion APIDTarget { set { return; } }
241 public override bool APIDActive { set { return; } }
242 public override float APIDStrength { set { return; } }
243 public override float APIDDamping { set { return; } }
244
208 // The current velocity forward 245 // The current velocity forward
209 public virtual float ForwardSpeed 246 public virtual float ForwardSpeed
210 { 247 {
@@ -226,10 +263,58 @@ public abstract class BSPhysObject : PhysicsActor
226 263
227 // The user can optionally set the center of mass. The user's setting will override any 264 // The user can optionally set the center of mass. The user's setting will override any
228 // computed center-of-mass (like in linksets). 265 // computed center-of-mass (like in linksets).
229 public OMV.Vector3? UserSetCenterOfMass { get; set; } 266 // Note this is a displacement from the root's coordinates. Zero means use the root prim as center-of-mass.
267 public OMV.Vector3? UserSetCenterOfMassDisplacement { get; set; }
268
269 public OMV.Vector3 LockedLinearAxis { get; set; } // zero means locked. one means free.
270 public OMV.Vector3 LockedAngularAxis { get; set; } // zero means locked. one means free.
271 public const float FreeAxis = 1f;
272 public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(FreeAxis, FreeAxis, FreeAxis); // All axis are free
273
274 // Enable physical actions. Bullet will keep sleeping non-moving physical objects so
275 // they need waking up when parameters are changed.
276 // Called in taint-time!!
277 public void ActivateIfPhysical(bool forceIt)
278 {
279 if (IsPhysical && PhysBody.HasPhysicalBody)
280 PhysScene.PE.Activate(PhysBody, forceIt);
281 }
230 282
231 public OMV.Vector3 LockedAxis { get; set; } // zero means locked. one means free. 283 // 'actors' act on the physical object to change or constrain its motion. These can range from
232 public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(1f, 1f, 1f); // All axis are free 284 // hovering to complex vehicle motion.
285 // May be called at non-taint time as this just adds the actor to the action list and the real
286 // work is done during the simulation step.
287 // Note that, if the actor is already in the list and we are disabling same, the actor is just left
288 // in the list disabled.
289 public delegate BSActor CreateActor();
290 public void EnableActor(bool enableActor, string actorName, CreateActor creator)
291 {
292 lock (PhysicalActors)
293 {
294 BSActor theActor;
295 if (PhysicalActors.TryGetActor(actorName, out theActor))
296 {
297 // The actor already exists so just turn it on or off
298 DetailLog("{0},BSPhysObject.EnableActor,enablingExistingActor,name={1},enable={2}", LocalID, actorName, enableActor);
299 theActor.Enabled = enableActor;
300 }
301 else
302 {
303 // The actor does not exist. If it should, create it.
304 if (enableActor)
305 {
306 DetailLog("{0},BSPhysObject.EnableActor,creatingActor,name={1}", LocalID, actorName);
307 theActor = creator();
308 PhysicalActors.Add(actorName, theActor);
309 theActor.Enabled = true;
310 }
311 else
312 {
313 DetailLog("{0},BSPhysObject.EnableActor,notCreatingActorSinceNotEnabled,name={1}", LocalID, actorName);
314 }
315 }
316 }
317 }
233 318
234 #region Collisions 319 #region Collisions
235 320
@@ -247,45 +332,50 @@ public abstract class BSPhysObject : PhysicsActor
247 protected CollisionFlags CurrentCollisionFlags { get; set; } 332 protected CollisionFlags CurrentCollisionFlags { get; set; }
248 // On a collision, check the collider and remember if the last collider was moving 333 // On a collision, check the collider and remember if the last collider was moving
249 // Used to modify the standing of avatars (avatars on stationary things stand still) 334 // Used to modify the standing of avatars (avatars on stationary things stand still)
250 protected bool ColliderIsMoving; 335 public bool ColliderIsMoving;
336 // Used by BSCharacter to manage standing (and not slipping)
337 public bool IsStationary;
251 338
252 // Count of collisions for this object 339 // Count of collisions for this object
253 protected long CollisionAccumulation { get; set; } 340 protected long CollisionAccumulation { get; set; }
254 341
255 public override bool IsColliding { 342 public override bool IsColliding {
256 get { return (CollidingStep == PhysicsScene.SimulationStep); } 343 get { return (CollidingStep == PhysScene.SimulationStep); }
257 set { 344 set {
258 if (value) 345 if (value)
259 CollidingStep = PhysicsScene.SimulationStep; 346 CollidingStep = PhysScene.SimulationStep;
260 else 347 else
261 CollidingStep = 0; 348 CollidingStep = 0;
262 } 349 }
263 } 350 }
264 public override bool CollidingGround { 351 public override bool CollidingGround {
265 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); } 352 get { return (CollidingGroundStep == PhysScene.SimulationStep); }
266 set 353 set
267 { 354 {
268 if (value) 355 if (value)
269 CollidingGroundStep = PhysicsScene.SimulationStep; 356 CollidingGroundStep = PhysScene.SimulationStep;
270 else 357 else
271 CollidingGroundStep = 0; 358 CollidingGroundStep = 0;
272 } 359 }
273 } 360 }
274 public override bool CollidingObj { 361 public override bool CollidingObj {
275 get { return (CollidingObjectStep == PhysicsScene.SimulationStep); } 362 get { return (CollidingObjectStep == PhysScene.SimulationStep); }
276 set { 363 set {
277 if (value) 364 if (value)
278 CollidingObjectStep = PhysicsScene.SimulationStep; 365 CollidingObjectStep = PhysScene.SimulationStep;
279 else 366 else
280 CollidingObjectStep = 0; 367 CollidingObjectStep = 0;
281 } 368 }
282 } 369 }
283 370
284 // The collisions that have been collected this tick 371 // The collisions that have been collected for the next collision reporting (throttled by subscription)
285 protected CollisionEventUpdate CollisionCollection; 372 protected CollisionEventUpdate CollisionCollection;
286 // Remember collisions from last tick for fancy collision based actions 373 // This is the collision collection last reported to the Simulator.
374 public CollisionEventUpdate CollisionsLastReported;
375 // Remember the collisions recorded in the last tick for fancy collision checking
287 // (like a BSCharacter walking up stairs). 376 // (like a BSCharacter walking up stairs).
288 protected CollisionEventUpdate CollisionsLastTick; 377 public CollisionEventUpdate CollisionsLastTick;
378 private long CollisionsLastTickStep = -1;
289 379
290 // The simulation step is telling this object about a collision. 380 // The simulation step is telling this object about a collision.
291 // Return 'true' if a collision was processed and should be sent up. 381 // Return 'true' if a collision was processed and should be sent up.
@@ -297,14 +387,14 @@ public abstract class BSPhysObject : PhysicsActor
297 bool ret = false; 387 bool ret = false;
298 388
299 // The following lines make IsColliding(), CollidingGround() and CollidingObj work 389 // The following lines make IsColliding(), CollidingGround() and CollidingObj work
300 CollidingStep = PhysicsScene.SimulationStep; 390 CollidingStep = PhysScene.SimulationStep;
301 if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID) 391 if (collidingWith <= PhysScene.TerrainManager.HighestTerrainID)
302 { 392 {
303 CollidingGroundStep = PhysicsScene.SimulationStep; 393 CollidingGroundStep = PhysScene.SimulationStep;
304 } 394 }
305 else 395 else
306 { 396 {
307 CollidingObjectStep = PhysicsScene.SimulationStep; 397 CollidingObjectStep = PhysScene.SimulationStep;
308 } 398 }
309 399
310 CollisionAccumulation++; 400 CollisionAccumulation++;
@@ -312,6 +402,15 @@ public abstract class BSPhysObject : PhysicsActor
312 // For movement tests, remember if we are colliding with an object that is moving. 402 // For movement tests, remember if we are colliding with an object that is moving.
313 ColliderIsMoving = collidee != null ? (collidee.RawVelocity != OMV.Vector3.Zero) : false; 403 ColliderIsMoving = collidee != null ? (collidee.RawVelocity != OMV.Vector3.Zero) : false;
314 404
405 // Make a collection of the collisions that happened the last simulation tick.
406 // This is different than the collection created for sending up to the simulator as it is cleared every tick.
407 if (CollisionsLastTickStep != PhysScene.SimulationStep)
408 {
409 CollisionsLastTick = new CollisionEventUpdate();
410 CollisionsLastTickStep = PhysScene.SimulationStep;
411 }
412 CollisionsLastTick.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
413
315 // If someone has subscribed for collision events log the collision so it will be reported up 414 // If someone has subscribed for collision events log the collision so it will be reported up
316 if (SubscribedEvents()) { 415 if (SubscribedEvents()) {
317 CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); 416 CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
@@ -332,12 +431,12 @@ public abstract class BSPhysObject : PhysicsActor
332 bool ret = true; 431 bool ret = true;
333 432
334 // If the 'no collision' call, force it to happen right now so quick collision_end 433 // If the 'no collision' call, force it to happen right now so quick collision_end
335 bool force = (CollisionCollection.Count == 0 && CollisionsLastTick.Count != 0); 434 bool force = (CollisionCollection.Count == 0 && CollisionsLastReported.Count != 0);
336 435
337 // throttle the collisions to the number of milliseconds specified in the subscription 436 // throttle the collisions to the number of milliseconds specified in the subscription
338 if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime)) 437 if (force || (PhysScene.SimulationNowTime >= NextCollisionOkTime))
339 { 438 {
340 NextCollisionOkTime = PhysicsScene.SimulationNowTime + SubscribedEventsMs; 439 NextCollisionOkTime = PhysScene.SimulationNowTime + SubscribedEventsMs;
341 440
342 // We are called if we previously had collisions. If there are no collisions 441 // We are called if we previously had collisions. If there are no collisions
343 // this time, send up one last empty event so OpenSim can sense collision end. 442 // this time, send up one last empty event so OpenSim can sense collision end.
@@ -351,11 +450,11 @@ public abstract class BSPhysObject : PhysicsActor
351 base.SendCollisionUpdate(CollisionCollection); 450 base.SendCollisionUpdate(CollisionCollection);
352 451
353 // Remember the collisions from this tick for some collision specific processing. 452 // Remember the collisions from this tick for some collision specific processing.
354 CollisionsLastTick = CollisionCollection; 453 CollisionsLastReported = CollisionCollection;
355 454
356 // The CollisionCollection instance is passed around in the simulator. 455 // The CollisionCollection instance is passed around in the simulator.
357 // Make sure we don't have a handle to that one and that a new one is used for next time. 456 // Make sure we don't have a handle to that one and that a new one is used for next time.
358 // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here, 457 // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here,
359 // a race condition is created for the other users of this instance. 458 // a race condition is created for the other users of this instance.
360 CollisionCollection = new CollisionEventUpdate(); 459 CollisionCollection = new CollisionEventUpdate();
361 } 460 }
@@ -372,10 +471,10 @@ public abstract class BSPhysObject : PhysicsActor
372 // make sure first collision happens 471 // make sure first collision happens
373 NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs); 472 NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs);
374 473
375 PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate() 474 PhysScene.TaintedObject(TypeName+".SubscribeEvents", delegate()
376 { 475 {
377 if (PhysBody.HasPhysicalBody) 476 if (PhysBody.HasPhysicalBody)
378 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 477 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
379 }); 478 });
380 } 479 }
381 else 480 else
@@ -387,11 +486,11 @@ public abstract class BSPhysObject : PhysicsActor
387 public override void UnSubscribeEvents() { 486 public override void UnSubscribeEvents() {
388 // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName); 487 // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName);
389 SubscribedEventsMs = 0; 488 SubscribedEventsMs = 0;
390 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() 489 PhysScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate()
391 { 490 {
392 // Make sure there is a body there because sometimes destruction happens in an un-ideal order. 491 // Make sure there is a body there because sometimes destruction happens in an un-ideal order.
393 if (PhysBody.HasPhysicalBody) 492 if (PhysBody.HasPhysicalBody)
394 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 493 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
395 }); 494 });
396 } 495 }
397 // Return 'true' if the simulator wants collision events 496 // Return 'true' if the simulator wants collision events
@@ -405,7 +504,7 @@ public abstract class BSPhysObject : PhysicsActor
405 { 504 {
406 // Scale the collision count by the time since the last collision. 505 // Scale the collision count by the time since the last collision.
407 // The "+1" prevents dividing by zero. 506 // The "+1" prevents dividing by zero.
408 long timeAgo = PhysicsScene.SimulationStep - CollidingStep + 1; 507 long timeAgo = PhysScene.SimulationStep - CollidingStep + 1;
409 CollisionScore = CollisionAccumulation / timeAgo; 508 CollisionScore = CollisionAccumulation / timeAgo;
410 } 509 }
411 public override float CollisionScore { get; set; } 510 public override float CollisionScore { get; set; }
@@ -413,103 +512,8 @@ public abstract class BSPhysObject : PhysicsActor
413 #endregion // Collisions 512 #endregion // Collisions
414 513
415 #region Per Simulation Step actions 514 #region Per Simulation Step actions
416 // There are some actions that must be performed for a physical object before each simulation step.
417 // These actions are optional so, rather than scanning all the physical objects and asking them
418 // if they have anything to do, a physical object registers for an event call before the step is performed.
419 // This bookkeeping makes it easy to add, remove and clean up after all these registrations.
420 private Dictionary<string, BSScene.PreStepAction> RegisteredPrestepActions = new Dictionary<string, BSScene.PreStepAction>();
421 private Dictionary<string, BSScene.PostStepAction> RegisteredPoststepActions = new Dictionary<string, BSScene.PostStepAction>();
422 protected void RegisterPreStepAction(string op, uint id, BSScene.PreStepAction actn)
423 {
424 string identifier = op + "-" + id.ToString();
425 515
426 lock (RegisteredPrestepActions) 516 public BSActorCollection PhysicalActors;
427 {
428 // Clean out any existing action
429 UnRegisterPreStepAction(op, id);
430 RegisteredPrestepActions[identifier] = actn;
431 PhysicsScene.BeforeStep += actn;
432 }
433 DetailLog("{0},BSPhysObject.RegisterPreStepAction,id={1}", LocalID, identifier);
434 }
435
436 // Unregister a pre step action. Safe to call if the action has not been registered.
437 // Returns 'true' if an action was actually removed
438 protected bool UnRegisterPreStepAction(string op, uint id)
439 {
440 string identifier = op + "-" + id.ToString();
441 bool removed = false;
442 lock (RegisteredPrestepActions)
443 {
444 if (RegisteredPrestepActions.ContainsKey(identifier))
445 {
446 PhysicsScene.BeforeStep -= RegisteredPrestepActions[identifier];
447 RegisteredPrestepActions.Remove(identifier);
448 removed = true;
449 }
450 }
451 DetailLog("{0},BSPhysObject.UnRegisterPreStepAction,id={1},removed={2}", LocalID, identifier, removed);
452 return removed;
453 }
454
455 protected void UnRegisterAllPreStepActions()
456 {
457 lock (RegisteredPrestepActions)
458 {
459 foreach (KeyValuePair<string, BSScene.PreStepAction> kvp in RegisteredPrestepActions)
460 {
461 PhysicsScene.BeforeStep -= kvp.Value;
462 }
463 RegisteredPrestepActions.Clear();
464 }
465 DetailLog("{0},BSPhysObject.UnRegisterAllPreStepActions,", LocalID);
466 }
467
468 protected void RegisterPostStepAction(string op, uint id, BSScene.PostStepAction actn)
469 {
470 string identifier = op + "-" + id.ToString();
471
472 lock (RegisteredPoststepActions)
473 {
474 // Clean out any existing action
475 UnRegisterPostStepAction(op, id);
476 RegisteredPoststepActions[identifier] = actn;
477 PhysicsScene.AfterStep += actn;
478 }
479 DetailLog("{0},BSPhysObject.RegisterPostStepAction,id={1}", LocalID, identifier);
480 }
481
482 // Unregister a pre step action. Safe to call if the action has not been registered.
483 // Returns 'true' if an action was actually removed.
484 protected bool UnRegisterPostStepAction(string op, uint id)
485 {
486 string identifier = op + "-" + id.ToString();
487 bool removed = false;
488 lock (RegisteredPoststepActions)
489 {
490 if (RegisteredPoststepActions.ContainsKey(identifier))
491 {
492 PhysicsScene.AfterStep -= RegisteredPoststepActions[identifier];
493 RegisteredPoststepActions.Remove(identifier);
494 removed = true;
495 }
496 }
497 DetailLog("{0},BSPhysObject.UnRegisterPostStepAction,id={1},removed={2}", LocalID, identifier, removed);
498 return removed;
499 }
500
501 protected void UnRegisterAllPostStepActions()
502 {
503 lock (RegisteredPoststepActions)
504 {
505 foreach (KeyValuePair<string, BSScene.PostStepAction> kvp in RegisteredPoststepActions)
506 {
507 PhysicsScene.AfterStep -= kvp.Value;
508 }
509 RegisteredPoststepActions.Clear();
510 }
511 DetailLog("{0},BSPhysObject.UnRegisterAllPostStepActions,", LocalID);
512 }
513 517
514 // When an update to the physical properties happens, this event is fired to let 518 // When an update to the physical properties happens, this event is fired to let
515 // different actors to modify the update before it is passed around 519 // different actors to modify the update before it is passed around
@@ -522,53 +526,13 @@ public abstract class BSPhysObject : PhysicsActor
522 actions(ref entprop); 526 actions(ref entprop);
523 } 527 }
524 528
525 private Dictionary<string, PreUpdatePropertyAction> RegisteredPreUpdatePropertyActions = new Dictionary<string, PreUpdatePropertyAction>();
526 public void RegisterPreUpdatePropertyAction(string identifier, PreUpdatePropertyAction actn)
527 {
528 lock (RegisteredPreUpdatePropertyActions)
529 {
530 // Clean out any existing action
531 UnRegisterPreUpdatePropertyAction(identifier);
532 RegisteredPreUpdatePropertyActions[identifier] = actn;
533 OnPreUpdateProperty += actn;
534 }
535 DetailLog("{0},BSPhysObject.RegisterPreUpdatePropertyAction,id={1}", LocalID, identifier);
536 }
537 public bool UnRegisterPreUpdatePropertyAction(string identifier)
538 {
539 bool removed = false;
540 lock (RegisteredPreUpdatePropertyActions)
541 {
542 if (RegisteredPreUpdatePropertyActions.ContainsKey(identifier))
543 {
544 OnPreUpdateProperty -= RegisteredPreUpdatePropertyActions[identifier];
545 RegisteredPreUpdatePropertyActions.Remove(identifier);
546 removed = true;
547 }
548 }
549 DetailLog("{0},BSPhysObject.UnRegisterPreUpdatePropertyAction,id={1},removed={2}", LocalID, identifier, removed);
550 return removed;
551 }
552 public void UnRegisterAllPreUpdatePropertyActions()
553 {
554 lock (RegisteredPreUpdatePropertyActions)
555 {
556 foreach (KeyValuePair<string, PreUpdatePropertyAction> kvp in RegisteredPreUpdatePropertyActions)
557 {
558 OnPreUpdateProperty -= kvp.Value;
559 }
560 RegisteredPreUpdatePropertyActions.Clear();
561 }
562 DetailLog("{0},BSPhysObject.UnRegisterAllPreUpdatePropertyAction,", LocalID);
563 }
564
565 #endregion // Per Simulation Step actions 529 #endregion // Per Simulation Step actions
566 530
567 // High performance detailed logging routine used by the physical objects. 531 // High performance detailed logging routine used by the physical objects.
568 protected void DetailLog(string msg, params Object[] args) 532 protected void DetailLog(string msg, params Object[] args)
569 { 533 {
570 if (PhysicsScene.PhysicsLogging.Enabled) 534 if (PhysScene.PhysicsLogging.Enabled)
571 PhysicsScene.DetailLog(msg, args); 535 PhysScene.DetailLog(msg, args);
572 } 536 }
573 537
574} 538}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 6a5461a..95bdc7b 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -55,9 +55,6 @@ public class BSPrim : BSPhysObject
55 private OMV.Vector3 _position; 55 private OMV.Vector3 _position;
56 56
57 private float _mass; // the mass of this object 57 private float _mass; // the mass of this object
58 private OMV.Vector3 _force;
59 private OMV.Vector3 _velocity;
60 private OMV.Vector3 _torque;
61 private OMV.Vector3 _acceleration; 58 private OMV.Vector3 _acceleration;
62 private OMV.Quaternion _orientation; 59 private OMV.Quaternion _orientation;
63 private int _physicsActorType; 60 private int _physicsActorType;
@@ -72,16 +69,19 @@ public class BSPrim : BSPhysObject
72 69
73 private int CrossingFailures { get; set; } 70 private int CrossingFailures { get; set; }
74 71
75 public BSDynamics VehicleController { get; private set; } 72 // Keep a handle to the vehicle actor so it is easy to set parameters on same.
73 public BSDynamics VehicleActor;
74 public const string VehicleActorName = "BasicVehicle";
76 75
77 private BSVMotor _targetMotor; 76 // Parameters for the hover actor
78 private OMV.Vector3 _PIDTarget; 77 public const string HoverActorName = "HoverActor";
79 private float _PIDTau; 78 // Parameters for the axis lock actor
80 79 public const String LockedAxisActorName = "BSPrim.LockedAxis";
81 private BSFMotor _hoverMotor; 80 // Parameters for the move to target actor
82 private float _PIDHoverHeight; 81 public const string MoveToTargetActorName = "MoveToTargetActor";
83 private PIDHoverType _PIDHoverType; 82 // Parameters for the setForce and setTorque actors
84 private float _PIDHoverTau; 83 public const string SetForceActorName = "SetForceActor";
84 public const string SetTorqueActorName = "SetTorqueActor";
85 85
86 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, 86 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
87 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) 87 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
@@ -94,26 +94,28 @@ public class BSPrim : BSPhysObject
94 Scale = size; // prims are the size the user wants them to be (different for BSCharactes). 94 Scale = size; // prims are the size the user wants them to be (different for BSCharactes).
95 _orientation = rotation; 95 _orientation = rotation;
96 _buoyancy = 0f; 96 _buoyancy = 0f;
97 _velocity = OMV.Vector3.Zero; 97 RawVelocity = OMV.Vector3.Zero;
98 _rotationalVelocity = OMV.Vector3.Zero; 98 _rotationalVelocity = OMV.Vector3.Zero;
99 BaseShape = pbs; 99 BaseShape = pbs;
100 _isPhysical = pisPhysical; 100 _isPhysical = pisPhysical;
101 _isVolumeDetect = false; 101 _isVolumeDetect = false;
102 102
103 VehicleController = new BSDynamics(PhysicsScene, this); // add vehicleness 103 // We keep a handle to the vehicle actor so we can set vehicle parameters later.
104 VehicleActor = new BSDynamics(PhysScene, this, VehicleActorName);
105 PhysicalActors.Add(VehicleActorName, VehicleActor);
104 106
105 _mass = CalculateMass(); 107 _mass = CalculateMass();
106 108
107 DetailLog("{0},BSPrim.constructor,call", LocalID); 109 // DetailLog("{0},BSPrim.constructor,call", LocalID);
108 // do the actual object creation at taint time 110 // do the actual object creation at taint time
109 PhysicsScene.TaintedObject("BSPrim.create", delegate() 111 PhysScene.TaintedObject("BSPrim.create", delegate()
110 { 112 {
111 // Make sure the object is being created with some sanity. 113 // Make sure the object is being created with some sanity.
112 ExtremeSanityCheck(true /* inTaintTime */); 114 ExtremeSanityCheck(true /* inTaintTime */);
113 115
114 CreateGeomAndObject(true); 116 CreateGeomAndObject(true);
115 117
116 CurrentCollisionFlags = PhysicsScene.PE.GetCollisionFlags(PhysBody); 118 CurrentCollisionFlags = PhysScene.PE.GetCollisionFlags(PhysBody);
117 }); 119 });
118 } 120 }
119 121
@@ -126,14 +128,14 @@ public class BSPrim : BSPhysObject
126 // Undo any vehicle properties 128 // Undo any vehicle properties
127 this.VehicleType = (int)Vehicle.TYPE_NONE; 129 this.VehicleType = (int)Vehicle.TYPE_NONE;
128 130
129 PhysicsScene.TaintedObject("BSPrim.destroy", delegate() 131 PhysScene.TaintedObject("BSPrim.Destroy", delegate()
130 { 132 {
131 DetailLog("{0},BSPrim.Destroy,taint,", LocalID); 133 DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
132 // If there are physical body and shape, release my use of same. 134 // If there are physical body and shape, release my use of same.
133 PhysicsScene.Shapes.DereferenceBody(PhysBody, null); 135 PhysScene.Shapes.DereferenceBody(PhysBody, null);
134 PhysBody.Clear(); 136 PhysBody.Clear();
135 PhysicsScene.Shapes.DereferenceShape(PhysShape, null); 137 PhysShape.Dereference(PhysScene);
136 PhysShape.Clear(); 138 PhysShape = new BSShapeNull();
137 }); 139 });
138 } 140 }
139 141
@@ -159,25 +161,13 @@ public class BSPrim : BSPhysObject
159 ForceBodyShapeRebuild(false); 161 ForceBodyShapeRebuild(false);
160 } 162 }
161 } 163 }
162 // 'unknown' says to choose the best type
163 public override BSPhysicsShapeType PreferredPhysicalShape
164 { get { return BSPhysicsShapeType.SHAPE_UNKNOWN; } }
165
166 public override bool ForceBodyShapeRebuild(bool inTaintTime) 164 public override bool ForceBodyShapeRebuild(bool inTaintTime)
167 { 165 {
168 if (inTaintTime) 166 PhysScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate()
169 { 167 {
170 _mass = CalculateMass(); // changing the shape changes the mass 168 _mass = CalculateMass(); // changing the shape changes the mass
171 CreateGeomAndObject(true); 169 CreateGeomAndObject(true);
172 } 170 });
173 else
174 {
175 PhysicsScene.TaintedObject("BSPrim.ForceBodyShapeRebuild", delegate()
176 {
177 _mass = CalculateMass(); // changing the shape changes the mass
178 CreateGeomAndObject(true);
179 });
180 }
181 return true; 171 return true;
182 } 172 }
183 public override bool Grabbed { 173 public override bool Grabbed {
@@ -190,7 +180,7 @@ public class BSPrim : BSPhysObject
190 if (value != _isSelected) 180 if (value != _isSelected)
191 { 181 {
192 _isSelected = value; 182 _isSelected = value;
193 PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() 183 PhysScene.TaintedObject("BSPrim.setSelected", delegate()
194 { 184 {
195 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); 185 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
196 SetObjectDynamic(false); 186 SetObjectDynamic(false);
@@ -231,124 +221,56 @@ public class BSPrim : BSPhysObject
231 // Called at taint time! 221 // Called at taint time!
232 public override void ZeroMotion(bool inTaintTime) 222 public override void ZeroMotion(bool inTaintTime)
233 { 223 {
234 _velocity = OMV.Vector3.Zero; 224 RawVelocity = OMV.Vector3.Zero;
235 _acceleration = OMV.Vector3.Zero; 225 _acceleration = OMV.Vector3.Zero;
236 _rotationalVelocity = OMV.Vector3.Zero; 226 _rotationalVelocity = OMV.Vector3.Zero;
237 227
238 // Zero some other properties in the physics engine 228 // Zero some other properties in the physics engine
239 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() 229 PhysScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
240 { 230 {
241 if (PhysBody.HasPhysicalBody) 231 if (PhysBody.HasPhysicalBody)
242 PhysicsScene.PE.ClearAllForces(PhysBody); 232 PhysScene.PE.ClearAllForces(PhysBody);
243 }); 233 });
244 } 234 }
245 public override void ZeroAngularMotion(bool inTaintTime) 235 public override void ZeroAngularMotion(bool inTaintTime)
246 { 236 {
247 _rotationalVelocity = OMV.Vector3.Zero; 237 _rotationalVelocity = OMV.Vector3.Zero;
248 // Zero some other properties in the physics engine 238 // Zero some other properties in the physics engine
249 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() 239 PhysScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
250 { 240 {
251 // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity); 241 // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity);
252 if (PhysBody.HasPhysicalBody) 242 if (PhysBody.HasPhysicalBody)
253 { 243 {
254 PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); 244 PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
255 PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); 245 PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
256 } 246 }
257 }); 247 });
258 } 248 }
259 249
260 bool TryExperimentalLockAxisCode = false;
261 BSConstraint LockAxisConstraint = null;
262 public override void LockAngularMotion(OMV.Vector3 axis) 250 public override void LockAngularMotion(OMV.Vector3 axis)
263 { 251 {
264 DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); 252 DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis);
265 253
266 // "1" means free, "0" means locked 254 // "1" means free, "0" means locked
267 OMV.Vector3 locking = new OMV.Vector3(1f, 1f, 1f); 255 OMV.Vector3 locking = LockedAxisFree;
268 if (axis.X != 1) locking.X = 0f; 256 if (axis.X != 1) locking.X = 0f;
269 if (axis.Y != 1) locking.Y = 0f; 257 if (axis.Y != 1) locking.Y = 0f;
270 if (axis.Z != 1) locking.Z = 0f; 258 if (axis.Z != 1) locking.Z = 0f;
271 LockedAxis = locking; 259 LockedAngularAxis = locking;
272 260
273 if (TryExperimentalLockAxisCode && LockedAxis != LockedAxisFree) 261 EnableActor(LockedAngularAxis != LockedAxisFree, LockedAxisActorName, delegate()
274 { 262 {
275 // Lock that axis by creating a 6DOF constraint that has one end in the world and 263 return new BSActorLockAxis(PhysScene, this, LockedAxisActorName);
276 // the other in the object. 264 });
277 // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=20817
278 // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=26380
279
280 PhysicsScene.TaintedObject("BSPrim.LockAngularMotion", delegate()
281 {
282 CleanUpLockAxisPhysicals(true /* inTaintTime */);
283
284 BSConstraint6Dof axisConstrainer = new BSConstraint6Dof(PhysicsScene.World, PhysBody,
285 OMV.Vector3.Zero, OMV.Quaternion.Inverse(RawOrientation),
286 true /* useLinearReferenceFrameB */, true /* disableCollisionsBetweenLinkedBodies */);
287 LockAxisConstraint = axisConstrainer;
288 PhysicsScene.Constraints.AddConstraint(LockAxisConstraint);
289
290 // The constraint is tied to the world and oriented to the prim.
291
292 // Free to move linearly
293 OMV.Vector3 linearLow = OMV.Vector3.Zero;
294 OMV.Vector3 linearHigh = PhysicsScene.TerrainManager.DefaultRegionSize;
295 axisConstrainer.SetLinearLimits(linearLow, linearHigh);
296
297 // Angular with some axis locked
298 float f2PI = (float)Math.PI * 2f;
299 OMV.Vector3 angularLow = new OMV.Vector3(-f2PI, -f2PI, -f2PI);
300 OMV.Vector3 angularHigh = new OMV.Vector3(f2PI, f2PI, f2PI);
301 if (LockedAxis.X != 1f)
302 {
303 angularLow.X = 0f;
304 angularHigh.X = 0f;
305 }
306 if (LockedAxis.Y != 1f)
307 {
308 angularLow.Y = 0f;
309 angularHigh.Y = 0f;
310 }
311 if (LockedAxis.Z != 1f)
312 {
313 angularLow.Z = 0f;
314 angularHigh.Z = 0f;
315 }
316 axisConstrainer.SetAngularLimits(angularLow, angularHigh);
317
318 DetailLog("{0},BSPrim.LockAngularMotion,create,linLow={1},linHi={2},angLow={3},angHi={4}",
319 LocalID, linearLow, linearHigh, angularLow, angularHigh);
320
321 // Constants from one of the posts mentioned above and used in Bullet's ConstraintDemo.
322 axisConstrainer.TranslationalLimitMotor(true /* enable */, 5.0f, 0.1f);
323 265
324 axisConstrainer.RecomputeConstraintVariables(RawMass); 266 // Update parameters so the new actor's Refresh() action is called at the right time.
325 }); 267 PhysScene.TaintedObject("BSPrim.LockAngularMotion", delegate()
326 }
327 else
328 { 268 {
329 // Everything seems unlocked 269 UpdatePhysicalParameters();
330 CleanUpLockAxisPhysicals(false /* inTaintTime */); 270 });
331 }
332 271
333 return; 272 return;
334 } 273 }
335 // Get rid of any constraint built for LockAxis
336 // Most often the constraint is removed when the constraint collection is cleaned for this prim.
337 private void CleanUpLockAxisPhysicals(bool inTaintTime)
338 {
339 if (LockAxisConstraint != null)
340 {
341 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.CleanUpLockAxisPhysicals", delegate()
342 {
343 if (LockAxisConstraint != null)
344 {
345 PhysicsScene.Constraints.RemoveAndDestroyConstraint(LockAxisConstraint);
346 LockAxisConstraint = null;
347 DetailLog("{0},BSPrim.CleanUpLockAxisPhysicals,destroyingConstraint", LocalID);
348 }
349 });
350 }
351 }
352 274
353 public override OMV.Vector3 RawPosition 275 public override OMV.Vector3 RawPosition
354 { 276 {
@@ -372,7 +294,7 @@ public class BSPrim : BSPhysObject
372 _position = value; 294 _position = value;
373 PositionSanityCheck(false); 295 PositionSanityCheck(false);
374 296
375 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() 297 PhysScene.TaintedObject("BSPrim.setPosition", delegate()
376 { 298 {
377 DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 299 DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
378 ForcePosition = _position; 300 ForcePosition = _position;
@@ -382,14 +304,14 @@ public class BSPrim : BSPhysObject
382 304
383 public override OMV.Vector3 ForcePosition { 305 public override OMV.Vector3 ForcePosition {
384 get { 306 get {
385 _position = PhysicsScene.PE.GetPosition(PhysBody); 307 _position = PhysScene.PE.GetPosition(PhysBody);
386 return _position; 308 return _position;
387 } 309 }
388 set { 310 set {
389 _position = value; 311 _position = value;
390 if (PhysBody.HasPhysicalBody) 312 if (PhysBody.HasPhysicalBody)
391 { 313 {
392 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); 314 PhysScene.PE.SetTranslation(PhysBody, _position, _orientation);
393 ActivateIfPhysical(false); 315 ActivateIfPhysical(false);
394 } 316 }
395 } 317 }
@@ -406,7 +328,7 @@ public class BSPrim : BSPhysObject
406 if (!IsPhysicallyActive) 328 if (!IsPhysicallyActive)
407 return ret; 329 return ret;
408 330
409 if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) 331 if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition))
410 { 332 {
411 // The physical object is out of the known/simulated area. 333 // The physical object is out of the known/simulated area.
412 // Upper levels of code will handle the transition to other areas so, for 334 // Upper levels of code will handle the transition to other areas so, for
@@ -414,7 +336,7 @@ public class BSPrim : BSPhysObject
414 return ret; 336 return ret;
415 } 337 }
416 338
417 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); 339 float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
418 OMV.Vector3 upForce = OMV.Vector3.Zero; 340 OMV.Vector3 upForce = OMV.Vector3.Zero;
419 float approxSize = Math.Max(Size.X, Math.Max(Size.Y, Size.Z)); 341 float approxSize = Math.Max(Size.X, Math.Max(Size.Y, Size.Z));
420 if ((RawPosition.Z + approxSize / 2f) < terrainHeight) 342 if ((RawPosition.Z + approxSize / 2f) < terrainHeight)
@@ -435,7 +357,7 @@ public class BSPrim : BSPhysObject
435 357
436 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) 358 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
437 { 359 {
438 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); 360 float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(_position);
439 // TODO: a floating motor so object will bob in the water 361 // TODO: a floating motor so object will bob in the water
440 if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f) 362 if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f)
441 { 363 {
@@ -443,7 +365,7 @@ public class BSPrim : BSPhysObject
443 upForce.Z = (waterHeight - RawPosition.Z) * 1f; 365 upForce.Z = (waterHeight - RawPosition.Z) * 1f;
444 366
445 // Apply upforce and overcome gravity. 367 // Apply upforce and overcome gravity.
446 OMV.Vector3 correctionForce = upForce - PhysicsScene.DefaultGravity; 368 OMV.Vector3 correctionForce = upForce - PhysScene.DefaultGravity;
447 DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce); 369 DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce);
448 AddForce(correctionForce, false, inTaintTime); 370 AddForce(correctionForce, false, inTaintTime);
449 ret = true; 371 ret = true;
@@ -471,9 +393,9 @@ public class BSPrim : BSPhysObject
471 ZeroMotion(inTaintTime); 393 ZeroMotion(inTaintTime);
472 ret = true; 394 ret = true;
473 } 395 }
474 if (_velocity.LengthSquared() > BSParam.MaxLinearVelocity) 396 if (RawVelocity.LengthSquared() > BSParam.MaxLinearVelocity)
475 { 397 {
476 _velocity = Util.ClampV(_velocity, BSParam.MaxLinearVelocity); 398 RawVelocity = Util.ClampV(RawVelocity, BSParam.MaxLinearVelocity);
477 ret = true; 399 ret = true;
478 } 400 }
479 if (_rotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared) 401 if (_rotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared)
@@ -498,7 +420,7 @@ public class BSPrim : BSPhysObject
498 get { return _mass; } 420 get { return _mass; }
499 } 421 }
500 // used when we only want this prim's mass and not the linkset thing 422 // used when we only want this prim's mass and not the linkset thing
501 public override float RawMass { 423 public override float RawMass {
502 get { return _mass; } 424 get { return _mass; }
503 } 425 }
504 // Set the physical mass to the passed mass. 426 // Set the physical mass to the passed mass.
@@ -509,10 +431,10 @@ public class BSPrim : BSPhysObject
509 { 431 {
510 if (IsStatic) 432 if (IsStatic)
511 { 433 {
512 PhysicsScene.PE.SetGravity(PhysBody, PhysicsScene.DefaultGravity); 434 PhysScene.PE.SetGravity(PhysBody, PhysScene.DefaultGravity);
513 Inertia = OMV.Vector3.Zero; 435 Inertia = OMV.Vector3.Zero;
514 PhysicsScene.PE.SetMassProps(PhysBody, 0f, Inertia); 436 PhysScene.PE.SetMassProps(PhysBody, 0f, Inertia);
515 PhysicsScene.PE.UpdateInertiaTensor(PhysBody); 437 PhysScene.PE.UpdateInertiaTensor(PhysBody);
516 } 438 }
517 else 439 else
518 { 440 {
@@ -521,16 +443,16 @@ public class BSPrim : BSPhysObject
521 // Changing interesting properties doesn't change proxy and collision cache 443 // Changing interesting properties doesn't change proxy and collision cache
522 // information. The Bullet solution is to re-add the object to the world 444 // information. The Bullet solution is to re-add the object to the world
523 // after parameters are changed. 445 // after parameters are changed.
524 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); 446 PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
525 } 447 }
526 448
527 // The computation of mass props requires gravity to be set on the object. 449 // The computation of mass props requires gravity to be set on the object.
528 Gravity = ComputeGravity(Buoyancy); 450 Gravity = ComputeGravity(Buoyancy);
529 PhysicsScene.PE.SetGravity(PhysBody, Gravity); 451 PhysScene.PE.SetGravity(PhysBody, Gravity);
530 452
531 Inertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass); 453 Inertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass);
532 PhysicsScene.PE.SetMassProps(PhysBody, physMass, Inertia); 454 PhysScene.PE.SetMassProps(PhysBody, physMass, Inertia);
533 PhysicsScene.PE.UpdateInertiaTensor(PhysBody); 455 PhysScene.PE.UpdateInertiaTensor(PhysBody);
534 456
535 DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}", 457 DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}",
536 LocalID, physMass, Inertia, Gravity, inWorld); 458 LocalID, physMass, Inertia, Gravity, inWorld);
@@ -546,7 +468,7 @@ public class BSPrim : BSPhysObject
546 // Return what gravity should be set to this very moment 468 // Return what gravity should be set to this very moment
547 public OMV.Vector3 ComputeGravity(float buoyancy) 469 public OMV.Vector3 ComputeGravity(float buoyancy)
548 { 470 {
549 OMV.Vector3 ret = PhysicsScene.DefaultGravity; 471 OMV.Vector3 ret = PhysScene.DefaultGravity;
550 472
551 if (!IsStatic) 473 if (!IsStatic)
552 { 474 {
@@ -570,95 +492,63 @@ public class BSPrim : BSPhysObject
570 } 492 }
571 493
572 public override OMV.Vector3 Force { 494 public override OMV.Vector3 Force {
573 get { return _force; } 495 get { return RawForce; }
574 set { 496 set {
575 _force = value; 497 RawForce = value;
576 if (_force != OMV.Vector3.Zero) 498 EnableActor(RawForce != OMV.Vector3.Zero, SetForceActorName, delegate()
577 { 499 {
578 // If the force is non-zero, it must be reapplied each tick because 500 return new BSActorSetForce(PhysScene, this, SetForceActorName);
579 // Bullet clears the forces applied last frame. 501 });
580 RegisterPreStepAction("BSPrim.setForce", LocalID,
581 delegate(float timeStep)
582 {
583 if (!IsPhysicallyActive || _force == OMV.Vector3.Zero)
584 {
585 UnRegisterPreStepAction("BSPrim.setForce", LocalID);
586 return;
587 }
588
589 DetailLog("{0},BSPrim.setForce,preStep,force={1}", LocalID, _force);
590 if (PhysBody.HasPhysicalBody)
591 {
592 PhysicsScene.PE.ApplyCentralForce(PhysBody, _force);
593 ActivateIfPhysical(false);
594 }
595 }
596 );
597 }
598 else
599 {
600 UnRegisterPreStepAction("BSPrim.setForce", LocalID);
601 }
602 } 502 }
603 } 503 }
604 504
605 public override int VehicleType { 505 public override int VehicleType {
606 get { 506 get {
607 return (int)VehicleController.Type; // if we are a vehicle, return that type 507 return (int)VehicleActor.Type;
608 } 508 }
609 set { 509 set {
610 Vehicle type = (Vehicle)value; 510 Vehicle type = (Vehicle)value;
611 511
612 PhysicsScene.TaintedObject("setVehicleType", delegate() 512 PhysScene.TaintedObject("setVehicleType", delegate()
613 { 513 {
614 // Done at taint time so we're sure the physics engine is not using the variables 514 // Some vehicle scripts change vehicle type on the fly as an easy way to
615 // Vehicle code changes the parameters for this vehicle type. 515 // change all the parameters. Like a plane changing to CAR when on the
616 VehicleController.ProcessTypeChange(type); 516 // ground. In this case, don't want to zero motion.
517 // ZeroMotion(true /* inTaintTime */);
518 VehicleActor.ProcessTypeChange(type);
617 ActivateIfPhysical(false); 519 ActivateIfPhysical(false);
618
619 // If an active vehicle, register the vehicle code to be called before each step
620 if (VehicleController.Type == Vehicle.TYPE_NONE)
621 {
622 UnRegisterPreStepAction("BSPrim.Vehicle", LocalID);
623 UnRegisterPostStepAction("BSPrim.Vehicle", LocalID);
624 }
625 else
626 {
627 RegisterPreStepAction("BSPrim.Vehicle", LocalID, VehicleController.Step);
628 RegisterPostStepAction("BSPrim.Vehicle", LocalID, VehicleController.PostStep);
629 }
630 }); 520 });
631 } 521 }
632 } 522 }
633 public override void VehicleFloatParam(int param, float value) 523 public override void VehicleFloatParam(int param, float value)
634 { 524 {
635 PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() 525 PhysScene.TaintedObject("BSPrim.VehicleFloatParam", delegate()
636 { 526 {
637 VehicleController.ProcessFloatVehicleParam((Vehicle)param, value); 527 VehicleActor.ProcessFloatVehicleParam((Vehicle)param, value);
638 ActivateIfPhysical(false); 528 ActivateIfPhysical(false);
639 }); 529 });
640 } 530 }
641 public override void VehicleVectorParam(int param, OMV.Vector3 value) 531 public override void VehicleVectorParam(int param, OMV.Vector3 value)
642 { 532 {
643 PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() 533 PhysScene.TaintedObject("BSPrim.VehicleVectorParam", delegate()
644 { 534 {
645 VehicleController.ProcessVectorVehicleParam((Vehicle)param, value); 535 VehicleActor.ProcessVectorVehicleParam((Vehicle)param, value);
646 ActivateIfPhysical(false); 536 ActivateIfPhysical(false);
647 }); 537 });
648 } 538 }
649 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) 539 public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
650 { 540 {
651 PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() 541 PhysScene.TaintedObject("BSPrim.VehicleRotationParam", delegate()
652 { 542 {
653 VehicleController.ProcessRotationVehicleParam((Vehicle)param, rotation); 543 VehicleActor.ProcessRotationVehicleParam((Vehicle)param, rotation);
654 ActivateIfPhysical(false); 544 ActivateIfPhysical(false);
655 }); 545 });
656 } 546 }
657 public override void VehicleFlags(int param, bool remove) 547 public override void VehicleFlags(int param, bool remove)
658 { 548 {
659 PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate() 549 PhysScene.TaintedObject("BSPrim.VehicleFlags", delegate()
660 { 550 {
661 VehicleController.ProcessVehicleFlags(param, remove); 551 VehicleActor.ProcessVehicleFlags(param, remove);
662 }); 552 });
663 } 553 }
664 554
@@ -668,7 +558,7 @@ public class BSPrim : BSPhysObject
668 if (_isVolumeDetect != newValue) 558 if (_isVolumeDetect != newValue)
669 { 559 {
670 _isVolumeDetect = newValue; 560 _isVolumeDetect = newValue;
671 PhysicsScene.TaintedObject("BSPrim.SetVolumeDetect", delegate() 561 PhysScene.TaintedObject("BSPrim.SetVolumeDetect", delegate()
672 { 562 {
673 // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect); 563 // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect);
674 SetObjectDynamic(true); 564 SetObjectDynamic(true);
@@ -679,7 +569,7 @@ public class BSPrim : BSPhysObject
679 public override void SetMaterial(int material) 569 public override void SetMaterial(int material)
680 { 570 {
681 base.SetMaterial(material); 571 base.SetMaterial(material);
682 PhysicsScene.TaintedObject("BSPrim.SetMaterial", delegate() 572 PhysScene.TaintedObject("BSPrim.SetMaterial", delegate()
683 { 573 {
684 UpdatePhysicalParameters(); 574 UpdatePhysicalParameters();
685 }); 575 });
@@ -692,7 +582,7 @@ public class BSPrim : BSPhysObject
692 if (base.Friction != value) 582 if (base.Friction != value)
693 { 583 {
694 base.Friction = value; 584 base.Friction = value;
695 PhysicsScene.TaintedObject("BSPrim.setFriction", delegate() 585 PhysScene.TaintedObject("BSPrim.setFriction", delegate()
696 { 586 {
697 UpdatePhysicalParameters(); 587 UpdatePhysicalParameters();
698 }); 588 });
@@ -707,7 +597,7 @@ public class BSPrim : BSPhysObject
707 if (base.Restitution != value) 597 if (base.Restitution != value)
708 { 598 {
709 base.Restitution = value; 599 base.Restitution = value;
710 PhysicsScene.TaintedObject("BSPrim.setRestitution", delegate() 600 PhysScene.TaintedObject("BSPrim.setRestitution", delegate()
711 { 601 {
712 UpdatePhysicalParameters(); 602 UpdatePhysicalParameters();
713 }); 603 });
@@ -724,7 +614,7 @@ public class BSPrim : BSPhysObject
724 if (base.Density != value) 614 if (base.Density != value)
725 { 615 {
726 base.Density = value; 616 base.Density = value;
727 PhysicsScene.TaintedObject("BSPrim.setDensity", delegate() 617 PhysScene.TaintedObject("BSPrim.setDensity", delegate()
728 { 618 {
729 UpdatePhysicalParameters(); 619 UpdatePhysicalParameters();
730 }); 620 });
@@ -739,70 +629,47 @@ public class BSPrim : BSPhysObject
739 if (base.GravModifier != value) 629 if (base.GravModifier != value)
740 { 630 {
741 base.GravModifier = value; 631 base.GravModifier = value;
742 PhysicsScene.TaintedObject("BSPrim.setGravityModifier", delegate() 632 PhysScene.TaintedObject("BSPrim.setGravityModifier", delegate()
743 { 633 {
744 UpdatePhysicalParameters(); 634 UpdatePhysicalParameters();
745 }); 635 });
746 } 636 }
747 } 637 }
748 } 638 }
749 public override OMV.Vector3 RawVelocity
750 {
751 get { return _velocity; }
752 set { _velocity = value; }
753 }
754 public override OMV.Vector3 Velocity { 639 public override OMV.Vector3 Velocity {
755 get { return _velocity; } 640 get { return RawVelocity; }
756 set { 641 set {
757 _velocity = value; 642 RawVelocity = value;
758 PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() 643 PhysScene.TaintedObject("BSPrim.setVelocity", delegate()
759 { 644 {
760 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); 645 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, RawVelocity);
761 ForceVelocity = _velocity; 646 ForceVelocity = RawVelocity;
762 }); 647 });
763 } 648 }
764 } 649 }
765 public override OMV.Vector3 ForceVelocity { 650 public override OMV.Vector3 ForceVelocity {
766 get { return _velocity; } 651 get { return RawVelocity; }
767 set { 652 set {
768 PhysicsScene.AssertInTaintTime("BSPrim.ForceVelocity"); 653 PhysScene.AssertInTaintTime("BSPrim.ForceVelocity");
769 654
770 _velocity = Util.ClampV(value, BSParam.MaxLinearVelocity); 655 RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity);
771 if (PhysBody.HasPhysicalBody) 656 if (PhysBody.HasPhysicalBody)
772 { 657 {
773 DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, _velocity); 658 DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, RawVelocity);
774 PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity); 659 PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity);
775 ActivateIfPhysical(false); 660 ActivateIfPhysical(false);
776 } 661 }
777 } 662 }
778 } 663 }
779 public override OMV.Vector3 Torque { 664 public override OMV.Vector3 Torque {
780 get { return _torque; } 665 get { return RawTorque; }
781 set { 666 set {
782 _torque = value; 667 RawTorque = value;
783 if (_torque != OMV.Vector3.Zero) 668 EnableActor(RawTorque != OMV.Vector3.Zero, SetTorqueActorName, delegate()
784 {
785 // If the torque is non-zero, it must be reapplied each tick because
786 // Bullet clears the forces applied last frame.
787 RegisterPreStepAction("BSPrim.setTorque", LocalID,
788 delegate(float timeStep)
789 {
790 if (!IsPhysicallyActive || _torque == OMV.Vector3.Zero)
791 {
792 UnRegisterPreStepAction("BSPrim.setTorque", LocalID);
793 return;
794 }
795
796 if (PhysBody.HasPhysicalBody)
797 AddAngularForce(_torque, false, true);
798 }
799 );
800 }
801 else
802 { 669 {
803 UnRegisterPreStepAction("BSPrim.setTorque", LocalID); 670 return new BSActorSetTorque(PhysScene, this, SetTorqueActorName);
804 } 671 });
805 // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); 672 DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, RawTorque);
806 } 673 }
807 } 674 }
808 public override OMV.Vector3 Acceleration { 675 public override OMV.Vector3 Acceleration {
@@ -823,7 +690,7 @@ public class BSPrim : BSPhysObject
823 return; 690 return;
824 _orientation = value; 691 _orientation = value;
825 692
826 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() 693 PhysScene.TaintedObject("BSPrim.setOrientation", delegate()
827 { 694 {
828 ForceOrientation = _orientation; 695 ForceOrientation = _orientation;
829 }); 696 });
@@ -834,14 +701,14 @@ public class BSPrim : BSPhysObject
834 { 701 {
835 get 702 get
836 { 703 {
837 _orientation = PhysicsScene.PE.GetOrientation(PhysBody); 704 _orientation = PhysScene.PE.GetOrientation(PhysBody);
838 return _orientation; 705 return _orientation;
839 } 706 }
840 set 707 set
841 { 708 {
842 _orientation = value; 709 _orientation = value;
843 if (PhysBody.HasPhysicalBody) 710 if (PhysBody.HasPhysicalBody)
844 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); 711 PhysScene.PE.SetTranslation(PhysBody, _position, _orientation);
845 } 712 }
846 } 713 }
847 public override int PhysicsActorType { 714 public override int PhysicsActorType {
@@ -854,7 +721,7 @@ public class BSPrim : BSPhysObject
854 if (_isPhysical != value) 721 if (_isPhysical != value)
855 { 722 {
856 _isPhysical = value; 723 _isPhysical = value;
857 PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate() 724 PhysScene.TaintedObject("BSPrim.setIsPhysical", delegate()
858 { 725 {
859 DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); 726 DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
860 SetObjectDynamic(true); 727 SetObjectDynamic(true);
@@ -903,19 +770,19 @@ public class BSPrim : BSPhysObject
903 if (!PhysBody.HasPhysicalBody) 770 if (!PhysBody.HasPhysicalBody)
904 { 771 {
905 // This would only happen if updates are called for during initialization when the body is not set up yet. 772 // This would only happen if updates are called for during initialization when the body is not set up yet.
906 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,calledWithNoPhysBody", LocalID); 773 // DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,calledWithNoPhysBody", LocalID);
907 return; 774 return;
908 } 775 }
909 776
910 // Mangling all the physical properties requires the object not be in the physical world. 777 // Mangling all the physical properties requires the object not be in the physical world.
911 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found). 778 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found).
912 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); 779 PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
913 780
914 // Set up the object physicalness (does gravity and collisions move this object) 781 // Set up the object physicalness (does gravity and collisions move this object)
915 MakeDynamic(IsStatic); 782 MakeDynamic(IsStatic);
916 783
917 // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters) 784 // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters)
918 VehicleController.Refresh(); 785 PhysicalActors.Refresh();
919 786
920 // Arrange for collision events if the simulator wants them 787 // Arrange for collision events if the simulator wants them
921 EnableCollisions(SubscribedEvents()); 788 EnableCollisions(SubscribedEvents());
@@ -926,10 +793,11 @@ public class BSPrim : BSPhysObject
926 AddObjectToPhysicalWorld(); 793 AddObjectToPhysicalWorld();
927 794
928 // Rebuild its shape 795 // Rebuild its shape
929 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody); 796 PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody);
930 797
931 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}", 798 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}",
932 LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape); 799 LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(),
800 CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape);
933 } 801 }
934 802
935 // "Making dynamic" means changing to and from static. 803 // "Making dynamic" means changing to and from static.
@@ -942,28 +810,28 @@ public class BSPrim : BSPhysObject
942 if (makeStatic) 810 if (makeStatic)
943 { 811 {
944 // Become a Bullet 'static' object type 812 // Become a Bullet 'static' object type
945 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); 813 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
946 // Stop all movement 814 // Stop all movement
947 ZeroMotion(true); 815 ZeroMotion(true);
948 816
949 // Set various physical properties so other object interact properly 817 // Set various physical properties so other object interact properly
950 PhysicsScene.PE.SetFriction(PhysBody, Friction); 818 PhysScene.PE.SetFriction(PhysBody, Friction);
951 PhysicsScene.PE.SetRestitution(PhysBody, Restitution); 819 PhysScene.PE.SetRestitution(PhysBody, Restitution);
952 PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); 820 PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
953 821
954 // Mass is zero which disables a bunch of physics stuff in Bullet 822 // Mass is zero which disables a bunch of physics stuff in Bullet
955 UpdatePhysicalMassProperties(0f, false); 823 UpdatePhysicalMassProperties(0f, false);
956 // Set collision detection parameters 824 // Set collision detection parameters
957 if (BSParam.CcdMotionThreshold > 0f) 825 if (BSParam.CcdMotionThreshold > 0f)
958 { 826 {
959 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); 827 PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
960 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); 828 PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
961 } 829 }
962 830
963 // The activation state is 'disabled' so Bullet will not try to act on it. 831 // The activation state is 'disabled' so Bullet will not try to act on it.
964 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION); 832 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION);
965 // Start it out sleeping and physical actions could wake it up. 833 // Start it out sleeping and physical actions could wake it up.
966 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING); 834 PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING);
967 835
968 // This collides like a static object 836 // This collides like a static object
969 PhysBody.collisionType = CollisionType.Static; 837 PhysBody.collisionType = CollisionType.Static;
@@ -971,11 +839,11 @@ public class BSPrim : BSPhysObject
971 else 839 else
972 { 840 {
973 // Not a Bullet static object 841 // Not a Bullet static object
974 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); 842 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
975 843
976 // Set various physical properties so other object interact properly 844 // Set various physical properties so other object interact properly
977 PhysicsScene.PE.SetFriction(PhysBody, Friction); 845 PhysScene.PE.SetFriction(PhysBody, Friction);
978 PhysicsScene.PE.SetRestitution(PhysBody, Restitution); 846 PhysScene.PE.SetRestitution(PhysBody, Restitution);
979 // DetailLog("{0},BSPrim.MakeDynamic,frict={1},rest={2}", LocalID, Friction, Restitution); 847 // DetailLog("{0},BSPrim.MakeDynamic,frict={1},rest={2}", LocalID, Friction, Restitution);
980 848
981 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 849 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
@@ -984,7 +852,7 @@ public class BSPrim : BSPhysObject
984 852
985 // For good measure, make sure the transform is set through to the motion state 853 // For good measure, make sure the transform is set through to the motion state
986 ForcePosition = _position; 854 ForcePosition = _position;
987 ForceVelocity = _velocity; 855 ForceVelocity = RawVelocity;
988 ForceRotationalVelocity = _rotationalVelocity; 856 ForceRotationalVelocity = _rotationalVelocity;
989 857
990 // A dynamic object has mass 858 // A dynamic object has mass
@@ -993,22 +861,22 @@ public class BSPrim : BSPhysObject
993 // Set collision detection parameters 861 // Set collision detection parameters
994 if (BSParam.CcdMotionThreshold > 0f) 862 if (BSParam.CcdMotionThreshold > 0f)
995 { 863 {
996 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); 864 PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
997 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); 865 PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
998 } 866 }
999 867
1000 // Various values for simulation limits 868 // Various values for simulation limits
1001 PhysicsScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping); 869 PhysScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping);
1002 PhysicsScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime); 870 PhysScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime);
1003 PhysicsScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold); 871 PhysScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold);
1004 PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); 872 PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
1005 873
1006 // This collides like an object. 874 // This collides like an object.
1007 PhysBody.collisionType = CollisionType.Dynamic; 875 PhysBody.collisionType = CollisionType.Dynamic;
1008 876
1009 // Force activation of the object so Bullet will act on it. 877 // Force activation of the object so Bullet will act on it.
1010 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. 878 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
1011 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); 879 PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
1012 } 880 }
1013 } 881 }
1014 882
@@ -1018,7 +886,7 @@ public class BSPrim : BSPhysObject
1018 // the functions after this one set up the state of a possibly newly created collision body. 886 // the functions after this one set up the state of a possibly newly created collision body.
1019 private void MakeSolid(bool makeSolid) 887 private void MakeSolid(bool makeSolid)
1020 { 888 {
1021 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(PhysBody); 889 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysScene.PE.GetBodyType(PhysBody);
1022 if (makeSolid) 890 if (makeSolid)
1023 { 891 {
1024 // Verify the previous code created the correct shape for this type of thing. 892 // Verify the previous code created the correct shape for this type of thing.
@@ -1026,7 +894,7 @@ public class BSPrim : BSPhysObject
1026 { 894 {
1027 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); 895 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType);
1028 } 896 }
1029 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); 897 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
1030 } 898 }
1031 else 899 else
1032 { 900 {
@@ -1034,32 +902,23 @@ public class BSPrim : BSPhysObject
1034 { 902 {
1035 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); 903 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
1036 } 904 }
1037 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); 905 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
1038 906
1039 // Change collision info from a static object to a ghosty collision object 907 // Change collision info from a static object to a ghosty collision object
1040 PhysBody.collisionType = CollisionType.VolumeDetect; 908 PhysBody.collisionType = CollisionType.VolumeDetect;
1041 } 909 }
1042 } 910 }
1043 911
1044 // Enable physical actions. Bullet will keep sleeping non-moving physical objects so
1045 // they need waking up when parameters are changed.
1046 // Called in taint-time!!
1047 private void ActivateIfPhysical(bool forceIt)
1048 {
1049 if (IsPhysical && PhysBody.HasPhysicalBody)
1050 PhysicsScene.PE.Activate(PhysBody, forceIt);
1051 }
1052
1053 // Turn on or off the flag controlling whether collision events are returned to the simulator. 912 // Turn on or off the flag controlling whether collision events are returned to the simulator.
1054 private void EnableCollisions(bool wantsCollisionEvents) 913 private void EnableCollisions(bool wantsCollisionEvents)
1055 { 914 {
1056 if (wantsCollisionEvents) 915 if (wantsCollisionEvents)
1057 { 916 {
1058 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 917 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
1059 } 918 }
1060 else 919 else
1061 { 920 {
1062 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 921 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
1063 } 922 }
1064 } 923 }
1065 924
@@ -1070,7 +929,7 @@ public class BSPrim : BSPhysObject
1070 { 929 {
1071 if (PhysBody.HasPhysicalBody) 930 if (PhysBody.HasPhysicalBody)
1072 { 931 {
1073 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); 932 PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody);
1074 } 933 }
1075 else 934 else
1076 { 935 {
@@ -1105,12 +964,12 @@ public class BSPrim : BSPhysObject
1105 public override bool FloatOnWater { 964 public override bool FloatOnWater {
1106 set { 965 set {
1107 _floatOnWater = value; 966 _floatOnWater = value;
1108 PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate() 967 PhysScene.TaintedObject("BSPrim.setFloatOnWater", delegate()
1109 { 968 {
1110 if (_floatOnWater) 969 if (_floatOnWater)
1111 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); 970 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
1112 else 971 else
1113 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); 972 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
1114 }); 973 });
1115 } 974 }
1116 } 975 }
@@ -1122,7 +981,7 @@ public class BSPrim : BSPhysObject
1122 _rotationalVelocity = value; 981 _rotationalVelocity = value;
1123 Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity); 982 Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity);
1124 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); 983 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
1125 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() 984 PhysScene.TaintedObject("BSPrim.setRotationalVelocity", delegate()
1126 { 985 {
1127 ForceRotationalVelocity = _rotationalVelocity; 986 ForceRotationalVelocity = _rotationalVelocity;
1128 }); 987 });
@@ -1137,7 +996,7 @@ public class BSPrim : BSPhysObject
1137 if (PhysBody.HasPhysicalBody) 996 if (PhysBody.HasPhysicalBody)
1138 { 997 {
1139 DetailLog("{0},BSPrim.ForceRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); 998 DetailLog("{0},BSPrim.ForceRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
1140 PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); 999 PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
1141 // PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); 1000 // PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
1142 ActivateIfPhysical(false); 1001 ActivateIfPhysical(false);
1143 } 1002 }
@@ -1153,7 +1012,7 @@ public class BSPrim : BSPhysObject
1153 get { return _buoyancy; } 1012 get { return _buoyancy; }
1154 set { 1013 set {
1155 _buoyancy = value; 1014 _buoyancy = value;
1156 PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate() 1015 PhysScene.TaintedObject("BSPrim.setBuoyancy", delegate()
1157 { 1016 {
1158 ForceBuoyancy = _buoyancy; 1017 ForceBuoyancy = _buoyancy;
1159 }); 1018 });
@@ -1171,78 +1030,13 @@ public class BSPrim : BSPhysObject
1171 } 1030 }
1172 } 1031 }
1173 1032
1174 // Used for MoveTo
1175 public override OMV.Vector3 PIDTarget {
1176 set
1177 {
1178 // TODO: add a sanity check -- don't move more than a region or something like that.
1179 _PIDTarget = value;
1180 }
1181 }
1182 public override float PIDTau {
1183 set { _PIDTau = value; }
1184 }
1185 public override bool PIDActive { 1033 public override bool PIDActive {
1186 set { 1034 set {
1187 if (value) 1035 base.MoveToTargetActive = value;
1188 { 1036 EnableActor(MoveToTargetActive, MoveToTargetActorName, delegate()
1189 // We're taking over after this.
1190 ZeroMotion(true);
1191
1192 _targetMotor = new BSVMotor("BSPrim.PIDTarget",
1193 _PIDTau, // timeScale
1194 BSMotor.Infinite, // decay time scale
1195 BSMotor.InfiniteVector, // friction timescale
1196 1f // efficiency
1197 );
1198 _targetMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
1199 _targetMotor.SetTarget(_PIDTarget);
1200 _targetMotor.SetCurrent(RawPosition);
1201 /*
1202 _targetMotor = new BSPIDVMotor("BSPrim.PIDTarget");
1203 _targetMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
1204
1205 _targetMotor.SetTarget(_PIDTarget);
1206 _targetMotor.SetCurrent(RawPosition);
1207 _targetMotor.TimeScale = _PIDTau;
1208 _targetMotor.Efficiency = 1f;
1209 */
1210
1211 RegisterPreStepAction("BSPrim.PIDTarget", LocalID, delegate(float timeStep)
1212 {
1213 if (!IsPhysicallyActive)
1214 {
1215 UnRegisterPreStepAction("BSPrim.PIDTarget", LocalID);
1216 return;
1217 }
1218
1219 OMV.Vector3 origPosition = RawPosition; // DEBUG DEBUG (for printout below)
1220
1221 // 'movePosition' is where we'd like the prim to be at this moment.
1222 OMV.Vector3 movePosition = RawPosition + _targetMotor.Step(timeStep);
1223
1224 // If we are very close to our target, turn off the movement motor.
1225 if (_targetMotor.ErrorIsZero())
1226 {
1227 DetailLog("{0},BSPrim.PIDTarget,zeroMovement,movePos={1},pos={2},mass={3}",
1228 LocalID, movePosition, RawPosition, Mass);
1229 ForcePosition = _targetMotor.TargetValue;
1230 _targetMotor.Enabled = false;
1231 }
1232 else
1233 {
1234 _position = movePosition;
1235 PositionSanityCheck(true /* intaintTime */);
1236 ForcePosition = _position;
1237 }
1238 DetailLog("{0},BSPrim.PIDTarget,move,fromPos={1},movePos={2}", LocalID, origPosition, movePosition);
1239 });
1240 }
1241 else
1242 { 1037 {
1243 // Stop any targetting 1038 return new BSActorMoveToTarget(PhysScene, this, MoveToTargetActorName);
1244 UnRegisterPreStepAction("BSPrim.PIDTarget", LocalID); 1039 });
1245 }
1246 } 1040 }
1247 } 1041 }
1248 1042
@@ -1250,94 +1044,20 @@ public class BSPrim : BSPhysObject
1250 // Hover Height will override MoveTo target's Z 1044 // Hover Height will override MoveTo target's Z
1251 public override bool PIDHoverActive { 1045 public override bool PIDHoverActive {
1252 set { 1046 set {
1253 if (value) 1047 base.HoverActive = value;
1254 { 1048 EnableActor(HoverActive, HoverActorName, delegate()
1255 // Turning the target on
1256 _hoverMotor = new BSFMotor("BSPrim.Hover",
1257 _PIDHoverTau, // timeScale
1258 BSMotor.Infinite, // decay time scale
1259 BSMotor.Infinite, // friction timescale
1260 1f // efficiency
1261 );
1262 _hoverMotor.SetTarget(ComputeCurrentPIDHoverHeight());
1263 _hoverMotor.SetCurrent(RawPosition.Z);
1264 _hoverMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
1265
1266 RegisterPreStepAction("BSPrim.Hover", LocalID, delegate(float timeStep)
1267 {
1268 // Don't do hovering while the object is selected.
1269 if (!IsPhysicallyActive)
1270 return;
1271
1272 _hoverMotor.SetCurrent(RawPosition.Z);
1273 _hoverMotor.SetTarget(ComputeCurrentPIDHoverHeight());
1274 float targetHeight = _hoverMotor.Step(timeStep);
1275
1276 // 'targetHeight' is where we'd like the Z of the prim to be at this moment.
1277 // Compute the amount of force to push us there.
1278 float moveForce = (targetHeight - RawPosition.Z) * Mass;
1279 // Undo anything the object thinks it's doing at the moment
1280 moveForce = -RawVelocity.Z * Mass;
1281
1282 PhysicsScene.PE.ApplyCentralImpulse(PhysBody, new OMV.Vector3(0f, 0f, moveForce));
1283 DetailLog("{0},BSPrim.Hover,move,targHt={1},moveForce={2},mass={3}", LocalID, targetHeight, moveForce, Mass);
1284 });
1285 }
1286 else
1287 { 1049 {
1288 UnRegisterPreStepAction("BSPrim.Hover", LocalID); 1050 return new BSActorHover(PhysScene, this, HoverActorName);
1289 } 1051 });
1290 }
1291 }
1292 public override float PIDHoverHeight {
1293 set { _PIDHoverHeight = value; }
1294 }
1295 public override PIDHoverType PIDHoverType {
1296 set { _PIDHoverType = value; }
1297 }
1298 public override float PIDHoverTau {
1299 set { _PIDHoverTau = value; }
1300 }
1301 // Based on current position, determine what we should be hovering at now.
1302 // Must recompute often. What if we walked offa cliff>
1303 private float ComputeCurrentPIDHoverHeight()
1304 {
1305 float ret = _PIDHoverHeight;
1306 float groundHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
1307
1308 switch (_PIDHoverType)
1309 {
1310 case PIDHoverType.Ground:
1311 ret = groundHeight + _PIDHoverHeight;
1312 break;
1313 case PIDHoverType.GroundAndWater:
1314 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition);
1315 if (groundHeight > waterHeight)
1316 {
1317 ret = groundHeight + _PIDHoverHeight;
1318 }
1319 else
1320 {
1321 ret = waterHeight + _PIDHoverHeight;
1322 }
1323 break;
1324 } 1052 }
1325 return ret;
1326 } 1053 }
1327 1054
1328
1329 // For RotLookAt
1330 public override OMV.Quaternion APIDTarget { set { return; } }
1331 public override bool APIDActive { set { return; } }
1332 public override float APIDStrength { set { return; } }
1333 public override float APIDDamping { set { return; } }
1334
1335 public override void AddForce(OMV.Vector3 force, bool pushforce) { 1055 public override void AddForce(OMV.Vector3 force, bool pushforce) {
1336 // Per documentation, max force is limited. 1056 // Per documentation, max force is limited.
1337 OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); 1057 OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);
1338 1058
1339 // Since this force is being applied in only one step, make this a force per second. 1059 // Since this force is being applied in only one step, make this a force per second.
1340 addForce /= PhysicsScene.LastTimeStep; 1060 addForce /= PhysScene.LastTimeStep;
1341 AddForce(addForce, pushforce, false /* inTaintTime */); 1061 AddForce(addForce, pushforce, false /* inTaintTime */);
1342 } 1062 }
1343 1063
@@ -1352,13 +1072,13 @@ public class BSPrim : BSPhysObject
1352 // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce); 1072 // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce);
1353 1073
1354 OMV.Vector3 addForce = force; 1074 OMV.Vector3 addForce = force;
1355 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate() 1075 PhysScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate()
1356 { 1076 {
1357 // Bullet adds this central force to the total force for this tick 1077 // Bullet adds this central force to the total force for this tick
1358 DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce); 1078 DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce);
1359 if (PhysBody.HasPhysicalBody) 1079 if (PhysBody.HasPhysicalBody)
1360 { 1080 {
1361 PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce); 1081 PhysScene.PE.ApplyCentralForce(PhysBody, addForce);
1362 ActivateIfPhysical(false); 1082 ActivateIfPhysical(false);
1363 } 1083 }
1364 }); 1084 });
@@ -1380,13 +1100,13 @@ public class BSPrim : BSPhysObject
1380 OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude); 1100 OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude);
1381 // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse); 1101 // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse);
1382 1102
1383 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddImpulse", delegate() 1103 PhysScene.TaintedObject(inTaintTime, "BSPrim.AddImpulse", delegate()
1384 { 1104 {
1385 // Bullet adds this impulse immediately to the velocity 1105 // Bullet adds this impulse immediately to the velocity
1386 DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse); 1106 DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse);
1387 if (PhysBody.HasPhysicalBody) 1107 if (PhysBody.HasPhysicalBody)
1388 { 1108 {
1389 PhysicsScene.PE.ApplyCentralImpulse(PhysBody, addImpulse); 1109 PhysScene.PE.ApplyCentralImpulse(PhysBody, addImpulse);
1390 ActivateIfPhysical(false); 1110 ActivateIfPhysical(false);
1391 } 1111 }
1392 }); 1112 });
@@ -1399,20 +1119,18 @@ public class BSPrim : BSPhysObject
1399 } 1119 }
1400 } 1120 }
1401 1121
1402 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 1122 // BSPhysObject.AddAngularForce()
1403 AddAngularForce(force, pushforce, false); 1123 public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime)
1404 }
1405 public void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime)
1406 { 1124 {
1407 if (force.IsFinite()) 1125 if (force.IsFinite())
1408 { 1126 {
1409 OMV.Vector3 angForce = force; 1127 OMV.Vector3 angForce = force;
1410 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate() 1128 PhysScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate()
1411 { 1129 {
1412 if (PhysBody.HasPhysicalBody) 1130 if (PhysBody.HasPhysicalBody)
1413 { 1131 {
1414 DetailLog("{0},BSPrim.AddAngularForce,taint,angForce={1}", LocalID, angForce); 1132 DetailLog("{0},BSPrim.AddAngularForce,taint,angForce={1}", LocalID, angForce);
1415 PhysicsScene.PE.ApplyTorque(PhysBody, angForce); 1133 PhysScene.PE.ApplyTorque(PhysBody, angForce);
1416 ActivateIfPhysical(false); 1134 ActivateIfPhysical(false);
1417 } 1135 }
1418 }); 1136 });
@@ -1431,11 +1149,11 @@ public class BSPrim : BSPhysObject
1431 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) 1149 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime)
1432 { 1150 {
1433 OMV.Vector3 applyImpulse = impulse; 1151 OMV.Vector3 applyImpulse = impulse;
1434 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() 1152 PhysScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate()
1435 { 1153 {
1436 if (PhysBody.HasPhysicalBody) 1154 if (PhysBody.HasPhysicalBody)
1437 { 1155 {
1438 PhysicsScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse); 1156 PhysScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse);
1439 ActivateIfPhysical(false); 1157 ActivateIfPhysical(false);
1440 } 1158 }
1441 }); 1159 });
@@ -1721,9 +1439,9 @@ public class BSPrim : BSPhysObject
1721 volume *= (profileEnd - profileBegin); 1439 volume *= (profileEnd - profileBegin);
1722 1440
1723 returnMass = Density * BSParam.DensityScaleFactor * volume; 1441 returnMass = Density * BSParam.DensityScaleFactor * volume;
1724 DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3}", LocalID, Density, volume, returnMass);
1725 1442
1726 returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass); 1443 returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass);
1444 // DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3}", LocalID, Density, volume, returnMass);
1727 1445
1728 return returnMass; 1446 return returnMass;
1729 }// end CalculateMass 1447 }// end CalculateMass
@@ -1736,13 +1454,14 @@ public class BSPrim : BSPhysObject
1736 { 1454 {
1737 // Create the correct physical representation for this type of object. 1455 // Create the correct physical representation for this type of object.
1738 // Updates base.PhysBody and base.PhysShape with the new information. 1456 // Updates base.PhysBody and base.PhysShape with the new information.
1739 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. 1457 // Ignore 'forceRebuild'. 'GetBodyAndShape' makes the right choices and changes of necessary.
1740 PhysicsScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysicsScene.World, this, null, delegate(BulletBody dBody) 1458 PhysScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysScene.World, this, delegate(BulletBody pBody, BulletShape pShape)
1741 { 1459 {
1742 // Called if the current prim body is about to be destroyed. 1460 // Called if the current prim body is about to be destroyed.
1743 // Remove all the physical dependencies on the old body. 1461 // Remove all the physical dependencies on the old body.
1744 // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...) 1462 // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...)
1745 RemoveBodyDependencies(); 1463 // Note: this virtual function is overloaded by BSPrimLinkable to remove linkset constraints.
1464 RemoveDependencies();
1746 }); 1465 });
1747 1466
1748 // Make sure the properties are set on the new object 1467 // Make sure the properties are set on the new object
@@ -1750,24 +1469,19 @@ public class BSPrim : BSPhysObject
1750 return; 1469 return;
1751 } 1470 }
1752 1471
1753 protected virtual void RemoveBodyDependencies() 1472 // Called at taint-time
1473 protected virtual void RemoveDependencies()
1754 { 1474 {
1755 VehicleController.RemoveBodyDependencies(this); 1475 PhysicalActors.RemoveDependencies();
1756 } 1476 }
1757 1477
1758 // The physics engine says that properties have updated. Update same and inform 1478 // The physics engine says that properties have updated. Update same and inform
1759 // the world that things have changed. 1479 // the world that things have changed.
1760 public override void UpdateProperties(EntityProperties entprop) 1480 public override void UpdateProperties(EntityProperties entprop)
1761 { 1481 {
1482 // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator.
1762 TriggerPreUpdatePropertyAction(ref entprop); 1483 TriggerPreUpdatePropertyAction(ref entprop);
1763 1484
1764 // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet
1765 // TODO: handle physics introduced by Bullet with computed vehicle physics.
1766 if (VehicleController.IsActive)
1767 {
1768 entprop.RotationalVelocity = OMV.Vector3.Zero;
1769 }
1770
1771 // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG 1485 // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG
1772 1486
1773 // Assign directly to the local variables so the normal set actions do not happen 1487 // Assign directly to the local variables so the normal set actions do not happen
@@ -1775,8 +1489,8 @@ public class BSPrim : BSPhysObject
1775 _orientation = entprop.Rotation; 1489 _orientation = entprop.Rotation;
1776 // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be 1490 // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be
1777 // very sensitive to velocity changes. 1491 // very sensitive to velocity changes.
1778 if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(_velocity, BSParam.UpdateVelocityChangeThreshold)) 1492 if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(RawVelocity, BSParam.UpdateVelocityChangeThreshold))
1779 _velocity = entprop.Velocity; 1493 RawVelocity = entprop.Velocity;
1780 _acceleration = entprop.Acceleration; 1494 _acceleration = entprop.Acceleration;
1781 _rotationalVelocity = entprop.RotationalVelocity; 1495 _rotationalVelocity = entprop.RotationalVelocity;
1782 1496
@@ -1786,7 +1500,7 @@ public class BSPrim : BSPhysObject
1786 if (PositionSanityCheck(true /* inTaintTime */ )) 1500 if (PositionSanityCheck(true /* inTaintTime */ ))
1787 { 1501 {
1788 entprop.Position = _position; 1502 entprop.Position = _position;
1789 entprop.Velocity = _velocity; 1503 entprop.Velocity = RawVelocity;
1790 entprop.RotationalVelocity = _rotationalVelocity; 1504 entprop.RotationalVelocity = _rotationalVelocity;
1791 entprop.Acceleration = _acceleration; 1505 entprop.Acceleration = _acceleration;
1792 } 1506 }
@@ -1798,16 +1512,9 @@ public class BSPrim : BSPhysObject
1798 LastEntityProperties = CurrentEntityProperties; 1512 LastEntityProperties = CurrentEntityProperties;
1799 CurrentEntityProperties = entprop; 1513 CurrentEntityProperties = entprop;
1800 1514
1801 base.RequestPhysicsterseUpdate(); 1515 // Note that BSPrim can be overloaded by BSPrimLinkable which controls updates from root and children prims.
1802 /* 1516
1803 else 1517 PhysScene.PostUpdate(this);
1804 {
1805 // For debugging, report the movement of children
1806 DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
1807 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
1808 entprop.Acceleration, entprop.RotationalVelocity);
1809 }
1810 */
1811 } 1518 }
1812} 1519}
1813} 1520}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs
index f1c3b5c..f5ee671 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs
@@ -78,14 +78,16 @@ public class BSPrimDisplaced : BSPrim
78 // Set this sets and computes the displacement from the passed prim to the center-of-mass. 78 // Set this sets and computes the displacement from the passed prim to the center-of-mass.
79 // A user set value for center-of-mass overrides whatever might be passed in here. 79 // A user set value for center-of-mass overrides whatever might be passed in here.
80 // The displacement is in local coordinates (relative to root prim in linkset oriented coordinates). 80 // The displacement is in local coordinates (relative to root prim in linkset oriented coordinates).
81 public virtual void SetEffectiveCenterOfMassW(Vector3 centerOfMassDisplacement) 81 public virtual void SetEffectiveCenterOfMassDisplacement(Vector3 centerOfMassDisplacement)
82 { 82 {
83 Vector3 comDisp; 83 Vector3 comDisp;
84 if (UserSetCenterOfMass.HasValue) 84 if (UserSetCenterOfMassDisplacement.HasValue)
85 comDisp = (OMV.Vector3)UserSetCenterOfMass; 85 comDisp = (OMV.Vector3)UserSetCenterOfMassDisplacement;
86 else 86 else
87 comDisp = centerOfMassDisplacement; 87 comDisp = centerOfMassDisplacement;
88 88
89 DetailLog("{0},BSPrimDisplaced.SetEffectiveCenterOfMassDisplacement,userSet={1},comDisp={2}",
90 LocalID, UserSetCenterOfMassDisplacement.HasValue, comDisp);
89 if (comDisp == Vector3.Zero) 91 if (comDisp == Vector3.Zero)
90 { 92 {
91 // If there is no diplacement. Things get reset. 93 // If there is no diplacement. Things get reset.
@@ -107,9 +109,15 @@ public class BSPrimDisplaced : BSPrim
107 set 109 set
108 { 110 {
109 if (PositionDisplacement != OMV.Vector3.Zero) 111 if (PositionDisplacement != OMV.Vector3.Zero)
110 base.ForcePosition = value - (PositionDisplacement * RawOrientation); 112 {
113 OMV.Vector3 displacedPos = value - (PositionDisplacement * RawOrientation);
114 DetailLog("{0},BSPrimDisplaced.ForcePosition,val={1},disp={2},newPos={3}", LocalID, value, PositionDisplacement, displacedPos);
115 base.ForcePosition = displacedPos;
116 }
111 else 117 else
118 {
112 base.ForcePosition = value; 119 base.ForcePosition = value;
120 }
113 } 121 }
114 } 122 }
115 123
@@ -118,6 +126,7 @@ public class BSPrimDisplaced : BSPrim
118 get { return base.ForceOrientation; } 126 get { return base.ForceOrientation; }
119 set 127 set
120 { 128 {
129 // TODO:
121 base.ForceOrientation = value; 130 base.ForceOrientation = value;
122 } 131 }
123 } 132 }
@@ -143,7 +152,10 @@ public class BSPrimDisplaced : BSPrim
143 { 152 {
144 // Correct for any rotation around the center-of-mass 153 // Correct for any rotation around the center-of-mass
145 // TODO!!! 154 // TODO!!!
146 entprop.Position = entprop.Position + (PositionDisplacement * entprop.Rotation); 155
156 OMV.Vector3 displacedPos = entprop.Position + (PositionDisplacement * entprop.Rotation);
157 DetailLog("{0},BSPrimDisplaced.ForcePosition,physPos={1},disp={2},newPos={3}", LocalID, entprop.Position, PositionDisplacement, displacedPos);
158 entprop.Position = displacedPos;
147 // entprop.Rotation = something; 159 // entprop.Rotation = something;
148 } 160 }
149 161
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs
index d65d407..235da78 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs
@@ -47,9 +47,9 @@ public class BSPrimLinkable : BSPrimDisplaced
47 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) 47 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
48 : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical) 48 : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical)
49 { 49 {
50 Linkset = BSLinkset.Factory(PhysicsScene, this); 50 Linkset = BSLinkset.Factory(PhysScene, this);
51 51
52 PhysicsScene.TaintedObject("BSPrimLinksetCompound.Refresh", delegate() 52 PhysScene.TaintedObject("BSPrimLinksetCompound.Refresh", delegate()
53 { 53 {
54 Linkset.Refresh(this); 54 Linkset.Refresh(this);
55 }); 55 });
@@ -61,9 +61,6 @@ public class BSPrimLinkable : BSPrimDisplaced
61 base.Destroy(); 61 base.Destroy();
62 } 62 }
63 63
64 public override BSPhysicsShapeType PreferredPhysicalShape
65 { get { return Linkset.PreferredPhysicalShape(this); } }
66
67 public override void link(Manager.PhysicsActor obj) 64 public override void link(Manager.PhysicsActor obj)
68 { 65 {
69 BSPrimLinkable parent = obj as BSPrimLinkable; 66 BSPrimLinkable parent = obj as BSPrimLinkable;
@@ -102,7 +99,7 @@ public class BSPrimLinkable : BSPrimDisplaced
102 set 99 set
103 { 100 {
104 base.Position = value; 101 base.Position = value;
105 PhysicsScene.TaintedObject("BSPrimLinkset.setPosition", delegate() 102 PhysScene.TaintedObject("BSPrimLinkset.setPosition", delegate()
106 { 103 {
107 Linkset.UpdateProperties(UpdatedProperties.Position, this); 104 Linkset.UpdateProperties(UpdatedProperties.Position, this);
108 }); 105 });
@@ -116,7 +113,7 @@ public class BSPrimLinkable : BSPrimDisplaced
116 set 113 set
117 { 114 {
118 base.Orientation = value; 115 base.Orientation = value;
119 PhysicsScene.TaintedObject("BSPrimLinkset.setOrientation", delegate() 116 PhysScene.TaintedObject("BSPrimLinkset.setOrientation", delegate()
120 { 117 {
121 Linkset.UpdateProperties(UpdatedProperties.Orientation, this); 118 Linkset.UpdateProperties(UpdatedProperties.Orientation, this);
122 }); 119 });
@@ -149,10 +146,10 @@ public class BSPrimLinkable : BSPrimDisplaced
149 } 146 }
150 147
151 // Body is being taken apart. Remove physical dependencies and schedule a rebuild. 148 // Body is being taken apart. Remove physical dependencies and schedule a rebuild.
152 protected override void RemoveBodyDependencies() 149 protected override void RemoveDependencies()
153 { 150 {
154 Linkset.RemoveBodyDependencies(this); 151 Linkset.RemoveDependencies(this);
155 base.RemoveBodyDependencies(); 152 base.RemoveDependencies();
156 } 153 }
157 154
158 public override void UpdateProperties(EntityProperties entprop) 155 public override void UpdateProperties(EntityProperties entprop)
@@ -163,6 +160,15 @@ public class BSPrimLinkable : BSPrimDisplaced
163 // TODO: this will have to change when linksets are articulated. 160 // TODO: this will have to change when linksets are articulated.
164 base.UpdateProperties(entprop); 161 base.UpdateProperties(entprop);
165 } 162 }
163 /*
164 else
165 {
166 // For debugging, report the movement of children
167 DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
168 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
169 entprop.Acceleration, entprop.RotationalVelocity);
170 }
171 */
166 // The linkset might like to know about changing locations 172 // The linkset might like to know about changing locations
167 Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this); 173 Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this);
168 } 174 }
@@ -176,6 +182,10 @@ public class BSPrimLinkable : BSPrimDisplaced
176 { 182 {
177 return false; 183 return false;
178 } 184 }
185
186 // TODO: handle collisions of other objects with with children of linkset.
187 // This is a problem for LinksetCompound since the children are packed into the root.
188
179 return base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth); 189 return base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth);
180 } 190 }
181} 191}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index e6aefd5..423c389 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -56,12 +56,23 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
56 public string BulletEngineName { get; private set; } 56 public string BulletEngineName { get; private set; }
57 public BSAPITemplate PE; 57 public BSAPITemplate PE;
58 58
59 // If the physics engine is running on a separate thread
60 public Thread m_physicsThread;
61
59 public Dictionary<uint, BSPhysObject> PhysObjects; 62 public Dictionary<uint, BSPhysObject> PhysObjects;
60 public BSShapeCollection Shapes; 63 public BSShapeCollection Shapes;
61 64
62 // Keeping track of the objects with collisions so we can report begin and end of a collision 65 // Keeping track of the objects with collisions so we can report begin and end of a collision
63 public HashSet<BSPhysObject> ObjectsWithCollisions = new HashSet<BSPhysObject>(); 66 public HashSet<BSPhysObject> ObjectsWithCollisions = new HashSet<BSPhysObject>();
64 public HashSet<BSPhysObject> ObjectsWithNoMoreCollisions = new HashSet<BSPhysObject>(); 67 public HashSet<BSPhysObject> ObjectsWithNoMoreCollisions = new HashSet<BSPhysObject>();
68
69 // All the collision processing is protected with this lock object
70 public Object CollisionLock = new Object();
71
72 // Properties are updated here
73 public Object UpdateLock = new Object();
74 public HashSet<BSPhysObject> ObjectsWithUpdates = new HashSet<BSPhysObject>();
75
65 // Keep track of all the avatars so we can send them a collision event 76 // Keep track of all the avatars so we can send them a collision event
66 // every tick so OpenSim will update its animation. 77 // every tick so OpenSim will update its animation.
67 private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>(); 78 private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>();
@@ -77,12 +88,19 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
77 public BSConstraintCollection Constraints { get; private set; } 88 public BSConstraintCollection Constraints { get; private set; }
78 89
79 // Simulation parameters 90 // Simulation parameters
91 internal float m_physicsStepTime; // if running independently, the interval simulated by default
92
80 internal int m_maxSubSteps; 93 internal int m_maxSubSteps;
81 internal float m_fixedTimeStep; 94 internal float m_fixedTimeStep;
82 internal long m_simulationStep = 0; 95
83 internal float NominalFrameRate { get; set; } 96 internal float m_simulatedTime; // the time simulated previously. Used for physics framerate calc.
97
98 internal long m_simulationStep = 0; // The current simulation step.
84 public long SimulationStep { get { return m_simulationStep; } } 99 public long SimulationStep { get { return m_simulationStep; } }
85 internal float LastTimeStep { get; private set; } 100
101 internal float LastTimeStep { get; private set; } // The simulation time from the last invocation of Simulate()
102
103 internal float NominalFrameRate { get; set; } // Parameterized ideal frame rate that simulation is scaled to
86 104
87 // Physical objects can register for prestep or poststep events 105 // Physical objects can register for prestep or poststep events
88 public delegate void PreStepAction(float timeStep); 106 public delegate void PreStepAction(float timeStep);
@@ -90,7 +108,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
90 public event PreStepAction BeforeStep; 108 public event PreStepAction BeforeStep;
91 public event PostStepAction AfterStep; 109 public event PostStepAction AfterStep;
92 110
93 // A value of the time now so all the collision and update routines do not have to get their own 111 // A value of the time 'now' so all the collision and update routines do not have to get their own
94 // Set to 'now' just before all the prims and actors are called for collisions and updates 112 // Set to 'now' just before all the prims and actors are called for collisions and updates
95 public int SimulationNowTime { get; private set; } 113 public int SimulationNowTime { get; private set; }
96 114
@@ -188,6 +206,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
188 PhysObjects = new Dictionary<uint, BSPhysObject>(); 206 PhysObjects = new Dictionary<uint, BSPhysObject>();
189 Shapes = new BSShapeCollection(this); 207 Shapes = new BSShapeCollection(this);
190 208
209 m_simulatedTime = 0f;
210 LastTimeStep = 0.1f;
211
191 // Allocate pinned memory to pass parameters. 212 // Allocate pinned memory to pass parameters.
192 UnmanagedParams = new ConfigurationParameters[1]; 213 UnmanagedParams = new ConfigurationParameters[1];
193 214
@@ -227,10 +248,20 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
227 TerrainManager = new BSTerrainManager(this); 248 TerrainManager = new BSTerrainManager(this);
228 TerrainManager.CreateInitialGroundPlaneAndTerrain(); 249 TerrainManager.CreateInitialGroundPlaneAndTerrain();
229 250
251 // Put some informational messages into the log file.
230 m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation); 252 m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation);
231 253
232 InTaintTime = false; 254 InTaintTime = false;
233 m_initialized = true; 255 m_initialized = true;
256
257 // If the physics engine runs on its own thread, start same.
258 if (BSParam.UseSeparatePhysicsThread)
259 {
260 // The physics simulation should happen independently of the heartbeat loop
261 m_physicsThread = new Thread(BulletSPluginPhysicsThread);
262 m_physicsThread.Name = BulletEngineName;
263 m_physicsThread.Start();
264 }
234 } 265 }
235 266
236 // All default parameter values are set here. There should be no values set in the 267 // All default parameter values are set here. There should be no values set in the
@@ -268,6 +299,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
268 // Do any replacements in the parameters 299 // Do any replacements in the parameters
269 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); 300 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
270 } 301 }
302 else
303 {
304 // Nothing in the configuration INI file so assume unmanaged and other defaults.
305 BulletEngineName = "BulletUnmanaged";
306 m_physicsLoggingEnabled = false;
307 VehicleLoggingEnabled = false;
308 }
271 309
272 // The material characteristics. 310 // The material characteristics.
273 BSMaterials.InitializeFromDefaults(Params); 311 BSMaterials.InitializeFromDefaults(Params);
@@ -311,11 +349,22 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
311 349
312 switch (selectionName) 350 switch (selectionName)
313 { 351 {
352 case "bullet":
314 case "bulletunmanaged": 353 case "bulletunmanaged":
315 ret = new BSAPIUnman(engineName, this); 354 ret = new BSAPIUnman(engineName, this);
316 break; 355 break;
317 case "bulletxna": 356 case "bulletxna":
318 ret = new BSAPIXNA(engineName, this); 357 ret = new BSAPIXNA(engineName, this);
358 // Disable some features that are not implemented in BulletXNA
359 m_log.InfoFormat("{0} Disabling some physics features not implemented by BulletXNA", LogHeader);
360 m_log.InfoFormat("{0} Disabling ShouldUseBulletHACD", LogHeader);
361 BSParam.ShouldUseBulletHACD = false;
362 m_log.InfoFormat("{0} Disabling ShouldUseSingleConvexHullForPrims", LogHeader);
363 BSParam.ShouldUseSingleConvexHullForPrims = false;
364 m_log.InfoFormat("{0} Disabling ShouldUseGImpactShapeForPrims", LogHeader);
365 BSParam.ShouldUseGImpactShapeForPrims = false;
366 m_log.InfoFormat("{0} Setting terrain implimentation to Heightmap", LogHeader);
367 BSParam.TerrainImplementation = (float)BSTerrainPhys.TerrainImplementation.Heightmap;
319 break; 368 break;
320 } 369 }
321 370
@@ -463,7 +512,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
463 512
464 if (!m_initialized) return null; 513 if (!m_initialized) return null;
465 514
466 DetailLog("{0},BSScene.AddPrimShape,call", localID); 515 // DetailLog("{0},BSScene.AddPrimShape,call", localID);
467 516
468 BSPhysObject prim = new BSPrimLinkable(localID, primName, this, position, size, rotation, pbs, isPhysical); 517 BSPhysObject prim = new BSPrimLinkable(localID, primName, this, position, size, rotation, pbs, isPhysical);
469 lock (PhysObjects) PhysObjects.Add(localID, prim); 518 lock (PhysObjects) PhysObjects.Add(localID, prim);
@@ -478,25 +527,41 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
478 #endregion // Prim and Avatar addition and removal 527 #endregion // Prim and Avatar addition and removal
479 528
480 #region Simulation 529 #region Simulation
481 // Simulate one timestep 530
531 // Call from the simulator to send physics information to the simulator objects.
532 // This pushes all the collision and property update events into the objects in
533 // the simulator and, since it is on the heartbeat thread, there is an implicit
534 // locking of those data structures from other heartbeat events.
535 // If the physics engine is running on a separate thread, the update information
536 // will be in the ObjectsWithCollions and ObjectsWithUpdates structures.
482 public override float Simulate(float timeStep) 537 public override float Simulate(float timeStep)
483 { 538 {
539 if (!BSParam.UseSeparatePhysicsThread)
540 {
541 DoPhysicsStep(timeStep);
542 }
543 return SendUpdatesToSimulator(timeStep);
544 }
545
546 // Call the physics engine to do one 'timeStep' and collect collisions and updates
547 // into ObjectsWithCollisions and ObjectsWithUpdates data structures.
548 private void DoPhysicsStep(float timeStep)
549 {
484 // prevent simulation until we've been initialized 550 // prevent simulation until we've been initialized
485 if (!m_initialized) return 5.0f; 551 if (!m_initialized) return;
486 552
487 LastTimeStep = timeStep; 553 LastTimeStep = timeStep;
488 554
489 int updatedEntityCount = 0; 555 int updatedEntityCount = 0;
490 int collidersCount = 0; 556 int collidersCount = 0;
491 557
492 int beforeTime = 0; 558 int beforeTime = Util.EnvironmentTickCount();
493 int simTime = 0; 559 int simTime = 0;
494 560
495 // update the prim states while we know the physics engine is not busy
496 int numTaints = _taintOperations.Count; 561 int numTaints = _taintOperations.Count;
497
498 InTaintTime = true; // Only used for debugging so locking is not necessary. 562 InTaintTime = true; // Only used for debugging so locking is not necessary.
499 563
564 // update the prim states while we know the physics engine is not busy
500 ProcessTaints(); 565 ProcessTaints();
501 566
502 // Some of the physical objects requre individual, pre-step calls 567 // Some of the physical objects requre individual, pre-step calls
@@ -519,18 +584,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
519 int numSubSteps = 0; 584 int numSubSteps = 0;
520 try 585 try
521 { 586 {
522 if (PhysicsLogging.Enabled)
523 beforeTime = Util.EnvironmentTickCount();
524
525 numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount); 587 numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount);
526 588
527 if (PhysicsLogging.Enabled)
528 {
529 simTime = Util.EnvironmentTickCountSubtract(beforeTime);
530 DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}",
531 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps,
532 updatedEntityCount, collidersCount, ObjectsWithCollisions.Count);
533 }
534 } 589 }
535 catch (Exception e) 590 catch (Exception e)
536 { 591 {
@@ -542,77 +597,62 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
542 collidersCount = 0; 597 collidersCount = 0;
543 } 598 }
544 599
600 // Make the physics engine dump useful statistics periodically
545 if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0)) 601 if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0))
546 PE.DumpPhysicsStatistics(World); 602 PE.DumpPhysicsStatistics(World);
547 603
548 // Get a value for 'now' so all the collision and update routines don't have to get their own. 604 // Get a value for 'now' so all the collision and update routines don't have to get their own.
549 SimulationNowTime = Util.EnvironmentTickCount(); 605 SimulationNowTime = Util.EnvironmentTickCount();
550 606
551 // If there were collisions, process them by sending the event to the prim. 607 // Send collision information to the colliding objects. The objects decide if the collision
552 // Collisions must be processed before updates. 608 // is 'real' (like linksets don't collide with themselves) and the individual objects
553 if (collidersCount > 0) 609 // know if the simulator has subscribed to collisions.
610 lock (CollisionLock)
554 { 611 {
555 for (int ii = 0; ii < collidersCount; ii++) 612 if (collidersCount > 0)
556 { 613 {
557 uint cA = m_collisionArray[ii].aID; 614 for (int ii = 0; ii < collidersCount; ii++)
558 uint cB = m_collisionArray[ii].bID;
559 Vector3 point = m_collisionArray[ii].point;
560 Vector3 normal = m_collisionArray[ii].normal;
561 float penetration = m_collisionArray[ii].penetration;
562 SendCollision(cA, cB, point, normal, penetration);
563 SendCollision(cB, cA, point, -normal, penetration);
564 }
565 }
566
567 // The above SendCollision's batch up the collisions on the objects.
568 // Now push the collisions into the simulator.
569 if (ObjectsWithCollisions.Count > 0)
570 {
571 foreach (BSPhysObject bsp in ObjectsWithCollisions)
572 if (!bsp.SendCollisions())
573 { 615 {
574 // If the object is done colliding, see that it's removed from the colliding list 616 uint cA = m_collisionArray[ii].aID;
575 ObjectsWithNoMoreCollisions.Add(bsp); 617 uint cB = m_collisionArray[ii].bID;
618 Vector3 point = m_collisionArray[ii].point;
619 Vector3 normal = m_collisionArray[ii].normal;
620 float penetration = m_collisionArray[ii].penetration;
621 SendCollision(cA, cB, point, normal, penetration);
622 SendCollision(cB, cA, point, -normal, penetration);
576 } 623 }
624 }
577 } 625 }
578 626
579 // This is a kludge to get avatar movement updates. 627 // If any of the objects had updated properties, tell the managed objects about the update
580 // The simulator expects collisions for avatars even if there are have been no collisions. 628 // and remember that there was a change so it will be passed to the simulator.
581 // The event updates avatar animations and stuff. 629 lock (UpdateLock)
582 // If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
583 foreach (BSPhysObject bsp in m_avatars)
584 if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice
585 bsp.SendCollisions();
586
587 // Objects that are done colliding are removed from the ObjectsWithCollisions list.
588 // Not done above because it is inside an iteration of ObjectWithCollisions.
589 // This complex collision processing is required to create an empty collision
590 // event call after all real collisions have happened on an object. This enables
591 // the simulator to generate the 'collision end' event.
592 if (ObjectsWithNoMoreCollisions.Count > 0)
593 {
594 foreach (BSPhysObject po in ObjectsWithNoMoreCollisions)
595 ObjectsWithCollisions.Remove(po);
596 ObjectsWithNoMoreCollisions.Clear();
597 }
598 // Done with collisions.
599
600 // If any of the objects had updated properties, tell the object it has been changed by the physics engine
601 if (updatedEntityCount > 0)
602 { 630 {
603 for (int ii = 0; ii < updatedEntityCount; ii++) 631 if (updatedEntityCount > 0)
604 { 632 {
605 EntityProperties entprop = m_updateArray[ii]; 633 for (int ii = 0; ii < updatedEntityCount; ii++)
606 BSPhysObject pobj;
607 if (PhysObjects.TryGetValue(entprop.ID, out pobj))
608 { 634 {
609 pobj.UpdateProperties(entprop); 635 EntityProperties entprop = m_updateArray[ii];
636 BSPhysObject pobj;
637 if (PhysObjects.TryGetValue(entprop.ID, out pobj))
638 {
639 pobj.UpdateProperties(entprop);
640 }
610 } 641 }
611 } 642 }
612 } 643 }
613 644
645 // Some actors want to know when the simulation step is complete.
614 TriggerPostStepEvent(timeStep); 646 TriggerPostStepEvent(timeStep);
615 647
648 simTime = Util.EnvironmentTickCountSubtract(beforeTime);
649 if (PhysicsLogging.Enabled)
650 {
651 DetailLog("{0},DoPhysicsStep,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}",
652 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps,
653 updatedEntityCount, collidersCount, ObjectsWithCollisions.Count);
654 }
655
616 // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. 656 // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world.
617 // Only enable this in a limited test world with few objects. 657 // Only enable this in a limited test world with few objects.
618 if (m_physicsPhysicalDumpEnabled) 658 if (m_physicsPhysicalDumpEnabled)
@@ -621,7 +661,84 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
621 // The physics engine returns the number of milliseconds it simulated this call. 661 // The physics engine returns the number of milliseconds it simulated this call.
622 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. 662 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
623 // Multiply by a fixed nominal frame rate to give a rate similar to the simulator (usually 55). 663 // Multiply by a fixed nominal frame rate to give a rate similar to the simulator (usually 55).
624 return (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate; 664 m_simulatedTime += (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate;
665 }
666
667 // Called by a BSPhysObject to note that it has changed properties and this information
668 // should be passed up to the simulator at the proper time.
669 // Note: this is called by the BSPhysObject from invocation via DoPhysicsStep() above so
670 // this is is under UpdateLock.
671 public void PostUpdate(BSPhysObject updatee)
672 {
673 ObjectsWithUpdates.Add(updatee);
674 }
675
676 // The simulator thinks it is physics time so return all the collisions and position
677 // updates that were collected in actual physics simulation.
678 private float SendUpdatesToSimulator(float timeStep)
679 {
680 if (!m_initialized) return 5.0f;
681
682 DetailLog("{0},SendUpdatesToSimulator,collisions={1},updates={2},simedTime={3}",
683 BSScene.DetailLogZero, ObjectsWithCollisions.Count, ObjectsWithUpdates.Count, m_simulatedTime);
684 // Push the collisions into the simulator.
685 lock (CollisionLock)
686 {
687 if (ObjectsWithCollisions.Count > 0)
688 {
689 foreach (BSPhysObject bsp in ObjectsWithCollisions)
690 if (!bsp.SendCollisions())
691 {
692 // If the object is done colliding, see that it's removed from the colliding list
693 ObjectsWithNoMoreCollisions.Add(bsp);
694 }
695 }
696
697 // This is a kludge to get avatar movement updates.
698 // The simulator expects collisions for avatars even if there are have been no collisions.
699 // The event updates avatar animations and stuff.
700 // If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
701 foreach (BSPhysObject bsp in m_avatars)
702 if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice
703 bsp.SendCollisions();
704
705 // Objects that are done colliding are removed from the ObjectsWithCollisions list.
706 // Not done above because it is inside an iteration of ObjectWithCollisions.
707 // This complex collision processing is required to create an empty collision
708 // event call after all real collisions have happened on an object. This allows
709 // the simulator to generate the 'collision end' event.
710 if (ObjectsWithNoMoreCollisions.Count > 0)
711 {
712 foreach (BSPhysObject po in ObjectsWithNoMoreCollisions)
713 ObjectsWithCollisions.Remove(po);
714 ObjectsWithNoMoreCollisions.Clear();
715 }
716 }
717
718 // Call the simulator for each object that has physics property updates.
719 HashSet<BSPhysObject> updatedObjects = null;
720 lock (UpdateLock)
721 {
722 if (ObjectsWithUpdates.Count > 0)
723 {
724 updatedObjects = ObjectsWithUpdates;
725 ObjectsWithUpdates = new HashSet<BSPhysObject>();
726 }
727 }
728 if (updatedObjects != null)
729 {
730 foreach (BSPhysObject obj in updatedObjects)
731 {
732 obj.RequestPhysicsterseUpdate();
733 }
734 updatedObjects.Clear();
735 }
736
737 // Return the framerate simulated to give the above returned results.
738 // (Race condition here but this is just bookkeeping so rare mistakes do not merit a lock).
739 float simTime = m_simulatedTime;
740 m_simulatedTime = 0f;
741 return simTime;
625 } 742 }
626 743
627 // Something has collided 744 // Something has collided
@@ -640,7 +757,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
640 return; 757 return;
641 } 758 }
642 759
643 // The terrain is not in the physical object list so 'collidee' can be null when Collide() is called. 760 // Note: the terrain is not in the physical object list so 'collidee' can be null when Collide() is called.
644 BSPhysObject collidee = null; 761 BSPhysObject collidee = null;
645 PhysObjects.TryGetValue(collidingWith, out collidee); 762 PhysObjects.TryGetValue(collidingWith, out collidee);
646 763
@@ -648,13 +765,39 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
648 765
649 if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) 766 if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration))
650 { 767 {
651 // If a collision was posted, remember to send it to the simulator 768 // If a collision was 'good', remember to send it to the simulator
652 ObjectsWithCollisions.Add(collider); 769 ObjectsWithCollisions.Add(collider);
653 } 770 }
654 771
655 return; 772 return;
656 } 773 }
657 774
775 public void BulletSPluginPhysicsThread()
776 {
777 while (m_initialized)
778 {
779 int beginSimulationRealtimeMS = Util.EnvironmentTickCount();
780 DoPhysicsStep(BSParam.PhysicsTimeStep);
781 int simulationRealtimeMS = Util.EnvironmentTickCountSubtract(beginSimulationRealtimeMS);
782 int simulationTimeVsRealtimeDifferenceMS = ((int)(BSParam.PhysicsTimeStep*1000f)) - simulationRealtimeMS;
783
784 if (simulationTimeVsRealtimeDifferenceMS > 0)
785 {
786 // The simulation of the time interval took less than realtime.
787 // Do a sleep for the rest of realtime.
788 DetailLog("{0},BulletSPluginPhysicsThread,sleeping={1}", BSScene.DetailLogZero, simulationTimeVsRealtimeDifferenceMS);
789 Thread.Sleep(simulationTimeVsRealtimeDifferenceMS);
790 }
791 else
792 {
793 // The simulation took longer than realtime.
794 // Do some scaling of simulation time.
795 // TODO.
796 DetailLog("{0},BulletSPluginPhysicsThread,longerThanRealtime={1}", BSScene.DetailLogZero, simulationTimeVsRealtimeDifferenceMS);
797 }
798 }
799 }
800
658 #endregion // Simulation 801 #endregion // Simulation
659 802
660 public override void GetResults() { } 803 public override void GetResults() { }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
index 220fbbc..32bbc8f 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
@@ -38,38 +38,15 @@ public sealed class BSShapeCollection : IDisposable
38{ 38{
39 private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]"; 39 private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]";
40 40
41 private BSScene PhysicsScene { get; set; } 41 private BSScene m_physicsScene { get; set; }
42 42
43 private Object m_collectionActivityLock = new Object(); 43 private Object m_collectionActivityLock = new Object();
44 44
45 // Description of a Mesh
46 private struct MeshDesc
47 {
48 public BulletShape shape;
49 public int referenceCount;
50 public DateTime lastReferenced;
51 public UInt64 shapeKey;
52 }
53
54 // Description of a hull.
55 // Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations.
56 private struct HullDesc
57 {
58 public BulletShape shape;
59 public int referenceCount;
60 public DateTime lastReferenced;
61 public UInt64 shapeKey;
62 }
63
64 // The sharable set of meshes and hulls. Indexed by their shape hash.
65 private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>();
66 private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>();
67
68 private bool DDetail = false; 45 private bool DDetail = false;
69 46
70 public BSShapeCollection(BSScene physScene) 47 public BSShapeCollection(BSScene physScene)
71 { 48 {
72 PhysicsScene = physScene; 49 m_physicsScene = physScene;
73 // Set the next to 'true' for very detailed shape update detailed logging (detailed details?) 50 // Set the next to 'true' for very detailed shape update detailed logging (detailed details?)
74 // While detailed debugging is still active, this is better than commenting out all the 51 // While detailed debugging is still active, this is better than commenting out all the
75 // DetailLog statements. When debugging slows down, this and the protected logging 52 // DetailLog statements. When debugging slows down, this and the protected logging
@@ -86,22 +63,18 @@ public sealed class BSShapeCollection : IDisposable
86 // Mostly used for changing bodies out from under Linksets. 63 // Mostly used for changing bodies out from under Linksets.
87 // Useful for other cases where parameters need saving. 64 // Useful for other cases where parameters need saving.
88 // Passing 'null' says no callback. 65 // Passing 'null' says no callback.
89 public delegate void ShapeDestructionCallback(BulletShape shape); 66 public delegate void PhysicalDestructionCallback(BulletBody pBody, BulletShape pShape);
90 public delegate void BodyDestructionCallback(BulletBody body);
91 67
92 // Called to update/change the body and shape for an object. 68 // Called to update/change the body and shape for an object.
93 // First checks the shape and updates that if necessary then makes 69 // The object has some shape and body on it. Here we decide if that is the correct shape
94 // sure the body is of the right type. 70 // for the current state of the object (static/dynamic/...).
71 // If bodyCallback is not null, it is called if either the body or the shape are changed
72 // so dependencies (like constraints) can be removed before the physical object is dereferenced.
95 // Return 'true' if either the body or the shape changed. 73 // Return 'true' if either the body or the shape changed.
96 // 'shapeCallback' and 'bodyCallback' are, if non-null, functions called just before 74 // Called at taint-time.
97 // the current shape or body is destroyed. This allows the caller to remove any 75 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim, PhysicalDestructionCallback bodyCallback)
98 // higher level dependencies on the shape or body. Mostly used for LinkSets to
99 // remove the physical constraints before the body is destroyed.
100 // Called at taint-time!!
101 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim,
102 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
103 { 76 {
104 PhysicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape"); 77 m_physicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape");
105 78
106 bool ret = false; 79 bool ret = false;
107 80
@@ -111,12 +84,12 @@ public sealed class BSShapeCollection : IDisposable
111 // Do we have the correct geometry for this type of object? 84 // Do we have the correct geometry for this type of object?
112 // Updates prim.BSShape with information/pointers to shape. 85 // Updates prim.BSShape with information/pointers to shape.
113 // Returns 'true' of BSShape is changed to a new shape. 86 // Returns 'true' of BSShape is changed to a new shape.
114 bool newGeom = CreateGeom(forceRebuild, prim, shapeCallback); 87 bool newGeom = CreateGeom(forceRebuild, prim, bodyCallback);
115 // If we had to select a new shape geometry for the object, 88 // If we had to select a new shape geometry for the object,
116 // rebuild the body around it. 89 // rebuild the body around it.
117 // Updates prim.BSBody with information/pointers to requested body 90 // Updates prim.BSBody with information/pointers to requested body
118 // Returns 'true' if BSBody was changed. 91 // Returns 'true' if BSBody was changed.
119 bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, bodyCallback); 92 bool newBody = CreateBody((newGeom || forceRebuild), prim, m_physicsScene.World, bodyCallback);
120 ret = newGeom || newBody; 93 ret = newGeom || newBody;
121 } 94 }
122 DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}", 95 DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}",
@@ -127,274 +100,20 @@ public sealed class BSShapeCollection : IDisposable
127 100
128 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim) 101 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim)
129 { 102 {
130 return GetBodyAndShape(forceRebuild, sim, prim, null, null); 103 return GetBodyAndShape(forceRebuild, sim, prim, null);
131 }
132
133 // Track another user of a body.
134 // We presume the caller has allocated the body.
135 // Bodies only have one user so the body is just put into the world if not already there.
136 private void ReferenceBody(BulletBody body)
137 {
138 lock (m_collectionActivityLock)
139 {
140 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body);
141 if (!PhysicsScene.PE.IsInWorld(PhysicsScene.World, body))
142 {
143 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, body);
144 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
145 }
146 }
147 }
148
149 // Release the usage of a body.
150 // Called when releasing use of a BSBody. BSShape is handled separately.
151 // Called in taint time.
152 public void DereferenceBody(BulletBody body, BodyDestructionCallback bodyCallback )
153 {
154 if (!body.HasPhysicalBody)
155 return;
156
157 PhysicsScene.AssertInTaintTime("BSShapeCollection.DereferenceBody");
158
159 lock (m_collectionActivityLock)
160 {
161 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1}", body.ID, body);
162 // If the caller needs to know the old body is going away, pass the event up.
163 if (bodyCallback != null) bodyCallback(body);
164
165 if (PhysicsScene.PE.IsInWorld(PhysicsScene.World, body))
166 {
167 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, body);
168 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body);
169 }
170
171 // Zero any reference to the shape so it is not freed when the body is deleted.
172 PhysicsScene.PE.SetCollisionShape(PhysicsScene.World, body, null);
173 PhysicsScene.PE.DestroyObject(PhysicsScene.World, body);
174 }
175 }
176
177 // Track the datastructures and use count for a shape.
178 // When creating a hull, this is called first to reference the mesh
179 // and then again to reference the hull.
180 // Meshes and hulls for the same shape have the same hash key.
181 // NOTE that native shapes are not added to the mesh list or removed.
182 // Returns 'true' if this is the initial reference to the shape. Otherwise reused.
183 public bool ReferenceShape(BulletShape shape)
184 {
185 bool ret = false;
186 switch (shape.type)
187 {
188 case BSPhysicsShapeType.SHAPE_MESH:
189 MeshDesc meshDesc;
190 if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
191 {
192 // There is an existing instance of this mesh.
193 meshDesc.referenceCount++;
194 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}",
195 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
196 }
197 else
198 {
199 // This is a new reference to a mesh
200 meshDesc.shape = shape.Clone();
201 meshDesc.shapeKey = shape.shapeKey;
202 // We keep a reference to the underlying IMesh data so a hull can be built
203 meshDesc.referenceCount = 1;
204 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}",
205 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
206 ret = true;
207 }
208 meshDesc.lastReferenced = System.DateTime.Now;
209 Meshes[shape.shapeKey] = meshDesc;
210 break;
211 case BSPhysicsShapeType.SHAPE_HULL:
212 HullDesc hullDesc;
213 if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
214 {
215 // There is an existing instance of this hull.
216 hullDesc.referenceCount++;
217 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}",
218 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
219 }
220 else
221 {
222 // This is a new reference to a hull
223 hullDesc.shape = shape.Clone();
224 hullDesc.shapeKey = shape.shapeKey;
225 hullDesc.referenceCount = 1;
226 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}",
227 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
228 ret = true;
229
230 }
231 hullDesc.lastReferenced = System.DateTime.Now;
232 Hulls[shape.shapeKey] = hullDesc;
233 break;
234 case BSPhysicsShapeType.SHAPE_UNKNOWN:
235 break;
236 default:
237 // Native shapes are not tracked and they don't go into any list
238 break;
239 }
240 return ret;
241 } 104 }
242 105
243 // Release the usage of a shape. 106 // If the existing prim's shape is to be replaced, remove the tie to the existing shape
244 public void DereferenceShape(BulletShape shape, ShapeDestructionCallback shapeCallback) 107 // before replacing it.
108 private void DereferenceExistingShape(BSPhysObject prim, PhysicalDestructionCallback shapeCallback)
245 { 109 {
246 if (!shape.HasPhysicalShape) 110 if (prim.PhysShape.HasPhysicalShape)
247 return;
248
249 PhysicsScene.AssertInTaintTime("BSShapeCollection.DereferenceShape");
250
251 if (shape.HasPhysicalShape)
252 {
253 if (shape.isNativeShape)
254 {
255 // Native shapes are not tracked and are released immediately
256 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1}",
257 BSScene.DetailLogZero, shape.AddrString);
258 if (shapeCallback != null) shapeCallback(shape);
259 PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape);
260 }
261 else
262 {
263 switch (shape.type)
264 {
265 case BSPhysicsShapeType.SHAPE_HULL:
266 DereferenceHull(shape, shapeCallback);
267 break;
268 case BSPhysicsShapeType.SHAPE_MESH:
269 DereferenceMesh(shape, shapeCallback);
270 break;
271 case BSPhysicsShapeType.SHAPE_COMPOUND:
272 DereferenceCompound(shape, shapeCallback);
273 break;
274 case BSPhysicsShapeType.SHAPE_UNKNOWN:
275 break;
276 default:
277 break;
278 }
279 }
280 }
281 }
282
283 // Count down the reference count for a mesh shape
284 // Called at taint-time.
285 private void DereferenceMesh(BulletShape shape, ShapeDestructionCallback shapeCallback)
286 {
287 MeshDesc meshDesc;
288 if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
289 { 111 {
290 meshDesc.referenceCount--; 112 if (shapeCallback != null)
291 // TODO: release the Bullet storage 113 shapeCallback(prim.PhysBody, prim.PhysShape.physShapeInfo);
292 if (shapeCallback != null) shapeCallback(shape); 114 prim.PhysShape.Dereference(m_physicsScene);
293 meshDesc.lastReferenced = System.DateTime.Now;
294 Meshes[shape.shapeKey] = meshDesc;
295 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}",
296 BSScene.DetailLogZero, shape, meshDesc.referenceCount);
297
298 }
299 }
300
301 // Count down the reference count for a hull shape
302 // Called at taint-time.
303 private void DereferenceHull(BulletShape shape, ShapeDestructionCallback shapeCallback)
304 {
305 HullDesc hullDesc;
306 if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
307 {
308 hullDesc.referenceCount--;
309 // TODO: release the Bullet storage (aging old entries?)
310
311 // Tell upper layers that, if they have dependencies on this shape, this link is going away
312 if (shapeCallback != null) shapeCallback(shape);
313
314 hullDesc.lastReferenced = System.DateTime.Now;
315 Hulls[shape.shapeKey] = hullDesc;
316 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}",
317 BSScene.DetailLogZero, shape, hullDesc.referenceCount);
318 }
319 }
320
321 // Remove a reference to a compound shape.
322 // Taking a compound shape apart is a little tricky because if you just delete the
323 // physical shape, it will free all the underlying children. We can't do that because
324 // they could be shared. So, this removes each of the children from the compound and
325 // dereferences them separately before destroying the compound collision object itself.
326 // Called at taint-time.
327 private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback)
328 {
329 if (!PhysicsScene.PE.IsCompound(shape))
330 {
331 // Failed the sanity check!!
332 PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}",
333 LogHeader, shape.type, shape.AddrString);
334 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
335 BSScene.DetailLogZero, shape.type, shape.AddrString);
336 return;
337 }
338
339 int numChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(shape);
340 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren);
341
342 for (int ii = numChildren - 1; ii >= 0; ii--)
343 {
344 BulletShape childShape = PhysicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(shape, ii);
345 DereferenceAnonCollisionShape(childShape);
346 }
347 PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape);
348 }
349
350 // Sometimes we have a pointer to a collision shape but don't know what type it is.
351 // Figure out type and call the correct dereference routine.
352 // Called at taint-time.
353 private void DereferenceAnonCollisionShape(BulletShape shapeInfo)
354 {
355 MeshDesc meshDesc;
356 HullDesc hullDesc;
357
358 if (TryGetMeshByPtr(shapeInfo, out meshDesc))
359 {
360 shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH;
361 shapeInfo.shapeKey = meshDesc.shapeKey;
362 }
363 else
364 {
365 if (TryGetHullByPtr(shapeInfo, out hullDesc))
366 {
367 shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL;
368 shapeInfo.shapeKey = hullDesc.shapeKey;
369 }
370 else
371 {
372 if (PhysicsScene.PE.IsCompound(shapeInfo))
373 {
374 shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND;
375 }
376 else
377 {
378 if (PhysicsScene.PE.IsNativeShape(shapeInfo))
379 {
380 shapeInfo.isNativeShape = true;
381 shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter)
382 }
383 }
384 }
385 }
386
387 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo);
388
389 if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN)
390 {
391 DereferenceShape(shapeInfo, null);
392 }
393 else
394 {
395 PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}",
396 LogHeader, PhysicsScene.RegionName, shapeInfo.AddrString);
397 } 115 }
116 prim.PhysShape = new BSShapeNull();
398 } 117 }
399 118
400 // Create the geometry information in Bullet for later use. 119 // Create the geometry information in Bullet for later use.
@@ -405,60 +124,41 @@ public sealed class BSShapeCollection : IDisposable
405 // Info in prim.BSShape is updated to the new shape. 124 // Info in prim.BSShape is updated to the new shape.
406 // Returns 'true' if the geometry was rebuilt. 125 // Returns 'true' if the geometry was rebuilt.
407 // Called at taint-time! 126 // Called at taint-time!
408 private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) 127 private bool CreateGeom(bool forceRebuild, BSPhysObject prim, PhysicalDestructionCallback shapeCallback)
409 { 128 {
410 bool ret = false; 129 bool ret = false;
411 bool haveShape = false; 130 bool haveShape = false;
131 bool nativeShapePossible = true;
132 PrimitiveBaseShape pbs = prim.BaseShape;
412 133
413 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) 134 // Kludge to create the capsule for the avatar.
135 // TDOD: Remove/redo this when BSShapeAvatar is working!!
136 BSCharacter theChar = prim as BSCharacter;
137 if (theChar != null)
414 { 138 {
415 // an avatar capsule is close to a native shape (it is not shared) 139 DereferenceExistingShape(prim, shapeCallback);
416 GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE, shapeCallback); 140 prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
417 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape); 141 BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE);
418 ret = true; 142 ret = true;
419 haveShape = true; 143 haveShape = true;
420 } 144 }
421 145
422 // Compound shapes are handled special as they are rebuilt from scratch.
423 // This isn't too great a hardship since most of the child shapes will have already been created.
424 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
425 {
426 ret = GetReferenceToCompoundShape(prim, shapeCallback);
427 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape);
428 haveShape = true;
429 }
430
431 if (!haveShape)
432 {
433 ret = CreateGeomNonSpecial(forceRebuild, prim, shapeCallback);
434 }
435
436 return ret;
437 }
438
439 // Create a mesh, hull or native shape.
440 // Return 'true' if the prim's shape was changed.
441 public bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback)
442 {
443 bool ret = false;
444 bool haveShape = false;
445 bool nativeShapePossible = true;
446 PrimitiveBaseShape pbs = prim.BaseShape;
447
448 // If the prim attributes are simple, this could be a simple Bullet native shape 146 // If the prim attributes are simple, this could be a simple Bullet native shape
147 // Native shapes work whether to object is static or physical.
449 if (!haveShape 148 if (!haveShape
450 && nativeShapePossible 149 && nativeShapePossible
451 && pbs != null 150 && pbs != null
452 && !pbs.SculptEntry 151 && PrimHasNoCuts(pbs)
453 && ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) || PrimHasNoCuts(pbs)) ) 152 && ( !pbs.SculptEntry || (pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) )
153 )
454 { 154 {
455 // Get the scale of any existing shape so we can see if the new shape is same native type and same size. 155 // Get the scale of any existing shape so we can see if the new shape is same native type and same size.
456 OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero; 156 OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero;
457 if (prim.PhysShape.HasPhysicalShape) 157 if (prim.PhysShape.HasPhysicalShape)
458 scaleOfExistingShape = PhysicsScene.PE.GetLocalScaling(prim.PhysShape); 158 scaleOfExistingShape = m_physicsScene.PE.GetLocalScaling(prim.PhysShape.physShapeInfo);
459 159
460 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}", 160 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}",
461 prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.type); 161 prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.physShapeInfo.shapeType);
462 162
463 // It doesn't look like Bullet scales native spheres so make sure the scales are all equal 163 // It doesn't look like Bullet scales native spheres so make sure the scales are all equal
464 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) 164 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
@@ -466,26 +166,30 @@ public sealed class BSShapeCollection : IDisposable
466 { 166 {
467 haveShape = true; 167 haveShape = true;
468 if (forceRebuild 168 if (forceRebuild
469 || prim.Scale != scaleOfExistingShape 169 || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_SPHERE
470 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE 170 )
471 )
472 { 171 {
473 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE, 172 DereferenceExistingShape(prim, shapeCallback);
474 FixedShapeKey.KEY_SPHERE, shapeCallback); 173 prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
174 BSPhysicsShapeType.SHAPE_SPHERE, FixedShapeKey.KEY_SPHERE);
175 ret = true;
475 } 176 }
476 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},rebuilt={2},shape={3}", 177 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},rebuilt={2},shape={3}",
477 prim.LocalID, forceRebuild, ret, prim.PhysShape); 178 prim.LocalID, forceRebuild, ret, prim.PhysShape);
478 } 179 }
180 // If we didn't make a sphere, maybe a box will work.
479 if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) 181 if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
480 { 182 {
481 haveShape = true; 183 haveShape = true;
482 if (forceRebuild 184 if (forceRebuild
483 || prim.Scale != scaleOfExistingShape 185 || prim.Scale != scaleOfExistingShape
484 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX 186 || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_BOX
485 ) 187 )
486 { 188 {
487 ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX, 189 DereferenceExistingShape(prim, shapeCallback);
488 FixedShapeKey.KEY_BOX, shapeCallback); 190 prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
191 BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
192 ret = true;
489 } 193 }
490 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},rebuilt={2},shape={3}", 194 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},rebuilt={2},shape={3}",
491 prim.LocalID, forceRebuild, ret, prim.PhysShape); 195 prim.LocalID, forceRebuild, ret, prim.PhysShape);
@@ -502,7 +206,7 @@ public sealed class BSShapeCollection : IDisposable
502 } 206 }
503 207
504 // return 'true' if this shape description does not include any cutting or twisting. 208 // return 'true' if this shape description does not include any cutting or twisting.
505 private bool PrimHasNoCuts(PrimitiveBaseShape pbs) 209 public static bool PrimHasNoCuts(PrimitiveBaseShape pbs)
506 { 210 {
507 return pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 211 return pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
508 && pbs.ProfileHollow == 0 212 && pbs.ProfileHollow == 0
@@ -514,7 +218,7 @@ public sealed class BSShapeCollection : IDisposable
514 } 218 }
515 219
516 // return 'true' if the prim's shape was changed. 220 // return 'true' if the prim's shape was changed.
517 public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) 221 private bool CreateGeomMeshOrHull(BSPhysObject prim, PhysicalDestructionCallback shapeCallback)
518 { 222 {
519 223
520 bool ret = false; 224 bool ret = false;
@@ -522,503 +226,121 @@ public sealed class BSShapeCollection : IDisposable
522 // made. Native shapes work in either case. 226 // made. Native shapes work in either case.
523 if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects) 227 if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects)
524 { 228 {
525 // Update prim.BSShape to reference a hull of this shape. 229 // Use a simple, single mesh convex hull shape if the object is simple enough
526 ret = GetReferenceToHull(prim, shapeCallback); 230 BSShape potentialHull = null;
527 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
528 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
529 }
530 else
531 {
532 ret = GetReferenceToMesh(prim, shapeCallback);
533 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
534 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
535 }
536 return ret;
537 }
538
539 // Creates a native shape and assignes it to prim.BSShape.
540 // "Native" shapes are never shared. they are created here and destroyed in DereferenceShape().
541 private bool GetReferenceToNativeShape(BSPhysObject prim,
542 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey,
543 ShapeDestructionCallback shapeCallback)
544 {
545 // release any previous shape
546 DereferenceShape(prim.PhysShape, shapeCallback);
547
548 BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey);
549
550 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
551 if (DDetail) DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
552 prim.LocalID, newShape, prim.Scale);
553
554 // native shapes are scaled by Bullet
555 prim.PhysShape = newShape;
556 return true;
557 }
558
559 private BulletShape BuildPhysicalNativeShape(BSPhysObject prim, BSPhysicsShapeType shapeType,
560 FixedShapeKey shapeKey)
561 {
562 BulletShape newShape;
563 // Need to make sure the passed shape information is for the native type.
564 ShapeData nativeShapeData = new ShapeData();
565 nativeShapeData.Type = shapeType;
566 nativeShapeData.ID = prim.LocalID;
567 nativeShapeData.Scale = prim.Scale;
568 nativeShapeData.Size = prim.Scale; // unneeded, I think.
569 nativeShapeData.MeshKey = (ulong)shapeKey;
570 nativeShapeData.HullKey = (ulong)shapeKey;
571
572 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
573 {
574 231
575 newShape = PhysicsScene.PE.BuildCapsuleShape(PhysicsScene.World, 1f, 1f, prim.Scale); 232 PrimitiveBaseShape pbs = prim.BaseShape;
576 if (DDetail) DetailLog("{0},BSShapeCollection.BuildPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); 233 // Use a simple, one section convex shape for prims that are probably convex (no cuts or twists)
577 } 234 if (BSParam.ShouldUseSingleConvexHullForPrims
578 else 235 && pbs != null
579 { 236 && !pbs.SculptEntry
580 // Native shapes are scaled in Bullet so set the scaling to the size 237 && PrimHasNoCuts(pbs)
581 newShape = PhysicsScene.PE.BuildNativeShape(PhysicsScene.World, nativeShapeData); 238 )
582 239 {
583 } 240 potentialHull = BSShapeConvexHull.GetReference(m_physicsScene, false /* forceRebuild */, prim);
584 if (!newShape.HasPhysicalShape) 241 }
585 { 242 // Use the GImpact shape if it is a prim that has some concaveness
586 PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", 243 if (potentialHull == null
587 LogHeader, prim.LocalID, shapeType); 244 && BSParam.ShouldUseGImpactShapeForPrims
588 } 245 && pbs != null
589 newShape.shapeKey = (System.UInt64)shapeKey; 246 && !pbs.SculptEntry
590 newShape.isNativeShape = true; 247 )
591 248 {
592 return newShape; 249 potentialHull = BSShapeGImpact.GetReference(m_physicsScene, false /* forceRebuild */, prim);
593 } 250 }
594 251 // If not any of the simple cases, just make a hull
595 // Builds a mesh shape in the physical world and updates prim.BSShape. 252 if (potentialHull == null)
596 // Dereferences previous shape in BSShape and adds a reference for this new shape. 253 {
597 // Returns 'true' of a mesh was actually built. Otherwise . 254 potentialHull = BSShapeHull.GetReference(m_physicsScene, false /*forceRebuild*/, prim);
598 // Called at taint-time! 255 }
599 private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
600 {
601 BulletShape newShape = new BulletShape();
602
603 float lod;
604 System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
605
606 // if this new shape is the same as last time, don't recreate the mesh
607 if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH)
608 return false;
609
610 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2},size={3},lod={4}",
611 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"), prim.Size, lod);
612
613 // Since we're recreating new, get rid of the reference to the previous shape
614 DereferenceShape(prim.PhysShape, shapeCallback);
615
616 newShape = CreatePhysicalMesh(prim, newMeshKey, prim.BaseShape, prim.Size, lod);
617 // Take evasive action if the mesh was not constructed.
618 newShape = VerifyMeshCreated(newShape, prim);
619
620 ReferenceShape(newShape);
621
622 prim.PhysShape = newShape;
623
624 return true; // 'true' means a new shape has been added to this prim
625 }
626
627 private BulletShape CreatePhysicalMesh(BSPhysObject prim, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
628 {
629 BulletShape newShape = new BulletShape();
630 256
631 MeshDesc meshDesc; 257 // If the current shape is not what is on the prim at the moment, time to change.
632 if (Meshes.TryGetValue(newMeshKey, out meshDesc)) 258 if (!prim.PhysShape.HasPhysicalShape
633 { 259 || potentialHull.ShapeType != prim.PhysShape.ShapeType
634 // If the mesh has already been built just use it. 260 || potentialHull.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey)
635 newShape = meshDesc.shape.Clone(); 261 {
262 DereferenceExistingShape(prim, shapeCallback);
263 prim.PhysShape = potentialHull;
264 ret = true;
265 }
266 else
267 {
268 // The current shape on the prim is the correct one. We don't need the potential reference.
269 potentialHull.Dereference(m_physicsScene);
270 }
271 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1}", prim.LocalID, prim.PhysShape);
636 } 272 }
637 else 273 else
638 { 274 {
639 IMesh meshData = PhysicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, 275 // Non-physical objects should be just meshes.
640 true, 276 BSShape potentialMesh = BSShapeMesh.GetReference(m_physicsScene, false /*forceRebuild*/, prim);
641 false, // say it is not physical so a bounding box is not built 277 // If the current shape is not what is on the prim at the moment, time to change.
642 false, // do not cache the mesh and do not use previously built versions 278 if (!prim.PhysShape.HasPhysicalShape
643 false // It's NOT for ODE 279 || potentialMesh.ShapeType != prim.PhysShape.ShapeType
644 ); 280 || potentialMesh.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey)
645
646 if (meshData != null)
647 { 281 {
648 282 DereferenceExistingShape(prim, shapeCallback);
649 int[] indices = meshData.getIndexListAsInt(); 283 prim.PhysShape = potentialMesh;
650 int realIndicesIndex = indices.Length; 284 ret = true;
651 float[] verticesAsFloats = meshData.getVertexListAsFloat();
652
653 if (BSParam.ShouldRemoveZeroWidthTriangles)
654 {
655 // Remove degenerate triangles. These are triangles with two of the vertices
656 // are the same. This is complicated by the problem that vertices are not
657 // made unique in sculpties so we have to compare the values in the vertex.
658 realIndicesIndex = 0;
659 for (int tri = 0; tri < indices.Length; tri += 3)
660 {
661 // Compute displacements into vertex array for each vertex of the triangle
662 int v1 = indices[tri + 0] * 3;
663 int v2 = indices[tri + 1] * 3;
664 int v3 = indices[tri + 2] * 3;
665 // Check to see if any two of the vertices are the same
666 if (!( ( verticesAsFloats[v1 + 0] == verticesAsFloats[v2 + 0]
667 && verticesAsFloats[v1 + 1] == verticesAsFloats[v2 + 1]
668 && verticesAsFloats[v1 + 2] == verticesAsFloats[v2 + 2])
669 || ( verticesAsFloats[v2 + 0] == verticesAsFloats[v3 + 0]
670 && verticesAsFloats[v2 + 1] == verticesAsFloats[v3 + 1]
671 && verticesAsFloats[v2 + 2] == verticesAsFloats[v3 + 2])
672 || ( verticesAsFloats[v1 + 0] == verticesAsFloats[v3 + 0]
673 && verticesAsFloats[v1 + 1] == verticesAsFloats[v3 + 1]
674 && verticesAsFloats[v1 + 2] == verticesAsFloats[v3 + 2]) )
675 )
676 {
677 // None of the vertices of the triangles are the same. This is a good triangle;
678 indices[realIndicesIndex + 0] = indices[tri + 0];
679 indices[realIndicesIndex + 1] = indices[tri + 1];
680 indices[realIndicesIndex + 2] = indices[tri + 2];
681 realIndicesIndex += 3;
682 }
683 }
684 }
685 DetailLog("{0},BSShapeCollection.CreatePhysicalMesh,origTri={1},realTri={2},numVerts={3}",
686 BSScene.DetailLogZero, indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3);
687
688 if (realIndicesIndex != 0)
689 {
690 newShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World,
691 realIndicesIndex, indices, verticesAsFloats.Length / 3, verticesAsFloats);
692 }
693 else
694 {
695 PhysicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim {1} at {2} in {3}",
696 LogHeader, prim.PhysObjectName, prim.RawPosition, PhysicsScene.Name);
697 }
698 } 285 }
286 else
287 {
288 // We don't need this reference to the mesh that is already being using.
289 potentialMesh.Dereference(m_physicsScene);
290 }
291 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1}", prim.LocalID, prim.PhysShape);
699 } 292 }
700 newShape.shapeKey = newMeshKey; 293 return ret;
701
702 return newShape;
703 }
704
705 // See that hull shape exists in the physical world and update prim.BSShape.
706 // We could be creating the hull because scale changed or whatever.
707 // Return 'true' if a new hull was built. Otherwise, returning a shared hull instance.
708 private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
709 {
710 BulletShape newShape;
711
712 float lod;
713 System.UInt64 newHullKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
714
715 // if the hull hasn't changed, don't rebuild it
716 if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL)
717 return false;
718
719 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}",
720 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
721
722 // Remove usage of the previous shape.
723 DereferenceShape(prim.PhysShape, shapeCallback);
724
725 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod);
726 // It might not have been created if we're waiting for an asset.
727 newShape = VerifyMeshCreated(newShape, prim);
728
729 ReferenceShape(newShape);
730
731 prim.PhysShape = newShape;
732 return true; // 'true' means a new shape has been added to this prim
733 } 294 }
734 295
735 List<ConvexResult> m_hulls; 296 // Track another user of a body.
736 private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) 297 // We presume the caller has allocated the body.
298 // Bodies only have one user so the body is just put into the world if not already there.
299 private void ReferenceBody(BulletBody body)
737 { 300 {
738 301 lock (m_collectionActivityLock)
739 BulletShape newShape = new BulletShape();
740 IntPtr hullPtr = IntPtr.Zero;
741
742 HullDesc hullDesc;
743 if (Hulls.TryGetValue(newHullKey, out hullDesc))
744 {
745 // If the hull shape already has been created, just use the one shared instance.
746 newShape = hullDesc.shape.Clone();
747 }
748 else
749 { 302 {
750 // Build a new hull in the physical world. 303 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body);
751 // Pass true for physicalness as this prevents the creation of bounding box which is not needed 304 if (!m_physicsScene.PE.IsInWorld(m_physicsScene.World, body))
752 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false, false, false);
753 if (meshData != null)
754 { 305 {
755 306 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, body);
756 int[] indices = meshData.getIndexListAsInt(); 307 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
757 List<OMV.Vector3> vertices = meshData.getVertexList();
758
759 //format conversion from IMesh format to DecompDesc format
760 List<int> convIndices = new List<int>();
761 List<float3> convVertices = new List<float3>();
762 for (int ii = 0; ii < indices.GetLength(0); ii++)
763 {
764 convIndices.Add(indices[ii]);
765 }
766 foreach (OMV.Vector3 vv in vertices)
767 {
768 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
769 }
770
771 uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit;
772 if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes)
773 {
774 // Simple primitive shapes we know are convex so they are better implemented with
775 // fewer hulls.
776 // Check for simple shape (prim without cuts) and reduce split parameter if so.
777 if (PrimHasNoCuts(pbs))
778 {
779 maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes;
780 }
781 }
782
783 // setup and do convex hull conversion
784 m_hulls = new List<ConvexResult>();
785 DecompDesc dcomp = new DecompDesc();
786 dcomp.mIndices = convIndices;
787 dcomp.mVertices = convVertices;
788 dcomp.mDepth = maxDepthSplit;
789 dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent;
790 dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent;
791 dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices;
792 dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth;
793 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
794 // create the hull into the _hulls variable
795 convexBuilder.process(dcomp);
796
797 DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}",
798 BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count);
799
800 // Convert the vertices and indices for passing to unmanaged.
801 // The hull information is passed as a large floating point array.
802 // The format is:
803 // convHulls[0] = number of hulls
804 // convHulls[1] = number of vertices in first hull
805 // convHulls[2] = hull centroid X coordinate
806 // convHulls[3] = hull centroid Y coordinate
807 // convHulls[4] = hull centroid Z coordinate
808 // convHulls[5] = first hull vertex X
809 // convHulls[6] = first hull vertex Y
810 // convHulls[7] = first hull vertex Z
811 // convHulls[8] = second hull vertex X
812 // ...
813 // convHulls[n] = number of vertices in second hull
814 // convHulls[n+1] = second hull centroid X coordinate
815 // ...
816 //
817 // TODO: is is very inefficient. Someday change the convex hull generator to return
818 // data structures that do not need to be converted in order to pass to Bullet.
819 // And maybe put the values directly into pinned memory rather than marshaling.
820 int hullCount = m_hulls.Count;
821 int totalVertices = 1; // include one for the count of the hulls
822 foreach (ConvexResult cr in m_hulls)
823 {
824 totalVertices += 4; // add four for the vertex count and centroid
825 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
826 }
827 float[] convHulls = new float[totalVertices];
828
829 convHulls[0] = (float)hullCount;
830 int jj = 1;
831 foreach (ConvexResult cr in m_hulls)
832 {
833 // copy vertices for index access
834 float3[] verts = new float3[cr.HullVertices.Count];
835 int kk = 0;
836 foreach (float3 ff in cr.HullVertices)
837 {
838 verts[kk++] = ff;
839 }
840
841 // add to the array one hull's worth of data
842 convHulls[jj++] = cr.HullIndices.Count;
843 convHulls[jj++] = 0f; // centroid x,y,z
844 convHulls[jj++] = 0f;
845 convHulls[jj++] = 0f;
846 foreach (int ind in cr.HullIndices)
847 {
848 convHulls[jj++] = verts[ind].x;
849 convHulls[jj++] = verts[ind].y;
850 convHulls[jj++] = verts[ind].z;
851 }
852 }
853 // create the hull data structure in Bullet
854 newShape = PhysicsScene.PE.CreateHullShape(PhysicsScene.World, hullCount, convHulls);
855 } 308 }
856 } 309 }
857
858 newShape.shapeKey = newHullKey;
859
860 return newShape;
861 }
862
863 // Callback from convex hull creater with a newly created hull.
864 // Just add it to our collection of hulls for this shape.
865 private void HullReturn(ConvexResult result)
866 {
867 m_hulls.Add(result);
868 return;
869 } 310 }
870 311
871 // Compound shapes are always built from scratch. 312 // Release the usage of a body.
872 // This shouldn't be to bad since most of the parts will be meshes that had been built previously. 313 // Called when releasing use of a BSBody. BSShape is handled separately.
873 private bool GetReferenceToCompoundShape(BSPhysObject prim, ShapeDestructionCallback shapeCallback) 314 // Called in taint time.
874 { 315 public void DereferenceBody(BulletBody body, PhysicalDestructionCallback bodyCallback )
875 // Remove reference to the old shape
876 // Don't need to do this as the shape is freed when the new root shape is created below.
877 // DereferenceShape(prim.PhysShape, true, shapeCallback);
878
879 BulletShape cShape = PhysicsScene.PE.CreateCompoundShape(PhysicsScene.World, false);
880
881 // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape.
882 CreateGeomMeshOrHull(prim, shapeCallback);
883 PhysicsScene.PE.AddChildShapeToCompoundShape(cShape, prim.PhysShape, OMV.Vector3.Zero, OMV.Quaternion.Identity);
884 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}",
885 prim.LocalID, cShape, prim.PhysShape);
886
887 prim.PhysShape = cShape;
888
889 return true;
890 }
891
892 // Create a hash of all the shape parameters to be used as a key
893 // for this particular shape.
894 private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
895 {
896 // level of detail based on size and type of the object
897 float lod = BSParam.MeshLOD;
898
899 // prims with curvy internal cuts need higher lod
900 if (pbs.HollowShape == HollowShape.Circle)
901 lod = BSParam.MeshCircularLOD;
902
903 if (pbs.SculptEntry)
904 lod = BSParam.SculptLOD;
905
906 // Mega prims usually get more detail because one can interact with shape approximations at this size.
907 float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
908 if (maxAxis > BSParam.MeshMegaPrimThreshold)
909 lod = BSParam.MeshMegaPrimLOD;
910
911 retLod = lod;
912 return pbs.GetMeshKey(size, lod);
913 }
914 // For those who don't want the LOD
915 private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs)
916 { 316 {
917 float lod; 317 if (!body.HasPhysicalBody)
918 return ComputeShapeKey(size, pbs, out lod); 318 return;
919 }
920 319
921 // The creation of a mesh or hull can fail if an underlying asset is not available. 320 m_physicsScene.AssertInTaintTime("BSShapeCollection.DereferenceBody");
922 // There are two cases: 1) the asset is not in the cache and it needs to be fetched;
923 // and 2) the asset cannot be converted (like failed decompression of JPEG2000s).
924 // The first case causes the asset to be fetched. The second case requires
925 // us to not loop forever.
926 // Called after creating a physical mesh or hull. If the physical shape was created,
927 // just return.
928 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim)
929 {
930 // If the shape was successfully created, nothing more to do
931 if (newShape.HasPhysicalShape)
932 return newShape;
933 321
934 // VerifyMeshCreated is called after trying to create the mesh. If we think the asset had been 322 lock (m_collectionActivityLock)
935 // fetched but we end up here again, the meshing of the asset must have failed.
936 // Prevent trying to keep fetching the mesh by declaring failure.
937 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
938 {
939 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
940 PhysicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. {1}, texture={2}",
941 LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture);
942 }
943 else
944 { 323 {
945 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset 324 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1}", body.ID, body);
946 if (prim.BaseShape.SculptEntry 325 // If the caller needs to know the old body is going away, pass the event up.
947 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Failed 326 if (bodyCallback != null)
948 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting 327 bodyCallback(body, null);
949 && prim.BaseShape.SculptTexture != OMV.UUID.Zero
950 )
951 {
952 DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset", prim.LocalID);
953 // Multiple requestors will know we're waiting for this asset
954 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting;
955
956 BSPhysObject xprim = prim;
957 Util.FireAndForget(delegate
958 {
959 RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
960 if (assetProvider != null)
961 {
962 BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
963 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
964 {
965 bool assetFound = false;
966 string mismatchIDs = String.Empty; // DEBUG DEBUG
967 if (asset != null && yprim.BaseShape.SculptEntry)
968 {
969 if (yprim.BaseShape.SculptTexture.ToString() == asset.ID)
970 {
971 yprim.BaseShape.SculptData = asset.Data;
972 // This will cause the prim to see that the filler shape is not the right
973 // one and try again to build the object.
974 // No race condition with the normal shape setting since the rebuild is at taint time.
975 yprim.ForceBodyShapeRebuild(false /* inTaintTime */);
976 assetFound = true;
977 }
978 else
979 {
980 mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID;
981 }
982 }
983 if (assetFound)
984 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched;
985 else
986 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
987 DetailLog("{0},BSShapeCollection,fetchAssetCallback,found={1},isSculpt={2},ids={3}",
988 yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs );
989 328
990 }); 329 // Removing an object not in the world is a NOOP
991 } 330 m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, body);
992 else
993 {
994 xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
995 PhysicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}",
996 LogHeader, PhysicsScene.Name);
997 }
998 });
999 }
1000 else
1001 {
1002 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed)
1003 {
1004 PhysicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. obj={1}, texture={2}",
1005 LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture);
1006 }
1007 }
1008 }
1009 331
1010 // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object. 332 // Zero any reference to the shape so it is not freed when the body is deleted.
1011 BulletShape fillinShape = BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); 333 m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, body, null);
1012 DetailLog("{0},BSShapeCollection.VerifyMeshCreated,boxTempShape", prim.LocalID);
1013 334
1014 return fillinShape; 335 m_physicsScene.PE.DestroyObject(m_physicsScene.World, body);
336 }
1015 } 337 }
1016 338
1017 // Create a body object in Bullet. 339 // Create a body object in Bullet.
1018 // Updates prim.BSBody with the information about the new body if one is created. 340 // Updates prim.BSBody with the information about the new body if one is created.
1019 // Returns 'true' if an object was actually created. 341 // Returns 'true' if an object was actually created.
1020 // Called at taint-time. 342 // Called at taint-time.
1021 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, BodyDestructionCallback bodyCallback) 343 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, PhysicalDestructionCallback bodyCallback)
1022 { 344 {
1023 bool ret = false; 345 bool ret = false;
1024 346
@@ -1029,7 +351,7 @@ public sealed class BSShapeCollection : IDisposable
1029 // If not a solid object, body is a GhostObject. Otherwise a RigidBody. 351 // If not a solid object, body is a GhostObject. Otherwise a RigidBody.
1030 if (!mustRebuild) 352 if (!mustRebuild)
1031 { 353 {
1032 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(prim.PhysBody); 354 CollisionObjectTypes bodyType = (CollisionObjectTypes)m_physicsScene.PE.GetBodyType(prim.PhysBody);
1033 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY 355 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY
1034 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) 356 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT)
1035 { 357 {
@@ -1047,12 +369,12 @@ public sealed class BSShapeCollection : IDisposable
1047 BulletBody aBody; 369 BulletBody aBody;
1048 if (prim.IsSolid) 370 if (prim.IsSolid)
1049 { 371 {
1050 aBody = PhysicsScene.PE.CreateBodyFromShape(sim, prim.PhysShape, prim.LocalID, prim.RawPosition, prim.RawOrientation); 372 aBody = m_physicsScene.PE.CreateBodyFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID, prim.RawPosition, prim.RawOrientation);
1051 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,mesh,body={1}", prim.LocalID, aBody); 373 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,rigid,body={1}", prim.LocalID, aBody);
1052 } 374 }
1053 else 375 else
1054 { 376 {
1055 aBody = PhysicsScene.PE.CreateGhostFromShape(sim, prim.PhysShape, prim.LocalID, prim.RawPosition, prim.RawOrientation); 377 aBody = m_physicsScene.PE.CreateGhostFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID, prim.RawPosition, prim.RawOrientation);
1056 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,body={1}", prim.LocalID, aBody); 378 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,body={1}", prim.LocalID, aBody);
1057 } 379 }
1058 380
@@ -1066,46 +388,10 @@ public sealed class BSShapeCollection : IDisposable
1066 return ret; 388 return ret;
1067 } 389 }
1068 390
1069 private bool TryGetMeshByPtr(BulletShape shape, out MeshDesc outDesc)
1070 {
1071 bool ret = false;
1072 MeshDesc foundDesc = new MeshDesc();
1073 foreach (MeshDesc md in Meshes.Values)
1074 {
1075 if (md.shape.ReferenceSame(shape))
1076 {
1077 foundDesc = md;
1078 ret = true;
1079 break;
1080 }
1081
1082 }
1083 outDesc = foundDesc;
1084 return ret;
1085 }
1086
1087 private bool TryGetHullByPtr(BulletShape shape, out HullDesc outDesc)
1088 {
1089 bool ret = false;
1090 HullDesc foundDesc = new HullDesc();
1091 foreach (HullDesc hd in Hulls.Values)
1092 {
1093 if (hd.shape.ReferenceSame(shape))
1094 {
1095 foundDesc = hd;
1096 ret = true;
1097 break;
1098 }
1099
1100 }
1101 outDesc = foundDesc;
1102 return ret;
1103 }
1104
1105 private void DetailLog(string msg, params Object[] args) 391 private void DetailLog(string msg, params Object[] args)
1106 { 392 {
1107 if (PhysicsScene.PhysicsLogging.Enabled) 393 if (m_physicsScene.PhysicsLogging.Enabled)
1108 PhysicsScene.DetailLog(msg, args); 394 m_physicsScene.DetailLog(msg, args);
1109 } 395 }
1110} 396}
1111} 397}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
index ee18379..326fc9e 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
@@ -29,115 +29,291 @@ using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Text; 30using System.Text;
31 31
32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager;
34using OpenSim.Region.Physics.Meshing;
35using OpenSim.Region.Physics.ConvexDecompositionDotNet;
36
32using OMV = OpenMetaverse; 37using OMV = OpenMetaverse;
33 38
34namespace OpenSim.Region.Physics.BulletSPlugin 39namespace OpenSim.Region.Physics.BulletSPlugin
35{ 40{
36public abstract class BSShape 41public abstract class BSShape
37{ 42{
43 private static string LogHeader = "[BULLETSIM SHAPE]";
44
38 public int referenceCount { get; set; } 45 public int referenceCount { get; set; }
39 public DateTime lastReferenced { get; set; } 46 public DateTime lastReferenced { get; set; }
47 public BulletShape physShapeInfo { get; set; }
40 48
41 public BSShape() 49 public BSShape()
42 { 50 {
43 referenceCount = 0; 51 referenceCount = 1;
44 lastReferenced = DateTime.Now; 52 lastReferenced = DateTime.Now;
53 physShapeInfo = new BulletShape();
45 } 54 }
46 55 public BSShape(BulletShape pShape)
47 // Get a reference to a physical shape. Create if it doesn't exist
48 public static BSShape GetShapeReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
49 { 56 {
50 BSShape ret = null; 57 referenceCount = 1;
51 58 lastReferenced = DateTime.Now;
52 if (prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) 59 physShapeInfo = pShape;
53 { 60 }
54 // an avatar capsule is close to a native shape (it is not shared)
55 ret = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_CAPSULE,
56 FixedShapeKey.KEY_CAPSULE);
57 physicsScene.DetailLog("{0},BSShape.GetShapeReference,avatarCapsule,shape={1}", prim.LocalID, ret);
58 }
59
60 // Compound shapes are handled special as they are rebuilt from scratch.
61 // This isn't too great a hardship since most of the child shapes will have already been created.
62 if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
63 {
64 // Getting a reference to a compound shape gets you the compound shape with the root prim shape added
65 ret = BSShapeCompound.GetReference(prim);
66 physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, ret);
67 }
68
69 // Avatars have their own unique shape
70 if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_AVATAR)
71 {
72 // Getting a reference to a compound shape gets you the compound shape with the root prim shape added
73 ret = BSShapeAvatar.GetReference(prim);
74 physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,avatarShape,shape={1}", prim.LocalID, ret);
75 }
76 61
77 if (ret == null) 62 // Get another reference to this shape.
78 ret = GetShapeReferenceNonSpecial(physicsScene, forceRebuild, prim); 63 public abstract BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim);
79 64
80 return ret; 65 // Called when this shape is being used again.
81 } 66 // Used internally. External callers should call instance.GetReference() to properly copy/reference
82 public static BSShape GetShapeReferenceNonSpecial(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) 67 // the shape.
68 protected virtual void IncrementReference()
83 { 69 {
84 return null; 70 referenceCount++;
71 lastReferenced = DateTime.Now;
85 } 72 }
86 public static BSShape GetShapeReferenceNonNative(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) 73
74 // Called when this shape is being used again.
75 protected virtual void DecrementReference()
87 { 76 {
88 return null; 77 referenceCount--;
78 lastReferenced = DateTime.Now;
89 } 79 }
90 80
91 // Release the use of a physical shape. 81 // Release the use of a physical shape.
92 public abstract void Dereference(BSScene physicsScene); 82 public abstract void Dereference(BSScene physicsScene);
93 83
94 // All shapes have a static call to get a reference to the physical shape 84 // Return 'true' if there is an allocated physics physical shape under this class instance.
95 // protected abstract static BSShape GetReference(); 85 public virtual bool HasPhysicalShape
86 {
87 get
88 {
89 if (physShapeInfo != null)
90 return physShapeInfo.HasPhysicalShape;
91 return false;
92 }
93 }
94 public virtual BSPhysicsShapeType ShapeType
95 {
96 get
97 {
98 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
99 if (physShapeInfo != null && physShapeInfo.HasPhysicalShape)
100 ret = physShapeInfo.shapeType;
101 return ret;
102 }
103 }
96 104
97 // Returns a string for debugging that uniquily identifies the memory used by this instance 105 // Returns a string for debugging that uniquily identifies the memory used by this instance
98 public virtual string AddrString 106 public virtual string AddrString
99 { 107 {
100 get { return "unknown"; } 108 get
109 {
110 if (physShapeInfo != null)
111 return physShapeInfo.AddrString;
112 return "unknown";
113 }
101 } 114 }
102 115
103 public override string ToString() 116 public override string ToString()
104 { 117 {
105 StringBuilder buff = new StringBuilder(); 118 StringBuilder buff = new StringBuilder();
106 buff.Append("<p="); 119 if (physShapeInfo == null)
107 buff.Append(AddrString); 120 {
121 buff.Append("<noPhys");
122 }
123 else
124 {
125 buff.Append("<phy=");
126 buff.Append(physShapeInfo.ToString());
127 }
108 buff.Append(",c="); 128 buff.Append(",c=");
109 buff.Append(referenceCount.ToString()); 129 buff.Append(referenceCount.ToString());
110 buff.Append(">"); 130 buff.Append(">");
111 return buff.ToString(); 131 return buff.ToString();
112 } 132 }
133
134 #region Common shape routines
135 // Create a hash of all the shape parameters to be used as a key for this particular shape.
136 public static System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
137 {
138 // level of detail based on size and type of the object
139 float lod = BSParam.MeshLOD;
140 if (pbs.SculptEntry)
141 lod = BSParam.SculptLOD;
142
143 // Mega prims usually get more detail because one can interact with shape approximations at this size.
144 float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
145 if (maxAxis > BSParam.MeshMegaPrimThreshold)
146 lod = BSParam.MeshMegaPrimLOD;
147
148 retLod = lod;
149 return pbs.GetMeshKey(size, lod);
150 }
151
152 // The creation of a mesh or hull can fail if an underlying asset is not available.
153 // There are two cases: 1) the asset is not in the cache and it needs to be fetched;
154 // and 2) the asset cannot be converted (like failed decompression of JPEG2000s).
155 // The first case causes the asset to be fetched. The second case requires
156 // us to not loop forever.
157 // Called after creating a physical mesh or hull. If the physical shape was created,
158 // just return.
159 public static BulletShape VerifyMeshCreated(BSScene physicsScene, BulletShape newShape, BSPhysObject prim)
160 {
161 // If the shape was successfully created, nothing more to do
162 if (newShape.HasPhysicalShape)
163 return newShape;
164
165 // VerifyMeshCreated is called after trying to create the mesh. If we think the asset had been
166 // fetched but we end up here again, the meshing of the asset must have failed.
167 // Prevent trying to keep fetching the mesh by declaring failure.
168 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
169 {
170 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
171 physicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. {1}, texture={2}",
172 LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture);
173 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,setFailed,objNam={1},tex={2}",
174 prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture);
175 }
176 else
177 {
178 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
179 if (prim.BaseShape.SculptEntry
180 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Failed
181 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting
182 && prim.BaseShape.SculptTexture != OMV.UUID.Zero
183 )
184 {
185 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAsset,objNam={1},tex={2}",
186 prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture);
187 // Multiple requestors will know we're waiting for this asset
188 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting;
189
190 BSPhysObject xprim = prim;
191 Util.FireAndForget(delegate
192 {
193 // physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,inFireAndForget", xprim.LocalID);
194 RequestAssetDelegate assetProvider = physicsScene.RequestAssetMethod;
195 if (assetProvider != null)
196 {
197 BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
198 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
199 {
200 // physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,assetProviderCallback", xprim.LocalID);
201 bool assetFound = false;
202 string mismatchIDs = String.Empty; // DEBUG DEBUG
203 if (asset != null && yprim.BaseShape.SculptEntry)
204 {
205 if (yprim.BaseShape.SculptTexture.ToString() == asset.ID)
206 {
207 yprim.BaseShape.SculptData = asset.Data;
208 // This will cause the prim to see that the filler shape is not the right
209 // one and try again to build the object.
210 // No race condition with the normal shape setting since the rebuild is at taint time.
211 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched;
212 yprim.ForceBodyShapeRebuild(false /* inTaintTime */);
213 assetFound = true;
214 }
215 else
216 {
217 mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID;
218 }
219 }
220 if (!assetFound)
221 {
222 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
223 }
224 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAssetCallback,found={1},isSculpt={2},ids={3}",
225 yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs );
226 });
227 }
228 else
229 {
230 xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
231 physicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}",
232 LogHeader, physicsScene.Name);
233 }
234 });
235 }
236 else
237 {
238 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed)
239 {
240 physicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. obj={1}, texture={2}",
241 LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture);
242 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailed,objNam={1},tex={2}",
243 prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture);
244 }
245 }
246 }
247
248 // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object.
249 BSShape fillShape = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
250 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,boxTempShape", prim.LocalID);
251
252 return fillShape.physShapeInfo;
253 }
254
255 #endregion // Common shape routines
113} 256}
114 257
258// ============================================================================================================
115public class BSShapeNull : BSShape 259public class BSShapeNull : BSShape
116{ 260{
117 public BSShapeNull() : base() 261 public BSShapeNull() : base()
118 { 262 {
119 } 263 }
120 public static BSShape GetReference() { return new BSShapeNull(); } 264 public static BSShape GetReference() { return new BSShapeNull(); }
265 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) { return new BSShapeNull(); }
121 public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ } 266 public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ }
122} 267}
123 268
269// ============================================================================================================
124public class BSShapeNative : BSShape 270public class BSShapeNative : BSShape
125{ 271{
126 private static string LogHeader = "[BULLETSIM SHAPE NATIVE]"; 272 private static string LogHeader = "[BULLETSIM SHAPE NATIVE]";
127 public BSShapeNative() : base() 273 public BSShapeNative(BulletShape pShape) : base(pShape)
128 { 274 {
129 } 275 }
130 public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim, 276
131 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) 277 public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim,
278 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
132 { 279 {
133 // Native shapes are not shared and are always built anew. 280 // Native shapes are not shared and are always built anew.
134 //return new BSShapeNative(physicsScene, prim, shapeType, shapeKey); 281 return new BSShapeNative(CreatePhysicalNativeShape(physicsScene, prim, shapeType, shapeKey));
135 return null; 282 }
283
284 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
285 {
286 // Native shapes are not shared so we return a new shape.
287 BSShape ret = null;
288 lock (physShapeInfo)
289 {
290 ret = new BSShapeNative(CreatePhysicalNativeShape(pPhysicsScene, pPrim,
291 physShapeInfo.shapeType, (FixedShapeKey)physShapeInfo.shapeKey));
292 }
293 return ret;
294 }
295
296 // Make this reference to the physical shape go away since native shapes are not shared.
297 public override void Dereference(BSScene physicsScene)
298 {
299 // Native shapes are not tracked and are released immediately
300 lock (physShapeInfo)
301 {
302 if (physShapeInfo.HasPhysicalShape)
303 {
304 physicsScene.DetailLog("{0},BSShapeNative.Dereference,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this);
305 physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo);
306 }
307 physShapeInfo.Clear();
308 // Garbage collection will free up this instance.
309 }
136 } 310 }
137 311
138 private BSShapeNative(BSScene physicsScene, BSPhysObject prim, 312 private static BulletShape CreatePhysicalNativeShape(BSScene physicsScene, BSPhysObject prim,
139 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) 313 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
140 { 314 {
315 BulletShape newShape;
316
141 ShapeData nativeShapeData = new ShapeData(); 317 ShapeData nativeShapeData = new ShapeData();
142 nativeShapeData.Type = shapeType; 318 nativeShapeData.Type = shapeType;
143 nativeShapeData.ID = prim.LocalID; 319 nativeShapeData.ID = prim.LocalID;
@@ -146,84 +322,849 @@ public class BSShapeNative : BSShape
146 nativeShapeData.MeshKey = (ulong)shapeKey; 322 nativeShapeData.MeshKey = (ulong)shapeKey;
147 nativeShapeData.HullKey = (ulong)shapeKey; 323 nativeShapeData.HullKey = (ulong)shapeKey;
148 324
149
150 /*
151 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) 325 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
152 { 326 {
153 ptr = PhysicsScene.PE.BuildCapsuleShape(physicsScene.World, 1f, 1f, prim.Scale); 327 newShape = physicsScene.PE.BuildCapsuleShape(physicsScene.World, 1f, 1f, prim.Scale);
154 physicsScene.DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); 328 physicsScene.DetailLog("{0},BSShapeNative,capsule,scale={1}", prim.LocalID, prim.Scale);
155 } 329 }
156 else 330 else
157 { 331 {
158 ptr = PhysicsScene.PE.BuildNativeShape(physicsScene.World, nativeShapeData); 332 newShape = physicsScene.PE.BuildNativeShape(physicsScene.World, nativeShapeData);
159 } 333 }
160 if (ptr == IntPtr.Zero) 334 if (!newShape.HasPhysicalShape)
161 { 335 {
162 physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", 336 physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
163 LogHeader, prim.LocalID, shapeType); 337 LogHeader, prim.LocalID, shapeType);
164 } 338 }
165 type = shapeType; 339 newShape.shapeType = shapeType;
166 key = (UInt64)shapeKey; 340 newShape.isNativeShape = true;
167 */ 341 newShape.shapeKey = (UInt64)shapeKey;
168 } 342 return newShape;
169 // Make this reference to the physical shape go away since native shapes are not shared.
170 public override void Dereference(BSScene physicsScene)
171 {
172 /*
173 // Native shapes are not tracked and are released immediately
174 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this);
175 PhysicsScene.PE.DeleteCollisionShape(physicsScene.World, this);
176 ptr = IntPtr.Zero;
177 // Garbage collection will free up this instance.
178 */
179 } 343 }
344
180} 345}
181 346
347// ============================================================================================================
182public class BSShapeMesh : BSShape 348public class BSShapeMesh : BSShape
183{ 349{
184 private static string LogHeader = "[BULLETSIM SHAPE MESH]"; 350 private static string LogHeader = "[BULLETSIM SHAPE MESH]";
185 private static Dictionary<System.UInt64, BSShapeMesh> Meshes = new Dictionary<System.UInt64, BSShapeMesh>(); 351 public static Dictionary<System.UInt64, BSShapeMesh> Meshes = new Dictionary<System.UInt64, BSShapeMesh>();
186 352
187 public BSShapeMesh() : base() 353 public BSShapeMesh(BulletShape pShape) : base(pShape)
188 { 354 {
189 } 355 }
190 public static BSShape GetReference() { return new BSShapeNull(); } 356 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
191 public override void Dereference(BSScene physicsScene) { } 357 {
358 float lod;
359 System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
360
361 BSShapeMesh retMesh = null;
362 lock (Meshes)
363 {
364 if (Meshes.TryGetValue(newMeshKey, out retMesh))
365 {
366 // The mesh has already been created. Return a new reference to same.
367 retMesh.IncrementReference();
368 }
369 else
370 {
371 retMesh = new BSShapeMesh(new BulletShape());
372 // An instance of this mesh has not been created. Build and remember same.
373 BulletShape newShape = retMesh.CreatePhysicalMesh(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod);
374
375 // Check to see if mesh was created (might require an asset).
376 newShape = VerifyMeshCreated(physicsScene, newShape, prim);
377 if (!newShape.isNativeShape || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed)
378 {
379 // If a mesh was what was created, remember the built shape for later sharing.
380 // Also note that if meshing failed we put it in the mesh list as there is nothing else to do about the mesh.
381 Meshes.Add(newMeshKey, retMesh);
382 }
383
384 retMesh.physShapeInfo = newShape;
385 }
386 }
387 physicsScene.DetailLog("{0},BSShapeMesh,getReference,mesh={1},size={2},lod={3}", prim.LocalID, retMesh, prim.Size, lod);
388 return retMesh;
389 }
390 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
391 {
392 BSShape ret = null;
393 // If the underlying shape is native, the actual shape has not been build (waiting for asset)
394 // and we must create a copy of the native shape since they are never shared.
395 if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape)
396 {
397 // TODO: decide when the native shapes should be freed. Check in Dereference?
398 ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
399 }
400 else
401 {
402 // Another reference to this shape is just counted.
403 IncrementReference();
404 ret = this;
405 }
406 return ret;
407 }
408 public override void Dereference(BSScene physicsScene)
409 {
410 lock (Meshes)
411 {
412 this.DecrementReference();
413 physicsScene.DetailLog("{0},BSShapeMesh.Dereference,shape={1}", BSScene.DetailLogZero, this);
414 // TODO: schedule aging and destruction of unused meshes.
415 }
416 }
417 // Loop through all the known meshes and return the description based on the physical address.
418 public static bool TryGetMeshByPtr(BulletShape pShape, out BSShapeMesh outMesh)
419 {
420 bool ret = false;
421 BSShapeMesh foundDesc = null;
422 lock (Meshes)
423 {
424 foreach (BSShapeMesh sm in Meshes.Values)
425 {
426 if (sm.physShapeInfo.ReferenceSame(pShape))
427 {
428 foundDesc = sm;
429 ret = true;
430 break;
431 }
432
433 }
434 }
435 outMesh = foundDesc;
436 return ret;
437 }
438
439 public delegate BulletShape CreateShapeCall(BulletWorld world, int indicesCount, int[] indices, int verticesCount, float[] vertices );
440 private BulletShape CreatePhysicalMesh(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey,
441 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
442 {
443 return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod,
444 (w, iC, i, vC, v) => physicsScene.PE.CreateMeshShape(w, iC, i, vC, v) );
445 }
446
447 // Code that uses the mesher to create the index/vertices info for a trimesh shape.
448 // This is used by the passed 'makeShape' call to create the Bullet mesh shape.
449 // The actual build call is passed so this logic can be used by several of the shapes that use a
450 // simple mesh as their base shape.
451 public static BulletShape CreatePhysicalMeshShape(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey,
452 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod, CreateShapeCall makeShape)
453 {
454 BulletShape newShape = new BulletShape();
455
456 IMesh meshData = null;
457 lock (physicsScene.mesher)
458 {
459 meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod,
460 false, // say it is not physical so a bounding box is not built
461 false, // do not cache the mesh and do not use previously built versions
462 false,
463 false
464 );
465 }
466
467 if (meshData != null)
468 {
469 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
470 {
471 // Release the fetched asset data once it has been used.
472 pbs.SculptData = new byte[0];
473 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown;
474 }
475
476 int[] indices = meshData.getIndexListAsInt();
477 int realIndicesIndex = indices.Length;
478 float[] verticesAsFloats = meshData.getVertexListAsFloat();
479
480 if (BSParam.ShouldRemoveZeroWidthTriangles)
481 {
482 // Remove degenerate triangles. These are triangles with two of the vertices
483 // are the same. This is complicated by the problem that vertices are not
484 // made unique in sculpties so we have to compare the values in the vertex.
485 realIndicesIndex = 0;
486 for (int tri = 0; tri < indices.Length; tri += 3)
487 {
488 // Compute displacements into vertex array for each vertex of the triangle
489 int v1 = indices[tri + 0] * 3;
490 int v2 = indices[tri + 1] * 3;
491 int v3 = indices[tri + 2] * 3;
492 // Check to see if any two of the vertices are the same
493 if (!( ( verticesAsFloats[v1 + 0] == verticesAsFloats[v2 + 0]
494 && verticesAsFloats[v1 + 1] == verticesAsFloats[v2 + 1]
495 && verticesAsFloats[v1 + 2] == verticesAsFloats[v2 + 2])
496 || ( verticesAsFloats[v2 + 0] == verticesAsFloats[v3 + 0]
497 && verticesAsFloats[v2 + 1] == verticesAsFloats[v3 + 1]
498 && verticesAsFloats[v2 + 2] == verticesAsFloats[v3 + 2])
499 || ( verticesAsFloats[v1 + 0] == verticesAsFloats[v3 + 0]
500 && verticesAsFloats[v1 + 1] == verticesAsFloats[v3 + 1]
501 && verticesAsFloats[v1 + 2] == verticesAsFloats[v3 + 2]) )
502 )
503 {
504 // None of the vertices of the triangles are the same. This is a good triangle;
505 indices[realIndicesIndex + 0] = indices[tri + 0];
506 indices[realIndicesIndex + 1] = indices[tri + 1];
507 indices[realIndicesIndex + 2] = indices[tri + 2];
508 realIndicesIndex += 3;
509 }
510 }
511 }
512 physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,key={1},origTri={2},realTri={3},numVerts={4}",
513 BSScene.DetailLogZero, newMeshKey.ToString("X"), indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3);
514
515 if (realIndicesIndex != 0)
516 {
517 newShape = makeShape(physicsScene.World, realIndicesIndex, indices, verticesAsFloats.Length / 3, verticesAsFloats);
518 }
519 else
520 {
521 // Force the asset condition to 'failed' so we won't try to keep fetching and processing this mesh.
522 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
523 physicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim {1} at {2} in {3}",
524 LogHeader, prim.PhysObjectName, prim.RawPosition, physicsScene.Name);
525 physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,allDegenerate,key={1}", prim.LocalID, newMeshKey);
526 }
527 }
528 newShape.shapeKey = newMeshKey;
529
530 return newShape;
531 }
192} 532}
193 533
534// ============================================================================================================
194public class BSShapeHull : BSShape 535public class BSShapeHull : BSShape
195{ 536{
196 private static string LogHeader = "[BULLETSIM SHAPE HULL]"; 537 private static string LogHeader = "[BULLETSIM SHAPE HULL]";
197 private static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>(); 538 public static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>();
198 539
199 public BSShapeHull() : base() 540 public BSShapeHull(BulletShape pShape) : base(pShape)
200 { 541 {
201 } 542 }
202 public static BSShape GetReference() { return new BSShapeNull(); } 543 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
203 public override void Dereference(BSScene physicsScene) { } 544 {
545 float lod;
546 System.UInt64 newHullKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
547
548 BSShapeHull retHull = null;
549 lock (Hulls)
550 {
551 if (Hulls.TryGetValue(newHullKey, out retHull))
552 {
553 // The mesh has already been created. Return a new reference to same.
554 retHull.IncrementReference();
555 }
556 else
557 {
558 retHull = new BSShapeHull(new BulletShape());
559 // An instance of this mesh has not been created. Build and remember same.
560 BulletShape newShape = retHull.CreatePhysicalHull(physicsScene, prim, newHullKey, prim.BaseShape, prim.Size, lod);
561
562 // Check to see if hull was created (might require an asset).
563 newShape = VerifyMeshCreated(physicsScene, newShape, prim);
564 if (!newShape.isNativeShape || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed)
565 {
566 // If a mesh was what was created, remember the built shape for later sharing.
567 Hulls.Add(newHullKey, retHull);
568 }
569 retHull.physShapeInfo = newShape;
570 }
571 }
572 physicsScene.DetailLog("{0},BSShapeHull,getReference,hull={1},size={2},lod={3}", prim.LocalID, retHull, prim.Size, lod);
573 return retHull;
574 }
575 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
576 {
577 BSShape ret = null;
578 // If the underlying shape is native, the actual shape has not been build (waiting for asset)
579 // and we must create a copy of the native shape since they are never shared.
580 if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape)
581 {
582 // TODO: decide when the native shapes should be freed. Check in Dereference?
583 ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
584 }
585 else
586 {
587 // Another reference to this shape is just counted.
588 IncrementReference();
589 ret = this;
590 }
591 return ret;
592 }
593 public override void Dereference(BSScene physicsScene)
594 {
595 lock (Hulls)
596 {
597 this.DecrementReference();
598 physicsScene.DetailLog("{0},BSShapeHull.Dereference,shape={1}", BSScene.DetailLogZero, this);
599 // TODO: schedule aging and destruction of unused meshes.
600 }
601 }
602 List<ConvexResult> m_hulls;
603 private BulletShape CreatePhysicalHull(BSScene physicsScene, BSPhysObject prim, System.UInt64 newHullKey,
604 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
605 {
606 BulletShape newShape = new BulletShape();
607
608 IMesh meshData = null;
609 List<List<OMV.Vector3>> allHulls = null;
610 lock (physicsScene.mesher)
611 {
612 // Pass true for physicalness as this prevents the creation of bounding box which is not needed
613 meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */, false, false);
614
615 // If we should use the asset's hull info, fetch it out of the locked mesher
616 if (meshData != null && BSParam.ShouldUseAssetHulls)
617 {
618 Meshmerizer realMesher = physicsScene.mesher as Meshmerizer;
619 if (realMesher != null)
620 {
621 allHulls = realMesher.GetConvexHulls(size);
622 }
623 if (allHulls == null)
624 {
625 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,noAssetHull", prim.LocalID);
626 }
627 }
628 }
629
630 // If there is hull data in the mesh asset, build the hull from that
631 if (allHulls != null && BSParam.ShouldUseAssetHulls)
632 {
633 int hullCount = allHulls.Count;
634 int totalVertices = 1; // include one for the count of the hulls
635 // Using the structure described for HACD hulls, create the memory sturcture
636 // to pass the hull data to the creater.
637 foreach (List<OMV.Vector3> hullVerts in allHulls)
638 {
639 totalVertices += 4; // add four for the vertex count and centroid
640 totalVertices += hullVerts.Count * 3; // one vertex is three dimensions
641 }
642 float[] convHulls = new float[totalVertices];
643
644 convHulls[0] = (float)hullCount;
645 int jj = 1;
646 foreach (List<OMV.Vector3> hullVerts in allHulls)
647 {
648 convHulls[jj + 0] = hullVerts.Count;
649 convHulls[jj + 1] = 0f; // centroid x,y,z
650 convHulls[jj + 2] = 0f;
651 convHulls[jj + 3] = 0f;
652 jj += 4;
653 foreach (OMV.Vector3 oneVert in hullVerts)
654 {
655 convHulls[jj + 0] = oneVert.X;
656 convHulls[jj + 1] = oneVert.Y;
657 convHulls[jj + 2] = oneVert.Z;
658 jj += 3;
659 }
660 }
661
662 // create the hull data structure in Bullet
663 newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls);
664
665 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,hulls={1},totVert={2},shape={3}",
666 prim.LocalID, hullCount, totalVertices, newShape);
667 }
668
669 // If no hull specified in the asset and we should use Bullet's HACD approximation...
670 if (!newShape.HasPhysicalShape && BSParam.ShouldUseBulletHACD)
671 {
672 // Build the hull shape from an existing mesh shape.
673 // The mesh should have already been created in Bullet.
674 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,entry", prim.LocalID);
675 BSShape meshShape = BSShapeMesh.GetReference(physicsScene, true, prim);
676
677 if (meshShape.physShapeInfo.HasPhysicalShape)
678 {
679 HACDParams parms;
680 parms.maxVerticesPerHull = BSParam.BHullMaxVerticesPerHull;
681 parms.minClusters = BSParam.BHullMinClusters;
682 parms.compacityWeight = BSParam.BHullCompacityWeight;
683 parms.volumeWeight = BSParam.BHullVolumeWeight;
684 parms.concavity = BSParam.BHullConcavity;
685 parms.addExtraDistPoints = BSParam.NumericBool(BSParam.BHullAddExtraDistPoints);
686 parms.addNeighboursDistPoints = BSParam.NumericBool(BSParam.BHullAddNeighboursDistPoints);
687 parms.addFacesPoints = BSParam.NumericBool(BSParam.BHullAddFacesPoints);
688 parms.shouldAdjustCollisionMargin = BSParam.NumericBool(BSParam.BHullShouldAdjustCollisionMargin);
689
690 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,beforeCall", prim.LocalID, newShape.HasPhysicalShape);
691 newShape = physicsScene.PE.BuildHullShapeFromMesh(physicsScene.World, meshShape.physShapeInfo, parms);
692 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,shape={1}", prim.LocalID, newShape);
693
694 // Now done with the mesh shape.
695 meshShape.Dereference(physicsScene);
696 }
697 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape);
698 }
699
700 // If no other hull specifications, use our HACD hull approximation.
701 if (!newShape.HasPhysicalShape && meshData != null)
702 {
703 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
704 {
705 // Release the fetched asset data once it has been used.
706 pbs.SculptData = new byte[0];
707 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown;
708 }
709
710 int[] indices = meshData.getIndexListAsInt();
711 List<OMV.Vector3> vertices = meshData.getVertexList();
712
713 //format conversion from IMesh format to DecompDesc format
714 List<int> convIndices = new List<int>();
715 List<float3> convVertices = new List<float3>();
716 for (int ii = 0; ii < indices.GetLength(0); ii++)
717 {
718 convIndices.Add(indices[ii]);
719 }
720 foreach (OMV.Vector3 vv in vertices)
721 {
722 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
723 }
724
725 uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit;
726 if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes)
727 {
728 // Simple primitive shapes we know are convex so they are better implemented with
729 // fewer hulls.
730 // Check for simple shape (prim without cuts) and reduce split parameter if so.
731 if (BSShapeCollection.PrimHasNoCuts(pbs))
732 {
733 maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes;
734 }
735 }
736
737 // setup and do convex hull conversion
738 m_hulls = new List<ConvexResult>();
739 DecompDesc dcomp = new DecompDesc();
740 dcomp.mIndices = convIndices;
741 dcomp.mVertices = convVertices;
742 dcomp.mDepth = maxDepthSplit;
743 dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent;
744 dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent;
745 dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices;
746 dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth;
747 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
748 // create the hull into the _hulls variable
749 convexBuilder.process(dcomp);
750
751 physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}",
752 BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count);
753
754 // Convert the vertices and indices for passing to unmanaged.
755 // The hull information is passed as a large floating point array.
756 // The format is:
757 // convHulls[0] = number of hulls
758 // convHulls[1] = number of vertices in first hull
759 // convHulls[2] = hull centroid X coordinate
760 // convHulls[3] = hull centroid Y coordinate
761 // convHulls[4] = hull centroid Z coordinate
762 // convHulls[5] = first hull vertex X
763 // convHulls[6] = first hull vertex Y
764 // convHulls[7] = first hull vertex Z
765 // convHulls[8] = second hull vertex X
766 // ...
767 // convHulls[n] = number of vertices in second hull
768 // convHulls[n+1] = second hull centroid X coordinate
769 // ...
770 //
771 // TODO: is is very inefficient. Someday change the convex hull generator to return
772 // data structures that do not need to be converted in order to pass to Bullet.
773 // And maybe put the values directly into pinned memory rather than marshaling.
774 int hullCount = m_hulls.Count;
775 int totalVertices = 1; // include one for the count of the hulls
776 foreach (ConvexResult cr in m_hulls)
777 {
778 totalVertices += 4; // add four for the vertex count and centroid
779 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
780 }
781 float[] convHulls = new float[totalVertices];
782
783 convHulls[0] = (float)hullCount;
784 int jj = 1;
785 foreach (ConvexResult cr in m_hulls)
786 {
787 // copy vertices for index access
788 float3[] verts = new float3[cr.HullVertices.Count];
789 int kk = 0;
790 foreach (float3 ff in cr.HullVertices)
791 {
792 verts[kk++] = ff;
793 }
794
795 // add to the array one hull's worth of data
796 convHulls[jj++] = cr.HullIndices.Count;
797 convHulls[jj++] = 0f; // centroid x,y,z
798 convHulls[jj++] = 0f;
799 convHulls[jj++] = 0f;
800 foreach (int ind in cr.HullIndices)
801 {
802 convHulls[jj++] = verts[ind].x;
803 convHulls[jj++] = verts[ind].y;
804 convHulls[jj++] = verts[ind].z;
805 }
806 }
807 // create the hull data structure in Bullet
808 newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls);
809 }
810 newShape.shapeKey = newHullKey;
811 return newShape;
812 }
813 // Callback from convex hull creater with a newly created hull.
814 // Just add it to our collection of hulls for this shape.
815 private void HullReturn(ConvexResult result)
816 {
817 m_hulls.Add(result);
818 return;
819 }
820 // Loop through all the known hulls and return the description based on the physical address.
821 public static bool TryGetHullByPtr(BulletShape pShape, out BSShapeHull outHull)
822 {
823 bool ret = false;
824 BSShapeHull foundDesc = null;
825 lock (Hulls)
826 {
827 foreach (BSShapeHull sh in Hulls.Values)
828 {
829 if (sh.physShapeInfo.ReferenceSame(pShape))
830 {
831 foundDesc = sh;
832 ret = true;
833 break;
834 }
835
836 }
837 }
838 outHull = foundDesc;
839 return ret;
840 }
204} 841}
205 842
843// ============================================================================================================
206public class BSShapeCompound : BSShape 844public class BSShapeCompound : BSShape
207{ 845{
208 private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]"; 846 private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]";
209 public BSShapeCompound() : base() 847 public BSShapeCompound(BulletShape pShape) : base(pShape)
210 { 848 {
211 } 849 }
212 public static BSShape GetReference(BSPhysObject prim) 850 public static BSShape GetReference(BSScene physicsScene)
213 { 851 {
214 return new BSShapeNull(); 852 // Base compound shapes are not shared so this returns a raw shape.
853 // A built compound shape can be reused in linksets.
854 return new BSShapeCompound(CreatePhysicalCompoundShape(physicsScene));
855 }
856 public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim)
857 {
858 // Calling this reference means we want another handle to an existing compound shape
859 // (usually linksets) so return this copy.
860 IncrementReference();
861 return this;
862 }
863 // Dereferencing a compound shape releases the hold on all the child shapes.
864 public override void Dereference(BSScene physicsScene)
865 {
866 lock (physShapeInfo)
867 {
868 this.DecrementReference();
869 physicsScene.DetailLog("{0},BSShapeCompound.Dereference,shape={1}", BSScene.DetailLogZero, this);
870 if (referenceCount <= 0)
871 {
872 if (!physicsScene.PE.IsCompound(physShapeInfo))
873 {
874 // Failed the sanity check!!
875 physicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}",
876 LogHeader, physShapeInfo.shapeType, physShapeInfo.AddrString);
877 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
878 BSScene.DetailLogZero, physShapeInfo.shapeType, physShapeInfo.AddrString);
879 return;
880 }
881
882 int numChildren = physicsScene.PE.GetNumberOfCompoundChildren(physShapeInfo);
883 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}",
884 BSScene.DetailLogZero, physShapeInfo, numChildren);
885
886 // Loop through all the children dereferencing each.
887 for (int ii = numChildren - 1; ii >= 0; ii--)
888 {
889 BulletShape childShape = physicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(physShapeInfo, ii);
890 DereferenceAnonCollisionShape(physicsScene, childShape);
891 }
892 physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo);
893 }
894 }
895 }
896 private static BulletShape CreatePhysicalCompoundShape(BSScene physicsScene)
897 {
898 BulletShape cShape = physicsScene.PE.CreateCompoundShape(physicsScene.World, false);
899 return cShape;
900 }
901 // Sometimes we have a pointer to a collision shape but don't know what type it is.
902 // Figure out type and call the correct dereference routine.
903 // Called at taint-time.
904 private void DereferenceAnonCollisionShape(BSScene physicsScene, BulletShape pShape)
905 {
906 // TODO: figure a better way to go through all the shape types and find a possible instance.
907 BSShapeMesh meshDesc;
908 if (BSShapeMesh.TryGetMeshByPtr(pShape, out meshDesc))
909 {
910 meshDesc.Dereference(physicsScene);
911 }
912 else
913 {
914 BSShapeHull hullDesc;
915 if (BSShapeHull.TryGetHullByPtr(pShape, out hullDesc))
916 {
917 hullDesc.Dereference(physicsScene);
918 }
919 else
920 {
921 BSShapeConvexHull chullDesc;
922 if (BSShapeConvexHull.TryGetHullByPtr(pShape, out chullDesc))
923 {
924 chullDesc.Dereference(physicsScene);
925 }
926 else
927 {
928 BSShapeGImpact gImpactDesc;
929 if (BSShapeGImpact.TryGetGImpactByPtr(pShape, out gImpactDesc))
930 {
931 gImpactDesc.Dereference(physicsScene);
932 }
933 else
934 {
935 // Didn't find it in the lists of specific types. It could be compound.
936 if (physicsScene.PE.IsCompound(pShape))
937 {
938 BSShapeCompound recursiveCompound = new BSShapeCompound(pShape);
939 recursiveCompound.Dereference(physicsScene);
940 }
941 else
942 {
943 // If none of the above, maybe it is a simple native shape.
944 if (physicsScene.PE.IsNativeShape(pShape))
945 {
946 BSShapeNative nativeShape = new BSShapeNative(pShape);
947 nativeShape.Dereference(physicsScene);
948 }
949 }
950 }
951 }
952 }
953 }
954 }
955}
956
957// ============================================================================================================
958public class BSShapeConvexHull : BSShape
959{
960 private static string LogHeader = "[BULLETSIM SHAPE CONVEX HULL]";
961 public static Dictionary<System.UInt64, BSShapeConvexHull> ConvexHulls = new Dictionary<System.UInt64, BSShapeConvexHull>();
962
963 public BSShapeConvexHull(BulletShape pShape) : base(pShape)
964 {
965 }
966 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
967 {
968 float lod;
969 System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
970
971 physicsScene.DetailLog("{0},BSShapeConvexHull,getReference,newKey={1},size={2},lod={3}",
972 prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod);
973
974 BSShapeConvexHull retConvexHull = null;
975 lock (ConvexHulls)
976 {
977 if (ConvexHulls.TryGetValue(newMeshKey, out retConvexHull))
978 {
979 // The mesh has already been created. Return a new reference to same.
980 retConvexHull.IncrementReference();
981 }
982 else
983 {
984 retConvexHull = new BSShapeConvexHull(new BulletShape());
985 BulletShape convexShape = null;
986
987 // Get a handle to a mesh to build the hull from
988 BSShape baseMesh = BSShapeMesh.GetReference(physicsScene, false /* forceRebuild */, prim);
989 if (baseMesh.physShapeInfo.isNativeShape)
990 {
991 // We get here if the mesh was not creatable. Could be waiting for an asset from the disk.
992 // In the short term, we return the native shape and a later ForceBodyShapeRebuild should
993 // get back to this code with a buildable mesh.
994 // TODO: not sure the temp native shape is freed when the mesh is rebuilt. When does this get freed?
995 convexShape = baseMesh.physShapeInfo;
996 }
997 else
998 {
999 convexShape = physicsScene.PE.BuildConvexHullShapeFromMesh(physicsScene.World, baseMesh.physShapeInfo);
1000 convexShape.shapeKey = newMeshKey;
1001 ConvexHulls.Add(convexShape.shapeKey, retConvexHull);
1002 }
1003
1004 // Done with the base mesh
1005 baseMesh.Dereference(physicsScene);
1006
1007 retConvexHull.physShapeInfo = convexShape;
1008 }
1009 }
1010 return retConvexHull;
1011 }
1012 public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim)
1013 {
1014 // Calling this reference means we want another handle to an existing shape
1015 // (usually linksets) so return this copy.
1016 IncrementReference();
1017 return this;
1018 }
1019 // Dereferencing a compound shape releases the hold on all the child shapes.
1020 public override void Dereference(BSScene physicsScene)
1021 {
1022 lock (ConvexHulls)
1023 {
1024 this.DecrementReference();
1025 physicsScene.DetailLog("{0},BSShapeConvexHull.Dereference,shape={1}", BSScene.DetailLogZero, this);
1026 // TODO: schedule aging and destruction of unused meshes.
1027 }
1028 }
1029 // Loop through all the known hulls and return the description based on the physical address.
1030 public static bool TryGetHullByPtr(BulletShape pShape, out BSShapeConvexHull outHull)
1031 {
1032 bool ret = false;
1033 BSShapeConvexHull foundDesc = null;
1034 lock (ConvexHulls)
1035 {
1036 foreach (BSShapeConvexHull sh in ConvexHulls.Values)
1037 {
1038 if (sh.physShapeInfo.ReferenceSame(pShape))
1039 {
1040 foundDesc = sh;
1041 ret = true;
1042 break;
1043 }
1044
1045 }
1046 }
1047 outHull = foundDesc;
1048 return ret;
215 } 1049 }
216 public override void Dereference(BSScene physicsScene) { }
217} 1050}
1051// ============================================================================================================
1052public class BSShapeGImpact : BSShape
1053{
1054 private static string LogHeader = "[BULLETSIM SHAPE GIMPACT]";
1055 public static Dictionary<System.UInt64, BSShapeGImpact> GImpacts = new Dictionary<System.UInt64, BSShapeGImpact>();
1056
1057 public BSShapeGImpact(BulletShape pShape) : base(pShape)
1058 {
1059 }
1060 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
1061 {
1062 float lod;
1063 System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
1064
1065 physicsScene.DetailLog("{0},BSShapeGImpact,getReference,newKey={1},size={2},lod={3}",
1066 prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod);
1067
1068 BSShapeGImpact retGImpact = null;
1069 lock (GImpacts)
1070 {
1071 if (GImpacts.TryGetValue(newMeshKey, out retGImpact))
1072 {
1073 // The mesh has already been created. Return a new reference to same.
1074 retGImpact.IncrementReference();
1075 }
1076 else
1077 {
1078 retGImpact = new BSShapeGImpact(new BulletShape());
1079 BulletShape newShape = retGImpact.CreatePhysicalGImpact(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod);
218 1080
1081 // Check to see if mesh was created (might require an asset).
1082 newShape = VerifyMeshCreated(physicsScene, newShape, prim);
1083 newShape.shapeKey = newMeshKey;
1084 if (!newShape.isNativeShape || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed)
1085 {
1086 // If a mesh was what was created, remember the built shape for later sharing.
1087 // Also note that if meshing failed we put it in the mesh list as there is nothing else to do about the mesh.
1088 GImpacts.Add(newMeshKey, retGImpact);
1089 }
1090
1091 retGImpact.physShapeInfo = newShape;
1092 }
1093 }
1094 return retGImpact;
1095 }
1096
1097 private BulletShape CreatePhysicalGImpact(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey,
1098 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
1099 {
1100 return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod,
1101 (w, iC, i, vC, v) => physicsScene.PE.CreateGImpactShape(w, iC, i, vC, v) );
1102 }
1103
1104 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
1105 {
1106 BSShape ret = null;
1107 // If the underlying shape is native, the actual shape has not been build (waiting for asset)
1108 // and we must create a copy of the native shape since they are never shared.
1109 if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape)
1110 {
1111 // TODO: decide when the native shapes should be freed. Check in Dereference?
1112 ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
1113 }
1114 else
1115 {
1116 // Another reference to this shape is just counted.
1117 IncrementReference();
1118 ret = this;
1119 }
1120 return ret;
1121 }
1122 // Dereferencing a compound shape releases the hold on all the child shapes.
1123 public override void Dereference(BSScene physicsScene)
1124 {
1125 lock (GImpacts)
1126 {
1127 this.DecrementReference();
1128 physicsScene.DetailLog("{0},BSShapeGImpact.Dereference,shape={1}", BSScene.DetailLogZero, this);
1129 // TODO: schedule aging and destruction of unused meshes.
1130 }
1131 }
1132 // Loop through all the known hulls and return the description based on the physical address.
1133 public static bool TryGetGImpactByPtr(BulletShape pShape, out BSShapeGImpact outHull)
1134 {
1135 bool ret = false;
1136 BSShapeGImpact foundDesc = null;
1137 lock (GImpacts)
1138 {
1139 foreach (BSShapeGImpact sh in GImpacts.Values)
1140 {
1141 if (sh.physShapeInfo.ReferenceSame(pShape))
1142 {
1143 foundDesc = sh;
1144 ret = true;
1145 break;
1146 }
1147
1148 }
1149 }
1150 outHull = foundDesc;
1151 return ret;
1152 }
1153}
1154
1155// ============================================================================================================
219public class BSShapeAvatar : BSShape 1156public class BSShapeAvatar : BSShape
220{ 1157{
221 private static string LogHeader = "[BULLETSIM SHAPE AVATAR]"; 1158 private static string LogHeader = "[BULLETSIM SHAPE AVATAR]";
222 public BSShapeAvatar() : base() 1159 public BSShapeAvatar() : base()
223 { 1160 {
224 } 1161 }
225 public static BSShape GetReference(BSPhysObject prim) 1162 public static BSShape GetReference(BSPhysObject prim)
226 { 1163 {
1164 return new BSShapeNull();
1165 }
1166 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
1167 {
227 return new BSShapeNull(); 1168 return new BSShapeNull();
228 } 1169 }
229 public override void Dereference(BSScene physicsScene) { } 1170 public override void Dereference(BSScene physicsScene) { }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
index e4fecc3..c7deb4e 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
@@ -68,7 +68,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
68 68
69 // This minCoords and maxCoords passed in give the size of the terrain (min and max Z 69 // This minCoords and maxCoords passed in give the size of the terrain (min and max Z
70 // are the high and low points of the heightmap). 70 // are the high and low points of the heightmap).
71 public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap, 71 public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap,
72 Vector3 minCoords, Vector3 maxCoords) 72 Vector3 minCoords, Vector3 maxCoords)
73 : base(physicsScene, regionBase, id) 73 : base(physicsScene, regionBase, id)
74 { 74 {
@@ -92,7 +92,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
92 private void BuildHeightmapTerrain() 92 private void BuildHeightmapTerrain()
93 { 93 {
94 // Create the terrain shape from the mapInfo 94 // Create the terrain shape from the mapInfo
95 m_mapInfo.terrainShape = PhysicsScene.PE.CreateTerrainShape( m_mapInfo.ID, 95 m_mapInfo.terrainShape = m_physicsScene.PE.CreateTerrainShape( m_mapInfo.ID,
96 new Vector3(m_mapInfo.sizeX, m_mapInfo.sizeY, 0), m_mapInfo.minZ, m_mapInfo.maxZ, 96 new Vector3(m_mapInfo.sizeX, m_mapInfo.sizeY, 0), m_mapInfo.minZ, m_mapInfo.maxZ,
97 m_mapInfo.heightMap, 1f, BSParam.TerrainCollisionMargin); 97 m_mapInfo.heightMap, 1f, BSParam.TerrainCollisionMargin);
98 98
@@ -103,26 +103,26 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
103 centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f); 103 centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f);
104 centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f); 104 centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f);
105 105
106 m_mapInfo.terrainBody = PhysicsScene.PE.CreateBodyWithDefaultMotionState(m_mapInfo.terrainShape, 106 m_mapInfo.terrainBody = m_physicsScene.PE.CreateBodyWithDefaultMotionState(m_mapInfo.terrainShape,
107 m_mapInfo.ID, centerPos, Quaternion.Identity); 107 m_mapInfo.ID, centerPos, Quaternion.Identity);
108 108
109 // Set current terrain attributes 109 // Set current terrain attributes
110 PhysicsScene.PE.SetFriction(m_mapInfo.terrainBody, BSParam.TerrainFriction); 110 m_physicsScene.PE.SetFriction(m_mapInfo.terrainBody, BSParam.TerrainFriction);
111 PhysicsScene.PE.SetHitFraction(m_mapInfo.terrainBody, BSParam.TerrainHitFraction); 111 m_physicsScene.PE.SetHitFraction(m_mapInfo.terrainBody, BSParam.TerrainHitFraction);
112 PhysicsScene.PE.SetRestitution(m_mapInfo.terrainBody, BSParam.TerrainRestitution); 112 m_physicsScene.PE.SetRestitution(m_mapInfo.terrainBody, BSParam.TerrainRestitution);
113 PhysicsScene.PE.SetCollisionFlags(m_mapInfo.terrainBody, CollisionFlags.CF_STATIC_OBJECT); 113 m_physicsScene.PE.SetCollisionFlags(m_mapInfo.terrainBody, CollisionFlags.CF_STATIC_OBJECT);
114 114
115 // Return the new terrain to the world of physical objects 115 // Return the new terrain to the world of physical objects
116 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_mapInfo.terrainBody); 116 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_mapInfo.terrainBody);
117 117
118 // redo its bounding box now that it is in the world 118 // redo its bounding box now that it is in the world
119 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_mapInfo.terrainBody); 119 m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_mapInfo.terrainBody);
120 120
121 m_mapInfo.terrainBody.collisionType = CollisionType.Terrain; 121 m_mapInfo.terrainBody.collisionType = CollisionType.Terrain;
122 m_mapInfo.terrainBody.ApplyCollisionMask(PhysicsScene); 122 m_mapInfo.terrainBody.ApplyCollisionMask(m_physicsScene);
123 123
124 // Make it so the terrain will not move or be considered for movement. 124 // Make it so the terrain will not move or be considered for movement.
125 PhysicsScene.PE.ForceActivationState(m_mapInfo.terrainBody, ActivationState.DISABLE_SIMULATION); 125 m_physicsScene.PE.ForceActivationState(m_mapInfo.terrainBody, ActivationState.DISABLE_SIMULATION);
126 126
127 return; 127 return;
128 } 128 }
@@ -134,9 +134,9 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
134 { 134 {
135 if (m_mapInfo.terrainBody.HasPhysicalBody) 135 if (m_mapInfo.terrainBody.HasPhysicalBody)
136 { 136 {
137 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_mapInfo.terrainBody); 137 m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_mapInfo.terrainBody);
138 // Frees both the body and the shape. 138 // Frees both the body and the shape.
139 PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_mapInfo.terrainBody); 139 m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_mapInfo.terrainBody);
140 } 140 }
141 } 141 }
142 m_mapInfo = null; 142 m_mapInfo = null;
@@ -155,7 +155,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
155 catch 155 catch
156 { 156 {
157 // Sometimes they give us wonky values of X and Y. Give a warning and return something. 157 // Sometimes they give us wonky values of X and Y. Give a warning and return something.
158 PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}", 158 m_physicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}",
159 LogHeader, m_mapInfo.terrainRegionBase, pos); 159 LogHeader, m_mapInfo.terrainRegionBase, pos);
160 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; 160 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
161 } 161 }
@@ -165,7 +165,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
165 // The passed position is relative to the base of the region. 165 // The passed position is relative to the base of the region.
166 public override float GetWaterLevelAtXYZ(Vector3 pos) 166 public override float GetWaterLevelAtXYZ(Vector3 pos)
167 { 167 {
168 return PhysicsScene.SimpleWaterLevel; 168 return m_physicsScene.SimpleWaterLevel;
169 } 169 }
170} 170}
171} 171}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
index b2fb835..c4807c4 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
@@ -50,14 +50,14 @@ public abstract class BSTerrainPhys : IDisposable
50 Mesh = 1 50 Mesh = 1
51 } 51 }
52 52
53 public BSScene PhysicsScene { get; private set; } 53 protected BSScene m_physicsScene { get; private set; }
54 // Base of the region in world coordinates. Coordinates inside the region are relative to this. 54 // Base of the region in world coordinates. Coordinates inside the region are relative to this.
55 public Vector3 TerrainBase { get; private set; } 55 public Vector3 TerrainBase { get; private set; }
56 public uint ID { get; private set; } 56 public uint ID { get; private set; }
57 57
58 public BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id) 58 public BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id)
59 { 59 {
60 PhysicsScene = physicsScene; 60 m_physicsScene = physicsScene;
61 TerrainBase = regionBase; 61 TerrainBase = regionBase;
62 ID = id; 62 ID = id;
63 } 63 }
@@ -86,7 +86,7 @@ public sealed class BSTerrainManager : IDisposable
86 public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); 86 public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
87 87
88 // The scene that I am part of 88 // The scene that I am part of
89 private BSScene PhysicsScene { get; set; } 89 private BSScene m_physicsScene { get; set; }
90 90
91 // The ground plane created to keep thing from falling to infinity. 91 // The ground plane created to keep thing from falling to infinity.
92 private BulletBody m_groundPlane; 92 private BulletBody m_groundPlane;
@@ -113,7 +113,7 @@ public sealed class BSTerrainManager : IDisposable
113 113
114 public BSTerrainManager(BSScene physicsScene) 114 public BSTerrainManager(BSScene physicsScene)
115 { 115 {
116 PhysicsScene = physicsScene; 116 m_physicsScene = physicsScene;
117 m_terrains = new Dictionary<Vector3,BSTerrainPhys>(); 117 m_terrains = new Dictionary<Vector3,BSTerrainPhys>();
118 118
119 // Assume one region of default size 119 // Assume one region of default size
@@ -132,21 +132,21 @@ public sealed class BSTerrainManager : IDisposable
132 // safe to call Bullet in real time. We hope no one is moving prims around yet. 132 // safe to call Bullet in real time. We hope no one is moving prims around yet.
133 public void CreateInitialGroundPlaneAndTerrain() 133 public void CreateInitialGroundPlaneAndTerrain()
134 { 134 {
135 DetailLog("{0},BSTerrainManager.CreateInitialGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, PhysicsScene.RegionName); 135 DetailLog("{0},BSTerrainManager.CreateInitialGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName);
136 // The ground plane is here to catch things that are trying to drop to negative infinity 136 // The ground plane is here to catch things that are trying to drop to negative infinity
137 BulletShape groundPlaneShape = PhysicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin); 137 BulletShape groundPlaneShape = m_physicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin);
138 m_groundPlane = PhysicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape, 138 m_groundPlane = m_physicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape,
139 BSScene.GROUNDPLANE_ID, Vector3.Zero, Quaternion.Identity); 139 BSScene.GROUNDPLANE_ID, Vector3.Zero, Quaternion.Identity);
140 140
141 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_groundPlane); 141 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_groundPlane);
142 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_groundPlane); 142 m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_groundPlane);
143 // Ground plane does not move 143 // Ground plane does not move
144 PhysicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION); 144 m_physicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION);
145 // Everything collides with the ground plane. 145 // Everything collides with the ground plane.
146 m_groundPlane.collisionType = CollisionType.Groundplane; 146 m_groundPlane.collisionType = CollisionType.Groundplane;
147 m_groundPlane.ApplyCollisionMask(PhysicsScene); 147 m_groundPlane.ApplyCollisionMask(m_physicsScene);
148 148
149 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); 149 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(m_physicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize);
150 lock (m_terrains) 150 lock (m_terrains)
151 { 151 {
152 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. 152 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
@@ -157,12 +157,12 @@ public sealed class BSTerrainManager : IDisposable
157 // Release all the terrain structures we might have allocated 157 // Release all the terrain structures we might have allocated
158 public void ReleaseGroundPlaneAndTerrain() 158 public void ReleaseGroundPlaneAndTerrain()
159 { 159 {
160 DetailLog("{0},BSTerrainManager.ReleaseGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, PhysicsScene.RegionName); 160 DetailLog("{0},BSTerrainManager.ReleaseGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName);
161 if (m_groundPlane.HasPhysicalBody) 161 if (m_groundPlane.HasPhysicalBody)
162 { 162 {
163 if (PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_groundPlane)) 163 if (m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_groundPlane))
164 { 164 {
165 PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_groundPlane); 165 m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_groundPlane);
166 } 166 }
167 m_groundPlane.Clear(); 167 m_groundPlane.Clear();
168 } 168 }
@@ -188,7 +188,7 @@ public sealed class BSTerrainManager : IDisposable
188 float[] localHeightMap = heightMap; 188 float[] localHeightMap = heightMap;
189 // If there are multiple requests for changes to the same terrain between ticks, 189 // If there are multiple requests for changes to the same terrain between ticks,
190 // only do that last one. 190 // only do that last one.
191 PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate() 191 m_physicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate()
192 { 192 {
193 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) 193 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
194 { 194 {
@@ -199,15 +199,8 @@ public sealed class BSTerrainManager : IDisposable
199 if (MegaRegionParentPhysicsScene is BSScene) 199 if (MegaRegionParentPhysicsScene is BSScene)
200 { 200 {
201 DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", BSScene.DetailLogZero, m_worldOffset, m_worldMax); 201 DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", BSScene.DetailLogZero, m_worldOffset, m_worldMax);
202 // This looks really odd but this region is passing its terrain to its mega-region root region 202 ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.AddMegaRegionChildTerrain(
203 // and the creation of the terrain must happen on the root region's taint thread and not 203 BSScene.CHILDTERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize);
204 // my taint thread.
205 ((BSScene)MegaRegionParentPhysicsScene).PostTaintObject("TerrainManager.SetTerrain.Mega-" + m_worldOffset.ToString(), 0, delegate()
206 {
207 ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateTerrain(
208 BSScene.CHILDTERRAIN_ID, localHeightMap,
209 m_worldOffset, m_worldOffset + DefaultRegionSize, true /* inTaintTime */);
210 });
211 } 204 }
212 } 205 }
213 else 206 else
@@ -215,12 +208,23 @@ public sealed class BSTerrainManager : IDisposable
215 // If not doing the mega-prim thing, just change the terrain 208 // If not doing the mega-prim thing, just change the terrain
216 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero); 209 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero);
217 210
218 UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, 211 UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize);
219 m_worldOffset, m_worldOffset + DefaultRegionSize, true /* inTaintTime */);
220 } 212 }
221 }); 213 });
222 } 214 }
223 215
216 // Another region is calling this region and passing a terrain.
217 // A region that is not the mega-region root will pass its terrain to the root region so the root region
218 // physics engine will have all the terrains.
219 private void AddMegaRegionChildTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
220 {
221 // Since we are called by another region's thread, the action must be rescheduled onto our processing thread.
222 m_physicsScene.PostTaintObject("TerrainManager.AddMegaRegionChild" + minCoords.ToString(), id, delegate()
223 {
224 UpdateTerrain(id, heightMap, minCoords, maxCoords);
225 });
226 }
227
224 // If called for terrain has has not been previously allocated, a new terrain will be built 228 // If called for terrain has has not been previously allocated, a new terrain will be built
225 // based on the passed information. The 'id' should be either the terrain id or 229 // based on the passed information. The 'id' should be either the terrain id or
226 // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used. 230 // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used.
@@ -230,11 +234,10 @@ public sealed class BSTerrainManager : IDisposable
230 // This call is most often used to update the heightMap and parameters of the terrain. 234 // This call is most often used to update the heightMap and parameters of the terrain.
231 // (The above does suggest that some simplification/refactoring is in order.) 235 // (The above does suggest that some simplification/refactoring is in order.)
232 // Called during taint-time. 236 // Called during taint-time.
233 private void UpdateTerrain(uint id, float[] heightMap, 237 private void UpdateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
234 Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
235 { 238 {
236 DetailLog("{0},BSTerrainManager.UpdateTerrain,call,id={1},minC={2},maxC={3},inTaintTime={4}", 239 DetailLog("{0},BSTerrainManager.UpdateTerrain,call,id={1},minC={2},maxC={3}",
237 BSScene.DetailLogZero, id, minCoords, maxCoords, inTaintTime); 240 BSScene.DetailLogZero, id, minCoords, maxCoords);
238 241
239 // Find high and low points of passed heightmap. 242 // Find high and low points of passed heightmap.
240 // The min and max passed in is usually the area objects can be in (maximum 243 // The min and max passed in is usually the area objects can be in (maximum
@@ -303,7 +306,7 @@ public sealed class BSTerrainManager : IDisposable
303 newTerrainID = ++m_terrainCount; 306 newTerrainID = ++m_terrainCount;
304 307
305 DetailLog("{0},BSTerrainManager.UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}", 308 DetailLog("{0},BSTerrainManager.UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}",
306 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); 309 BSScene.DetailLogZero, newTerrainID, minCoords, maxCoords);
307 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); 310 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
308 m_terrains.Add(terrainRegionBase, newTerrainPhys); 311 m_terrains.Add(terrainRegionBase, newTerrainPhys);
309 312
@@ -315,26 +318,26 @@ public sealed class BSTerrainManager : IDisposable
315 // TODO: redo terrain implementation selection to allow other base types than heightMap. 318 // TODO: redo terrain implementation selection to allow other base types than heightMap.
316 private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) 319 private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
317 { 320 {
318 PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}", 321 m_physicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}",
319 LogHeader, PhysicsScene.RegionName, terrainRegionBase, 322 LogHeader, m_physicsScene.RegionName, terrainRegionBase,
320 (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation); 323 (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation);
321 BSTerrainPhys newTerrainPhys = null; 324 BSTerrainPhys newTerrainPhys = null;
322 switch ((int)BSParam.TerrainImplementation) 325 switch ((int)BSParam.TerrainImplementation)
323 { 326 {
324 case (int)BSTerrainPhys.TerrainImplementation.Heightmap: 327 case (int)BSTerrainPhys.TerrainImplementation.Heightmap:
325 newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id, 328 newTerrainPhys = new BSTerrainHeightmap(m_physicsScene, terrainRegionBase, id,
326 heightMap, minCoords, maxCoords); 329 heightMap, minCoords, maxCoords);
327 break; 330 break;
328 case (int)BSTerrainPhys.TerrainImplementation.Mesh: 331 case (int)BSTerrainPhys.TerrainImplementation.Mesh:
329 newTerrainPhys = new BSTerrainMesh(PhysicsScene, terrainRegionBase, id, 332 newTerrainPhys = new BSTerrainMesh(m_physicsScene, terrainRegionBase, id,
330 heightMap, minCoords, maxCoords); 333 heightMap, minCoords, maxCoords);
331 break; 334 break;
332 default: 335 default:
333 PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}", 336 m_physicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}",
334 LogHeader, 337 LogHeader,
335 (int)BSParam.TerrainImplementation, 338 (int)BSParam.TerrainImplementation,
336 BSParam.TerrainImplementation, 339 BSParam.TerrainImplementation,
337 PhysicsScene.RegionName, terrainRegionBase); 340 m_physicsScene.RegionName, terrainRegionBase);
338 break; 341 break;
339 } 342 }
340 return newTerrainPhys; 343 return newTerrainPhys;
@@ -426,8 +429,8 @@ public sealed class BSTerrainManager : IDisposable
426 } 429 }
427 else 430 else
428 { 431 {
429 PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", 432 m_physicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
430 LogHeader, PhysicsScene.RegionName, tX, tY); 433 LogHeader, m_physicsScene.RegionName, tX, tY);
431 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}", 434 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}",
432 BSScene.DetailLogZero, pos, terrainBaseXYZ); 435 BSScene.DetailLogZero, pos, terrainBaseXYZ);
433 } 436 }
@@ -448,8 +451,8 @@ public sealed class BSTerrainManager : IDisposable
448 } 451 }
449 else 452 else
450 { 453 {
451 PhysicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}", 454 m_physicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}",
452 LogHeader, PhysicsScene.RegionName, pos, terrainBaseXYZ, ret); 455 LogHeader, m_physicsScene.RegionName, pos, terrainBaseXYZ, ret);
453 } 456 }
454 return ret; 457 return ret;
455 } 458 }
@@ -561,7 +564,7 @@ public sealed class BSTerrainManager : IDisposable
561 564
562 private void DetailLog(string msg, params Object[] args) 565 private void DetailLog(string msg, params Object[] args)
563 { 566 {
564 PhysicsScene.PhysicsLogging.Write(msg, args); 567 m_physicsScene.PhysicsLogging.Write(msg, args);
565 } 568 }
566} 569}
567} 570}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
index 2ce1513..e4ca098 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
@@ -51,7 +51,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
51 BulletShape m_terrainShape; 51 BulletShape m_terrainShape;
52 BulletBody m_terrainBody; 52 BulletBody m_terrainBody;
53 53
54 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize) 54 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize)
55 : base(physicsScene, regionBase, id) 55 : base(physicsScene, regionBase, id)
56 { 56 {
57 } 57 }
@@ -62,7 +62,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
62 } 62 }
63 63
64 // Create terrain mesh from a heightmap. 64 // Create terrain mesh from a heightmap.
65 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap, 65 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap,
66 Vector3 minCoords, Vector3 maxCoords) 66 Vector3 minCoords, Vector3 maxCoords)
67 : base(physicsScene, regionBase, id) 67 : base(physicsScene, regionBase, id)
68 { 68 {
@@ -80,7 +80,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
80 if (BSParam.TerrainMeshMagnification == 1) 80 if (BSParam.TerrainMeshMagnification == 1)
81 { 81 {
82 // If a magnification of one, use the old routine that is tried and true. 82 // If a magnification of one, use the old routine that is tried and true.
83 meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh(PhysicsScene, 83 meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh(m_physicsScene,
84 initialMap, m_sizeX, m_sizeY, // input size 84 initialMap, m_sizeX, m_sizeY, // input size
85 Vector3.Zero, // base for mesh 85 Vector3.Zero, // base for mesh
86 out indicesCount, out indices, out verticesCount, out vertices); 86 out indicesCount, out indices, out verticesCount, out vertices);
@@ -88,7 +88,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
88 else 88 else
89 { 89 {
90 // Other magnifications use the newer routine 90 // Other magnifications use the newer routine
91 meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh2(PhysicsScene, 91 meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh2(m_physicsScene,
92 initialMap, m_sizeX, m_sizeY, // input size 92 initialMap, m_sizeX, m_sizeY, // input size
93 BSParam.TerrainMeshMagnification, 93 BSParam.TerrainMeshMagnification,
94 physicsScene.TerrainManager.DefaultRegionSize, 94 physicsScene.TerrainManager.DefaultRegionSize,
@@ -98,21 +98,21 @@ public sealed class BSTerrainMesh : BSTerrainPhys
98 if (!meshCreationSuccess) 98 if (!meshCreationSuccess)
99 { 99 {
100 // DISASTER!! 100 // DISASTER!!
101 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap,id={1}", BSScene.DetailLogZero, ID); 101 m_physicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap,id={1}", BSScene.DetailLogZero, ID);
102 PhysicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase); 102 m_physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase);
103 // Something is very messed up and a crash is in our future. 103 // Something is very messed up and a crash is in our future.
104 return; 104 return;
105 } 105 }
106 106
107 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,id={1},indices={2},indSz={3},vertices={4},vertSz={5}", 107 m_physicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,id={1},indices={2},indSz={3},vertices={4},vertSz={5}",
108 BSScene.DetailLogZero, ID, indicesCount, indices.Length, verticesCount, vertices.Length); 108 BSScene.DetailLogZero, ID, indicesCount, indices.Length, verticesCount, vertices.Length);
109 109
110 m_terrainShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World, indicesCount, indices, verticesCount, vertices); 110 m_terrainShape = m_physicsScene.PE.CreateMeshShape(m_physicsScene.World, indicesCount, indices, verticesCount, vertices);
111 if (!m_terrainShape.HasPhysicalShape) 111 if (!m_terrainShape.HasPhysicalShape)
112 { 112 {
113 // DISASTER!! 113 // DISASTER!!
114 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape,id={1}", BSScene.DetailLogZero, ID); 114 m_physicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape,id={1}", BSScene.DetailLogZero, ID);
115 PhysicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase); 115 m_physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase);
116 // Something is very messed up and a crash is in our future. 116 // Something is very messed up and a crash is in our future.
117 return; 117 return;
118 } 118 }
@@ -120,52 +120,52 @@ public sealed class BSTerrainMesh : BSTerrainPhys
120 Vector3 pos = regionBase; 120 Vector3 pos = regionBase;
121 Quaternion rot = Quaternion.Identity; 121 Quaternion rot = Quaternion.Identity;
122 122
123 m_terrainBody = PhysicsScene.PE.CreateBodyWithDefaultMotionState(m_terrainShape, ID, pos, rot); 123 m_terrainBody = m_physicsScene.PE.CreateBodyWithDefaultMotionState(m_terrainShape, ID, pos, rot);
124 if (!m_terrainBody.HasPhysicalBody) 124 if (!m_terrainBody.HasPhysicalBody)
125 { 125 {
126 // DISASTER!! 126 // DISASTER!!
127 PhysicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase); 127 m_physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase);
128 // Something is very messed up and a crash is in our future. 128 // Something is very messed up and a crash is in our future.
129 return; 129 return;
130 } 130 }
131 physicsScene.PE.SetShapeCollisionMargin(m_terrainShape, BSParam.TerrainCollisionMargin); 131 physicsScene.PE.SetShapeCollisionMargin(m_terrainShape, BSParam.TerrainCollisionMargin);
132 132
133 // Set current terrain attributes 133 // Set current terrain attributes
134 PhysicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction); 134 m_physicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction);
135 PhysicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction); 135 m_physicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction);
136 PhysicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution); 136 m_physicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution);
137 PhysicsScene.PE.SetContactProcessingThreshold(m_terrainBody, BSParam.TerrainContactProcessingThreshold); 137 m_physicsScene.PE.SetContactProcessingThreshold(m_terrainBody, BSParam.TerrainContactProcessingThreshold);
138 PhysicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT); 138 m_physicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT);
139 139
140 // Static objects are not very massive. 140 // Static objects are not very massive.
141 PhysicsScene.PE.SetMassProps(m_terrainBody, 0f, Vector3.Zero); 141 m_physicsScene.PE.SetMassProps(m_terrainBody, 0f, Vector3.Zero);
142 142
143 // Put the new terrain to the world of physical objects 143 // Put the new terrain to the world of physical objects
144 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_terrainBody); 144 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_terrainBody);
145 145
146 // Redo its bounding box now that it is in the world 146 // Redo its bounding box now that it is in the world
147 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_terrainBody); 147 m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_terrainBody);
148 148
149 m_terrainBody.collisionType = CollisionType.Terrain; 149 m_terrainBody.collisionType = CollisionType.Terrain;
150 m_terrainBody.ApplyCollisionMask(PhysicsScene); 150 m_terrainBody.ApplyCollisionMask(m_physicsScene);
151 151
152 if (BSParam.UseSingleSidedMeshes) 152 if (BSParam.UseSingleSidedMeshes)
153 { 153 {
154 PhysicsScene.DetailLog("{0},BSTerrainMesh.settingCustomMaterial,id={1}", BSScene.DetailLogZero, id); 154 m_physicsScene.DetailLog("{0},BSTerrainMesh.settingCustomMaterial,id={1}", BSScene.DetailLogZero, id);
155 PhysicsScene.PE.AddToCollisionFlags(m_terrainBody, CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK); 155 m_physicsScene.PE.AddToCollisionFlags(m_terrainBody, CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK);
156 } 156 }
157 157
158 // Make it so the terrain will not move or be considered for movement. 158 // Make it so the terrain will not move or be considered for movement.
159 PhysicsScene.PE.ForceActivationState(m_terrainBody, ActivationState.DISABLE_SIMULATION); 159 m_physicsScene.PE.ForceActivationState(m_terrainBody, ActivationState.DISABLE_SIMULATION);
160 } 160 }
161 161
162 public override void Dispose() 162 public override void Dispose()
163 { 163 {
164 if (m_terrainBody.HasPhysicalBody) 164 if (m_terrainBody.HasPhysicalBody)
165 { 165 {
166 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_terrainBody); 166 m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_terrainBody);
167 // Frees both the body and the shape. 167 // Frees both the body and the shape.
168 PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_terrainBody); 168 m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_terrainBody);
169 m_terrainBody.Clear(); 169 m_terrainBody.Clear();
170 m_terrainShape.Clear(); 170 m_terrainShape.Clear();
171 } 171 }
@@ -185,7 +185,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
185 catch 185 catch
186 { 186 {
187 // Sometimes they give us wonky values of X and Y. Give a warning and return something. 187 // Sometimes they give us wonky values of X and Y. Give a warning and return something.
188 PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}", 188 m_physicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}",
189 LogHeader, TerrainBase, pos); 189 LogHeader, TerrainBase, pos);
190 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; 190 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
191 } 191 }
@@ -195,7 +195,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
195 // The passed position is relative to the base of the region. 195 // The passed position is relative to the base of the region.
196 public override float GetWaterLevelAtXYZ(Vector3 pos) 196 public override float GetWaterLevelAtXYZ(Vector3 pos)
197 { 197 {
198 return PhysicsScene.SimpleWaterLevel; 198 return m_physicsScene.SimpleWaterLevel;
199 } 199 }
200 200
201 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). 201 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs
index 8012d91..d5060e3 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs
@@ -104,11 +104,11 @@ public class BulletShape
104{ 104{
105 public BulletShape() 105 public BulletShape()
106 { 106 {
107 type = BSPhysicsShapeType.SHAPE_UNKNOWN; 107 shapeType = BSPhysicsShapeType.SHAPE_UNKNOWN;
108 shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE; 108 shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE;
109 isNativeShape = false; 109 isNativeShape = false;
110 } 110 }
111 public BSPhysicsShapeType type; 111 public BSPhysicsShapeType shapeType;
112 public System.UInt64 shapeKey; 112 public System.UInt64 shapeKey;
113 public bool isNativeShape; 113 public bool isNativeShape;
114 114
@@ -133,7 +133,7 @@ public class BulletShape
133 buff.Append("<p="); 133 buff.Append("<p=");
134 buff.Append(AddrString); 134 buff.Append(AddrString);
135 buff.Append(",s="); 135 buff.Append(",s=");
136 buff.Append(type.ToString()); 136 buff.Append(shapeType.ToString());
137 buff.Append(",k="); 137 buff.Append(",k=");
138 buff.Append(shapeKey.ToString("X")); 138 buff.Append(shapeKey.ToString("X"));
139 buff.Append(",n="); 139 buff.Append(",n=");
@@ -224,42 +224,42 @@ public static class BulletSimData
224// As mentioned above, don't use the CollisionFilterGroups definitions directly in the code 224// As mentioned above, don't use the CollisionFilterGroups definitions directly in the code
225// but, instead, use references to this dictionary. Finding and debugging 225// but, instead, use references to this dictionary. Finding and debugging
226// collision flag problems will be made easier. 226// collision flag problems will be made easier.
227public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks 227public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks
228 = new Dictionary<CollisionType, CollisionTypeFilterGroup>() 228 = new Dictionary<CollisionType, CollisionTypeFilterGroup>()
229{ 229{
230 { CollisionType.Avatar, 230 { CollisionType.Avatar,
231 new CollisionTypeFilterGroup(CollisionType.Avatar, 231 new CollisionTypeFilterGroup(CollisionType.Avatar,
232 (uint)CollisionFilterGroups.BCharacterGroup, 232 (uint)CollisionFilterGroups.BCharacterGroup,
233 (uint)CollisionFilterGroups.BAllGroup) 233 (uint)CollisionFilterGroups.BAllGroup)
234 }, 234 },
235 { CollisionType.Groundplane, 235 { CollisionType.Groundplane,
236 new CollisionTypeFilterGroup(CollisionType.Groundplane, 236 new CollisionTypeFilterGroup(CollisionType.Groundplane,
237 (uint)CollisionFilterGroups.BGroundPlaneGroup, 237 (uint)CollisionFilterGroups.BGroundPlaneGroup,
238 (uint)CollisionFilterGroups.BAllGroup) 238 (uint)CollisionFilterGroups.BAllGroup)
239 }, 239 },
240 { CollisionType.Terrain, 240 { CollisionType.Terrain,
241 new CollisionTypeFilterGroup(CollisionType.Terrain, 241 new CollisionTypeFilterGroup(CollisionType.Terrain,
242 (uint)CollisionFilterGroups.BTerrainGroup, 242 (uint)CollisionFilterGroups.BTerrainGroup,
243 (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup)) 243 (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup))
244 }, 244 },
245 { CollisionType.Static, 245 { CollisionType.Static,
246 new CollisionTypeFilterGroup(CollisionType.Static, 246 new CollisionTypeFilterGroup(CollisionType.Static,
247 (uint)CollisionFilterGroups.BStaticGroup, 247 (uint)CollisionFilterGroups.BStaticGroup,
248 (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) 248 (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
249 }, 249 },
250 { CollisionType.Dynamic, 250 { CollisionType.Dynamic,
251 new CollisionTypeFilterGroup(CollisionType.Dynamic, 251 new CollisionTypeFilterGroup(CollisionType.Dynamic,
252 (uint)CollisionFilterGroups.BSolidGroup, 252 (uint)CollisionFilterGroups.BSolidGroup,
253 (uint)(CollisionFilterGroups.BAllGroup)) 253 (uint)(CollisionFilterGroups.BAllGroup))
254 }, 254 },
255 { CollisionType.VolumeDetect, 255 { CollisionType.VolumeDetect,
256 new CollisionTypeFilterGroup(CollisionType.VolumeDetect, 256 new CollisionTypeFilterGroup(CollisionType.VolumeDetect,
257 (uint)CollisionFilterGroups.BSensorTrigger, 257 (uint)CollisionFilterGroups.BSensorTrigger,
258 (uint)(~CollisionFilterGroups.BSensorTrigger)) 258 (uint)(~CollisionFilterGroups.BSensorTrigger))
259 }, 259 },
260 { CollisionType.LinksetChild, 260 { CollisionType.LinksetChild,
261 new CollisionTypeFilterGroup(CollisionType.LinksetChild, 261 new CollisionTypeFilterGroup(CollisionType.LinksetChild,
262 (uint)CollisionFilterGroups.BLinksetChildGroup, 262 (uint)CollisionFilterGroups.BLinksetChildGroup,
263 (uint)(CollisionFilterGroups.BNoneGroup)) 263 (uint)(CollisionFilterGroups.BNoneGroup))
264 // (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) 264 // (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
265 }, 265 },
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
index 8a15abe..df1da63 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
@@ -1,17 +1,23 @@
1CURRENT PRIORITIES 1CURRENT PROBLEMS TO FIX AND/OR LOOK AT
2================================================= 2=================================================
3Use the HACD convex hull routine in Bullet rather than the C# version. 3Script changing rotation of child prim while vehicle moving (eg turning wheel) causes
4 Speed up hullifying large meshes. 4 the wheel to appear to jump back. Looks like sending position from previous update.
5Vehicle ride, get up, ride again. Second time vehicle does not act correctly.
6 Have to rez new vehicle and delete the old to fix situation.
7Hitting RESET on Nebadon's vehicle while riding causes vehicle to get into odd
8 position state where it will not settle onto ground properly, etc
9Two of Nebadon vehicles in a sim max the CPU. This is new.
5Enable vehicle border crossings (at least as poorly as ODE) 10Enable vehicle border crossings (at least as poorly as ODE)
6 Terrain skirts 11 Terrain skirts
7 Avatar created in previous region and not new region when crossing border 12 Avatar created in previous region and not new region when crossing border
8 Vehicle recreated in new sim at small Z value (offset from root value?) (DONE) 13 Vehicle recreated in new sim at small Z value (offset from root value?) (DONE)
9Lock axis
10Deleting a linkset while standing on the root will leave the physical shape of the root behind. 14Deleting a linkset while standing on the root will leave the physical shape of the root behind.
11 Not sure if it is because standing on it. Done with large prim linksets. 15 Not sure if it is because standing on it. Done with large prim linksets.
12Linkset child rotations. 16Linkset child rotations.
13 Nebadon spiral tube has middle sections which are rotated wrong. 17 Nebadon spiral tube has middle sections which are rotated wrong.
14 Select linked spiral tube. Delink and note where the middle section ends up. 18 Select linked spiral tube. Delink and note where the middle section ends up.
19Refarb compound linkset creation to create a pseudo-root for center-of-mass
20 Let children change their shape to physical indendently and just add shapes to compound
15Vehicle angular vertical attraction 21Vehicle angular vertical attraction
16vehicle angular banking 22vehicle angular banking
17Center-of-gravity 23Center-of-gravity
@@ -28,14 +34,13 @@ llLookAt
28Avatars walking up stairs (HALF DONE) 34Avatars walking up stairs (HALF DONE)
29Avatar movement 35Avatar movement
30 flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle (DONE) 36 flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle (DONE)
31 walking up stairs is not calibrated correctly (stairs out of Kepler cabin) 37 walking up stairs is not calibrated correctly (stairs out of Kepler cabin) (DONE)
32 avatar capsule rotation completed (NOT DONE - Bullet's capsule shape is not the solution) 38 avatar capsule rotation completed (NOT DONE - Bullet's capsule shape is not the solution)
33Vehicle script tuning/debugging 39Vehicle script tuning/debugging
34 Avanti speed script 40 Avanti speed script
35 Weapon shooter script 41 Weapon shooter script
36Move material definitions (friction, ...) into simulator. 42Move material definitions (friction, ...) into simulator.
37Add material densities to the material types. 43Add material densities to the material types.
38Terrain detail: double terrain mesh detail
39One sided meshes? Should terrain be built into a closed shape? 44One sided meshes? Should terrain be built into a closed shape?
40 When meshes get partially wedged into the terrain, they cannot push themselves out. 45 When meshes get partially wedged into the terrain, they cannot push themselves out.
41 It is possible that Bullet processes collisions whether entering or leaving a mesh. 46 It is possible that Bullet processes collisions whether entering or leaving a mesh.
@@ -43,6 +48,11 @@ One sided meshes? Should terrain be built into a closed shape?
43 48
44VEHICLES TODO LIST: 49VEHICLES TODO LIST:
45================================================= 50=================================================
51LINEAR_MOTOR_DIRECTION values should be clamped to reasonable numbers.
52 What are the limits in SL?
53 Same for other velocity settings.
54UBit improvements to remove rubber-banding of avatars sitting on vehicle child prims:
55 https://github.com/UbitUmarov/Ubit-opensim
46Border crossing with linked vehicle causes crash 56Border crossing with linked vehicle causes crash
47 20121129.1411: editting/moving phys object across region boundries causes crash 57 20121129.1411: editting/moving phys object across region boundries causes crash
48 getPos-> btRigidBody::upcast -> getBodyType -> BOOM 58 getPos-> btRigidBody::upcast -> getBodyType -> BOOM
@@ -168,6 +178,7 @@ Eliminate collisions between objects in a linkset. (LinksetConstraint)
168 178
169MORE 179MORE
170====================================================== 180======================================================
181Compute avatar size and scale correctly. Now it is a bit off from the capsule size.
171Create tests for different interface components 182Create tests for different interface components
172 Have test objects/scripts measure themselves and turn color if correct/bad 183 Have test objects/scripts measure themselves and turn color if correct/bad
173 Test functions in SL and calibrate correctness there 184 Test functions in SL and calibrate correctness there
@@ -344,3 +355,8 @@ Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE.
344 Verify that angular motion specified around Z moves in the vehicle coordinates. 355 Verify that angular motion specified around Z moves in the vehicle coordinates.
345 DONE 20130120: BulletSim properly applies force in vehicle relative coordinates. 356 DONE 20130120: BulletSim properly applies force in vehicle relative coordinates.
346Nebadon vehicles turning funny in arena (DONE) 357Nebadon vehicles turning funny in arena (DONE)
358Lock axis (DONE 20130401)
359Terrain detail: double terrain mesh detail (DONE)
360Use the HACD convex hull routine in Bullet rather than the C# version.
361 Speed up hullifying large meshes. (DONE)
362
diff --git a/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs b/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs
index 33232bd..b040e21 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs
@@ -114,9 +114,9 @@ public class BasicVehicles : OpenSimTestCase
114 // Instead the appropriate values are set and calls are made just the parts of the 114 // Instead the appropriate values are set and calls are made just the parts of the
115 // controller we want to exercise. Stepping the physics engine then applies 115 // controller we want to exercise. Stepping the physics engine then applies
116 // the actions of that one feature. 116 // the actions of that one feature.
117 TestVehicle.VehicleController.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_EFFICIENCY, efficiency); 117 TestVehicle.VehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_EFFICIENCY, efficiency);
118 TestVehicle.VehicleController.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_TIMESCALE, timeScale); 118 TestVehicle.VehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_TIMESCALE, timeScale);
119 TestVehicle.VehicleController.enableAngularVerticalAttraction = true; 119 TestVehicle.VehicleActor.enableAngularVerticalAttraction = true;
120 120
121 TestVehicle.IsPhysical = true; 121 TestVehicle.IsPhysical = true;
122 PhysicsScene.ProcessTaints(); 122 PhysicsScene.ProcessTaints();
@@ -124,9 +124,9 @@ public class BasicVehicles : OpenSimTestCase
124 // Step the simulator a bunch of times and vertical attraction should orient the vehicle up 124 // Step the simulator a bunch of times and vertical attraction should orient the vehicle up
125 for (int ii = 0; ii < simSteps; ii++) 125 for (int ii = 0; ii < simSteps; ii++)
126 { 126 {
127 TestVehicle.VehicleController.ForgetKnownVehicleProperties(); 127 TestVehicle.VehicleActor.ForgetKnownVehicleProperties();
128 TestVehicle.VehicleController.ComputeAngularVerticalAttraction(); 128 TestVehicle.VehicleActor.ComputeAngularVerticalAttraction();
129 TestVehicle.VehicleController.PushKnownChanged(); 129 TestVehicle.VehicleActor.PushKnownChanged();
130 130
131 PhysicsScene.Simulate(simulationTimeStep); 131 PhysicsScene.Simulate(simulationTimeStep);
132 } 132 }
diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
index d181b78..16d65eb 100644
--- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
+++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
@@ -64,6 +64,7 @@ namespace OpenSim.Region.Physics.Meshing
64 public class Meshmerizer : IMesher 64 public class Meshmerizer : IMesher
65 { 65 {
66 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 66 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
67 private static string LogHeader = "[MESH]";
67 68
68 // Setting baseDir to a path will enable the dumping of raw files 69 // Setting baseDir to a path will enable the dumping of raw files
69 // raw files can be imported by blender so a visual inspection of the results can be done 70 // raw files can be imported by blender so a visual inspection of the results can be done
@@ -72,6 +73,8 @@ namespace OpenSim.Region.Physics.Meshing
72#else 73#else
73 private const string baseDir = null; //"rawFiles"; 74 private const string baseDir = null; //"rawFiles";
74#endif 75#endif
76 // If 'true', lots of DEBUG logging of asset parsing details
77 private bool debugDetail = false;
75 78
76 private bool cacheSculptMaps = true; 79 private bool cacheSculptMaps = true;
77 private string decodedSculptMapPath = null; 80 private string decodedSculptMapPath = null;
@@ -79,6 +82,9 @@ namespace OpenSim.Region.Physics.Meshing
79 82
80 private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh 83 private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh
81 84
85 private List<List<Vector3>> mConvexHulls = null;
86 private List<Vector3> mBoundingHull = null;
87
82 private Dictionary<ulong, Mesh> m_uniqueMeshes = new Dictionary<ulong, Mesh>(); 88 private Dictionary<ulong, Mesh> m_uniqueMeshes = new Dictionary<ulong, Mesh>();
83 89
84 public Meshmerizer(IConfigSource config) 90 public Meshmerizer(IConfigSource config)
@@ -88,8 +94,11 @@ namespace OpenSim.Region.Physics.Meshing
88 94
89 decodedSculptMapPath = start_config.GetString("DecodedSculptMapPath","j2kDecodeCache"); 95 decodedSculptMapPath = start_config.GetString("DecodedSculptMapPath","j2kDecodeCache");
90 cacheSculptMaps = start_config.GetBoolean("CacheSculptMaps", cacheSculptMaps); 96 cacheSculptMaps = start_config.GetBoolean("CacheSculptMaps", cacheSculptMaps);
91 if(mesh_config != null) 97 if (mesh_config != null)
98 {
92 useMeshiesPhysicsMesh = mesh_config.GetBoolean("UseMeshiesPhysicsMesh", useMeshiesPhysicsMesh); 99 useMeshiesPhysicsMesh = mesh_config.GetBoolean("UseMeshiesPhysicsMesh", useMeshiesPhysicsMesh);
100 debugDetail = mesh_config.GetBoolean("LogMeshDetails", debugDetail);
101 }
93 102
94 try 103 try
95 { 104 {
@@ -319,6 +328,9 @@ namespace OpenSim.Region.Physics.Meshing
319 faces = new List<Face>(); 328 faces = new List<Face>();
320 OSD meshOsd = null; 329 OSD meshOsd = null;
321 330
331 mConvexHulls = null;
332 mBoundingHull = null;
333
322 if (primShape.SculptData.Length <= 0) 334 if (primShape.SculptData.Length <= 0)
323 { 335 {
324 // XXX: At the moment we can not log here since ODEPrim, for instance, ends up triggering this 336 // XXX: At the moment we can not log here since ODEPrim, for instance, ends up triggering this
@@ -355,9 +367,139 @@ namespace OpenSim.Region.Physics.Meshing
355 OSDMap physicsParms = null; 367 OSDMap physicsParms = null;
356 OSDMap map = (OSDMap)meshOsd; 368 OSDMap map = (OSDMap)meshOsd;
357 if (map.ContainsKey("physics_shape")) 369 if (map.ContainsKey("physics_shape"))
370 {
358 physicsParms = (OSDMap)map["physics_shape"]; // old asset format 371 physicsParms = (OSDMap)map["physics_shape"]; // old asset format
372 if (debugDetail) m_log.DebugFormat("{0} prim='{1}': using 'physics_shape' mesh data", LogHeader, primName);
373 }
359 else if (map.ContainsKey("physics_mesh")) 374 else if (map.ContainsKey("physics_mesh"))
375 {
360 physicsParms = (OSDMap)map["physics_mesh"]; // new asset format 376 physicsParms = (OSDMap)map["physics_mesh"]; // new asset format
377 if (debugDetail) m_log.DebugFormat("{0} prim='{1}':using 'physics_mesh' mesh data", LogHeader, primName);
378 }
379 else if (map.ContainsKey("medium_lod"))
380 {
381 physicsParms = (OSDMap)map["medium_lod"]; // if no physics mesh, try to fall back to medium LOD display mesh
382 if (debugDetail) m_log.DebugFormat("{0} prim='{1}':using 'medium_lod' mesh data", LogHeader, primName);
383 }
384 else if (map.ContainsKey("high_lod"))
385 {
386 physicsParms = (OSDMap)map["high_lod"]; // if all else fails, use highest LOD display mesh and hope it works :)
387 if (debugDetail) m_log.DebugFormat("{0} prim='{1}':using 'high_lod' mesh data", LogHeader, primName);
388 }
389
390 if (map.ContainsKey("physics_convex"))
391 { // pull this out also in case physics engine can use it
392 OSD convexBlockOsd = null;
393 try
394 {
395 OSDMap convexBlock = (OSDMap)map["physics_convex"];
396 {
397 int convexOffset = convexBlock["offset"].AsInteger() + (int)start;
398 int convexSize = convexBlock["size"].AsInteger();
399
400 byte[] convexBytes = new byte[convexSize];
401
402 System.Buffer.BlockCopy(primShape.SculptData, convexOffset, convexBytes, 0, convexSize);
403
404 try
405 {
406 convexBlockOsd = DecompressOsd(convexBytes);
407 }
408 catch (Exception e)
409 {
410 m_log.ErrorFormat("{0} prim='{1}': exception decoding convex block: {2}", LogHeader, primName, e);
411 //return false;
412 }
413 }
414
415 if (convexBlockOsd != null && convexBlockOsd is OSDMap)
416 {
417 convexBlock = convexBlockOsd as OSDMap;
418
419 if (debugDetail)
420 {
421 string keys = LogHeader + " keys found in convexBlock: ";
422 foreach (KeyValuePair<string, OSD> kvp in convexBlock)
423 keys += "'" + kvp.Key + "' ";
424 m_log.Debug(keys);
425 }
426
427 Vector3 min = new Vector3(-0.5f, -0.5f, -0.5f);
428 if (convexBlock.ContainsKey("Min")) min = convexBlock["Min"].AsVector3();
429 Vector3 max = new Vector3(0.5f, 0.5f, 0.5f);
430 if (convexBlock.ContainsKey("Max")) max = convexBlock["Max"].AsVector3();
431
432 List<Vector3> boundingHull = null;
433
434 if (convexBlock.ContainsKey("BoundingVerts"))
435 {
436 byte[] boundingVertsBytes = convexBlock["BoundingVerts"].AsBinary();
437 boundingHull = new List<Vector3>();
438 for (int i = 0; i < boundingVertsBytes.Length; )
439 {
440 ushort uX = Utils.BytesToUInt16(boundingVertsBytes, i); i += 2;
441 ushort uY = Utils.BytesToUInt16(boundingVertsBytes, i); i += 2;
442 ushort uZ = Utils.BytesToUInt16(boundingVertsBytes, i); i += 2;
443
444 Vector3 pos = new Vector3(
445 Utils.UInt16ToFloat(uX, min.X, max.X),
446 Utils.UInt16ToFloat(uY, min.Y, max.Y),
447 Utils.UInt16ToFloat(uZ, min.Z, max.Z)
448 );
449
450 boundingHull.Add(pos);
451 }
452
453 mBoundingHull = boundingHull;
454 if (debugDetail) m_log.DebugFormat("{0} prim='{1}': parsed bounding hull. nVerts={2}", LogHeader, primName, mBoundingHull.Count);
455 }
456
457 if (convexBlock.ContainsKey("HullList"))
458 {
459 byte[] hullList = convexBlock["HullList"].AsBinary();
460
461 byte[] posBytes = convexBlock["Positions"].AsBinary();
462
463 List<List<Vector3>> hulls = new List<List<Vector3>>();
464 int posNdx = 0;
465
466 foreach (byte cnt in hullList)
467 {
468 int count = cnt == 0 ? 256 : cnt;
469 List<Vector3> hull = new List<Vector3>();
470
471 for (int i = 0; i < count; i++)
472 {
473 ushort uX = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2;
474 ushort uY = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2;
475 ushort uZ = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2;
476
477 Vector3 pos = new Vector3(
478 Utils.UInt16ToFloat(uX, min.X, max.X),
479 Utils.UInt16ToFloat(uY, min.Y, max.Y),
480 Utils.UInt16ToFloat(uZ, min.Z, max.Z)
481 );
482
483 hull.Add(pos);
484 }
485
486 hulls.Add(hull);
487 }
488
489 mConvexHulls = hulls;
490 if (debugDetail) m_log.DebugFormat("{0} prim='{1}': parsed hulls. nHulls={2}", LogHeader, primName, mConvexHulls.Count);
491 }
492 else
493 {
494 if (debugDetail) m_log.DebugFormat("{0} prim='{1}' has physics_convex but no HullList", LogHeader, primName);
495 }
496 }
497 }
498 catch (Exception e)
499 {
500 m_log.WarnFormat("{0} exception decoding convex block: {1}", LogHeader, e);
501 }
502 }
361 503
362 if (physicsParms == null) 504 if (physicsParms == null)
363 { 505 {
@@ -374,34 +516,14 @@ namespace OpenSim.Region.Physics.Meshing
374 OSD decodedMeshOsd = new OSD(); 516 OSD decodedMeshOsd = new OSD();
375 byte[] meshBytes = new byte[physSize]; 517 byte[] meshBytes = new byte[physSize];
376 System.Buffer.BlockCopy(primShape.SculptData, physOffset, meshBytes, 0, physSize); 518 System.Buffer.BlockCopy(primShape.SculptData, physOffset, meshBytes, 0, physSize);
377// byte[] decompressed = new byte[physSize * 5]; 519 // byte[] decompressed = new byte[physSize * 5];
378 try 520 try
379 { 521 {
380 using (MemoryStream inMs = new MemoryStream(meshBytes)) 522 decodedMeshOsd = DecompressOsd(meshBytes);
381 {
382 using (MemoryStream outMs = new MemoryStream())
383 {
384 using (ZOutputStream zOut = new ZOutputStream(outMs))
385 {
386 byte[] readBuffer = new byte[2048];
387 int readLen = 0;
388 while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0)
389 {
390 zOut.Write(readBuffer, 0, readLen);
391 }
392 zOut.Flush();
393 outMs.Seek(0, SeekOrigin.Begin);
394
395 byte[] decompressedBuf = outMs.GetBuffer();
396
397 decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf);
398 }
399 }
400 }
401 } 523 }
402 catch (Exception e) 524 catch (Exception e)
403 { 525 {
404 m_log.Error("[MESH]: exception decoding physical mesh: " + e.ToString()); 526 m_log.ErrorFormat("{0} prim='{1}': exception decoding physical mesh: {2}", LogHeader, primName, e);
405 return false; 527 return false;
406 } 528 }
407 529
@@ -410,7 +532,7 @@ namespace OpenSim.Region.Physics.Meshing
410 // physics_shape is an array of OSDMaps, one for each submesh 532 // physics_shape is an array of OSDMaps, one for each submesh
411 if (decodedMeshOsd is OSDArray) 533 if (decodedMeshOsd is OSDArray)
412 { 534 {
413// Console.WriteLine("decodedMeshOsd for {0} - {1}", primName, Util.GetFormattedXml(decodedMeshOsd)); 535 // Console.WriteLine("decodedMeshOsd for {0} - {1}", primName, Util.GetFormattedXml(decodedMeshOsd));
414 536
415 decodedMeshOsdArray = (OSDArray)decodedMeshOsd; 537 decodedMeshOsdArray = (OSDArray)decodedMeshOsd;
416 foreach (OSD subMeshOsd in decodedMeshOsdArray) 538 foreach (OSD subMeshOsd in decodedMeshOsdArray)
@@ -418,12 +540,50 @@ namespace OpenSim.Region.Physics.Meshing
418 if (subMeshOsd is OSDMap) 540 if (subMeshOsd is OSDMap)
419 AddSubMesh(subMeshOsd as OSDMap, size, coords, faces); 541 AddSubMesh(subMeshOsd as OSDMap, size, coords, faces);
420 } 542 }
543 if (debugDetail)
544 m_log.DebugFormat("{0} {1}: mesh decoded. offset={2}, size={3}, nCoords={4}, nFaces={5}",
545 LogHeader, primName, physOffset, physSize, coords.Count, faces.Count);
421 } 546 }
422 } 547 }
423 548
424 return true; 549 return true;
425 } 550 }
426 551
552
553 /// <summary>
554 /// decompresses a gzipped OSD object
555 /// </summary>
556 /// <param name="decodedOsd"></param> the OSD object
557 /// <param name="meshBytes"></param>
558 /// <returns></returns>
559 private static OSD DecompressOsd(byte[] meshBytes)
560 {
561 OSD decodedOsd = null;
562
563 using (MemoryStream inMs = new MemoryStream(meshBytes))
564 {
565 using (MemoryStream outMs = new MemoryStream())
566 {
567 using (ZOutputStream zOut = new ZOutputStream(outMs))
568 {
569 byte[] readBuffer = new byte[2048];
570 int readLen = 0;
571 while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0)
572 {
573 zOut.Write(readBuffer, 0, readLen);
574 }
575 zOut.Flush();
576 outMs.Seek(0, SeekOrigin.Begin);
577
578 byte[] decompressedBuf = outMs.GetBuffer();
579
580 decodedOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf);
581 }
582 }
583 }
584 return decodedOsd;
585 }
586
427 /// <summary> 587 /// <summary>
428 /// Generate the co-ords and faces necessary to construct a mesh from the sculpt data the accompanies a prim. 588 /// Generate the co-ords and faces necessary to construct a mesh from the sculpt data the accompanies a prim.
429 /// </summary> 589 /// </summary>
@@ -700,6 +860,45 @@ namespace OpenSim.Region.Physics.Meshing
700 return true; 860 return true;
701 } 861 }
702 862
863 /// <summary>
864 /// temporary prototype code - please do not use until the interface has been finalized!
865 /// </summary>
866 /// <param name="size">value to scale the hull points by</param>
867 /// <returns>a list of vertices in the bounding hull if it exists and has been successfully decoded, otherwise null</returns>
868 public List<Vector3> GetBoundingHull(Vector3 size)
869 {
870 if (mBoundingHull == null)
871 return null;
872
873 List<Vector3> verts = new List<Vector3>();
874 foreach (var vert in mBoundingHull)
875 verts.Add(vert * size);
876
877 return verts;
878 }
879
880 /// <summary>
881 /// temporary prototype code - please do not use until the interface has been finalized!
882 /// </summary>
883 /// <param name="size">value to scale the hull points by</param>
884 /// <returns>a list of hulls if they exist and have been successfully decoded, otherwise null</returns>
885 public List<List<Vector3>> GetConvexHulls(Vector3 size)
886 {
887 if (mConvexHulls == null)
888 return null;
889
890 List<List<Vector3>> hulls = new List<List<Vector3>>();
891 foreach (var hull in mConvexHulls)
892 {
893 List<Vector3> verts = new List<Vector3>();
894 foreach (var vert in hull)
895 verts.Add(vert * size);
896 hulls.Add(verts);
897 }
898
899 return hulls;
900 }
901
703 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) 902 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod)
704 { 903 {
705 return CreateMesh(primName, primShape, size, lod, false, true); 904 return CreateMesh(primName, primShape, size, lod, false, true);
diff --git a/OpenSim/Region/RegionCombinerModule/RegionCombinerLargeLandChannel.cs b/OpenSim/Region/RegionCombinerModule/RegionCombinerLargeLandChannel.cs
index b4abc1d..4bf2a82 100644
--- a/OpenSim/Region/RegionCombinerModule/RegionCombinerLargeLandChannel.cs
+++ b/OpenSim/Region/RegionCombinerModule/RegionCombinerLargeLandChannel.cs
@@ -27,6 +27,8 @@
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Reflection;
31using log4net;
30using OpenMetaverse; 32using OpenMetaverse;
31using OpenSim.Framework; 33using OpenSim.Framework;
32using OpenSim.Region.Framework.Interfaces; 34using OpenSim.Region.Framework.Interfaces;
@@ -34,10 +36,10 @@ using OpenSim.Region.CoreModules.World.Land;
34 36
35namespace OpenSim.Region.RegionCombinerModule 37namespace OpenSim.Region.RegionCombinerModule
36{ 38{
37public class RegionCombinerLargeLandChannel : ILandChannel 39 public class RegionCombinerLargeLandChannel : ILandChannel
38 { 40 {
39 // private static readonly ILog m_log = 41// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
40 // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 42
41 private RegionData RegData; 43 private RegionData RegData;
42 private ILandChannel RootRegionLandChannel; 44 private ILandChannel RootRegionLandChannel;
43 private readonly List<RegionData> RegionConnections; 45 private readonly List<RegionData> RegionConnections;
@@ -75,40 +77,51 @@ public class RegionCombinerLargeLandChannel : ILandChannel
75 77
76 public ILandObject GetLandObject(int x, int y) 78 public ILandObject GetLandObject(int x, int y)
77 { 79 {
78 //m_log.DebugFormat("[BIGLANDTESTINT]: <{0},{1}>", x, y); 80 return GetLandObject((float)x, (float)y);
79 81
80 if (x > 0 && x <= (int)Constants.RegionSize && y > 0 && y <= (int)Constants.RegionSize) 82// m_log.DebugFormat("[BIGLANDTESTINT]: <{0},{1}>", x, y);
81 { 83//
82 return RootRegionLandChannel.GetLandObject(x, y); 84// if (x > 0 && x <= (int)Constants.RegionSize && y > 0 && y <= (int)Constants.RegionSize)
83 } 85// {
84 else 86// return RootRegionLandChannel.GetLandObject(x, y);
85 { 87// }
86 int offsetX = (x / (int)Constants.RegionSize); 88// else
87 int offsetY = (y / (int)Constants.RegionSize); 89// {
88 offsetX *= (int)Constants.RegionSize; 90// int offsetX = (x / (int)Constants.RegionSize);
89 offsetY *= (int)Constants.RegionSize; 91// int offsetY = (y / (int)Constants.RegionSize);
90 92// offsetX *= (int)Constants.RegionSize;
91 foreach (RegionData regionData in RegionConnections) 93// offsetY *= (int)Constants.RegionSize;
92 { 94//
93 if (regionData.Offset.X == offsetX && regionData.Offset.Y == offsetY) 95// foreach (RegionData regionData in RegionConnections)
94 { 96// {
95 return regionData.RegionScene.LandChannel.GetLandObject(x - offsetX, y - offsetY); 97// if (regionData.Offset.X == offsetX && regionData.Offset.Y == offsetY)
96 } 98// {
97 } 99// m_log.DebugFormat(
98 ILandObject obj = new LandObject(UUID.Zero, false, RegData.RegionScene); 100// "[REGION COMBINER LARGE LAND CHANNEL]: Found region {0} at offset {1},{2}",
99 obj.LandData.Name = "NO LAND"; 101// regionData.RegionScene.Name, offsetX, offsetY);
100 return obj; 102//
101 } 103// return regionData.RegionScene.LandChannel.GetLandObject(x - offsetX, y - offsetY);
104// }
105// }
106// //ILandObject obj = new LandObject(UUID.Zero, false, RegData.RegionScene);
107// //obj.LandData.Name = "NO LAND";
108// //return obj;
109// }
110//
111// m_log.DebugFormat("[REGION COMBINER LARGE LAND CHANNEL]: No region found at {0},{1}, returning null", x, y);
112//
113// return null;
102 } 114 }
103 115
104 public ILandObject GetLandObject(int localID) 116 public ILandObject GetLandObject(int localID)
105 { 117 {
118 // XXX: Possibly should be looking in every land channel, not just the root.
106 return RootRegionLandChannel.GetLandObject(localID); 119 return RootRegionLandChannel.GetLandObject(localID);
107 } 120 }
108 121
109 public ILandObject GetLandObject(float x, float y) 122 public ILandObject GetLandObject(float x, float y)
110 { 123 {
111 //m_log.DebugFormat("[BIGLANDTESTFLOAT]: <{0},{1}>", x, y); 124// m_log.DebugFormat("[BIGLANDTESTFLOAT]: <{0},{1}>", x, y);
112 125
113 if (x > 0 && x <= (int)Constants.RegionSize && y > 0 && y <= (int)Constants.RegionSize) 126 if (x > 0 && x <= (int)Constants.RegionSize && y > 0 && y <= (int)Constants.RegionSize)
114 { 127 {
@@ -125,14 +138,22 @@ public class RegionCombinerLargeLandChannel : ILandChannel
125 { 138 {
126 if (regionData.Offset.X == offsetX && regionData.Offset.Y == offsetY) 139 if (regionData.Offset.X == offsetX && regionData.Offset.Y == offsetY)
127 { 140 {
141// m_log.DebugFormat(
142// "[REGION COMBINER LARGE LAND CHANNEL]: Found region {0} at offset {1},{2}",
143// regionData.RegionScene.Name, offsetX, offsetY);
144
128 return regionData.RegionScene.LandChannel.GetLandObject(x - offsetX, y - offsetY); 145 return regionData.RegionScene.LandChannel.GetLandObject(x - offsetX, y - offsetY);
129 } 146 }
130 } 147 }
131 148
132 ILandObject obj = new LandObject(UUID.Zero, false, RegData.RegionScene); 149// ILandObject obj = new LandObject(UUID.Zero, false, RegData.RegionScene);
133 obj.LandData.Name = "NO LAND"; 150// obj.LandData.Name = "NO LAND";
134 return obj; 151// return obj;
135 } 152 }
153
154// m_log.DebugFormat("[REGION COMBINER LARGE LAND CHANNEL]: No region found at {0},{1}, returning null", x, y);
155
156 return null;
136 } 157 }
137 158
138 public bool IsForcefulBansAllowed() 159 public bool IsForcefulBansAllowed()
diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
index 35ae44c..b9a217b 100644
--- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
+++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
@@ -51,7 +51,7 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
51 public interface IScriptWorkItem 51 public interface IScriptWorkItem
52 { 52 {
53 bool Cancel(); 53 bool Cancel();
54 void Abort(); 54 bool Abort();
55 55
56 /// <summary> 56 /// <summary>
57 /// Wait for the work item to complete. 57 /// Wait for the work item to complete.
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs
index 6879ebb..1e19032 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs
@@ -37,6 +37,8 @@ using OpenSim.Region.ScriptEngine.Interfaces;
37using OpenSim.Region.ScriptEngine.Shared; 37using OpenSim.Region.ScriptEngine.Shared;
38using OpenSim.Region.ScriptEngine.Shared.Api.Plugins; 38using OpenSim.Region.ScriptEngine.Shared.Api.Plugins;
39using Timer=OpenSim.Region.ScriptEngine.Shared.Api.Plugins.Timer; 39using Timer=OpenSim.Region.ScriptEngine.Shared.Api.Plugins.Timer;
40using System.Reflection;
41using log4net;
40 42
41namespace OpenSim.Region.ScriptEngine.Shared.Api 43namespace OpenSim.Region.ScriptEngine.Shared.Api
42{ 44{
@@ -45,15 +47,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
45 /// </summary> 47 /// </summary>
46 public class AsyncCommandManager 48 public class AsyncCommandManager
47 { 49 {
50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51
48 private static Thread cmdHandlerThread; 52 private static Thread cmdHandlerThread;
49 private static int cmdHandlerThreadCycleSleepms; 53 private static int cmdHandlerThreadCycleSleepms;
50 54
51 private static List<IScene> m_Scenes = new List<IScene>(); 55 /// <summary>
56 /// Lock for reading/writing static components of AsyncCommandManager.
57 /// </summary>
58 /// <remarks>
59 /// This lock exists so that multiple threads from different engines and/or different copies of the same engine
60 /// are prevented from running non-thread safe code (e.g. read/write of lists) concurrently.
61 /// </remarks>
62 private static object staticLock = new object();
63
52 private static List<IScriptEngine> m_ScriptEngines = 64 private static List<IScriptEngine> m_ScriptEngines =
53 new List<IScriptEngine>(); 65 new List<IScriptEngine>();
54 66
55 public IScriptEngine m_ScriptEngine; 67 public IScriptEngine m_ScriptEngine;
56 private IScene m_Scene;
57 68
58 private static Dictionary<IScriptEngine, Dataserver> m_Dataserver = 69 private static Dictionary<IScriptEngine, Dataserver> m_Dataserver =
59 new Dictionary<IScriptEngine, Dataserver>(); 70 new Dictionary<IScriptEngine, Dataserver>();
@@ -70,67 +81,99 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
70 81
71 public Dataserver DataserverPlugin 82 public Dataserver DataserverPlugin
72 { 83 {
73 get { return m_Dataserver[m_ScriptEngine]; } 84 get
85 {
86 lock (staticLock)
87 return m_Dataserver[m_ScriptEngine];
88 }
74 } 89 }
75 90
76 public Timer TimerPlugin 91 public Timer TimerPlugin
77 { 92 {
78 get { return m_Timer[m_ScriptEngine]; } 93 get
94 {
95 lock (staticLock)
96 return m_Timer[m_ScriptEngine];
97 }
79 } 98 }
80 99
81 public HttpRequest HttpRequestPlugin 100 public HttpRequest HttpRequestPlugin
82 { 101 {
83 get { return m_HttpRequest[m_ScriptEngine]; } 102 get
103 {
104 lock (staticLock)
105 return m_HttpRequest[m_ScriptEngine];
106 }
84 } 107 }
85 108
86 public Listener ListenerPlugin 109 public Listener ListenerPlugin
87 { 110 {
88 get { return m_Listener[m_ScriptEngine]; } 111 get
112 {
113 lock (staticLock)
114 return m_Listener[m_ScriptEngine];
115 }
89 } 116 }
90 117
91 public SensorRepeat SensorRepeatPlugin 118 public SensorRepeat SensorRepeatPlugin
92 { 119 {
93 get { return m_SensorRepeat[m_ScriptEngine]; } 120 get
121 {
122 lock (staticLock)
123 return m_SensorRepeat[m_ScriptEngine];
124 }
94 } 125 }
95 126
96 public XmlRequest XmlRequestPlugin 127 public XmlRequest XmlRequestPlugin
97 { 128 {
98 get { return m_XmlRequest[m_ScriptEngine]; } 129 get
130 {
131 lock (staticLock)
132 return m_XmlRequest[m_ScriptEngine];
133 }
99 } 134 }
100 135
101 public IScriptEngine[] ScriptEngines 136 public IScriptEngine[] ScriptEngines
102 { 137 {
103 get { return m_ScriptEngines.ToArray(); } 138 get
139 {
140 lock (staticLock)
141 return m_ScriptEngines.ToArray();
142 }
104 } 143 }
105 144
106 public AsyncCommandManager(IScriptEngine _ScriptEngine) 145 public AsyncCommandManager(IScriptEngine _ScriptEngine)
107 { 146 {
108 m_ScriptEngine = _ScriptEngine; 147 m_ScriptEngine = _ScriptEngine;
109 m_Scene = m_ScriptEngine.World; 148
110 149 // If there is more than one scene in the simulator or multiple script engines are used on the same region
111 if (m_Scenes.Count == 0) 150 // then more than one thread could arrive at this block of code simultaneously. However, it cannot be
112 ReadConfig(); 151 // executed concurrently both because concurrent list operations are not thread-safe and because of other
113 152 // race conditions such as the later check of cmdHandlerThread == null.
114 if (!m_Scenes.Contains(m_Scene)) 153 lock (staticLock)
115 m_Scenes.Add(m_Scene); 154 {
116 if (!m_ScriptEngines.Contains(m_ScriptEngine)) 155 if (m_ScriptEngines.Count == 0)
117 m_ScriptEngines.Add(m_ScriptEngine); 156 ReadConfig();
118 157
119 // Create instances of all plugins 158 if (!m_ScriptEngines.Contains(m_ScriptEngine))
120 if (!m_Dataserver.ContainsKey(m_ScriptEngine)) 159 m_ScriptEngines.Add(m_ScriptEngine);
121 m_Dataserver[m_ScriptEngine] = new Dataserver(this); 160
122 if (!m_Timer.ContainsKey(m_ScriptEngine)) 161 // Create instances of all plugins
123 m_Timer[m_ScriptEngine] = new Timer(this); 162 if (!m_Dataserver.ContainsKey(m_ScriptEngine))
124 if (!m_HttpRequest.ContainsKey(m_ScriptEngine)) 163 m_Dataserver[m_ScriptEngine] = new Dataserver(this);
125 m_HttpRequest[m_ScriptEngine] = new HttpRequest(this); 164 if (!m_Timer.ContainsKey(m_ScriptEngine))
126 if (!m_Listener.ContainsKey(m_ScriptEngine)) 165 m_Timer[m_ScriptEngine] = new Timer(this);
127 m_Listener[m_ScriptEngine] = new Listener(this); 166 if (!m_HttpRequest.ContainsKey(m_ScriptEngine))
128 if (!m_SensorRepeat.ContainsKey(m_ScriptEngine)) 167 m_HttpRequest[m_ScriptEngine] = new HttpRequest(this);
129 m_SensorRepeat[m_ScriptEngine] = new SensorRepeat(this); 168 if (!m_Listener.ContainsKey(m_ScriptEngine))
130 if (!m_XmlRequest.ContainsKey(m_ScriptEngine)) 169 m_Listener[m_ScriptEngine] = new Listener(this);
131 m_XmlRequest[m_ScriptEngine] = new XmlRequest(this); 170 if (!m_SensorRepeat.ContainsKey(m_ScriptEngine))
132 171 m_SensorRepeat[m_ScriptEngine] = new SensorRepeat(this);
133 StartThread(); 172 if (!m_XmlRequest.ContainsKey(m_ScriptEngine))
173 m_XmlRequest[m_ScriptEngine] = new XmlRequest(this);
174
175 StartThread();
176 }
134 } 177 }
135 178
136 private static void StartThread() 179 private static void StartThread()
@@ -179,42 +222,43 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
179 { 222 {
180 try 223 try
181 { 224 {
182 while (true) 225 Thread.Sleep(cmdHandlerThreadCycleSleepms);
183 {
184 Thread.Sleep(cmdHandlerThreadCycleSleepms);
185 226
186 DoOneCmdHandlerPass(); 227 DoOneCmdHandlerPass();
187 228
188 Watchdog.UpdateThread(); 229 Watchdog.UpdateThread();
189 }
190 } 230 }
191 catch 231 catch (Exception e)
192 { 232 {
233 m_log.Error("[ASYNC COMMAND MANAGER]: Exception in command handler pass: ", e);
193 } 234 }
194 } 235 }
195 } 236 }
196 237
197 private static void DoOneCmdHandlerPass() 238 private static void DoOneCmdHandlerPass()
198 { 239 {
199 // Check HttpRequests 240 lock (staticLock)
200 m_HttpRequest[m_ScriptEngines[0]].CheckHttpRequests(); 241 {
242 // Check HttpRequests
243 m_HttpRequest[m_ScriptEngines[0]].CheckHttpRequests();
201 244
202 // Check XMLRPCRequests 245 // Check XMLRPCRequests
203 m_XmlRequest[m_ScriptEngines[0]].CheckXMLRPCRequests(); 246 m_XmlRequest[m_ScriptEngines[0]].CheckXMLRPCRequests();
204 247
205 foreach (IScriptEngine s in m_ScriptEngines) 248 foreach (IScriptEngine s in m_ScriptEngines)
206 { 249 {
207 // Check Listeners 250 // Check Listeners
208 m_Listener[s].CheckListeners(); 251 m_Listener[s].CheckListeners();
209 252
210 // Check timers 253 // Check timers
211 m_Timer[s].CheckTimerEvents(); 254 m_Timer[s].CheckTimerEvents();
212 255
213 // Check Sensors 256 // Check Sensors
214 m_SensorRepeat[s].CheckSenseRepeaterEvents(); 257 m_SensorRepeat[s].CheckSenseRepeaterEvents();
215 258
216 // Check dataserver 259 // Check dataserver
217 m_Dataserver[s].ExpireRequests(); 260 m_Dataserver[s].ExpireRequests();
261 }
218 } 262 }
219 } 263 }
220 264
@@ -226,31 +270,35 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
226 public static void RemoveScript(IScriptEngine engine, uint localID, UUID itemID) 270 public static void RemoveScript(IScriptEngine engine, uint localID, UUID itemID)
227 { 271 {
228 // Remove a specific script 272 // Remove a specific script
273// m_log.DebugFormat("[ASYNC COMMAND MANAGER]: Removing facilities for script {0}", itemID);
229 274
230 // Remove dataserver events 275 lock (staticLock)
231 m_Dataserver[engine].RemoveEvents(localID, itemID); 276 {
277 // Remove dataserver events
278 m_Dataserver[engine].RemoveEvents(localID, itemID);
232 279
233 // Remove from: Timers 280 // Remove from: Timers
234 m_Timer[engine].UnSetTimerEvents(localID, itemID); 281 m_Timer[engine].UnSetTimerEvents(localID, itemID);
235 282
236 // Remove from: HttpRequest 283 // Remove from: HttpRequest
237 IHttpRequestModule iHttpReq = engine.World.RequestModuleInterface<IHttpRequestModule>(); 284 IHttpRequestModule iHttpReq = engine.World.RequestModuleInterface<IHttpRequestModule>();
238 if (iHttpReq != null) 285 if (iHttpReq != null)
239 iHttpReq.StopHttpRequest(localID, itemID); 286 iHttpReq.StopHttpRequest(localID, itemID);
240 287
241 IWorldComm comms = engine.World.RequestModuleInterface<IWorldComm>(); 288 IWorldComm comms = engine.World.RequestModuleInterface<IWorldComm>();
242 if (comms != null) 289 if (comms != null)
243 comms.DeleteListener(itemID); 290 comms.DeleteListener(itemID);
244 291
245 IXMLRPC xmlrpc = engine.World.RequestModuleInterface<IXMLRPC>(); 292 IXMLRPC xmlrpc = engine.World.RequestModuleInterface<IXMLRPC>();
246 if (xmlrpc != null) 293 if (xmlrpc != null)
247 { 294 {
248 xmlrpc.DeleteChannels(itemID); 295 xmlrpc.DeleteChannels(itemID);
249 xmlrpc.CancelSRDRequests(itemID); 296 xmlrpc.CancelSRDRequests(itemID);
250 } 297 }
251 298
252 // Remove Sensors 299 // Remove Sensors
253 m_SensorRepeat[engine].UnSetSenseRepeaterEvents(localID, itemID); 300 m_SensorRepeat[engine].UnSetSenseRepeaterEvents(localID, itemID);
301 }
254 } 302 }
255 303
256 /// <summary> 304 /// <summary>
@@ -260,10 +308,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
260 /// <returns></returns> 308 /// <returns></returns>
261 public static SensorRepeat GetSensorRepeatPlugin(IScriptEngine engine) 309 public static SensorRepeat GetSensorRepeatPlugin(IScriptEngine engine)
262 { 310 {
263 if (m_SensorRepeat.ContainsKey(engine)) 311 lock (staticLock)
264 return m_SensorRepeat[engine]; 312 {
265 else 313 if (m_SensorRepeat.ContainsKey(engine))
266 return null; 314 return m_SensorRepeat[engine];
315 else
316 return null;
317 }
267 } 318 }
268 319
269 /// <summary> 320 /// <summary>
@@ -273,10 +324,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
273 /// <returns></returns> 324 /// <returns></returns>
274 public static Dataserver GetDataserverPlugin(IScriptEngine engine) 325 public static Dataserver GetDataserverPlugin(IScriptEngine engine)
275 { 326 {
276 if (m_Dataserver.ContainsKey(engine)) 327 lock (staticLock)
277 return m_Dataserver[engine]; 328 {
278 else 329 if (m_Dataserver.ContainsKey(engine))
279 return null; 330 return m_Dataserver[engine];
331 else
332 return null;
333 }
280 } 334 }
281 335
282 /// <summary> 336 /// <summary>
@@ -286,10 +340,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
286 /// <returns></returns> 340 /// <returns></returns>
287 public static Timer GetTimerPlugin(IScriptEngine engine) 341 public static Timer GetTimerPlugin(IScriptEngine engine)
288 { 342 {
289 if (m_Timer.ContainsKey(engine)) 343 lock (staticLock)
290 return m_Timer[engine]; 344 {
291 else 345 if (m_Timer.ContainsKey(engine))
292 return null; 346 return m_Timer[engine];
347 else
348 return null;
349 }
293 } 350 }
294 351
295 /// <summary> 352 /// <summary>
@@ -299,10 +356,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
299 /// <returns></returns> 356 /// <returns></returns>
300 public static Listener GetListenerPlugin(IScriptEngine engine) 357 public static Listener GetListenerPlugin(IScriptEngine engine)
301 { 358 {
302 if (m_Listener.ContainsKey(engine)) 359 lock (staticLock)
303 return m_Listener[engine]; 360 {
304 else 361 if (m_Listener.ContainsKey(engine))
305 return null; 362 return m_Listener[engine];
363 else
364 return null;
365 }
306 } 366 }
307 367
308 public static void StateChange(IScriptEngine engine, uint localID, UUID itemID) 368 public static void StateChange(IScriptEngine engine, uint localID, UUID itemID)
@@ -332,28 +392,31 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
332 { 392 {
333 List<Object> data = new List<Object>(); 393 List<Object> data = new List<Object>();
334 394
335 Object[] listeners = m_Listener[engine].GetSerializationData(itemID); 395 lock (staticLock)
336 if (listeners.Length > 0)
337 { 396 {
338 data.Add("listener"); 397 Object[] listeners = m_Listener[engine].GetSerializationData(itemID);
339 data.Add(listeners.Length); 398 if (listeners.Length > 0)
340 data.AddRange(listeners); 399 {
341 } 400 data.Add("listener");
401 data.Add(listeners.Length);
402 data.AddRange(listeners);
403 }
342 404
343 Object[] timers=m_Timer[engine].GetSerializationData(itemID); 405 Object[] timers=m_Timer[engine].GetSerializationData(itemID);
344 if (timers.Length > 0) 406 if (timers.Length > 0)
345 { 407 {
346 data.Add("timer"); 408 data.Add("timer");
347 data.Add(timers.Length); 409 data.Add(timers.Length);
348 data.AddRange(timers); 410 data.AddRange(timers);
349 } 411 }
350 412
351 Object[] sensors = m_SensorRepeat[engine].GetSerializationData(itemID); 413 Object[] sensors = m_SensorRepeat[engine].GetSerializationData(itemID);
352 if (sensors.Length > 0) 414 if (sensors.Length > 0)
353 { 415 {
354 data.Add("sensor"); 416 data.Add("sensor");
355 data.Add(sensors.Length); 417 data.Add(sensors.Length);
356 data.AddRange(sensors); 418 data.AddRange(sensors);
419 }
357 } 420 }
358 421
359 return data.ToArray(); 422 return data.ToArray();
@@ -378,41 +441,26 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
378 441
379 idx+=len; 442 idx+=len;
380 443
444 lock (staticLock)
445 {
381 switch (type) 446 switch (type)
382 { 447 {
383 case "listener": 448 case "listener":
384 m_Listener[engine].CreateFromData(localID, itemID, 449 m_Listener[engine].CreateFromData(localID, itemID,
385 hostID, item); 450 hostID, item);
386 break; 451 break;
387 case "timer": 452 case "timer":
388 m_Timer[engine].CreateFromData(localID, itemID, 453 m_Timer[engine].CreateFromData(localID, itemID,
389 hostID, item); 454 hostID, item);
390 break; 455 break;
391 case "sensor": 456 case "sensor":
392 m_SensorRepeat[engine].CreateFromData(localID, 457 m_SensorRepeat[engine].CreateFromData(localID,
393 itemID, hostID, item); 458 itemID, hostID, item);
394 break; 459 break;
460 }
395 } 461 }
396 } 462 }
397 } 463 }
398 } 464 }
399
400 #region Check llRemoteData channels
401
402 #endregion
403
404 #region Check llListeners
405
406 #endregion
407
408 /// <summary>
409 /// If set to true then threads and stuff should try to make a graceful exit
410 /// </summary>
411 public bool PleaseShutdown
412 {
413 get { return _PleaseShutdown; }
414 set { _PleaseShutdown = value; }
415 }
416 private bool _PleaseShutdown = false;
417 } 465 }
418} 466}
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
index 5ea14c7..7c375e6 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
@@ -2772,9 +2772,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2772 // send the sound, once, to all clients in range 2772 // send the sound, once, to all clients in range
2773 if (m_SoundModule != null) 2773 if (m_SoundModule != null)
2774 { 2774 {
2775 m_SoundModule.SendSound(m_host.UUID, 2775 m_SoundModule.SendSound(
2776 ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound), volume, false, 0, 2776 m_host.UUID,
2777 0, false, false); 2777 ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound),
2778 volume, false, m_host.SoundQueueing ? (byte)SoundFlags.Queue : (byte)SoundFlags.None,
2779 0, false, false);
2778 } 2780 }
2779 } 2781 }
2780 2782
@@ -12672,6 +12674,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
12672 public void llSetSoundQueueing(int queue) 12674 public void llSetSoundQueueing(int queue)
12673 { 12675 {
12674 m_host.AddScriptLPS(1); 12676 m_host.AddScriptLPS(1);
12677
12678 if (m_SoundModule != null)
12679 m_SoundModule.SetSoundQueueing(m_host.UUID, queue == ScriptBaseClass.TRUE.value);
12675 } 12680 }
12676 12681
12677 public void llCollisionSprite(string impact_sprite) 12682 public void llCollisionSprite(string impact_sprite)
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
index 26850c4..8da06d1 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
@@ -528,8 +528,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
528 { 528 {
529 File.Delete(savedState); 529 File.Delete(savedState);
530 } 530 }
531 catch(Exception) 531 catch (Exception e)
532 { 532 {
533 m_log.Warn(
534 string.Format(
535 "[SCRIPT INSTANCE]: Could not delete script state {0} for script {1} (id {2}) in part {3} (id {4}) in object {5} in {6}. Exception ",
536 ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name),
537 e);
533 } 538 }
534 } 539 }
535 540
@@ -567,9 +572,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
567 572
568 public bool Stop(int timeout) 573 public bool Stop(int timeout)
569 { 574 {
570// m_log.DebugFormat( 575 if (DebugLevel >= 1)
571// "[SCRIPT INSTANCE]: Stopping script {0} {1} in {2} {3} with timeout {4} {5} {6}", 576 m_log.DebugFormat(
572// ScriptName, ItemID, PrimName, ObjectID, timeout, m_InSelfDelete, DateTime.Now.Ticks); 577 "[SCRIPT INSTANCE]: Stopping script {0} {1} in {2} {3} with timeout {4} {5} {6}",
578 ScriptName, ItemID, PrimName, ObjectID, timeout, m_InSelfDelete, DateTime.Now.Ticks);
573 579
574 IScriptWorkItem workItem; 580 IScriptWorkItem workItem;
575 581
diff --git a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs
index b524a18..3e69ab9 100644
--- a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs
@@ -546,21 +546,33 @@ namespace OpenSim.Region.ScriptEngine.Shared
546 546
547 set {m_data = value; } 547 set {m_data = value; }
548 } 548 }
549 // Function to obtain LSL type from an index. This is needed 549
550 // because LSL lists allow for multiple types, and safely 550 /// <summary>
551 // iterating in them requires a type check. 551 /// Obtain LSL type from an index.
552 /// </summary>
553 /// <remarks>
554 /// This is needed because LSL lists allow for multiple types, and safely
555 /// iterating in them requires a type check.
556 /// </remarks>
557 /// <returns></returns>
558 /// <param name='itemIndex'></param>
552 public Type GetLSLListItemType(int itemIndex) 559 public Type GetLSLListItemType(int itemIndex)
553 { 560 {
554 return m_data[itemIndex].GetType(); 561 return m_data[itemIndex].GetType();
555 } 562 }
556 563
557 // Member functions to obtain item as specific types. 564 /// <summary>
558 // For cases where implicit conversions would apply if items 565 /// Obtain float from an index.
559 // were not in a list (e.g. integer to float, but not float 566 /// </summary>
560 // to integer) functions check for alternate types so as to 567 /// <remarks>
561 // down-cast from Object to the correct type. 568 /// For cases where implicit conversions would apply if items
562 // Note: no checks for item index being valid are performed 569 /// were not in a list (e.g. integer to float, but not float
563 570 /// to integer) functions check for alternate types so as to
571 /// down-cast from Object to the correct type.
572 /// Note: no checks for item index being valid are performed
573 /// </remarks>
574 /// <returns></returns>
575 /// <param name='itemIndex'></param>
564 public LSL_Types.LSLFloat GetLSLFloatItem(int itemIndex) 576 public LSL_Types.LSLFloat GetLSLFloatItem(int itemIndex)
565 { 577 {
566 if (m_data[itemIndex] is LSL_Types.LSLInteger) 578 if (m_data[itemIndex] is LSL_Types.LSLInteger)
@@ -591,26 +603,14 @@ namespace OpenSim.Region.ScriptEngine.Shared
591 603
592 public LSL_Types.LSLString GetLSLStringItem(int itemIndex) 604 public LSL_Types.LSLString GetLSLStringItem(int itemIndex)
593 { 605 {
594 if (m_data[itemIndex] is LSL_Types.key) 606 if (m_data[itemIndex] is LSL_Types.key)
595 { 607 {
596 return (LSL_Types.key)m_data[itemIndex]; 608 return (LSL_Types.key)m_data[itemIndex];
597 } 609 }
598 else if (m_data[itemIndex] is String) 610 else
599 { 611 {
600 return new LSL_Types.LSLString((string)m_data[itemIndex]); 612 return new LSL_Types.LSLString(m_data[itemIndex].ToString());
601 } 613 }
602 else if (m_data[itemIndex] is LSL_Types.LSLFloat)
603 {
604 return new LSL_Types.LSLString((LSLFloat)m_data[itemIndex]);
605 }
606 else if (m_data[itemIndex] is LSL_Types.LSLInteger)
607 {
608 return new LSL_Types.LSLString((LSLInteger)m_data[itemIndex]);
609 }
610 else
611 {
612 return (LSL_Types.LSLString)m_data[itemIndex];
613 }
614 } 614 }
615 615
616 public LSL_Types.LSLInteger GetLSLIntegerItem(int itemIndex) 616 public LSL_Types.LSLInteger GetLSLIntegerItem(int itemIndex)
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
index 17243ab..9d1e143 100644
--- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
+++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
@@ -551,7 +551,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
551 /// <param name="instance"></param> 551 /// <param name="instance"></param>
552 /// <param name="keySelector">Basis on which to sort output. Can be null if no sort needs to take place</param> 552 /// <param name="keySelector">Basis on which to sort output. Can be null if no sort needs to take place</param>
553 private void HandleScriptsAction<TKey>( 553 private void HandleScriptsAction<TKey>(
554 string[] cmdparams, Action<IScriptInstance> action, Func<IScriptInstance, TKey> keySelector) 554 string[] cmdparams, Action<IScriptInstance> action, System.Func<IScriptInstance, TKey> keySelector)
555 { 555 {
556 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene)) 556 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene))
557 return; 557 return;
@@ -609,7 +609,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
609 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene)) 609 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene))
610 return; 610 return;
611 611
612 MainConsole.Instance.OutputFormat(GetStatusReport()); 612 MainConsole.Instance.Output(GetStatusReport());
613 } 613 }
614 614
615 public string GetStatusReport() 615 public string GetStatusReport()
@@ -708,7 +708,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
708 sb.AppendFormat("Containing part UUID: {0}\n", instance.ObjectID); 708 sb.AppendFormat("Containing part UUID: {0}\n", instance.ObjectID);
709 sb.AppendFormat("Position : {0}\n", sop.AbsolutePosition); 709 sb.AppendFormat("Position : {0}\n", sop.AbsolutePosition);
710 710
711 MainConsole.Instance.OutputFormat(sb.ToString()); 711 MainConsole.Instance.Output(sb.ToString());
712 } 712 }
713 713
714 private void HandleSuspendScript(IScriptInstance instance) 714 private void HandleSuspendScript(IScriptInstance instance)
@@ -1599,7 +1599,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1599 startInfo.MaxWorkerThreads = maxThreads; 1599 startInfo.MaxWorkerThreads = maxThreads;
1600 startInfo.MinWorkerThreads = minThreads; 1600 startInfo.MinWorkerThreads = minThreads;
1601 startInfo.ThreadPriority = threadPriority;; 1601 startInfo.ThreadPriority = threadPriority;;
1602 startInfo.StackSize = stackSize; 1602 startInfo.MaxStackSize = stackSize;
1603 startInfo.StartSuspended = true; 1603 startInfo.StartSuspended = true;
1604 1604
1605 m_ThreadPool = new SmartThreadPool(startInfo); 1605 m_ThreadPool = new SmartThreadPool(startInfo);
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs b/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs
index 8dd7677..9d9dee1 100644
--- a/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs
+++ b/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs
@@ -52,16 +52,16 @@ namespace OpenSim.Region.ScriptEngine.XEngine
52 return wr.Cancel(); 52 return wr.Cancel();
53 } 53 }
54 54
55 public void Abort() 55 public bool Abort()
56 { 56 {
57 wr.Abort(); 57 return wr.Cancel(true);
58 } 58 }
59 59
60 public bool Wait(int t) 60 public bool Wait(int t)
61 { 61 {
62 // We use the integer version of WaitAll because the current version of SmartThreadPool has a bug with the 62 // We use the integer version of WaitAll because the current version of SmartThreadPool has a bug with the
63 // TimeSpan version. The number of milliseconds in TimeSpan is an int64 so when STP casts it down to an 63 // TimeSpan version. The number of milliseconds in TimeSpan is an int64 so when STP casts it down to an
64 // int (32-bit) we can end up with bad values. This occurs on Windows though curious not on Mono 2.10.8 64 // int (32-bit) we can end up with bad values. This occurs on Windows though curiously not on Mono 2.10.8
65 // (or very likely other versions of Mono at least up until 3.0.3). 65 // (or very likely other versions of Mono at least up until 3.0.3).
66 return SmartThreadPool.WaitAll(new IWorkItemResult[] {wr}, t, false); 66 return SmartThreadPool.WaitAll(new IWorkItemResult[] {wr}, t, false);
67 } 67 }
diff --git a/OpenSim/Server/Base/ServerUtils.cs b/OpenSim/Server/Base/ServerUtils.cs
index 210a314..08ba50d 100644
--- a/OpenSim/Server/Base/ServerUtils.cs
+++ b/OpenSim/Server/Base/ServerUtils.cs
@@ -286,6 +286,7 @@ namespace OpenSim.Server.Base
286 e.InnerException == null ? e.Message : e.InnerException.Message, 286 e.InnerException == null ? e.Message : e.InnerException.Message,
287 e.StackTrace); 287 e.StackTrace);
288 } 288 }
289 m_log.ErrorFormat("[SERVER UTILS]: Error loading plugin {0}: {1} args.Length {2}", dllName, e.Message, args.Length);
289 return null; 290 return null;
290 } 291 }
291 292
diff --git a/OpenSim/Server/Base/ServicesServerBase.cs b/OpenSim/Server/Base/ServicesServerBase.cs
index 7c8e6b7..b13c87d 100644
--- a/OpenSim/Server/Base/ServicesServerBase.cs
+++ b/OpenSim/Server/Base/ServicesServerBase.cs
@@ -171,11 +171,6 @@ namespace OpenSim.Server.Base
171 171
172 m_console = MainConsole.Instance; 172 m_console = MainConsole.Instance;
173 173
174 // Configure the appenders for log4net
175 //
176 OpenSimAppender consoleAppender = null;
177 FileAppender fileAppender = null;
178
179 if (logConfig != null) 174 if (logConfig != null)
180 { 175 {
181 FileInfo cfg = new FileInfo(logConfig); 176 FileInfo cfg = new FileInfo(logConfig);
diff --git a/OpenSim/Server/Handlers/Hypergrid/GatekeeperServerConnector.cs b/OpenSim/Server/Handlers/Hypergrid/GatekeeperServerConnector.cs
index 0d4990a..ffe2f36 100644
--- a/OpenSim/Server/Handlers/Hypergrid/GatekeeperServerConnector.cs
+++ b/OpenSim/Server/Handlers/Hypergrid/GatekeeperServerConnector.cs
@@ -76,10 +76,14 @@ namespace OpenSim.Server.Handlers.Hypergrid
76 server.AddStreamHandler(new GatekeeperAgentHandler(m_GatekeeperService, m_Proxy)); 76 server.AddStreamHandler(new GatekeeperAgentHandler(m_GatekeeperService, m_Proxy));
77 } 77 }
78 78
79 public GatekeeperServiceInConnector(IConfigSource config, IHttpServer server) 79 public GatekeeperServiceInConnector(IConfigSource config, IHttpServer server, string configName)
80 : this(config, server, null) 80 : this(config, server, (ISimulationService)null)
81 { 81 {
82 } 82 }
83 83
84 public GatekeeperServiceInConnector(IConfigSource config, IHttpServer server)
85 : this(config, server, String.Empty)
86 {
87 }
84 } 88 }
85} 89}
diff --git a/OpenSim/Server/Handlers/Hypergrid/InstantMessageServerConnector.cs b/OpenSim/Server/Handlers/Hypergrid/InstantMessageServerConnector.cs
index 80eb5d2..8145a21 100644
--- a/OpenSim/Server/Handlers/Hypergrid/InstantMessageServerConnector.cs
+++ b/OpenSim/Server/Handlers/Hypergrid/InstantMessageServerConnector.cs
@@ -54,10 +54,15 @@ namespace OpenSim.Server.Handlers.Hypergrid
54 private IInstantMessage m_IMService; 54 private IInstantMessage m_IMService;
55 55
56 public InstantMessageServerConnector(IConfigSource config, IHttpServer server) : 56 public InstantMessageServerConnector(IConfigSource config, IHttpServer server) :
57 this(config, server, null) 57 this(config, server, (IInstantMessageSimConnector)null)
58 { 58 {
59 } 59 }
60 60
61 public InstantMessageServerConnector(IConfigSource config, IHttpServer server, string configName) :
62 this(config, server)
63 {
64 }
65
61 public InstantMessageServerConnector(IConfigSource config, IHttpServer server, IInstantMessageSimConnector simConnector) : 66 public InstantMessageServerConnector(IConfigSource config, IHttpServer server, IInstantMessageSimConnector simConnector) :
62 base(config, server, String.Empty) 67 base(config, server, String.Empty)
63 { 68 {
diff --git a/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs b/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs
index db62aaa..b20f467 100644
--- a/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs
+++ b/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs
@@ -62,10 +62,15 @@ namespace OpenSim.Server.Handlers.Hypergrid
62 private bool m_VerifyCallers = false; 62 private bool m_VerifyCallers = false;
63 63
64 public UserAgentServerConnector(IConfigSource config, IHttpServer server) : 64 public UserAgentServerConnector(IConfigSource config, IHttpServer server) :
65 this(config, server, null) 65 this(config, server, (IFriendsSimConnector)null)
66 { 66 {
67 } 67 }
68 68
69 public UserAgentServerConnector(IConfigSource config, IHttpServer server, string configName) :
70 this(config, server)
71 {
72 }
73
69 public UserAgentServerConnector(IConfigSource config, IHttpServer server, IFriendsSimConnector friendsConnector) : 74 public UserAgentServerConnector(IConfigSource config, IHttpServer server, IFriendsSimConnector friendsConnector) :
70 base(config, server, String.Empty) 75 base(config, server, String.Empty)
71 { 76 {
diff --git a/OpenSim/Server/Handlers/Login/LLLoginServiceInConnector.cs b/OpenSim/Server/Handlers/Login/LLLoginServiceInConnector.cs
index 9a7ad34..1fb0dbc 100644
--- a/OpenSim/Server/Handlers/Login/LLLoginServiceInConnector.cs
+++ b/OpenSim/Server/Handlers/Login/LLLoginServiceInConnector.cs
@@ -60,8 +60,8 @@ namespace OpenSim.Server.Handlers.Login
60 InitializeHandlers(server); 60 InitializeHandlers(server);
61 } 61 }
62 62
63 public LLLoginServiceInConnector(IConfigSource config, IHttpServer server) : 63 public LLLoginServiceInConnector(IConfigSource config, IHttpServer server, string configName) :
64 base(config, server, String.Empty) 64 base(config, server, configName)
65 { 65 {
66 string loginService = ReadLocalServiceFromConfig(config); 66 string loginService = ReadLocalServiceFromConfig(config);
67 67
@@ -72,6 +72,11 @@ namespace OpenSim.Server.Handlers.Login
72 InitializeHandlers(server); 72 InitializeHandlers(server);
73 } 73 }
74 74
75 public LLLoginServiceInConnector(IConfigSource config, IHttpServer server) :
76 this(config, server, String.Empty)
77 {
78 }
79
75 private string ReadLocalServiceFromConfig(IConfigSource config) 80 private string ReadLocalServiceFromConfig(IConfigSource config)
76 { 81 {
77 IConfig serverConfig = config.Configs["LoginService"]; 82 IConfig serverConfig = config.Configs["LoginService"];
diff --git a/OpenSim/Server/Handlers/Profiles/UserProfilesConnector.cs b/OpenSim/Server/Handlers/Profiles/UserProfilesConnector.cs
new file mode 100644
index 0000000..f9a520a
--- /dev/null
+++ b/OpenSim/Server/Handlers/Profiles/UserProfilesConnector.cs
@@ -0,0 +1,114 @@
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 OpenSim.Server.Base;
32using OpenSim.Services.Interfaces;
33using OpenSim.Framework.Servers.HttpServer;
34using OpenSim.Framework;
35using OpenSim.Server.Handlers.Base;
36using log4net;
37
38namespace OpenSim.Server.Handlers.Profiles
39{
40 public class UserProfilesConnector: ServiceConnector
41 {
42 static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
43
44
45 // Our Local Module
46 public IUserProfilesService ServiceModule
47 {
48 get; private set;
49 }
50
51 // The HTTP server.
52 public IHttpServer Server
53 {
54 get; private set;
55 }
56
57 public string ConfigName
58 {
59 get; private set;
60 }
61
62 public bool Enabled
63 {
64 get; private set;
65 }
66
67 public UserProfilesConnector(IConfigSource config, IHttpServer server, string configName) :
68 base(config, server, configName)
69 {
70 ConfigName = "UserProfilesService";
71 if(!string.IsNullOrEmpty(configName))
72 ConfigName = configName;
73
74 IConfig serverConfig = config.Configs[ConfigName];
75 if (serverConfig == null)
76 throw new Exception(String.Format("No section {0} in config file", ConfigName));
77
78 if(!serverConfig.GetBoolean("Enabled",false))
79 {
80 Enabled = false;
81 return;
82 }
83
84 Enabled = true;
85
86 Server = server;
87
88 string service = serverConfig.GetString("LocalServiceModule", String.Empty);
89
90 Object[] args = new Object[] { config, ConfigName };
91 ServiceModule = ServerUtils.LoadPlugin<IUserProfilesService>(service, args);
92
93 JsonRpcProfileHandlers handler = new JsonRpcProfileHandlers(ServiceModule);
94
95 Server.AddJsonRPCHandler("avatarclassifiedsrequest", handler.AvatarClassifiedsRequest);
96 Server.AddJsonRPCHandler("classified_update", handler.ClassifiedUpdate);
97 Server.AddJsonRPCHandler("classifieds_info_query", handler.ClassifiedInfoRequest);
98 Server.AddJsonRPCHandler("classified_delete", handler.ClassifiedDelete);
99 Server.AddJsonRPCHandler("avatarpicksrequest", handler.AvatarPicksRequest);
100 Server.AddJsonRPCHandler("pickinforequest", handler.PickInfoRequest);
101 Server.AddJsonRPCHandler("picks_update", handler.PicksUpdate);
102 Server.AddJsonRPCHandler("picks_delete", handler.PicksDelete);
103 Server.AddJsonRPCHandler("avatarnotesrequest", handler.AvatarNotesRequest);
104 Server.AddJsonRPCHandler("avatar_notes_update", handler.NotesUpdate);
105 Server.AddJsonRPCHandler("avatar_properties_request", handler.AvatarPropertiesRequest);
106 Server.AddJsonRPCHandler("avatar_properties_update", handler.AvatarPropertiesUpdate);
107 Server.AddJsonRPCHandler("avatar_interests_update", handler.AvatarInterestsUpdate);
108 Server.AddJsonRPCHandler("image_assets_request", handler.AvatarImageAssetsRequest);
109 Server.AddJsonRPCHandler("user_data_request", handler.RequestUserAppData);
110 Server.AddJsonRPCHandler("user_data_update", handler.UpdateUserAppData);
111 }
112 }
113}
114
diff --git a/OpenSim/Server/Handlers/Profiles/UserProfilesHandlers.cs b/OpenSim/Server/Handlers/Profiles/UserProfilesHandlers.cs
new file mode 100644
index 0000000..f5f0794
--- /dev/null
+++ b/OpenSim/Server/Handlers/Profiles/UserProfilesHandlers.cs
@@ -0,0 +1,461 @@
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 OpenMetaverse;
31using OpenMetaverse.StructuredData;
32using log4net;
33using OpenSim.Services.Interfaces;
34using OpenSim.Framework.Servers.HttpServer;
35using OpenSim.Framework;
36
37namespace OpenSim.Server.Handlers
38{
39 public class UserProfilesHandlers
40 {
41 public UserProfilesHandlers ()
42 {
43 }
44 }
45
46 public class JsonRpcProfileHandlers
47 {
48 static readonly ILog m_log =
49 LogManager.GetLogger(
50 MethodBase.GetCurrentMethod().DeclaringType);
51
52 public IUserProfilesService Service
53 {
54 get; private set;
55 }
56
57 public JsonRpcProfileHandlers(IUserProfilesService service)
58 {
59 Service = service;
60 }
61
62 #region Classifieds
63 /// <summary>
64 /// Request avatar's classified ads.
65 /// </summary>
66 /// <returns>
67 /// An array containing all the calassified uuid and it's name created by the creator id
68 /// </returns>
69 /// <param name='json'>
70 /// Our parameters are in the OSDMap json["params"]
71 /// </param>
72 /// <param name='response'>
73 /// If set to <c>true</c> response.
74 /// </param>
75 public bool AvatarClassifiedsRequest(OSDMap json, ref JsonRpcResponse response)
76 {
77 if(!json.ContainsKey("params"))
78 {
79 response.Error.Code = ErrorCode.ParseError;
80 m_log.DebugFormat ("Classified Request");
81 return false;
82 }
83
84 OSDMap request = (OSDMap)json["params"];
85 UUID creatorId = new UUID(request["creatorId"].AsString());
86
87
88 OSDArray data = (OSDArray) Service.AvatarClassifiedsRequest(creatorId);
89 response.Result = data;
90
91 return true;
92 }
93
94 public bool ClassifiedUpdate(OSDMap json, ref JsonRpcResponse response)
95 {
96 if(!json.ContainsKey("params"))
97 {
98 response.Error.Code = ErrorCode.ParseError;
99 response.Error.Message = "Error parsing classified update request";
100 m_log.DebugFormat ("Classified Update Request");
101 return false;
102 }
103
104 string result = string.Empty;
105 UserClassifiedAdd ad = new UserClassifiedAdd();
106 object Ad = (object)ad;
107 OSD.DeserializeMembers(ref Ad, (OSDMap)json["params"]);
108 if(Service.ClassifiedUpdate(ad, ref result))
109 {
110 response.Result = OSD.SerializeMembers(ad);
111 return true;
112 }
113
114 response.Error.Code = ErrorCode.InternalError;
115 response.Error.Message = string.Format("{0}", result);
116 return false;
117 }
118
119 public bool ClassifiedDelete(OSDMap json, ref JsonRpcResponse response)
120 {
121 if(!json.ContainsKey("params"))
122 {
123 response.Error.Code = ErrorCode.ParseError;
124 m_log.DebugFormat ("Classified Delete Request");
125 return false;
126 }
127
128 OSDMap request = (OSDMap)json["params"];
129 UUID classifiedId = new UUID(request["classifiedID"].AsString());
130
131 OSDMap res = new OSDMap();
132 res["result"] = OSD.FromString("success");
133 response.Result = res;
134
135 return true;
136
137 }
138
139 public bool ClassifiedInfoRequest(OSDMap json, ref JsonRpcResponse response)
140 {
141 if(!json.ContainsKey("params"))
142 {
143 response.Error.Code = ErrorCode.ParseError;
144 response.Error.Message = "no parameters supplied";
145 m_log.DebugFormat ("Classified Info Request");
146 return false;
147 }
148
149 string result = string.Empty;
150 UserClassifiedAdd ad = new UserClassifiedAdd();
151 object Ad = (object)ad;
152 OSD.DeserializeMembers(ref Ad, (OSDMap)json["params"]);
153 if(Service.ClassifiedInfoRequest(ref ad, ref result))
154 {
155 response.Result = OSD.SerializeMembers(ad);
156 return true;
157 }
158
159 response.Error.Code = ErrorCode.InternalError;
160 response.Error.Message = string.Format("{0}", result);
161 return false;
162 }
163 #endregion Classifieds
164
165 #region Picks
166 public bool AvatarPicksRequest(OSDMap json, ref JsonRpcResponse response)
167 {
168 if(!json.ContainsKey("params"))
169 {
170 response.Error.Code = ErrorCode.ParseError;
171 m_log.DebugFormat ("Avatar Picks Request");
172 return false;
173 }
174
175 OSDMap request = (OSDMap)json["params"];
176 UUID creatorId = new UUID(request["creatorId"].AsString());
177
178
179 OSDArray data = (OSDArray) Service.AvatarPicksRequest(creatorId);
180 response.Result = data;
181
182 return true;
183 }
184
185 public bool PickInfoRequest(OSDMap json, ref JsonRpcResponse response)
186 {
187 if(!json.ContainsKey("params"))
188 {
189 response.Error.Code = ErrorCode.ParseError;
190 response.Error.Message = "no parameters supplied";
191 m_log.DebugFormat ("Avatar Picks Info Request");
192 return false;
193 }
194
195 string result = string.Empty;
196 UserProfilePick pick = new UserProfilePick();
197 object Pick = (object)pick;
198 OSD.DeserializeMembers(ref Pick, (OSDMap)json["params"]);
199 if(Service.PickInfoRequest(ref pick, ref result))
200 {
201 response.Result = OSD.SerializeMembers(pick);
202 return true;
203 }
204
205 response.Error.Code = ErrorCode.InternalError;
206 response.Error.Message = string.Format("{0}", result);
207 return false;
208 }
209
210 public bool PicksUpdate(OSDMap json, ref JsonRpcResponse response)
211 {
212 if(!json.ContainsKey("params"))
213 {
214 response.Error.Code = ErrorCode.ParseError;
215 response.Error.Message = "no parameters supplied";
216 m_log.DebugFormat ("Avatar Picks Update Request");
217 return false;
218 }
219
220 string result = string.Empty;
221 UserProfilePick pick = new UserProfilePick();
222 object Pick = (object)pick;
223 OSD.DeserializeMembers(ref Pick, (OSDMap)json["params"]);
224 if(Service.PicksUpdate(ref pick, ref result))
225 {
226 response.Result = OSD.SerializeMembers(pick);
227 return true;
228 }
229
230 response.Error.Code = ErrorCode.InternalError;
231 response.Error.Message = "unable to update pick";
232
233 return false;
234 }
235
236 public bool PicksDelete(OSDMap json, ref JsonRpcResponse response)
237 {
238 if(!json.ContainsKey("params"))
239 {
240 response.Error.Code = ErrorCode.ParseError;
241 m_log.DebugFormat ("Avatar Picks Delete Request");
242 return false;
243 }
244
245 OSDMap request = (OSDMap)json["params"];
246 UUID pickId = new UUID(request["pickId"].AsString());
247 if(Service.PicksDelete(pickId))
248 return true;
249
250 response.Error.Code = ErrorCode.InternalError;
251 response.Error.Message = "data error removing record";
252 return false;
253 }
254 #endregion Picks
255
256 #region Notes
257 public bool AvatarNotesRequest(OSDMap json, ref JsonRpcResponse response)
258 {
259 if(!json.ContainsKey("params"))
260 {
261 response.Error.Code = ErrorCode.ParseError;
262 response.Error.Message = "Params missing";
263 m_log.DebugFormat ("Avatar Notes Request");
264 return false;
265 }
266
267 string result = string.Empty;
268 UserProfileNotes note = new UserProfileNotes();
269 object Note = (object)note;
270 OSD.DeserializeMembers(ref Note, (OSDMap)json["params"]);
271 if(Service.AvatarNotesRequest(ref note))
272 {
273 response.Result = OSD.SerializeMembers(note);
274 return true;
275 }
276
277 object Notes = (object) note;
278 OSD.DeserializeMembers(ref Notes, (OSDMap)json["params"]);
279 return true;
280 }
281
282 public bool NotesUpdate(OSDMap json, ref JsonRpcResponse response)
283 {
284 if(!json.ContainsKey("params"))
285 {
286 response.Error.Code = ErrorCode.ParseError;
287 response.Error.Message = "No parameters";
288 m_log.DebugFormat ("Avatar Notes Update Request");
289 return false;
290 }
291
292 string result = string.Empty;
293 UserProfileNotes note = new UserProfileNotes();
294 object Notes = (object) note;
295 OSD.DeserializeMembers(ref Notes, (OSDMap)json["params"]);
296 if(Service.NotesUpdate(ref note, ref result))
297 {
298 response.Result = OSD.SerializeMembers(note);
299 return true;
300 }
301 return true;
302 }
303 #endregion Notes
304
305 #region Profile Properties
306 public bool AvatarPropertiesRequest(OSDMap json, ref JsonRpcResponse response)
307 {
308 if(!json.ContainsKey("params"))
309 {
310 response.Error.Code = ErrorCode.ParseError;
311 response.Error.Message = "no parameters supplied";
312 m_log.DebugFormat ("Avatar Properties Request");
313 return false;
314 }
315
316 string result = string.Empty;
317 UserProfileProperties props = new UserProfileProperties();
318 object Props = (object)props;
319 OSD.DeserializeMembers(ref Props, (OSDMap)json["params"]);
320 if(Service.AvatarPropertiesRequest(ref props, ref result))
321 {
322 response.Result = OSD.SerializeMembers(props);
323 return true;
324 }
325
326 response.Error.Code = ErrorCode.InternalError;
327 response.Error.Message = string.Format("{0}", result);
328 return false;
329 }
330
331 public bool AvatarPropertiesUpdate(OSDMap json, ref JsonRpcResponse response)
332 {
333 if(!json.ContainsKey("params"))
334 {
335 response.Error.Code = ErrorCode.ParseError;
336 response.Error.Message = "no parameters supplied";
337 m_log.DebugFormat ("Avatar Properties Update Request");
338 return false;
339 }
340
341 string result = string.Empty;
342 UserProfileProperties props = new UserProfileProperties();
343 object Props = (object)props;
344 OSD.DeserializeMembers(ref Props, (OSDMap)json["params"]);
345 if(Service.AvatarPropertiesUpdate(ref props, ref result))
346 {
347 response.Result = OSD.SerializeMembers(props);
348 return true;
349 }
350
351 response.Error.Code = ErrorCode.InternalError;
352 response.Error.Message = string.Format("{0}", result);
353 return false;
354 }
355 #endregion Profile Properties
356
357 #region Interests
358 public bool AvatarInterestsUpdate(OSDMap json, ref JsonRpcResponse response)
359 {
360 if(!json.ContainsKey("params"))
361 {
362 response.Error.Code = ErrorCode.ParseError;
363 response.Error.Message = "no parameters supplied";
364 m_log.DebugFormat ("Avatar Interests Update Request");
365 return false;
366 }
367
368 string result = string.Empty;
369 UserProfileProperties props = new UserProfileProperties();
370 object Props = (object)props;
371 OSD.DeserializeMembers(ref Props, (OSDMap)json["params"]);
372 if(Service.AvatarInterestsUpdate(props, ref result))
373 {
374 response.Result = OSD.SerializeMembers(props);
375 return true;
376 }
377
378 response.Error.Code = ErrorCode.InternalError;
379 response.Error.Message = string.Format("{0}", result);
380 return false;
381 }
382 #endregion Interests
383
384 #region Utility
385 public bool AvatarImageAssetsRequest(OSDMap json, ref JsonRpcResponse response)
386 {
387 if(!json.ContainsKey("params"))
388 {
389 response.Error.Code = ErrorCode.ParseError;
390 m_log.DebugFormat ("Avatar Image Assets Request");
391 return false;
392 }
393
394 OSDMap request = (OSDMap)json["params"];
395 UUID avatarId = new UUID(request["avatarId"].AsString());
396
397 OSDArray data = (OSDArray) Service.AvatarImageAssetsRequest(avatarId);
398 response.Result = data;
399
400 return true;
401 }
402 #endregion Utiltiy
403
404 #region UserData
405 public bool RequestUserAppData(OSDMap json, ref JsonRpcResponse response)
406 {
407 if(!json.ContainsKey("params"))
408 {
409 response.Error.Code = ErrorCode.ParseError;
410 response.Error.Message = "no parameters supplied";
411 m_log.DebugFormat ("User Application Service URL Request: No Parameters!");
412 return false;
413 }
414
415 string result = string.Empty;
416 UserAppData props = new UserAppData();
417 object Props = (object)props;
418 OSD.DeserializeMembers(ref Props, (OSDMap)json["params"]);
419 if(Service.RequestUserAppData(ref props, ref result))
420 {
421 OSDMap res = new OSDMap();
422 res["result"] = OSD.FromString("success");
423 res["token"] = OSD.FromString (result);
424 response.Result = res;
425
426 return true;
427 }
428
429 response.Error.Code = ErrorCode.InternalError;
430 response.Error.Message = string.Format("{0}", result);
431 return false;
432 }
433
434 public bool UpdateUserAppData(OSDMap json, ref JsonRpcResponse response)
435 {
436 if(!json.ContainsKey("params"))
437 {
438 response.Error.Code = ErrorCode.ParseError;
439 response.Error.Message = "no parameters supplied";
440 m_log.DebugFormat ("User App Data Update Request");
441 return false;
442 }
443
444 string result = string.Empty;
445 UserAppData props = new UserAppData();
446 object Props = (object)props;
447 OSD.DeserializeMembers(ref Props, (OSDMap)json["params"]);
448 if(Service.SetUserAppData(props, ref result))
449 {
450 response.Result = OSD.SerializeMembers(props);
451 return true;
452 }
453
454 response.Error.Code = ErrorCode.InternalError;
455 response.Error.Message = string.Format("{0}", result);
456 return false;
457 }
458 #endregion UserData
459 }
460}
461
diff --git a/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs b/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs
index 0bd8269..9b34298 100644
--- a/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs
+++ b/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs
@@ -241,7 +241,7 @@ namespace OpenSim.Server.Handlers.Simulation
241 if (action.Equals("release")) 241 if (action.Equals("release"))
242 ReleaseAgent(regionID, id); 242 ReleaseAgent(regionID, id);
243 else 243 else
244 m_SimulationService.CloseAgent(destination, id); 244 Util.FireAndForget(delegate { m_SimulationService.CloseAgent(destination, id); });
245 245
246 responsedata["int_response_code"] = HttpStatusCode.OK; 246 responsedata["int_response_code"] = HttpStatusCode.OK;
247 responsedata["str_response_string"] = "OpenSim agent " + id.ToString(); 247 responsedata["str_response_string"] = "OpenSim agent " + id.ToString();
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs
index 854bea4..7bb06fb 100644
--- a/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs
+++ b/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs
@@ -137,10 +137,11 @@ namespace OpenSim.Services.Connectors.SimianGrid
137 userID, sessionID, secureSessionID); 137 userID, sessionID, secureSessionID);
138 138
139 NameValueCollection requestArgs = new NameValueCollection 139 NameValueCollection requestArgs = new NameValueCollection
140 { 140 {
141 { "RequestMethod", "AddSession" }, 141 { "RequestMethod", "AddSession" },
142 { "UserID", userID.ToString() } 142 { "UserID", userID.ToString() }
143 }; 143 };
144
144 if (sessionID != UUID.Zero) 145 if (sessionID != UUID.Zero)
145 { 146 {
146 requestArgs["SessionID"] = sessionID.ToString(); 147 requestArgs["SessionID"] = sessionID.ToString();
@@ -158,13 +159,13 @@ namespace OpenSim.Services.Connectors.SimianGrid
158 159
159 public bool LogoutAgent(UUID sessionID) 160 public bool LogoutAgent(UUID sessionID)
160 { 161 {
161// m_log.InfoFormat("[SIMIAN PRESENCE CONNECTOR]: Logout requested for agent with sessionID " + sessionID); 162 // m_log.InfoFormat("[SIMIAN PRESENCE CONNECTOR]: Logout requested for agent with sessionID " + sessionID);
162 163
163 NameValueCollection requestArgs = new NameValueCollection 164 NameValueCollection requestArgs = new NameValueCollection
164 { 165 {
165 { "RequestMethod", "RemoveSession" }, 166 { "RequestMethod", "RemoveSession" },
166 { "SessionID", sessionID.ToString() } 167 { "SessionID", sessionID.ToString() }
167 }; 168 };
168 169
169 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); 170 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
170 bool success = response["Success"].AsBoolean(); 171 bool success = response["Success"].AsBoolean();
@@ -177,13 +178,13 @@ namespace OpenSim.Services.Connectors.SimianGrid
177 178
178 public bool LogoutRegionAgents(UUID regionID) 179 public bool LogoutRegionAgents(UUID regionID)
179 { 180 {
180// m_log.InfoFormat("[SIMIAN PRESENCE CONNECTOR]: Logout requested for all agents in region " + regionID); 181 // m_log.InfoFormat("[SIMIAN PRESENCE CONNECTOR]: Logout requested for all agents in region " + regionID);
181 182
182 NameValueCollection requestArgs = new NameValueCollection 183 NameValueCollection requestArgs = new NameValueCollection
183 { 184 {
184 { "RequestMethod", "RemoveSessions" }, 185 { "RequestMethod", "RemoveSessions" },
185 { "SceneID", regionID.ToString() } 186 { "SceneID", regionID.ToString() }
186 }; 187 };
187 188
188 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); 189 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
189 bool success = response["Success"].AsBoolean(); 190 bool success = response["Success"].AsBoolean();
@@ -202,49 +203,46 @@ namespace OpenSim.Services.Connectors.SimianGrid
202 203
203 public PresenceInfo GetAgent(UUID sessionID) 204 public PresenceInfo GetAgent(UUID sessionID)
204 { 205 {
205// m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting session data for agent with sessionID " + sessionID); 206 OSDMap sessionResponse = GetSessionDataFromSessionID(sessionID);
206 207 if (sessionResponse == null)
207 NameValueCollection requestArgs = new NameValueCollection
208 {
209 { "RequestMethod", "GetSession" },
210 { "SessionID", sessionID.ToString() }
211 };
212
213 OSDMap sessionResponse = WebUtil.PostToService(m_serverUrl, requestArgs);
214 if (sessionResponse["Success"].AsBoolean())
215 { 208 {
216 UUID userID = sessionResponse["UserID"].AsUUID(); 209 m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve session {0}: {1}",sessionID.ToString(),sessionResponse["Message"].AsString());
217 m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting user data for " + userID); 210 return null;
218
219 requestArgs = new NameValueCollection
220 {
221 { "RequestMethod", "GetUser" },
222 { "UserID", userID.ToString() }
223 };
224
225 OSDMap userResponse = WebUtil.PostToService(m_serverUrl, requestArgs);
226 if (userResponse["Success"].AsBoolean())
227 return ResponseToPresenceInfo(sessionResponse, userResponse);
228 else
229 m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for " + userID + ": " + userResponse["Message"].AsString());
230 } 211 }
231 else 212
213 UUID userID = sessionResponse["UserID"].AsUUID();
214 OSDMap userResponse = GetUserData(userID);
215 if (userResponse == null)
232 { 216 {
233 m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve session " + sessionID + ": " + sessionResponse["Message"].AsString()); 217 m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for {0}: {1}",userID.ToString(),userResponse["Message"].AsString());
218 return null;
234 } 219 }
235 220
236 return null; 221 return ResponseToPresenceInfo(sessionResponse);
237 } 222 }
238 223
239 public PresenceInfo[] GetAgents(string[] userIDs) 224 public PresenceInfo[] GetAgents(string[] userIDs)
240 { 225 {
241 List<PresenceInfo> presences = new List<PresenceInfo>(userIDs.Length); 226 List<PresenceInfo> presences = new List<PresenceInfo>();
242 227
243 for (int i = 0; i < userIDs.Length; i++) 228 NameValueCollection requestArgs = new NameValueCollection
229 {
230 { "RequestMethod", "GetSessions" },
231 { "UserIDList", String.Join(",",userIDs) }
232 };
233
234 OSDMap sessionListResponse = WebUtil.PostToService(m_serverUrl, requestArgs);
235 if (! sessionListResponse["Success"].AsBoolean())
244 { 236 {
245 UUID userID; 237 m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve sessions: {0}",sessionListResponse["Message"].AsString());
246 if (UUID.TryParse(userIDs[i], out userID) && userID != UUID.Zero) 238 return null;
247 presences.AddRange(GetSessions(userID)); 239 }
240
241 OSDArray sessionList = sessionListResponse["Sessions"] as OSDArray;
242 for (int i = 0; i < sessionList.Count; i++)
243 {
244 OSDMap sessionInfo = sessionList[i] as OSDMap;
245 presences.Add(ResponseToPresenceInfo(sessionInfo));
248 } 246 }
249 247
250 return presences.ToArray(); 248 return presences.ToArray();
@@ -262,7 +260,7 @@ namespace OpenSim.Services.Connectors.SimianGrid
262 260
263 public bool LoggedOut(string userID, UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt) 261 public bool LoggedOut(string userID, UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt)
264 { 262 {
265// m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Logging out user " + userID); 263 // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Logging out user " + userID);
266 264
267 // Remove the session to mark this user offline 265 // Remove the session to mark this user offline
268 if (!LogoutAgent(sessionID)) 266 if (!LogoutAgent(sessionID))
@@ -270,11 +268,11 @@ namespace OpenSim.Services.Connectors.SimianGrid
270 268
271 // Save our last position as user data 269 // Save our last position as user data
272 NameValueCollection requestArgs = new NameValueCollection 270 NameValueCollection requestArgs = new NameValueCollection
273 { 271 {
274 { "RequestMethod", "AddUserData" }, 272 { "RequestMethod", "AddUserData" },
275 { "UserID", userID.ToString() }, 273 { "UserID", userID.ToString() },
276 { "LastLocation", SerializeLocation(regionID, lastPosition, lastLookAt) } 274 { "LastLocation", SerializeLocation(regionID, lastPosition, lastLookAt) }
277 }; 275 };
278 276
279 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); 277 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
280 bool success = response["Success"].AsBoolean(); 278 bool success = response["Success"].AsBoolean();
@@ -287,14 +285,14 @@ namespace OpenSim.Services.Connectors.SimianGrid
287 285
288 public bool SetHome(string userID, UUID regionID, Vector3 position, Vector3 lookAt) 286 public bool SetHome(string userID, UUID regionID, Vector3 position, Vector3 lookAt)
289 { 287 {
290// m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Setting home location for user " + userID); 288 // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Setting home location for user " + userID);
291 289
292 NameValueCollection requestArgs = new NameValueCollection 290 NameValueCollection requestArgs = new NameValueCollection
293 { 291 {
294 { "RequestMethod", "AddUserData" }, 292 { "RequestMethod", "AddUserData" },
295 { "UserID", userID.ToString() }, 293 { "UserID", userID.ToString() },
296 { "HomeLocation", SerializeLocation(regionID, position, lookAt) } 294 { "HomeLocation", SerializeLocation(regionID, position, lookAt) }
297 }; 295 };
298 296
299 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); 297 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
300 bool success = response["Success"].AsBoolean(); 298 bool success = response["Success"].AsBoolean();
@@ -312,23 +310,14 @@ namespace OpenSim.Services.Connectors.SimianGrid
312 310
313 public GridUserInfo GetGridUserInfo(string user) 311 public GridUserInfo GetGridUserInfo(string user)
314 { 312 {
315// m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting session data for agent " + user); 313 // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting session data for agent " + user);
316 314
317 UUID userID = new UUID(user); 315 UUID userID = new UUID(user);
318// m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting user data for " + userID); 316 OSDMap userResponse = GetUserData(userID);
319 317 if (userResponse != null)
320 NameValueCollection requestArgs = new NameValueCollection
321 {
322 { "RequestMethod", "GetUser" },
323 { "UserID", userID.ToString() }
324 };
325
326 OSDMap userResponse = WebUtil.PostToService(m_serverUrl, requestArgs);
327 if (userResponse["Success"].AsBoolean())
328 return ResponseToGridUserInfo(userResponse); 318 return ResponseToGridUserInfo(userResponse);
329 else
330 m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for " + userID + ": " + userResponse["Message"].AsString());
331 319
320 m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for {0}: {1}",userID,userResponse["Message"].AsString());
332 return null; 321 return null;
333 } 322 }
334 323
@@ -338,65 +327,49 @@ namespace OpenSim.Services.Connectors.SimianGrid
338 327
339 private OSDMap GetUserData(UUID userID) 328 private OSDMap GetUserData(UUID userID)
340 { 329 {
341// m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting user data for " + userID); 330 // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting user data for " + userID);
342 331
343 NameValueCollection requestArgs = new NameValueCollection 332 NameValueCollection requestArgs = new NameValueCollection
344 { 333 {
345 { "RequestMethod", "GetUser" }, 334 { "RequestMethod", "GetUser" },
346 { "UserID", userID.ToString() } 335 { "UserID", userID.ToString() }
347 }; 336 };
348 337
349 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); 338 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
350 if (response["Success"].AsBoolean() && response["User"] is OSDMap) 339 if (response["Success"].AsBoolean() && response["User"] is OSDMap)
351 return response; 340 return response;
352 else
353 m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for " + userID + ": " + response["Message"].AsString());
354 341
342 m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for {0}; {1}",userID.ToString(),response["Message"].AsString());
355 return null; 343 return null;
356 } 344 }
357 345
358 private List<PresenceInfo> GetSessions(UUID userID) 346 private OSDMap GetSessionDataFromSessionID(UUID sessionID)
359 { 347 {
360 List<PresenceInfo> presences = new List<PresenceInfo>(1); 348 NameValueCollection requestArgs = new NameValueCollection
361
362 OSDMap userResponse = GetUserData(userID);
363 if (userResponse != null)
364 {
365// m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting sessions for " + userID);
366
367 NameValueCollection requestArgs = new NameValueCollection
368 { 349 {
369 { "RequestMethod", "GetSession" }, 350 { "RequestMethod", "GetSession" },
370 { "UserID", userID.ToString() } 351 { "SessionID", sessionID.ToString() }
371 }; 352 };
372 353
373 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); 354 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
374 if (response["Success"].AsBoolean()) 355 if (response["Success"].AsBoolean())
375 { 356 return response;
376 PresenceInfo presence = ResponseToPresenceInfo(response, userResponse);
377 if (presence != null)
378 presences.Add(presence);
379 }
380// else
381// {
382// m_log.Debug("[SIMIAN PRESENCE CONNECTOR]: No session returned for " + userID + ": " + response["Message"].AsString());
383// }
384 }
385 357
386 return presences; 358 m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve session data for {0}; {1}",sessionID.ToString(),response["Message"].AsString());
359 return null;
387 } 360 }
388 361
389 private bool UpdateSession(UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt) 362 private bool UpdateSession(UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt)
390 { 363 {
391 // Save our current location as session data 364 // Save our current location as session data
392 NameValueCollection requestArgs = new NameValueCollection 365 NameValueCollection requestArgs = new NameValueCollection
393 { 366 {
394 { "RequestMethod", "UpdateSession" }, 367 { "RequestMethod", "UpdateSession" },
395 { "SessionID", sessionID.ToString() }, 368 { "SessionID", sessionID.ToString() },
396 { "SceneID", regionID.ToString() }, 369 { "SceneID", regionID.ToString() },
397 { "ScenePosition", lastPosition.ToString() }, 370 { "ScenePosition", lastPosition.ToString() },
398 { "SceneLookAt", lastLookAt.ToString() } 371 { "SceneLookAt", lastLookAt.ToString() }
399 }; 372 };
400 373
401 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); 374 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
402 bool success = response["Success"].AsBoolean(); 375 bool success = response["Success"].AsBoolean();
@@ -407,7 +380,7 @@ namespace OpenSim.Services.Connectors.SimianGrid
407 return success; 380 return success;
408 } 381 }
409 382
410 private PresenceInfo ResponseToPresenceInfo(OSDMap sessionResponse, OSDMap userResponse) 383 private PresenceInfo ResponseToPresenceInfo(OSDMap sessionResponse)
411 { 384 {
412 if (sessionResponse == null) 385 if (sessionResponse == null)
413 return null; 386 return null;
diff --git a/OpenSim/Services/HypergridService/GatekeeperService.cs b/OpenSim/Services/HypergridService/GatekeeperService.cs
index 97a0afc..0cf1c14 100644
--- a/OpenSim/Services/HypergridService/GatekeeperService.cs
+++ b/OpenSim/Services/HypergridService/GatekeeperService.cs
@@ -58,6 +58,7 @@ namespace OpenSim.Services.HypergridService
58 private static IUserAgentService m_UserAgentService; 58 private static IUserAgentService m_UserAgentService;
59 private static ISimulationService m_SimulationService; 59 private static ISimulationService m_SimulationService;
60 private static IGridUserService m_GridUserService; 60 private static IGridUserService m_GridUserService;
61 private static IBansService m_BansService;
61 62
62 private static string m_AllowedClients = string.Empty; 63 private static string m_AllowedClients = string.Empty;
63 private static string m_DeniedClients = string.Empty; 64 private static string m_DeniedClients = string.Empty;
@@ -87,6 +88,7 @@ namespace OpenSim.Services.HypergridService
87 string presenceService = serverConfig.GetString("PresenceService", String.Empty); 88 string presenceService = serverConfig.GetString("PresenceService", String.Empty);
88 string simulationService = serverConfig.GetString("SimulationService", String.Empty); 89 string simulationService = serverConfig.GetString("SimulationService", String.Empty);
89 string gridUserService = serverConfig.GetString("GridUserService", String.Empty); 90 string gridUserService = serverConfig.GetString("GridUserService", String.Empty);
91 string bansService = serverConfig.GetString("BansService", String.Empty);
90 92
91 // These are mandatory, the others aren't 93 // These are mandatory, the others aren't
92 if (gridService == string.Empty || presenceService == string.Empty) 94 if (gridService == string.Empty || presenceService == string.Empty)
@@ -121,6 +123,8 @@ namespace OpenSim.Services.HypergridService
121 m_UserAgentService = ServerUtils.LoadPlugin<IUserAgentService>(homeUsersService, args); 123 m_UserAgentService = ServerUtils.LoadPlugin<IUserAgentService>(homeUsersService, args);
122 if (gridUserService != string.Empty) 124 if (gridUserService != string.Empty)
123 m_GridUserService = ServerUtils.LoadPlugin<IGridUserService>(gridUserService, args); 125 m_GridUserService = ServerUtils.LoadPlugin<IGridUserService>(gridUserService, args);
126 if (bansService != string.Empty)
127 m_BansService = ServerUtils.LoadPlugin<IBansService>(bansService, args);
124 128
125 if (simService != null) 129 if (simService != null)
126 m_SimulationService = simService; 130 m_SimulationService = simService;
@@ -223,7 +227,7 @@ namespace OpenSim.Services.HypergridService
223 m_log.InfoFormat("[GATEKEEPER SERVICE]: Login request for {0} {1} @ {2} ({3}) at {4} using viewer {5}, channel {6}, IP {7}, Mac {8}, Id0 {9} Teleport Flags {10}", 227 m_log.InfoFormat("[GATEKEEPER SERVICE]: Login request for {0} {1} @ {2} ({3}) at {4} using viewer {5}, channel {6}, IP {7}, Mac {8}, Id0 {9} Teleport Flags {10}",
224 aCircuit.firstname, aCircuit.lastname, authURL, aCircuit.AgentID, destination.RegionName, 228 aCircuit.firstname, aCircuit.lastname, authURL, aCircuit.AgentID, destination.RegionName,
225 aCircuit.Viewer, aCircuit.Channel, aCircuit.IPAddress, aCircuit.Mac, aCircuit.Id0, aCircuit.teleportFlags.ToString()); 229 aCircuit.Viewer, aCircuit.Channel, aCircuit.IPAddress, aCircuit.Mac, aCircuit.Id0, aCircuit.teleportFlags.ToString());
226 230
227 // 231 //
228 // Check client 232 // Check client
229 // 233 //
@@ -287,17 +291,16 @@ namespace OpenSim.Services.HypergridService
287 } 291 }
288 } 292 }
289 } 293 }
290 m_log.DebugFormat("[GATEKEEPER SERVICE]: User is ok");
291 294
292 // 295 //
293 // Foreign agents allowed? Exceptions? 296 // Foreign agents allowed? Exceptions?
294 // 297 //
295 if (account == null) 298 if (account == null)
296 { 299 {
297 bool allowed = m_ForeignAgentsAllowed; 300 bool allowed = m_ForeignAgentsAllowed;
298 301
299 if (m_ForeignAgentsAllowed && IsException(aCircuit, m_ForeignsAllowedExceptions)) 302 if (m_ForeignAgentsAllowed && IsException(aCircuit, m_ForeignsAllowedExceptions))
300 allowed = false; 303 allowed = false;
301 304
302 if (!m_ForeignAgentsAllowed && IsException(aCircuit, m_ForeignsDisallowedExceptions)) 305 if (!m_ForeignAgentsAllowed && IsException(aCircuit, m_ForeignsDisallowedExceptions))
303 allowed = true; 306 allowed = true;
@@ -311,6 +314,20 @@ namespace OpenSim.Services.HypergridService
311 } 314 }
312 } 315 }
313 316
317 //
318 // Is the user banned?
319 // This uses a Ban service that's more powerful than the configs
320 //
321 string uui = (account != null ? aCircuit.AgentID.ToString() : Util.ProduceUserUniversalIdentifier(aCircuit));
322 if (m_BansService != null && m_BansService.IsBanned(uui, aCircuit.IPAddress, aCircuit.Id0, authURL))
323 {
324 reason = "You are banned from this world";
325 m_log.InfoFormat("[GATEKEEPER SERVICE]: Login failed, reason: user {0} is banned", uui);
326 return false;
327 }
328
329 m_log.DebugFormat("[GATEKEEPER SERVICE]: User is OK");
330
314 bool isFirstLogin = false; 331 bool isFirstLogin = false;
315 // 332 //
316 // Login the presence, if it's not there yet (by the login service) 333 // Login the presence, if it's not there yet (by the login service)
diff --git a/OpenSim/Services/Interfaces/IBansService.cs b/OpenSim/Services/Interfaces/IBansService.cs
new file mode 100644
index 0000000..8fd3521
--- /dev/null
+++ b/OpenSim/Services/Interfaces/IBansService.cs
@@ -0,0 +1,48 @@
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 */
27using System;
28using System.Collections.Generic;
29
30using OpenSim.Framework;
31using OpenMetaverse;
32
33namespace OpenSim.Services.Interfaces
34{
35 public interface IBansService
36 {
37 /// <summary>
38 /// Are any of the given arguments banned from the grid?
39 /// </summary>
40 /// <param name="userID"></param>
41 /// <param name="ip"></param>
42 /// <param name="id0"></param>
43 /// <param name="origin"></param>
44 /// <returns></returns>
45 bool IsBanned(string userID, string ip, string id0, string origin);
46 }
47
48}
diff --git a/OpenSim/Services/Interfaces/IUserProfilesService.cs b/OpenSim/Services/Interfaces/IUserProfilesService.cs
new file mode 100644
index 0000000..319d307
--- /dev/null
+++ b/OpenSim/Services/Interfaces/IUserProfilesService.cs
@@ -0,0 +1,75 @@
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 OpenSim.Framework;
30using OpenMetaverse;
31using OpenMetaverse.StructuredData;
32
33namespace OpenSim.Services.Interfaces
34{
35 public interface IUserProfilesService
36 {
37 #region Classifieds
38 OSD AvatarClassifiedsRequest(UUID creatorId);
39 bool ClassifiedUpdate(UserClassifiedAdd ad, ref string result);
40 bool ClassifiedInfoRequest(ref UserClassifiedAdd ad, ref string result);
41 bool ClassifiedDelete(UUID recordId);
42 #endregion Classifieds
43
44 #region Picks
45 OSD AvatarPicksRequest(UUID creatorId);
46 bool PickInfoRequest(ref UserProfilePick pick, ref string result);
47 bool PicksUpdate(ref UserProfilePick pick, ref string result);
48 bool PicksDelete(UUID pickId);
49 #endregion Picks
50
51 #region Notes
52 bool AvatarNotesRequest(ref UserProfileNotes note);
53 bool NotesUpdate(ref UserProfileNotes note, ref string result);
54 #endregion Notes
55
56 #region Profile Properties
57 bool AvatarPropertiesRequest(ref UserProfileProperties prop, ref string result);
58 bool AvatarPropertiesUpdate(ref UserProfileProperties prop, ref string result);
59 #endregion Profile Properties
60
61 #region Interests
62 bool AvatarInterestsUpdate(UserProfileProperties prop, ref string result);
63 #endregion Interests
64
65 #region Utility
66 OSD AvatarImageAssetsRequest(UUID avatarId);
67 #endregion Utility
68
69 #region UserData
70 bool RequestUserAppData(ref UserAppData prop, ref string result);
71 bool SetUserAppData(UserAppData prop, ref string result);
72 #endregion UserData
73 }
74}
75
diff --git a/OpenSim/Services/LLLoginService/LLLoginResponse.cs b/OpenSim/Services/LLLoginService/LLLoginResponse.cs
index e2f947c..da6c016 100644
--- a/OpenSim/Services/LLLoginService/LLLoginResponse.cs
+++ b/OpenSim/Services/LLLoginService/LLLoginResponse.cs
@@ -233,7 +233,7 @@ namespace OpenSim.Services.LLLoginService
233 GridRegion destination, List<InventoryFolderBase> invSkel, FriendInfo[] friendsList, ILibraryService libService, 233 GridRegion destination, List<InventoryFolderBase> invSkel, FriendInfo[] friendsList, ILibraryService libService,
234 string where, string startlocation, Vector3 position, Vector3 lookAt, List<InventoryItemBase> gestures, string message, 234 string where, string startlocation, Vector3 position, Vector3 lookAt, List<InventoryItemBase> gestures, string message,
235 GridRegion home, IPEndPoint clientIP, string mapTileURL, string profileURL, string openIDURL, string searchURL, string currency, 235 GridRegion home, IPEndPoint clientIP, string mapTileURL, string profileURL, string openIDURL, string searchURL, string currency,
236 string DSTZone, UUID realID) 236 string DSTZone, string destinationsURL, string avatarsURL, UUID realID)
237 : this() 237 : this()
238 { 238 {
239 FillOutInventoryData(invSkel, libService); 239 FillOutInventoryData(invSkel, libService);
@@ -253,6 +253,8 @@ namespace OpenSim.Services.LLLoginService
253 MapTileURL = mapTileURL; 253 MapTileURL = mapTileURL;
254 ProfileURL = profileURL; 254 ProfileURL = profileURL;
255 OpenIDURL = openIDURL; 255 OpenIDURL = openIDURL;
256 DestinationsURL = destinationsURL;
257 AvatarsURL = avatarsURL;
256 258
257 SearchURL = searchURL; 259 SearchURL = searchURL;
258 Currency = currency; 260 Currency = currency;
@@ -543,6 +545,12 @@ namespace OpenSim.Services.LLLoginService
543 if (profileURL != String.Empty) 545 if (profileURL != String.Empty)
544 responseData["profile-server-url"] = profileURL; 546 responseData["profile-server-url"] = profileURL;
545 547
548 if (DestinationsURL != String.Empty)
549 responseData["destination_guide_url"] = DestinationsURL;
550
551 if (AvatarsURL != String.Empty)
552 responseData["avatar_picker_url"] = AvatarsURL;
553
546 // We need to send an openid_token back in the response too 554 // We need to send an openid_token back in the response too
547 if (openIDURL != String.Empty) 555 if (openIDURL != String.Empty)
548 responseData["openid_url"] = openIDURL; 556 responseData["openid_url"] = openIDURL;
@@ -1073,6 +1081,16 @@ namespace OpenSim.Services.LLLoginService
1073 set { currency = value; } 1081 set { currency = value; }
1074 } 1082 }
1075 1083
1084 public string DestinationsURL
1085 {
1086 get; set;
1087 }
1088
1089 public string AvatarsURL
1090 {
1091 get; set;
1092 }
1093
1076 #endregion 1094 #endregion
1077 1095
1078 public class UserInfo 1096 public class UserInfo
diff --git a/OpenSim/Services/LLLoginService/LLLoginService.cs b/OpenSim/Services/LLLoginService/LLLoginService.cs
index ede2353..351c1ac 100644
--- a/OpenSim/Services/LLLoginService/LLLoginService.cs
+++ b/OpenSim/Services/LLLoginService/LLLoginService.cs
@@ -78,6 +78,8 @@ namespace OpenSim.Services.LLLoginService
78 protected string m_OpenIDURL; 78 protected string m_OpenIDURL;
79 protected string m_SearchURL; 79 protected string m_SearchURL;
80 protected string m_Currency; 80 protected string m_Currency;
81 protected string m_DestinationGuide;
82 protected string m_AvatarPicker;
81 83
82 protected string m_AllowedClients; 84 protected string m_AllowedClients;
83 protected string m_DeniedClients; 85 protected string m_DeniedClients;
@@ -117,6 +119,8 @@ namespace OpenSim.Services.LLLoginService
117 m_OpenIDURL = m_LoginServerConfig.GetString("OpenIDServerURL", String.Empty); 119 m_OpenIDURL = m_LoginServerConfig.GetString("OpenIDServerURL", String.Empty);
118 m_SearchURL = m_LoginServerConfig.GetString("SearchURL", string.Empty); 120 m_SearchURL = m_LoginServerConfig.GetString("SearchURL", string.Empty);
119 m_Currency = m_LoginServerConfig.GetString("Currency", string.Empty); 121 m_Currency = m_LoginServerConfig.GetString("Currency", string.Empty);
122 m_DestinationGuide = m_LoginServerConfig.GetString ("DestinationGuide", string.Empty);
123 m_AvatarPicker = m_LoginServerConfig.GetString ("AvatarPicker", string.Empty);
120 124
121 m_AllowedClients = m_LoginServerConfig.GetString("AllowedClients", string.Empty); 125 m_AllowedClients = m_LoginServerConfig.GetString("AllowedClients", string.Empty);
122 m_DeniedClients = m_LoginServerConfig.GetString("DeniedClients", string.Empty); 126 m_DeniedClients = m_LoginServerConfig.GetString("DeniedClients", string.Empty);
@@ -461,7 +465,8 @@ namespace OpenSim.Services.LLLoginService
461 = new LLLoginResponse( 465 = new LLLoginResponse(
462 account, aCircuit, guinfo, destination, inventorySkel, friendsList, m_LibraryService, 466 account, aCircuit, guinfo, destination, inventorySkel, friendsList, m_LibraryService,
463 where, startLocation, position, lookAt, gestures, m_WelcomeMessage, home, clientIP, 467 where, startLocation, position, lookAt, gestures, m_WelcomeMessage, home, clientIP,
464 m_MapTileURL, m_ProfileURL, m_OpenIDURL, m_SearchURL, m_Currency, m_DSTZone, realID); 468 m_MapTileURL, m_ProfileURL, m_OpenIDURL, m_SearchURL, m_Currency, m_DSTZone,
469 m_DestinationGuide, m_AvatarPicker, realID);
465 470
466 m_log.DebugFormat("[LLOGIN SERVICE]: All clear. Sending login response to {0} {1}", firstName, lastName); 471 m_log.DebugFormat("[LLOGIN SERVICE]: All clear. Sending login response to {0} {1}", firstName, lastName);
467 472
diff --git a/OpenSim/Services/UserAccountService/GridUserService.cs b/OpenSim/Services/UserAccountService/GridUserService.cs
index 43fa04b..8388180 100644
--- a/OpenSim/Services/UserAccountService/GridUserService.cs
+++ b/OpenSim/Services/UserAccountService/GridUserService.cs
@@ -73,7 +73,7 @@ namespace OpenSim.Services.UserAccountService
73 return info; 73 return info;
74 } 74 }
75 75
76 public GridUserInfo[] GetGridUserInfo(string[] userIDs) 76 public virtual GridUserInfo[] GetGridUserInfo(string[] userIDs)
77 { 77 {
78 List<GridUserInfo> ret = new List<GridUserInfo>(); 78 List<GridUserInfo> ret = new List<GridUserInfo>();
79 79
diff --git a/OpenSim/Services/UserProfilesService/UserProfilesService.cs b/OpenSim/Services/UserProfilesService/UserProfilesService.cs
new file mode 100644
index 0000000..d00f34d
--- /dev/null
+++ b/OpenSim/Services/UserProfilesService/UserProfilesService.cs
@@ -0,0 +1,187 @@
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 System.Text;
31using Nini.Config;
32using log4net;
33using OpenSim.Server.Base;
34using OpenSim.Services.Interfaces;
35using OpenSim.Services.UserAccountService;
36using OpenSim.Data;
37using OpenMetaverse;
38using OpenMetaverse.StructuredData;
39using OpenSim.Framework;
40
41namespace OpenSim.Services.ProfilesService
42{
43 public class UserProfilesService: UserProfilesServiceBase, IUserProfilesService
44 {
45 static readonly ILog m_log =
46 LogManager.GetLogger(
47 MethodBase.GetCurrentMethod().DeclaringType);
48
49 IUserAccountService userAccounts;
50 IAuthenticationService authService;
51
52 public UserProfilesService(IConfigSource config, string configName):
53 base(config, configName)
54 {
55 IConfig Config = config.Configs[configName];
56 if (Config == null)
57 {
58 m_log.Warn("[PROFILES]: No configuration found!");
59 return;
60 }
61 Object[] args = null;
62
63 args = new Object[] { config };
64 string accountService = Config.GetString("UserAccountService", String.Empty);
65 if (accountService != string.Empty)
66 userAccounts = ServerUtils.LoadPlugin<IUserAccountService>(accountService, args);
67
68 args = new Object[] { config };
69 string authServiceConfig = Config.GetString("AuthenticationServiceModule", String.Empty);
70 if (accountService != string.Empty)
71 authService = ServerUtils.LoadPlugin<IAuthenticationService>(authServiceConfig, args);
72 }
73
74 #region Classifieds
75 public OSD AvatarClassifiedsRequest(UUID creatorId)
76 {
77 OSDArray records = ProfilesData.GetClassifiedRecords(creatorId);
78
79 return records;
80 }
81
82 public bool ClassifiedUpdate(UserClassifiedAdd ad, ref string result)
83 {
84 if(!ProfilesData.UpdateClassifiedRecord(ad, ref result))
85 {
86 return false;
87 }
88 result = "success";
89 return true;
90 }
91
92 public bool ClassifiedDelete(UUID recordId)
93 {
94 if(ProfilesData.DeleteClassifiedRecord(recordId))
95 return true;
96
97 return false;
98 }
99
100 public bool ClassifiedInfoRequest(ref UserClassifiedAdd ad, ref string result)
101 {
102 if(ProfilesData.GetClassifiedInfo(ref ad, ref result))
103 return true;
104
105 return false;
106 }
107 #endregion Classifieds
108
109 #region Picks
110 public OSD AvatarPicksRequest(UUID creatorId)
111 {
112 OSDArray records = ProfilesData.GetAvatarPicks(creatorId);
113
114 return records;
115 }
116
117 public bool PickInfoRequest(ref UserProfilePick pick, ref string result)
118 {
119 pick = ProfilesData.GetPickInfo(pick.CreatorId, pick.PickId);
120 result = "OK";
121 return true;
122 }
123
124 public bool PicksUpdate(ref UserProfilePick pick, ref string result)
125 {
126 return ProfilesData.UpdatePicksRecord(pick);
127 }
128
129 public bool PicksDelete(UUID pickId)
130 {
131 return ProfilesData.DeletePicksRecord(pickId);
132 }
133 #endregion Picks
134
135 #region Notes
136 public bool AvatarNotesRequest(ref UserProfileNotes note)
137 {
138 return ProfilesData.GetAvatarNotes(ref note);
139 }
140
141 public bool NotesUpdate(ref UserProfileNotes note, ref string result)
142 {
143 return ProfilesData.UpdateAvatarNotes(ref note, ref result);
144 }
145 #endregion Notes
146
147 #region Profile Properties
148 public bool AvatarPropertiesRequest(ref UserProfileProperties prop, ref string result)
149 {
150 return ProfilesData.GetAvatarProperties(ref prop, ref result);
151 }
152
153 public bool AvatarPropertiesUpdate(ref UserProfileProperties prop, ref string result)
154 {
155 return ProfilesData.UpdateAvatarProperties(ref prop, ref result);
156 }
157 #endregion Profile Properties
158
159 #region Interests
160 public bool AvatarInterestsUpdate(UserProfileProperties prop, ref string result)
161 {
162 return ProfilesData.UpdateAvatarInterests(prop, ref result);
163 }
164 #endregion Interests
165
166 #region Utility
167 public OSD AvatarImageAssetsRequest(UUID avatarId)
168 {
169 OSDArray records = ProfilesData.GetUserImageAssets(avatarId);
170 return records;
171 }
172 #endregion Utility
173
174 #region UserData
175 public bool RequestUserAppData(ref UserAppData prop, ref string result)
176 {
177 return ProfilesData.GetUserAppData(ref prop, ref result);
178 }
179
180 public bool SetUserAppData(UserAppData prop, ref string result)
181 {
182 return true;
183 }
184 #endregion UserData
185 }
186}
187
diff --git a/OpenSim/Services/UserProfilesService/UserProfilesServiceBase.cs b/OpenSim/Services/UserProfilesService/UserProfilesServiceBase.cs
new file mode 100644
index 0000000..927f7c9
--- /dev/null
+++ b/OpenSim/Services/UserProfilesService/UserProfilesServiceBase.cs
@@ -0,0 +1,86 @@
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 log4net;
32using OpenSim.Services.Base;
33using OpenSim.Data;
34
35namespace OpenSim.Services.ProfilesService
36{
37 public class UserProfilesServiceBase: ServiceBase
38 {
39 static readonly ILog m_log =
40 LogManager.GetLogger(
41 MethodBase.GetCurrentMethod().DeclaringType);
42
43 public IProfilesData ProfilesData;
44
45 public string ConfigName
46 {
47 get; private set;
48 }
49
50 public UserProfilesServiceBase(IConfigSource config, string configName):
51 base(config)
52 {
53 if(string.IsNullOrEmpty(configName))
54 {
55 m_log.WarnFormat("[PROFILES]: Configuration section not given!");
56 return;
57 }
58
59 string dllName = String.Empty;
60 string connString = null;
61 string realm = String.Empty;
62
63 IConfig dbConfig = config.Configs["DatabaseService"];
64 if (dbConfig != null)
65 {
66 if (dllName == String.Empty)
67 dllName = dbConfig.GetString("StorageProvider", String.Empty);
68 if (string.IsNullOrEmpty(connString))
69 connString = dbConfig.GetString("ConnectionString", String.Empty);
70 }
71
72 IConfig ProfilesConfig = config.Configs[configName];
73 if (ProfilesConfig != null)
74 {
75 connString = ProfilesConfig.GetString("ConnectionString", connString);
76 realm = ProfilesConfig.GetString("Realm", realm);
77 }
78
79 ProfilesData = LoadPlugin<IProfilesData>(dllName, new Object[] { connString });
80 if (ProfilesData == null)
81 throw new Exception("Could not find a storage interface in the given module");
82
83 }
84 }
85}
86
diff --git a/OpenSim/Tests/Common/Helpers/EntityTransferHelpers.cs b/OpenSim/Tests/Common/Helpers/EntityTransferHelpers.cs
index 6cc7ff2..1b960b1 100644
--- a/OpenSim/Tests/Common/Helpers/EntityTransferHelpers.cs
+++ b/OpenSim/Tests/Common/Helpers/EntityTransferHelpers.cs
@@ -82,7 +82,7 @@ namespace OpenSim.Tests.Common
82 Scene neighbourScene; 82 Scene neighbourScene;
83 SceneManager.Instance.TryGetScene(x, y, out neighbourScene); 83 SceneManager.Instance.TryGetScene(x, y, out neighbourScene);
84 84
85 TestClient neighbourTc = new TestClient(newAgent, neighbourScene, SceneManager.Instance); 85 TestClient neighbourTc = new TestClient(newAgent, neighbourScene);
86 neighbourTcs.Add(neighbourTc); 86 neighbourTcs.Add(neighbourTc);
87 neighbourScene.AddNewClient(neighbourTc, PresenceType.User); 87 neighbourScene.AddNewClient(neighbourTc, PresenceType.User);
88 }; 88 };
diff --git a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs
index bdd9093..d9bb85e 100644
--- a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs
+++ b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs
@@ -447,9 +447,6 @@ namespace OpenSim.Tests.Common
447 /// Add a root agent where the details of the agent connection (apart from the id) are unimportant for the test 447 /// Add a root agent where the details of the agent connection (apart from the id) are unimportant for the test
448 /// </summary> 448 /// </summary>
449 /// <remarks> 449 /// <remarks>
450 /// This can be used for tests where there is only one region or where there are multiple non-neighbour regions
451 /// and teleport doesn't take place.
452 ///
453 /// XXX: Use the version of this method that takes the UserAccount structure wherever possible - this will 450 /// XXX: Use the version of this method that takes the UserAccount structure wherever possible - this will
454 /// make the agent circuit data (e.g. first, lastname) consistent with the user account data. 451 /// make the agent circuit data (e.g. first, lastname) consistent with the user account data.
455 /// </remarks> 452 /// </remarks>
@@ -462,22 +459,6 @@ namespace OpenSim.Tests.Common
462 } 459 }
463 460
464 /// <summary> 461 /// <summary>
465 /// Add a root agent where the details of the agent connection (apart from the id) are unimportant for the test
466 /// </summary>
467 /// <remarks>
468 /// XXX: Use the version of this method that takes the UserAccount structure wherever possible - this will
469 /// make the agent circuit data (e.g. first, lastname) consistent with the user account data.
470 /// </remarks>
471 /// <param name="scene"></param>
472 /// <param name="agentId"></param>
473 /// <param name="sceneManager"></param>
474 /// <returns></returns>
475 public static ScenePresence AddScenePresence(Scene scene, UUID agentId, SceneManager sceneManager)
476 {
477 return AddScenePresence(scene, GenerateAgentData(agentId), sceneManager);
478 }
479
480 /// <summary>
481 /// Add a root agent. 462 /// Add a root agent.
482 /// </summary> 463 /// </summary>
483 /// <param name="scene"></param> 464 /// <param name="scene"></param>
@@ -508,31 +489,7 @@ namespace OpenSim.Tests.Common
508 /// <returns></returns> 489 /// <returns></returns>
509 public static ScenePresence AddScenePresence(Scene scene, AgentCircuitData agentData) 490 public static ScenePresence AddScenePresence(Scene scene, AgentCircuitData agentData)
510 { 491 {
511 return AddScenePresence(scene, agentData, null); 492 return AddScenePresence(scene, new TestClient(agentData, scene), agentData);
512 }
513
514 /// <summary>
515 /// Add a root agent.
516 /// </summary>
517 /// <remarks>
518 /// This function
519 ///
520 /// 1) Tells the scene that an agent is coming. Normally, the login service (local if standalone, from the
521 /// userserver if grid) would give initial login data back to the client and separately tell the scene that the
522 /// agent was coming.
523 ///
524 /// 2) Connects the agent with the scene
525 ///
526 /// This function performs actions equivalent with notifying the scene that an agent is
527 /// coming and then actually connecting the agent to the scene. The one step missed out is the very first
528 /// </remarks>
529 /// <param name="scene"></param>
530 /// <param name="agentData"></param>
531 /// <param name="sceneManager"></param>
532 /// <returns></returns>
533 public static ScenePresence AddScenePresence(Scene scene, AgentCircuitData agentData, SceneManager sceneManager)
534 {
535 return AddScenePresence(scene, new TestClient(agentData, scene, sceneManager), agentData, sceneManager);
536 } 493 }
537 494
538 /// <summary> 495 /// <summary>
@@ -552,10 +509,9 @@ namespace OpenSim.Tests.Common
552 /// </remarks> 509 /// </remarks>
553 /// <param name="scene"></param> 510 /// <param name="scene"></param>
554 /// <param name="agentData"></param> 511 /// <param name="agentData"></param>
555 /// <param name="sceneManager"></param>
556 /// <returns></returns> 512 /// <returns></returns>
557 public static ScenePresence AddScenePresence( 513 public static ScenePresence AddScenePresence(
558 Scene scene, IClientAPI client, AgentCircuitData agentData, SceneManager sceneManager) 514 Scene scene, IClientAPI client, AgentCircuitData agentData)
559 { 515 {
560 // We emulate the proper login sequence here by doing things in four stages 516 // We emulate the proper login sequence here by doing things in four stages
561 517
@@ -578,10 +534,6 @@ namespace OpenSim.Tests.Common
578 /// Introduce an agent into the scene by adding a new client. 534 /// Introduce an agent into the scene by adding a new client.
579 /// </summary> 535 /// </summary>
580 /// <returns>The scene presence added</returns> 536 /// <returns>The scene presence added</returns>
581 /// <param name='sceneManager'>
582 /// Scene manager. Can be null if there is only one region in the test or multiple regions that are not
583 /// neighbours and where no teleporting takes place.
584 /// </param>
585 /// <param name='scene'></param> 537 /// <param name='scene'></param>
586 /// <param name='testClient'></param> 538 /// <param name='testClient'></param>
587 /// <param name='agentData'></param> 539 /// <param name='agentData'></param>
@@ -607,7 +559,7 @@ namespace OpenSim.Tests.Common
607 acd.child = true; 559 acd.child = true;
608 560
609 // XXX: ViaLogin may not be correct for child agents 561 // XXX: ViaLogin may not be correct for child agents
610 TestClient client = new TestClient(acd, scene, null); 562 TestClient client = new TestClient(acd, scene);
611 return IntroduceClientToScene(scene, client, acd, TeleportFlags.ViaLogin); 563 return IntroduceClientToScene(scene, client, acd, TeleportFlags.ViaLogin);
612 } 564 }
613 565
diff --git a/OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs b/OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs
index a1794c9..b3b75af 100644
--- a/OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs
+++ b/OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs
@@ -218,12 +218,37 @@ namespace OpenSim.Tests.Common
218 public static InventoryFolderBase CreateInventoryFolder( 218 public static InventoryFolderBase CreateInventoryFolder(
219 IInventoryService inventoryService, UUID userId, string path, bool useExistingFolders) 219 IInventoryService inventoryService, UUID userId, string path, bool useExistingFolders)
220 { 220 {
221 return CreateInventoryFolder(inventoryService, userId, UUID.Random(), path, useExistingFolders);
222 }
223
224 /// <summary>
225 /// Create inventory folders starting from the user's root folder.
226 /// </summary>
227 /// <param name="inventoryService"></param>
228 /// <param name="userId"></param>
229 /// <param name="folderId"></param>
230 /// <param name="path">
231 /// The folders to create. Multiple folders can be specified on a path delimited by the PATH_DELIMITER
232 /// </param>
233 /// <param name="useExistingFolders">
234 /// If true, then folders in the path which already the same name are
235 /// used. This applies to the terminal folder as well.
236 /// If false, then all folders in the path are created, even if there is already a folder at a particular
237 /// level with the same name.
238 /// </param>
239 /// <returns>
240 /// The folder created. If the path contains multiple folders then the last one created is returned.
241 /// Will return null if the root folder could not be found.
242 /// </returns>
243 public static InventoryFolderBase CreateInventoryFolder(
244 IInventoryService inventoryService, UUID userId, UUID folderId, string path, bool useExistingFolders)
245 {
221 InventoryFolderBase rootFolder = inventoryService.GetRootFolder(userId); 246 InventoryFolderBase rootFolder = inventoryService.GetRootFolder(userId);
222 247
223 if (null == rootFolder) 248 if (null == rootFolder)
224 return null; 249 return null;
225 250
226 return CreateInventoryFolder(inventoryService, rootFolder, path, useExistingFolders); 251 return CreateInventoryFolder(inventoryService, folderId, rootFolder, path, useExistingFolders);
227 } 252 }
228 253
229 /// <summary> 254 /// <summary>
@@ -235,6 +260,7 @@ namespace OpenSim.Tests.Common
235 /// TODO: May need to make it an option to create duplicate folders. 260 /// TODO: May need to make it an option to create duplicate folders.
236 /// </remarks> 261 /// </remarks>
237 /// <param name="inventoryService"></param> 262 /// <param name="inventoryService"></param>
263 /// <param name="folderId">ID of the folder to create</param>
238 /// <param name="parentFolder"></param> 264 /// <param name="parentFolder"></param>
239 /// <param name="path"> 265 /// <param name="path">
240 /// The folder to create. 266 /// The folder to create.
@@ -249,7 +275,7 @@ namespace OpenSim.Tests.Common
249 /// The folder created. If the path contains multiple folders then the last one created is returned. 275 /// The folder created. If the path contains multiple folders then the last one created is returned.
250 /// </returns> 276 /// </returns>
251 public static InventoryFolderBase CreateInventoryFolder( 277 public static InventoryFolderBase CreateInventoryFolder(
252 IInventoryService inventoryService, InventoryFolderBase parentFolder, string path, bool useExistingFolders) 278 IInventoryService inventoryService, UUID folderId, InventoryFolderBase parentFolder, string path, bool useExistingFolders)
253 { 279 {
254 string[] components = path.Split(new string[] { PATH_DELIMITER }, 2, StringSplitOptions.None); 280 string[] components = path.Split(new string[] { PATH_DELIMITER }, 2, StringSplitOptions.None);
255 281
@@ -262,9 +288,16 @@ namespace OpenSim.Tests.Common
262 { 288 {
263// Console.WriteLine("Creating folder {0} at {1}", components[0], parentFolder.Name); 289// Console.WriteLine("Creating folder {0} at {1}", components[0], parentFolder.Name);
264 290
291 UUID folderIdForCreate;
292
293 if (components.Length > 1)
294 folderIdForCreate = UUID.Random();
295 else
296 folderIdForCreate = folderId;
297
265 folder 298 folder
266 = new InventoryFolderBase( 299 = new InventoryFolderBase(
267 UUID.Random(), components[0], parentFolder.Owner, (short)AssetType.Unknown, parentFolder.ID, 0); 300 folderIdForCreate, components[0], parentFolder.Owner, (short)AssetType.Unknown, parentFolder.ID, 0);
268 301
269 inventoryService.AddFolder(folder); 302 inventoryService.AddFolder(folder);
270 } 303 }
@@ -274,7 +307,7 @@ namespace OpenSim.Tests.Common
274// } 307// }
275 308
276 if (components.Length > 1) 309 if (components.Length > 1)
277 return CreateInventoryFolder(inventoryService, folder, components[1], useExistingFolders); 310 return CreateInventoryFolder(inventoryService, folderId, folder, components[1], useExistingFolders);
278 else 311 else
279 return folder; 312 return folder;
280 } 313 }
diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs
index dce2fd7..179a91f 100644
--- a/OpenSim/Tests/Common/Mock/TestClient.cs
+++ b/OpenSim/Tests/Common/Mock/TestClient.cs
@@ -47,9 +47,9 @@ namespace OpenSim.Tests.Common.Mock
47 EventWaitHandle wh = new EventWaitHandle (false, EventResetMode.AutoReset, "Crossing"); 47 EventWaitHandle wh = new EventWaitHandle (false, EventResetMode.AutoReset, "Crossing");
48 48
49 private Scene m_scene; 49 private Scene m_scene;
50 private SceneManager m_sceneManager;
51 50
52 // Properties so that we can get at received data for test purposes 51 // Properties so that we can get at received data for test purposes
52 public List<uint> ReceivedKills { get; private set; }
53 public List<UUID> ReceivedOfflineNotifications { get; private set; } 53 public List<UUID> ReceivedOfflineNotifications { get; private set; }
54 public List<UUID> ReceivedOnlineNotifications { get; private set; } 54 public List<UUID> ReceivedOnlineNotifications { get; private set; }
55 public List<UUID> ReceivedFriendshipTerminations { get; private set; } 55 public List<UUID> ReceivedFriendshipTerminations { get; private set; }
@@ -61,6 +61,7 @@ namespace OpenSim.Tests.Common.Mock
61 // Test client specific events - for use by tests to implement some IClientAPI behaviour. 61 // Test client specific events - for use by tests to implement some IClientAPI behaviour.
62 public event Action<RegionInfo, Vector3, Vector3> OnReceivedMoveAgentIntoRegion; 62 public event Action<RegionInfo, Vector3, Vector3> OnReceivedMoveAgentIntoRegion;
63 public event Action<ulong, IPEndPoint> OnTestClientInformClientOfNeighbour; 63 public event Action<ulong, IPEndPoint> OnTestClientInformClientOfNeighbour;
64 public event Action<GridInstantMessage> OnReceivedInstantMessage;
64 65
65// disable warning: public events, part of the public API 66// disable warning: public events, part of the public API
66#pragma warning disable 67 67#pragma warning disable 67
@@ -197,6 +198,7 @@ namespace OpenSim.Tests.Common.Mock
197 public event EstateCovenantRequest OnEstateCovenantRequest; 198 public event EstateCovenantRequest OnEstateCovenantRequest;
198 public event EstateChangeInfo OnEstateChangeInfo; 199 public event EstateChangeInfo OnEstateChangeInfo;
199 public event EstateManageTelehub OnEstateManageTelehub; 200 public event EstateManageTelehub OnEstateManageTelehub;
201 public event CachedTextureRequest OnCachedTextureRequest;
200 202
201 public event ObjectDuplicateOnRay OnObjectDuplicateOnRay; 203 public event ObjectDuplicateOnRay OnObjectDuplicateOnRay;
202 204
@@ -435,33 +437,21 @@ namespace OpenSim.Tests.Common.Mock
435 /// <summary> 437 /// <summary>
436 /// Constructor 438 /// Constructor
437 /// </summary> 439 /// </summary>
438 /// <remarks>
439 /// Can be used for a test where there is only one region or where there are multiple regions that are not
440 /// neighbours and where no teleporting takes place. In other situations, the constructor that takes in a
441 /// scene manager should be used.
442 /// </remarks>
443 /// <param name="agentData"></param>
444 /// <param name="scene"></param>
445 public TestClient(AgentCircuitData agentData, Scene scene) : this(agentData, scene, null) {}
446
447 /// <summary>
448 /// Constructor
449 /// </summary>
450 /// <param name="agentData"></param> 440 /// <param name="agentData"></param>
451 /// <param name="scene"></param> 441 /// <param name="scene"></param>
452 /// <param name="sceneManager"></param> 442 /// <param name="sceneManager"></param>
453 public TestClient(AgentCircuitData agentData, Scene scene, SceneManager sceneManager) 443 public TestClient(AgentCircuitData agentData, Scene scene)
454 { 444 {
455 m_agentId = agentData.AgentID; 445 m_agentId = agentData.AgentID;
456 m_firstName = agentData.firstname; 446 m_firstName = agentData.firstname;
457 m_lastName = agentData.lastname; 447 m_lastName = agentData.lastname;
458 m_circuitCode = agentData.circuitcode; 448 m_circuitCode = agentData.circuitcode;
459 m_scene = scene; 449 m_scene = scene;
460 m_sceneManager = sceneManager;
461 SessionId = agentData.SessionID; 450 SessionId = agentData.SessionID;
462 SecureSessionId = agentData.SecureSessionID; 451 SecureSessionId = agentData.SecureSessionID;
463 CapsSeedUrl = agentData.CapsPath; 452 CapsSeedUrl = agentData.CapsPath;
464 453
454 ReceivedKills = new List<uint>();
465 ReceivedOfflineNotifications = new List<UUID>(); 455 ReceivedOfflineNotifications = new List<UUID>();
466 ReceivedOnlineNotifications = new List<UUID>(); 456 ReceivedOnlineNotifications = new List<UUID>();
467 ReceivedFriendshipTerminations = new List<UUID>(); 457 ReceivedFriendshipTerminations = new List<UUID>();
@@ -487,6 +477,18 @@ namespace OpenSim.Tests.Common.Mock
487 OnCompleteMovementToRegion(this, true); 477 OnCompleteMovementToRegion(this, true);
488 } 478 }
489 479
480 /// <summary>
481 /// Emulate sending an IM from the viewer to the simulator.
482 /// </summary>
483 /// <param name='im'></param>
484 public void HandleImprovedInstantMessage(GridInstantMessage im)
485 {
486 ImprovedInstantMessage handlerInstantMessage = OnInstantMessage;
487
488 if (handlerInstantMessage != null)
489 handlerInstantMessage(this, im);
490 }
491
490 public virtual void ActivateGesture(UUID assetId, UUID gestureId) 492 public virtual void ActivateGesture(UUID assetId, UUID gestureId)
491 { 493 {
492 } 494 }
@@ -499,6 +501,11 @@ namespace OpenSim.Tests.Common.Mock
499 { 501 {
500 } 502 }
501 503
504 public void SendCachedTextureResponse(ISceneEntity avatar, int serial, List<CachedTextureResponseArg> cachedTextures)
505 {
506
507 }
508
502 public virtual void Kick(string message) 509 public virtual void Kick(string message)
503 { 510 {
504 } 511 }
@@ -513,11 +520,11 @@ namespace OpenSim.Tests.Common.Mock
513 520
514 public virtual void SendAgentDataUpdate(UUID agentid, UUID activegroupid, string firstname, string lastname, ulong grouppowers, string groupname, string grouptitle) 521 public virtual void SendAgentDataUpdate(UUID agentid, UUID activegroupid, string firstname, string lastname, ulong grouppowers, string groupname, string grouptitle)
515 { 522 {
516
517 } 523 }
518 524
519 public virtual void SendKillObject(ulong regionHandle, List<uint> localID) 525 public virtual void SendKillObject(List<uint> localID)
520 { 526 {
527 ReceivedKills.AddRange(localID);
521 } 528 }
522 529
523 public virtual void SetChildAgentThrottle(byte[] throttle) 530 public virtual void SetChildAgentThrottle(byte[] throttle)
@@ -526,15 +533,13 @@ namespace OpenSim.Tests.Common.Mock
526 533
527 public void SetAgentThrottleSilent(int throttle, int setting) 534 public void SetAgentThrottleSilent(int throttle, int setting)
528 { 535 {
529
530
531 } 536 }
537
532 public byte[] GetThrottlesPacked(float multiplier) 538 public byte[] GetThrottlesPacked(float multiplier)
533 { 539 {
534 return new byte[0]; 540 return new byte[0];
535 } 541 }
536 542
537
538 public virtual void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs) 543 public virtual void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs)
539 { 544 {
540 } 545 }
@@ -547,7 +552,8 @@ namespace OpenSim.Tests.Common.Mock
547 552
548 public void SendInstantMessage(GridInstantMessage im) 553 public void SendInstantMessage(GridInstantMessage im)
549 { 554 {
550 555 if (OnReceivedInstantMessage != null)
556 OnReceivedInstantMessage(im);
551 } 557 }
552 558
553 public void SendGenericMessage(string method, UUID invoice, List<string> message) 559 public void SendGenericMessage(string method, UUID invoice, List<string> message)
diff --git a/OpenSim/Tests/Common/Mock/TestXInventoryDataPlugin.cs b/OpenSim/Tests/Common/Mock/TestXInventoryDataPlugin.cs
index ccbdf81..2be5524 100644
--- a/OpenSim/Tests/Common/Mock/TestXInventoryDataPlugin.cs
+++ b/OpenSim/Tests/Common/Mock/TestXInventoryDataPlugin.cs
@@ -53,6 +53,9 @@ namespace OpenSim.Tests.Common.Mock
53 53
54 public XInventoryFolder[] GetFolders(string[] fields, string[] vals) 54 public XInventoryFolder[] GetFolders(string[] fields, string[] vals)
55 { 55 {
56// Console.WriteLine(
57// "Requesting folders, fields {0}, vals {1}", string.Join(",", fields), string.Join(",", vals));
58
56 List<XInventoryFolder> origFolders 59 List<XInventoryFolder> origFolders
57 = Get<XInventoryFolder>(fields, vals, m_allFolders.Values.ToList()); 60 = Get<XInventoryFolder>(fields, vals, m_allFolders.Values.ToList());
58 61
@@ -104,7 +107,30 @@ namespace OpenSim.Tests.Common.Mock
104 } 107 }
105 108
106 public bool MoveItem(string id, string newParent) { throw new NotImplementedException(); } 109 public bool MoveItem(string id, string newParent) { throw new NotImplementedException(); }
107 public bool MoveFolder(string id, string newParent) { throw new NotImplementedException(); } 110
111 public bool MoveFolder(string id, string newParent)
112 {
113 // Don't use GetFolders() here - it takes a clone!
114 XInventoryFolder folder = m_allFolders[new UUID(id)];
115
116 if (folder == null)
117 return false;
118
119 folder.parentFolderID = new UUID(newParent);
120
121// XInventoryFolder[] newParentFolders
122// = GetFolders(new string[] { "folderID" }, new string[] { folder.parentFolderID.ToString() });
123
124// Console.WriteLine(
125// "Moved folder {0} {1}, to {2} {3}",
126// folder.folderName, folder.folderID, newParentFolders[0].folderName, folder.parentFolderID);
127
128 // TODO: Really need to implement folder version incrementing, though this should be common code anyway,
129 // not reimplemented in each db plugin.
130
131 return true;
132 }
133
108 public XInventoryItem[] GetActiveGestures(UUID principalID) { throw new NotImplementedException(); } 134 public XInventoryItem[] GetActiveGestures(UUID principalID) { throw new NotImplementedException(); }
109 public int GetAssetPermissions(UUID principalID, UUID assetID) { throw new NotImplementedException(); } 135 public int GetAssetPermissions(UUID principalID, UUID assetID) { throw new NotImplementedException(); }
110 } 136 }